diff options
author | Alexander Nozdrin <alik@sun.com> | 2010-06-07 12:47:04 +0400 |
---|---|---|
committer | Alexander Nozdrin <alik@sun.com> | 2010-06-07 12:47:04 +0400 |
commit | f29d24b0f88b67504bc701b6f2773a0109ad6154 (patch) | |
tree | 4268070936d3c9dbd27165b1d9c1593e17ec0d61 | |
parent | 9b5312db1d78247b893066205cffe8b32e0f573d (diff) | |
parent | 60a9d9bbb94ac03159bcc2d75b649abb1c9dc956 (diff) | |
download | mariadb-git-f29d24b0f88b67504bc701b6f2773a0109ad6154.tar.gz |
Manual merge from mysql-trunk-bugfixing.
Conflicts:
- BUILD/SETUP.sh
- mysql-test/mysql-test-run.pl
- mysql-test/r/partition_error.result
- mysql-test/t/disabled.def
- mysql-test/t/partition_error.test
- sql/share/errmsg-utf8.txt
571 files changed, 28450 insertions, 24820 deletions
diff --git a/.bzr-mysql/default.conf b/.bzr-mysql/default.conf index fcb3cab2de6..4eab3d239d0 100644 --- a/.bzr-mysql/default.conf +++ b/.bzr-mysql/default.conf @@ -1,4 +1,4 @@ [MYSQL] post_commit_to = "commits@lists.mysql.com" post_push_to = "commits@lists.mysql.com" -tree_name = "mysql-trunk" +tree_name = "mysql-trunk-bugfixing" diff --git a/.bzrignore b/.bzrignore index d51ffc7265b..7733bd2aa7c 100644 --- a/.bzrignore +++ b/.bzrignore @@ -3085,3 +3085,13 @@ client/dtoa.c libmysqld/sql_audit.cc configure.am libmysqld/des_key_file.cc +CPackConfig.cmake +CPackSourceConfig.cmake +make_dist.cmake +client/echo +libmysql/libmysql_exports_file.cc +libmysql/merge_archives_mysqlclient.cmake +libmysqld/merge_archives_mysqlserver.cmake +libmysqld/mysqlserver_depends.c +libmysqld/examples/mysql_embedded +sql/.empty diff --git a/BUILD/Makefile.am b/BUILD/Makefile.am index 496fb302b16..c7bf813c9fe 100644 --- a/BUILD/Makefile.am +++ b/BUILD/Makefile.am @@ -25,8 +25,6 @@ EXTRA_DIST = FINISH.sh \ check-cpu \ cleanup \ compile-alpha \ - compile-alpha-ccc \ - compile-alpha-cxx \ compile-alpha-debug \ compile-amd64-debug-max \ compile-amd64-debug-max-no-ndb \ diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 86207049f89..0bc16f120e5 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -122,8 +122,9 @@ fi # Override -DFORCE_INIT_OF_VARS from debug_cflags. It enables the macro # LINT_INIT(), which is only useful for silencing spurious warnings # of static analysis tools. We want LINT_INIT() to be a no-op in Valgrind. -valgrind_flags="-USAFEMALLOC -UFORCE_INIT_OF_VARS -DHAVE_purify " +valgrind_flags="-UFORCE_INIT_OF_VARS -DHAVE_purify " valgrind_flags="$valgrind_flags -DMYSQL_SERVER_SUFFIX=-valgrind-max" +valgrind_configs="--with-valgrind" # # Used in -debug builds debug_cflags="-DUNIV_MUST_NOT_INLINE -DEXTRA_DEBUG -DFORCE_INIT_OF_VARS " diff --git a/BUILD/build_mccge.sh b/BUILD/build_mccge.sh index 8ca31b2d119..2d7c0d2a2c2 100755 --- a/BUILD/build_mccge.sh +++ b/BUILD/build_mccge.sh @@ -1010,9 +1010,10 @@ set_ccache_usage() set_valgrind_flags() { if test "x$valgrind_flag" = "xyes" ; then - loc_valgrind_flags="-USAFEMALLOC -UFORCE_INIT_OF_VARS -DHAVE_purify " + loc_valgrind_flags="-UFORCE_INIT_OF_VARS -DHAVE_purify " loc_valgrind_flags="$loc_valgrind_flags -DMYSQL_SERVER_SUFFIX=-valgrind-max" compiler_flags="$compiler_flags $loc_valgrind_flags" + with_flags="$with_flags --with-valgrind" fi } diff --git a/BUILD/compile-alpha-ccc b/BUILD/compile-alpha-ccc deleted file mode 100755 index 59ed241d51c..00000000000 --- a/BUILD/compile-alpha-ccc +++ /dev/null @@ -1,41 +0,0 @@ -#! /bin/sh - -/bin/rm -f */.deps/*.P */*.o -make -k maintainer-clean -/bin/rm -f */.deps/*.P */*.o -/bin/rm -f config.cache mysql-*.tar.gz - -path=`dirname $0` -. "$path/autorun.sh" - -CC=ccc CFLAGS="-fast -O3 -fomit-frame-pointer" CXX=gcc CXXFLAGS="-O6 -fomit-frame-pointer -felide-constructors -fno-exceptions -fno-rtti -mcpu=ev6 -Wa,-mev6" CXXLDFLAGS='/usr/lib/compaq/libots-2.2.7/libots.so /usr/lib/compaq/cpml-5.0.0/libcpml_ev6.a' ./configure --prefix=/usr/local/mysql --disable-shared --with-extra-charsets=complex --enable-thread-safe-client -make -rm */.deps/* -make -if [ $? = 0 ] -then - rm */.deps/* - bin/mysqladmin shutdown - sur make install - if [ $? = 0 ] - then - scripts/make_binary_distribution - fi -fi - -exit - -# This should give better performance by compiling many files at once, but -# according to our benchmarks there isn't any real difference. - -pwd=`pwd` -for i in */make-ccc -do - cd `dirname $i` - make-ccc - cd $pwd -done -cd sql -rm mysqld .deps/*.P -make mysqld -cd $pwd diff --git a/BUILD/compile-alpha-cxx b/BUILD/compile-alpha-cxx deleted file mode 100755 index a1b5605ac5e..00000000000 --- a/BUILD/compile-alpha-cxx +++ /dev/null @@ -1,43 +0,0 @@ -#! /bin/sh - -/bin/rm -f */.deps/*.P */*.o -make -k maintainer-clean -/bin/rm -f */.deps/*.P */*.o -/bin/rm -f */.deps/*.P config.cache storage/innobase/config.cache mysql-*.tar.gz - -path=`dirname $0` -. "$path/autorun.sh" - -CC=ccc CFLAGS="-fast" CXX=cxx CXXFLAGS="-fast -noexceptions -nortti" ./configure --prefix=/usr/local/mysql --disable-shared --with-extra-charsets=complex --enable-thread-safe-client --with-mysqld-ldflags=-non_shared --with-client-ldflags=-non_shared --without-extra-tools --disable-dependency-tracking - -make -j2 -find . -name ".deps" | xargs rm -r -make -if [ $? = 0 ] -then - find . -name ".deps" | xargs rm -r - bin/mysqladmin shutdown - sur make install - if [ $? = 0 ] - then - scripts/make_binary_distribution - fi - make test -fi - -exit - -# This should give better performance by compiling many files at once, but -# according to our benchmarks there isn't any real difference. - -pwd=`pwd` -for i in */make-ccc -do - cd `dirname $i` - make-ccc - cd $pwd -done -cd sql -rm mysqld .deps/*.P -make mysqld -cd $pwd diff --git a/BUILD/compile-amd64-valgrind-max b/BUILD/compile-amd64-valgrind-max index 962d0f17b04..fb8dce38df3 100755 --- a/BUILD/compile-amd64-valgrind-max +++ b/BUILD/compile-amd64-valgrind-max @@ -4,7 +4,7 @@ path=`dirname $0` . "$path/SETUP.sh" extra_flags="$amd64_cflags $debug_cflags $valgrind_flags" -extra_configs="$amd64_configs $debug_configs $max_configs" +extra_configs="$amd64_configs $debug_configs $valgrind_configs $max_configs" . "$path/FINISH.sh" diff --git a/BUILD/compile-pentium-icc-valgrind-max b/BUILD/compile-pentium-icc-valgrind-max index 58acf892f5a..0babf9ee881 100755 --- a/BUILD/compile-pentium-icc-valgrind-max +++ b/BUILD/compile-pentium-icc-valgrind-max @@ -29,6 +29,6 @@ extra_flags="$pentium_cflags $debug_cflags $valgrind_flags" c_warnings="-Wall -Wcheck -wd161,444,279,810,981,1292,1469,1572" cxx_warnings="$c_warnings -wd869,874" base_cxxflags="-fno-exceptions -fno-rtti" -extra_configs="$pentium_configs $debug_configs" +extra_configs="$pentium_configs $debug_configs $valgrind_configs" . "$path/FINISH.sh" diff --git a/BUILD/compile-pentium-valgrind-max b/BUILD/compile-pentium-valgrind-max index 09cc162d2be..8ef47bfbc17 100755 --- a/BUILD/compile-pentium-valgrind-max +++ b/BUILD/compile-pentium-valgrind-max @@ -4,7 +4,7 @@ path=`dirname $0` . "$path/SETUP.sh" extra_flags="$pentium_cflags $debug_cflags $valgrind_flags" -extra_configs="$pentium_configs $debug_configs $max_configs" +extra_configs="$pentium_configs $debug_configs $valgrind_configs $max_configs" . "$path/FINISH.sh" diff --git a/BUILD/compile-pentium-valgrind-max-no-ndb b/BUILD/compile-pentium-valgrind-max-no-ndb index 66f6ae08a7f..f480f83ebf7 100755 --- a/BUILD/compile-pentium-valgrind-max-no-ndb +++ b/BUILD/compile-pentium-valgrind-max-no-ndb @@ -4,7 +4,7 @@ path=`dirname $0` . "$path/SETUP.sh" extra_flags="$pentium_cflags $debug_cflags $valgrind_flags" -extra_configs="$pentium_configs $debug_configs $max_no_ndb_configs" +extra_configs="$pentium_configs $debug_configs $valgrind_configs $max_no_ndb_configs" . "$path/FINISH.sh" diff --git a/BUILD/compile-pentium64-valgrind-max b/BUILD/compile-pentium64-valgrind-max index fa476cbb50a..eb3d20c874d 100755 --- a/BUILD/compile-pentium64-valgrind-max +++ b/BUILD/compile-pentium64-valgrind-max @@ -4,7 +4,7 @@ path=`dirname $0` . "$path/SETUP.sh" extra_flags="$pentium64_cflags $debug_cflags $valgrind_flags" -extra_configs="$pentium_configs $debug_configs $max_configs" +extra_configs="$pentium_configs $debug_configs $valgrind_configs $max_configs" . "$path/FINISH.sh" diff --git a/CMakeLists.txt b/CMakeLists.txt index 889dc463769..536fae9f4b1 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -262,6 +262,7 @@ IF(NOT WITHOUT_SERVER) ENDIF() INCLUDE(cmake/abi_check.cmake) +INCLUDE(cmake/tags.cmake) CONFIGURE_FILE(config.h.cmake ${CMAKE_BINARY_DIR}/include/my_config.h) CONFIGURE_FILE(config.h.cmake ${CMAKE_BINARY_DIR}/include/config.h) diff --git a/client/mysql.cc b/client/mysql.cc index 86094edc039..45fabe9cf8c 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -59,8 +59,6 @@ static char *server_version= NULL; /* Array of options to pass to libemysqld */ #define MAX_SERVER_ARGS 64 -void* sql_alloc(unsigned size); // Don't use mysqld alloc for these -void sql_element_free(void *ptr); #include "sql_string.h" extern "C" { @@ -2318,8 +2316,10 @@ static bool add_line(String &buffer,char *line,char *in_string, #ifdef HAVE_READLINE +C_MODE_START static char *new_command_generator(const char *text, int); -extern "C" char **new_mysql_completion (const char *text, int start, int end); +static char **new_mysql_completion(const char *text, int start, int end); +C_MODE_END /* Tell the GNU Readline library how to complete. We want to try to complete @@ -2451,9 +2451,9 @@ static void initialize_readline (char *name) array of matches, or NULL if there aren't any. */ -char **new_mysql_completion (const char *text, - int start __attribute__((unused)), - int end __attribute__((unused))) +static char **new_mysql_completion(const char *text, + int start __attribute__((unused)), + int end __attribute__((unused))) { if (!status.batch && !quick) #if defined(USE_NEW_READLINE_INTERFACE) @@ -4963,17 +4963,3 @@ static int com_prompt(String *buffer, char *line) tee_fprintf(stdout, "PROMPT set to '%s'\n", current_prompt); return 0; } - -#ifndef EMBEDDED_LIBRARY -/* Keep sql_string library happy */ - -void *sql_alloc(size_t Size) -{ - return my_malloc(Size,MYF(MY_WME)); -} - -void sql_element_free(void *ptr) -{ - my_free(ptr,MYF(0)); -} -#endif /* EMBEDDED_LIBRARY */ diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 24d520ff97f..0312a0a030b 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -77,11 +77,17 @@ static int setenv(const char *name, const char *value, int overwrite); #endif +C_MODE_START +static sig_handler signal_handler(int sig); +static my_bool get_one_option(int optid, const struct my_option *, + char *argument); +C_MODE_END + enum { OPT_SKIP_SAFEMALLOC=OPT_MAX_CLIENT_OPTION, OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL, OPT_MAX_CONNECT_RETRIES, OPT_MAX_CONNECTIONS, OPT_MARK_PROGRESS, - OPT_LOG_DIR, OPT_TAIL_LINES, OPT_RESULT_FORMAT_VERSION, + OPT_LOG_DIR, OPT_TAIL_LINES, OPT_RESULT_FORMAT_VERSION }; static int record= 0, opt_sleep= -1; @@ -462,7 +468,6 @@ void log_msg(const char *fmt, ...) VAR* var_from_env(const char *, const char *); VAR* var_init(VAR* v, const char *name, int name_len, const char *val, int val_len); -void var_free(void* v); VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, my_bool ignore_not_existing); void eval_expr(VAR* v, const char *p, const char** p_end); @@ -1914,6 +1919,8 @@ static void strip_parentheses(struct st_command *command) } +C_MODE_START + static uchar *get_var_key(const uchar* var, size_t *len, my_bool __attribute__((unused)) t) { @@ -1924,6 +1931,16 @@ static uchar *get_var_key(const uchar* var, size_t *len, } +static void var_free(void *v) +{ + my_free(((VAR*) v)->str_val, MYF(MY_WME)); + if (((VAR*)v)->alloced) + my_free(v, MYF(MY_WME)); +} + +C_MODE_END + + VAR *var_init(VAR *v, const char *name, int name_len, const char *val, int val_len) { @@ -1966,14 +1983,6 @@ VAR *var_init(VAR *v, const char *name, int name_len, const char *val, } -void var_free(void *v) -{ - my_free(((VAR*) v)->str_val, MYF(MY_WME)); - if (((VAR*)v)->alloced) - my_free(v, MYF(MY_WME)); -} - - VAR* var_from_env(const char *name, const char *def_val) { const char *tmp; @@ -6070,8 +6079,7 @@ void read_embedded_server_arguments(const char *name) static my_bool -get_one_option(int optid, const struct my_option *opt __attribute__((unused)), - char *argument) +get_one_option(int optid, const struct my_option *, char *argument) { switch(optid) { case '#': diff --git a/client/sql_string.cc b/client/sql_string.cc index ccbc8977e7f..6b749409a64 100644 --- a/client/sql_string.cc +++ b/client/sql_string.cc @@ -24,13 +24,6 @@ #include <m_string.h> #include <m_ctype.h> #include <mysql_com.h> -/* - The following extern declarations are ok as these are interface functions - required by the string function -*/ - -extern void sql_alloc(size_t size); -extern void sql_element_free(void *ptr); #include "sql_string.h" diff --git a/cmake/Makefile.am b/cmake/Makefile.am index 6fe1a9556be..af3ec4f980d 100644 --- a/cmake/Makefile.am +++ b/cmake/Makefile.am @@ -24,6 +24,7 @@ EXTRA_DIST = \ dtrace_prelink.cmake \ versioninfo.rc.in \ mysql_add_executable.cmake \ + tags.cmake \ install_layout.cmake \ build_configurations/mysql_release.cmake \ os/Windows.cmake \ diff --git a/cmake/os/FreeBSD.cmake b/cmake/os/FreeBSD.cmake index 0b958c61315..be7af778e93 100644 --- a/cmake/os/FreeBSD.cmake +++ b/cmake/os/FreeBSD.cmake @@ -1,5 +1,5 @@ -# Copyright (C) 2010 Sun Microsystems, Inc +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. # # 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 @@ -15,6 +15,9 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # This file includes FreeBSD specific options and quirks, related to system checks -#Legacy option, maybe not needed anymore , taken as is from autotools build -ADD_DEFINITIONS(-DNET_RETRY_COUNT=1000000) +# Should not be needed any more, but kept for easy resurrection if needed +# #Legacy option, maybe not needed anymore , taken as is from autotools build +# ADD_DEFINITIONS(-DNET_RETRY_COUNT=1000000) + +ADD_DEFINITIONS(-DHAVE_BROKEN_REALPATH) diff --git a/cmake/tags.cmake b/cmake/tags.cmake new file mode 100644 index 00000000000..07c1411a1d6 --- /dev/null +++ b/cmake/tags.cmake @@ -0,0 +1,26 @@ +# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. +# +# 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; 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, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +# Generate tag files +IF(UNIX) + ADD_CUSTOM_TARGET (tags + COMMAND support-files/build-tags + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + ADD_CUSTOM_TARGET (ctags + COMMAND ctags -R -f CTAGS + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) +ENDIF() diff --git a/cmd-line-utils/libedit/filecomplete.c b/cmd-line-utils/libedit/filecomplete.c index 4c63f57bc45..05bd10e9f9e 100644 --- a/cmd-line-utils/libedit/filecomplete.c +++ b/cmd-line-utils/libedit/filecomplete.c @@ -95,10 +95,9 @@ static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', '$', char * fn_tilde_expand(const char *txt) { - struct passwd pwres, *pass; + struct passwd *pass; char *temp; size_t len = 0; - char pwbuf[1024]; if (txt[0] != '~') return (strdup(txt)); diff --git a/cmd-line-utils/readline/input.c b/cmd-line-utils/readline/input.c index 84c0422059a..af81d9cd3b0 100644 --- a/cmd-line-utils/readline/input.c +++ b/cmd-line-utils/readline/input.c @@ -318,7 +318,9 @@ _rl_input_available () return (_kbhit ()); #endif +#if !defined (HAVE_SELECT) return 0; +#endif } int diff --git a/config.h.cmake b/config.h.cmake index b3b234a153b..c6c049814ba 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -282,6 +282,8 @@ #cmakedefine HAVE_NETINET_IN6_H 1 #cmakedefine HAVE_IPV6 1 #cmakedefine ss_family @ss_family@ +#cmakedefine HAVE_SOCKADDR_IN_SIN_LEN 1 +#cmakedefine HAVE_SOCKADDR_IN6_SIN6_LEN 1 #cmakedefine HAVE_TIMESPEC_TS_SEC 1 #cmakedefine STRUCT_DIRENT_HAS_D_INO 1 #cmakedefine STRUCT_DIRENT_HAS_D_NAMLEN 1 diff --git a/configure.cmake b/configure.cmake index 94d2cfd5804..1727e2b2c10 100644 --- a/configure.cmake +++ b/configure.cmake @@ -54,6 +54,15 @@ IF(NOT SYSTEM_TYPE) ENDIF() +# Always enable -Wall for gnu C/C++ +IF(CMAKE_COMPILER_IS_GNUCXX) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused-parameter") +ENDIF() +IF(CMAKE_COMPILER_IS_GNUCC) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall") +ENDIF() + + IF(CMAKE_COMPILER_IS_GNUCXX) # MySQL "canonical" GCC flags. At least -fno-rtti flag affects # ABI and cannot be simply removed. @@ -1000,6 +1009,21 @@ IF(NOT HAVE_SOCKADDR_STORAGE_SS_FAMILY) SET(ss_family __ss_family) ENDIF() ENDIF() + +# +# Check if struct sockaddr_in::sin_len is available. +# + +CHECK_STRUCT_HAS_MEMBER("struct sockaddr_in" sin_len + "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_SOCKADDR_IN_SIN_LEN) + +# +# Check if struct sockaddr_in6::sin6_len is available. +# + +CHECK_STRUCT_HAS_MEMBER("struct sockaddr_in6" sin6_len + "${CMAKE_EXTRA_INCLUDE_FILES}" HAVE_SOCKADDR_IN6_SIN6_LEN) + SET(CMAKE_EXTRA_INCLUDE_FILES) CHECK_STRUCT_HAS_MEMBER("struct dirent" d_ino "dirent.h" STRUCT_DIRENT_HAS_D_INO) diff --git a/configure.in b/configure.in index 26f31dfd844..5de43fc7951 100644 --- a/configure.in +++ b/configure.in @@ -1,7 +1,7 @@ dnl -*- ksh -*- dnl Process this file with autoconf to produce a configure script. -# Copyright (C) 2008-2009 Sun Microsystems, Inc +# Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. # # 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 @@ -1013,6 +1013,66 @@ else AC_MSG_RESULT([yes]) fi +#-------------------------------------------------------------------------- +# Check if struct sockaddr_in::sin_len is available +#-------------------------------------------------------------------------- + +AC_CACHE_CHECK( + [if sockaddr_in::sin_len is available], + mysql_cv_have_sockaddr_in_sin_len, + AC_TRY_COMPILE( + [ + #ifdef WIN32 + #include <winsock2.h> + #else + #include <sys/types.h> + #include <netinet/in.h> + #include <sys/socket.h> + #endif + ], + [unsigned int i = sizeof(((struct sockaddr_in *) 0)->sin_len)], + mysql_cv_have_sockaddr_in_sin_len=yes, + mysql_cv_have_sockaddr_in_sin_len=no)) + +if test "$mysql_cv_have_sockaddr_in_sin_len" = "yes"; then + AC_DEFINE( + [HAVE_SOCKADDR_IN_SIN_LEN], + [1], + [If sockaddr_in::sin_len is available]) +fi + +#-------------------------------------------------------------------------- +# Check if struct sockaddr_in6::sin6_len is available +#-------------------------------------------------------------------------- + +AC_CACHE_CHECK( + [if sockaddr_in6::sin6_len is available], + mysql_cv_have_sockaddr_in6_sin6_len, + AC_TRY_COMPILE( + [ + #ifdef WIN32 + #include <winsock2.h> + #else + #include <sys/types.h> + #include <netinet/in.h> + #include <sys/socket.h> + #endif + + #ifdef HAVE_NETINET_IN6_H + #include <netinet/in6.h> + #endif + ], + [unsigned int i = sizeof(((struct sockaddr_in6 *) 0)->sin6_len)], + mysql_cv_have_sockaddr_in6_sin6_len=yes, + mysql_cv_have_sockaddr_in6_sin6_len=no)) + +if test "$mysql_cv_have_sockaddr_in_sin6_len" = "yes"; then + AC_DEFINE( + [HAVE_SOCKADDR_IN6_SIN6_LEN], + [1], + [If sockaddr_in6::sin6_len is available]) +fi + #-------------------------------------------------------------------- # Check for TCP wrapper support #-------------------------------------------------------------------- @@ -1236,14 +1296,22 @@ case $SYSTEM_TYPE in fi ;; *freebsd*|*dragonfly*) - AC_MSG_WARN([Adding fix for interrupted reads]) + dnl These dependencies have not really been checked for some time OSVERSION=`sysctl -a | grep osreldate | awk '{ print $2 }'` - if test "$OSVERSION" -gt "480100" && \ + if test "$OSVERSION" -gt "600000" + then + # Post user-level threads, MYSQLD_NET_RETRY_COUNT is not needed any more + AC_MSG_WARN([Adding fix for broken realpath]) + CFLAGS="$CFLAGS -DHAVE_BROKEN_REALPATH" + CXXFLAGS="$CXXFLAGS -DHAVE_BROKEN_REALPATH" + elif test "$OSVERSION" -gt "480100" && \ test "$OSVERSION" -lt "500000" || \ test "$OSVERSION" -gt "500109" then + AC_MSG_WARN([Adding fix for interrupted reads]) CXXFLAGS="$CXXFLAGS -DMYSQLD_NET_RETRY_COUNT=1000000" else + AC_MSG_WARN([Adding fix for interrupted reads and broken realpath]) CFLAGS="$CFLAGS -DHAVE_BROKEN_REALPATH" CXXFLAGS="$CXXFLAGS -DMYSQLD_NET_RETRY_COUNT=1000000 -DHAVE_BROKEN_REALPATH" fi @@ -1845,6 +1913,17 @@ else CXXFLAGS="$OPTIMIZE_CXXFLAGS $CXXFLAGS" fi +AC_ARG_WITH([valgrind], + [AS_HELP_STRING([--with-valgrind], + [Valgrind instrumentation @<:@default=no@:>@])], + [], [with_valgrind=no]) + +if test "$with_valgrind" != "no" +then + AC_CHECK_HEADERS([valgrind/valgrind.h valgrind/memcheck.h], + [AC_DEFINE([HAVE_VALGRIND], [1], [Define for Valgrind support])]) +fi + # Debug Sync Facility. NOTE: depends on 'with_debug'. Must be behind it. AC_MSG_CHECKING(if Debug Sync Facility should be enabled.) AC_ARG_ENABLE(debug_sync, @@ -3122,6 +3201,7 @@ esac AC_SUBST([RDTSC_SPARC_ASSEMBLY]) + #-------------------------------------------------------------------- # Output results #-------------------------------------------------------------------- diff --git a/extra/comp_err.c b/extra/comp_err.c index e4a07caa2ef..362533d9781 100644 --- a/extra/comp_err.c +++ b/extra/comp_err.c @@ -686,7 +686,7 @@ static ha_checksum checksum_format_specifier(const char* msg) case 'u': case 'x': case 's': - chksum= my_checksum(chksum, start, (uint) (p + 1 - start)); + chksum= my_checksum(chksum, (uchar*) start, (uint) (p + 1 - start)); start= 0; /* Not in format specifier anymore */ break; diff --git a/extra/perror.c b/extra/perror.c index d9c636ceb8c..eda0253129d 100644 --- a/extra/perror.c +++ b/extra/perror.c @@ -269,7 +269,7 @@ int main(int argc,char *argv[]) HA_ERRORS *ha_err_ptr; for (code=1 ; code < sys_nerr ; code++) { - if (sys_errlist[code][0]) + if (sys_errlist[code] && sys_errlist[code][0]) { /* Skip if no error-text */ printf("%3d = %s\n",code,sys_errlist[code]); } diff --git a/extra/yassl/taocrypt/include/runtime.hpp b/extra/yassl/taocrypt/include/runtime.hpp index 99bbe3ac8a3..b59f61a1cde 100644 --- a/extra/yassl/taocrypt/include/runtime.hpp +++ b/extra/yassl/taocrypt/include/runtime.hpp @@ -60,7 +60,7 @@ static int __cxa_pure_virtual() __attribute__((noinline, used)); static int __cxa_pure_virtual() { // oops, pure virtual called! - assert("Pure virtual method called." == "Aborted"); + assert(!"Pure virtual method called. Aborted"); return 0; } diff --git a/include/m_string.h b/include/m_string.h index 7bd39e7483f..1a2a508edfb 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -127,9 +127,6 @@ extern size_t bcmp(const uchar *s1,const uchar *s2,size_t len); extern size_t my_bcmp(const uchar *s1,const uchar *s2,size_t len); #undef bcmp #define bcmp(A,B,C) my_bcmp((A),(B),(C)) -#define bzero_if_purify(A,B) bzero(A,B) -#else -#define bzero_if_purify(A,B) #endif /* HAVE_purify */ #ifndef bmove512 diff --git a/include/my_alloc.h b/include/my_alloc.h index 93b7438a1df..4b1ffd3d444 100644 --- a/include/my_alloc.h +++ b/include/my_alloc.h @@ -23,6 +23,10 @@ #define ALLOC_MAX_BLOCK_TO_DROP 4096 #define ALLOC_MAX_BLOCK_USAGE_BEFORE_DROP 10 +#ifdef __cplusplus +extern "C" { +#endif + typedef struct st_used_mem { /* struct for once_alloc (block) */ struct st_used_mem *next; /* Next block in use */ @@ -48,4 +52,9 @@ typedef struct st_mem_root void (*error_handler)(void); } MEM_ROOT; + +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/my_base.h b/include/my_base.h index 7766d4165a2..28dc55b1b84 100644 --- a/include/my_base.h +++ b/include/my_base.h @@ -562,6 +562,8 @@ typedef ulong ha_rows; #define HA_VARCHAR_PACKLENGTH(field_length) ((field_length) < 256 ? 1 :2) /* invalidator function reference for Query Cache */ +C_MODE_START typedef void (* invalidator_by_filename)(const char * filename); +C_MODE_END #endif /* _my_base_h */ diff --git a/include/my_global.h b/include/my_global.h index 6246bde0cbc..7b9c34cd724 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -77,6 +77,11 @@ #define C_MODE_END #endif +#ifdef __cplusplus +#define CPP_UNNAMED_NS_START namespace { +#define CPP_UNNAMED_NS_END } +#endif + #if defined(_WIN32) #include <my_config.h> #elif defined(__NETWARE__) @@ -1074,6 +1079,17 @@ typedef long long my_ptrdiff_t; #define MY_DIV_UP(A, B) (((A) + (B) - 1) / (B)) #define MY_ALIGNED_BYTE_ARRAY(N, S, T) T N[MY_DIV_UP(S, sizeof(T))] +#ifdef __cplusplus +template <size_t sz> struct Aligned_char_array +{ + union { + void *v; // Ensures alignment. + char arr[sz]; // The actual buffer. + } u; + void* arr() { return &u.arr[0]; } +}; +#endif /* __cplusplus */ + /* Custom version of standard offsetof() macro which can be used to get offsets of members in class for non-POD types (according to the current diff --git a/include/my_pthread.h b/include/my_pthread.h index e41abba950e..ea37f6e6b92 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -712,7 +712,6 @@ extern my_bool my_thread_init(void); extern void my_thread_end(void); extern const char *my_thread_name(void); extern my_thread_id my_thread_dbug_id(void); -extern int pthread_no_free(void *); extern int pthread_dummy(int); /* All thread specific variables are in the following struct */ diff --git a/include/my_sys.h b/include/my_sys.h index ac10628f943..cca4d713ca6 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -28,6 +28,19 @@ typedef struct my_aio_result { } my_aio_result; #endif +#ifdef HAVE_VALGRIND +# include <valgrind/memcheck.h> +# define MEM_UNDEFINED(a,len) VALGRIND_MAKE_MEM_UNDEFINED(a,len) +# define MEM_NOACCESS(a,len) VALGRIND_MAKE_MEM_NOACCESS(a,len) +# define MEM_CHECK_ADDRESSABLE(a,len) VALGRIND_CHECK_MEM_IS_ADDRESSABLE(a,len) +# define MEM_CHECK_DEFINED(a,len) VALGRIND_CHECK_MEM_IS_DEFINED(a,len) +#else /* HAVE_VALGRIND */ +# define MEM_UNDEFINED(a,len) ((void) 0) +# define MEM_NOACCESS(a,len) ((void) 0) +# define MEM_CHECK_ADDRESSABLE(a,len) ((void) 0) +# define MEM_CHECK_DEFINED(a,len) ((void) 0) +#endif /* HAVE_VALGRIND */ + #ifndef THREAD extern int NEAR my_errno; /* Last error in mysys */ #else @@ -41,8 +54,6 @@ extern int NEAR my_errno; /* Last error in mysys */ #include <malloc.h> /*for alloca*/ #endif -#define MYSYS_PROGRAM_USES_CURSES() { error_handler_hook = my_message_curses; mysys_uses_curses=1; } -#define MYSYS_PROGRAM_DONT_USE_CURSES() { error_handler_hook = my_message_no_curses; mysys_uses_curses=0;} #define MY_INIT(name); { my_progname= name; my_init(); } /** @@ -156,7 +167,7 @@ extern int NEAR my_errno; /* Last error in mysys */ #define my_memdup(A,B,C) _my_memdup((A),(B), __FILE__,__LINE__,C) #define my_strdup(A,C) _my_strdup((A), __FILE__,__LINE__,C) #define my_strndup(A,B,C) _my_strndup((A),(B),__FILE__,__LINE__,C) -#define TRASH(A,B) bfill(A, B, 0x8F) +#define TRASH(A,B) do { bfill(A, B, 0x8F); MEM_UNDEFINED(A, B); } while (0) #define QUICK_SAFEMALLOC sf_malloc_quick=1 #define NORMAL_SAFEMALLOC sf_malloc_quick=0 extern uint sf_malloc_prehunc,sf_malloc_endhunc,sf_malloc_quick; @@ -184,7 +195,7 @@ extern char *my_strndup(const char *from, size_t length, #define CALLER_INFO_PROTO /* nothing */ #define CALLER_INFO /* nothing */ #define ORIG_CALLER_INFO /* nothing */ -#define TRASH(A,B) /* nothing */ +#define TRASH(A,B) do{MEM_CHECK_ADDRESSABLE(A,B);MEM_UNDEFINED(A,B);} while (0) #endif #if defined(ENABLED_DEBUG_SYNC) @@ -272,7 +283,7 @@ extern int NEAR my_umask_dir, NEAR my_recived_signals, /* Signals we have got */ NEAR my_safe_to_handle_signal, /* Set when allowed to SIGTSTP */ NEAR my_dont_interrupt; /* call remember_intr when set */ -extern my_bool NEAR mysys_uses_curses, my_use_symdir; +extern my_bool NEAR my_use_symdir; extern size_t sf_malloc_cur_memory, sf_malloc_max_memory; extern ulong my_default_record_cache_size; @@ -669,7 +680,6 @@ extern int nt_share_delete(const char *name,myf MyFlags); #ifdef _WIN32 /* Windows-only functions (CRT equivalents)*/ -extern File my_sopen(const char *path, int oflag, int shflag, int pmode); extern HANDLE my_get_osfhandle(File fd); extern void my_osmaperr(unsigned long last_error); #endif @@ -698,8 +708,7 @@ extern int my_error_register(const char** (*get_errmsgs) (), int first, int last); extern const char **my_error_unregister(int first, int last); extern void my_message(uint my_err, const char *str,myf MyFlags); -extern void my_message_no_curses(uint my_err, const char *str,myf MyFlags); -extern void my_message_curses(uint my_err, const char *str,myf MyFlags); +extern void my_message_stderr(uint my_err, const char *str, myf MyFlags); extern my_bool my_basic_init(void); extern my_bool my_init(void); extern void my_end(int infoflag); diff --git a/include/mysql_com.h b/include/mysql_com.h index e2baa06b160..90fe4ac1995 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -197,7 +197,14 @@ enum enum_server_command & ~CLIENT_COMPRESS) \ & ~CLIENT_SSL_VERIFY_SERVER_CERT) -#define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */ +/** + Is raised when a multi-statement transaction + has been started, either explicitly, by means + of BEGIN or COMMIT AND CHAIN, or + implicitly, by the first transactional + statement, when autocommit=off. +*/ +#define SERVER_STATUS_IN_TRANS 1 #define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */ #define SERVER_MORE_RESULTS_EXISTS 8 /* Multi query - next query exists */ #define SERVER_QUERY_NO_GOOD_INDEX_USED 16 diff --git a/libmysql/Makefile.shared b/libmysql/Makefile.shared index 71649b83991..71a4fd867bd 100644 --- a/libmysql/Makefile.shared +++ b/libmysql/Makefile.shared @@ -56,7 +56,7 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ my_create.lo my_delete.lo mf_tempfile.lo my_open.lo \ my_file.lo my_read.lo my_write.lo errors.lo \ my_error.lo my_getwd.lo my_div.lo \ - mf_pack.lo my_messnc.lo mf_dirname.lo mf_fn_ext.lo\ + mf_pack.lo my_mess.lo mf_dirname.lo mf_fn_ext.lo\ mf_wcomp.lo typelib.lo safemalloc.lo my_alloc.lo \ mf_format.lo mf_path.lo mf_unixpath.lo my_fopen.lo \ my_symlink.lo my_fstream.lo mf_arr_appstr.lo \ diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 72379fbc089..e727122293c 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -953,7 +953,8 @@ bool Protocol::send_result_set_metadata(List<Item> *list, uint flags) server_field.type <= (int) MYSQL_TYPE_BLOB) ? server_field.length / item->collation.collation->mbminlen : server_field.length / item->collation.collation->mbmaxlen; - client_field->length= max_char_len * thd_cs->mbmaxlen; + client_field->length= char_to_byte_length_safe(max_char_len, + thd_cs->mbmaxlen); } client_field->type= server_field.type; client_field->flags= server_field.flags; diff --git a/mysql-test/include/check_concurrent_insert.inc b/mysql-test/include/check_concurrent_insert.inc new file mode 100644 index 00000000000..6a9ada65562 --- /dev/null +++ b/mysql-test/include/check_concurrent_insert.inc @@ -0,0 +1,96 @@ +# +# SUMMARY +# Check if statement reading table '$table' allows concurrent +# inserts in it. +# +# PARAMETERS +# $table Table in which concurrent inserts should be allowed. +# $con_aux1 Name of the first auxiliary connection to be used by this +# script. +# $con_aux2 Name of the second auxiliary connection to be used by this +# script. +# $statement Statement to be checked. +# $restore_table Table which might be modified affected by statement to be +# checked and thus needs backing up before its execution +# and restoring after it (can be empty). +# +# EXAMPLE +# lock_sync.test +# +--disable_result_log +--disable_query_log + +# Reset DEBUG_SYNC facility for safety. +set debug_sync= "RESET"; + +if (`SELECT '$restore_table' <> ''`) +{ +--eval create table t_backup select * from $restore_table; +} + +connection $con_aux1; +set debug_sync='after_lock_tables_takes_lock SIGNAL parked WAIT_FOR go'; +--send_eval $statement; + +connection $con_aux2; +set debug_sync='now WAIT_FOR parked'; +--send_eval insert into $table values (0); + +--enable_result_log +--enable_query_log +connection default; +# Wait until concurrent insert is successfully executed while +# statement being checked has its tables locked. +# We use wait_condition.inc instead of simply executing +# concurrent insert here in order to avoid deadlocks if test +# fails and timing out instead. +let $wait_condition= + select count(*) = 0 from information_schema.processlist + where info = "insert into $table values (0)"; +--source include/wait_condition.inc + +--disable_result_log +--disable_query_log + +if ($success) +{ +# Apparently concurrent insert was successfully executed. +# To be safe against wait_condition.inc succeeding due to +# races let us first reap concurrent insert to ensure that +# it has really been successfully executed. +connection $con_aux2; +--reap +connection default; +set debug_sync= 'now SIGNAL go'; +connection $con_aux1; +--reap +connection default; +--echo Success: '$statement' allows concurrent inserts into '$table'. +} +if (!$success) +{ +# Waiting has timed out. Apparently concurrent insert was blocked. +# So to be able to continue we need to end our statement first. +set debug_sync= 'now SIGNAL go'; +connection $con_aux1; +--reap +connection $con_aux2; +--reap +connection default; +--echo Error: '$statement' doesn't allow concurrent inserts into '$table'! +} + +--eval delete from $table where i = 0; + +if (`SELECT '$restore_table' <> ''`) +{ +--eval truncate table $restore_table; +--eval insert into $restore_table select * from t_backup; +drop table t_backup; +} + +# Clean-up. Reset DEBUG_SYNC facility after use. +set debug_sync= "RESET"; + +--enable_result_log +--enable_query_log diff --git a/mysql-test/include/check_no_concurrent_insert.inc b/mysql-test/include/check_no_concurrent_insert.inc new file mode 100644 index 00000000000..278ffeffb1e --- /dev/null +++ b/mysql-test/include/check_no_concurrent_insert.inc @@ -0,0 +1,81 @@ +# +# SUMMARY +# Check that statement reading table '$table' doesn't allow concurrent +# inserts in it. +# +# PARAMETERS +# $table Table in which concurrent inserts should be disallowed. +# $con_aux1 Name of the first auxiliary connection to be used by this +# script. +# $con_aux2 Name of the second auxiliary connection to be used by this +# script. +# $statement Statement to be checked. +# $restore_table Table which might be modified affected by statement to be +# checked and thus needs backing up before its execution +# and restoring after it (can be empty). +# +# EXAMPLE +# lock_sync.test +# +--disable_result_log +--disable_query_log + +# Reset DEBUG_SYNC facility for safety. +set debug_sync= "RESET"; + +if (`SELECT '$restore_table' <> ''`) +{ +--eval create table t_backup select * from $restore_table; +} + +connection $con_aux1; +set debug_sync='after_lock_tables_takes_lock SIGNAL parked WAIT_FOR go'; +--send_eval $statement; + +connection $con_aux2; +set debug_sync='now WAIT_FOR parked'; +--send_eval insert into $table values (0); + +--enable_result_log +--enable_query_log +connection default; +# Wait until concurrent insert is successfully blocked because +# of our statement. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Table lock" and info = "insert into $table values (0)"; +--source include/wait_condition.inc + +--disable_result_log +--disable_query_log + +set debug_sync= 'now SIGNAL go'; +connection $con_aux1; +--reap +connection $con_aux2; +--reap +connection default; + +if ($success) +{ +--echo Success: '$statement' doesn't allow concurrent inserts into '$table'. +} +if (!$success) +{ +--echo Error: '$statement' allows concurrent inserts into '$table'! +} + +--eval delete from $table where i = 0; + +if (`SELECT '$restore_table' <> ''`) +{ +--eval truncate table $restore_table; +--eval insert into $restore_table select * from t_backup; +drop table t_backup; +} + +# Clean-up. Reset DEBUG_SYNC facility after use. +set debug_sync= "RESET"; + +--enable_result_log +--enable_query_log diff --git a/mysql-test/include/check_no_row_lock.inc b/mysql-test/include/check_no_row_lock.inc new file mode 100644 index 00000000000..958161b9b7f --- /dev/null +++ b/mysql-test/include/check_no_row_lock.inc @@ -0,0 +1,71 @@ +# +# SUMMARY +# Check if statement affecting or reading table '$table' doesn't +# take any kind of locks on its rows. +# +# PARAMETERS +# $table Table for which presence of row locks should be checked. +# $con_aux Name of auxiliary connection to be used by this script. +# $statement Statement to be checked. +# +# EXAMPLE +# innodb_mysql_lock2.test +# +--disable_result_log +--disable_query_log + +connection default; +begin; +--eval select * from $table for update; + +connection $con_aux; +begin; +--send_eval $statement; + +--enable_result_log +--enable_query_log + +connection default; +# Wait until statement is successfully executed while +# all rows in table are X-locked. This means that it +# does not acquire any row locks. +# We use wait_condition.inc instead of simply executing +# statement here in order to avoid deadlocks if test +# fails and timing out instead. +let $wait_condition= + select count(*) = 0 from information_schema.processlist + where info = "$statement"; +--source include/wait_condition.inc + +--disable_result_log +--disable_query_log + +if ($success) +{ +# Apparently statement was successfully executed and thus it +# has not required any row locks. +# To be safe against wait_condition.inc succeeding due to +# races let us first reap the statement being checked to +# ensure that it has been successfully executed. +connection $con_aux; +--reap +rollback; +connection default; +rollback; +--echo Success: '$statement' doesn't take row locks on '$table'. +} +if (!$success) +{ +# Waiting has timed out. Apparently statement was blocked on +# some row lock. So to be able to continue we need to unlock +# rows first. +rollback; +connection $con_aux; +--reap +rollback; +connection default; +--echo Error: '$statement' takes some row locks on '$table'! +} + +--enable_result_log +--enable_query_log diff --git a/mysql-test/include/check_shared_row_lock.inc b/mysql-test/include/check_shared_row_lock.inc new file mode 100644 index 00000000000..efc7e13b3aa --- /dev/null +++ b/mysql-test/include/check_shared_row_lock.inc @@ -0,0 +1,61 @@ +# +# SUMMARY +# Check if statement reading table '$table' takes shared locks +# on some of its rows. +# +# PARAMETERS +# $table Table for which presence of row locks should be checked. +# $con_aux Name of auxiliary connection to be used by this script. +# $statement Statement to be checked. +# $wait_statement Sub-statement which is supposed to acquire locks (should +# be the same as $statement for ordinary statements). +# +# EXAMPLE +# innodb_mysql_lock2.test +# +--disable_result_log +--disable_query_log + +connection default; +begin; +--eval select * from $table for update; + +connection $con_aux; +begin; +--send_eval $statement; + +--enable_result_log +--enable_query_log + +connection default; +# Wait until statement is successfully blocked because +# all rows in table are X-locked. This means that at +# least it acquires S-locks on some of rows. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state in ("Sending data","statistics", "preparing") and + info = "$wait_statement"; +--source include/wait_condition.inc + +--disable_result_log +--disable_query_log + +rollback; + +connection $con_aux; +--reap +rollback; + +connection default; +--enable_result_log +--enable_query_log + +if ($success) +{ +--echo Success: '$statement' takes shared row locks on '$table'. +} + +if (!$success) +{ +--echo Error: '$statement' hasn't taken shared row locks on '$table'! +} diff --git a/storage/innobase/mysql-test/innodb-index.inc b/mysql-test/include/innodb-index.inc index 37de3162abe..37de3162abe 100644 --- a/storage/innobase/mysql-test/innodb-index.inc +++ b/mysql-test/include/innodb-index.inc diff --git a/mysql-test/include/not_var_link.inc b/mysql-test/include/not_var_link.inc index 96db4f1dfd5..e1eb1dff2d7 100644 --- a/mysql-test/include/not_var_link.inc +++ b/mysql-test/include/not_var_link.inc @@ -1,6 +1,11 @@ +# Test if MYSQLTEST_VARDIR is a soft link +# If we run in parallel, we have a suffix "/$child_num", so chop off that. + perl; + my $path= $ENV{'MYSQLTEST_VARDIR'}; + $path=~ s|/\d+$||; open (ISLINK, ">" . $ENV{'MYSQL_TMP_DIR'} . "/mtr_var_link"); - my $mvr= -l $ENV{'MYSQLTEST_VARDIR'} ? 1 : 0; + my $mvr= -l $path ? 1 : 0; print ISLINK "let \$mtr_var_link= $mvr;\n"; close ISLINK; EOF diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 83c07eaa5f1..fa2db663e1e 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2114,7 +2114,7 @@ sub environment_setup { # mysqlhotcopy # ---------------------------------------------------- my $mysqlhotcopy= - mtr_pl_maybe_exists("$basedir/scripts/mysqlhotcopy"); + mtr_pl_maybe_exists("$bindir/scripts/mysqlhotcopy"); # Since mysqltest interprets the real path as "false" in an if, # use 1 ("true") to indicate "not exists" so it can be tested for $ENV{'MYSQLHOTCOPY'}= $mysqlhotcopy || 1; diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index 581ce66a3d4..90dde034e10 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -1366,3 +1366,7 @@ ERROR HY000: Incorrect prefix key; the used key part isn't a string, the used le CREATE INDEX i2 ON t1 (a(20)); ERROR HY000: Incorrect prefix key; the used key part isn't a string, the used length is longer than the key part, or the storage engine doesn't support unique prefix keys DROP TABLE t1; +CREATE TABLE t1 (id int); +INSERT INTO t1 VALUES (1), (2); +ALTER TABLE t1 ADD COLUMN (f1 INT), ADD COLUMN (f2 INT), ADD KEY f2k(f2); +DROP TABLE t1; diff --git a/mysql-test/r/bug39022.result b/mysql-test/r/bug39022.result index 5963709aa2a..75899ed686b 100644 --- a/mysql-test/r/bug39022.result +++ b/mysql-test/r/bug39022.result @@ -12,7 +12,7 @@ INSERT INTO t2 VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10), START TRANSACTION; # in thread2 REPLACE INTO t2 VALUES (-17); -SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d); +SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d) LOCK IN SHARE MODE; d # in thread1 REPLACE INTO t1(a,b) VALUES (67,20); @@ -21,10 +21,10 @@ COMMIT; START TRANSACTION; REPLACE INTO t1(a,b) VALUES (65,-50); REPLACE INTO t2 VALUES (-91); -SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d); +SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d) LOCK IN SHARE MODE; # in thread1 # should not crash -SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d); +SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d) LOCK IN SHARE MODE; ERROR 40001: Deadlock found when trying to get lock; try restarting transaction # in thread2 d diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index eb1437414e7..e37f9d580ba 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -1977,3 +1977,59 @@ CREATE TABLE t1 LIKE t2; ERROR 42S01: Table 't1' already exists DROP TABLE t2; DROP TABLE t1; +# +# Bug #48800 CREATE TABLE t...SELECT fails if t is a +# temporary table +# +CREATE TEMPORARY TABLE t1 (a INT); +CREATE TABLE t1 (a INT); +CREATE TEMPORARY TABLE t2 (a INT); +CREATE VIEW t2 AS SELECT 1; +CREATE TABLE t3 (a INT); +CREATE TEMPORARY TABLE t3 SELECT 1; +CREATE TEMPORARY TABLE t4 (a INT); +CREATE TABLE t4 AS SELECT 1; +DROP TEMPORARY TABLE t1, t2, t3, t4; +DROP TABLE t1, t3, t4; +DROP VIEW t2; +# +# Bug #49193 CREATE TABLE reacts differently depending +# on whether data is selected or not +# +CREATE TEMPORARY TABLE t2 (ID INT); +INSERT INTO t2 VALUES (1),(2),(3); +CREATE TEMPORARY TABLE t1 (ID INT); +CREATE TABLE IF NOT EXISTS t1 (ID INT); +INSERT INTO t1 SELECT * FROM t2; +SELECT * FROM t1; +ID +1 +2 +3 +DROP TEMPORARY TABLE t1; +SELECT * FROM t1; +ID +DROP TABLE t1; +CREATE TEMPORARY TABLE t1 (ID INT); +CREATE TABLE IF NOT EXISTS t1 SELECT * FROM t2; +SELECT * FROM t1; +ID +DROP TEMPORARY TABLE t1; +SELECT * FROM t1; +ID +1 +2 +3 +DROP TABLE t1; +CREATE TEMPORARY TABLE t1 (ID INT); +CREATE TABLE t1 SELECT * FROM t2; +SELECT * FROM t1; +ID +DROP TEMPORARY TABLE t1; +SELECT * FROM t1; +ID +1 +2 +3 +DROP TABLE t1; +DROP TEMPORARY TABLE t2; diff --git a/mysql-test/r/ctype_utf16.result b/mysql-test/r/ctype_utf16.result index 3c2fe316d71..c5fd7ef1439 100644 --- a/mysql-test/r/ctype_utf16.result +++ b/mysql-test/r/ctype_utf16.result @@ -1034,5 +1034,48 @@ DROP TABLE t1; SET max_sort_length=DEFAULT; SET NAMES latin1; # +# Bug#52520 Difference in tinytext utf column metadata +# +CREATE TABLE t1 ( +s1 TINYTEXT CHARACTER SET utf16, +s2 TEXT CHARACTER SET utf16, +s3 MEDIUMTEXT CHARACTER SET utf16, +s4 LONGTEXT CHARACTER SET utf16 +); +SET NAMES utf8, @@character_set_results=NULL; +SELECT *, HEX(s1) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 s1 s1 252 255 0 Y 16 0 54 +def test t1 t1 s2 s2 252 65535 0 Y 16 0 54 +def test t1 t1 s3 s3 252 16777215 0 Y 16 0 54 +def test t1 t1 s4 s4 252 4294967295 0 Y 16 0 54 +def HEX(s1) 253 6120 0 Y 0 0 33 +s1 s2 s3 s4 HEX(s1) +SET NAMES latin1; +SELECT *, HEX(s1) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 s1 s1 252 127 0 Y 16 0 8 +def test t1 t1 s2 s2 252 32767 0 Y 16 0 8 +def test t1 t1 s3 s3 252 8388607 0 Y 16 0 8 +def test t1 t1 s4 s4 252 2147483647 0 Y 16 0 8 +def HEX(s1) 253 2040 0 Y 0 0 8 +s1 s2 s3 s4 HEX(s1) +SET NAMES utf8; +SELECT *, HEX(s1) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 s1 s1 252 381 0 Y 16 0 33 +def test t1 t1 s2 s2 252 98301 0 Y 16 0 33 +def test t1 t1 s3 s3 252 25165821 0 Y 16 0 33 +def test t1 t1 s4 s4 252 4294967295 0 Y 16 0 33 +def HEX(s1) 253 6120 0 Y 0 0 33 +s1 s2 s3 s4 HEX(s1) +CREATE TABLE t2 AS SELECT CONCAT(s1) FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `CONCAT(s1)` varchar(255) CHARACTER SET utf16 DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1, t2; +# # End of 5.5 tests # diff --git a/mysql-test/r/ctype_utf32.result b/mysql-test/r/ctype_utf32.result index f0f10be9743..9f395f87be7 100644 --- a/mysql-test/r/ctype_utf32.result +++ b/mysql-test/r/ctype_utf32.result @@ -1048,5 +1048,48 @@ DROP TABLE t1; SET max_sort_length=DEFAULT; SET NAMES latin1; # +# Bug#52520 Difference in tinytext utf column metadata +# +CREATE TABLE t1 ( +s1 TINYTEXT CHARACTER SET utf32, +s2 TEXT CHARACTER SET utf32, +s3 MEDIUMTEXT CHARACTER SET utf32, +s4 LONGTEXT CHARACTER SET utf32 +); +SET NAMES utf8mb4, @@character_set_results=NULL; +SELECT *, HEX(s1) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 s1 s1 252 255 0 Y 16 0 60 +def test t1 t1 s2 s2 252 65535 0 Y 16 0 60 +def test t1 t1 s3 s3 252 16777215 0 Y 16 0 60 +def test t1 t1 s4 s4 252 4294967295 0 Y 16 0 60 +def HEX(s1) 253 8160 0 Y 0 0 45 +s1 s2 s3 s4 HEX(s1) +SET NAMES latin1; +SELECT *, HEX(s1) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 s1 s1 252 63 0 Y 16 0 8 +def test t1 t1 s2 s2 252 16383 0 Y 16 0 8 +def test t1 t1 s3 s3 252 4194303 0 Y 16 0 8 +def test t1 t1 s4 s4 252 1073741823 0 Y 16 0 8 +def HEX(s1) 253 2040 0 Y 0 0 8 +s1 s2 s3 s4 HEX(s1) +SET NAMES utf8mb4; +SELECT *, HEX(s1) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 s1 s1 252 252 0 Y 16 0 45 +def test t1 t1 s2 s2 252 65532 0 Y 16 0 45 +def test t1 t1 s3 s3 252 16777212 0 Y 16 0 45 +def test t1 t1 s4 s4 252 4294967292 0 Y 16 0 45 +def HEX(s1) 253 8160 0 Y 0 0 45 +s1 s2 s3 s4 HEX(s1) +CREATE TABLE t2 AS SELECT CONCAT(s1) FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `CONCAT(s1)` varchar(255) CHARACTER SET utf32 DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1, t2; +# # End of 5.5 tests # diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 03040d1676c..a4e7c4ef53a 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -2041,3 +2041,52 @@ predicted_order hex(utf8_encoding) 101 E0B78AE2808DE0B6BB DROP TABLE t1; End of 5.4 tests +# +# Start of 5.5 tests +# +# +# Bug#52520 Difference in tinytext utf column metadata +# +CREATE TABLE t1 ( +s1 TINYTEXT CHARACTER SET utf8, +s2 TEXT CHARACTER SET utf8, +s3 MEDIUMTEXT CHARACTER SET utf8, +s4 LONGTEXT CHARACTER SET utf8 +); +SET NAMES utf8, @@character_set_results=NULL; +SELECT *, HEX(s1) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 s1 s1 252 255 0 Y 16 0 33 +def test t1 t1 s2 s2 252 65535 0 Y 16 0 33 +def test t1 t1 s3 s3 252 16777215 0 Y 16 0 33 +def test t1 t1 s4 s4 252 4294967295 0 Y 16 0 33 +def HEX(s1) 253 4590 0 Y 0 0 33 +s1 s2 s3 s4 HEX(s1) +SET NAMES latin1; +SELECT *, HEX(s1) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 s1 s1 252 255 0 Y 16 0 8 +def test t1 t1 s2 s2 252 65535 0 Y 16 0 8 +def test t1 t1 s3 s3 252 16777215 0 Y 16 0 8 +def test t1 t1 s4 s4 252 4294967295 0 Y 16 0 8 +def HEX(s1) 253 1530 0 Y 0 0 8 +s1 s2 s3 s4 HEX(s1) +SET NAMES utf8; +SELECT *, HEX(s1) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 s1 s1 252 765 0 Y 16 0 33 +def test t1 t1 s2 s2 252 196605 0 Y 16 0 33 +def test t1 t1 s3 s3 252 50331645 0 Y 16 0 33 +def test t1 t1 s4 s4 252 4294967295 0 Y 16 0 33 +def HEX(s1) 253 4590 0 Y 0 0 33 +s1 s2 s3 s4 HEX(s1) +CREATE TABLE t2 AS SELECT CONCAT(s1) FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `CONCAT(s1)` varchar(255) CHARACTER SET utf8 DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1, t2; +# +# End of 5.5 tests +# diff --git a/mysql-test/r/ctype_utf8mb4.result b/mysql-test/r/ctype_utf8mb4.result index 4de7a192546..454c9d4bfbb 100644 --- a/mysql-test/r/ctype_utf8mb4.result +++ b/mysql-test/r/ctype_utf8mb4.result @@ -2471,6 +2471,49 @@ abc𐐀def 𐐀 DROP TABLE t1; # +# Bug#52520 Difference in tinytext utf column metadata +# +CREATE TABLE t1 ( +s1 TINYTEXT CHARACTER SET utf8mb4, +s2 TEXT CHARACTER SET utf8mb4, +s3 MEDIUMTEXT CHARACTER SET utf8mb4, +s4 LONGTEXT CHARACTER SET utf8mb4 +); +SET NAMES utf8mb4, @@character_set_results=NULL; +SELECT *, HEX(s1) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 s1 s1 252 255 0 Y 16 0 45 +def test t1 t1 s2 s2 252 65535 0 Y 16 0 45 +def test t1 t1 s3 s3 252 16777215 0 Y 16 0 45 +def test t1 t1 s4 s4 252 4294967295 0 Y 16 0 45 +def HEX(s1) 253 8160 0 Y 0 0 45 +s1 s2 s3 s4 HEX(s1) +SET NAMES latin1; +SELECT *, HEX(s1) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 s1 s1 252 255 0 Y 16 0 8 +def test t1 t1 s2 s2 252 65535 0 Y 16 0 8 +def test t1 t1 s3 s3 252 16777215 0 Y 16 0 8 +def test t1 t1 s4 s4 252 4294967295 0 Y 16 0 8 +def HEX(s1) 253 2040 0 Y 0 0 8 +s1 s2 s3 s4 HEX(s1) +SET NAMES utf8mb4; +SELECT *, HEX(s1) FROM t1; +Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr +def test t1 t1 s1 s1 252 1020 0 Y 16 0 45 +def test t1 t1 s2 s2 252 262140 0 Y 16 0 45 +def test t1 t1 s3 s3 252 67108860 0 Y 16 0 45 +def test t1 t1 s4 s4 252 4294967295 0 Y 16 0 45 +def HEX(s1) 253 8160 0 Y 0 0 45 +s1 s2 s3 s4 HEX(s1) +CREATE TABLE t2 AS SELECT CONCAT(s1) FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `CONCAT(s1)` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE t1, t2; +# # End of 5.5 tests # # diff --git a/mysql-test/r/errors.result b/mysql-test/r/errors.result index a3a8fe0b147..3d247a242a3 100644 --- a/mysql-test/r/errors.result +++ b/mysql-test/r/errors.result @@ -120,3 +120,17 @@ SET sql_quote_show_create= _utf8 x'5452C39C45'; ERROR 42000: Variable 'sql_quote_show_create' can't be set to the value of 'TRÜE' SET sql_quote_show_create=_latin1 x'5452DC45'; ERROR 42000: Variable 'sql_quote_show_create' can't be set to the value of 'TRÜE' +# +# Bug#52430 Incorrect key in the error message for duplicate key error involving BINARY type +# +CREATE TABLE t1(c1 BINARY(10), c2 BINARY(10), c3 BINARY(10), +PRIMARY KEY(c1,c2,c3)); +INSERT INTO t1 (c1,c2,c3) VALUES('abc','abc','abc'); +INSERT INTO t1 (c1,c2,c3) VALUES('abc','abc','abc'); +ERROR 23000: Duplicate entry 'abc-abc-abc' for key 'PRIMARY' +DROP TABLE t1; +CREATE TABLE t1 (f1 VARBINARY(19) PRIMARY KEY); +INSERT INTO t1 VALUES ('abc\0\0'); +INSERT INTO t1 VALUES ('abc\0\0'); +ERROR 23000: Duplicate entry 'abc\x00\x00' for key 'PRIMARY' +DROP TABLE t1; diff --git a/mysql-test/r/information_schema_part.result b/mysql-test/r/information_schema_part.result index 11c57ceb2c2..b34183ebdee 100644 --- a/mysql-test/r/information_schema_part.result +++ b/mysql-test/r/information_schema_part.result @@ -37,9 +37,9 @@ partitions 3; select * from information_schema.partitions where table_schema="test" and table_name="t4"; TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PARTITION_NAME SUBPARTITION_NAME PARTITION_ORDINAL_POSITION SUBPARTITION_ORDINAL_POSITION PARTITION_METHOD SUBPARTITION_METHOD PARTITION_EXPRESSION SUBPARTITION_EXPRESSION PARTITION_DESCRIPTION TABLE_ROWS AVG_ROW_LENGTH DATA_LENGTH MAX_DATA_LENGTH INDEX_LENGTH DATA_FREE CREATE_TIME UPDATE_TIME CHECK_TIME CHECKSUM PARTITION_COMMENT NODEGROUP TABLESPACE_NAME -def test t4 p0 NULL 1 NULL KEY NULL f1,f2 NULL NULL 0 0 0 # 1024 0 # # NULL NULL default NULL -def test t4 p1 NULL 2 NULL KEY NULL f1,f2 NULL NULL 0 0 0 # 1024 0 # # NULL NULL default NULL -def test t4 p2 NULL 3 NULL KEY NULL f1,f2 NULL NULL 0 0 0 # 1024 0 # # NULL NULL default NULL +def test t4 p0 NULL 1 NULL KEY NULL `f1`,`f2` NULL NULL 0 0 0 # 1024 0 # # NULL NULL default NULL +def test t4 p1 NULL 2 NULL KEY NULL `f1`,`f2` NULL NULL 0 0 0 # 1024 0 # # NULL NULL default NULL +def test t4 p2 NULL 3 NULL KEY NULL `f1`,`f2` NULL NULL 0 0 0 # 1024 0 # # NULL NULL default NULL drop table t1,t2,t3,t4; create table t1 (a int not null,b int not null,c int not null,primary key (a,b)) partition by range (a) @@ -67,10 +67,10 @@ def test t1 x1 x11 1 1 RANGE HASH a a+b 1 0 0 0 # 1024 0 # # NULL NULL default def test t1 x1 x12 1 2 RANGE HASH a a+b 1 0 0 0 # 1024 0 # # NULL NULL default t2 def test t1 x2 x21 2 1 RANGE HASH a a+b 5 0 0 0 # 1024 0 # # NULL NULL default t1 def test t1 x2 x22 2 2 RANGE HASH a a+b 5 0 0 0 # 1024 0 # # NULL NULL default t2 -def test t2 x1 x11 1 1 RANGE KEY a a 1 0 0 0 # 1024 0 # # NULL NULL default t1 -def test t2 x1 x12 1 2 RANGE KEY a a 1 0 0 0 # 1024 0 # # NULL NULL default t2 -def test t2 x2 x21 2 1 RANGE KEY a a 5 0 0 0 # 1024 0 # # NULL NULL default t1 -def test t2 x2 x22 2 2 RANGE KEY a a 5 0 0 0 # 1024 0 # # NULL NULL default t2 +def test t2 x1 x11 1 1 RANGE KEY a `a` 1 0 0 0 # 1024 0 # # NULL NULL default t1 +def test t2 x1 x12 1 2 RANGE KEY a `a` 1 0 0 0 # 1024 0 # # NULL NULL default t2 +def test t2 x2 x21 2 1 RANGE KEY a `a` 5 0 0 0 # 1024 0 # # NULL NULL default t1 +def test t2 x2 x22 2 2 RANGE KEY a `a` 5 0 0 0 # 1024 0 # # NULL NULL default t2 drop table t1,t2; create table t1 ( a int not null, diff --git a/mysql-test/r/innodb_bug21704.result b/mysql-test/r/innodb_bug21704.result deleted file mode 100644 index b8e0b15d50d..00000000000 --- a/mysql-test/r/innodb_bug21704.result +++ /dev/null @@ -1,55 +0,0 @@ -# -# Bug#21704: Renaming column does not update FK definition. -# - -# Test that it's not possible to rename columns participating in a -# foreign key (either in the referencing or referenced table). - -DROP TABLE IF EXISTS t1; -DROP TABLE IF EXISTS t2; -DROP TABLE IF EXISTS t3; -CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ROW_FORMAT=COMPACT ENGINE=INNODB; -CREATE TABLE t2 (a INT PRIMARY KEY, b INT, -CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1(a)) -ROW_FORMAT=COMPACT ENGINE=INNODB; -CREATE TABLE t3 (a INT PRIMARY KEY, b INT, KEY(b), C INT, -CONSTRAINT fk2 FOREIGN KEY (b) REFERENCES t3 (a)) -ROW_FORMAT=COMPACT ENGINE=INNODB; -INSERT INTO t1 VALUES (1,1),(2,2),(3,3); -INSERT INTO t2 VALUES (1,1),(2,2),(3,3); -INSERT INTO t3 VALUES (1,1,1),(2,2,2),(3,3,3); - -# Test renaming the column in the referenced table. - -ALTER TABLE t1 CHANGE a c INT; -ERROR HY000: Error on rename of '#sql-temporary' to './test/t1' (errno: 150) -# Ensure that online column rename works. -ALTER TABLE t1 CHANGE b c INT; -affected rows: 0 -info: Records: 0 Duplicates: 0 Warnings: 0 - -# Test renaming the column in the referencing table - -ALTER TABLE t2 CHANGE a c INT; -ERROR HY000: Error on rename of '#sql-temporary' to './test/t2' (errno: 150) -# Ensure that online column rename works. -ALTER TABLE t2 CHANGE b c INT; -affected rows: 0 -info: Records: 0 Duplicates: 0 Warnings: 0 - -# Test with self-referential constraints - -ALTER TABLE t3 CHANGE a d INT; -ERROR HY000: Error on rename of '#sql-temporary' to './test/t3' (errno: 150) -ALTER TABLE t3 CHANGE b d INT; -ERROR HY000: Error on rename of '#sql-temporary' to './test/t3' (errno: 150) -# Ensure that online column rename works. -ALTER TABLE t3 CHANGE c d INT; -affected rows: 0 -info: Records: 0 Duplicates: 0 Warnings: 0 - -# Cleanup. - -DROP TABLE t3; -DROP TABLE t2; -DROP TABLE t1; diff --git a/mysql-test/r/innodb_bug38231.result b/mysql-test/r/innodb_bug38231.result deleted file mode 100644 index 2f909779755..00000000000 --- a/mysql-test/r/innodb_bug38231.result +++ /dev/null @@ -1,11 +0,0 @@ -SET storage_engine=InnoDB; -INSERT INTO bug38231 VALUES (1), (10), (300); -SET autocommit=0; -SELECT * FROM bug38231 FOR UPDATE; -a -1 -10 -300 -TRUNCATE TABLE bug38231; -COMMIT; -DROP TABLE bug38231; diff --git a/mysql-test/r/innodb_bug44571.result b/mysql-test/r/innodb_bug44571.result deleted file mode 100644 index 36374edcb3e..00000000000 --- a/mysql-test/r/innodb_bug44571.result +++ /dev/null @@ -1,9 +0,0 @@ -CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; -ALTER TABLE bug44571 CHANGE foo bar INT; -ALTER TABLE bug44571 ADD INDEX bug44571b (foo); -ERROR 42000: Key column 'foo' doesn't exist in table -ALTER TABLE bug44571 ADD INDEX bug44571b (bar); -ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it -CREATE INDEX bug44571b ON bug44571 (bar); -ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it -DROP TABLE bug44571; diff --git a/mysql-test/r/innodb_mysql_lock.result b/mysql-test/r/innodb_mysql_lock.result index 375ae8aeb12..95adf712cb4 100644 --- a/mysql-test/r/innodb_mysql_lock.result +++ b/mysql-test/r/innodb_mysql_lock.result @@ -86,3 +86,33 @@ release_lock('bug42147_lock') UNLOCK TABLES; # Connection 1 DROP TABLE t1; +# +# Bug#53798 OPTIMIZE TABLE breaks repeatable read +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a INT) engine=innodb; +INSERT INTO t1 VALUES (1), (2), (3); +# Connection con1 +START TRANSACTION WITH CONSISTENT SNAPSHOT; +SELECT * FROM t1; +a +1 +2 +3 +# Connection default +# This should block +# Sending: +OPTIMIZE TABLE t1; +# Connection con1 +SELECT * FROM t1; +a +1 +2 +3 +COMMIT; +# Connection default +# Reaping OPTIMIZE TABLE t1 +Table Op Msg_type Msg_text +test.t1 optimize note Table does not support optimize, doing recreate + analyze instead +test.t1 optimize status OK +DROP TABLE t1; diff --git a/mysql-test/r/innodb_mysql_lock2.result b/mysql-test/r/innodb_mysql_lock2.result new file mode 100644 index 00000000000..aed704e6b3e --- /dev/null +++ b/mysql-test/r/innodb_mysql_lock2.result @@ -0,0 +1,564 @@ +# +# Test how do we handle locking in various cases when +# we read data from InnoDB tables. +# +# In fact by performing this test we check two things: +# 1) That SQL-layer correctly determine type of thr_lock.c +# lock to be acquired/passed to InnoDB engine. +# 2) That InnoDB engine correctly interprets this lock +# type and takes necessary row locks or does not +# take them if they are not necessary. +# +# This test makes sense only in REPEATABLE-READ mode as +# in SERIALIZABLE mode all statements that read data take +# shared lock on them to enforce its semantics. +select @@session.tx_isolation; +@@session.tx_isolation +REPEATABLE-READ +# Prepare playground by creating tables, views, +# routines and triggers used in tests. +drop table if exists t0, t1, t2, t3, t4, t5; +drop view if exists v1, v2; +drop procedure if exists p1; +drop procedure if exists p2; +drop function if exists f1; +drop function if exists f2; +drop function if exists f3; +drop function if exists f4; +drop function if exists f5; +drop function if exists f6; +drop function if exists f7; +drop function if exists f8; +drop function if exists f9; +drop function if exists f10; +drop function if exists f11; +drop function if exists f12; +drop function if exists f13; +drop function if exists f14; +drop function if exists f15; +create table t1 (i int primary key) engine=innodb; +insert into t1 values (1), (2), (3), (4), (5); +create table t2 (j int primary key) engine=innodb; +insert into t2 values (1), (2), (3), (4), (5); +create table t3 (k int primary key) engine=innodb; +insert into t3 values (1), (2), (3); +create table t4 (l int primary key) engine=innodb; +insert into t4 values (1); +create table t5 (l int primary key) engine=innodb; +insert into t5 values (1); +create view v1 as select i from t1; +create view v2 as select j from t2 where j in (select i from t1); +create procedure p1(k int) insert into t2 values (k); +create function f1() returns int +begin +declare j int; +select i from t1 where i = 1 into j; +return j; +end| +create function f2() returns int +begin +declare k int; +select i from t1 where i = 1 into k; +insert into t2 values (k + 5); +return 0; +end| +create function f3() returns int +begin +return (select i from t1 where i = 3); +end| +create function f4() returns int +begin +if (select i from t1 where i = 3) then +return 1; +else +return 0; +end if; +end| +create function f5() returns int +begin +insert into t2 values ((select i from t1 where i = 1) + 5); +return 0; +end| +create function f6() returns int +begin +declare k int; +select i from v1 where i = 1 into k; +return k; +end| +create function f7() returns int +begin +declare k int; +select j from v2 where j = 1 into k; +return k; +end| +create function f8() returns int +begin +declare k int; +select i from v1 where i = 1 into k; +insert into t2 values (k+5); +return k; +end| +create function f9() returns int +begin +update v2 set j=j+10 where j=1; +return 1; +end| +create function f10() returns int +begin +return f1(); +end| +create function f11() returns int +begin +declare k int; +set k= f1(); +insert into t2 values (k+5); +return k; +end| +create function f12(p int) returns int +begin +insert into t2 values (p); +return p; +end| +create function f13(p int) returns int +begin +return p; +end| +create procedure p2(inout p int) +begin +select i from t1 where i = 1 into p; +end| +create function f14() returns int +begin +declare k int; +call p2(k); +insert into t2 values (k+5); +return k; +end| +create function f15() returns int +begin +declare k int; +call p2(k); +return k; +end| +create trigger t4_bi before insert on t4 for each row +begin +declare k int; +select i from t1 where i=1 into k; +set new.l= k+1; +end| +create trigger t4_bu before update on t4 for each row +begin +if (select i from t1 where i=1) then +set new.l= 2; +end if; +end| +create trigger t4_bd before delete on t4 for each row +begin +if !(select i from v1 where i=1) then +signal sqlstate '45000'; +end if; +end| +create trigger t5_bi before insert on t5 for each row +begin +set new.l= f1()+1; +end| +create trigger t5_bu before update on t5 for each row +begin +declare j int; +call p2(j); +set new.l= j + 1; +end| +# +# Set common variables to be used by scripts called below. +# +# +# 1. Statements that read tables and do not use subqueries. +# +# +# 1.1 Simple SELECT statement. +# +# No locks are necessary as this statement won't be written +# to the binary log and thanks to how MyISAM works SELECT +# will see version of the table prior to concurrent insert. +Success: 'select * from t1' doesn't take row locks on 't1'. +# +# 1.2 Multi-UPDATE statement. +# +# Has to take shared locks on rows in the table being read as this +# statement will be written to the binary log and therefore should +# be serialized with concurrent statements. +Success: 'update t2, t1 set j= j - 1 where i = j' takes shared row locks on 't1'. +# +# 1.3 Multi-DELETE statement. +# +# The above is true for this statement as well. +Success: 'delete t2 from t1, t2 where i = j' takes shared row locks on 't1'. +# +# 1.4 DESCRIBE statement. +# +# This statement does not really read data from the +# target table and thus does not take any lock on it. +# We check this for completeness of coverage. +Success: 'describe t1' doesn't take row locks on 't1'. +# +# 1.5 SHOW statements. +# +# The above is true for SHOW statements as well. +Success: 'show create table t1' doesn't take row locks on 't1'. +Success: 'show keys from t1' doesn't take row locks on 't1'. +# +# 2. Statements which read tables through subqueries. +# +# +# 2.1 CALL with a subquery. +# +# A strong lock is not necessary as this statement is not +# written to the binary log as a whole (it is written +# statement-by-statement) and thanks to MVCC we can always get +# versions of rows prior to the update that has locked them. +# But in practice InnoDB does locking reads for all statements +# other than SELECT (unless it is a READ-COMITTED mode or +# innodb_locks_unsafe_for_binlog is ON). +Success: 'call p1((select i + 5 from t1 where i = 1))' takes shared row locks on 't1'. +# +# 2.2 CREATE TABLE with a subquery. +# +# Has to take shared locks on rows in the table being read as +# this statement is written to the binary log and therefore +# should be serialized with concurrent statements. +Success: 'create table t0 engine=innodb select * from t1' takes shared row locks on 't1'. +drop table t0; +Success: 'create table t0 engine=innodb select j from t2 where j in (select i from t1)' takes shared row locks on 't1'. +drop table t0; +# +# 2.3 DELETE with a subquery. +# +# The above is true for this statement as well. +Success: 'delete from t2 where j in (select i from t1)' takes shared row locks on 't1'. +# +# 2.4 MULTI-DELETE with a subquery. +# +# Same is true for this statement as well. +Success: 'delete t2 from t3, t2 where k = j and j in (select i from t1)' takes shared row locks on 't1'. +# +# 2.5 DO with a subquery. +# +# In theory should not take row locks as it is not logged. +# In practice InnoDB takes shared row locks. +Success: 'do (select i from t1 where i = 1)' takes shared row locks on 't1'. +# +# 2.6 INSERT with a subquery. +# +# Has to take shared locks on rows in the table being read as +# this statement is written to the binary log and therefore +# should be serialized with concurrent statements. +Success: 'insert into t2 select i+5 from t1' takes shared row locks on 't1'. +Success: 'insert into t2 values ((select i+5 from t1 where i = 4))' takes shared row locks on 't1'. +# +# 2.7 LOAD DATA with a subquery. +# +# The above is true for this statement as well. +Success: 'load data infile '../../std_data/rpl_loaddata.dat' into table t2 (@a, @b) set j= @b + (select i from t1 where i = 1)' takes shared row locks on 't1'. +# +# 2.8 REPLACE with a subquery. +# +# Same is true for this statement as well. +Success: 'replace into t2 select i+5 from t1' takes shared row locks on 't1'. +Success: 'replace into t2 values ((select i+5 from t1 where i = 4))' takes shared row locks on 't1'. +# +# 2.9 SELECT with a subquery. +# +# Locks are not necessary as this statement is not written +# to the binary log and thanks to MVCC we can always get +# versions of rows prior to the update that has locked them. +# +# Also serves as a test case for bug #46947 "Embedded SELECT +# without FOR UPDATE is causing a lock". +Success: 'select * from t2 where j in (select i from t1)' doesn't take row locks on 't1'. +# +# 2.10 SET with a subquery. +# +# In theory should not require locking as it is not written +# to the binary log. In practice InnoDB acquires shared row +# locks. +Success: 'set @a:= (select i from t1 where i = 1)' takes shared row locks on 't1'. +# +# 2.11 SHOW with a subquery. +# +# Similarly to the previous case, in theory should not require locking +# as it is not written to the binary log. In practice InnoDB +# acquires shared row locks. +Success: 'show tables from test where Tables_in_test = 't2' and (select i from t1 where i = 1)' takes shared row locks on 't1'. +Success: 'show columns from t2 where (select i from t1 where i = 1)' takes shared row locks on 't1'. +# +# 2.12 UPDATE with a subquery. +# +# Has to take shared locks on rows in the table being read as +# this statement is written to the binary log and therefore +# should be serialized with concurrent statements. +Success: 'update t2 set j= j-10 where j in (select i from t1)' takes shared row locks on 't1'. +# +# 2.13 MULTI-UPDATE with a subquery. +# +# Same is true for this statement as well. +Success: 'update t2, t3 set j= j -10 where j=k and j in (select i from t1)' takes shared row locks on 't1'. +# +# 3. Statements which read tables through a view. +# +# +# 3.1 SELECT statement which uses some table through a view. +# +# Since this statement is not written to the binary log +# and old version of rows are accessible thanks to MVCC, +# no locking is necessary. +Success: 'select * from v1' doesn't take row locks on 't1'. +Success: 'select * from v2' doesn't take row locks on 't1'. +Success: 'select * from t2 where j in (select i from v1)' doesn't take row locks on 't1'. +Success: 'select * from t3 where k in (select j from v2)' doesn't take row locks on 't1'. +# +# 3.2 Statements which modify a table and use views. +# +# Since such statements are going to be written to the binary +# log they need to be serialized against concurrent statements +# and therefore should take shared row locks on data read. +Success: 'update t2 set j= j-10 where j in (select i from v1)' takes shared row locks on 't1'. +Success: 'update t3 set k= k-10 where k in (select j from v2)' takes shared row locks on 't1'. +Success: 'update t2, v1 set j= j-10 where j = i' takes shared row locks on 't1'. +Success: 'update v2 set j= j-10 where j = 3' takes shared row locks on 't1'. +# +# 4. Statements which read tables through stored functions. +# +# +# 4.1 SELECT/SET with a stored function which does not +# modify data and uses SELECT in its turn. +# +# In theory there is no need to take row locks on the table +# being selected from in SF as the call to such function +# won't get into the binary log. In practice, however, we +# discover that fact too late in the process to be able to +# affect the decision what locks should be taken. +# Hence, strong locks are taken in this case. +Success: 'select f1()' takes shared row locks on 't1'. +Success: 'set @a:= f1()' takes shared row locks on 't1'. +# +# 4.2 INSERT (or other statement which modifies data) with +# a stored function which does not modify data and uses +# SELECT. +# +# Since such statement is written to the binary log it should +# be serialized with concurrent statements affecting the data +# it uses. Therefore it should take row locks on the data +# it reads. +Success: 'insert into t2 values (f1() + 5)' takes shared row locks on 't1'. +# +# 4.3 SELECT/SET with a stored function which +# reads and modifies data. +# +# Since a call to such function is written to the binary log, +# it should be serialized with concurrent statements affecting +# the data it uses. Hence, row locks on the data read +# should be taken. +Success: 'select f2()' takes shared row locks on 't1'. +Success: 'set @a:= f2()' takes shared row locks on 't1'. +# +# 4.4. SELECT/SET with a stored function which does not +# modify data and reads a table through subselect +# in a control construct. +# +# Again, in theory a call to this function won't get to the +# binary log and thus no locking is needed. But in practice +# we don't detect this fact early enough (get_lock_type_for_table()) +# to avoid taking row locks. +Success: 'select f3()' takes shared row locks on 't1'. +Success: 'set @a:= f3()' takes shared row locks on 't1'. +Success: 'select f4()' takes shared row locks on 't1'. +Success: 'set @a:= f4()' takes shared row locks on 't1'. +# +# 4.5. INSERT (or other statement which modifies data) with +# a stored function which does not modify data and reads +# the table through a subselect in one of its control +# constructs. +# +# Since such statement is written to the binary log it should +# be serialized with concurrent statements affecting data it +# uses. Therefore it should take row locks on the data +# it reads. +Success: 'insert into t2 values (f3() + 5)' takes shared row locks on 't1'. +Success: 'insert into t2 values (f4() + 6)' takes shared row locks on 't1'. +# +# 4.6 SELECT/SET which uses a stored function with +# DML which reads a table via a subquery. +# +# Since call to such function is written to the binary log +# it should be serialized with concurrent statements. +# Hence reads should take row locks. +Success: 'select f5()' takes shared row locks on 't1'. +Success: 'set @a:= f5()' takes shared row locks on 't1'. +# +# 4.7 SELECT/SET which uses a stored function which +# doesn't modify data and reads tables through +# a view. +# +# Once again, in theory, calls to such functions won't +# get into the binary log and thus don't need row +# locks. But in practice this fact is discovered +# too late to have any effect. +Success: 'select f6()' takes shared row locks on 't1'. +Success: 'set @a:= f6()' takes shared row locks on 't1'. +Success: 'select f7()' takes shared row locks on 't1'. +Success: 'set @a:= f7()' takes shared row locks on 't1'. +# +# 4.8 INSERT which uses stored function which +# doesn't modify data and reads a table +# through a view. +# +# Since such statement is written to the binary log and +# should be serialized with concurrent statements affecting +# the data it uses. Therefore it should take row locks on +# the rows it reads. +Success: 'insert into t3 values (f6() + 5)' takes shared row locks on 't1'. +Success: 'insert into t3 values (f7() + 5)' takes shared row locks on 't1'. +# +# 4.9 SELECT which uses a stored function which +# modifies data and reads tables through a view. +# +# Since a call to such function is written to the binary log +# it should be serialized with concurrent statements. +# Hence, reads should take row locks. +Success: 'select f8()' takes shared row locks on 't1'. +Success: 'select f9()' takes shared row locks on 't1'. +# +# 4.10 SELECT which uses stored function which doesn't modify +# data and reads a table indirectly, by calling another +# function. +# +# In theory, calls to such functions won't get into the binary +# log and thus don't need to acquire row locks. But in practice +# this fact is discovered too late to have any effect. +Success: 'select f10()' takes shared row locks on 't1'. +# +# 4.11 INSERT which uses a stored function which doesn't modify +# data and reads a table indirectly, by calling another +# function. +# +# Since such statement is written to the binary log, it should +# be serialized with concurrent statements affecting the data it +# uses. Therefore it should take row locks on data it reads. +Success: 'insert into t2 values (f10() + 5)' takes shared row locks on 't1'. +# +# 4.12 SELECT which uses a stored function which modifies +# data and reads a table indirectly, by calling another +# function. +# +# Since a call to such function is written to the binary log +# it should be serialized from concurrent statements. +# Hence, reads should take row locks. +Success: 'select f11()' takes shared row locks on 't1'. +# +# 4.13 SELECT that reads a table through a subquery passed +# as a parameter to a stored function which modifies +# data. +# +# Even though a call to this function is written to the +# binary log, values of its parameters are written as literals. +# So there is no need to acquire row locks on rows used in +# the subquery. +Success: 'select f12((select i+10 from t1 where i=1))' doesn't take row locks on 't1'. +# +# 4.14 INSERT that reads a table via a subquery passed +# as a parameter to a stored function which doesn't +# modify data. +# +# Since this statement is written to the binary log it should +# be serialized with concurrent statements affecting the data it +# uses. Therefore it should take row locks on the data it reads. +Success: 'insert into t2 values (f13((select i+10 from t1 where i=1)))' takes shared row locks on 't1'. +# +# 5. Statements that read tables through stored procedures. +# +# +# 5.1 CALL statement which reads a table via SELECT. +# +# Since neither this statement nor its components are +# written to the binary log, there is no need to take +# row locks on the data it reads. +Success: 'call p2(@a)' doesn't take row locks on 't1'. +# +# 5.2 Function that modifes data and uses CALL, +# which reads a table through SELECT. +# +# Since a call to such function is written to the binary +# log, it should be serialized with concurrent statements. +# Hence, in this case reads should take row locks on data. +Success: 'select f14()' takes shared row locks on 't1'. +# +# 5.3 SELECT that calls a function that doesn't modify data and +# uses a CALL statement that reads a table via SELECT. +# +# In theory, calls to such functions won't get into the binary +# log and thus don't need to acquire row locks. But in practice +# this fact is discovered too late to have any effect. +Success: 'select f15()' takes shared row locks on 't1'. +# +# 5.4 INSERT which calls function which doesn't modify data and +# uses CALL statement which reads table through SELECT. +# +# Since such statement is written to the binary log it should +# be serialized with concurrent statements affecting data it +# uses. Therefore it should take row locks on data it reads. +Success: 'insert into t2 values (f15()+5)' takes shared row locks on 't1'. +# +# 6. Statements that use triggers. +# +# +# 6.1 Statement invoking a trigger that reads table via SELECT. +# +# Since this statement is written to the binary log it should +# be serialized with concurrent statements affecting the data +# it uses. Therefore, it should take row locks on the data +# it reads. +Success: 'insert into t4 values (2)' takes shared row locks on 't1'. +# +# 6.2 Statement invoking a trigger that reads table through +# a subquery in a control construct. +# +# The above is true for this statement as well. +Success: 'update t4 set l= 2 where l = 1' takes shared row locks on 't1'. +# +# 6.3 Statement invoking a trigger that reads a table through +# a view. +# +# And for this statement. +Success: 'delete from t4 where l = 1' takes shared row locks on 't1'. +# +# 6.4 Statement invoking a trigger that reads a table through +# a stored function. +# +# And for this statement. +Success: 'insert into t5 values (2)' takes shared row locks on 't1'. +# +# 6.5 Statement invoking a trigger that reads a table through +# stored procedure. +# +# And for this statement. +Success: 'update t5 set l= 2 where l = 1' takes shared row locks on 't1'. +# Clean-up. +drop function f1; +drop function f2; +drop function f3; +drop function f4; +drop function f5; +drop function f6; +drop function f7; +drop function f8; +drop function f9; +drop function f10; +drop function f11; +drop function f12; +drop function f13; +drop function f14; +drop function f15; +drop view v1, v2; +drop procedure p1; +drop procedure p2; +drop table t1, t2, t3, t4, t5; diff --git a/mysql-test/r/lock_sync.result b/mysql-test/r/lock_sync.result index 18f3f6bc1a7..e6265f1cb5e 100644 --- a/mysql-test/r/lock_sync.result +++ b/mysql-test/r/lock_sync.result @@ -1,4 +1,596 @@ # +# Test how we handle locking in various cases when +# we read data from MyISAM tables. +# +# In this test we mostly check that the SQL-layer correctly +# determines the type of thr_lock.c lock for a table being +# read. +# I.e. that it disallows concurrent inserts when the statement +# is going to be written to the binary log and therefore +# should be serialized, and allows concurrent inserts when +# such serialization is not necessary (e.g. when +# the statement is not written to binary log). +# +# Force concurrent inserts to be performed even if the table +# has gaps. This allows to simplify clean up in scripts +# used below (instead of backing up table being inserted +# into and then restoring it from backup at the end of the +# script we can simply delete rows which were inserted). +set @old_concurrent_insert= @@global.concurrent_insert; +set @@global.concurrent_insert= 2; +select @@global.concurrent_insert; +@@global.concurrent_insert +ALWAYS +# Prepare playground by creating tables, views, +# routines and triggers used in tests. +drop table if exists t0, t1, t2, t3, t4, t5; +drop view if exists v1, v2; +drop procedure if exists p1; +drop procedure if exists p2; +drop function if exists f1; +drop function if exists f2; +drop function if exists f3; +drop function if exists f4; +drop function if exists f5; +drop function if exists f6; +drop function if exists f7; +drop function if exists f8; +drop function if exists f9; +drop function if exists f10; +drop function if exists f11; +drop function if exists f12; +drop function if exists f13; +drop function if exists f14; +drop function if exists f15; +create table t1 (i int primary key); +insert into t1 values (1), (2), (3), (4), (5); +create table t2 (j int primary key); +insert into t2 values (1), (2), (3), (4), (5); +create table t3 (k int primary key); +insert into t3 values (1), (2), (3); +create table t4 (l int primary key); +insert into t4 values (1); +create table t5 (l int primary key); +insert into t5 values (1); +create view v1 as select i from t1; +create view v2 as select j from t2 where j in (select i from t1); +create procedure p1(k int) insert into t2 values (k); +create function f1() returns int +begin +declare j int; +select i from t1 where i = 1 into j; +return j; +end| +create function f2() returns int +begin +declare k int; +select i from t1 where i = 1 into k; +insert into t2 values (k + 5); +return 0; +end| +create function f3() returns int +begin +return (select i from t1 where i = 3); +end| +create function f4() returns int +begin +if (select i from t1 where i = 3) then +return 1; +else +return 0; +end if; +end| +create function f5() returns int +begin +insert into t2 values ((select i from t1 where i = 1) + 5); +return 0; +end| +create function f6() returns int +begin +declare k int; +select i from v1 where i = 1 into k; +return k; +end| +create function f7() returns int +begin +declare k int; +select j from v2 where j = 1 into k; +return k; +end| +create function f8() returns int +begin +declare k int; +select i from v1 where i = 1 into k; +insert into t2 values (k+5); +return k; +end| +create function f9() returns int +begin +update v2 set j=j+10 where j=1; +return 1; +end| +create function f10() returns int +begin +return f1(); +end| +create function f11() returns int +begin +declare k int; +set k= f1(); +insert into t2 values (k+5); +return k; +end| +create function f12(p int) returns int +begin +insert into t2 values (p); +return p; +end| +create function f13(p int) returns int +begin +return p; +end| +create procedure p2(inout p int) +begin +select i from t1 where i = 1 into p; +end| +create function f14() returns int +begin +declare k int; +call p2(k); +insert into t2 values (k+5); +return k; +end| +create function f15() returns int +begin +declare k int; +call p2(k); +return k; +end| +create trigger t4_bi before insert on t4 for each row +begin +declare k int; +select i from t1 where i=1 into k; +set new.l= k+1; +end| +create trigger t4_bu before update on t4 for each row +begin +if (select i from t1 where i=1) then +set new.l= 2; +end if; +end| +create trigger t4_bd before delete on t4 for each row +begin +if !(select i from v1 where i=1) then +signal sqlstate '45000'; +end if; +end| +create trigger t5_bi before insert on t5 for each row +begin +set new.l= f1()+1; +end| +create trigger t5_bu before update on t5 for each row +begin +declare j int; +call p2(j); +set new.l= j + 1; +end| +# +# Set common variables to be used by the scripts +# called below. +# +# Switch to connection 'con1'. +# Cache all functions used in the tests below so statements +# calling them won't need to open and lock mysql.proc table +# and we can assume that each statement locks its tables +# once during its execution. +show create procedure p1; +show create procedure p2; +show create function f1; +show create function f2; +show create function f3; +show create function f4; +show create function f5; +show create function f6; +show create function f7; +show create function f8; +show create function f9; +show create function f10; +show create function f11; +show create function f12; +show create function f13; +show create function f14; +show create function f15; +# Switch back to connection 'default'. +# +# 1. Statements that read tables and do not use subqueries. +# +# +# 1.1 Simple SELECT statement. +# +# No locks are necessary as this statement won't be written +# to the binary log and thanks to how MyISAM works SELECT +# will see version of the table prior to concurrent insert. +Success: 'select * from t1' allows concurrent inserts into 't1'. +# +# 1.2 Multi-UPDATE statement. +# +# Has to take shared locks on rows in the table being read as this +# statement will be written to the binary log and therefore should +# be serialized with concurrent statements. +Success: 'update t2, t1 set j= j - 1 where i = j' doesn't allow concurrent inserts into 't1'. +# +# 1.3 Multi-DELETE statement. +# +# The above is true for this statement as well. +Success: 'delete t2 from t1, t2 where i = j' doesn't allow concurrent inserts into 't1'. +# +# 1.4 DESCRIBE statement. +# +# This statement does not really read data from the +# target table and thus does not take any lock on it. +# We check this for completeness of coverage. +lock table t1 write; +# Switching to connection 'con1'. +# This statement should not be blocked. +describe t1; +# Switching to connection 'default'. +unlock tables; +# +# 1.5 SHOW statements. +# +# The above is true for SHOW statements as well. +lock table t1 write; +# Switching to connection 'con1'. +# These statements should not be blocked. +show keys from t1; +# Switching to connection 'default'. +unlock tables; +# +# 2. Statements which read tables through subqueries. +# +# +# 2.1 CALL with a subquery. +# +# A strong lock is not necessary as this statement is not +# written to the binary log as a whole (it is written +# statement-by-statement). +Success: 'call p1((select i + 5 from t1 where i = 1))' allows concurrent inserts into 't1'. +# +# 2.2 CREATE TABLE with a subquery. +# +# Has to take a strong lock on the table being read as +# this statement is written to the binary log and therefore +# should be serialized with concurrent statements. +Success: 'create table t0 select * from t1' doesn't allow concurrent inserts into 't1'. +drop table t0; +Success: 'create table t0 select j from t2 where j in (select i from t1)' doesn't allow concurrent inserts into 't1'. +drop table t0; +# +# 2.3 DELETE with a subquery. +# +# The above is true for this statement as well. +Success: 'delete from t2 where j in (select i from t1)' doesn't allow concurrent inserts into 't1'. +# +# 2.4 MULTI-DELETE with a subquery. +# +# Same is true for this statement as well. +Success: 'delete t2 from t3, t2 where k = j and j in (select i from t1)' doesn't allow concurrent inserts into 't1'. +# +# 2.5 DO with a subquery. +# +# A strong lock is not necessary as it is not logged. +Success: 'do (select i from t1 where i = 1)' allows concurrent inserts into 't1'. +# +# 2.6 INSERT with a subquery. +# +# Has to take a strong lock on the table being read as +# this statement is written to the binary log and therefore +# should be serialized with concurrent inserts. +Success: 'insert into t2 select i+5 from t1' doesn't allow concurrent inserts into 't1'. +Success: 'insert into t2 values ((select i+5 from t1 where i = 4))' doesn't allow concurrent inserts into 't1'. +# +# 2.7 LOAD DATA with a subquery. +# +# The above is true for this statement as well. +Success: 'load data infile '../../std_data/rpl_loaddata.dat' into table t2 (@a, @b) set j= @b + (select i from t1 where i = 1)' doesn't allow concurrent inserts into 't1'. +# +# 2.8 REPLACE with a subquery. +# +# Same is true for this statement as well. +Success: 'replace into t2 select i+5 from t1' doesn't allow concurrent inserts into 't1'. +Success: 'replace into t2 values ((select i+5 from t1 where i = 4))' doesn't allow concurrent inserts into 't1'. +# +# 2.9 SELECT with a subquery. +# +# Strong locks are not necessary as this statement is not written +# to the binary log and thanks to how MyISAM works this statement +# sees a version of the table prior to the concurrent insert. +Success: 'select * from t2 where j in (select i from t1)' allows concurrent inserts into 't1'. +# +# 2.10 SET with a subquery. +# +# The same is true for this statement as well. +Success: 'set @a:= (select i from t1 where i = 1)' allows concurrent inserts into 't1'. +# +# 2.11 SHOW with a subquery. +# +# And for this statement too. +Success: 'show tables from test where Tables_in_test = 't2' and (select i from t1 where i = 1)' allows concurrent inserts into 't1'. +Success: 'show columns from t2 where (select i from t1 where i = 1)' allows concurrent inserts into 't1'. +# +# 2.12 UPDATE with a subquery. +# +# Has to take a strong lock on the table being read as +# this statement is written to the binary log and therefore +# should be serialized with concurrent inserts. +Success: 'update t2 set j= j-10 where j in (select i from t1)' doesn't allow concurrent inserts into 't1'. +# +# 2.13 MULTI-UPDATE with a subquery. +# +# Same is true for this statement as well. +Success: 'update t2, t3 set j= j -10 where j=k and j in (select i from t1)' doesn't allow concurrent inserts into 't1'. +# +# 3. Statements which read tables through a view. +# +# +# 3.1 SELECT statement which uses some table through a view. +# +# Since this statement is not written to the binary log and +# an old version of the table is accessible thanks to how MyISAM +# handles concurrent insert, no locking is necessary. +Success: 'select * from v1' allows concurrent inserts into 't1'. +Success: 'select * from v2' allows concurrent inserts into 't1'. +Success: 'select * from t2 where j in (select i from v1)' allows concurrent inserts into 't1'. +Success: 'select * from t3 where k in (select j from v2)' allows concurrent inserts into 't1'. +# +# 3.2 Statements which modify a table and use views. +# +# Since such statements are going to be written to the binary +# log they need to be serialized against concurrent statements +# and therefore should take strong locks on the data read. +Success: 'update t2 set j= j-10 where j in (select i from v1)' doesn't allow concurrent inserts into 't1'. +Success: 'update t3 set k= k-10 where k in (select j from v2)' doesn't allow concurrent inserts into 't1'. +Success: 'update t2, v1 set j= j-10 where j = i' doesn't allow concurrent inserts into 't1'. +Success: 'update v2 set j= j-10 where j = 3' doesn't allow concurrent inserts into 't1'. +# +# 4. Statements which read tables through stored functions. +# +# +# 4.1 SELECT/SET with a stored function which does not +# modify data and uses SELECT in its turn. +# +# In theory there is no need to take strong locks on the table +# being selected from in SF as the call to such function +# won't get into the binary log. In practice, however, we +# discover that fact too late in the process to be able to +# affect the decision what locks should be taken. +# Hence, strong locks are taken in this case. +Success: 'select f1()' doesn't allow concurrent inserts into 't1'. +Success: 'set @a:= f1()' doesn't allow concurrent inserts into 't1'. +# +# 4.2 INSERT (or other statement which modifies data) with +# a stored function which does not modify data and uses +# SELECT. +# +# Since such statement is written to the binary log it should +# be serialized with concurrent statements affecting the data +# it uses. Therefore it should take strong lock on the data +# it reads. +Success: 'insert into t2 values (f1() + 5)' doesn't allow concurrent inserts into 't1'. +# +# 4.3 SELECT/SET with a stored function which +# reads and modifies data. +# +# Since a call to such function is written to the binary log, +# it should be serialized with concurrent statements affecting +# the data it uses. Hence, a strong lock on the data read +# should be taken. +Success: 'select f2()' doesn't allow concurrent inserts into 't1'. +Success: 'set @a:= f2()' doesn't allow concurrent inserts into 't1'. +# +# 4.4. SELECT/SET with a stored function which does not +# modify data and reads a table through subselect +# in a control construct. +# +# Again, in theory a call to this function won't get to the +# binary log and thus no strong lock is needed. But in practice +# we don't detect this fact early enough (get_lock_type_for_table()) +# to avoid taking a strong lock. +Success: 'select f3()' doesn't allow concurrent inserts into 't1'. +Success: 'set @a:= f3()' doesn't allow concurrent inserts into 't1'. +Success: 'select f4()' doesn't allow concurrent inserts into 't1'. +Success: 'set @a:= f4()' doesn't allow concurrent inserts into 't1'. +# +# 4.5. INSERT (or other statement which modifies data) with +# a stored function which does not modify data and reads +# the table through a subselect in one of its control +# constructs. +# +# Since such statement is written to the binary log it should +# be serialized with concurrent statements affecting data it +# uses. Therefore it should take a strong lock on the data +# it reads. +Success: 'insert into t2 values (f3() + 5)' doesn't allow concurrent inserts into 't1'. +Success: 'insert into t2 values (f4() + 6)' doesn't allow concurrent inserts into 't1'. +# +# 4.6 SELECT/SET which uses a stored function with +# DML which reads a table via a subquery. +# +# Since call to such function is written to the binary log +# it should be serialized with concurrent statements. +# Hence reads should take a strong lock. +Success: 'select f5()' doesn't allow concurrent inserts into 't1'. +Success: 'set @a:= f5()' doesn't allow concurrent inserts into 't1'. +# +# 4.7 SELECT/SET which uses a stored function which +# doesn't modify data and reads tables through +# a view. +# +# Once again, in theory, calls to such functions won't +# get into the binary log and thus don't need strong +# locks. But in practice this fact is discovered +# too late to have any effect. +Success: 'select f6()' doesn't allow concurrent inserts into 't1'. +Success: 'set @a:= f6()' doesn't allow concurrent inserts into 't1'. +Success: 'select f7()' doesn't allow concurrent inserts into 't1'. +Success: 'set @a:= f7()' doesn't allow concurrent inserts into 't1'. +# +# 4.8 INSERT which uses stored function which +# doesn't modify data and reads a table +# through a view. +# +# Since such statement is written to the binary log and +# should be serialized with concurrent statements affecting +# the data it uses. Therefore it should take a strong lock on +# the table it reads. +Success: 'insert into t3 values (f6() + 5)' doesn't allow concurrent inserts into 't1'. +Success: 'insert into t3 values (f7() + 5)' doesn't allow concurrent inserts into 't1'. +# +# 4.9 SELECT which uses a stored function which +# modifies data and reads tables through a view. +# +# Since a call to such function is written to the binary log +# it should be serialized with concurrent statements. +# Hence, reads should take strong locks. +Success: 'select f8()' doesn't allow concurrent inserts into 't1'. +Success: 'select f9()' doesn't allow concurrent inserts into 't1'. +# +# 4.10 SELECT which uses a stored function which doesn't modify +# data and reads a table indirectly, by calling another +# function. +# +# In theory, calls to such functions won't get into the binary +# log and thus don't need to acquire strong locks. But in practice +# this fact is discovered too late to have any effect. +Success: 'select f10()' doesn't allow concurrent inserts into 't1'. +# +# 4.11 INSERT which uses a stored function which doesn't modify +# data and reads a table indirectly, by calling another +# function. +# +# Since such statement is written to the binary log, it should +# be serialized with concurrent statements affecting the data it +# uses. Therefore it should take strong locks on data it reads. +Success: 'insert into t2 values (f10() + 5)' doesn't allow concurrent inserts into 't1'. +# +# 4.12 SELECT which uses a stored function which modifies +# data and reads a table indirectly, by calling another +# function. +# +# Since a call to such function is written to the binary log +# it should be serialized from concurrent statements. +# Hence, read should take a strong lock. +Success: 'select f11()' doesn't allow concurrent inserts into 't1'. +# +# 4.13 SELECT that reads a table through a subquery passed +# as a parameter to a stored function which modifies +# data. +# +# Even though a call to this function is written to the +# binary log, values of its parameters are written as literals. +# So there is no need to acquire strong locks for tables used in +# the subquery. +Success: 'select f12((select i+10 from t1 where i=1))' allows concurrent inserts into 't1'. +# +# 4.14 INSERT that reads a table via a subquery passed +# as a parameter to a stored function which doesn't +# modify data. +# +# Since this statement is written to the binary log it should +# be serialized with concurrent statements affecting the data it +# uses. Therefore it should take strong locks on the data it reads. +Success: 'insert into t2 values (f13((select i+10 from t1 where i=1)))' doesn't allow concurrent inserts into 't1'. +# +# 5. Statements that read tables through stored procedures. +# +# +# 5.1 CALL statement which reads a table via SELECT. +# +# Since neither this statement nor its components are +# written to the binary log, there is no need to take +# strong locks on the data it reads. +Success: 'call p2(@a)' allows concurrent inserts into 't1'. +# +# 5.2 Function that modifes data and uses CALL, +# which reads a table through SELECT. +# +# Since a call to such function is written to the binary +# log, it should be serialized with concurrent statements. +# Hence, in this case reads should take strong locks on data. +Success: 'select f14()' doesn't allow concurrent inserts into 't1'. +# +# 5.3 SELECT that calls a function that doesn't modify data and +# uses a CALL statement that reads a table via SELECT. +# +# In theory, calls to such functions won't get into the binary +# log and thus don't need to acquire strong locks. But in practice +# this fact is discovered too late to have any effect. +Success: 'select f15()' doesn't allow concurrent inserts into 't1'. +# +# 5.4 INSERT which calls function which doesn't modify data and +# uses CALL statement which reads table through SELECT. +# +# Since such statement is written to the binary log it should +# be serialized with concurrent statements affecting data it +# uses. Therefore it should take strong locks on data it reads. +Success: 'insert into t2 values (f15()+5)' doesn't allow concurrent inserts into 't1'. +# +# 6. Statements that use triggers. +# +# +# 6.1 Statement invoking a trigger that reads table via SELECT. +# +# Since this statement is written to the binary log it should +# be serialized with concurrent statements affecting the data +# it uses. Therefore, it should take strong locks on the data +# it reads. +Success: 'insert into t4 values (2)' doesn't allow concurrent inserts into 't1'. +# +# 6.2 Statement invoking a trigger that reads table through +# a subquery in a control construct. +# +# The above is true for this statement as well. +Success: 'update t4 set l= 2 where l = 1' doesn't allow concurrent inserts into 't1'. +# +# 6.3 Statement invoking a trigger that reads a table through +# a view. +# +# And for this statement. +Success: 'delete from t4 where l = 1' doesn't allow concurrent inserts into 't1'. +# +# 6.4 Statement invoking a trigger that reads a table through +# a stored function. +# +# And for this statement. +Success: 'insert into t5 values (2)' doesn't allow concurrent inserts into 't1'. +# +# 6.5 Statement invoking a trigger that reads a table through +# stored procedure. +# +# And for this statement. +Success: 'update t5 set l= 2 where l = 1' doesn't allow concurrent inserts into 't1'. +# Clean-up. +drop function f1; +drop function f2; +drop function f3; +drop function f4; +drop function f5; +drop function f6; +drop function f7; +drop function f8; +drop function f9; +drop function f10; +drop function f11; +drop function f12; +drop function f13; +drop function f14; +drop function f15; +drop view v1, v2; +drop procedure p1; +drop procedure p2; +drop table t1, t2, t3, t4, t5; +set @@global.concurrent_insert= @old_concurrent_insert; +# # Test for bug #45143 "All connections hang on concurrent ALTER TABLE". # # Concurrent execution of statements which required weak write lock diff --git a/mysql-test/r/mdl_sync.result b/mysql-test/r/mdl_sync.result index 984f0df3d0e..b78b8dadc77 100644 --- a/mysql-test/r/mdl_sync.result +++ b/mysql-test/r/mdl_sync.result @@ -2381,3 +2381,17 @@ commit; # Reap ALTER TABLE. set debug_sync= 'RESET'; drop table t1; +# +# Bug#52856 concurrent show columns or show full columns causes a crash!!! +# +CREATE TABLE t1(a CHAR(255)); +SET DEBUG_SYNC= "get_schema_column SIGNAL waiting WAIT_FOR completed"; +SHOW FULL COLUMNS FROM t1; +SET DEBUG_SYNC= "now WAIT_FOR waiting"; +SHOW FULL COLUMNS FROM t1; +Field Type Collation Null Key Default Extra Privileges Comment +a char(255) latin1_swedish_ci YES NULL # +SET DEBUG_SYNC= "now SIGNAL completed"; +Field Type Collation Null Key Default Extra Privileges Comment +a char(255) latin1_swedish_ci YES NULL # +DROP TABLE t1; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index ff9b1a84dbc..e46d8e75ab1 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -277,7 +277,7 @@ t3 CREATE TABLE `t3` ( drop table t3,t2,t1; create table t1 (a int not null, key(a)) engine=merge; select * from t1; -ERROR HY000: Got error 124 from storage engine +a drop table t1; create table t1 (a int not null, b int not null, key(a,b)); create table t2 (a int not null, b int not null, key(a,b)); @@ -988,6 +988,11 @@ m1 CREATE TABLE `m1` ( `a` int(11) DEFAULT NULL ) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1, m1; +CREATE TABLE t1(a INT, KEY(a)) ENGINE=merge; +SELECT MAX(a) FROM t1; +MAX(a) +NULL +DROP TABLE t1; CREATE TABLE t1(a INT); CREATE TABLE t2(a VARCHAR(10)); CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(t1, t2); diff --git a/mysql-test/r/mysqlshow.result b/mysql-test/r/mysqlshow.result index 4293465df67..f7b5869a3e3 100644 --- a/mysql-test/r/mysqlshow.result +++ b/mysql-test/r/mysqlshow.result @@ -109,13 +109,20 @@ Database: information_schema | TRIGGERS | | USER_PRIVILEGES | | VIEWS | -| INNODB_CMP_RESET | +| INNODB_SYS_FIELDS | | INNODB_TRX | -| INNODB_CMPMEM_RESET | +| INNODB_SYS_INDEXES | | INNODB_LOCK_WAITS | -| INNODB_CMPMEM | +| INNODB_SYS_TABLESTATS | | INNODB_CMP | +| INNODB_SYS_COLUMNS | +| INNODB_CMP_RESET | +| INNODB_SYS_FOREIGN_COLS | | INNODB_LOCKS | +| INNODB_CMPMEM_RESET | +| INNODB_CMPMEM | +| INNODB_SYS_FOREIGN | +| INNODB_SYS_TABLES | +---------------------------------------+ Database: INFORMATION_SCHEMA +---------------------------------------+ @@ -151,13 +158,20 @@ Database: INFORMATION_SCHEMA | TRIGGERS | | USER_PRIVILEGES | | VIEWS | -| INNODB_CMP_RESET | +| INNODB_SYS_FIELDS | | INNODB_TRX | -| INNODB_CMPMEM_RESET | +| INNODB_SYS_INDEXES | | INNODB_LOCK_WAITS | -| INNODB_CMPMEM | +| INNODB_SYS_TABLESTATS | | INNODB_CMP | +| INNODB_SYS_COLUMNS | +| INNODB_CMP_RESET | +| INNODB_SYS_FOREIGN_COLS | | INNODB_LOCKS | +| INNODB_CMPMEM_RESET | +| INNODB_CMPMEM | +| INNODB_SYS_FOREIGN | +| INNODB_SYS_TABLES | +---------------------------------------+ Wildcard: inf_rmation_schema +--------------------+ diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 6827fd0bc76..fa5d8142baf 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -1618,3 +1618,32 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 ALL NULL NULL NULL NULL 10 Using join buffer DROP TABLE t1, t2; End of 5.1 tests +# +# Bug #38745: MySQL 5.1 optimizer uses filesort for ORDER BY +# when it should use index +# +CREATE TABLE t1 (i1 integer NOT NULL PRIMARY KEY); +CREATE TABLE t2 (i2 integer NOT NULL PRIMARY KEY); +CREATE TABLE t3 (i3 integer); +INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12); +INSERT INTO t2 SELECT * FROM t1; +EXPLAIN EXTENDED +SELECT t1.*, t2.* FROM t1 JOIN t2 ON t1.i1 = t2.i2 +LEFT JOIN t3 ON t2.i2 = t3.i3 +ORDER BY t1.i1 LIMIT 5; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t3 system NULL NULL NULL NULL 0 0.00 const row not found +1 SIMPLE t1 index PRIMARY PRIMARY 4 NULL 5 240.00 Using index +1 SIMPLE t2 eq_ref PRIMARY PRIMARY 4 test.t1.i1 1 100.00 Using index +Warnings: +Note 1003 select `test`.`t1`.`i1` AS `i1`,`test`.`t2`.`i2` AS `i2` from `test`.`t1` join `test`.`t2` where (`test`.`t2`.`i2` = `test`.`t1`.`i1`) order by `test`.`t1`.`i1` limit 5 +SELECT t1.*, t2.* FROM t1 JOIN t2 ON t1.i1 = t2.i2 +LEFT JOIN t3 ON t2.i2 = t3.i3 +ORDER BY t1.i1 LIMIT 5; +i1 i2 +1 1 +2 2 +3 3 +4 4 +5 5 +DROP TABLE t1, t2, t3; diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result index 80d520007a4..55366bd2e07 100644 --- a/mysql-test/r/partition.result +++ b/mysql-test/r/partition.result @@ -1,4 +1,46 @@ drop table if exists t1, t2; +# Bug#39338: Fieldnames in +# INFORMATIONSCHEMA.PARTITIONS.PARTITION_EXPRESSION become unescaped +# NOTE: the partition expression is saved as a string, so changing from +# normal quotes to ansi quotes does not change the expression, only +# for partition by KEY. +CREATE TABLE t1 ( +ID int(11) NOT NULL, +`aaaa,aaaaa` tinyint(3) UNSIGNED NOT NULL DEFAULT '0', +ddddddddd int(11) NOT NULL DEFAULT '0', +new_field0 varchar(50), +PRIMARY KEY(ID, `aaaa,aaaaa`, ddddddddd)) +PARTITION BY RANGE(ID) +PARTITIONS 3 +SUBPARTITION BY LINEAR KEY(ID,`aaaa,aaaaa`) +SUBPARTITIONS 2 ( +PARTITION p01 VALUES LESS THAN(100), +PARTITION p11 VALUES LESS THAN(200), +PARTITION p21 VALUES LESS THAN MAXVALUE); +SELECT PARTITION_EXPRESSION, SUBPARTITION_EXPRESSION FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='t1'; +PARTITION_EXPRESSION SUBPARTITION_EXPRESSION +ID `ID`,`aaaa,aaaaa` +ID `ID`,`aaaa,aaaaa` +ID `ID`,`aaaa,aaaaa` +ID `ID`,`aaaa,aaaaa` +ID `ID`,`aaaa,aaaaa` +ID `ID`,`aaaa,aaaaa` +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `ID` int(11) NOT NULL, + `aaaa,aaaaa` tinyint(3) unsigned NOT NULL DEFAULT '0', + `ddddddddd` int(11) NOT NULL DEFAULT '0', + `new_field0` varchar(50) DEFAULT NULL, + PRIMARY KEY (`ID`,`aaaa,aaaaa`,`ddddddddd`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (ID) +SUBPARTITION BY LINEAR KEY (ID,`aaaa,aaaaa`) +SUBPARTITIONS 2 +(PARTITION p01 VALUES LESS THAN (100) ENGINE = MyISAM, + PARTITION p11 VALUES LESS THAN (200) ENGINE = MyISAM, + PARTITION p21 VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ +drop table t1; CREATE TABLE t1 (a INT, b INT) PARTITION BY LIST (a) SUBPARTITION BY HASH (b) diff --git a/mysql-test/r/partition_binlog_stmt.result b/mysql-test/r/partition_binlog_stmt.result new file mode 100644 index 00000000000..9be23636ca6 --- /dev/null +++ b/mysql-test/r/partition_binlog_stmt.result @@ -0,0 +1,13 @@ +DROP TABLE IF EXISTS t1; +# +# Bug#51851: Server with SBR locks mutex twice on LOAD DATA into +# partitioned MyISAM table +CREATE TABLE t1 +(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, +name TINYBLOB NOT NULL, +modified TIMESTAMP DEFAULT '0000-00-00 00:00:00', +INDEX namelocs (name(255))) ENGINE = MyISAM +PARTITION BY HASH(id) PARTITIONS 2; +LOAD DATA LOCAL INFILE 'init_file.txt' +INTO TABLE t1 (name); +DROP TABLE t1; diff --git a/mysql-test/r/partition_column.result b/mysql-test/r/partition_column.result index 458343a6b92..7b45ffcb0de 100644 --- a/mysql-test/r/partition_column.result +++ b/mysql-test/r/partition_column.result @@ -1,4 +1,44 @@ drop table if exists t1; +# +# Bug#52815: LIST COLUMNS doesn't insert rows in correct partition +# if muliple columns used +CREATE TABLE t1 ( +id INT NOT NULL, +name VARCHAR(255), +department VARCHAR(10), +country VARCHAR(255) +) PARTITION BY LIST COLUMNS (department, country) ( +PARTITION first_office VALUES IN (('dep1', 'Russia'), ('dep1', 'Croatia')), +PARTITION second_office VALUES IN (('dep2', 'Russia')) +); +INSERT INTO t1 VALUES(1, 'Ann', 'dep1', 'Russia'); +INSERT INTO t1 VALUES(2, 'Bob', 'dep1', 'Croatia'); +INSERT INTO t1 VALUES(3, 'Cecil', 'dep2', 'Russia'); +INSERT INTO t1 VALUES(3, 'Dan', 'dep2', 'Croatia'); +ERROR HY000: Table has no partition for value from column_list +SELECT PARTITION_NAME,TABLE_ROWS +FROM INFORMATION_SCHEMA.PARTITIONS +WHERE TABLE_NAME = 't1'; +PARTITION_NAME TABLE_ROWS +first_office 2 +second_office 1 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) NOT NULL, + `name` varchar(255) DEFAULT NULL, + `department` varchar(10) DEFAULT NULL, + `country` varchar(255) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50500 PARTITION BY LIST COLUMNS(department,country) +(PARTITION first_office VALUES IN (('dep1','Russia'),('dep1','Croatia')) ENGINE = MyISAM, + PARTITION second_office VALUES IN (('dep2','Russia')) ENGINE = MyISAM) */ +SELECT * FROM t1 WHERE department = 'dep2' and country = 'Croatia'; +id name department country +SELECT * FROM t1 WHERE department = 'dep1' and country = 'Croatia'; +id name department country +2 Bob dep1 Croatia +DROP TABLE t1; CREATE TABLE t1 (a DECIMAL) PARTITION BY RANGE COLUMNS (a) (PARTITION p0 VALUES LESS THAN (0)); @@ -168,22 +208,22 @@ partition p3 values less than (1, MAXVALUE, MAXVALUE, MAXVALUE)); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; partition_method partition_expression partition_description -RANGE COLUMNS a,b,c,d 1,'0',MAXVALUE,'1900-01-01' -RANGE COLUMNS a,b,c,d 1,'0',MAXVALUE,'1900-01-01' -RANGE COLUMNS a,b,c,d 1,'0',MAXVALUE,'1900-01-01' -RANGE COLUMNS a,b,c,d 1,'0',MAXVALUE,'1900-01-01' -RANGE COLUMNS a,b,c,d 1,'a',MAXVALUE,'1999-01-01' -RANGE COLUMNS a,b,c,d 1,'a',MAXVALUE,'1999-01-01' -RANGE COLUMNS a,b,c,d 1,'a',MAXVALUE,'1999-01-01' -RANGE COLUMNS a,b,c,d 1,'a',MAXVALUE,'1999-01-01' -RANGE COLUMNS a,b,c,d 1,'b',MAXVALUE,MAXVALUE -RANGE COLUMNS a,b,c,d 1,'b',MAXVALUE,MAXVALUE -RANGE COLUMNS a,b,c,d 1,'b',MAXVALUE,MAXVALUE -RANGE COLUMNS a,b,c,d 1,'b',MAXVALUE,MAXVALUE -RANGE COLUMNS a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE -RANGE COLUMNS a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE -RANGE COLUMNS a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE -RANGE COLUMNS a,b,c,d 1,MAXVALUE,MAXVALUE,MAXVALUE +RANGE COLUMNS `a`,`b`,`c`,`d` 1,'0',MAXVALUE,'1900-01-01' +RANGE COLUMNS `a`,`b`,`c`,`d` 1,'0',MAXVALUE,'1900-01-01' +RANGE COLUMNS `a`,`b`,`c`,`d` 1,'0',MAXVALUE,'1900-01-01' +RANGE COLUMNS `a`,`b`,`c`,`d` 1,'0',MAXVALUE,'1900-01-01' +RANGE COLUMNS `a`,`b`,`c`,`d` 1,'a',MAXVALUE,'1999-01-01' +RANGE COLUMNS `a`,`b`,`c`,`d` 1,'a',MAXVALUE,'1999-01-01' +RANGE COLUMNS `a`,`b`,`c`,`d` 1,'a',MAXVALUE,'1999-01-01' +RANGE COLUMNS `a`,`b`,`c`,`d` 1,'a',MAXVALUE,'1999-01-01' +RANGE COLUMNS `a`,`b`,`c`,`d` 1,'b',MAXVALUE,MAXVALUE +RANGE COLUMNS `a`,`b`,`c`,`d` 1,'b',MAXVALUE,MAXVALUE +RANGE COLUMNS `a`,`b`,`c`,`d` 1,'b',MAXVALUE,MAXVALUE +RANGE COLUMNS `a`,`b`,`c`,`d` 1,'b',MAXVALUE,MAXVALUE +RANGE COLUMNS `a`,`b`,`c`,`d` 1,MAXVALUE,MAXVALUE,MAXVALUE +RANGE COLUMNS `a`,`b`,`c`,`d` 1,MAXVALUE,MAXVALUE,MAXVALUE +RANGE COLUMNS `a`,`b`,`c`,`d` 1,MAXVALUE,MAXVALUE,MAXVALUE +RANGE COLUMNS `a`,`b`,`c`,`d` 1,MAXVALUE,MAXVALUE,MAXVALUE show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -266,9 +306,9 @@ partition p2 values in ((3, NULL), (NULL, 1))); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; partition_method partition_expression partition_description -LIST COLUMNS a,b (1,NULL),(2,NULL),(NULL,NULL) -LIST COLUMNS a,b (1,1),(2,2) -LIST COLUMNS a,b (3,NULL),(NULL,1) +LIST COLUMNS `a`,`b` (1,NULL),(2,NULL),(NULL,NULL) +LIST COLUMNS `a`,`b` (1,1),(2,2) +LIST COLUMNS `a`,`b` (3,NULL),(NULL,1) show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -298,11 +338,11 @@ select * from t1 where a > 8; a b select * from t1 where a not between 8 and 8; a b +1 NULL 2 NULL +1 1 2 2 3 NULL -1 NULL -1 1 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -356,8 +396,8 @@ partition p1 values in (4, NULL, 3)); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; partition_method partition_expression partition_description -LIST COLUMNS a 2,1 -LIST COLUMNS a 4,NULL,3 +LIST COLUMNS `a` 2,1 +LIST COLUMNS `a` 4,NULL,3 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -393,18 +433,18 @@ partition p3 values less than (4,'abc','abc')); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; partition_method partition_expression partition_description -RANGE COLUMNS a,b,c 1,'abc','abc' -RANGE COLUMNS a,b,c 1,'abc','abc' -RANGE COLUMNS a,b,c 1,'abc','abc' -RANGE COLUMNS a,b,c 2,'abc','abc' -RANGE COLUMNS a,b,c 2,'abc','abc' -RANGE COLUMNS a,b,c 2,'abc','abc' -RANGE COLUMNS a,b,c 3,'abc','abc' -RANGE COLUMNS a,b,c 3,'abc','abc' -RANGE COLUMNS a,b,c 3,'abc','abc' -RANGE COLUMNS a,b,c 4,'abc','abc' -RANGE COLUMNS a,b,c 4,'abc','abc' -RANGE COLUMNS a,b,c 4,'abc','abc' +RANGE COLUMNS `a`,`b`,`c` 1,'abc','abc' +RANGE COLUMNS `a`,`b`,`c` 1,'abc','abc' +RANGE COLUMNS `a`,`b`,`c` 1,'abc','abc' +RANGE COLUMNS `a`,`b`,`c` 2,'abc','abc' +RANGE COLUMNS `a`,`b`,`c` 2,'abc','abc' +RANGE COLUMNS `a`,`b`,`c` 2,'abc','abc' +RANGE COLUMNS `a`,`b`,`c` 3,'abc','abc' +RANGE COLUMNS `a`,`b`,`c` 3,'abc','abc' +RANGE COLUMNS `a`,`b`,`c` 3,'abc','abc' +RANGE COLUMNS `a`,`b`,`c` 4,'abc','abc' +RANGE COLUMNS `a`,`b`,`c` 4,'abc','abc' +RANGE COLUMNS `a`,`b`,`c` 4,'abc','abc' show create table t1; Table Create Table t1 CREATE TABLE `t1` ( @@ -437,8 +477,8 @@ partition p1 values less than (1, 'B', 1)); select partition_method, partition_expression, partition_description from information_schema.partitions where table_name = "t1"; partition_method partition_expression partition_description -RANGE COLUMNS a,b,c 1,'A',1 -RANGE COLUMNS a,b,c 1,'B',1 +RANGE COLUMNS `a`,`b`,`c` 1,'A',1 +RANGE COLUMNS `a`,`b`,`c` 1,'B',1 show create table t1; Table Create Table t1 CREATE TABLE `t1` ( diff --git a/mysql-test/r/partition_error.result b/mysql-test/r/partition_error.result index b506c2eb0cb..25addd7fdea 100644 --- a/mysql-test/r/partition_error.result +++ b/mysql-test/r/partition_error.result @@ -24,6 +24,76 @@ CREATE TEMPORARY TABLE tmp_t1 LIKE t1; ERROR HY000: Cannot create temporary table with partitions DROP TABLE t1; # +# Bug#42954: SQL MODE 'NO_DIR_IN_CREATE' does not work with +# subpartitions +SET @org_mode=@@sql_mode; +SET @@sql_mode='NO_DIR_IN_CREATE'; +SELECT @@sql_mode; +@@sql_mode +NO_DIR_IN_CREATE +CREATE TABLE t1 (id INT, purchased DATE) +PARTITION BY RANGE(YEAR(purchased)) +SUBPARTITION BY HASH(TO_DAYS(purchased)) +(PARTITION p0 VALUES LESS THAN MAXVALUE +DATA DIRECTORY = '/tmp/not-existing' +INDEX DIRECTORY = '/tmp/not-existing'); +Warnings: +Warning 1618 <DATA DIRECTORY> option ignored +Warning 1618 <INDEX DIRECTORY> option ignored +Warning 1618 <DATA DIRECTORY> option ignored +Warning 1618 <INDEX DIRECTORY> option ignored +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) DEFAULT NULL, + `purchased` date DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (YEAR(purchased)) +SUBPARTITION BY HASH (TO_DAYS(purchased)) +(PARTITION p0 VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ +DROP TABLE t1; +CREATE TABLE t1 (id INT, purchased DATE) +PARTITION BY RANGE(YEAR(purchased)) +SUBPARTITION BY HASH(TO_DAYS(purchased)) SUBPARTITIONS 2 +(PARTITION p0 VALUES LESS THAN MAXVALUE +(SUBPARTITION sp0 +DATA DIRECTORY = '/tmp/not-existing' +INDEX DIRECTORY = '/tmp/not-existing', +SUBPARTITION sp1)); +Warnings: +Warning 1618 <DATA DIRECTORY> option ignored +Warning 1618 <INDEX DIRECTORY> option ignored +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) DEFAULT NULL, + `purchased` date DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (YEAR(purchased)) +SUBPARTITION BY HASH (TO_DAYS(purchased)) +(PARTITION p0 VALUES LESS THAN MAXVALUE + (SUBPARTITION sp0 ENGINE = MyISAM, + SUBPARTITION sp1 ENGINE = MyISAM)) */ +DROP TABLE t1; +CREATE TABLE t1 (id INT, purchased DATE) +PARTITION BY RANGE(YEAR(purchased)) +(PARTITION p0 VALUES LESS THAN MAXVALUE +DATA DIRECTORY = '/tmp/not-existing' +INDEX DIRECTORY = '/tmp/not-existing'); +Warnings: +Warning 1618 <DATA DIRECTORY> option ignored +Warning 1618 <INDEX DIRECTORY> option ignored +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(11) DEFAULT NULL, + `purchased` date DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +/*!50100 PARTITION BY RANGE (YEAR(purchased)) +(PARTITION p0 VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */ +DROP TABLE t1; +SET @@sql_mode= @org_mode; +# # Bug#50392: insert_id is not reset for partitioned tables # auto_increment on duplicate entry CREATE TABLE t1 (a INT AUTO_INCREMENT PRIMARY KEY); diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index 9ba1a0446dd..ef2277fef38 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -1436,6 +1436,7 @@ DROP PROCEDURE p1; DROP FUNCTION f1; DROP TABLE t1; DROP EVENT ev1; +SHOW STORAGE ENGINES; CREATE USER test_u@localhost; GRANT PROCESS ON *.* TO test_u@localhost; SHOW ENGINE MYISAM MUTEX; diff --git a/mysql-test/r/type_binary.result b/mysql-test/r/type_binary.result index 01841bf27fc..b00d1585b29 100644 --- a/mysql-test/r/type_binary.result +++ b/mysql-test/r/type_binary.result @@ -47,7 +47,7 @@ create table t1 (s1 binary(2) primary key); insert into t1 values (0x01); insert into t1 values (0x0120); insert into t1 values (0x0100); -ERROR 23000: Duplicate entry '\x01\x00' for key 'PRIMARY' +ERROR 23000: Duplicate entry '\x01' for key 'PRIMARY' select hex(s1) from t1 order by s1; hex(s1) 0100 diff --git a/mysql-test/r/type_decimal.result b/mysql-test/r/type_decimal.result index d131fa2b4d5..d08f86909ba 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -966,3 +966,31 @@ max(case 1 when 1 then c else null end) 300.00 drop table t1; End of 5.0 tests +CREATE TABLE t1 (a INTEGER); +INSERT INTO t1 VALUES (NULL); +CREATE TABLE t2 (b INTEGER); +INSERT INTO t2 VALUES (NULL), (NULL); +SELECT b FROM t1 JOIN t2 WHERE CONVERT(a, DECIMAL)|CONVERT(b, DECIMAL); +b +DROP TABLE t1, t2; +CREATE TABLE t1 (col0 INTEGER, col1 REAL); +CREATE TABLE t2 (col0 INTEGER); +INSERT INTO t1 VALUES (0, 0.0), (NULL, NULL); +INSERT INTO t2 VALUES (1); +SELECT 1 FROM t1 +JOIN +( +SELECT t2.col0 FROM t2 RIGHT JOIN t1 USING(col0) +GROUP BY t2.col0 +) AS subq +WHERE t1.col1 + CAST(subq.col0 AS DECIMAL); +1 +SELECT 1 FROM t1 +JOIN +( +SELECT t2.col0 FROM t2 RIGHT JOIN t1 USING(col0) +GROUP BY t2.col0 +) AS subq +WHERE CONCAT(t1.col1, CAST(subq.col0 AS DECIMAL)); +1 +DROP TABLE t1, t2; diff --git a/mysql-test/suite/binlog/r/binlog_multi_engine.result b/mysql-test/suite/binlog/r/binlog_multi_engine.result index 2cdd62655fa..b0ec756b651 100644 --- a/mysql-test/suite/binlog/r/binlog_multi_engine.result +++ b/mysql-test/suite/binlog/r/binlog_multi_engine.result @@ -8,14 +8,14 @@ INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2); INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2); UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. The last event before the COMMIT is use `test`; UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c *** Please look in binlog_multi_engine.test if you have a diff here **** START TRANSACTION; INSERT INTO t1n VALUES (1,1), (1,2), (2,1), (2,2); UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c; COMMIT; TRUNCATE t1m; diff --git a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result index 6643c4557c2..86da7468892 100644 --- a/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_row_mix_innodb_myisam.result @@ -412,13 +412,41 @@ master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE IF NOT EXISTS `t2` ( + `a` int(11) NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE IF NOT EXISTS `t2` ( + `a` int(11) NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB +master-bin.000001 # Query # # ROLLBACK +master-bin.000001 # Query # # BEGIN master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE IF NOT EXISTS `t2` ( + `a` int(11) NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE IF NOT EXISTS `t2` ( + `a` int(11) NOT NULL DEFAULT '0', + `b` int(11) DEFAULT NULL, + PRIMARY KEY (`a`) +) ENGINE=InnoDB +master-bin.000001 # Query # # ROLLBACK master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */ master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `t2` /* generated by server */ reset master; diff --git a/mysql-test/suite/binlog/r/binlog_spurious_ddl_errors.result b/mysql-test/suite/binlog/r/binlog_spurious_ddl_errors.result new file mode 100644 index 00000000000..17a473ff062 --- /dev/null +++ b/mysql-test/suite/binlog/r/binlog_spurious_ddl_errors.result @@ -0,0 +1,53 @@ +SET @old_binlog_format= @@global.binlog_format; +INSTALL PLUGIN example SONAME 'ha_example.so'; +################################################################################ +# Verifies if ER_BINLOG_STMT_MODE_AND_ROW_ENGINE happens by setting the binlog +# format to STATEMENT and the transaction isolation level to READ COMMITTED as +# such changes force Innodb to accept changes in the row format. +# +# When CREATE TABLE, ALTER TABLE, CREATE INDEX and CREATE TRIGGER are executed +# any error should be triggered. +# +# In contrast, CREATE TABLE ... SELECT should trigger the following error: +# ER_BINLOG_STMT_MODE_AND_ROW_ENGINE. +################################################################################ +SET binlog_format = STATEMENT; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +CREATE TABLE t_row (a VARCHAR(100)) ENGINE = InnoDB; +ALTER TABLE t_row ADD COLUMN b INT; +CREATE TRIGGER trig_row BEFORE INSERT ON t_row FOR EACH ROW INSERT INTO t_stmt VALUES (1); +CREATE INDEX i ON t_row(a); +CREATE TABLE t_row_new ENGINE = InnoDB SELECT * FROM t_row; +ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED. +DROP TABLE t_row; + + +################################################################################ +# Verifies if ER_BINLOG_ROW_MODE_AND_STMT_ENGINE happens by setting the binlog +# format to ROW and using a engine, i.e. EXAMPLE, that only supports STATEMENT. +# +# When CREATE TABLE, ALTER TABLE, CREATE INDEX and CREATE TRIGGER are executed +# the error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE is not triggered. Note that other +# errors are triggered due to restrictions in the engine. +# +# In contrast, CREATE TABLE ... SELECT should trigger the following error: +# ER_BINLOG_ROW_MODE_AND_STMT_ENGINE. +################################################################################ +SET binlog_format = ROW; +CREATE TABLE t_stmt (a VARCHAR(100)) ENGINE = EXAMPLE; +ALTER TABLE t_stmt ADD COLUMN b INT; +ERROR 42000: This version of MySQL doesn't yet support 'ALTER TABLE' +CREATE TRIGGER trig_stmt BEFORE INSERT ON t_stmt FOR EACH ROW INSERT INTO t_stmt VALUES (1); +CREATE INDEX i ON t_stmt(a); +ERROR 42000: Too many key parts specified; max 0 parts allowed +CREATE TABLE t_stmt_new ENGINE = EXAMPLE SELECT * FROM t_stmt; +ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-based logging. +DROP TABLE t_stmt; + + +################################################################################ +# CLEAN UP # +################################################################################ +UNINSTALL PLUGIN example; +SET @@global.binlog_format = @old_binlog_format; +SET @@session.binlog_format = @old_binlog_format; diff --git a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result index cea3819cad3..9bf6f4de144 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result +++ b/mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result @@ -8,7 +8,7 @@ begin; insert into t1 values(1); insert into t2 select * from t1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. commit; show binlog events from <binlog_start>; Log_name Pos Event_type Server_id End_log_pos Info @@ -23,7 +23,7 @@ begin; insert into t1 values(2); insert into t2 select * from t1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. rollback; Warnings: Warning 1196 Some non-transactional changed tables couldn't be rolled back @@ -42,7 +42,7 @@ savepoint my_savepoint; insert into t1 values(4); insert into t2 select * from t1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. rollback to savepoint my_savepoint; Warnings: Warning 1196 Some non-transactional changed tables couldn't be rolled back @@ -65,7 +65,7 @@ savepoint my_savepoint; insert into t1 values(6); insert into t2 select * from t1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. rollback to savepoint my_savepoint; Warnings: Warning 1196 Some non-transactional changed tables couldn't be rolled back @@ -95,7 +95,7 @@ begin; insert into t1 values(8); insert into t2 select * from t1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. select get_lock("a",10); get_lock("a",10) 1 @@ -111,7 +111,7 @@ reset master; insert into t1 values(9); insert into t2 select * from t1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. show binlog events from <binlog_start>; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN @@ -127,7 +127,7 @@ insert into t1 values(10); begin; insert into t2 select * from t1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. show binlog events from <binlog_start>; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN @@ -246,7 +246,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back create table t0 (n int); insert t0 select * from t1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. set autocommit=1; insert into t0 select GET_LOCK("lock1",null); Warnings: @@ -418,6 +418,9 @@ master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO t2 values (100,100) master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO t2 values (101,101) +master-bin.000001 # Query # # ROLLBACK master-bin.000001 # Query # # use `test`; DROP TABLE t1,t2 reset master; create table t1 (a int) engine=innodb; @@ -429,7 +432,7 @@ begin; insert into t1 values(8); insert into t2 select * from t1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. select get_lock("a",10); get_lock("a",10) 1 diff --git a/mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result b/mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result index e3250f00dbf..d6d44ccad8e 100644 --- a/mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result +++ b/mysql-test/suite/binlog/r/binlog_stm_unsafe_warning.result @@ -67,11 +67,8 @@ Note 1592 Unsafe statement written to the binary log using statement format sinc SELECT sf_bug50192(); sf_bug50192() 1 -Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly. SHOW WARNINGS; Level Code Message -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly. DROP FUNCTION sf_bug50192; DROP TRIGGER tr_bug50192; DROP TABLE t1, t2; diff --git a/mysql-test/suite/binlog/r/binlog_switch_inside_trans.result b/mysql-test/suite/binlog/r/binlog_switch_inside_trans.result index de224a190c2..48b6dfa61d9 100644 --- a/mysql-test/suite/binlog/r/binlog_switch_inside_trans.result +++ b/mysql-test/suite/binlog/r/binlog_switch_inside_trans.result @@ -1,5 +1,6 @@ set @save_binlog_format= @@global.binlog_format; set @save_binlog_dirct= @@global.binlog_direct_non_transactional_updates; +set @save_sql_log_bin= @@global.sql_log_bin; create table t1 (a int) engine= myisam; create table t2 (a int) engine= innodb; SELECT @@session.binlog_format; @@ -8,116 +9,148 @@ ROW SELECT @@session.binlog_direct_non_transactional_updates; @@session.binlog_direct_non_transactional_updates 1 +SELECT @@session.sql_log_bin; +@@session.sql_log_bin +1 SET AUTOCOMMIT=1; -# Test that the session variable 'binlog_format' and -# 'binlog_direct_non_transactional_updates' are -# writable outside a transaction. -# Current session values are ROW and FALSE, respectively. +# Test that the session variable 'binlog_format', +# 'binlog_direct_non_transactional_updates' and 'sql_log_bin' +# are writable outside a transaction. +# Current session values are ROW, FALSE, TRUE, respectively. set @@session.binlog_format= statement; set @@session.binlog_direct_non_transactional_updates= TRUE; +set @@session.sql_log_bin= FALSE; SELECT @@session.binlog_format; @@session.binlog_format STATEMENT SELECT @@session.binlog_direct_non_transactional_updates; @@session.binlog_direct_non_transactional_updates 1 +SELECT @@session.sql_log_bin; +@@session.sql_log_bin +0 begin; -# Test that the session variable 'binlog_format' and -# 'binlog_direct_non_transactional_updates' are +# Test that the session variable 'binlog_format', +# 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are # read-only inside a transaction with no preceding updates. -# Current session values are STATEMENT and TRUE, respectively. +# Current session values are STATEMENT, TRUE, FALSE, respectively. set @@session.binlog_format= mixed; ERROR HY000: Cannot modify @@session.binlog_format inside a transaction set @@session.binlog_direct_non_transactional_updates= FALSE; ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction +set @@session.sql_log_bin= FALSE; +ERROR HY000: Cannot modify @@session.sql_log_bin inside a transaction insert into t2 values (1); -# Test that the session variable 'binlog_format' and -# 'binlog_direct_non_transactional_updates' are +# Test that the session variable 'binlog_format', +# 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are # read-only inside a transaction with preceding transactional updates. -# Current session values are STATEMENT and TRUE, respectively. +# Current session values are STATEMENT, TRUE and FALSE, respectively. set @@session.binlog_format= row; ERROR HY000: Cannot modify @@session.binlog_format inside a transaction set @@session.binlog_direct_non_transactional_updates= FALSE; ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction +set @@session.sql_log_bin= FALSE; +ERROR HY000: Cannot modify @@session.sql_log_bin inside a transaction commit; begin; insert into t1 values (2); -# Test that the session variable 'binlog_format' and -# 'binlog_direct_non_transactional_updates' are +# Test that the session variable 'binlog_format' +# 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are # read-only inside a transaction with preceding non-transactional updates. -# Current session values are STATEMENT and TRUE, respectively. +# Current session values are STATEMENT, TRUE, FALSE, respectively. set @@session.binlog_format= mixed; ERROR HY000: Cannot modify @@session.binlog_format inside a transaction set @@session.binlog_direct_non_transactional_updates= FALSE; ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction +set @@session.sql_log_bin= FALSE; +ERROR HY000: Cannot modify @@session.sql_log_bin inside a transaction commit; -# Test that the session variable 'binlog_format' and -# 'binlog_direct_non_transactional_updates' are +# Test that the session variable 'binlog_format', +# 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are # writable when AUTOCOMMIT=0, before a transaction has started. -# Current session values are STATEMENT and TRUE, respectively. +# Current session values are STATEMENT, TRUE, FALSE, respectively. set AUTOCOMMIT=0; set @@session.binlog_format= row; set @@session.binlog_direct_non_transactional_updates= FALSE; +set @@session.sql_log_bin= TRUE; SELECT @@session.binlog_format; @@session.binlog_format ROW SELECT @@session.binlog_direct_non_transactional_updates; @@session.binlog_direct_non_transactional_updates 0 +SELECT @@session.sql_log_bin; +@@session.sql_log_bin +1 insert into t1 values (3); -# Test that the session variable 'binlog_format' and -# 'binlog_direct_non_transactional_updates' are +# Test that the session variable 'binlog_format', +# 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are # read-only inside an AUTOCOMMIT=0 transaction # with preceding non-transactional updates. -# Current session values are ROW and FALSE, respectively. +# Current session values are ROW, FALSE, TRUE, respectively. set @@session.binlog_format= statement; ERROR HY000: Cannot modify @@session.binlog_format inside a transaction set @@session.binlog_direct_non_transactional_updates= TRUE; ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction +set @@session.sql_log_bin= FALSE; +ERROR HY000: Cannot modify @@session.sql_log_bin inside a transaction SELECT @@session.binlog_format; @@session.binlog_format ROW SELECT @@session.binlog_direct_non_transactional_updates; @@session.binlog_direct_non_transactional_updates 0 +SELECT @@session.sql_log_bin; +@@session.sql_log_bin +1 commit; insert into t2 values (4); -# Test that the session variable 'binlog_format' and -# 'binlog_direct_non_transactional_updates' are +# Test that the session variable 'binlog_format', +# 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are # read-only inside an AUTOCOMMIT=0 transaction with # preceding transactional updates. -# Current session values are ROW and FALSE, respectively. +# Current session values are ROW, FALSE, TRUE, respectively. set @@session.binlog_format= statement; ERROR HY000: Cannot modify @@session.binlog_format inside a transaction set @@session.binlog_direct_non_transactional_updates= TRUE; ERROR HY000: Cannot modify @@session.binlog_direct_non_transactional_updates inside a transaction +set @@session.sql_log_bin= FALSE; +ERROR HY000: Cannot modify @@session.sql_log_bin inside a transaction SELECT @@session.binlog_format; @@session.binlog_format ROW SELECT @@session.binlog_direct_non_transactional_updates; @@session.binlog_direct_non_transactional_updates 0 +SELECT @@session.sql_log_bin; +@@session.sql_log_bin +1 commit; begin; insert into t2 values (5); # Test that the global variable 'binlog_format' and -# 'binlog_direct_non_transactional_updates' are +# 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are # writable inside a transaction. -# Current session values are ROW and FALSE, respectively. +# Current session values are ROW, FALSE, TRUE respectively. SELECT @@global.binlog_format; @@global.binlog_format ROW set @@global.binlog_format= statement; set @@global.binlog_direct_non_transactional_updates= TRUE; +set @@global.sql_log_bin= FALSE; SELECT @@global.binlog_format; @@global.binlog_format STATEMENT SELECT @@global.binlog_direct_non_transactional_updates; @@global.binlog_direct_non_transactional_updates 1 +SELECT @@global.sql_log_bin; +@@global.sql_log_bin +0 commit; set @@global.binlog_format= @save_binlog_format; set @@global.binlog_direct_non_transactional_updates= @save_binlog_dirct; +set @@global.sql_log_bin= @save_sql_log_bin; create table t3(a int, b int) engine= innodb; create table t4(a int) engine= innodb; create table t5(a int) engine= innodb; @@ -153,6 +186,23 @@ ERROR HY000: Cannot change the binlog direct flag inside a stored function or tr SELECT @@session.binlog_direct_non_transactional_updates; @@session.binlog_direct_non_transactional_updates 0 +create table t9(a int, b int) engine= innodb; +create table t10(a int) engine= innodb; +create table t11(a int) engine= innodb; +create trigger tr3 after insert on t9 for each row begin +insert into t10(a) values(1); +set @@session.sql_log_bin= TRUE; +insert into t10(a) values(2); +insert into t11(a) values(3); +end | +# Test that the session variable 'sql_log_bin' is +# read-only in sub-statements. +# Current session value is FALSE. +insert into t9(a,b) values(1,1); +ERROR HY000: Cannot change the sql_log_bin inside a stored function or trigger +SELECT @@session.sql_log_bin; +@@session.sql_log_bin +1 drop table t1; drop table t2; drop table t3; @@ -161,3 +211,6 @@ drop table t5; drop table t6; drop table t7; drop table t8; +drop table t9; +drop table t10; +drop table t11; diff --git a/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors-master.opt b/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors-master.opt new file mode 100644 index 00000000000..ffa981152ea --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors-master.opt @@ -0,0 +1 @@ +--innodb $EXAMPLE_PLUGIN_OPT diff --git a/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors.test b/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors.test new file mode 100644 index 00000000000..6514ff1f712 --- /dev/null +++ b/mysql-test/suite/binlog/t/binlog_spurious_ddl_errors.test @@ -0,0 +1,95 @@ +################################################################################ +# BUG#50479 DDL stmt on row-only/stmt-only tables generate spurious +# binlog_format errors +# +# In the fix of BUG#39934 in 5.1-rep+3, errors are generated when +# binlog_format=row and a statement modifies a table restricted to +# statement-logging (ER_BINLOG_ROW_MODE_AND_STMT_ENGINE); or if +# binlog_format=statement and a statement modifies a table limited to +# row-logging (ER_BINLOG_STMT_MODE_AND_ROW_ENGINE). +# +# In this test case, we check if some DDL statements that lock tables do not +# trigger errors as they do not generate rows events and as such are harmless +# from the point of view of conflicts between the engine's supported logging +# format and the value of binlog_format. +# +# In particular, we check if: +# 1 - ALTER TABLE, CREATE INDEX and CREATE TRIGGER do not generate either +# ER_BINLOG_STMT_MODE_AND_ROW_ENGINE or ER_BINLOG_STMT_MODE_AND_ROW_ENGINE +# +# 2 - CREATE TABLE ... SELECT generates an error because the command can +# generate row events but CREATE TABLE without SELECT does not generate +# an error. +################################################################################ +--source include/have_innodb.inc +--source include/have_example_plugin.inc +--source include/have_log_bin.inc + +SET @old_binlog_format= @@global.binlog_format; +INSTALL PLUGIN example SONAME 'ha_example.so'; + +--echo ################################################################################ +--echo # Verifies if ER_BINLOG_STMT_MODE_AND_ROW_ENGINE happens by setting the binlog +--echo # format to STATEMENT and the transaction isolation level to READ COMMITTED as +--echo # such changes force Innodb to accept changes in the row format. +--echo # +--echo # When CREATE TABLE, ALTER TABLE, CREATE INDEX and CREATE TRIGGER are executed +--echo # any error should be triggered. +--echo # +--echo # In contrast, CREATE TABLE ... SELECT should trigger the following error: +--echo # ER_BINLOG_STMT_MODE_AND_ROW_ENGINE. +--echo ################################################################################ +SET binlog_format = STATEMENT; +SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; +CREATE TABLE t_row (a VARCHAR(100)) ENGINE = InnoDB; + +ALTER TABLE t_row ADD COLUMN b INT; + +CREATE TRIGGER trig_row BEFORE INSERT ON t_row FOR EACH ROW INSERT INTO t_stmt VALUES (1); + +CREATE INDEX i ON t_row(a); + +--error ER_BINLOG_STMT_MODE_AND_ROW_ENGINE +CREATE TABLE t_row_new ENGINE = InnoDB SELECT * FROM t_row; + +DROP TABLE t_row; + +--echo +--echo + +--echo ################################################################################ +--echo # Verifies if ER_BINLOG_ROW_MODE_AND_STMT_ENGINE happens by setting the binlog +--echo # format to ROW and using a engine, i.e. EXAMPLE, that only supports STATEMENT. +--echo # +--echo # When CREATE TABLE, ALTER TABLE, CREATE INDEX and CREATE TRIGGER are executed +--echo # the error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE is not triggered. Note that other +--echo # errors are triggered due to restrictions in the engine. +--echo # +--echo # In contrast, CREATE TABLE ... SELECT should trigger the following error: +--echo # ER_BINLOG_ROW_MODE_AND_STMT_ENGINE. +--echo ################################################################################ +SET binlog_format = ROW; +CREATE TABLE t_stmt (a VARCHAR(100)) ENGINE = EXAMPLE; + +--error ER_NOT_SUPPORTED_YET +ALTER TABLE t_stmt ADD COLUMN b INT; + +CREATE TRIGGER trig_stmt BEFORE INSERT ON t_stmt FOR EACH ROW INSERT INTO t_stmt VALUES (1); + +--error ER_TOO_MANY_KEY_PARTS +CREATE INDEX i ON t_stmt(a); + +--error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE +CREATE TABLE t_stmt_new ENGINE = EXAMPLE SELECT * FROM t_stmt; + +DROP TABLE t_stmt; + +--echo +--echo + +--echo ################################################################################ +--echo # CLEAN UP # +--echo ################################################################################ +UNINSTALL PLUGIN example; +SET @@global.binlog_format = @old_binlog_format; +SET @@session.binlog_format = @old_binlog_format; diff --git a/mysql-test/suite/binlog/t/binlog_switch_inside_trans.test b/mysql-test/suite/binlog/t/binlog_switch_inside_trans.test index cdc94198933..06c5e78bd0e 100644 --- a/mysql-test/suite/binlog/t/binlog_switch_inside_trans.test +++ b/mysql-test/suite/binlog/t/binlog_switch_inside_trans.test @@ -10,107 +10,128 @@ source include/have_binlog_format_row.inc; set @save_binlog_format= @@global.binlog_format; set @save_binlog_dirct= @@global.binlog_direct_non_transactional_updates; +set @save_sql_log_bin= @@global.sql_log_bin; create table t1 (a int) engine= myisam; create table t2 (a int) engine= innodb; SELECT @@session.binlog_format; SELECT @@session.binlog_direct_non_transactional_updates; +SELECT @@session.sql_log_bin; SET AUTOCOMMIT=1; ---echo # Test that the session variable 'binlog_format' and ---echo # 'binlog_direct_non_transactional_updates' are ---echo # writable outside a transaction. ---echo # Current session values are ROW and FALSE, respectively. +--echo # Test that the session variable 'binlog_format', +--echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' +--echo # are writable outside a transaction. +--echo # Current session values are ROW, FALSE, TRUE, respectively. set @@session.binlog_format= statement; set @@session.binlog_direct_non_transactional_updates= TRUE; +set @@session.sql_log_bin= FALSE; SELECT @@session.binlog_format; SELECT @@session.binlog_direct_non_transactional_updates; +SELECT @@session.sql_log_bin; begin; ---echo # Test that the session variable 'binlog_format' and ---echo # 'binlog_direct_non_transactional_updates' are +--echo # Test that the session variable 'binlog_format', +--echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are --echo # read-only inside a transaction with no preceding updates. ---echo # Current session values are STATEMENT and TRUE, respectively. +--echo # Current session values are STATEMENT, TRUE, FALSE, respectively. --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT set @@session.binlog_format= mixed; --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT set @@session.binlog_direct_non_transactional_updates= FALSE; +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN +set @@session.sql_log_bin= FALSE; insert into t2 values (1); ---echo # Test that the session variable 'binlog_format' and ---echo # 'binlog_direct_non_transactional_updates' are +--echo # Test that the session variable 'binlog_format', +--echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are --echo # read-only inside a transaction with preceding transactional updates. ---echo # Current session values are STATEMENT and TRUE, respectively. +--echo # Current session values are STATEMENT, TRUE and FALSE, respectively. --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT set @@session.binlog_format= row; --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT set @@session.binlog_direct_non_transactional_updates= FALSE; +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN +set @@session.sql_log_bin= FALSE; commit; begin; insert into t1 values (2); ---echo # Test that the session variable 'binlog_format' and ---echo # 'binlog_direct_non_transactional_updates' are +--echo # Test that the session variable 'binlog_format' +--echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are --echo # read-only inside a transaction with preceding non-transactional updates. ---echo # Current session values are STATEMENT and TRUE, respectively. +--echo # Current session values are STATEMENT, TRUE, FALSE, respectively. --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT set @@session.binlog_format= mixed; --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT set @@session.binlog_direct_non_transactional_updates= FALSE; +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN +set @@session.sql_log_bin= FALSE; commit; ---echo # Test that the session variable 'binlog_format' and ---echo # 'binlog_direct_non_transactional_updates' are +--echo # Test that the session variable 'binlog_format', +--echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are --echo # writable when AUTOCOMMIT=0, before a transaction has started. ---echo # Current session values are STATEMENT and TRUE, respectively. +--echo # Current session values are STATEMENT, TRUE, FALSE, respectively. set AUTOCOMMIT=0; set @@session.binlog_format= row; set @@session.binlog_direct_non_transactional_updates= FALSE; +set @@session.sql_log_bin= TRUE; SELECT @@session.binlog_format; SELECT @@session.binlog_direct_non_transactional_updates; +SELECT @@session.sql_log_bin; insert into t1 values (3); ---echo # Test that the session variable 'binlog_format' and ---echo # 'binlog_direct_non_transactional_updates' are +--echo # Test that the session variable 'binlog_format', +--echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are --echo # read-only inside an AUTOCOMMIT=0 transaction --echo # with preceding non-transactional updates. ---echo # Current session values are ROW and FALSE, respectively. +--echo # Current session values are ROW, FALSE, TRUE, respectively. --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT set @@session.binlog_format= statement; --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT set @@session.binlog_direct_non_transactional_updates= TRUE; +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN +set @@session.sql_log_bin= FALSE; SELECT @@session.binlog_format; SELECT @@session.binlog_direct_non_transactional_updates; +SELECT @@session.sql_log_bin; commit; insert into t2 values (4); ---echo # Test that the session variable 'binlog_format' and ---echo # 'binlog_direct_non_transactional_updates' are +--echo # Test that the session variable 'binlog_format', +--echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are --echo # read-only inside an AUTOCOMMIT=0 transaction with --echo # preceding transactional updates. ---echo # Current session values are ROW and FALSE, respectively. +--echo # Current session values are ROW, FALSE, TRUE, respectively. --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT set @@session.binlog_format= statement; --error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT set @@session.binlog_direct_non_transactional_updates= TRUE; +--error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN +set @@session.sql_log_bin= FALSE; SELECT @@session.binlog_format; SELECT @@session.binlog_direct_non_transactional_updates; +SELECT @@session.sql_log_bin; commit; begin; insert into t2 values (5); --echo # Test that the global variable 'binlog_format' and ---echo # 'binlog_direct_non_transactional_updates' are +--echo # 'binlog_direct_non_transactional_updates' and 'sql_log_bin' are --echo # writable inside a transaction. ---echo # Current session values are ROW and FALSE, respectively. +--echo # Current session values are ROW, FALSE, TRUE respectively. SELECT @@global.binlog_format; set @@global.binlog_format= statement; set @@global.binlog_direct_non_transactional_updates= TRUE; + set @@global.sql_log_bin= FALSE; SELECT @@global.binlog_format; SELECT @@global.binlog_direct_non_transactional_updates; + SELECT @@global.sql_log_bin; commit; set @@global.binlog_format= @save_binlog_format; set @@global.binlog_direct_non_transactional_updates= @save_binlog_dirct; +set @@global.sql_log_bin= @save_sql_log_bin; create table t3(a int, b int) engine= innodb; create table t4(a int) engine= innodb; @@ -151,6 +172,25 @@ delimiter ;| insert into t6(a,b) values(1,1); SELECT @@session.binlog_direct_non_transactional_updates; +create table t9(a int, b int) engine= innodb; +create table t10(a int) engine= innodb; +create table t11(a int) engine= innodb; +delimiter |; +eval create trigger tr3 after insert on t9 for each row begin + insert into t10(a) values(1); + set @@session.sql_log_bin= TRUE; + insert into t10(a) values(2); + insert into t11(a) values(3); +end | +delimiter ;| + +--echo # Test that the session variable 'sql_log_bin' is +--echo # read-only in sub-statements. +--echo # Current session value is FALSE. +--error ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN +insert into t9(a,b) values(1,1); +SELECT @@session.sql_log_bin; + drop table t1; drop table t2; drop table t3; @@ -159,3 +199,6 @@ drop table t5; drop table t6; drop table t7; drop table t8; +drop table t9; +drop table t10; +drop table t11; diff --git a/mysql-test/suite/binlog/t/disabled.def b/mysql-test/suite/binlog/t/disabled.def index a86136fec69..b6086edb2f0 100644 --- a/mysql-test/suite/binlog/t/disabled.def +++ b/mysql-test/suite/binlog/t/disabled.def @@ -9,6 +9,6 @@ # Do not use any TAB characters for whitespace. # ############################################################################## -binlog_truncate_innodb : BUG#42643 2009-02-06 mats Changes to InnoDB requires to complete fix for BUG#36763 -binlog_unsafe : BUG#50312 2010-01-13 lsoares Warnings for unsafe sub-statement not returned to client - +binlog_truncate_innodb : BUG#42643 2009-02-06 mats Changes to InnoDB requires to complete fix for BUG#36763 +binlog_unsafe : BUG#50312 2010-01-13 lsoares Warnings for unsafe sub-statement not returned to client +binlog_spurious_ddl_errors : BUG#54195 2010-06-03 alik binlog_spurious_ddl_errors.test fails, thus disabled diff --git a/mysql-test/suite/innodb/r/innodb-autoinc-44030.result b/mysql-test/suite/innodb/r/innodb-autoinc-44030.result new file mode 100644 index 00000000000..54e972843f5 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb-autoinc-44030.result @@ -0,0 +1,30 @@ +drop table if exists t1; +SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; +CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (null); +INSERT INTO t1 VALUES (null); +ALTER TABLE t1 CHANGE c1 d1 INT NOT NULL AUTO_INCREMENT; +SELECT * FROM t1; +d1 +1 +2 +SELECT * FROM t1; +d1 +1 +2 +INSERT INTO t1 VALUES(null); +ALTER TABLE t1 AUTO_INCREMENT = 3; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `d1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`d1`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES(null); +SELECT * FROM t1; +d1 +1 +2 +3 +4 +DROP TABLE t1; diff --git a/mysql-test/r/innodb-autoinc.result b/mysql-test/suite/innodb/r/innodb-autoinc.result index abb8f3da072..a36b3a1a865 100644 --- a/mysql-test/r/innodb-autoinc.result +++ b/mysql-test/suite/innodb/r/innodb-autoinc.result @@ -868,35 +868,6 @@ Got one of the listed errors DROP TABLE t1; DROP TABLE t2; SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; -INSERT INTO t1 VALUES (null); -INSERT INTO t1 VALUES (null); -ALTER TABLE t1 CHANGE c1 d1 INT NOT NULL AUTO_INCREMENT; -SELECT * FROM t1; -d1 -1 -2 -SELECT * FROM t1; -d1 -1 -2 -INSERT INTO t1 VALUES(null); -Got one of the listed errors -ALTER TABLE t1 AUTO_INCREMENT = 3; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `d1` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`d1`) -) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 -INSERT INTO t1 VALUES(null); -SELECT * FROM t1; -d1 -1 -2 -3 -DROP TABLE t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; SHOW VARIABLES LIKE "%auto_inc%"; Variable_name Value auto_increment_increment 1 @@ -1111,18 +1082,165 @@ c1 c2 3 innodb 4 NULL DROP TABLE t1; -CREATE TABLE T1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) AUTO_INCREMENT=10 ENGINE=InnoDB; -CREATE INDEX i1 on T1(c2); -SHOW CREATE TABLE T1; +CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) AUTO_INCREMENT=10 ENGINE=InnoDB; +CREATE INDEX i1 on t1(c2); +SHOW CREATE TABLE t1; Table Create Table -T1 CREATE TABLE `T1` ( +t1 CREATE TABLE `t1` ( `c1` int(11) NOT NULL AUTO_INCREMENT, `c2` int(11) DEFAULT NULL, PRIMARY KEY (`c1`), KEY `i1` (`c2`) ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1 -INSERT INTO T1 (c2) values (0); -SELECT * FROM T1; +INSERT INTO t1 (c2) values (0); +SELECT * FROM t1; c1 c2 10 0 -DROP TABLE T1; +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1(C1 DOUBLE AUTO_INCREMENT KEY, C2 CHAR(10)) ENGINE=InnoDB; +INSERT INTO t1(C1, C2) VALUES (1, 'innodb'), (3, 'innodb'); +INSERT INTO t1(C2) VALUES ('innodb'); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `C1` double NOT NULL AUTO_INCREMENT, + `C2` char(10) DEFAULT NULL, + PRIMARY KEY (`C1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1(C1 FLOAT AUTO_INCREMENT KEY, C2 CHAR(10)) ENGINE=InnoDB; +INSERT INTO t1(C1, C2) VALUES (1, 'innodb'), (3, 'innodb'); +INSERT INTO t1(C2) VALUES ('innodb'); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `C1` float NOT NULL AUTO_INCREMENT, + `C2` char(10) DEFAULT NULL, + PRIMARY KEY (`C1`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1 (c1 INT AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 SET c1 = 1; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1 +INSERT INTO t1 SET c1 = 2; +INSERT INTO t1 SET c1 = -1; +SELECT * FROM t1; +c1 +-1 +1 +2 +INSERT INTO t1 SET c1 = -1; +Got one of the listed errors +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +REPLACE INTO t1 VALUES (-1); +SELECT * FROM t1; +c1 +-1 +1 +2 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1 +DROP TABLE t1; +DROP TABLE IF EXISTS t1; +Warnings: +Note 1051 Unknown table 't1' +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (-685113344), (1), (NULL), (NULL); +SELECT * FROM t1; +c1 +-685113344 +1 +2 +3 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (-685113344), (2), (NULL), (NULL); +SELECT * FROM t1; +c1 +-685113344 +2 +3 +4 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL), (2), (-685113344), (NULL); +INSERT INTO t1 VALUES (4), (5), (6), (NULL); +SELECT * FROM t1; +c1 +-685113344 +1 +2 +3 +4 +5 +6 +7 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL), (2), (-685113344), (5); +SELECT * FROM t1; +c1 +-685113344 +1 +2 +5 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1 +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1), (2), (-685113344), (NULL); +SELECT * FROM t1; +c1 +-685113344 +1 +2 +3 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) NOT NULL AUTO_INCREMENT, + PRIMARY KEY (`c1`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/r/innodb-consistent.result b/mysql-test/suite/innodb/r/innodb-consistent.result index 9115791b99c..9115791b99c 100644 --- a/mysql-test/r/innodb-consistent.result +++ b/mysql-test/suite/innodb/r/innodb-consistent.result diff --git a/mysql-test/suite/innodb/r/innodb-index.result b/mysql-test/suite/innodb/r/innodb-index.result index 67fbe0dce02..5d67a06b80f 100644 --- a/mysql-test/suite/innodb/r/innodb-index.result +++ b/mysql-test/suite/innodb/r/innodb-index.result @@ -46,13 +46,6 @@ t1 CREATE TABLE `t1` ( KEY `d2` (`d`), KEY `b` (`b`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 -CREATE TABLE `t1#1`(a INT PRIMARY KEY) ENGINE=InnoDB; -alter table t1 add unique index (c), add index (d); -ERROR HY000: Table 'test.t1#1' already exists -rename table `t1#1` to `t1#2`; -alter table t1 add unique index (c), add index (d); -ERROR HY000: Table 'test.t1#2' already exists -drop table `t1#2`; alter table t1 add unique index (c), add index (d); show create table t1; Table Create Table @@ -441,6 +434,7 @@ t3 CREATE TABLE `t3` ( KEY `c` (`c`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 alter table t2 drop index b, add index (b); +ERROR 42000: Incorrect index name 'b' show create table t2; Table Create Table t2 CREATE TABLE `t2` ( @@ -451,8 +445,8 @@ t2 CREATE TABLE `t2` ( `e` int(11) DEFAULT NULL, PRIMARY KEY (`a`), UNIQUE KEY `dc` (`d`,`c`), - KEY `c` (`c`), KEY `b` (`b`), + KEY `c` (`c`), CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`b`) ON DELETE CASCADE, CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`c`) REFERENCES `t3` (`c`), CONSTRAINT `t2_ibfk_3` FOREIGN KEY (`d`) REFERENCES `t4` (`d`) @@ -841,48 +835,6 @@ test.t1 check status OK explain select * from t1 where b like 'adfd%'; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL b NULL NULL NULL 15 Using where -create table t2(a int, b varchar(255), primary key(a,b)) engine=innodb; -insert into t2 select a,left(b,255) from t1; -drop table t1; -rename table t2 to t1; -set innodb_lock_wait_timeout=1; -begin; -select a from t1 limit 1 for update; -a -22 -set innodb_lock_wait_timeout=1; -create index t1ba on t1 (b,a); -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -commit; -begin; -select a from t1 limit 1 lock in share mode; -a -22 -create index t1ba on t1 (b,a); -drop index t1ba on t1; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -commit; -explain select a from t1 order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL t1ba 261 NULL 15 Using index -select a,sleep(2+a/100) from t1 order by b limit 3; -select sleep(1); -sleep(1) -0 -drop index t1ba on t1; -a sleep(2+a/100) -22 0 -44 0 -66 0 -explain select a from t1 order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 261 NULL 15 Using index; Using filesort -select a from t1 order by b limit 3; -a -22 -66 -44 -commit; drop table t1; set global innodb_file_per_table=on; set global innodb_file_format='Barracuda'; @@ -1133,39 +1085,3 @@ t2 CREATE TABLE `t2` ( ) ENGINE=InnoDB DEFAULT CHARSET=latin1 DROP TABLE t2; DROP TABLE t1; -CREATE TABLE t1 (a INT, b CHAR(1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (3,'a'),(3,'b'),(1,'c'),(0,'d'),(1,'e'); -BEGIN; -SELECT * FROM t1; -a b -3 a -3 b -1 c -0 d -1 e -CREATE INDEX t1a ON t1(a); -SELECT * FROM t1; -a b -3 a -3 b -1 c -0 d -1 e -SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a; -ERROR HY000: Table definition has changed, please retry transaction -SELECT * FROM t1; -a b -3 a -3 b -1 c -0 d -1 e -COMMIT; -SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a; -a b -0 d -1 c -1 e -3 a -3 b -DROP TABLE t1; diff --git a/mysql-test/r/innodb-lock.result b/mysql-test/suite/innodb/r/innodb-lock.result index ab7e9aa7b25..41f308788a2 100644 --- a/mysql-test/r/innodb-lock.result +++ b/mysql-test/suite/innodb/r/innodb-lock.result @@ -27,9 +27,10 @@ commit; drop table t1; # # Old lock method (where LOCK TABLE was ignored by InnoDB) no longer -# works due to fix for bugs #46272 "MySQL 5.4.4, new MDL: unnecessary -# deadlock" and bug #37346 "innodb does not detect deadlock between -# update and alter table". +# works when LOCK TABLE ... WRITE is used due to fix for bugs #46272 +# "MySQL 5.4.4, new MDL: unnecessary and bug #37346 "innodb does not +# detect deadlock between update and alter table". But it still works +# for LOCK TABLE ... READ. # set @@innodb_table_locks=0; create table t1 (id integer primary key, x integer) engine=INNODB; @@ -61,4 +62,30 @@ commit; # Reap LOCK TABLE. unlock tables; # Connection 'con1'. +select * from t1 where id = 0 for update; +id x +0 1 +# Connection 'con2'. +# The below statement should not be blocked as LOCK TABLES ... READ +# does not take strong SQL-level lock on t1. SELECTs which do not +# conflict with transaction in the first connections should not be +# blocked. +lock table t1 read; +select * from t1; +id x +0 1 +1 1 +2 2 +select * from t1 where id = 1 lock in share mode; +id x +1 1 +unlock tables; +select * from t1; +id x +0 1 +1 1 +2 2 +commit; +# Connection 'con1'. +commit; drop table t1; diff --git a/mysql-test/r/innodb-replace.result b/mysql-test/suite/innodb/r/innodb-replace.result index c926bb89a2e..c926bb89a2e 100644 --- a/mysql-test/r/innodb-replace.result +++ b/mysql-test/suite/innodb/r/innodb-replace.result diff --git a/mysql-test/r/innodb-semi-consistent.result b/mysql-test/suite/innodb/r/innodb-semi-consistent.result index ca0e362ef80..ca0e362ef80 100644 --- a/mysql-test/r/innodb-semi-consistent.result +++ b/mysql-test/suite/innodb/r/innodb-semi-consistent.result diff --git a/mysql-test/suite/innodb/r/innodb-system-table-view.result b/mysql-test/suite/innodb/r/innodb-system-table-view.result new file mode 100644 index 00000000000..ffa57ee32ce --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb-system-table-view.result @@ -0,0 +1,110 @@ +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES; +TABLE_ID NAME FLAG N_COLS SPACE +11 SYS_FOREIGN 0 7 0 +12 SYS_FOREIGN_COLS 0 7 0 +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES; +INDEX_ID NAME TABLE_ID TYPE N_FIELDS PAGE_NO SPACE +11 ID_IND 11 3 1 302 0 +12 FOR_IND 11 0 1 303 0 +13 REF_IND 11 0 1 304 0 +14 ID_IND 12 3 2 305 0 +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS; +TABLE_ID NAME POS MTYPE PRTYPE LEN +11 ID 0 1 524292 0 +11 FOR_NAME 1 1 524292 0 +11 REF_NAME 2 1 524292 0 +11 N_COLS 3 6 0 4 +12 ID 0 1 524292 0 +12 POS 1 6 0 4 +12 FOR_COL_NAME 2 1 524292 0 +12 REF_COL_NAME 3 1 524292 0 +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FIELDS; +INDEX_ID NAME POS +11 ID 0 +12 FOR_NAME 0 +13 REF_NAME 0 +14 ID 0 +14 POS 1 +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN; +ID FOR_NAME REF_NAME N_COLS TYPE +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS; +ID FOR_COL_NAME REF_COL_NAME POS +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS; +TABLE_ID NAME STATS_INITIALIZED NUM_ROWS CLUST_INDEX_SIZE OTHER_INDEX_SIZE MODIFIED_COUNTER AUTOINC MYSQL_HANDLES_OPENED +11 SYS_FOREIGN Uninitialized 0 0 0 0 0 0 +12 SYS_FOREIGN_COLS Uninitialized 0 0 0 0 0 0 +CREATE TABLE parent (id INT NOT NULL, +PRIMARY KEY (id)) ENGINE=INNODB; +CREATE TABLE child (id INT, parent_id INT, +INDEX par_ind (parent_id), +CONSTRAINT constraint_test +FOREIGN KEY (parent_id) REFERENCES parent(id) +ON DELETE CASCADE) ENGINE=INNODB; +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN; +ID FOR_NAME REF_NAME N_COLS TYPE +test/constraint_test test/child test/parent 1 1 +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS; +ID FOR_COL_NAME REF_COL_NAME POS +test/constraint_test parent_id id 0 +INSERT INTO parent VALUES(1); +SELECT name, num_rows, mysql_handles_opened +FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS +WHERE name LIKE "%parent"; +name num_rows mysql_handles_opened +test/parent 1 1 +SELECT NAME, FLAG, N_COLS, SPACE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES; +NAME FLAG N_COLS SPACE +SYS_FOREIGN 0 7 0 +SYS_FOREIGN_COLS 0 7 0 +test/child 1 5 0 +test/parent 1 4 0 +SELECT name, n_fields +from INFORMATION_SCHEMA.INNODB_SYS_INDEXES +WHERE table_id In (SELECT table_id from +INFORMATION_SCHEMA.INNODB_SYS_TABLES +WHERE name LIKE "%parent%"); +name n_fields +PRIMARY 1 +SELECT name, n_fields +from INFORMATION_SCHEMA.INNODB_SYS_INDEXES +WHERE table_id In (SELECT table_id from +INFORMATION_SCHEMA.INNODB_SYS_TABLES +WHERE name LIKE "%child%"); +name n_fields +GEN_CLUST_INDEX 0 +par_ind 1 +SELECT name, pos, mtype, len +from INFORMATION_SCHEMA.INNODB_SYS_COLUMNS +WHERE table_id In (SELECT table_id from +INFORMATION_SCHEMA.INNODB_SYS_TABLES +WHERE name LIKE "%child%"); +name pos mtype len +id 0 6 4 +parent_id 1 6 4 +DROP TABLE child; +DROP TABLE parent; +CREATE TABLE parent (id INT NOT NULL, newid INT NOT NULL, +PRIMARY KEY (id, newid)) ENGINE=INNODB; +CREATE TABLE child (id INT, parent_id INT, +INDEX par_ind (parent_id), +CONSTRAINT constraint_test +FOREIGN KEY (id, parent_id) REFERENCES parent(id, newid) +ON DELETE CASCADE) ENGINE=INNODB; +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN; +ID FOR_NAME REF_NAME N_COLS TYPE +test/constraint_test test/child test/parent 2 1 +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS; +ID FOR_COL_NAME REF_COL_NAME POS +test/constraint_test id id 0 +test/constraint_test parent_id newid 1 +INSERT INTO parent VALUES(1, 9); +SELECT * FROM parent WHERE id IN (SELECT id FROM parent); +id newid +1 9 +SELECT name, num_rows, mysql_handles_opened +FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS +WHERE name LIKE "%parent"; +name num_rows mysql_handles_opened +test/parent 1 2 +DROP TABLE child; +DROP TABLE parent; diff --git a/mysql-test/r/innodb.result b/mysql-test/suite/innodb/r/innodb.result index 4f2009764fc..2e5585ee7af 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/suite/innodb/r/innodb.result @@ -169,10 +169,10 @@ Table Op Msg_type Msg_text test.t1 optimize note Table does not support optimize, doing recreate + analyze instead test.t1 optimize status OK show keys from t1; -Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment -t1 0 PRIMARY 1 id A # NULL NULL BTREE -t1 1 parent_id 1 parent_id A # NULL NULL BTREE -t1 1 level 1 level A # NULL NULL BTREE +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 PRIMARY 1 id A # NULL NULL BTREE +t1 1 parent_id 1 parent_id A # NULL NULL BTREE +t1 1 level 1 level A # NULL NULL BTREE drop table t1; CREATE TABLE t1 ( gesuchnr int(11) DEFAULT '0' NOT NULL, @@ -213,8 +213,8 @@ analyze table t1; Table Op Msg_type Msg_text test.t1 analyze status OK show keys from t1; -Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment -t1 1 skr 1 a A # NULL NULL YES BTREE +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 1 skr 1 a A # NULL NULL YES BTREE drop table t1; create table t1 (a int,b varchar(20),key(a)) engine=innodb; insert into t1 values (1,""), (2,"testing"); @@ -401,13 +401,13 @@ drop table t1; CREATE TABLE t1 (a int not null, b int not null,c int not null, key(a),primary key(a,b), unique(c),key(a),unique(b)); show index from t1; -Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment -t1 0 PRIMARY 1 a A # NULL NULL BTREE -t1 0 PRIMARY 2 b A # NULL NULL BTREE -t1 0 c 1 c A # NULL NULL BTREE -t1 0 b 1 b A # NULL NULL BTREE -t1 1 a 1 a A # NULL NULL BTREE -t1 1 a_2 1 a A # NULL NULL BTREE +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 PRIMARY 1 a A # NULL NULL BTREE +t1 0 PRIMARY 2 b A # NULL NULL BTREE +t1 0 c 1 c A # NULL NULL BTREE +t1 0 b 1 b A # NULL NULL BTREE +t1 1 a 1 a A # NULL NULL BTREE +t1 1 a_2 1 a A # NULL NULL BTREE drop table t1; create table t1 (col1 int not null, col2 char(4) not null, primary key(col1)); alter table t1 engine=innodb; @@ -692,6 +692,8 @@ select count(*) from t1 where sca_pic is null; count(*) 2 alter table t1 drop index sca_pic, add index sca_pic (cat_code, sca_pic); +alter table t1 drop index sca_pic; +alter table t1 add index sca_pic (cat_code, sca_pic); select count(*) from t1 where sca_code='PD' and sca_pic is null; count(*) 1 @@ -699,6 +701,9 @@ select count(*) from t1 where cat_code='E'; count(*) 0 alter table t1 drop index sca_pic, add index (sca_pic, cat_code); +ERROR 42000: Incorrect index name 'sca_pic' +alter table t1 drop index sca_pic; +alter table t1 add index (sca_pic, cat_code); select count(*) from t1 where sca_code='PD' and sca_pic is null; count(*) 1 @@ -743,8 +748,8 @@ Table Op Msg_type Msg_text test.t1 optimize note Table does not support optimize, doing recreate + analyze instead test.t1 optimize status OK show keys from t1; -Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment -t1 0 PRIMARY 1 a A # NULL NULL BTREE +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t1 0 PRIMARY 1 a A # NULL NULL BTREE drop table t1; create table t1 (i int, j int ) ENGINE=innodb; insert into t1 values (1,2); @@ -1179,82 +1184,6 @@ a b 8 8 9 9 drop table t1; -CREATE TABLE t1 (a int not null primary key, b int not null, key (b)) engine=innodb; -CREATE TABLE t2 (a int not null primary key, b int not null, key (b)) engine=innodb; -INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12); -INSERT INTO t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); -update t1,t2 set t1.a=t1.a+100; -select * from t1; -a b -101 1 -102 2 -103 3 -104 4 -105 5 -106 6 -107 7 -108 8 -109 9 -110 10 -111 11 -112 12 -update t1,t2 set t1.a=t1.a+100 where t1.a=101; -select * from t1; -a b -201 1 -102 2 -103 3 -104 4 -105 5 -106 6 -107 7 -108 8 -109 9 -110 10 -111 11 -112 12 -update t1,t2 set t1.b=t1.b+10 where t1.b=2; -select * from t1; -a b -201 1 -103 3 -104 4 -105 5 -106 6 -107 7 -108 8 -109 9 -110 10 -111 11 -102 12 -112 12 -update t1,t2 set t1.b=t1.b+2,t2.b=t1.b+10 where t1.b between 3 and 5 and t1.a=t2.a+100; -select * from t1; -a b -201 1 -103 5 -104 6 -106 6 -105 7 -107 7 -108 8 -109 9 -110 10 -111 11 -102 12 -112 12 -select * from t2; -a b -1 1 -2 2 -6 6 -7 7 -8 8 -9 9 -3 13 -4 14 -5 15 -drop table t1,t2; CREATE TABLE t2 ( NEXT_T BIGINT NOT NULL PRIMARY KEY) ENGINE=MyISAM; CREATE TABLE t1 ( B_ID INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; SET AUTOCOMMIT=0; @@ -1643,12 +1572,6 @@ ERROR 42S21: Duplicate column name 'c1' alter table t1 add key (c1,c1,c2); ERROR 42S21: Duplicate column name 'c1' drop table t1; -create table t1(a int(1) , b int(1)) engine=innodb; -insert into t1 values ('1111', '3333'); -select distinct concat(a, b) from t1; -concat(a, b) -11113333 -drop table t1; CREATE TABLE t1 ( a char(10) ) ENGINE=InnoDB; SELECT a FROM t1 WHERE MATCH (a) AGAINST ('test' IN BOOLEAN MODE); ERROR HY000: The used table type doesn't support FULLTEXT indexes @@ -1738,7 +1661,7 @@ count(*) drop table t1; SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_buffer_pool_pages_total'; variable_value -512 +511 SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_page_size'; variable_value 16384 @@ -1747,10 +1670,10 @@ variable_value - @innodb_rows_deleted_orig 71 SELECT variable_value - @innodb_rows_inserted_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_inserted'; variable_value - @innodb_rows_inserted_orig -1084 +1065 SELECT variable_value - @innodb_rows_updated_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_updated'; variable_value - @innodb_rows_updated_orig -885 +865 SELECT variable_value - @innodb_row_lock_waits_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_waits'; variable_value - @innodb_row_lock_waits_orig 0 @@ -1833,6 +1756,7 @@ show variables like "innodb_thread_sleep_delay"; Variable_name Value innodb_thread_sleep_delay 10000 set storage_engine=INNODB; +set session old_alter_table=1; drop table if exists t1,t2,t3; --- Testing varchar --- --- Testing varchar --- @@ -1970,7 +1894,7 @@ explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ref v v 13 const # Using where; Using index alter table t1 add unique(v); -ERROR 23000: Duplicate entry 'v' for key 'v_2' +ERROR 23000: Duplicate entry '{ ' for key 'v_2' alter table t1 add key(v); select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a'; qq @@ -2406,6 +2330,7 @@ select * from t1 where a=20 and b is null; a b 20 NULL drop table t1; +set session old_alter_table=0; create table t1 (v varchar(65530), key(v)); Warnings: Warning 1071 Specified key was too long; max key length is 767 bytes @@ -2723,7 +2648,7 @@ create table t3 (s1 varchar(2) binary,primary key (s1)) engine=innodb; create table t4 (s1 char(2) binary,primary key (s1)) engine=innodb; insert into t1 values (0x41),(0x4120),(0x4100); insert into t2 values (0x41),(0x4120),(0x4100); -ERROR 23000: Duplicate entry 'A\x00' for key 'PRIMARY' +ERROR 23000: Duplicate entry 'A' for key 'PRIMARY' insert into t2 values (0x41),(0x4120); insert into t3 values (0x41),(0x4120),(0x4100); ERROR 23000: Duplicate entry 'A ' for key 'PRIMARY' @@ -2832,65 +2757,6 @@ t2 CREATE TABLE `t2` ( KEY `t2_ibfk_0` (`a`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 DROP TABLE t2,t1; -create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -insert into t1(a) values (1),(2),(3); -create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end | -commit; -set autocommit = 0; -update t1 set b = 5 where a = 2; -set autocommit = 0; -insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100), -(11),(21),(31),(41),(51),(61),(71),(81),(91),(101), -(12),(22),(32),(42),(52),(62),(72),(82),(92),(102), -(13),(23),(33),(43),(53),(63),(73),(83),(93),(103), -(14),(24),(34),(44),(54),(64),(74),(84),(94),(104); -commit; -commit; -drop trigger t1t; -drop table t1; -create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t2(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t3(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t4(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t5(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -insert into t1(a) values (1),(2),(3); -insert into t2(a) values (1),(2),(3); -insert into t3(a) values (1),(2),(3); -insert into t4(a) values (1),(2),(3); -insert into t3(a) values (5),(7),(8); -insert into t4(a) values (5),(7),(8); -insert into t5(a) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12); -create trigger t1t before insert on t1 for each row begin -INSERT INTO t2 SET a = NEW.a; -end | -create trigger t2t before insert on t2 for each row begin -DELETE FROM t3 WHERE a = NEW.a; -end | -create trigger t3t before delete on t3 for each row begin -UPDATE t4 SET b = b + 1 WHERE a = OLD.a; -end | -create trigger t4t before update on t4 for each row begin -UPDATE t5 SET b = b + 1 where a = NEW.a; -end | -commit; -set autocommit = 0; -update t1 set b = b + 5 where a = 1; -update t2 set b = b + 5 where a = 1; -update t3 set b = b + 5 where a = 1; -update t4 set b = b + 5 where a = 1; -insert into t5(a) values(20); -set autocommit = 0; -insert into t1(a) values(7); -insert into t2(a) values(8); -delete from t2 where a = 3; -update t4 set b = b + 1 where a = 3; -commit; -commit; -drop trigger t1t; -drop trigger t2t; -drop trigger t3t; -drop trigger t4t; -drop table t1, t2, t3, t4, t5; CREATE TABLE t1 ( field1 varchar(8) NOT NULL DEFAULT '', field2 varchar(8) NOT NULL DEFAULT '', diff --git a/storage/innobase/mysql-test/innodb_bug21704.result b/mysql-test/suite/innodb/r/innodb_bug21704.result index b8e0b15d50d..ffbfa8a337e 100644 --- a/storage/innobase/mysql-test/innodb_bug21704.result +++ b/mysql-test/suite/innodb/r/innodb_bug21704.result @@ -25,8 +25,8 @@ ALTER TABLE t1 CHANGE a c INT; ERROR HY000: Error on rename of '#sql-temporary' to './test/t1' (errno: 150) # Ensure that online column rename works. ALTER TABLE t1 CHANGE b c INT; -affected rows: 0 -info: Records: 0 Duplicates: 0 Warnings: 0 +affected rows: 3 +info: Records: 3 Duplicates: 0 Warnings: 0 # Test renaming the column in the referencing table @@ -34,8 +34,8 @@ ALTER TABLE t2 CHANGE a c INT; ERROR HY000: Error on rename of '#sql-temporary' to './test/t2' (errno: 150) # Ensure that online column rename works. ALTER TABLE t2 CHANGE b c INT; -affected rows: 0 -info: Records: 0 Duplicates: 0 Warnings: 0 +affected rows: 3 +info: Records: 3 Duplicates: 0 Warnings: 0 # Test with self-referential constraints @@ -45,8 +45,8 @@ ALTER TABLE t3 CHANGE b d INT; ERROR HY000: Error on rename of '#sql-temporary' to './test/t3' (errno: 150) # Ensure that online column rename works. ALTER TABLE t3 CHANGE c d INT; -affected rows: 0 -info: Records: 0 Duplicates: 0 Warnings: 0 +affected rows: 3 +info: Records: 3 Duplicates: 0 Warnings: 0 # Cleanup. diff --git a/mysql-test/r/innodb_bug34053.result b/mysql-test/suite/innodb/r/innodb_bug34053.result index 195775f74c8..195775f74c8 100644 --- a/mysql-test/r/innodb_bug34053.result +++ b/mysql-test/suite/innodb/r/innodb_bug34053.result diff --git a/mysql-test/r/innodb_bug34300.result b/mysql-test/suite/innodb/r/innodb_bug34300.result index ae9fee81ad7..ae9fee81ad7 100644 --- a/mysql-test/r/innodb_bug34300.result +++ b/mysql-test/suite/innodb/r/innodb_bug34300.result diff --git a/mysql-test/r/innodb_bug35220.result b/mysql-test/suite/innodb/r/innodb_bug35220.result index 195775f74c8..195775f74c8 100644 --- a/mysql-test/r/innodb_bug35220.result +++ b/mysql-test/suite/innodb/r/innodb_bug35220.result diff --git a/mysql-test/suite/innodb/r/innodb_bug38231.result b/mysql-test/suite/innodb/r/innodb_bug38231.result new file mode 100644 index 00000000000..41a40542b84 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug38231.result @@ -0,0 +1,11 @@ +SET storage_engine=InnoDB; +INSERT INTO bug38231_2 VALUES (1), (10), (300); +SET autocommit=0; +SELECT * FROM bug38231_2 FOR UPDATE; +a +1 +10 +300 +TRUNCATE TABLE bug38231_2; +COMMIT; +DROP TABLE bug38231_2; diff --git a/mysql-test/r/innodb_bug39438.result b/mysql-test/suite/innodb/r/innodb_bug39438.result index 195775f74c8..195775f74c8 100644 --- a/mysql-test/r/innodb_bug39438.result +++ b/mysql-test/suite/innodb/r/innodb_bug39438.result diff --git a/mysql-test/r/innodb_bug40565.result b/mysql-test/suite/innodb/r/innodb_bug40565.result index 21e923d9336..21e923d9336 100644 --- a/mysql-test/r/innodb_bug40565.result +++ b/mysql-test/suite/innodb/r/innodb_bug40565.result diff --git a/mysql-test/r/innodb_bug42101-nonzero.result b/mysql-test/suite/innodb/r/innodb_bug42101-nonzero.result index f43cb9da239..f43cb9da239 100644 --- a/mysql-test/r/innodb_bug42101-nonzero.result +++ b/mysql-test/suite/innodb/r/innodb_bug42101-nonzero.result diff --git a/mysql-test/r/innodb_bug42101.result b/mysql-test/suite/innodb/r/innodb_bug42101.result index 4e3367d5a54..4e3367d5a54 100644 --- a/mysql-test/r/innodb_bug42101.result +++ b/mysql-test/suite/innodb/r/innodb_bug42101.result diff --git a/mysql-test/r/innodb_bug44369.result b/mysql-test/suite/innodb/r/innodb_bug44369.result index ff25c774aa2..ff25c774aa2 100644 --- a/mysql-test/r/innodb_bug44369.result +++ b/mysql-test/suite/innodb/r/innodb_bug44369.result diff --git a/mysql-test/suite/innodb/r/innodb_bug44571.result b/mysql-test/suite/innodb/r/innodb_bug44571.result new file mode 100644 index 00000000000..7ee7820a02d --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug44571.result @@ -0,0 +1,8 @@ +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +ERROR 42000: Key column 'foo' doesn't exist in table +ALTER TABLE bug44571 ADD INDEX bug44571c (bar); +DROP INDEX bug44571c ON bug44571; +CREATE INDEX bug44571c ON bug44571 (bar); +DROP TABLE bug44571; diff --git a/mysql-test/r/innodb_bug45357.result b/mysql-test/suite/innodb/r/innodb_bug45357.result index 7adeff2062f..7adeff2062f 100644 --- a/mysql-test/r/innodb_bug45357.result +++ b/mysql-test/suite/innodb/r/innodb_bug45357.result diff --git a/mysql-test/r/innodb_bug46000.result b/mysql-test/suite/innodb/r/innodb_bug46000.result index c8e3db8d641..c8e3db8d641 100644 --- a/mysql-test/r/innodb_bug46000.result +++ b/mysql-test/suite/innodb/r/innodb_bug46000.result diff --git a/mysql-test/suite/innodb/r/innodb_bug47621.result b/mysql-test/suite/innodb/r/innodb_bug47621.result new file mode 100644 index 00000000000..c5f56c09788 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug47621.result @@ -0,0 +1,21 @@ +CREATE TABLE bug47621 (salesperson INT) ENGINE=InnoDB; +ALTER TABLE bug47621 CHANGE salesperson sales_acct_id INT; +create index orgs on bug47621(sales_acct_id); +ALTER TABLE bug47621 CHANGE sales_acct_id salesperson INT; +drop table bug47621; +CREATE TABLE bug47621_sale ( +salesperson INT, +PRIMARY KEY(salesperson)) engine = innodb; +CREATE TABLE bug47621_shirt( +id SMALLINT, +owner INT, +FOREIGN KEY(owner) +references bug47621_sale(salesperson) ON DELETE RESTRICT) +engine = innodb; +insert into bug47621_sale values(9); +insert into bug47621_shirt values(1, 9); +ALTER TABLE bug47621_shirt CHANGE id new_id INT; +drop table bug47621_shirt; +ALTER TABLE bug47621_sale CHANGE salesperson sales_acct_id INT; +ALTER TABLE bug47621_sale ADD INDEX idx (sales_acct_id); +drop table bug47621_sale; diff --git a/mysql-test/suite/innodb/r/innodb_bug47622.result b/mysql-test/suite/innodb/r/innodb_bug47622.result new file mode 100644 index 00000000000..f5d13711c52 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug47622.result @@ -0,0 +1,23 @@ +CREATE TABLE bug47622( +`rule_key` int(11) NOT NULL DEFAULT '0', +`seq` smallint(6) NOT NULL DEFAULT '0', +`action` smallint(6) NOT NULL DEFAULT '0', +`arg_id` smallint(6) DEFAULT NULL, +`else_ind` TINYINT NOT NULL, +KEY IDX_A (`arg_id`) +) ENGINE=InnoDB; +ALTER TABLE bug47622 ADD UNIQUE IDX_B (rule_key,else_ind,seq,action,arg_id); +drop index IDX_B on bug47622; +create index idx on bug47622(seq, arg_id); +ALTER TABLE bug47622 ADD UNIQUE IDX_X (rule_key,else_ind,seq,action); +drop table bug47622; +CREATE TABLE bug47622 ( +`a` int(11) NOT NULL, +`b` int(11) DEFAULT NULL, +`c` char(10) DEFAULT NULL, +`d` varchar(20) DEFAULT NULL, +PRIMARY KEY (`a`), +KEY `b` (`b`) +) ENGINE=InnoDB; +alter table bug47622 add unique index (c), add index (d); +drop table bug47622; diff --git a/mysql-test/r/innodb_bug47777.result b/mysql-test/suite/innodb/r/innodb_bug47777.result index fbba47edcfc..fbba47edcfc 100644 --- a/mysql-test/r/innodb_bug47777.result +++ b/mysql-test/suite/innodb/r/innodb_bug47777.result diff --git a/mysql-test/suite/innodb/r/innodb_bug48024.result b/mysql-test/suite/innodb/r/innodb_bug48024.result new file mode 100644 index 00000000000..611923d2796 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug48024.result @@ -0,0 +1,10 @@ +CREATE TABLE bug48024(a int PRIMARY KEY,b int NOT NULL,KEY(b)) ENGINE=InnoDB; +CREATE TABLE bug48024_b(b int PRIMARY KEY) ENGINE=InnoDB; +ALTER TABLE bug48024 /*/ADD CONSTRAINT FOREIGN KEY(c) REFERENCES(a),/*/ +ADD CONSTRAINT FOREIGN KEY(b) REFERENCES bug48024_b(b); +DROP TABLE bug48024,bug48024_b; +CREATE TABLE bug48024(a int PRIMARY KEY,b int NOT NULL,KEY(b)) ENGINE=InnoDB; +CREATE TABLE bug48024_b(b int PRIMARY KEY) ENGINE=InnoDB; +ALTER TABLE bug48024 /*/ADD CONSTRAINT FOREIGN KEY(c) REFERENCES(a),/*/ +ADD CONSTRAINT FOREIGN KEY(b) REFERENCES bug48024_b(b)| +DROP TABLE bug48024,bug48024_b; diff --git a/mysql-test/suite/innodb/r/innodb_bug49164.result b/mysql-test/suite/innodb/r/innodb_bug49164.result new file mode 100644 index 00000000000..9456702e1d0 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug49164.result @@ -0,0 +1,42 @@ +SET tx_isolation = 'READ-COMMITTED'; +CREATE TABLE bug49164 (a INT, b BIGINT, c TINYINT, PRIMARY KEY (a, b)) +ENGINE=InnoDB; +insert into bug49164 values (1,1,1), (2,2,2), (3,3,3); +begin; +update bug49164 set c=7; +select * from bug49164; +a b c +1 1 7 +2 2 7 +3 3 7 +rollback; +select * from bug49164; +a b c +1 1 1 +2 2 2 +3 3 3 +begin; +update bug49164 set c=7; +SET tx_isolation = 'READ-COMMITTED'; +begin; +select * from bug49164; +a b c +1 1 1 +2 2 2 +3 3 3 +commit; +begin; +update bug49164 set c=6 where a=1 and b=1; +rollback; +select * from bug49164; +a b c +1 1 1 +2 2 2 +3 3 3 +commit; +select * from bug49164; +a b c +1 1 6 +2 2 2 +3 3 3 +drop table bug49164; diff --git a/mysql-test/suite/innodb/r/innodb_bug51378.result b/mysql-test/suite/innodb/r/innodb_bug51378.result new file mode 100644 index 00000000000..a3ca73c16a9 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug51378.result @@ -0,0 +1,66 @@ +create table bug51378 ( +col1 int not null, +col2 blob not null, +col3 time not null) engine = innodb; +create unique index idx on bug51378(col1, col2(31)); +alter table bug51378 add unique index idx2(col1, col2(31)); +create unique index idx3 on bug51378(col1, col3); +SHOW CREATE TABLE bug51378; +Table Create Table +bug51378 CREATE TABLE `bug51378` ( + `col1` int(11) NOT NULL, + `col2` blob NOT NULL, + `col3` time NOT NULL, + UNIQUE KEY `idx3` (`col1`,`col3`), + UNIQUE KEY `idx` (`col1`,`col2`(31)), + UNIQUE KEY `idx2` (`col1`,`col2`(31)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop index idx3 on bug51378; +SHOW CREATE TABLE bug51378; +Table Create Table +bug51378 CREATE TABLE `bug51378` ( + `col1` int(11) NOT NULL, + `col2` blob NOT NULL, + `col3` time NOT NULL, + UNIQUE KEY `idx` (`col1`,`col2`(31)), + UNIQUE KEY `idx2` (`col1`,`col2`(31)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +alter table bug51378 add primary key idx3(col1, col2(31)); +SHOW CREATE TABLE bug51378; +Table Create Table +bug51378 CREATE TABLE `bug51378` ( + `col1` int(11) NOT NULL, + `col2` blob NOT NULL, + `col3` time NOT NULL, + PRIMARY KEY (`col1`,`col2`(31)), + UNIQUE KEY `idx` (`col1`,`col2`(31)), + UNIQUE KEY `idx2` (`col1`,`col2`(31)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop table bug51378; +create table bug51378 ( +col1 int not null, +col2 blob not null, +col3 time not null, primary key(col1, col2(31))) engine = innodb; +create unique index idx on bug51378(col1, col2(31)); +SHOW CREATE TABLE bug51378; +Table Create Table +bug51378 CREATE TABLE `bug51378` ( + `col1` int(11) NOT NULL, + `col2` blob NOT NULL, + `col3` time NOT NULL, + PRIMARY KEY (`col1`,`col2`(31)), + UNIQUE KEY `idx` (`col1`,`col2`(31)) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop table bug51378; +create table bug51378 ( +col1 int not null, +col2 int ) engine = innodb; +create unique index idx on bug51378(col1, col2); +SHOW CREATE TABLE bug51378; +Table Create Table +bug51378 CREATE TABLE `bug51378` ( + `col1` int(11) NOT NULL, + `col2` int(11) DEFAULT NULL, + UNIQUE KEY `idx` (`col1`,`col2`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop table bug51378; diff --git a/mysql-test/suite/innodb/r/innodb_bug51920.result b/mysql-test/suite/innodb/r/innodb_bug51920.result new file mode 100644 index 00000000000..7ded141c239 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug51920.result @@ -0,0 +1,13 @@ +CREATE TABLE bug51920 (i INT) ENGINE=InnoDB; +INSERT INTO bug51920 VALUES (1); +BEGIN; +SELECT * FROM bug51920 FOR UPDATE; +i +1 +UPDATE bug51920 SET i=2; +SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE INFO="UPDATE bug51920 SET i=2" +INTO @thread_id; +KILL @thread_id; +Got one of the listed errors +DROP TABLE bug51920; diff --git a/mysql-test/suite/innodb/r/innodb_bug52663.result b/mysql-test/suite/innodb/r/innodb_bug52663.result new file mode 100644 index 00000000000..89add18617b --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug52663.result @@ -0,0 +1,26 @@ +set session transaction isolation level read committed; +create table innodb_bug52663 (what varchar(5), id integer, count integer, primary key +(what, id)) engine=innodb; +insert into innodb_bug52663 values ('total', 0, 0); +begin; +set session transaction isolation level read committed; +begin; +update innodb_bug52663 set count = count + 1 where what = 'total' and id = 0; +select * from innodb_bug52663; +what id count +total 0 1 +update innodb_bug52663 set count = count + 1 where what = 'total' and id = 0; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +select * from innodb_bug52663; +what id count +total 0 0 +commit; +update innodb_bug52663 set count = count + 1 where what = 'total' and id = 0; +commit; +select * from innodb_bug52663; +what id count +total 0 2 +select * from innodb_bug52663; +what id count +total 0 2 +drop table innodb_bug52663; diff --git a/mysql-test/suite/innodb/r/innodb_bug52745.result b/mysql-test/suite/innodb/r/innodb_bug52745.result new file mode 100644 index 00000000000..254c6525257 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug52745.result @@ -0,0 +1,130 @@ +SET GLOBAL innodb_file_format='Barracuda'; +SET GLOBAL innodb_file_per_table=on; +CREATE TABLE bug52745 ( +a2 int(10) unsigned DEFAULT NULL, +col37 time DEFAULT NULL, +col38 char(229) CHARACTER SET utf8 DEFAULT NULL, +col39 text, +col40 timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, +col41 int(10) unsigned DEFAULT NULL, +col42 varchar(248) CHARACTER SET utf8 DEFAULT NULL, +col43 smallint(5) unsigned zerofill DEFAULT NULL, +col44 varchar(150) CHARACTER SET utf8 DEFAULT NULL, +col45 float unsigned zerofill DEFAULT NULL, +col46 binary(1) DEFAULT NULL, +col47 tinyint(4) DEFAULT NULL, +col48 tinyint(1) DEFAULT NULL, +col49 timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', +col50 binary(1) DEFAULT NULL, +col51 double unsigned zerofill DEFAULT NULL, +col52 int(10) unsigned DEFAULT NULL, +col53 time DEFAULT NULL, +col54 double unsigned DEFAULT NULL, +col55 time DEFAULT NULL, +col56 mediumtext CHARACTER SET latin2, +col57 blob, +col58 decimal(52,16) unsigned zerofill NOT NULL DEFAULT '000000000000000000000000000000000000.0000000000000000', +col59 binary(1) DEFAULT NULL, +col60 longblob, +col61 time DEFAULT NULL, +col62 longtext CHARACTER SET utf8 COLLATE utf8_persian_ci, +col63 timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', +col64 int(10) unsigned DEFAULT NULL, +col65 date DEFAULT NULL, +col66 timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', +col67 binary(1) DEFAULT NULL, +col68 tinyblob, +col69 date DEFAULT NULL, +col70 tinyint(3) unsigned zerofill DEFAULT NULL, +col71 varchar(44) CHARACTER SET utf8 DEFAULT NULL, +col72 datetime DEFAULT NULL, +col73 smallint(5) unsigned zerofill DEFAULT NULL, +col74 longblob, +col75 bit(34) DEFAULT NULL, +col76 float unsigned zerofill DEFAULT NULL, +col77 year(2) DEFAULT NULL, +col78 tinyint(3) unsigned DEFAULT NULL, +col79 set('msfheowh','tbpxbgf','by','wahnrjw','myqfasxz','rsokyumrt') CHARACTER SET latin2 DEFAULT NULL, +col80 datetime DEFAULT NULL, +col81 smallint(6) DEFAULT NULL, +col82 enum('xtaurnqfqz','rifrse','kuzwpbvb','niisabk','zxavro','rbvasv','','uulrfaove','','') DEFAULT NULL, +col83 bigint(20) unsigned zerofill DEFAULT NULL, +col84 float unsigned zerofill DEFAULT NULL, +col85 double DEFAULT NULL, +col86 enum('ylannv','','vlkhycqc','snke','cxifustp','xiaxaswzp','oxl') CHARACTER SET latin1 COLLATE latin1_german2_ci DEFAULT NULL, +col87 varbinary(221) DEFAULT NULL, +col88 double unsigned DEFAULT NULL, +col89 float unsigned zerofill DEFAULT NULL, +col90 tinyblob +) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; +Warnings: +Note 1291 Column 'col82' has duplicated value '' in ENUM +Note 1291 Column 'col82' has duplicated value '' in ENUM +INSERT INTO bug52745 SET +col40='0000-00-00 00:00:00', +col51=16547, +col53='7711484', +col54=-28604, +col55='7112612', +col56='wakefulness\'', +col57=repeat('absorbefacient\'',106), +col58=11027, +col59='AM09gW7', +col60=repeat('Noelani\'',16), +col61='2520576', +col62='substitutiv', +col63='19950106155112', +col64=-12038, +col65='86238806', +col66='19600719080256', +col68=repeat('Sagittarius\'',54), +col69='38943902', +col70=1232, +col71='Elora\'', +col74=repeat('zipp',11), +col75='0', +col76=23254, +col78=13247, +col79='56219', +col80='20500609035724', +col81=11632, +col82=7, +col84=-23863, +col85=6341, +col87='HZdkf.4 s7t,5Rmq 8so fmr,ruGLUG25TrtI.yQ 2SuHq0ML7rw7.4 b2yf2E5TJxOtBBZImezDnzpj,uPYfznnEUDN1e9aQoO 2DsplB7TFWy oQJ br HLF :F,eQ p4i1oWsr lL3PG,hjCz6hYqN h1QTjLCjrv:QCdSzpYBibJAtZCxLOk3l6Blsh.W', +col88=16894, +col89=6161, +col90=repeat('gale',48); +Warnings: +Warning 1265 Data truncated for column 'col53' at row 1 +Warning 1264 Out of range value for column 'col54' at row 1 +Warning 1265 Data truncated for column 'col59' at row 1 +Warning 1265 Data truncated for column 'col61' at row 1 +Warning 1264 Out of range value for column 'col64' at row 1 +Warning 1265 Data truncated for column 'col65' at row 1 +Warning 1264 Out of range value for column 'col66' at row 1 +Warning 1265 Data truncated for column 'col68' at row 1 +Warning 1265 Data truncated for column 'col69' at row 1 +Warning 1264 Out of range value for column 'col70' at row 1 +Warning 1264 Out of range value for column 'col78' at row 1 +Warning 1265 Data truncated for column 'col79' at row 1 +Warning 1264 Out of range value for column 'col84' at row 1 +SHOW WARNINGS; +Level Code Message +Warning 1265 Data truncated for column 'col53' at row 1 +Warning 1264 Out of range value for column 'col54' at row 1 +Warning 1265 Data truncated for column 'col59' at row 1 +Warning 1265 Data truncated for column 'col61' at row 1 +Warning 1264 Out of range value for column 'col64' at row 1 +Warning 1265 Data truncated for column 'col65' at row 1 +Warning 1264 Out of range value for column 'col66' at row 1 +Warning 1265 Data truncated for column 'col68' at row 1 +Warning 1265 Data truncated for column 'col69' at row 1 +Warning 1264 Out of range value for column 'col70' at row 1 +Warning 1264 Out of range value for column 'col78' at row 1 +Warning 1265 Data truncated for column 'col79' at row 1 +Warning 1264 Out of range value for column 'col84' at row 1 +DROP TABLE bug52745; +SET GLOBAL innodb_file_format=Antelope; +SET GLOBAL innodb_file_format_check=Antelope; +SET GLOBAL innodb_file_per_table=0; diff --git a/mysql-test/suite/innodb/r/innodb_bug53290.result b/mysql-test/suite/innodb/r/innodb_bug53290.result new file mode 100644 index 00000000000..46cd7248c4e --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug53290.result @@ -0,0 +1,17 @@ +create table bug53290 (x bigint) engine=innodb; +insert into bug53290 () values (),(),(),(),(),(),(),(),(),(),(),(); +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +alter table bug53290 add unique index `idx` (x); +drop table bug53290; diff --git a/mysql-test/suite/innodb/r/innodb_bug53591.result b/mysql-test/suite/innodb/r/innodb_bug53591.result new file mode 100644 index 00000000000..1f05b6d2a57 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug53591.result @@ -0,0 +1,16 @@ +SET GLOBAL innodb_file_format='Barracuda'; +SET GLOBAL innodb_file_per_table=on; +set old_alter_table=0; +CREATE TABLE bug53591(a text charset utf8 not null) +ENGINE=InnoDB KEY_BLOCK_SIZE=1; +ALTER TABLE bug53591 ADD PRIMARY KEY(a(220)); +ERROR HY000: Too big row +SHOW WARNINGS; +Level Code Message +Error 139 Too big row +Error 1118 Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs +Error 1030 Got error 139 from storage engine +DROP TABLE bug53591; +SET GLOBAL innodb_file_format=Antelope; +SET GLOBAL innodb_file_format_check=Antelope; +SET GLOBAL innodb_file_per_table=0; diff --git a/mysql-test/suite/innodb/r/innodb_bug53592.result b/mysql-test/suite/innodb/r/innodb_bug53592.result new file mode 100644 index 00000000000..63b30f50413 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug53592.result @@ -0,0 +1,43 @@ +set old_alter_table=0; +create table bug53592(a int) engine=innodb row_format=compact; +alter table bug53592 add column b text charset utf8; +alter table bug53592 add column c blob not null; +create index bug53592_b on bug53592(b(81)); +create unique index bug53592_c on bug53592(c(1)); +replace into bug53592 values (),(); +Warnings: +Warning 1364 Field 'c' doesn't have a default value +check table bug53592; +Table Op Msg_type Msg_text +test.bug53592 check status OK +drop table bug53592; +set old_alter_table=1; +create table bug53592(a int) engine=innodb row_format=compact; +alter table bug53592 add column b text charset utf8; +alter table bug53592 add column c blob not null; +create index bug53592_b on bug53592(b(81)); +create unique index bug53592_c on bug53592(c(1)); +replace into bug53592 values (),(); +Warnings: +Warning 1364 Field 'c' doesn't have a default value +check table bug53592; +Table Op Msg_type Msg_text +test.bug53592 check status OK +drop table bug53592; +CREATE TABLE bug53592_1( +col1 int, col2 int, +PRIMARY KEY (col1, col2) +) ENGINE=InnoDB; +CREATE TABLE bug53592_2 ( +col int PRIMARY KEY, +FOREIGN KEY (col) REFERENCES bug53592_1 (col1) +ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB; +INSERT INTO bug53592_1 VALUES (1, 2); +INSERT INTO bug53592_1 VALUES (3, 4); +INSERT INTO bug53592_2 VALUES (1); +INSERT INTO bug53592_2 VALUES (3); +UPDATE bug53592_1 SET col1 = 3 WHERE col2 = 2; +ERROR 23000: Upholding foreign key constraints for table 'bug53592_1', entry '3-2', key 1 would lead to a duplicate entry +drop table bug53592_2; +drop table bug53592_1; diff --git a/mysql-test/suite/innodb/r/innodb_bug53674.result b/mysql-test/suite/innodb/r/innodb_bug53674.result new file mode 100644 index 00000000000..c4021c2e7cd --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug53674.result @@ -0,0 +1,11 @@ +create table bug53674(a int)engine=innodb; +insert into bug53674 values (1),(2); +start transaction; +select * from bug53674 for update; +a +1 +2 +select * from bug53674 where a=(select a from bug53674 where a > 1); +a +2 +drop table bug53674; diff --git a/mysql-test/suite/innodb/r/innodb_file_format.result b/mysql-test/suite/innodb/r/innodb_file_format.result index 107025e4e52..6a573d8658e 100644 --- a/mysql-test/suite/innodb/r/innodb_file_format.result +++ b/mysql-test/suite/innodb/r/innodb_file_format.result @@ -1,4 +1,3 @@ -call mtr.add_suppression("InnoDB: invalid innodb_file_format_check value"); select @@innodb_file_format; @@innodb_file_format Antelope @@ -41,3 +40,4 @@ ERROR 42000: Variable 'innodb_file_format' can't be set to the value of 'off' select @@innodb_file_format_check; @@innodb_file_format_check Barracuda +set global innodb_file_format_check=antelope; diff --git a/mysql-test/suite/innodb/r/innodb_information_schema.result b/mysql-test/suite/innodb/r/innodb_information_schema.result index 396cae579ce..ad8729804df 100644 --- a/mysql-test/suite/innodb/r/innodb_information_schema.result +++ b/mysql-test/suite/innodb/r/innodb_information_schema.result @@ -21,3 +21,46 @@ lock_table COUNT(*) "test"."t_max" 2 "test"."t_min" 2 "test"."`t'\""_str" 10 +Field Type Null Key Default Extra +trx_id varchar(18) NO +trx_state varchar(13) NO +trx_started datetime NO 0000-00-00 00:00:00 +trx_requested_lock_id varchar(81) YES NULL +trx_wait_started datetime YES NULL +trx_weight bigint(21) unsigned NO 0 +trx_mysql_thread_id bigint(21) unsigned NO 0 +trx_query varchar(1024) YES NULL +trx_operation_state varchar(64) YES NULL +trx_tables_in_use bigint(21) unsigned NO 0 +trx_tables_locked bigint(21) unsigned NO 0 +trx_lock_structs bigint(21) unsigned NO 0 +trx_lock_memory_bytes bigint(21) unsigned NO 0 +trx_rows_locked bigint(21) unsigned NO 0 +trx_rows_modified bigint(21) unsigned NO 0 +trx_concurrency_tickets bigint(21) unsigned NO 0 +trx_isolation_level varchar(16) NO +trx_unique_checks int(1) NO 0 +trx_foreign_key_checks int(1) NO 0 +trx_last_foreign_key_error varchar(256) YES NULL +trx_apative_hash_latched int(1) NO 0 +trx_adaptive_hash_timeout bigint(21) unsigned NO 0 +trx_operation_state varchar(64) YES NULL +trx_tables_in_use bigint(21) unsigned NO 0 +trx_tables_locked bigint(21) unsigned NO 0 +trx_lock_structs bigint(21) unsigned NO 0 +trx_lock_memory_bytes bigint(21) unsigned NO 0 +trx_rows_locked bigint(21) unsigned NO 0 +trx_rows_modified bigint(21) unsigned NO 0 +trx_concurrency_tickets bigint(21) unsigned NO 0 +trx_isolation_level varchar(16) NO +trx_unique_checks int(1) NO 0 +trx_foreign_key_checks int(1) NO 0 +trx_last_foreign_key_error varchar(256) YES NULL +trx_apative_hash_latched int(1) NO 0 +trx_adaptive_hash_timeout bigint(21) unsigned NO 0 +trx_state trx_weight trx_tables_in_use trx_tables_locked trx_rows_locked trx_rows_modified trx_concurrency_tickets trx_isolation_level trx_unique_checks trx_foreign_key_checks +RUNNING 4 0 0 7 1 0 REPEATABLE READ 1 1 +trx_isolation_level trx_unique_checks trx_foreign_key_checks +SERIALIZABLE 0 0 +trx_state trx_isolation_level trx_last_foreign_key_error +RUNNING SERIALIZABLE `test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`c02`) REFERENCES `t1` (`c01`) diff --git a/mysql-test/suite/innodb/r/innodb_multi_update.result b/mysql-test/suite/innodb/r/innodb_multi_update.result new file mode 100644 index 00000000000..7af9b030d1f --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_multi_update.result @@ -0,0 +1,76 @@ +CREATE TABLE bug38999_1 (a int not null primary key, b int not null, key (b)) engine=innodb; +CREATE TABLE bug38999_2 (a int not null primary key, b int not null, key (b)) engine=innodb; +INSERT INTO bug38999_1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12); +INSERT INTO bug38999_2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); +update bug38999_1,bug38999_2 set bug38999_1.a=bug38999_1.a+100; +select * from bug38999_1; +a b +101 1 +102 2 +103 3 +104 4 +105 5 +106 6 +107 7 +108 8 +109 9 +110 10 +111 11 +112 12 +update bug38999_1,bug38999_2 set bug38999_1.a=bug38999_1.a+100 where bug38999_1.a=101; +select * from bug38999_1; +a b +201 1 +102 2 +103 3 +104 4 +105 5 +106 6 +107 7 +108 8 +109 9 +110 10 +111 11 +112 12 +update bug38999_1,bug38999_2 set bug38999_1.b=bug38999_1.b+10 where bug38999_1.b=2; +select * from bug38999_1; +a b +201 1 +103 3 +104 4 +105 5 +106 6 +107 7 +108 8 +109 9 +110 10 +111 11 +102 12 +112 12 +update bug38999_1,bug38999_2 set bug38999_1.b=bug38999_1.b+2,bug38999_2.b=bug38999_1.b+10 where bug38999_1.b between 3 and 5 and bug38999_1.a=bug38999_2.a+100; +select * from bug38999_1; +a b +201 1 +103 5 +104 6 +106 6 +105 7 +107 7 +108 8 +109 9 +110 10 +111 11 +102 12 +112 12 +select * from bug38999_2; +a b +1 1 +2 2 +6 6 +7 7 +8 8 +9 9 +3 13 +4 14 +5 15 +drop table bug38999_1,bug38999_2; diff --git a/mysql-test/r/innodb_trx_weight.result b/mysql-test/suite/innodb/r/innodb_trx_weight.result index 195775f74c8..195775f74c8 100644 --- a/mysql-test/r/innodb_trx_weight.result +++ b/mysql-test/suite/innodb/r/innodb_trx_weight.result diff --git a/mysql-test/suite/innodb/t/disabled.def b/mysql-test/suite/innodb/t/disabled.def index 6535ee27887..da04138fd0a 100644 --- a/mysql-test/suite/innodb/t/disabled.def +++ b/mysql-test/suite/innodb/t/disabled.def @@ -1 +1,12 @@ -innodb-index : Bug#49396 2009-12-03 test fails in embedded mode +############################################################################## +# +# List the test cases that are to be disabled temporarily. +# +# Separate the test case name and the comment with ':'. +# +# <testcasename> : BUG#<xxxx> <date disabled> <disabler> <comment> +# +# Do not use any TAB characters for whitespace. +# +############################################################################## +innodb_multi_update: Bug #38999 2010-05-05 mmakela Valgrind warnings diff --git a/mysql-test/suite/innodb/t/innodb-autoinc-44030.test b/mysql-test/suite/innodb/t/innodb-autoinc-44030.test new file mode 100644 index 00000000000..17c836004a1 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb-autoinc-44030.test @@ -0,0 +1,43 @@ +-- source include/have_innodb.inc +# embedded server ignores 'delayed', so skip this +-- source include/not_embedded.inc + +let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# +# 44030: Error: (1500) Couldn't read the MAX(ID) autoinc value from +# the index (PRIMARY) +# This test requires a restart of the server +SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; +CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; +INSERT INTO t1 VALUES (null); +INSERT INTO t1 VALUES (null); +ALTER TABLE t1 CHANGE c1 d1 INT NOT NULL AUTO_INCREMENT; +SELECT * FROM t1; +# Restart the server +-- source include/restart_mysqld.inc +# The MySQL and InnoDB data dictionaries should now be out of sync. +# The select should print message to the error log +SELECT * FROM t1; +# MySQL have made a change (http://lists.mysql.com/commits/75268) that no +# longer results in the two data dictionaries being out of sync. If they +# revert their changes then this check for ER_AUTOINC_READ_FAILED will need +# to be enabled. Also, see http://bugs.mysql.com/bug.php?id=47621. +#-- error ER_AUTOINC_READ_FAILED,1467 +INSERT INTO t1 VALUES(null); +ALTER TABLE t1 AUTO_INCREMENT = 3; +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES(null); +SELECT * FROM t1; +DROP TABLE t1; + +# +# restore environment to the state it was before this test execution +# + +-- disable_query_log +eval SET GLOBAL innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/mysql-test/t/innodb-autoinc.test b/mysql-test/suite/innodb/t/innodb-autoinc.test index 558de6a1060..c1cae16153e 100644 --- a/mysql-test/t/innodb-autoinc.test +++ b/mysql-test/suite/innodb/t/innodb-autoinc.test @@ -2,6 +2,8 @@ # embedded server ignores 'delayed', so skip this -- source include/not_embedded.inc +let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; + --disable_warnings drop table if exists t1; --enable_warnings @@ -478,28 +480,6 @@ INSERT INTO t2 SELECT c1 FROM t1; INSERT INTO t2 SELECT NULL FROM t1; DROP TABLE t1; DROP TABLE t2; -# -# 44030: Error: (1500) Couldn't read the MAX(ID) autoinc value from -# the index (PRIMARY) -# This test requires a restart of the server -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; -INSERT INTO t1 VALUES (null); -INSERT INTO t1 VALUES (null); -ALTER TABLE t1 CHANGE c1 d1 INT NOT NULL AUTO_INCREMENT; -SELECT * FROM t1; -# Restart the server --- source include/restart_mysqld.inc -# The MySQL and InnoDB data dictionaries should now be out of sync. -# The select should print message to the error log -SELECT * FROM t1; --- error ER_AUTOINC_READ_FAILED,1467 -INSERT INTO t1 VALUES(null); -ALTER TABLE t1 AUTO_INCREMENT = 3; -SHOW CREATE TABLE t1; -INSERT INTO t1 VALUES(null); -SELECT * FROM t1; -DROP TABLE t1; # If the user has specified negative values for an AUTOINC column then # InnoDB should ignore those values when setting the table's max value. @@ -610,9 +590,85 @@ DROP TABLE t1; # 47125: auto_increment start value is ignored if an index is created # and engine=innodb # -CREATE TABLE T1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) AUTO_INCREMENT=10 ENGINE=InnoDB; -CREATE INDEX i1 on T1(c2); -SHOW CREATE TABLE T1; -INSERT INTO T1 (c2) values (0); -SELECT * FROM T1; -DROP TABLE T1; +CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) AUTO_INCREMENT=10 ENGINE=InnoDB; +CREATE INDEX i1 on t1(c2); +SHOW CREATE TABLE t1; +INSERT INTO t1 (c2) values (0); +SELECT * FROM t1; +DROP TABLE t1; + +## +# 49032: Use the correct function to read the AUTOINC column value +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1(C1 DOUBLE AUTO_INCREMENT KEY, C2 CHAR(10)) ENGINE=InnoDB; +INSERT INTO t1(C1, C2) VALUES (1, 'innodb'), (3, 'innodb'); +# Restart the server +-- source include/restart_mysqld.inc +INSERT INTO t1(C2) VALUES ('innodb'); +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1(C1 FLOAT AUTO_INCREMENT KEY, C2 CHAR(10)) ENGINE=InnoDB; +INSERT INTO t1(C1, C2) VALUES (1, 'innodb'), (3, 'innodb'); +# Restart the server +-- source include/restart_mysqld.inc +INSERT INTO t1(C2) VALUES ('innodb'); +SHOW CREATE TABLE t1; +DROP TABLE t1; + +## +# 47720: REPLACE INTO Autoincrement column with negative values +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 INT AUTO_INCREMENT PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 SET c1 = 1; +SHOW CREATE TABLE t1; +INSERT INTO t1 SET c1 = 2; +INSERT INTO t1 SET c1 = -1; +SELECT * FROM t1; +-- error ER_DUP_ENTRY,1062 +INSERT INTO t1 SET c1 = -1; +SHOW CREATE TABLE t1; +REPLACE INTO t1 VALUES (-1); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + +## +# 49497: Error 1467 (ER_AUTOINC_READ_FAILED) on inserting a negative value +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (-685113344), (1), (NULL), (NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (-685113344), (2), (NULL), (NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL), (2), (-685113344), (NULL); +INSERT INTO t1 VALUES (4), (5), (6), (NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (NULL), (2), (-685113344), (5); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (c1 INTEGER AUTO_INCREMENT, PRIMARY KEY (c1)) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1), (2), (-685113344), (NULL); +SELECT * FROM t1; +SHOW CREATE TABLE t1; +DROP TABLE t1; + + +# +# restore environment to the state it was before this test execution +# + +-- disable_query_log +eval SET GLOBAL innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/storage/innobase/mysql-test/innodb-semi-consistent-master.opt b/mysql-test/suite/innodb/t/innodb-consistent-master.opt index e76299453d3..e76299453d3 100644 --- a/storage/innobase/mysql-test/innodb-semi-consistent-master.opt +++ b/mysql-test/suite/innodb/t/innodb-consistent-master.opt diff --git a/mysql-test/t/innodb-consistent.test b/mysql-test/suite/innodb/t/innodb-consistent.test index 791600fc8a7..bf829a74ea2 100644 --- a/mysql-test/t/innodb-consistent.test +++ b/mysql-test/suite/innodb/t/innodb-consistent.test @@ -1,58 +1,58 @@ --- source include/not_embedded.inc
--- source include/have_innodb.inc
-
---disable_warnings
-drop table if exists t1;
---enable_warnings
-
-# REPLACE INTO ... SELECT and INSERT INTO ... SELECT should do
-# a consistent read of the source table.
-
-connect (a,localhost,root,,);
-connect (b,localhost,root,,);
-connection a;
-set session transaction isolation level read committed;
-create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
-create table t2 like t1;
-insert into t2 values (1),(2),(3),(4),(5),(6),(7);
-set autocommit=0;
-
-# REPLACE INTO ... SELECT case
-begin;
-# this should not result in any locks on t2.
-replace into t1 select * from t2;
-
-connection b;
-set session transaction isolation level read committed;
-set autocommit=0;
-# should not cuase a lock wait.
-delete from t2 where a=5;
-commit;
-delete from t2;
-commit;
-connection a;
-commit;
-
-# INSERT INTO ... SELECT case
-begin;
-# this should not result in any locks on t2.
-insert into t1 select * from t2;
-
-connection b;
-set session transaction isolation level read committed;
-set autocommit=0;
-# should not cuase a lock wait.
-delete from t2 where a=5;
-commit;
-delete from t2;
-commit;
-connection a;
-commit;
-
-select * from t1;
-drop table t1;
-drop table t2;
-
-connection default;
-disconnect a;
-disconnect b;
+-- source include/not_embedded.inc +-- source include/have_innodb.inc + +--disable_warnings +drop table if exists t1; +--enable_warnings + +# REPLACE INTO ... SELECT and INSERT INTO ... SELECT should do +# a consistent read of the source table. + +connect (a,localhost,root,,); +connect (b,localhost,root,,); +connection a; +set session transaction isolation level read committed; +create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; +create table t2 like t1; +insert into t2 values (1),(2),(3),(4),(5),(6),(7); +set autocommit=0; + +# REPLACE INTO ... SELECT case +begin; +# this should not result in any locks on t2. +replace into t1 select * from t2; + +connection b; +set session transaction isolation level read committed; +set autocommit=0; +# should not cause a lock wait. +delete from t2 where a=5; +commit; +delete from t2; +commit; +connection a; +commit; + +# INSERT INTO ... SELECT case +begin; +# this should not result in any locks on t2. +insert into t1 select * from t2; + +connection b; +set session transaction isolation level read committed; +set autocommit=0; +# should not cause a lock wait. +delete from t2 where a=5; +commit; +delete from t2; +commit; +connection a; +commit; + +select * from t1; +drop table t1; +drop table t2; + +connection default; +disconnect a; +disconnect b; diff --git a/mysql-test/suite/innodb/t/innodb-index.test b/mysql-test/suite/innodb/t/innodb-index.test index b5dd2e037e7..f7cf3050704 100644 --- a/mysql-test/suite/innodb/t/innodb-index.test +++ b/mysql-test/suite/innodb/t/innodb-index.test @@ -1,5 +1,7 @@ -- source include/have_innodb.inc +let $MYSQLD_DATADIR= `select @@datadir`; + let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb; @@ -19,16 +21,6 @@ show create table t1; alter table t1 add index (b); show create table t1; -# Check how existing tables interfere with temporary tables. -CREATE TABLE `t1#1`(a INT PRIMARY KEY) ENGINE=InnoDB; - ---error 156 -alter table t1 add unique index (c), add index (d); -rename table `t1#1` to `t1#2`; ---error 156 -alter table t1 add unique index (c), add index (d); -drop table `t1#2`; - alter table t1 add unique index (c), add index (d); show create table t1; explain select * from t1 force index(c) order by c; @@ -139,6 +131,8 @@ show create table t4; --error ER_CANT_CREATE_TABLE alter table t3 add constraint dc foreign key (a) references t1(a); show create table t3; +# this should be fixed by MySQL (see Bug #51451) +--error ER_WRONG_NAME_FOR_INDEX alter table t2 drop index b, add index (b); show create table t2; --error ER_ROW_IS_REFERENCED_2 @@ -146,7 +140,9 @@ delete from t1; --error ER_CANT_DROP_FIELD_OR_KEY drop index dc on t4; # there is no foreign key dc on t3 ---replace_regex /'\.\/test\/#sql2-[0-9a-f-]*'/'#sql2-temporary'/ +--replace_regex /'[^']*test\/#sql2-[0-9a-f-]*'/'#sql2-temporary'/ +# Embedded server doesn't chdir to data directory +--replace_result $MYSQLD_DATADIR ./ master-data/ '' --error ER_ERROR_ON_RENAME alter table t3 drop foreign key dc; alter table t4 drop foreign key dc; @@ -157,7 +153,7 @@ select * from t2; drop table t2,t4,t3,t1; -- let charset = utf8 --- source suite/innodb/include/innodb-index.inc +-- source include/innodb-index.inc create table t1(a int not null, b int) engine = innodb; insert into t1 values (1,1),(1,1),(1,1),(1,1); @@ -292,66 +288,73 @@ show create table t1; check table t1; explain select * from t1 where b like 'adfd%'; +# The following tests are disabled because of the introduced timeouts for +# metadata locks at the MySQL level as part of the fix for +# Bug#45225 Locking: hang if drop table with no timeout +# The following commands now play with MySQL metadata locks instead of +# InnoDB locks +# start disabled45225_1 +## +## Test locking +## # -# Test locking +#create table t2(a int, b varchar(255), primary key(a,b)) engine=innodb; +#insert into t2 select a,left(b,255) from t1; +#drop table t1; +#rename table t2 to t1; # - -create table t2(a int, b varchar(255), primary key(a,b)) engine=innodb; -insert into t2 select a,left(b,255) from t1; -drop table t1; -rename table t2 to t1; - -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connection a; -set innodb_lock_wait_timeout=1; -begin; -# Obtain an IX lock on the table -select a from t1 limit 1 for update; -connection b; -set innodb_lock_wait_timeout=1; -# This would require an S lock on the table, conflicting with the IX lock. ---error ER_LOCK_WAIT_TIMEOUT -create index t1ba on t1 (b,a); -connection a; -commit; -begin; -# Obtain an IS lock on the table -select a from t1 limit 1 lock in share mode; -connection b; -# This will require an S lock on the table. No conflict with the IS lock. -create index t1ba on t1 (b,a); -# This would require an X lock on the table, conflicting with the IS lock. ---error ER_LOCK_WAIT_TIMEOUT -drop index t1ba on t1; -connection a; -commit; -explain select a from t1 order by b; ---send -select a,sleep(2+a/100) from t1 order by b limit 3; - -# The following DROP INDEX will succeed, altough the SELECT above has -# opened a read view. However, during the execution of the SELECT, -# MySQL should hold a table lock that should block the execution -# of the DROP INDEX below. - -connection b; -select sleep(1); -drop index t1ba on t1; - -# After the index was dropped, subsequent SELECTs will use the same -# read view, but they should not be accessing the dropped index any more. - -connection a; -reap; -explain select a from t1 order by b; -select a from t1 order by b limit 3; -commit; - -connection default; -disconnect a; -disconnect b; - +#connect (a,localhost,root,,); +#connect (b,localhost,root,,); +#connection a; +#set innodb_lock_wait_timeout=1; +#begin; +## Obtain an IX lock on the table +#select a from t1 limit 1 for update; +#connection b; +#set innodb_lock_wait_timeout=1; +## This would require an S lock on the table, conflicting with the IX lock. +#--error ER_LOCK_WAIT_TIMEOUT +#create index t1ba on t1 (b,a); +#connection a; +#commit; +#begin; +## Obtain an IS lock on the table +#select a from t1 limit 1 lock in share mode; +#connection b; +## This will require an S lock on the table. No conflict with the IS lock. +#create index t1ba on t1 (b,a); +## This would require an X lock on the table, conflicting with the IS lock. +#--error ER_LOCK_WAIT_TIMEOUT +#drop index t1ba on t1; +#connection a; +#commit; +#explain select a from t1 order by b; +#--send +#select a,sleep(2+a/100) from t1 order by b limit 3; +# +## The following DROP INDEX will succeed, altough the SELECT above has +## opened a read view. However, during the execution of the SELECT, +## MySQL should hold a table lock that should block the execution +## of the DROP INDEX below. +# +#connection b; +#select sleep(1); +#drop index t1ba on t1; +# +## After the index was dropped, subsequent SELECTs will use the same +## read view, but they should not be accessing the dropped index any more. +# +#connection a; +#reap; +#explain select a from t1 order by b; +#select a from t1 order by b limit 3; +#commit; +# +#connection default; +#disconnect a; +#disconnect b; +# +# end disabled45225_1 drop table t1; let $per_table=`select @@innodb_file_per_table`; @@ -513,28 +516,34 @@ SHOW CREATE TABLE t2; DROP TABLE t2; DROP TABLE t1; -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connection a; -CREATE TABLE t1 (a INT, b CHAR(1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (3,'a'),(3,'b'),(1,'c'),(0,'d'),(1,'e'); -connection b; -BEGIN; -SELECT * FROM t1; -connection a; -CREATE INDEX t1a ON t1(a); -connection b; -SELECT * FROM t1; ---error ER_TABLE_DEF_CHANGED -SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a; -SELECT * FROM t1; -COMMIT; -SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a; -connection default; -disconnect a; -disconnect b; - -DROP TABLE t1; +# The following tests are disabled because of the introduced timeouts for +# metadata locks at the MySQL level as part of the fix for +# Bug#45225 Locking: hang if drop table with no timeout +# The following CREATE INDEX t1a ON t1(a); causes a lock wait timeout +# start disabled45225_2 +#connect (a,localhost,root,,); +#connect (b,localhost,root,,); +#connection a; +#CREATE TABLE t1 (a INT, b CHAR(1)) ENGINE=InnoDB; +#INSERT INTO t1 VALUES (3,'a'),(3,'b'),(1,'c'),(0,'d'),(1,'e'); +#connection b; +#BEGIN; +#SELECT * FROM t1; +#connection a; +#CREATE INDEX t1a ON t1(a); +#connection b; +#SELECT * FROM t1; +#--error ER_TABLE_DEF_CHANGED +#SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a; +#SELECT * FROM t1; +#COMMIT; +#SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a; +#connection default; +#disconnect a; +#disconnect b; +# +#DROP TABLE t1; +# end disabled45225_2 # # restore environment to the state it was before this test execution diff --git a/mysql-test/suite/innodb/t/innodb-index_ucs2.test b/mysql-test/suite/innodb/t/innodb-index_ucs2.test index db4626ac346..fff9a4da1a8 100644 --- a/mysql-test/suite/innodb/t/innodb-index_ucs2.test +++ b/mysql-test/suite/innodb/t/innodb-index_ucs2.test @@ -2,4 +2,4 @@ -- source include/have_ucs2.inc -- let charset = ucs2 --- source suite/innodb/include/innodb-index.inc +-- source include/innodb-index.inc diff --git a/mysql-test/t/innodb-lock.test b/mysql-test/suite/innodb/t/innodb-lock.test index d2f630ccaba..05df3615822 100644 --- a/mysql-test/t/innodb-lock.test +++ b/mysql-test/suite/innodb/t/innodb-lock.test @@ -58,9 +58,10 @@ drop table t1; --echo # --echo # Old lock method (where LOCK TABLE was ignored by InnoDB) no longer ---echo # works due to fix for bugs #46272 "MySQL 5.4.4, new MDL: unnecessary ---echo # deadlock" and bug #37346 "innodb does not detect deadlock between ---echo # update and alter table". +--echo # works when LOCK TABLE ... WRITE is used due to fix for bugs #46272 +--echo # "MySQL 5.4.4, new MDL: unnecessary and bug #37346 "innodb does not +--echo # detect deadlock between update and alter table". But it still works +--echo # for LOCK TABLE ... READ. --echo # set @@innodb_table_locks=0; @@ -102,6 +103,26 @@ unlock tables; --echo # Connection 'con1'. connection con1; + +select * from t1 where id = 0 for update; + +--echo # Connection 'con2'. +connection con2; +--echo # The below statement should not be blocked as LOCK TABLES ... READ +--echo # does not take strong SQL-level lock on t1. SELECTs which do not +--echo # conflict with transaction in the first connections should not be +--echo # blocked. +lock table t1 read; +select * from t1; +select * from t1 where id = 1 lock in share mode; +unlock tables; +select * from t1; +commit; + +--echo # Connection 'con1'. +connection con1; +commit; + drop table t1; # End of 4.1 tests diff --git a/storage/innobase/mysql-test/innodb-master.opt b/mysql-test/suite/innodb/t/innodb-master.opt index 4901efb416c..4901efb416c 100644 --- a/storage/innobase/mysql-test/innodb-master.opt +++ b/mysql-test/suite/innodb/t/innodb-master.opt diff --git a/mysql-test/t/innodb-replace.test b/mysql-test/suite/innodb/t/innodb-replace.test index 8c3aacde5e8..8c3aacde5e8 100644 --- a/mysql-test/t/innodb-replace.test +++ b/mysql-test/suite/innodb/t/innodb-replace.test diff --git a/mysql-test/t/innodb-consistent-master.opt b/mysql-test/suite/innodb/t/innodb-semi-consistent-master.opt index 8cca44767da..e76299453d3 100644 --- a/mysql-test/t/innodb-consistent-master.opt +++ b/mysql-test/suite/innodb/t/innodb-semi-consistent-master.opt @@ -1 +1 @@ ---innodb_lock_wait_timeout=2
+--innodb_lock_wait_timeout=2 diff --git a/mysql-test/t/innodb-semi-consistent.test b/mysql-test/suite/innodb/t/innodb-semi-consistent.test index 61ad7815ca9..61ad7815ca9 100644 --- a/mysql-test/t/innodb-semi-consistent.test +++ b/mysql-test/suite/innodb/t/innodb-semi-consistent.test diff --git a/mysql-test/suite/innodb/t/innodb-system-table-view.test b/mysql-test/suite/innodb/t/innodb-system-table-view.test new file mode 100644 index 00000000000..e570a33b59d --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb-system-table-view.test @@ -0,0 +1,94 @@ +# This is the test for Information Schema System Table View +# that displays the InnoDB system table content through +# information schema tables. + +--source include/have_innodb.inc + +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_COLUMNS; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FIELDS; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS; + +# Create a foreign key constraint, and verify the information +# in INFORMATION_SCHEMA.INNODB_SYS_FOREIGN and +# INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS +CREATE TABLE parent (id INT NOT NULL, + PRIMARY KEY (id)) ENGINE=INNODB; + +CREATE TABLE child (id INT, parent_id INT, + INDEX par_ind (parent_id), + CONSTRAINT constraint_test + FOREIGN KEY (parent_id) REFERENCES parent(id) + ON DELETE CASCADE) ENGINE=INNODB; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS; + +# Insert a row in the table "parent", and see whether that reflected in +# INNODB_SYS_TABLESTATS +INSERT INTO parent VALUES(1); + +SELECT name, num_rows, mysql_handles_opened +FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS +WHERE name LIKE "%parent"; + +SELECT NAME, FLAG, N_COLS, SPACE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES; + +SELECT name, n_fields +from INFORMATION_SCHEMA.INNODB_SYS_INDEXES +WHERE table_id In (SELECT table_id from + INFORMATION_SCHEMA.INNODB_SYS_TABLES + WHERE name LIKE "%parent%"); + +SELECT name, n_fields +from INFORMATION_SCHEMA.INNODB_SYS_INDEXES +WHERE table_id In (SELECT table_id from + INFORMATION_SCHEMA.INNODB_SYS_TABLES + WHERE name LIKE "%child%"); + +SELECT name, pos, mtype, len +from INFORMATION_SCHEMA.INNODB_SYS_COLUMNS +WHERE table_id In (SELECT table_id from + INFORMATION_SCHEMA.INNODB_SYS_TABLES + WHERE name LIKE "%child%"); + +DROP TABLE child; + +DROP TABLE parent; + +# Create table with 2 columns in the foreign key constraint +CREATE TABLE parent (id INT NOT NULL, newid INT NOT NULL, + PRIMARY KEY (id, newid)) ENGINE=INNODB; + +CREATE TABLE child (id INT, parent_id INT, + INDEX par_ind (parent_id), + CONSTRAINT constraint_test + FOREIGN KEY (id, parent_id) REFERENCES parent(id, newid) + ON DELETE CASCADE) ENGINE=INNODB; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN; + +SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS; + +INSERT INTO parent VALUES(1, 9); + +# Nested query will open the table handle twice +SELECT * FROM parent WHERE id IN (SELECT id FROM parent); + +SELECT name, num_rows, mysql_handles_opened +FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS +WHERE name LIKE "%parent"; + +DROP TABLE child; + +DROP TABLE parent; diff --git a/mysql-test/suite/innodb/t/innodb-use-sys-malloc-master.opt b/mysql-test/suite/innodb/t/innodb-use-sys-malloc-master.opt index 8ec086387f8..acf3b8729ed 100644 --- a/mysql-test/suite/innodb/t/innodb-use-sys-malloc-master.opt +++ b/mysql-test/suite/innodb/t/innodb-use-sys-malloc-master.opt @@ -1,2 +1 @@ ---loose-innodb-use-sys-malloc=true ---loose-innodb-use-sys-malloc=true +--innodb-use-sys-malloc=true diff --git a/mysql-test/suite/innodb/t/innodb-zip.test b/mysql-test/suite/innodb/t/innodb-zip.test index eb517563416..8ba83517b44 100644 --- a/mysql-test/suite/innodb/t/innodb-zip.test +++ b/mysql-test/suite/innodb/t/innodb-zip.test @@ -85,7 +85,8 @@ SELECT table_schema, table_name, row_format FROM information_schema.tables WHERE engine='innodb'; drop table t1,t2; -# The following should fail even in non-strict mode. +# The following should fail in non-strict mode too. +# (The fix of Bug #50945 only affects REDUNDANT and COMPACT tables.) SET SESSION innodb_strict_mode = off; --error ER_TOO_BIG_ROWSIZE CREATE TABLE t1( diff --git a/mysql-test/t/innodb.test b/mysql-test/suite/innodb/t/innodb.test index c4380ff8f43..a283cd26ccb 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/suite/innodb/t/innodb.test @@ -1,3 +1,9 @@ +--source include/not_windows_embedded.inc +# remove this when +# Bug#53947 InnoDB: Assertion failure in thread 4224 in file +# .\sync\sync0sync.c line 324 +# is fixed + ####################################################################### # # # Please, DO NOT TOUCH this file as well as the innodb.result file. # @@ -15,6 +21,8 @@ -- source include/have_innodb.inc +let $MYSQLD_DATADIR= `select @@datadir`; + # Save the original values of some variables in order to be able to # estimate how much they have changed during the tests. Previously this # test assumed that e.g. rows_deleted is 0 here and after deleting 23 @@ -425,11 +433,21 @@ INSERT INTO t1 ( sca_code, cat_code, sca_desc, lan_code, sca_pic, sca_sdesc, sca select count(*) from t1 where sca_code = 'PD'; select count(*) from t1 where sca_code <= 'PD'; select count(*) from t1 where sca_pic is null; +# this should be fixed by MySQL (see Bug #51451) +# now that http://bugs.mysql.com/49838 is fixed the following ALTER does +# copy the table instead of failing +# --error ER_WRONG_NAME_FOR_INDEX alter table t1 drop index sca_pic, add index sca_pic (cat_code, sca_pic); +alter table t1 drop index sca_pic; +alter table t1 add index sca_pic (cat_code, sca_pic); select count(*) from t1 where sca_code='PD' and sca_pic is null; select count(*) from t1 where cat_code='E'; +# this should be fixed by MySQL (see Bug #51451) +--error ER_WRONG_NAME_FOR_INDEX alter table t1 drop index sca_pic, add index (sca_pic, cat_code); +alter table t1 drop index sca_pic; +alter table t1 add index (sca_pic, cat_code); select count(*) from t1 where sca_code='PD' and sca_pic is null; select count(*) from t1 where sca_pic >= 'n'; select sca_pic from t1 where sca_pic is null; @@ -903,33 +921,6 @@ UPDATE t1 set a=a+100 where b between 2 and 3 and a < 1000; SELECT * from t1; drop table t1; -# -# Test multi update with different join methods -# - -CREATE TABLE t1 (a int not null primary key, b int not null, key (b)) engine=innodb; -CREATE TABLE t2 (a int not null primary key, b int not null, key (b)) engine=innodb; -INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12); -INSERT INTO t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); - -# Full join, without key -update t1,t2 set t1.a=t1.a+100; -select * from t1; - -# unique key -update t1,t2 set t1.a=t1.a+100 where t1.a=101; -select * from t1; - -# ref key -update t1,t2 set t1.b=t1.b+10 where t1.b=2; -select * from t1; - -# Range key (in t1) -update t1,t2 set t1.b=t1.b+2,t2.b=t1.b+10 where t1.b between 3 and 5 and t1.a=t2.a+100; -select * from t1; -select * from t2; - -drop table t1,t2; CREATE TABLE t2 ( NEXT_T BIGINT NOT NULL PRIMARY KEY) ENGINE=MyISAM; CREATE TABLE t1 ( B_ID INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; SET AUTOCOMMIT=0; @@ -1225,11 +1216,11 @@ drop table t1; # # Bug #4082: integer truncation # - -create table t1(a int(1) , b int(1)) engine=innodb; -insert into t1 values ('1111', '3333'); -select distinct concat(a, b) from t1; -drop table t1; +# disable because the bug has resurfaced +#create table t1(a int(1) , b int(1)) engine=innodb; +#insert into t1 values ('1111', '3333'); +#select distinct concat(a, b) from t1; +#drop table t1; # # BUG#7709 test case - Boolean fulltext query against unsupported @@ -1317,7 +1308,7 @@ drop table t1; # Test for testable InnoDB status variables. This test # uses previous ones(pages_created, rows_deleted, ...). ---replace_result 511 512 +--replace_result 512 511 SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_buffer_pool_pages_total'; SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_page_size'; SELECT variable_value - @innodb_rows_deleted_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_deleted'; @@ -1375,7 +1366,10 @@ show variables like "innodb_thread_sleep_delay"; let $default=`select @@storage_engine`; set storage_engine=INNODB; +# this should be fixed by MySQL (see Bug #51451) +set session old_alter_table=1; source include/varchar.inc; +set session old_alter_table=0; # # Some errors/warnings on create @@ -1700,7 +1694,7 @@ set foreign_key_checks=0; create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8; # Embedded server doesn't chdir to data directory ---replace_result $MYSQLTEST_VARDIR . master-data/ '' +--replace_result $MYSQLD_DATADIR ./ master-data/ '' -- error 1025 rename table t3 to t1; set foreign_key_checks=1; @@ -1848,95 +1842,97 @@ DROP TABLE t2,t1; # # Test case for bug #16229: MySQL/InnoDB uses full explicit table locks in trigger processing # - -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connection a; -create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -insert into t1(a) values (1),(2),(3); -delimiter |; -create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end | -delimiter ;| -commit; -connection b; -set autocommit = 0; -update t1 set b = 5 where a = 2; -connection a; -set autocommit = 0; -insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100), -(11),(21),(31),(41),(51),(61),(71),(81),(91),(101), -(12),(22),(32),(42),(52),(62),(72),(82),(92),(102), -(13),(23),(33),(43),(53),(63),(73),(83),(93),(103), -(14),(24),(34),(44),(54),(64),(74),(84),(94),(104); -connection b; -commit; -connection a; -commit; -drop trigger t1t; -drop table t1; -disconnect a; -disconnect b; -# -# Another trigger test -# -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connection a; -create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t2(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t3(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t4(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t5(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -insert into t1(a) values (1),(2),(3); -insert into t2(a) values (1),(2),(3); -insert into t3(a) values (1),(2),(3); -insert into t4(a) values (1),(2),(3); -insert into t3(a) values (5),(7),(8); -insert into t4(a) values (5),(7),(8); -insert into t5(a) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12); - -delimiter |; -create trigger t1t before insert on t1 for each row begin - INSERT INTO t2 SET a = NEW.a; -end | - -create trigger t2t before insert on t2 for each row begin - DELETE FROM t3 WHERE a = NEW.a; -end | - -create trigger t3t before delete on t3 for each row begin - UPDATE t4 SET b = b + 1 WHERE a = OLD.a; -end | - -create trigger t4t before update on t4 for each row begin - UPDATE t5 SET b = b + 1 where a = NEW.a; -end | -delimiter ;| -commit; -set autocommit = 0; -update t1 set b = b + 5 where a = 1; -update t2 set b = b + 5 where a = 1; -update t3 set b = b + 5 where a = 1; -update t4 set b = b + 5 where a = 1; -insert into t5(a) values(20); -connection b; -set autocommit = 0; -insert into t1(a) values(7); -insert into t2(a) values(8); -delete from t2 where a = 3; -update t4 set b = b + 1 where a = 3; -commit; -connection a; -commit; -connection b; -drop trigger t1t; -drop trigger t2t; -drop trigger t3t; -drop trigger t4t; -drop table t1, t2, t3, t4, t5; -connection default; -disconnect a; -disconnect b; +## the following cannot be tested after the introduction of metadata locks +## because the create trigger command blocks and waits for connection b to +## commit +## begin disabled_mdl +#connect (a,localhost,root,,); +#connect (b,localhost,root,,); +#connection a; +#create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +#insert into t1(a) values (1),(2),(3); +#commit; +#connection b; +#set autocommit = 0; +#update t1 set b = 5 where a = 2; +#connection a; +#delimiter |; +#create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end | +#delimiter ;| +#set autocommit = 0; +#connection a; +#insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100), +#(11),(21),(31),(41),(51),(61),(71),(81),(91),(101), +#(12),(22),(32),(42),(52),(62),(72),(82),(92),(102), +#(13),(23),(33),(43),(53),(63),(73),(83),(93),(103), +#(14),(24),(34),(44),(54),(64),(74),(84),(94),(104); +#connection b; +#commit; +#connection a; +#commit; +#drop trigger t1t; +#drop table t1; +#disconnect a; +#disconnect b; +## +## Another trigger test +## +#connect (a,localhost,root,,); +#connect (b,localhost,root,,); +#connection a; +#create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +#create table t2(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +#create table t3(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +#create table t4(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +#create table t5(a int not null, b int, c int, d int, primary key(a)) engine=innodb; +#insert into t1(a) values (1),(2),(3); +#insert into t2(a) values (1),(2),(3); +#insert into t3(a) values (1),(2),(3); +#insert into t4(a) values (1),(2),(3); +#insert into t3(a) values (5),(7),(8); +#insert into t4(a) values (5),(7),(8); +#insert into t5(a) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12); +# +#delimiter |; +#create trigger t1t before insert on t1 for each row begin +# INSERT INTO t2 SET a = NEW.a; +#end | +# +#create trigger t2t before insert on t2 for each row begin +# DELETE FROM t3 WHERE a = NEW.a; +#end | +# +#create trigger t3t before delete on t3 for each row begin +# UPDATE t4 SET b = b + 1 WHERE a = OLD.a; +#end | +# +#create trigger t4t before update on t4 for each row begin +# UPDATE t5 SET b = b + 1 where a = NEW.a; +#end | +#delimiter ;| +#commit; +#set autocommit = 0; +#update t1 set b = b + 5 where a = 1; +#update t2 set b = b + 5 where a = 1; +#update t3 set b = b + 5 where a = 1; +#update t4 set b = b + 5 where a = 1; +#insert into t5(a) values(20); +#connection b; +#set autocommit = 0; +#insert into t1(a) values(7); +#insert into t2(a) values(8); +#delete from t2 where a = 3; +#update t4 set b = b + 1 where a = 3; +#commit; +#drop trigger t1t; +#drop trigger t2t; +#drop trigger t3t; +#drop trigger t4t; +#drop table t1, t2, t3, t4, t5; +#connection default; +#disconnect a; +#disconnect b; +## end disabled_mdl # # Test that cascading updates leading to duplicate keys give the correct @@ -2342,7 +2338,7 @@ ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1 (a) ON DELETE SET NULL; # mysqltest first does replace_regex, then replace_result --replace_regex /'[^']*test\/#sql-[0-9a-f_]*'/'#sql-temporary'/ # Embedded server doesn't chdir to data directory ---replace_result $MYSQLTEST_VARDIR . master-data/ '' +--replace_result $MYSQLD_DATADIR ./ master-data/ '' --error 1025 ALTER TABLE t2 MODIFY a INT NOT NULL; DELETE FROM t1; diff --git a/mysql-test/t/innodb_bug21704.test b/mysql-test/suite/innodb/t/innodb_bug21704.test index c649b61034c..c649b61034c 100644 --- a/mysql-test/t/innodb_bug21704.test +++ b/mysql-test/suite/innodb/t/innodb_bug21704.test diff --git a/mysql-test/t/innodb_bug34053.test b/mysql-test/suite/innodb/t/innodb_bug34053.test index b935e45c06d..b935e45c06d 100644 --- a/mysql-test/t/innodb_bug34053.test +++ b/mysql-test/suite/innodb/t/innodb_bug34053.test diff --git a/mysql-test/t/innodb_bug34300.test b/mysql-test/suite/innodb/t/innodb_bug34300.test index 68c385fd72a..68c385fd72a 100644 --- a/mysql-test/t/innodb_bug34300.test +++ b/mysql-test/suite/innodb/t/innodb_bug34300.test diff --git a/mysql-test/t/innodb_bug35220.test b/mysql-test/suite/innodb/t/innodb_bug35220.test index 26f7d6b1ddd..26f7d6b1ddd 100644 --- a/mysql-test/t/innodb_bug35220.test +++ b/mysql-test/suite/innodb/t/innodb_bug35220.test diff --git a/mysql-test/suite/innodb/t/innodb_bug36169.test b/mysql-test/suite/innodb/t/innodb_bug36169.test index 5bf55193b5c..5bbbf45d484 100644 --- a/mysql-test/suite/innodb/t/innodb_bug36169.test +++ b/mysql-test/suite/innodb/t/innodb_bug36169.test @@ -24,6 +24,7 @@ SET GLOBAL innodb_file_per_table=ON; # Generating 10 tables # Creating a table with 94 columns and 24 indexes DROP TABLE IF EXISTS `table0`; +set innodb_strict_mode=on; --error ER_TOO_BIG_ROWSIZE CREATE TABLE IF NOT EXISTS `table0` (`col0` BOOL, diff --git a/mysql-test/suite/innodb/t/innodb_bug38231.test b/mysql-test/suite/innodb/t/innodb_bug38231.test new file mode 100644 index 00000000000..a0a10bbd100 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug38231.test @@ -0,0 +1,100 @@ +# +# Bug#38231 Innodb crash in lock_reset_all_on_table() on TRUNCATE + LOCK / UNLOCK +# http://bugs.mysql.com/38231 +# + +-- source include/have_innodb.inc + +# skip this test in embedded mode because "TRUNCATE TABLE bug38231_1" +# hangs in that mode waiting for "lock_wait_timeout" although it is +# preceded by --send +-- source include/not_embedded.inc + +SET storage_engine=InnoDB; + +# we care only that the following SQL commands do not crash the server +-- disable_query_log +-- disable_result_log + +DROP TABLE IF EXISTS bug38231_1; +CREATE TABLE bug38231_1 (a INT); + +-- connect (lock_gain,localhost,root,,) +-- connect (lock_wait1,localhost,root,,) +-- connect (lock_wait2,localhost,root,,) +-- connect (truncate_wait,localhost,root,,) + +-- connection lock_gain +SET autocommit=0; +LOCK TABLE bug38231_1 WRITE; + +-- connection lock_wait1 +SET autocommit=0; +-- send +LOCK TABLE bug38231_1 WRITE; + +-- connection lock_wait2 +SET autocommit=0; +-- send +LOCK TABLE bug38231_1 WRITE; + +-- connection truncate_wait +-- send +TRUNCATE TABLE bug38231_1; + +-- connection lock_gain +# this crashes the server if the bug is present +UNLOCK TABLES; + +# clean up + +# do not clean up - we do not know which of the three has been released +# so the --reap command may hang because the command that is being executed +# in that connection is still running/waiting +#-- connection lock_wait1 +#-- reap +#UNLOCK TABLES; +# +#-- connection lock_wait2 +#-- reap +#UNLOCK TABLES; +# +#-- connection truncate_wait +#-- reap + +-- connection default + +-- disconnect lock_gain +-- disconnect lock_wait1 +-- disconnect lock_wait2 +-- disconnect truncate_wait + +DROP TABLE bug38231_1; + +# test that TRUNCATE works with row-level locks + +DROP TABLE IF EXISTS bug38231_2; +CREATE TABLE bug38231_2 (a INT); + +-- enable_query_log +-- enable_result_log + +INSERT INTO bug38231_2 VALUES (1), (10), (300); + +-- connect (con4,localhost,root,,) + +-- connection con4 +SET autocommit=0; +SELECT * FROM bug38231_2 FOR UPDATE; + +-- connection default +TRUNCATE TABLE bug38231_2; + +-- connection con4 +COMMIT; + +-- connection default + +-- disconnect con4 + +DROP TABLE bug38231_2; diff --git a/mysql-test/t/innodb_bug39438-master.opt b/mysql-test/suite/innodb/t/innodb_bug39438-master.opt index 43fac202fd4..43fac202fd4 100644 --- a/mysql-test/t/innodb_bug39438-master.opt +++ b/mysql-test/suite/innodb/t/innodb_bug39438-master.opt diff --git a/mysql-test/suite/innodb/t/innodb_bug39438.test b/mysql-test/suite/innodb/t/innodb_bug39438.test new file mode 100644 index 00000000000..52302871beb --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug39438.test @@ -0,0 +1,51 @@ +# +# Bug#39438 Testcase for Bug#39436 crashes on 5.1 in fil_space_get_latch +# http://bugs.mysql.com/39438 +# +# This test must be run with innodb_file_per_table=1 because the crash +# only occurs if that option is turned on and DISCARD TABLESPACE only +# works with innodb_file_per_table. +# + +-- source include/have_innodb.inc + +SET storage_engine=InnoDB; + +# we care only that the following SQL commands do not crash the server +-- disable_query_log +-- disable_result_log + +DROP TABLE IF EXISTS bug39438; + +CREATE TABLE bug39438 (id INT) ENGINE=INNODB; + +# remove: XXX Uncomment the following ALTER and remove those lines after +# remove: applying the patch. +# remove: Obviously this test is useless without this ALTER command, +# remove: but it causes warnings to be printed by mysqld and the whole +# remove: mysql-test suite fails at the end (returns non-zero). Please +# remove: apply this patch to the mysql source tree, remove those lines +# remove: and uncomment the following ALTER. We do not care about the +# remove: warnings, this test is to ensure mysqld does not crash. +# remove: === modified file 'mysql-test/lib/mtr_report.pl' +# remove: --- mysql-test/lib/mtr_report.pl 2008-08-12 10:26:23 +0000 +# remove: +++ mysql-test/lib/mtr_report.pl 2008-10-01 11:57:41 +0000 +# remove: @@ -412,7 +412,10 @@ +# remove: +# remove: # When trying to set lower_case_table_names = 2 +# remove: # on a case sensitive file system. Bug#37402. +# remove: - /lower_case_table_names was set to 2, even though your the file system '.*' is case sensitive. Now setting lower_case_table_names to 0 to avoid future problems./ +# remove: + /lower_case_table_names was set to 2, even though your the file system '.*' is case sensitive. Now setting lower_case_table_names to 0 to avoid future problems./ or +# remove: + +# remove: + # this test is expected to print warnings +# remove: + ($testname eq 'main.innodb_bug39438') +# remove: ) +# remove: { +# remove: next; # Skip these lines +# remove: +#ALTER TABLE bug39438 DISCARD TABLESPACE; + +# this crashes the server if the bug is present +SHOW TABLE STATUS; + +DROP TABLE bug39438; diff --git a/mysql-test/t/innodb_bug40565.test b/mysql-test/suite/innodb/t/innodb_bug40565.test index d7aa0fd514a..d7aa0fd514a 100644 --- a/mysql-test/t/innodb_bug40565.test +++ b/mysql-test/suite/innodb/t/innodb_bug40565.test diff --git a/storage/innobase/mysql-test/innodb_bug42101-nonzero-master.opt b/mysql-test/suite/innodb/t/innodb_bug42101-nonzero-master.opt index d71dbe17d5b..d71dbe17d5b 100644 --- a/storage/innobase/mysql-test/innodb_bug42101-nonzero-master.opt +++ b/mysql-test/suite/innodb/t/innodb_bug42101-nonzero-master.opt diff --git a/mysql-test/t/innodb_bug42101-nonzero.test b/mysql-test/suite/innodb/t/innodb_bug42101-nonzero.test index 2e4cf1f46dd..2e4cf1f46dd 100644 --- a/mysql-test/t/innodb_bug42101-nonzero.test +++ b/mysql-test/suite/innodb/t/innodb_bug42101-nonzero.test diff --git a/mysql-test/t/innodb_bug42101.test b/mysql-test/suite/innodb/t/innodb_bug42101.test index f0b88e034a0..f0b88e034a0 100644 --- a/mysql-test/t/innodb_bug42101.test +++ b/mysql-test/suite/innodb/t/innodb_bug42101.test diff --git a/mysql-test/t/innodb_bug44369.test b/mysql-test/suite/innodb/t/innodb_bug44369.test index f5d85cd5815..f5d85cd5815 100644 --- a/mysql-test/t/innodb_bug44369.test +++ b/mysql-test/suite/innodb/t/innodb_bug44369.test diff --git a/mysql-test/suite/innodb/t/innodb_bug44571.test b/mysql-test/suite/innodb/t/innodb_bug44571.test new file mode 100644 index 00000000000..91b6722d8af --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug44571.test @@ -0,0 +1,22 @@ +# +# Bug#44571 InnoDB Plugin crashes on ADD INDEX +# http://bugs.mysql.com/44571 +# Please also refer to related fix in +# http://bugs.mysql.com/47621 +# +-- source include/have_innodb.inc + +CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; +ALTER TABLE bug44571 CHANGE foo bar INT; +# Create index with the old column name will fail, +# because the CHANGE foo bar is successful. And +# the column name change would communicate to +# InnoDB with the fix from bug #47621 +-- error ER_KEY_COLUMN_DOES_NOT_EXITS +ALTER TABLE bug44571 ADD INDEX bug44571b (foo); +# The following create indexes should succeed, +# indirectly confirm the CHANGE foo bar is successful. +ALTER TABLE bug44571 ADD INDEX bug44571c (bar); +DROP INDEX bug44571c ON bug44571; +CREATE INDEX bug44571c ON bug44571 (bar); +DROP TABLE bug44571; diff --git a/mysql-test/t/innodb_bug45357.test b/mysql-test/suite/innodb/t/innodb_bug45357.test index 81727f352dd..81727f352dd 100644 --- a/mysql-test/t/innodb_bug45357.test +++ b/mysql-test/suite/innodb/t/innodb_bug45357.test diff --git a/mysql-test/t/innodb_bug46000.test b/mysql-test/suite/innodb/t/innodb_bug46000.test index 5a3c666326e..5a3c666326e 100644 --- a/mysql-test/t/innodb_bug46000.test +++ b/mysql-test/suite/innodb/t/innodb_bug46000.test diff --git a/mysql-test/suite/innodb/t/innodb_bug47621.test b/mysql-test/suite/innodb/t/innodb_bug47621.test new file mode 100644 index 00000000000..4863cc6bba1 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug47621.test @@ -0,0 +1,57 @@ +# This is the test for bug #47621, column rename operation should +# not result in column definition inconsistency between MySQL and +# InnoDB + +--source include/have_innodb.inc + +CREATE TABLE bug47621 (salesperson INT) ENGINE=InnoDB; + +# Change the column name +ALTER TABLE bug47621 CHANGE salesperson sales_acct_id INT; + +# If there is inconsistency of column name definition +# in MySQL or InnoDB, following create index would fail +create index orgs on bug47621(sales_acct_id); + +# Change the column name back with the index defined on it. +ALTER TABLE bug47621 CHANGE sales_acct_id salesperson INT; + +drop table bug47621; + +CREATE TABLE bug47621_sale ( + salesperson INT, + PRIMARY KEY(salesperson)) engine = innodb; + +CREATE TABLE bug47621_shirt( + id SMALLINT, + owner INT, + FOREIGN KEY(owner) + references bug47621_sale(salesperson) ON DELETE RESTRICT) + engine = innodb; + +insert into bug47621_sale values(9); + +insert into bug47621_shirt values(1, 9); + +# Any rename operation on columns involved in a reference constraint will +# fail, as it will be rejected by InnoDB row_rename_table_for_mysql(). +# In above example, any rename on column "salesperson" for table +# "bug47621_sale", or on column "owner" for table "bug47621_shirt will +# be blocked. We do not put such rename in the test since InnoDB error +# message will be printed in the error log, and result in test failure. +# +# ALTER TABLE bug47621_sale CHANGE salesperson sales_acct_id INT; + +# Any rename on columns not involved in the foreign key constraint +# could still proceed +ALTER TABLE bug47621_shirt CHANGE id new_id INT; + +# Referencing table dropped, the rename operation on related columns +# could proceed +drop table bug47621_shirt; + +ALTER TABLE bug47621_sale CHANGE salesperson sales_acct_id INT; + +ALTER TABLE bug47621_sale ADD INDEX idx (sales_acct_id); + +drop table bug47621_sale; diff --git a/mysql-test/suite/innodb/t/innodb_bug47622.test b/mysql-test/suite/innodb/t/innodb_bug47622.test new file mode 100644 index 00000000000..9cf9d0e531b --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug47622.test @@ -0,0 +1,55 @@ +# This is the test for bug 47622. There could be index +# metadata sequence mismatch between MySQL and Innodb +# after creating index through FIC interfaces. +# We resolve the problem by sync the index sequence +# up when opening the table. + +--source include/have_innodb.inc + +connect (a,localhost,root,,); +connect (b,localhost,root,,); + +# Create a table with a non-unique index +CREATE TABLE bug47622( + `rule_key` int(11) NOT NULL DEFAULT '0', + `seq` smallint(6) NOT NULL DEFAULT '0', + `action` smallint(6) NOT NULL DEFAULT '0', + `arg_id` smallint(6) DEFAULT NULL, + `else_ind` TINYINT NOT NULL, + KEY IDX_A (`arg_id`) +) ENGINE=InnoDB; + +connection a; + +# A subsequent creating unique index should not trigger +# any error message. Unique index would be ranked ahead +# of regular index. +ALTER TABLE bug47622 ADD UNIQUE IDX_B (rule_key,else_ind,seq,action,arg_id); + +drop index IDX_B on bug47622; + +# In another connection, create additional set of normal +# index and unique index. Again, unique index would be ranked +# ahead of regular index. +connection b; +create index idx on bug47622(seq, arg_id); + +ALTER TABLE bug47622 ADD UNIQUE IDX_X (rule_key,else_ind,seq,action); + +drop table bug47622; + +# Create a table with one Primary key and a non-unique key +CREATE TABLE bug47622 ( + `a` int(11) NOT NULL, + `b` int(11) DEFAULT NULL, + `c` char(10) DEFAULT NULL, + `d` varchar(20) DEFAULT NULL, + PRIMARY KEY (`a`), + KEY `b` (`b`) +) ENGINE=InnoDB; + +# Add two index with one unique and one non-unique. +# Index sequence is "PRIMARY", "c", "b" and "d" +alter table bug47622 add unique index (c), add index (d); + +drop table bug47622; diff --git a/mysql-test/t/innodb_bug47777.test b/mysql-test/suite/innodb/t/innodb_bug47777.test index 8f2985b2cf0..8f2985b2cf0 100644 --- a/mysql-test/t/innodb_bug47777.test +++ b/mysql-test/suite/innodb/t/innodb_bug47777.test diff --git a/mysql-test/suite/innodb/t/innodb_bug48024.test b/mysql-test/suite/innodb/t/innodb_bug48024.test new file mode 100644 index 00000000000..db828aa1cda --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug48024.test @@ -0,0 +1,22 @@ +# Bug #48024 Innodb doesn't work with multi-statements + +--source include/have_innodb.inc + +CREATE TABLE bug48024(a int PRIMARY KEY,b int NOT NULL,KEY(b)) ENGINE=InnoDB; +CREATE TABLE bug48024_b(b int PRIMARY KEY) ENGINE=InnoDB; +# Bug #53644 InnoDB thinks that /*/ starts and ends a comment +ALTER TABLE bug48024 /*/ADD CONSTRAINT FOREIGN KEY(c) REFERENCES(a),/*/ +ADD CONSTRAINT FOREIGN KEY(b) REFERENCES bug48024_b(b); + +DROP TABLE bug48024,bug48024_b; + +# Work around Bug #53750 (failure in mysql-test-run --ps-protocol) +-- disable_ps_protocol +delimiter |; +CREATE TABLE bug48024(a int PRIMARY KEY,b int NOT NULL,KEY(b)) ENGINE=InnoDB; +CREATE TABLE bug48024_b(b int PRIMARY KEY) ENGINE=InnoDB; +ALTER TABLE bug48024 /*/ADD CONSTRAINT FOREIGN KEY(c) REFERENCES(a),/*/ +ADD CONSTRAINT FOREIGN KEY(b) REFERENCES bug48024_b(b)| +delimiter ;| + +DROP TABLE bug48024,bug48024_b; diff --git a/mysql-test/suite/innodb/t/innodb_bug49164.test b/mysql-test/suite/innodb/t/innodb_bug49164.test new file mode 100644 index 00000000000..7f1c9f4ca9c --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug49164.test @@ -0,0 +1,47 @@ +-- source include/have_innodb.inc + +# Bug #49164 READ-COMMITTED reports "matched: 0" on compound PK +# a duplicate of +# Bug #52663 Lost update incrementing column value under READ COMMITTED + +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); + +connection con1; +SET tx_isolation = 'READ-COMMITTED'; + +CREATE TABLE bug49164 (a INT, b BIGINT, c TINYINT, PRIMARY KEY (a, b)) +ENGINE=InnoDB; + +insert into bug49164 values (1,1,1), (2,2,2), (3,3,3); + +begin; +update bug49164 set c=7; +select * from bug49164; +rollback; +select * from bug49164; +begin; +update bug49164 set c=7; + +connection con2; + +SET tx_isolation = 'READ-COMMITTED'; +begin; +select * from bug49164; +commit; +begin; +--send +update bug49164 set c=6 where a=1 and b=1; + +connection con1; +rollback; +select * from bug49164; +connection con2; +reap; +commit; +connection con1; +select * from bug49164; +connection default; +disconnect con1; +disconnect con2; +drop table bug49164; diff --git a/mysql-test/suite/innodb/t/innodb_bug51378.test b/mysql-test/suite/innodb/t/innodb_bug51378.test new file mode 100644 index 00000000000..8f7b0b9605a --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug51378.test @@ -0,0 +1,77 @@ +# This is the test for bug 51378. Unique index created +# through "create index" and "alter table add unique index" +# interfaces should not be treated as primary index if indexed +# columns contain one or more column prefix(es) (only prefix/part of +# the column is indexed) +# On the other hand, if there is a unique index covers all +# columns of a table, and they are non-null columns, and +# full length of the column are indexed, then this index +# will be created as primary index +# Following queries test various scenario, no mismatch +# error message should be printed. +--source include/have_innodb.inc + +# Create a table contains a BLOB column +create table bug51378 ( + col1 int not null, + col2 blob not null, + col3 time not null) engine = innodb; + +# Create following unique indexes on 'col1' and 'col2(31)' +# of the table, the index should not be treated as primary +# key because it indexes only first 31 bytes of col2. +# Thus it contains "column prefix", and will not be +# upgraded to primary index. +# There should not be mismatch message printed in the +# errorlog +create unique index idx on bug51378(col1, col2(31)); + +alter table bug51378 add unique index idx2(col1, col2(31)); + +# Unique index on 'col1' and 'col3' will be created as primary index, +# since the index does not contain column prefix +create unique index idx3 on bug51378(col1, col3); + +# Show create table would show idx3 created as unique index, internally, +# idx3 is treated as primary index both by MySQL and Innodb +SHOW CREATE TABLE bug51378; + +# "GEN_CLUST_INDEX" will be re-created as default primary index +# after idx3 is dropped +drop index idx3 on bug51378; + +SHOW CREATE TABLE bug51378; + +# Or we can add the primary key through alter table interfaces +alter table bug51378 add primary key idx3(col1, col2(31)); + +SHOW CREATE TABLE bug51378; + +drop table bug51378; + +# Or we can create such primary key through create table interfaces +create table bug51378 ( + col1 int not null, + col2 blob not null, + col3 time not null, primary key(col1, col2(31))) engine = innodb; + +# Unique index on one or more column prefix(es) will be created +# as non-cluster index +create unique index idx on bug51378(col1, col2(31)); + +SHOW CREATE TABLE bug51378; + +drop table bug51378; + +# If a table has a NULLABLE column, unique index on it will not +# be treated as primary index. +create table bug51378 ( + col1 int not null, + col2 int ) engine = innodb; + +# This will be created as non-cluster index since col2 is nullable +create unique index idx on bug51378(col1, col2); + +SHOW CREATE TABLE bug51378; + +drop table bug51378; diff --git a/mysql-test/suite/innodb/t/innodb_bug51920.test b/mysql-test/suite/innodb/t/innodb_bug51920.test new file mode 100644 index 00000000000..bc3bb006c1c --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug51920.test @@ -0,0 +1,43 @@ +# +# Bug #51920: InnoDB connections in lock wait ignore KILL until timeout +# +-- source include/not_embedded.inc +-- source include/have_innodb.inc + +CREATE TABLE bug51920 (i INT) ENGINE=InnoDB; +INSERT INTO bug51920 VALUES (1); + +BEGIN; +SELECT * FROM bug51920 FOR UPDATE; + +connect (con1,localhost,root,,); + +connection con1; +--send +UPDATE bug51920 SET i=2; + +connection default; +let $wait_condition = + SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE INFO="UPDATE bug51920 SET i=2"; +-- source include/wait_condition.inc + +SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST +WHERE INFO="UPDATE bug51920 SET i=2" +INTO @thread_id; + +KILL @thread_id; +let $wait_condition = + SELECT COUNT(*)=0 FROM information_schema.processlist WHERE ID=@thread_id; +-- source include/wait_condition.inc + +# +# Bug#19723: kill of active connection yields different error code +# depending on platform. +# +connection con1; +-- error 1317, 2006, 2013 +reap; +connection default; +DROP TABLE bug51920; +-- disconnect con1 diff --git a/mysql-test/suite/innodb/t/innodb_bug52663.test b/mysql-test/suite/innodb/t/innodb_bug52663.test new file mode 100644 index 00000000000..fcf97531e00 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug52663.test @@ -0,0 +1,34 @@ +--source include/have_innodb.inc + +set session transaction isolation level read committed; + +create table innodb_bug52663 (what varchar(5), id integer, count integer, primary key +(what, id)) engine=innodb; +insert into innodb_bug52663 values ('total', 0, 0); +begin; + +connect (addconroot, localhost, root,,); +connection addconroot; +set session transaction isolation level read committed; +begin; + +connection default; +update innodb_bug52663 set count = count + 1 where what = 'total' and id = 0; +select * from innodb_bug52663; + +connection addconroot; +--error ER_LOCK_WAIT_TIMEOUT +update innodb_bug52663 set count = count + 1 where what = 'total' and id = 0; +select * from innodb_bug52663; + +connection default; +commit; + +connection addconroot; +update innodb_bug52663 set count = count + 1 where what = 'total' and id = 0; +commit; +select * from innodb_bug52663; + +connection default; +select * from innodb_bug52663; +drop table innodb_bug52663; diff --git a/mysql-test/suite/innodb/t/innodb_bug52745.test b/mysql-test/suite/innodb/t/innodb_bug52745.test new file mode 100644 index 00000000000..d2de869648b --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug52745.test @@ -0,0 +1,109 @@ +-- source include/have_innodb.inc + +let $file_format=`select @@innodb_file_format`; +let $file_format_check=`select @@innodb_file_format_check`; +let $file_per_table=`select @@innodb_file_per_table`; +SET GLOBAL innodb_file_format='Barracuda'; +SET GLOBAL innodb_file_per_table=on; + +CREATE TABLE bug52745 ( + a2 int(10) unsigned DEFAULT NULL, + col37 time DEFAULT NULL, + col38 char(229) CHARACTER SET utf8 DEFAULT NULL, + col39 text, + col40 timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + col41 int(10) unsigned DEFAULT NULL, + col42 varchar(248) CHARACTER SET utf8 DEFAULT NULL, + col43 smallint(5) unsigned zerofill DEFAULT NULL, + col44 varchar(150) CHARACTER SET utf8 DEFAULT NULL, + col45 float unsigned zerofill DEFAULT NULL, + col46 binary(1) DEFAULT NULL, + col47 tinyint(4) DEFAULT NULL, + col48 tinyint(1) DEFAULT NULL, + col49 timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + col50 binary(1) DEFAULT NULL, + col51 double unsigned zerofill DEFAULT NULL, + col52 int(10) unsigned DEFAULT NULL, + col53 time DEFAULT NULL, + col54 double unsigned DEFAULT NULL, + col55 time DEFAULT NULL, + col56 mediumtext CHARACTER SET latin2, + col57 blob, + col58 decimal(52,16) unsigned zerofill NOT NULL DEFAULT '000000000000000000000000000000000000.0000000000000000', + col59 binary(1) DEFAULT NULL, + col60 longblob, + col61 time DEFAULT NULL, + col62 longtext CHARACTER SET utf8 COLLATE utf8_persian_ci, + col63 timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + col64 int(10) unsigned DEFAULT NULL, + col65 date DEFAULT NULL, + col66 timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', + col67 binary(1) DEFAULT NULL, + col68 tinyblob, + col69 date DEFAULT NULL, + col70 tinyint(3) unsigned zerofill DEFAULT NULL, + col71 varchar(44) CHARACTER SET utf8 DEFAULT NULL, + col72 datetime DEFAULT NULL, + col73 smallint(5) unsigned zerofill DEFAULT NULL, + col74 longblob, + col75 bit(34) DEFAULT NULL, + col76 float unsigned zerofill DEFAULT NULL, + col77 year(2) DEFAULT NULL, + col78 tinyint(3) unsigned DEFAULT NULL, + col79 set('msfheowh','tbpxbgf','by','wahnrjw','myqfasxz','rsokyumrt') CHARACTER SET latin2 DEFAULT NULL, + col80 datetime DEFAULT NULL, + col81 smallint(6) DEFAULT NULL, + col82 enum('xtaurnqfqz','rifrse','kuzwpbvb','niisabk','zxavro','rbvasv','','uulrfaove','','') DEFAULT NULL, + col83 bigint(20) unsigned zerofill DEFAULT NULL, + col84 float unsigned zerofill DEFAULT NULL, + col85 double DEFAULT NULL, + col86 enum('ylannv','','vlkhycqc','snke','cxifustp','xiaxaswzp','oxl') CHARACTER SET latin1 COLLATE latin1_german2_ci DEFAULT NULL, + col87 varbinary(221) DEFAULT NULL, + col88 double unsigned DEFAULT NULL, + col89 float unsigned zerofill DEFAULT NULL, + col90 tinyblob +) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; + +INSERT INTO bug52745 SET +col40='0000-00-00 00:00:00', +col51=16547, +col53='7711484', +col54=-28604, +col55='7112612', +col56='wakefulness\'', +col57=repeat('absorbefacient\'',106), +col58=11027, +col59='AM09gW7', +col60=repeat('Noelani\'',16), +col61='2520576', +col62='substitutiv', +col63='19950106155112', +col64=-12038, +col65='86238806', +col66='19600719080256', +col68=repeat('Sagittarius\'',54), +col69='38943902', +col70=1232, +col71='Elora\'', +col74=repeat('zipp',11), +col75='0', +col76=23254, +col78=13247, +col79='56219', +col80='20500609035724', +col81=11632, +col82=7, +col84=-23863, +col85=6341, +col87='HZdkf.4 s7t,5Rmq 8so fmr,ruGLUG25TrtI.yQ 2SuHq0ML7rw7.4 b2yf2E5TJxOtBBZImezDnzpj,uPYfznnEUDN1e9aQoO 2DsplB7TFWy oQJ br HLF :F,eQ p4i1oWsr lL3PG,hjCz6hYqN h1QTjLCjrv:QCdSzpYBibJAtZCxLOk3l6Blsh.W', +col88=16894, +col89=6161, +col90=repeat('gale',48); + +SHOW WARNINGS; + +DROP TABLE bug52745; + +EVAL SET GLOBAL innodb_file_format=$file_format; +EVAL SET GLOBAL innodb_file_format_check=$file_format_check; +EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/mysql-test/suite/innodb/t/innodb_bug53290.test b/mysql-test/suite/innodb/t/innodb_bug53290.test new file mode 100644 index 00000000000..ea15212fa39 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug53290.test @@ -0,0 +1,22 @@ +-- source include/have_innodb.inc + +create table bug53290 (x bigint) engine=innodb; + +insert into bug53290 () values (),(),(),(),(),(),(),(),(),(),(),(); +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; +insert into bug53290 select * from bug53290; + +alter table bug53290 add unique index `idx` (x); + +drop table bug53290; diff --git a/mysql-test/suite/innodb/t/innodb_bug53591.test b/mysql-test/suite/innodb/t/innodb_bug53591.test new file mode 100644 index 00000000000..58a7596dff9 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug53591.test @@ -0,0 +1,22 @@ +-- source include/have_innodb.inc + +let $file_format=`select @@innodb_file_format`; +let $file_format_check=`select @@innodb_file_format_check`; +let $file_per_table=`select @@innodb_file_per_table`; + +SET GLOBAL innodb_file_format='Barracuda'; +SET GLOBAL innodb_file_per_table=on; + +set old_alter_table=0; + +CREATE TABLE bug53591(a text charset utf8 not null) +ENGINE=InnoDB KEY_BLOCK_SIZE=1; +-- error 139 +ALTER TABLE bug53591 ADD PRIMARY KEY(a(220)); +SHOW WARNINGS; + +DROP TABLE bug53591; + +EVAL SET GLOBAL innodb_file_format=$file_format; +EVAL SET GLOBAL innodb_file_format_check=$file_format_check; +EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/mysql-test/suite/innodb/t/innodb_bug53592.test b/mysql-test/suite/innodb/t/innodb_bug53592.test new file mode 100644 index 00000000000..bc37743f6bf --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug53592.test @@ -0,0 +1,82 @@ +# Testcase for Bug #53592 - "crash replacing duplicates into +# table after fast alter table added unique key". The fix is to make +# sure index number lookup should go through "index translation table". + +--source include/have_innodb.inc + +# Use FIC for index creation +set old_alter_table=0; + +create table bug53592(a int) engine=innodb row_format=compact; + +alter table bug53592 add column b text charset utf8; + +alter table bug53592 add column c blob not null; + +# Create a non-unique nonclustered index +create index bug53592_b on bug53592(b(81)); + +# Create a unique index, this unique index should have smaller +# index number than bug53592_b, since unique index ranks higher +# than regular index does +create unique index bug53592_c on bug53592(c(1)); + +# This will trigger a dup key error and will require fetching +# the index number through a index structure for the error reporting. +# To get the correct index number, the code should go through index +# translation table. Otherwise, it will get the wrong index +# number and later trigger a server crash. +replace into bug53592 values (),(); + +check table bug53592; + +drop table bug53592; + +# Running the same set of test when "old_alter_table" is turned on +set old_alter_table=1; + +create table bug53592(a int) engine=innodb row_format=compact; + +alter table bug53592 add column b text charset utf8; + +alter table bug53592 add column c blob not null; + +# Create a non-unique nonclustered index +create index bug53592_b on bug53592(b(81)); + +# Create a unique index +create unique index bug53592_c on bug53592(c(1)); + +# This will trigger a dup key error and will require fetching +# the index number through a index structure for the error reporting. +# To get the correct index number, the code should go through index +# translation table. Otherwise, it will get the wrong index +# number and later trigger a server crash. +replace into bug53592 values (),(); + +check table bug53592; +drop table bug53592; + +# Test a dup key reported by foreign key constriant. +CREATE TABLE bug53592_1( + col1 int, col2 int, + PRIMARY KEY (col1, col2) +) ENGINE=InnoDB; + +CREATE TABLE bug53592_2 ( + col int PRIMARY KEY, + FOREIGN KEY (col) REFERENCES bug53592_1 (col1) + ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB; + +INSERT INTO bug53592_1 VALUES (1, 2); +INSERT INTO bug53592_1 VALUES (3, 4); + +INSERT INTO bug53592_2 VALUES (1); +INSERT INTO bug53592_2 VALUES (3); + +--error ER_FOREIGN_DUPLICATE_KEY +UPDATE bug53592_1 SET col1 = 3 WHERE col2 = 2; + +drop table bug53592_2; +drop table bug53592_1; diff --git a/mysql-test/suite/innodb/t/innodb_bug53674-master.opt b/mysql-test/suite/innodb/t/innodb_bug53674-master.opt new file mode 100644 index 00000000000..f1cfd7ab6c7 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug53674-master.opt @@ -0,0 +1 @@ +--log-bin --innodb-locks-unsafe-for-binlog --binlog-format=mixed diff --git a/mysql-test/suite/innodb/t/innodb_bug53674.test b/mysql-test/suite/innodb/t/innodb_bug53674.test new file mode 100644 index 00000000000..47f67f109c3 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug53674.test @@ -0,0 +1,8 @@ +-- source include/have_innodb.inc + +create table bug53674(a int)engine=innodb; +insert into bug53674 values (1),(2); +start transaction; +select * from bug53674 for update; +select * from bug53674 where a=(select a from bug53674 where a > 1); +drop table bug53674; diff --git a/mysql-test/suite/innodb/t/innodb_file_format.test b/mysql-test/suite/innodb/t/innodb_file_format.test index 4e11da5f123..5d094cb9dba 100644 --- a/mysql-test/suite/innodb/t/innodb_file_format.test +++ b/mysql-test/suite/innodb/t/innodb_file_format.test @@ -1,10 +1,5 @@ -- source include/have_innodb.inc -call mtr.add_suppression("InnoDB: invalid innodb_file_format_check value"); - -let $format=`select @@innodb_file_format`; -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; - select @@innodb_file_format; select @@innodb_file_format_check; set global innodb_file_format=antelope; @@ -31,12 +26,4 @@ set global innodb_file_format=on; --error ER_WRONG_VALUE_FOR_VAR set global innodb_file_format=off; select @@innodb_file_format_check; - -# -# restore environment to the state it was before this test execution -# - --- disable_query_log -eval set global innodb_file_format=$format; -eval set global innodb_file_format_check=$innodb_file_format_check_orig; --- enable_query_log +set global innodb_file_format_check=antelope; diff --git a/mysql-test/suite/innodb/t/innodb_information_schema.test b/mysql-test/suite/innodb/t/innodb_information_schema.test index fc1d38d8d14..3dc2a8a40d4 100644 --- a/mysql-test/suite/innodb/t/innodb_information_schema.test +++ b/mysql-test/suite/innodb/t/innodb_information_schema.test @@ -64,6 +64,8 @@ INSERT INTO ```t'\"_str` VALUES INSERT INTO ```t'\"_str` VALUES ('4', 'abc', 0x00616263, 0x61626300, 0x61006263, 0x6100626300, 0x610062630000); +--source include/count_sessions.inc + -- connect (con_lock,localhost,root,,) -- connect (con_min_trylock,localhost,root,,) -- connect (con_max_trylock,localhost,root,,) @@ -147,3 +149,104 @@ SET @@sql_mode=@save_sql_mode; -- disconnect con_verify_innodb_locks DROP TABLE t_min, t_max, ```t'\"_str`; + +--source include/wait_until_count_sessions.inc + +# +# Test that transaction data is correctly "visualized" in +# INFORMATION_SCHEMA.INNODB_TRX +# + +-- enable_result_log +DESCRIBE INFORMATION_SCHEMA.INNODB_TRX; +-- disable_result_log + +-- disable_warnings +DROP TABLE IF EXISTS t1; +-- enable_warnings + +CREATE TABLE t1 ( + c01 INT, + c02 INT, + PRIMARY KEY (c01) +) ENGINE = InnoDB; + +INSERT INTO t1 VALUES +(1,2),(2,4),(3,6),(4,8); + +CREATE TABLE t2 ( + c01 INT, + c02 INT, + PRIMARY KEY (c01), + FOREIGN KEY fk1 (c02) REFERENCES t1 (c01) +) ENGINE = InnoDB; + +INSERT INTO t2 VALUES +(1,1),(2,2),(3,3); + +-- connect (con_trx,localhost,root,,) +-- connect (con_verify_innodb_trx,localhost,root,,) + +-- connection con_trx +SET autocommit=0; +INSERT INTO t1 VALUES (5,10); +SELECT * FROM t1 FOR UPDATE; + +let $wait_condition= + SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_TRX; +--source include/wait_condition.inc +-- disable_query_log + +-- connection con_verify_innodb_trx +-- enable_result_log +SELECT trx_state, trx_weight, trx_tables_in_use, trx_tables_locked, +trx_rows_locked, trx_rows_modified, trx_concurrency_tickets, +trx_isolation_level, trx_unique_checks, trx_foreign_key_checks +FROM INFORMATION_SCHEMA.INNODB_TRX; + +-- connection con_trx +-- disable_result_log +ROLLBACK; +SET FOREIGN_KEY_CHECKS = 0; +SET UNIQUE_CHECKS = 0; +SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; +BEGIN; +INSERT INTO t1 VALUES (6,12); + +let $wait_condition= + SELECT trx_unique_checks = 0 FROM INFORMATION_SCHEMA.INNODB_TRX; +--source include/wait_condition.inc +-- disable_query_log + +-- connection con_verify_innodb_trx +-- enable_result_log +SELECT trx_isolation_level, trx_unique_checks, trx_foreign_key_checks +FROM INFORMATION_SCHEMA.INNODB_TRX; + +-- disable_result_log +-- connection con_trx +ROLLBACK; +SET FOREIGN_KEY_CHECKS = 1; +SET UNIQUE_CHECKS = 1; +BEGIN; +-- error 1452 +INSERT INTO t2 VALUES (4,10); + +let $wait_condition= + SELECT trx_unique_checks = 1 FROM INFORMATION_SCHEMA.INNODB_TRX; +--source include/wait_condition.inc +-- disable_query_log + +-- enable_result_log +-- connection con_verify_innodb_trx +SELECT trx_state, trx_isolation_level, trx_last_foreign_key_error +FROM INFORMATION_SCHEMA.INNODB_TRX; +-- disable_result_log + +-- connection default + +-- disconnect con_trx +-- disconnect con_verify_innodb_trx + +DROP TABLE t2; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/innodb_multi_update.test b/mysql-test/suite/innodb/t/innodb_multi_update.test new file mode 100644 index 00000000000..7ab17ccf70a --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_multi_update.test @@ -0,0 +1,29 @@ +-- source include/have_innodb.inc + +# +# Test multi update with different join methods +# + +CREATE TABLE bug38999_1 (a int not null primary key, b int not null, key (b)) engine=innodb; +CREATE TABLE bug38999_2 (a int not null primary key, b int not null, key (b)) engine=innodb; +INSERT INTO bug38999_1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12); +INSERT INTO bug38999_2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); + +# Full join, without key +update bug38999_1,bug38999_2 set bug38999_1.a=bug38999_1.a+100; +select * from bug38999_1; + +# unique key +update bug38999_1,bug38999_2 set bug38999_1.a=bug38999_1.a+100 where bug38999_1.a=101; +select * from bug38999_1; + +# ref key +update bug38999_1,bug38999_2 set bug38999_1.b=bug38999_1.b+10 where bug38999_1.b=2; +select * from bug38999_1; + +# Range key (in bug38999_1) +update bug38999_1,bug38999_2 set bug38999_1.b=bug38999_1.b+2,bug38999_2.b=bug38999_1.b+10 where bug38999_1.b between 3 and 5 and bug38999_1.a=bug38999_2.a+100; +select * from bug38999_1; +select * from bug38999_2; + +drop table bug38999_1,bug38999_2; diff --git a/mysql-test/t/innodb_trx_weight.test b/mysql-test/suite/innodb/t/innodb_trx_weight.test index b72eaad345f..b72eaad345f 100644 --- a/mysql-test/t/innodb_trx_weight.test +++ b/mysql-test/suite/innodb/t/innodb_trx_weight.test diff --git a/mysql-test/suite/ndb/r/ndb_binlog_format.result b/mysql-test/suite/ndb/r/ndb_binlog_format.result index baf00186ff3..909d122bfc6 100644 --- a/mysql-test/suite/ndb/r/ndb_binlog_format.result +++ b/mysql-test/suite/ndb/r/ndb_binlog_format.result @@ -9,12 +9,12 @@ INSERT INTO t1 VALUES (1,1), (1,2), (2,1), (2,2); INSERT INTO t2 VALUES (1,1), (1,2), (2,1), (2,2); UPDATE t1, t2 SET m = 2, b = 3 WHERE n = c; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. START TRANSACTION; INSERT INTO t3 VALUES (1,1), (1,2), (2,1), (2,2); UPDATE t1, t3 SET m = 2, e = 3 WHERE n = f; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. UPDATE t3, t2 SET e = 2, b = 3 WHERE f = c; COMMIT; show binlog events from <binlog_start>; diff --git a/mysql-test/suite/perfschema/r/dml_setup_instruments.result b/mysql-test/suite/perfschema/r/dml_setup_instruments.result index 448aaa7400f..73dc1178a54 100644 --- a/mysql-test/suite/perfschema/r/dml_setup_instruments.result +++ b/mysql-test/suite/perfschema/r/dml_setup_instruments.result @@ -8,12 +8,12 @@ wait/synch/mutex/sql/Cversion_lock YES YES wait/synch/mutex/sql/Delayed_insert::mutex YES YES wait/synch/mutex/sql/Event_scheduler::LOCK_scheduler_state YES YES wait/synch/mutex/sql/hash_filo::lock YES YES +wait/synch/mutex/sql/HA_DATA_PARTITION::LOCK_auto_inc YES YES wait/synch/mutex/sql/LOCK_active_mi YES YES wait/synch/mutex/sql/LOCK_audit_mask YES YES wait/synch/mutex/sql/LOCK_connection_count YES YES wait/synch/mutex/sql/LOCK_crypt YES YES wait/synch/mutex/sql/LOCK_delayed_create YES YES -wait/synch/mutex/sql/LOCK_delayed_insert YES YES select * from performance_schema.SETUP_INSTRUMENTS where name like 'Wait/Synch/Rwlock/sql/%' and name not in ('wait/synch/rwlock/sql/CRYPTO_dynlock_value::lock') diff --git a/mysql-test/suite/rpl/r/rpl_concurrency_error.result b/mysql-test/suite/rpl/r/rpl_concurrency_error.result index 033783c65b4..013f02c3a86 100644 --- a/mysql-test/suite/rpl/r/rpl_concurrency_error.result +++ b/mysql-test/suite/rpl/r/rpl_concurrency_error.result @@ -22,7 +22,7 @@ SET AUTOCOMMIT = 1; BEGIN; UPDATE t SET f = 'yellow 2' WHERE i = 3; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. SET AUTOCOMMIT = 1; BEGIN; UPDATE t SET f = 'magenta 2' WHERE f = 'red'; @@ -51,7 +51,7 @@ SET AUTOCOMMIT = 1; BEGIN; UPDATE t SET f = 'gray 2' WHERE i = 3; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. SET AUTOCOMMIT = 1; BEGIN; UPDATE t SET f = 'dark blue 2' WHERE f = 'red'; @@ -77,7 +77,7 @@ master-bin.000001 # Xid # # COMMIT /* XID */ SET AUTOCOMMIT = 0; UPDATE t SET f = 'yellow 1' WHERE i = 3; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. SET AUTOCOMMIT = 0; UPDATE t SET f = 'magenta 1' WHERE f = 'red'; ERROR HY000: Lock wait timeout exceeded; try restarting transaction @@ -104,7 +104,7 @@ master-bin.000001 # Query # # ROLLBACK SET AUTOCOMMIT = 0; UPDATE t SET f = 'gray 1' WHERE i = 3; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. SET AUTOCOMMIT = 0; UPDATE t SET f = 'dark blue 1' WHERE f = 'red'; ERROR HY000: Lock wait timeout exceeded; try restarting transaction diff --git a/mysql-test/suite/rpl/r/rpl_non_direct_stm_mixing_engines.result b/mysql-test/suite/rpl/r/rpl_non_direct_stm_mixing_engines.result index dfceb41948d..ab02432b0d4 100644 --- a/mysql-test/suite/rpl/r/rpl_non_direct_stm_mixing_engines.result +++ b/mysql-test/suite/rpl/r/rpl_non_direct_stm_mixing_engines.result @@ -392,7 +392,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 23, 1, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 23, 1, COUNT(*) FROM tt_1 @@ -408,7 +408,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 24, 1, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 24, 1, COUNT(*) FROM nt_1 @@ -424,7 +424,7 @@ master-bin.000001 # Xid # # COMMIT /* XID */ -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 25 --> 1", tt_3.info= "new text 25 --> 1" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; UPDATE nt_3, tt_3 SET nt_3.info= "new text 25 --> 1", tt_3.info= "new text 25 --> 1" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1 @@ -439,6 +439,8 @@ master-bin.000001 # Xid # # COMMIT /* XID */ -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (26, 1); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_4(trans_id, stmt_id) VALUES (26, 1) @@ -453,6 +455,8 @@ master-bin.000001 # Xid # # COMMIT /* XID */ -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (27, 1, fc_i_tt_5_suc(27, 1)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (27, 1, fc_i_tt_5_suc(27, 1)) @@ -468,7 +472,7 @@ master-bin.000001 # Xid # # COMMIT /* XID */ -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 28 --> 1", nt_4.info= "new text 28 --> 1" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; UPDATE tt_4, nt_4 SET tt_4.info= "new text 28 --> 1", nt_4.info= "new text 28 --> 1" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1 @@ -483,6 +487,8 @@ master-bin.000001 # Xid # # COMMIT /* XID */ -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (29, 1); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO tt_3(trans_id, stmt_id) VALUES (29, 1) @@ -497,6 +503,8 @@ master-bin.000001 # Xid # # COMMIT /* XID */ -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (30, 1, fc_i_nt_5_suc(30, 1)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (30, 1, fc_i_nt_5_suc(30, 1)) @@ -3637,6 +3645,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (134, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> N-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -3755,6 +3765,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (138, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> N-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -3877,6 +3889,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (142, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> N-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -4001,6 +4015,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T-proc << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (146, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> N-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -4261,6 +4277,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (154, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> N-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -4387,6 +4405,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (158, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> N-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -4517,6 +4537,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (162, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> N-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -4649,6 +4671,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T-proc << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (166, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> N-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -6053,7 +6077,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 205, 2, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 205, 2, COUNT(*) FROM tt_1 @@ -6087,7 +6111,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 206, 2, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6117,7 +6141,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 207 --> 2", tt_3.info= "new text 207 --> 2" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6146,6 +6170,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (208, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6174,6 +6200,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (209, 2, fc_i_tt_5_suc(209, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6203,7 +6231,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 210 --> 2", nt_4.info= "new text 210 --> 2" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6232,6 +6260,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (211, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6260,6 +6290,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (212, 2, fc_i_nt_5_suc(212, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6487,7 +6519,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 219, 2, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 219, 2, COUNT(*) FROM tt_1 @@ -6523,7 +6555,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 220, 2, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6545,7 +6577,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 221 --> 2", tt_3.info= "new text 221 --> 2" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6576,6 +6608,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (222, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6606,6 +6640,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (223, 2, fc_i_tt_5_suc(223, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6637,7 +6673,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 224 --> 2", nt_4.info= "new text 224 --> 2" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6668,6 +6704,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (225, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6698,6 +6736,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (226, 2, fc_i_nt_5_suc(226, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6934,7 +6974,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 233, 4, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> tN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -6964,7 +7004,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 234, 4, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -6994,7 +7034,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 235 --> 4", tt_3.info= "new text 235 --> 4" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -7023,6 +7063,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (236, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -7051,6 +7093,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (237, 4, fc_i_tt_5_suc(237, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -7080,7 +7124,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 238 --> 4", nt_4.info= "new text 238 --> 4" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -7109,6 +7153,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (239, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -7137,6 +7183,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (240, 4, fc_i_nt_5_suc(240, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -7358,7 +7406,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 247, 4, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> tN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7390,7 +7438,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 248, 4, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7412,7 +7460,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 249 --> 4", tt_3.info= "new text 249 --> 4" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7443,6 +7491,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (250, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7473,6 +7523,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (251, 4, fc_i_tt_5_suc(251, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7504,7 +7556,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 252 --> 4", nt_4.info= "new text 252 --> 4" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7535,6 +7587,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (253, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7565,6 +7619,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (254, 4, fc_i_nt_5_suc(254, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7790,7 +7846,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 261, 2, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 261, 2, COUNT(*) FROM tt_1 @@ -7824,7 +7880,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 262, 2, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -7856,7 +7912,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 263 --> 2", tt_3.info= "new text 263 --> 2" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -7887,6 +7943,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (264, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -7917,6 +7975,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (265, 2, fc_i_tt_5_suc(265, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -7948,7 +8008,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 266 --> 2", nt_4.info= "new text 266 --> 2" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -7979,6 +8039,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (267, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8009,6 +8071,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (268, 2, fc_i_nt_5_suc(268, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8248,7 +8312,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 275, 2, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 275, 2, COUNT(*) FROM tt_1 @@ -8284,7 +8348,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 276, 2, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8318,7 +8382,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 277 --> 2", tt_3.info= "new text 277 --> 2" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8351,6 +8415,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (278, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8383,6 +8449,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (279, 2, fc_i_tt_5_suc(279, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8416,7 +8484,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 280 --> 2", nt_4.info= "new text 280 --> 2" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8449,6 +8517,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (281, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8481,6 +8551,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (282, 2, fc_i_nt_5_suc(282, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8740,7 +8812,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 289, 4, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 289, 4, COUNT(*) FROM tt_1 @@ -8774,7 +8846,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 290, 4, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -8808,7 +8880,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 291 --> 4", tt_3.info= "new text 291 --> 4" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -8841,6 +8913,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (292, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -8873,6 +8947,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (293, 4, fc_i_tt_5_suc(293, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -8906,7 +8982,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 294 --> 4", nt_4.info= "new text 294 --> 4" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -8939,6 +9015,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (295, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -8971,6 +9049,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (296, 4, fc_i_nt_5_suc(296, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -9218,7 +9298,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 303, 4, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 303, 4, COUNT(*) FROM tt_1 @@ -9254,7 +9334,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 304, 4, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -9290,7 +9370,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 305 --> 4", tt_3.info= "new text 305 --> 4" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -9325,6 +9405,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (306, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -9359,6 +9441,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (307, 4, fc_i_tt_5_suc(307, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -9394,7 +9478,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 308 --> 4", nt_4.info= "new text 308 --> 4" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -9429,6 +9513,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (309, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -9463,6 +9549,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (310, 4, fc_i_nt_5_suc(310, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -10047,7 +10135,7 @@ Log_name Pos Event_type Server_id End_log_pos Info INSERT INTO tt_xx_7(trans_id, stmt_id, info) SELECT trans_id, stmt_id, USER() FROM nt_1;; 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. -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> IS-T<-N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -10125,7 +10213,7 @@ Log_name Pos Event_type Server_id End_log_pos Info INSERT INTO tt_xx_7(trans_id, stmt_id, info) SELECT trans_id, stmt_id, USER() FROM nt_1;; 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. -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> IS-T<-N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -10389,7 +10477,7 @@ Log_name Pos Event_type Server_id End_log_pos Info INSERT INTO nt_xx_9(trans_id, stmt_id, info) SELECT trans_id, stmt_id, USER() FROM tt_1;; 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. -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> IS-N<-T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -10469,7 +10557,7 @@ Log_name Pos Event_type Server_id End_log_pos Info INSERT INTO nt_xx_9(trans_id, stmt_id, info) SELECT trans_id, stmt_id, USER() FROM tt_1;; 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. -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_xx_9(trans_id, stmt_id, info) SELECT trans_id, stmt_id, USER() FROM tt_1 @@ -10879,7 +10967,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 357, 2, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 357, 2, COUNT(*) FROM tt_1 diff --git a/mysql-test/suite/rpl/r/rpl_stm_mixing_engines.result b/mysql-test/suite/rpl/r/rpl_stm_mixing_engines.result index 579e5eb02e9..a5219662881 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_mixing_engines.result +++ b/mysql-test/suite/rpl/r/rpl_stm_mixing_engines.result @@ -392,7 +392,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 23, 1, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 23, 1, COUNT(*) FROM tt_1 @@ -408,7 +408,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 24, 1, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 24, 1, COUNT(*) FROM nt_1 @@ -424,7 +424,7 @@ master-bin.000001 # Xid # # COMMIT /* XID */ -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 25 --> 1", tt_3.info= "new text 25 --> 1" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; UPDATE nt_3, tt_3 SET nt_3.info= "new text 25 --> 1", tt_3.info= "new text 25 --> 1" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1 @@ -439,6 +439,8 @@ master-bin.000001 # Xid # # COMMIT /* XID */ -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (26, 1); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_4(trans_id, stmt_id) VALUES (26, 1) @@ -453,6 +455,8 @@ master-bin.000001 # Xid # # COMMIT /* XID */ -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (27, 1, fc_i_tt_5_suc(27, 1)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (27, 1, fc_i_tt_5_suc(27, 1)) @@ -468,7 +472,7 @@ master-bin.000001 # Xid # # COMMIT /* XID */ -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 28 --> 1", nt_4.info= "new text 28 --> 1" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; UPDATE tt_4, nt_4 SET tt_4.info= "new text 28 --> 1", nt_4.info= "new text 28 --> 1" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1 @@ -483,6 +487,8 @@ master-bin.000001 # Xid # # COMMIT /* XID */ -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (29, 1); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO tt_3(trans_id, stmt_id) VALUES (29, 1) @@ -497,6 +503,8 @@ master-bin.000001 # Xid # # COMMIT /* XID */ -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (30, 1, fc_i_nt_5_suc(30, 1)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (30, 1, fc_i_nt_5_suc(30, 1)) @@ -3641,6 +3649,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (134, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_5(trans_id, stmt_id) VALUES (134, 4) @@ -3779,6 +3789,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (138, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_5(trans_id, stmt_id) VALUES (138, 4) @@ -3921,6 +3933,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (142, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_5(trans_id, stmt_id) VALUES (142, 4) @@ -4065,6 +4079,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T-proc << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (146, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_5(trans_id, stmt_id) VALUES (146, 4) @@ -4349,6 +4365,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (154, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_5(trans_id, stmt_id) VALUES (154, 4) @@ -4495,6 +4513,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (158, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_5(trans_id, stmt_id) VALUES (158, 4) @@ -4645,6 +4665,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (162, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_5(trans_id, stmt_id) VALUES (162, 4) @@ -4797,6 +4819,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T-proc << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id) VALUES (166, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_5(trans_id, stmt_id) VALUES (166, 4) @@ -6221,7 +6245,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 205, 2, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 205, 2, COUNT(*) FROM tt_1 @@ -6255,7 +6279,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 206, 2, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6285,7 +6309,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 207 --> 2", tt_3.info= "new text 207 --> 2" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6314,6 +6338,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (208, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6342,6 +6368,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (209, 2, fc_i_tt_5_suc(209, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6371,7 +6399,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 210 --> 2", nt_4.info= "new text 210 --> 2" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6400,6 +6428,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (211, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6428,6 +6458,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (212, 2, fc_i_nt_5_suc(212, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6655,7 +6687,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 219, 2, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 219, 2, COUNT(*) FROM tt_1 @@ -6691,7 +6723,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 220, 2, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6713,7 +6745,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 221 --> 2", tt_3.info= "new text 221 --> 2" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6744,6 +6776,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (222, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6774,6 +6808,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (223, 2, fc_i_tt_5_suc(223, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6805,7 +6841,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 224 --> 2", nt_4.info= "new text 224 --> 2" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6836,6 +6872,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (225, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -6866,6 +6904,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (226, 2, fc_i_nt_5_suc(226, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -7102,7 +7142,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 233, 4, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 233, 4, COUNT(*) FROM tt_1 @@ -7136,7 +7176,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 234, 4, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -7166,7 +7206,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 235 --> 4", tt_3.info= "new text 235 --> 4" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -7195,6 +7235,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (236, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -7223,6 +7265,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (237, 4, fc_i_tt_5_suc(237, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -7252,7 +7296,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 238 --> 4", nt_4.info= "new text 238 --> 4" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -7281,6 +7325,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (239, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -7309,6 +7355,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (240, 4, fc_i_nt_5_suc(240, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -7534,7 +7582,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 247, 4, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 247, 4, COUNT(*) FROM tt_1 @@ -7570,7 +7618,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 248, 4, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7592,7 +7640,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 249 --> 4", tt_3.info= "new text 249 --> 4" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7623,6 +7671,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (250, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7653,6 +7703,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (251, 4, fc_i_tt_5_suc(251, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7684,7 +7736,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 252 --> 4", nt_4.info= "new text 252 --> 4" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7715,6 +7767,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (253, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7745,6 +7799,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> T << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (254, 4, fc_i_nt_5_suc(254, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -7974,7 +8030,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 261, 2, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 261, 2, COUNT(*) FROM tt_1 @@ -8008,7 +8064,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 262, 2, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8044,7 +8100,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 263 --> 2", tt_3.info= "new text 263 --> 2" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8079,6 +8135,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (264, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8113,6 +8171,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (265, 2, fc_i_tt_5_suc(265, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8148,7 +8208,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 266 --> 2", nt_4.info= "new text 266 --> 2" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8183,6 +8243,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (267, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8217,6 +8279,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (268, 2, fc_i_nt_5_suc(268, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8476,7 +8540,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 275, 2, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 275, 2, COUNT(*) FROM tt_1 @@ -8512,7 +8576,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 276, 2, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8550,7 +8614,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 277 --> 2", tt_3.info= "new text 277 --> 2" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8587,6 +8651,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (278, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8623,6 +8689,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (279, 2, fc_i_tt_5_suc(279, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8660,7 +8728,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 280 --> 2", nt_4.info= "new text 280 --> 2" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8697,6 +8765,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (281, 2); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -8733,6 +8803,8 @@ Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> B << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (282, 2, fc_i_nt_5_suc(282, 2)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> N << -b-b-b-b-b-b-b-b-b-b-b- @@ -9012,7 +9084,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 289, 4, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 289, 4, COUNT(*) FROM tt_1 @@ -9046,7 +9118,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 290, 4, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -9080,7 +9152,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 291 --> 4", tt_3.info= "new text 291 --> 4" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -9113,6 +9185,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (292, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -9145,6 +9219,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (293, 4, fc_i_tt_5_suc(293, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -9178,7 +9254,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 294 --> 4", nt_4.info= "new text 294 --> 4" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -9211,6 +9287,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (295, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -9243,6 +9321,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (296, 4, fc_i_nt_5_suc(296, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> C << -b-b-b-b-b-b-b-b-b-b-b- @@ -9490,7 +9570,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 303, 4, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 303, 4, COUNT(*) FROM tt_1 @@ -9526,7 +9606,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> nT << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_1(trans_id, stmt_id, info) SELECT 304, 4, COUNT(*) FROM nt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> nT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -9562,7 +9642,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> NT << -b-b-b-b-b-b-b-b-b-b-b- UPDATE nt_3, tt_3 SET nt_3.info= "new text 305 --> 4", tt_3.info= "new text 305 --> 4" where nt_3.trans_id = tt_3.trans_id and tt_3.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -9597,6 +9677,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_4(trans_id, stmt_id) VALUES (306, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -9631,6 +9713,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> NT-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_5(trans_id, stmt_id, info) VALUES (307, 4, fc_i_tt_5_suc(307, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> NT-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -9666,7 +9750,7 @@ master-bin.000001 # Query # # COMMIT -b-b-b-b-b-b-b-b-b-b-b- >> TN << -b-b-b-b-b-b-b-b-b-b-b- UPDATE tt_4, nt_4 SET tt_4.info= "new text 308 --> 4", nt_4.info= "new text 308 --> 4" where nt_4.trans_id = tt_4.trans_id and tt_4.trans_id = 1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -9701,6 +9785,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-trig << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_3(trans_id, stmt_id) VALUES (309, 4); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-trig << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -9735,6 +9821,8 @@ master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> TN-func << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO tt_5(trans_id, stmt_id, info) VALUES (310, 4, fc_i_nt_5_suc(310, 4)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> TN-func << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> R << -b-b-b-b-b-b-b-b-b-b-b- @@ -10327,7 +10415,7 @@ Log_name Pos Event_type Server_id End_log_pos Info INSERT INTO tt_xx_7(trans_id, stmt_id, info) SELECT trans_id, stmt_id, USER() FROM nt_1;; 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. -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> IS-T<-N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -10405,7 +10493,7 @@ Log_name Pos Event_type Server_id End_log_pos Info INSERT INTO tt_xx_7(trans_id, stmt_id, info) SELECT trans_id, stmt_id, USER() FROM nt_1;; 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. -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info -e-e-e-e-e-e-e-e-e-e-e- >> IS-T<-N << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> T << -b-b-b-b-b-b-b-b-b-b-b- @@ -10669,7 +10757,7 @@ Log_name Pos Event_type Server_id End_log_pos Info INSERT INTO nt_xx_9(trans_id, stmt_id, info) SELECT trans_id, stmt_id, USER() FROM tt_1;; 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. -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_xx_9(trans_id, stmt_id, info) SELECT trans_id, stmt_id, USER() FROM tt_1 @@ -10757,7 +10845,7 @@ Log_name Pos Event_type Server_id End_log_pos Info INSERT INTO nt_xx_9(trans_id, stmt_id, info) SELECT trans_id, stmt_id, USER() FROM tt_1;; 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. -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_xx_9(trans_id, stmt_id, info) SELECT trans_id, stmt_id, USER() FROM tt_1 @@ -11175,7 +11263,7 @@ Log_name Pos Event_type Server_id End_log_pos Info -b-b-b-b-b-b-b-b-b-b-b- >> tN << -b-b-b-b-b-b-b-b-b-b-b- INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 357, 2, COUNT(*) FROM tt_1; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # BEGIN master-bin.000001 # Query # # use `test`; INSERT INTO nt_1(trans_id, stmt_id, info) SELECT 357, 2, COUNT(*) FROM tt_1 diff --git a/mysql-test/suite/rpl/r/rpl_stm_stop_middle_group.result b/mysql-test/suite/rpl/r/rpl_stm_stop_middle_group.result index e4e98f0bfe5..96829a1b1ec 100644 --- a/mysql-test/suite/rpl/r/rpl_stm_stop_middle_group.result +++ b/mysql-test/suite/rpl/r/rpl_stm_stop_middle_group.result @@ -53,7 +53,7 @@ set @@global.debug="+d,stop_slave_middle_group"; set @@global.debug="+d,incomplete_group_in_relay_log"; update tm as t1, ti as t2 set t1.a=t1.a * 2, t2.a=t2.a * 2; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. SELECT "Fatal error: ... The slave SQL is stopped, leaving the current group of events unfinished with a non-transaction table changed. If the group consists solely of Row-based events, you can try restarting the slave with --slave-exec-mode=IDEMPOTENT, which ignores duplicate key, key not found, and similar errors (see documentation for details)." AS Last_SQL_Error, @check as `true`; Last_SQL_Error true Fatal error: ... The slave SQL is stopped, leaving the current group of events unfinished with a non-transaction table changed. If the group consists solely of Row-based events, you can try restarting the slave with --slave-exec-mode=IDEMPOTENT, which ignores duplicate key, key not found, and similar errors (see documentation for details). 1 diff --git a/mysql-test/suite/rpl/r/rpl_temp_temporary.result b/mysql-test/suite/rpl/r/rpl_temp_temporary.result index 19b36da2800..3911bd8a773 100644 --- a/mysql-test/suite/rpl/r/rpl_temp_temporary.result +++ b/mysql-test/suite/rpl/r/rpl_temp_temporary.result @@ -24,7 +24,7 @@ INSERT INTO t_innodb_temp VALUES(1); BEGIN; INSERT INTO t_myisam SELECT * FROM t_myisam_temp; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. INSERT INTO t_innodb SELECT * FROM t_myisam_temp; INSERT INTO t_innodb SELECT * FROM t_innodb_temp; ROLLBACK; @@ -33,7 +33,7 @@ Warning 1196 Some non-transactional changed tables couldn't be rolled back BEGIN; INSERT INTO t_myisam SELECT * FROM t_innodb_temp; Warnings: -Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe. +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them. INSERT INTO t_innodb SELECT * FROM t_myisam_temp; INSERT INTO t_innodb SELECT * FROM t_innodb_temp; ROLLBACK; @@ -193,8 +193,6 @@ Warnings: Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction. INSERT INTO t_innodb VALUES(1); COMMIT; -DROP TABLE t_myisam; -DROP TABLE t_innodb; show binlog events from <binlog_start>; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp1(id int) engine= MyIsam @@ -214,8 +212,29 @@ master-bin.000001 # Query # # use `test`; INSERT INTO tmp1 VALUES(1) master-bin.000001 # Query # # use `test`; INSERT INTO t_innodb VALUES(1) master-bin.000001 # Query # # use `test`; INSERT INTO t_innodb VALUES(1) master-bin.000001 # Xid # # COMMIT /* XID */ -master-bin.000001 # Query # # use `test`; DROP TABLE t_myisam -master-bin.000001 # Query # # use `test`; DROP TABLE t_innodb +######################################################################## +# VERIFY ITEM 8 +######################################################################## +SET BINLOG_FORMAT=MIXED; +BEGIN; +CREATE TEMPORARY TABLE tmp2 SELECT * FROM t_innodb; +INSERT INTO t_innodb VALUES(1); +INSERT INTO t_innodb VALUES(1); +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp2 SELECT * FROM t_innodb +master-bin.000001 # Query # # use `test`; INSERT INTO t_innodb VALUES(1) +master-bin.000001 # Query # # use `test`; INSERT INTO t_innodb VALUES(1) +master-bin.000001 # Query # # ROLLBACK ################################################################################### # CHECK CONSISTENCY ################################################################################### +################################################################################### +# CLEAN UP +################################################################################### +DROP TABLE t_myisam; +DROP TABLE t_innodb; diff --git a/mysql-test/suite/rpl/t/rpl_semi_sync.test b/mysql-test/suite/rpl/t/rpl_semi_sync.test index 7610ee68417..1bf4f1a3396 100644 --- a/mysql-test/suite/rpl/t/rpl_semi_sync.test +++ b/mysql-test/suite/rpl/t/rpl_semi_sync.test @@ -602,7 +602,11 @@ source include/stop_slave.inc; UNINSTALL PLUGIN rpl_semi_sync_slave; connection master; +# The dump thread may still be running on the master, and so the following +# UNINSTALL could generate a warning about the plugin is busy. +disable_warnings; UNINSTALL PLUGIN rpl_semi_sync_master; +enable_warnings; connection slave; source include/start_slave.inc; diff --git a/mysql-test/suite/rpl/t/rpl_temp_temporary.test b/mysql-test/suite/rpl/t/rpl_temp_temporary.test index a7234c53655..4eb2d16b91e 100644 --- a/mysql-test/suite/rpl/t/rpl_temp_temporary.test +++ b/mysql-test/suite/rpl/t/rpl_temp_temporary.test @@ -34,10 +34,13 @@ # the CREATE TEMPORARY is not logged and the DROP TEMPORARY is extended with # the IF EXISTS clause. # -# 7 - It also verifies if the CONNECTION_ID along with a non-transactional +# 7 - It verifies if the CONNECTION_ID along with a non-transactional # table is written outside the transaction boundaries and is not classified # as unsafe. See BUG#53075. # +# 8 - It verifies if OPTION_KEEP_LOG is set and thus forcing to write the +# trx-cache to the binary log when an rollback is issued and only trx-tables +# were updated. See BUG#53421. ################################################################################ source include/master-slave.inc; @@ -186,18 +189,40 @@ INSERT INTO t_innodb VALUES(1); INSERT INTO t_myisam VALUES(CONNECTION_ID()); INSERT INTO t_innodb VALUES(1); COMMIT; -DROP TABLE t_myisam; -DROP TABLE t_innodb; +source include/show_binlog_events.inc; + +--echo ######################################################################## +--echo # VERIFY ITEM 8 +--echo ######################################################################## +# +# Before the patch for BUG#53421, nothing were written to the binary log on +# behalf of the transaction presented below: +# +SET BINLOG_FORMAT=MIXED; +let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1); +BEGIN; +CREATE TEMPORARY TABLE tmp2 SELECT * FROM t_innodb; +INSERT INTO t_innodb VALUES(1); +INSERT INTO t_innodb VALUES(1); +ROLLBACK; source include/show_binlog_events.inc; --echo ################################################################################### --echo # CHECK CONSISTENCY --echo ################################################################################### -connection master; sync_slave_with_master; +connection master; --exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/test-nmt-master.sql --exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/test-nmt-slave.sql --diff_files $MYSQLTEST_VARDIR/tmp/test-nmt-master.sql $MYSQLTEST_VARDIR/tmp/test-nmt-slave.sql +--echo ################################################################################### +--echo # CLEAN UP +--echo ################################################################################### +connection master; +DROP TABLE t_myisam; +DROP TABLE t_innodb; + +sync_slave_with_master; diff --git a/mysql-test/suite/rpl_ndb/r/rpl_ndb_binlog_format_errors.result b/mysql-test/suite/rpl_ndb/r/rpl_ndb_binlog_format_errors.result index 7350f10e53e..64ab9a6d637 100644 --- a/mysql-test/suite/rpl_ndb/r/rpl_ndb_binlog_format_errors.result +++ b/mysql-test/suite/rpl_ndb/r/rpl_ndb_binlog_format_errors.result @@ -43,11 +43,11 @@ SELECT * FROM t /* Should be empty */; a * Modify both row-only and stmt-only table CREATE TRIGGER trig_2 AFTER INSERT ON t_stmt FOR EACH ROW BEGIN INSERT INTO t_row VALUES(1); END; -ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-based logging. INSERT INTO t_stmt VALUES (1); -ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-based logging. +ERROR HY000: Cannot execute statement: impossible to write to binary log since both row-incapable engines and statement-incapable engines are involved. SELECT * FROM t_stmt /* should be empty */; a +DROP TRIGGER trig_2; * Stmt-only table and binlog_format=row INSERT INTO t_stmt VALUES (1); ERROR HY000: Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = ROW and at least one table uses a storage engine limited to statement-based logging. diff --git a/mysql-test/suite/rpl_ndb/t/rpl_ndb_binlog_format_errors.test b/mysql-test/suite/rpl_ndb/t/rpl_ndb_binlog_format_errors.test index 14f39d7de2b..1aae0d2d57f 100644 --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_binlog_format_errors.test +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_binlog_format_errors.test @@ -97,11 +97,11 @@ SELECT * FROM t_self_logging /* Should be empty */; SELECT * FROM t /* Should be empty */; --echo * Modify both row-only and stmt-only table ---error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE --eval CREATE TRIGGER trig_2 AFTER INSERT ON t_stmt FOR EACH ROW BEGIN INSERT INTO t_row VALUES(1); END ---error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE +--error ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE INSERT INTO t_stmt VALUES (1); SELECT * FROM t_stmt /* should be empty */; +DROP TRIGGER trig_2; --echo * Stmt-only table and binlog_format=row --error ER_BINLOG_ROW_MODE_AND_STMT_ENGINE diff --git a/mysql-test/suite/sys_vars/r/innodb_buffer_pool_instances_basic.result b/mysql-test/suite/sys_vars/r/innodb_buffer_pool_instances_basic.result new file mode 100644 index 00000000000..a3c1a7b7bd4 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_buffer_pool_instances_basic.result @@ -0,0 +1,53 @@ +'#---------------------BS_STVARS_035_01----------------------#' +SELECT COUNT(@@GLOBAL.innodb_buffer_pool_instances); +COUNT(@@GLOBAL.innodb_buffer_pool_instances) +1 +1 Expected +'#---------------------BS_STVARS_035_02----------------------#' +SET @@GLOBAL.innodb_buffer_pool_instances=1; +ERROR HY000: Variable 'innodb_buffer_pool_instances' is a read only variable +Expected error 'Read only variable' +SELECT COUNT(@@GLOBAL.innodb_buffer_pool_instances); +COUNT(@@GLOBAL.innodb_buffer_pool_instances) +1 +1 Expected +'#---------------------BS_STVARS_035_03----------------------#' +SELECT @@GLOBAL.innodb_buffer_pool_instances = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_buffer_pool_instances'; +@@GLOBAL.innodb_buffer_pool_instances = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.innodb_buffer_pool_instances); +COUNT(@@GLOBAL.innodb_buffer_pool_instances) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_buffer_pool_instances'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +'#---------------------BS_STVARS_035_04----------------------#' +SELECT @@innodb_buffer_pool_instances = @@GLOBAL.innodb_buffer_pool_instances; +@@innodb_buffer_pool_instances = @@GLOBAL.innodb_buffer_pool_instances +1 +1 Expected +'#---------------------BS_STVARS_035_05----------------------#' +SELECT COUNT(@@innodb_buffer_pool_instances); +COUNT(@@innodb_buffer_pool_instances) +1 +1 Expected +SELECT COUNT(@@local.innodb_buffer_pool_instances); +ERROR HY000: Variable 'innodb_buffer_pool_instances' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.innodb_buffer_pool_instances); +ERROR HY000: Variable 'innodb_buffer_pool_instances' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.innodb_buffer_pool_instances); +COUNT(@@GLOBAL.innodb_buffer_pool_instances) +1 +1 Expected +SELECT innodb_buffer_pool_instances = @@SESSION.innodb_buffer_pool_instances; +ERROR 42S22: Unknown column 'innodb_buffer_pool_instances' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/r/innodb_change_buffering_basic.result b/mysql-test/suite/sys_vars/r/innodb_change_buffering_basic.result index 70b0425ce6f..f80ed54100f 100644 --- a/mysql-test/suite/sys_vars/r/innodb_change_buffering_basic.result +++ b/mysql-test/suite/sys_vars/r/innodb_change_buffering_basic.result @@ -1,28 +1,28 @@ SET @start_global_value = @@global.innodb_change_buffering; SELECT @start_global_value; @start_global_value -inserts -Valid values are 'inserts' and 'none' -select @@global.innodb_change_buffering in ('inserts', 'none'); -@@global.innodb_change_buffering in ('inserts', 'none') +all +Valid values are 'all', 'deletes', 'changes', 'inserts', 'none', 'purges' +select @@global.innodb_change_buffering in ('all', 'deletes', 'changes', 'inserts', 'none', 'purges'); +@@global.innodb_change_buffering in ('all', 'deletes', 'changes', 'inserts', 'none', 'purges') 1 select @@global.innodb_change_buffering; @@global.innodb_change_buffering -inserts +all select @@session.innodb_change_buffering; ERROR HY000: Variable 'innodb_change_buffering' is a GLOBAL variable show global variables like 'innodb_change_buffering'; Variable_name Value -innodb_change_buffering inserts +innodb_change_buffering all show session variables like 'innodb_change_buffering'; Variable_name Value -innodb_change_buffering inserts +innodb_change_buffering all select * from information_schema.global_variables where variable_name='innodb_change_buffering'; VARIABLE_NAME VARIABLE_VALUE -INNODB_CHANGE_BUFFERING inserts +INNODB_CHANGE_BUFFERING all select * from information_schema.session_variables where variable_name='innodb_change_buffering'; VARIABLE_NAME VARIABLE_VALUE -INNODB_CHANGE_BUFFERING inserts +INNODB_CHANGE_BUFFERING all set global innodb_change_buffering='none'; select @@global.innodb_change_buffering; @@global.innodb_change_buffering @@ -60,4 +60,4 @@ ERROR 42000: Variable 'innodb_change_buffering' can't be set to the value of 'so SET @@global.innodb_change_buffering = @start_global_value; SELECT @@global.innodb_change_buffering; @@global.innodb_change_buffering -inserts +all diff --git a/mysql-test/suite/sys_vars/r/innodb_purge_batch_size_basic.result b/mysql-test/suite/sys_vars/r/innodb_purge_batch_size_basic.result new file mode 100644 index 00000000000..1ff36237907 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_purge_batch_size_basic.result @@ -0,0 +1,98 @@ +SET @global_start_value = @@global.innodb_purge_batch_size; +SELECT @global_start_value; +@global_start_value +20 +'#--------------------FN_DYNVARS_046_01------------------------#' +SET @@global.innodb_purge_batch_size = 1; +SET @@global.innodb_purge_batch_size = DEFAULT; +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +20 +'#---------------------FN_DYNVARS_046_02-------------------------#' +SET innodb_purge_batch_size = 1; +ERROR HY000: Variable 'innodb_purge_batch_size' is a GLOBAL variable and should be set with SET GLOBAL +SELECT @@innodb_purge_batch_size; +@@innodb_purge_batch_size +20 +SELECT local.innodb_purge_batch_size; +ERROR 42S02: Unknown table 'local' in field list +SET global innodb_purge_batch_size = 1; +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +1 +'#--------------------FN_DYNVARS_046_03------------------------#' +SET @@global.innodb_purge_batch_size = 1; +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +1 +SET @@global.innodb_purge_batch_size = 5000; +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +5000 +SET @@global.innodb_purge_batch_size = 1000; +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +1000 +'#--------------------FN_DYNVARS_046_04-------------------------#' +SET @@global.innodb_purge_batch_size = 0; +Warnings: +Warning 1292 Truncated incorrect innodb_purge_batch_size value: '0' +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +1 +SET @@global.innodb_purge_batch_size = "T"; +ERROR 42000: Incorrect argument type to variable 'innodb_purge_batch_size' +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +1 +SET @@global.innodb_purge_batch_size = "Y"; +ERROR 42000: Incorrect argument type to variable 'innodb_purge_batch_size' +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +1 +SET @@global.innodb_purge_batch_size = 5001; +Warnings: +Warning 1292 Truncated incorrect innodb_purge_batch_size value: '5001' +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +5000 +'#----------------------FN_DYNVARS_046_05------------------------#' +SELECT @@global.innodb_purge_batch_size = +VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_purge_batch_size'; +@@global.innodb_purge_batch_size = +VARIABLE_VALUE +1 +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +5000 +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_purge_batch_size'; +VARIABLE_VALUE +5000 +'#---------------------FN_DYNVARS_046_06-------------------------#' +SET @@global.innodb_purge_batch_size = OFF; +ERROR 42000: Incorrect argument type to variable 'innodb_purge_batch_size' +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +5000 +SET @@global.innodb_purge_batch_size = ON; +ERROR 42000: Incorrect argument type to variable 'innodb_purge_batch_size' +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +5000 +'#---------------------FN_DYNVARS_046_07----------------------#' +SET @@global.innodb_purge_batch_size = TRUE; +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +1 +SET @@global.innodb_purge_batch_size = FALSE; +Warnings: +Warning 1292 Truncated incorrect innodb_purge_batch_size value: '0' +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +1 +SET @@global.innodb_purge_batch_size = @global_start_value; +SELECT @@global.innodb_purge_batch_size; +@@global.innodb_purge_batch_size +20 diff --git a/mysql-test/suite/sys_vars/r/innodb_purge_threads_basic.result b/mysql-test/suite/sys_vars/r/innodb_purge_threads_basic.result new file mode 100644 index 00000000000..e3358a14ea2 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_purge_threads_basic.result @@ -0,0 +1,53 @@ +'#---------------------BS_STVARS_035_01----------------------#' +SELECT COUNT(@@GLOBAL.innodb_purge_threads); +COUNT(@@GLOBAL.innodb_purge_threads) +1 +1 Expected +'#---------------------BS_STVARS_035_02----------------------#' +SET @@GLOBAL.innodb_purge_threads=1; +ERROR HY000: Variable 'innodb_purge_threads' is a read only variable +Expected error 'Read only variable' +SELECT COUNT(@@GLOBAL.innodb_purge_threads); +COUNT(@@GLOBAL.innodb_purge_threads) +1 +1 Expected +'#---------------------BS_STVARS_035_03----------------------#' +SELECT @@GLOBAL.innodb_purge_threads = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_purge_threads'; +@@GLOBAL.innodb_purge_threads = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.innodb_purge_threads); +COUNT(@@GLOBAL.innodb_purge_threads) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_purge_threads'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +'#---------------------BS_STVARS_035_04----------------------#' +SELECT @@innodb_purge_threads = @@GLOBAL.innodb_purge_threads; +@@innodb_purge_threads = @@GLOBAL.innodb_purge_threads +1 +1 Expected +'#---------------------BS_STVARS_035_05----------------------#' +SELECT COUNT(@@innodb_purge_threads); +COUNT(@@innodb_purge_threads) +1 +1 Expected +SELECT COUNT(@@local.innodb_purge_threads); +ERROR HY000: Variable 'innodb_purge_threads' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.innodb_purge_threads); +ERROR HY000: Variable 'innodb_purge_threads' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.innodb_purge_threads); +COUNT(@@GLOBAL.innodb_purge_threads) +1 +1 Expected +SELECT innodb_purge_threads = @@SESSION.innodb_purge_threads; +ERROR 42S22: Unknown column 'innodb_purge_threads' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/r/innodb_use_native_aio_basic.result b/mysql-test/suite/sys_vars/r/innodb_use_native_aio_basic.result new file mode 100644 index 00000000000..2e093a9fd2a --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_use_native_aio_basic.result @@ -0,0 +1,53 @@ +'#---------------------BS_STVARS_035_01----------------------#' +SELECT COUNT(@@GLOBAL.innodb_use_native_aio); +COUNT(@@GLOBAL.innodb_use_native_aio) +1 +1 Expected +'#---------------------BS_STVARS_035_02----------------------#' +SET @@GLOBAL.innodb_use_native_aio=1; +ERROR HY000: Variable 'innodb_use_native_aio' is a read only variable +Expected error 'Read only variable' +SELECT COUNT(@@GLOBAL.innodb_use_native_aio); +COUNT(@@GLOBAL.innodb_use_native_aio) +1 +1 Expected +'#---------------------BS_STVARS_035_03----------------------#' +SELECT IF(@@GLOBAL.innodb_use_native_aio, 'ON', 'OFF') = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_use_native_aio'; +IF(@@GLOBAL.innodb_use_native_aio, 'ON', 'OFF') = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.innodb_use_native_aio); +COUNT(@@GLOBAL.innodb_use_native_aio) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_use_native_aio'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +'#---------------------BS_STVARS_035_04----------------------#' +SELECT @@innodb_use_native_aio = @@GLOBAL.innodb_use_native_aio; +@@innodb_use_native_aio = @@GLOBAL.innodb_use_native_aio +1 +1 Expected +'#---------------------BS_STVARS_035_05----------------------#' +SELECT COUNT(@@innodb_use_native_aio); +COUNT(@@innodb_use_native_aio) +1 +1 Expected +SELECT COUNT(@@local.innodb_use_native_aio); +ERROR HY000: Variable 'innodb_use_native_aio' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.innodb_use_native_aio); +ERROR HY000: Variable 'innodb_use_native_aio' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@GLOBAL.innodb_use_native_aio); +COUNT(@@GLOBAL.innodb_use_native_aio) +1 +1 Expected +SELECT innodb_use_native_aio = @@SESSION.innodb_use_native_aio; +ERROR 42S22: Unknown column 'innodb_use_native_aio' in 'field list' +Expected error 'Readonly variable' diff --git a/mysql-test/suite/sys_vars/r/tx_isolation_func.result b/mysql-test/suite/sys_vars/r/tx_isolation_func.result index 2242525f14b..6b4c990c71c 100644 --- a/mysql-test/suite/sys_vars/r/tx_isolation_func.result +++ b/mysql-test/suite/sys_vars/r/tx_isolation_func.result @@ -95,10 +95,7 @@ a b 22 10 24 10 INSERT INTO t1 VALUES(23, 23); -ERROR HY000: Lock wait timeout exceeded; try restarting transaction INSERT INTO t1 VALUES(25, 25); -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -Bug: Only even rows are being locked, error 1205 should'nt have occured SELECT * FROM t1; a b 2 10 @@ -109,7 +106,9 @@ a b 18 10 20 10 22 10 +23 23 24 10 +25 25 COMMIT; ** Connection con0 ** COMMIT; @@ -144,7 +143,9 @@ a b 18 10 20 10 22 10 +23 23 24 10 +25 25 INSERT INTO t1 VALUES(5, 5); INSERT INTO t1 VALUES(7, 7); SELECT * FROM t1; @@ -159,7 +160,9 @@ a b 18 10 20 10 22 10 +23 23 24 10 +25 25 COMMIT; ** Connection con0 ** COMMIT; @@ -196,7 +199,9 @@ a b 18 11 20 11 22 11 +23 23 24 11 +25 25 INSERT INTO t1 VALUES(9, 9); ERROR HY000: Lock wait timeout exceeded; try restarting transaction INSERT INTO t1 VALUES(13, 13); @@ -214,7 +219,9 @@ a b 18 11 20 11 22 11 +23 23 24 11 +25 25 COMMIT; ** Connection con0 ** COMMIT; @@ -225,6 +232,8 @@ SELECT * FROM t1 WHERE a IN (2,4,6,8,10,12,14,16,18,20,22,24,26) = 0 FOR UPDATE; a b 5 5 7 7 +23 23 +25 25 UPDATE t1 SET b = 13 WHERE a IN (2,4,6,8,10,12,14,16,18,20,22,24,26) = 0; ** Connection con1 ** START TRANSACTION; @@ -240,7 +249,9 @@ a b 18 12 20 12 22 12 +23 23 24 12 +25 25 INSERT INTO t1 VALUES(9, 9); ERROR HY000: Lock wait timeout exceeded; try restarting transaction INSERT INTO t1 VALUES(13, 13); @@ -258,7 +269,9 @@ a b 18 12 20 12 22 12 +23 23 24 12 +25 25 COMMIT; ** Connection con0 ** COMMIT; @@ -273,7 +286,9 @@ a b 18 12 20 12 22 12 +23 13 24 12 +25 13 UPDATE t1 SET b = 14 WHERE a IN (2,4,6,8) = 0; ** Connection con1 ** START TRANSACTION; @@ -289,7 +304,9 @@ a b 18 12 20 12 22 12 +23 13 24 12 +25 13 INSERT INTO t1 VALUES(9, 9); ERROR HY000: Lock wait timeout exceeded; try restarting transaction INSERT INTO t1 VALUES(13, 13); @@ -307,7 +324,9 @@ a b 18 12 20 12 22 12 +23 13 24 12 +25 13 COMMIT; ** Connection con0 ** COMMIT; diff --git a/mysql-test/suite/sys_vars/t/identity_func.test b/mysql-test/suite/sys_vars/t/identity_func.test index ff93607a2cd..6f7b6bac18e 100644 --- a/mysql-test/suite/sys_vars/t/identity_func.test +++ b/mysql-test/suite/sys_vars/t/identity_func.test @@ -1,3 +1,9 @@ +--source include/not_windows_embedded.inc +# remove this when +# Bug#53947 InnoDB: Assertion failure in thread 4224 in file +# .\sync\sync0sync.c line 324 +# is fixed + #################### mysql-test\t\identity_func.test ########################## # # # Variable Name: identity # diff --git a/mysql-test/suite/sys_vars/t/innodb_autoinc_lock_mode_func.test b/mysql-test/suite/sys_vars/t/innodb_autoinc_lock_mode_func.test index 89c1c80a6dc..082507efd07 100644 --- a/mysql-test/suite/sys_vars/t/innodb_autoinc_lock_mode_func.test +++ b/mysql-test/suite/sys_vars/t/innodb_autoinc_lock_mode_func.test @@ -1,3 +1,9 @@ +--source include/not_windows_embedded.inc +# remove this when +# Bug#53947 InnoDB: Assertion failure in thread 4224 in file +# .\sync\sync0sync.c line 324 +# is fixed + ################# mysql-test\t\innodb_autoinc_lock_mode_func.test ############ # # # Variable Name: innodb_autoinc_lock_mode # diff --git a/mysql-test/suite/sys_vars/t/innodb_buffer_pool_instances_basic.test b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_instances_basic.test new file mode 100644 index 00000000000..0960f1fb38b --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_buffer_pool_instances_basic.test @@ -0,0 +1,103 @@ + + +################## mysql-test\t\innodb_buffer_pool_instances_basic.test ####### +# # +# Variable Name: innodb_buffer_pool_instances # +# Scope: Global # +# Access Type: Static # +# Data Type: numeric # +# # +# # +# Creation Date: 2008-02-07 # +# Author : Sharique Abdullah # +# # +# # +# Description:Test Cases of Dynamic System Variable # +# innodb_buffer_pool_instances # +# that checks the behavior of this variable in the following ways # +# * Value Check # +# * Scope Check # +# # +# Reference: http://dev.mysql.com/doc/refman/5.1/en/ # +# server-system-variables.html # +# # +############################################################################### + +--source include/have_innodb.inc + +--echo '#---------------------BS_STVARS_035_01----------------------#' +#################################################################### +# Displaying default value # +#################################################################### +SELECT COUNT(@@GLOBAL.innodb_buffer_pool_instances); +--echo 1 Expected + + +--echo '#---------------------BS_STVARS_035_02----------------------#' +#################################################################### +# Check if Value can set # +#################################################################### + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@GLOBAL.innodb_buffer_pool_instances=1; +--echo Expected error 'Read only variable' + +SELECT COUNT(@@GLOBAL.innodb_buffer_pool_instances); +--echo 1 Expected + + + + +--echo '#---------------------BS_STVARS_035_03----------------------#' +################################################################# +# Check if the value in GLOBAL Table matches value in variable # +################################################################# + +SELECT @@GLOBAL.innodb_buffer_pool_instances = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_buffer_pool_instances'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.innodb_buffer_pool_instances); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_buffer_pool_instances'; +--echo 1 Expected + + + +--echo '#---------------------BS_STVARS_035_04----------------------#' +################################################################################ +# Check if accessing variable with and without GLOBAL point to same variable # +################################################################################ +SELECT @@innodb_buffer_pool_instances = @@GLOBAL.innodb_buffer_pool_instances; +--echo 1 Expected + + + +--echo '#---------------------BS_STVARS_035_05----------------------#' +################################################################################ +# Check if innodb_buffer_pool_instances can be accessed with and without @@ sign # +################################################################################ + +SELECT COUNT(@@innodb_buffer_pool_instances); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.innodb_buffer_pool_instances); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.innodb_buffer_pool_instances); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.innodb_buffer_pool_instances); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT innodb_buffer_pool_instances = @@SESSION.innodb_buffer_pool_instances; +--echo Expected error 'Readonly variable' + + diff --git a/mysql-test/suite/sys_vars/t/innodb_change_buffering_basic.test b/mysql-test/suite/sys_vars/t/innodb_change_buffering_basic.test index 65e36aa9cb3..abdfddb4c4b 100644 --- a/mysql-test/suite/sys_vars/t/innodb_change_buffering_basic.test +++ b/mysql-test/suite/sys_vars/t/innodb_change_buffering_basic.test @@ -11,8 +11,8 @@ SELECT @start_global_value; # # exists as global only # ---echo Valid values are 'inserts' and 'none' -select @@global.innodb_change_buffering in ('inserts', 'none'); +--echo Valid values are 'all', 'deletes', 'changes', 'inserts', 'none', 'purges' +select @@global.innodb_change_buffering in ('all', 'deletes', 'changes', 'inserts', 'none', 'purges'); select @@global.innodb_change_buffering; --error ER_INCORRECT_GLOBAL_LOCAL_VAR select @@session.innodb_change_buffering; diff --git a/mysql-test/suite/sys_vars/t/innodb_purge_batch_size_basic.test b/mysql-test/suite/sys_vars/t/innodb_purge_batch_size_basic.test new file mode 100644 index 00000000000..88271d26965 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_purge_batch_size_basic.test @@ -0,0 +1,142 @@ +################# mysql-test\t\innodb_purge_batch_size_basic.test ############# +# # +# Variable Name: innodb_purge_batch_size # +# Scope: GLOBAL # +# Access Type: Dynamic # +# Data Type: Numeric # +# Default Value: 20 # +# Range: 0-4294967295 # +# # +# # +# Creation Date: 2008-02-07 # +# Author: Rizwan # +# # +#Description:Test Cases of Dynamic System Variable innodb_purge_batch_size # +# that checks the behavior of this variable in the following ways # +# * Default Value # +# * Valid & Invalid values # +# * Scope & Access method # +# * Data Integrity # +# # +# Reference: http://dev.mysql.com/doc/refman/5.1/en/ # +# server-system-variables.html # +# # +############################################################################### + +--source include/have_innodb.inc +--source include/load_sysvars.inc + +######################################################################## +# START OF innodb_purge_batch_size TESTS # +######################################################################## + + +############################################################################ +# Saving initial value of innodb_purge_batch_size in a temporary variable # +############################################################################ + +SET @global_start_value = @@global.innodb_purge_batch_size; +SELECT @global_start_value; + +--echo '#--------------------FN_DYNVARS_046_01------------------------#' +######################################################################## +# Display the DEFAULT value of innodb_purge_batch_size # +######################################################################## + +SET @@global.innodb_purge_batch_size = 1; +SET @@global.innodb_purge_batch_size = DEFAULT; +SELECT @@global.innodb_purge_batch_size; + +--echo '#---------------------FN_DYNVARS_046_02-------------------------#' +############################################################################## +# Check if innodb_purge_batch_size can be accessed with and without @@ sign # +############################################################################## + +--Error ER_GLOBAL_VARIABLE +SET innodb_purge_batch_size = 1; +SELECT @@innodb_purge_batch_size; + +--Error ER_UNKNOWN_TABLE +SELECT local.innodb_purge_batch_size; + +SET global innodb_purge_batch_size = 1; +SELECT @@global.innodb_purge_batch_size; + +--echo '#--------------------FN_DYNVARS_046_03------------------------#' +########################################################################## +# change the value of innodb_purge_batch_size to a valid value # +########################################################################## + +SET @@global.innodb_purge_batch_size = 1; +SELECT @@global.innodb_purge_batch_size; + +SET @@global.innodb_purge_batch_size = 5000; +SELECT @@global.innodb_purge_batch_size; +SET @@global.innodb_purge_batch_size = 1000; +SELECT @@global.innodb_purge_batch_size; + +--echo '#--------------------FN_DYNVARS_046_04-------------------------#' +########################################################################### +# Change the value of innodb_purge_batch_size to invalid value # +########################################################################### + +SET @@global.innodb_purge_batch_size = 0; +SELECT @@global.innodb_purge_batch_size; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.innodb_purge_batch_size = "T"; +SELECT @@global.innodb_purge_batch_size; + +--Error ER_WRONG_TYPE_FOR_VAR +SET @@global.innodb_purge_batch_size = "Y"; +SELECT @@global.innodb_purge_batch_size; + +SET @@global.innodb_purge_batch_size = 5001; +SELECT @@global.innodb_purge_batch_size; + +--echo '#----------------------FN_DYNVARS_046_05------------------------#' +######################################################################### +# Check if the value in GLOBAL Table matches value in variable # +######################################################################### + +SELECT @@global.innodb_purge_batch_size = + VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES + WHERE VARIABLE_NAME='innodb_purge_batch_size'; +SELECT @@global.innodb_purge_batch_size; +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES + WHERE VARIABLE_NAME='innodb_purge_batch_size'; + +--echo '#---------------------FN_DYNVARS_046_06-------------------------#' +################################################################### +# Check if ON and OFF values can be used on variable # +################################################################### + +--ERROR ER_WRONG_TYPE_FOR_VAR +SET @@global.innodb_purge_batch_size = OFF; +SELECT @@global.innodb_purge_batch_size; + +--ERROR ER_WRONG_TYPE_FOR_VAR +SET @@global.innodb_purge_batch_size = ON; +SELECT @@global.innodb_purge_batch_size; + +--echo '#---------------------FN_DYNVARS_046_07----------------------#' +################################################################### +# Check if TRUE and FALSE values can be used on variable # +################################################################### + + +SET @@global.innodb_purge_batch_size = TRUE; +SELECT @@global.innodb_purge_batch_size; +SET @@global.innodb_purge_batch_size = FALSE; +SELECT @@global.innodb_purge_batch_size; + +############################## +# Restore initial value # +############################## + +SET @@global.innodb_purge_batch_size = @global_start_value; +SELECT @@global.innodb_purge_batch_size; + +############################################################### +# END OF innodb_purge_batch_size TESTS # +############################################################### diff --git a/mysql-test/suite/sys_vars/t/innodb_purge_threads_basic.test b/mysql-test/suite/sys_vars/t/innodb_purge_threads_basic.test new file mode 100644 index 00000000000..64d834c6344 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_purge_threads_basic.test @@ -0,0 +1,102 @@ + + +################## mysql-test\t\innodb_log_purge_threads_basic.test ########### +# # +# Variable Name: innodb_purge_threads # +# Scope: Global # +# Access Type: Static # +# Data Type: numeric # +# # +# # +# Creation Date: 2008-02-07 # +# Author : Sharique Abdullah # +# # +# # +# Description:Test Cases of Dynamic System Variable innodb_purge_threads # +# that checks the behavior of this variable in the following ways # +# * Value Check # +# * Scope Check # +# # +# Reference: http://dev.mysql.com/doc/refman/5.1/en/ # +# server-system-variables.html # +# # +############################################################################### + +--source include/have_innodb.inc + +--echo '#---------------------BS_STVARS_035_01----------------------#' +#################################################################### +# Displaying default value # +#################################################################### +SELECT COUNT(@@GLOBAL.innodb_purge_threads); +--echo 1 Expected + + +--echo '#---------------------BS_STVARS_035_02----------------------#' +#################################################################### +# Check if Value can set # +#################################################################### + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@GLOBAL.innodb_purge_threads=1; +--echo Expected error 'Read only variable' + +SELECT COUNT(@@GLOBAL.innodb_purge_threads); +--echo 1 Expected + + + + +--echo '#---------------------BS_STVARS_035_03----------------------#' +################################################################# +# Check if the value in GLOBAL Table matches value in variable # +################################################################# + +SELECT @@GLOBAL.innodb_purge_threads = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_purge_threads'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.innodb_purge_threads); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_purge_threads'; +--echo 1 Expected + + + +--echo '#---------------------BS_STVARS_035_04----------------------#' +################################################################################ +# Check if accessing variable with and without GLOBAL point to same variable # +################################################################################ +SELECT @@innodb_purge_threads = @@GLOBAL.innodb_purge_threads; +--echo 1 Expected + + + +--echo '#---------------------BS_STVARS_035_05----------------------#' +################################################################################ +# Check if innodb_purge_threads can be accessed with and without @@ sign # +################################################################################ + +SELECT COUNT(@@innodb_purge_threads); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.innodb_purge_threads); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.innodb_purge_threads); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.innodb_purge_threads); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT innodb_purge_threads = @@SESSION.innodb_purge_threads; +--echo Expected error 'Readonly variable' + + diff --git a/mysql-test/suite/sys_vars/t/innodb_use_native_aio_basic.test b/mysql-test/suite/sys_vars/t/innodb_use_native_aio_basic.test new file mode 100644 index 00000000000..37879530d75 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_use_native_aio_basic.test @@ -0,0 +1,102 @@ + + +################## mysql-test\t\innodb_use_native_aio_basic.test ############## +# # +# Variable Name: innodb_use_native_aio # +# Scope: Global # +# Access Type: Static # +# Data Type: numeric # +# # +# # +# Creation Date: 2008-02-07 # +# Author : Sharique Abdullah # +# # +# # +# Description:Test Cases of Dynamic System Variable innodb_use_native_aio # +# that checks the behavior of this variable in the following ways # +# * Value Check # +# * Scope Check # +# # +# Reference: http://dev.mysql.com/doc/refman/5.1/en/ # +# server-system-variables.html # +# # +############################################################################### + +--source include/have_innodb.inc + +--echo '#---------------------BS_STVARS_035_01----------------------#' +#################################################################### +# Displaying default value # +#################################################################### +SELECT COUNT(@@GLOBAL.innodb_use_native_aio); +--echo 1 Expected + + +--echo '#---------------------BS_STVARS_035_02----------------------#' +#################################################################### +# Check if Value can set # +#################################################################### + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +SET @@GLOBAL.innodb_use_native_aio=1; +--echo Expected error 'Read only variable' + +SELECT COUNT(@@GLOBAL.innodb_use_native_aio); +--echo 1 Expected + + + + +--echo '#---------------------BS_STVARS_035_03----------------------#' +################################################################# +# Check if the value in GLOBAL Table matches value in variable # +################################################################# + +SELECT IF(@@GLOBAL.innodb_use_native_aio, 'ON', 'OFF') = VARIABLE_VALUE +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_use_native_aio'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.innodb_use_native_aio); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES +WHERE VARIABLE_NAME='innodb_use_native_aio'; +--echo 1 Expected + + + +--echo '#---------------------BS_STVARS_035_04----------------------#' +################################################################################ +# Check if accessing variable with and without GLOBAL point to same variable # +################################################################################ +SELECT @@innodb_use_native_aio = @@GLOBAL.innodb_use_native_aio; +--echo 1 Expected + + + +--echo '#---------------------BS_STVARS_035_05----------------------#' +################################################################################ +# Check if innodb_log_file_size can be accessed with and without @@ sign # +################################################################################ + +SELECT COUNT(@@innodb_use_native_aio); +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.innodb_use_native_aio); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.innodb_use_native_aio); +--echo Expected error 'Variable is a GLOBAL variable' + +SELECT COUNT(@@GLOBAL.innodb_use_native_aio); +--echo 1 Expected + +--Error ER_BAD_FIELD_ERROR +SELECT innodb_use_native_aio = @@SESSION.innodb_use_native_aio; +--echo Expected error 'Readonly variable' + + diff --git a/mysql-test/suite/sys_vars/t/last_insert_id_func.test b/mysql-test/suite/sys_vars/t/last_insert_id_func.test index 2309c539bd9..bb3adbc1c64 100644 --- a/mysql-test/suite/sys_vars/t/last_insert_id_func.test +++ b/mysql-test/suite/sys_vars/t/last_insert_id_func.test @@ -1,3 +1,9 @@ +--source include/not_windows_embedded.inc +# remove this when +# Bug#53947 InnoDB: Assertion failure in thread 4224 in file +# .\sync\sync0sync.c line 324 +# is fixed + ################# mysql-test\t\last_insert_id_func.test ####################### # # # Variable Name: last_insert_id # diff --git a/mysql-test/suite/sys_vars/t/storage_engine_basic.test b/mysql-test/suite/sys_vars/t/storage_engine_basic.test index e62390cb384..7ec071e6414 100644 --- a/mysql-test/suite/sys_vars/t/storage_engine_basic.test +++ b/mysql-test/suite/sys_vars/t/storage_engine_basic.test @@ -1,3 +1,9 @@ +--source include/not_windows_embedded.inc +# remove this when +# Bug#53947 InnoDB: Assertion failure in thread 4224 in file +# .\sync\sync0sync.c line 324 +# is fixed + ############## mysql-test\t\storage_engine_basic.test ################## # # # # diff --git a/mysql-test/suite/sys_vars/t/tx_isolation_func.test b/mysql-test/suite/sys_vars/t/tx_isolation_func.test index 1fd2e323db8..3a78d46e527 100644 --- a/mysql-test/suite/sys_vars/t/tx_isolation_func.test +++ b/mysql-test/suite/sys_vars/t/tx_isolation_func.test @@ -1,3 +1,9 @@ +--source include/not_windows_embedded.inc +# remove this when +# Bug#53947 InnoDB: Assertion failure in thread 4224 in file +# .\sync\sync0sync.c line 324 +# is fixed + ############# mysql-test\t\tx_isolation_func.test ####################################### # # # Variable Name: tx_isolation # @@ -134,12 +140,9 @@ START TRANSACTION; SELECT * FROM t1; ---error ER_LOCK_WAIT_TIMEOUT INSERT INTO t1 VALUES(23, 23); ---error ER_LOCK_WAIT_TIMEOUT INSERT INTO t1 VALUES(25, 25); ---echo Bug: Only even rows are being locked, error 1205 should'nt have occured SELECT * FROM t1; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 54c662bccf2..d7f7a12cbf8 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -1117,3 +1117,14 @@ CREATE INDEX i2 ON t1 (a(20)); # cleanup DROP TABLE t1; + +# +# Bug #45052 ALTER TABLE ADD COLUMN crashes server with multiple foreign key columns +# The alter table fails if 2 or more new fields added and +# also added a key with these fields +# +CREATE TABLE t1 (id int); +INSERT INTO t1 VALUES (1), (2); +ALTER TABLE t1 ADD COLUMN (f1 INT), ADD COLUMN (f2 INT), ADD KEY f2k(f2); +DROP TABLE t1; + diff --git a/mysql-test/t/bug39022.test b/mysql-test/t/bug39022.test index 268b207e0e5..6056dbf0e7b 100644 --- a/mysql-test/t/bug39022.test +++ b/mysql-test/t/bug39022.test @@ -24,7 +24,7 @@ START TRANSACTION; connection thread2; --echo # in thread2 REPLACE INTO t2 VALUES (-17); -SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d); +SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d) LOCK IN SHARE MODE; connection thread1; --echo # in thread1 @@ -37,14 +37,14 @@ START TRANSACTION; REPLACE INTO t1(a,b) VALUES (65,-50); REPLACE INTO t2 VALUES (-91); send; -SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d); #waits +SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d) LOCK IN SHARE MODE; #waits connection thread1; --echo # in thread1 --echo # should not crash --error ER_LOCK_DEADLOCK -SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d); #crashes +SELECT d FROM t2,t1 WHERE d=(SELECT MAX(a) FROM t1 WHERE t1.a > t2.d) LOCK IN SHARE MODE; #crashes connection thread2; --echo # in thread2 diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index e0a6fde1381..383ba98ae6d 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -1668,3 +1668,66 @@ CREATE TABLE t1 LIKE t2; DROP TABLE t2; DROP TABLE t1; + +--echo # +--echo # Bug #48800 CREATE TABLE t...SELECT fails if t is a +--echo # temporary table +--echo # + +CREATE TEMPORARY TABLE t1 (a INT); +CREATE TABLE t1 (a INT); + +CREATE TEMPORARY TABLE t2 (a INT); +CREATE VIEW t2 AS SELECT 1; + +CREATE TABLE t3 (a INT); +CREATE TEMPORARY TABLE t3 SELECT 1; + +CREATE TEMPORARY TABLE t4 (a INT); +CREATE TABLE t4 AS SELECT 1; + +DROP TEMPORARY TABLE t1, t2, t3, t4; +DROP TABLE t1, t3, t4; +DROP VIEW t2; + +--echo # +--echo # Bug #49193 CREATE TABLE reacts differently depending +--echo # on whether data is selected or not +--echo # + +CREATE TEMPORARY TABLE t2 (ID INT); +INSERT INTO t2 VALUES (1),(2),(3); + +# Case 1 -- did not fail +CREATE TEMPORARY TABLE t1 (ID INT); +CREATE TABLE IF NOT EXISTS t1 (ID INT); +INSERT INTO t1 SELECT * FROM t2; +SELECT * FROM t1; +DROP TEMPORARY TABLE t1; +SELECT * FROM t1; + +DROP TABLE t1; + +# Case 2 -- The DROP TABLE t1 failed with +# Table 'test.t1' doesn't exist in the SELECT * +# as the (permanent) table was not created +CREATE TEMPORARY TABLE t1 (ID INT); +CREATE TABLE IF NOT EXISTS t1 SELECT * FROM t2; +SELECT * FROM t1; +DROP TEMPORARY TABLE t1; +SELECT * FROM t1; + +DROP TABLE t1; + +# Case 3 -- The CREATE TABLE failed with +# Table 't1' already exists +CREATE TEMPORARY TABLE t1 (ID INT); +CREATE TABLE t1 SELECT * FROM t2; +SELECT * FROM t1; +DROP TEMPORARY TABLE t1; +SELECT * FROM t1; + +DROP TABLE t1; + +DROP TEMPORARY TABLE t2; + diff --git a/mysql-test/t/ctype_utf16.test b/mysql-test/t/ctype_utf16.test index b997bde6e7c..e9c7e569250 100644 --- a/mysql-test/t/ctype_utf16.test +++ b/mysql-test/t/ctype_utf16.test @@ -723,6 +723,27 @@ DROP TABLE t1; SET max_sort_length=DEFAULT; SET NAMES latin1; +--echo # +--echo # Bug#52520 Difference in tinytext utf column metadata +--echo # +CREATE TABLE t1 ( + s1 TINYTEXT CHARACTER SET utf16, + s2 TEXT CHARACTER SET utf16, + s3 MEDIUMTEXT CHARACTER SET utf16, + s4 LONGTEXT CHARACTER SET utf16 +); +--enable_metadata +SET NAMES utf8, @@character_set_results=NULL; +SELECT *, HEX(s1) FROM t1; +SET NAMES latin1; +SELECT *, HEX(s1) FROM t1; +SET NAMES utf8; +SELECT *, HEX(s1) FROM t1; +--disable_metadata +CREATE TABLE t2 AS SELECT CONCAT(s1) FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t1, t2; + # ## TODO: add tests for all engines diff --git a/mysql-test/t/ctype_utf32.test b/mysql-test/t/ctype_utf32.test index f1e17532b88..96f1a341d38 100644 --- a/mysql-test/t/ctype_utf32.test +++ b/mysql-test/t/ctype_utf32.test @@ -780,5 +780,26 @@ SET max_sort_length=DEFAULT; SET NAMES latin1; --echo # +--echo # Bug#52520 Difference in tinytext utf column metadata +--echo # +CREATE TABLE t1 ( + s1 TINYTEXT CHARACTER SET utf32, + s2 TEXT CHARACTER SET utf32, + s3 MEDIUMTEXT CHARACTER SET utf32, + s4 LONGTEXT CHARACTER SET utf32 +); +--enable_metadata +SET NAMES utf8mb4, @@character_set_results=NULL; +SELECT *, HEX(s1) FROM t1; +SET NAMES latin1; +SELECT *, HEX(s1) FROM t1; +SET NAMES utf8mb4; +SELECT *, HEX(s1) FROM t1; +--disable_metadata +CREATE TABLE t2 AS SELECT CONCAT(s1) FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t1, t2; + +--echo # --echo # End of 5.5 tests --echo # diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 201e96b0b09..f2287488a4f 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -1480,3 +1480,31 @@ DROP TABLE t1; --echo End of 5.4 tests +--echo # +--echo # Start of 5.5 tests +--echo # + +--echo # +--echo # Bug#52520 Difference in tinytext utf column metadata +--echo # +CREATE TABLE t1 ( + s1 TINYTEXT CHARACTER SET utf8, + s2 TEXT CHARACTER SET utf8, + s3 MEDIUMTEXT CHARACTER SET utf8, + s4 LONGTEXT CHARACTER SET utf8 +); +--enable_metadata +SET NAMES utf8, @@character_set_results=NULL; +SELECT *, HEX(s1) FROM t1; +SET NAMES latin1; +SELECT *, HEX(s1) FROM t1; +SET NAMES utf8; +SELECT *, HEX(s1) FROM t1; +--disable_metadata +CREATE TABLE t2 AS SELECT CONCAT(s1) FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t1, t2; + +--echo # +--echo # End of 5.5 tests +--echo # diff --git a/mysql-test/t/ctype_utf8mb4.test b/mysql-test/t/ctype_utf8mb4.test index f396d36e5b0..8fcba92ff47 100644 --- a/mysql-test/t/ctype_utf8mb4.test +++ b/mysql-test/t/ctype_utf8mb4.test @@ -1790,6 +1790,27 @@ SELECT subject FROM t1 ORDER BY 1; DROP TABLE t1; --echo # +--echo # Bug#52520 Difference in tinytext utf column metadata +--echo # +CREATE TABLE t1 ( + s1 TINYTEXT CHARACTER SET utf8mb4, + s2 TEXT CHARACTER SET utf8mb4, + s3 MEDIUMTEXT CHARACTER SET utf8mb4, + s4 LONGTEXT CHARACTER SET utf8mb4 +); +--enable_metadata +SET NAMES utf8mb4, @@character_set_results=NULL; +SELECT *, HEX(s1) FROM t1; +SET NAMES latin1; +SELECT *, HEX(s1) FROM t1; +SET NAMES utf8mb4; +SELECT *, HEX(s1) FROM t1; +--disable_metadata +CREATE TABLE t2 AS SELECT CONCAT(s1) FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t1, t2; + +--echo # --echo # End of 5.5 tests --echo # diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 37682550487..7b14c332233 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -11,9 +11,8 @@ ############################################################################## kill : Bug#37780 2008-12-03 HHunger need some changes to be robust enough for pushbuild. query_cache_28249 : Bug#43861 2009-03-25 main.query_cache_28249 fails sporadically -innodb-autoinc : Bug#49267 2009-12-02 test fails on windows because of different case mode -innodb : Bug#49396 2009-12-03 test fails in embedded mode +sp_sync : Bug#48157 2010-02-06 5.5-m3 demands a differnt solution plugin_load : Bug#42144 2009-12-21 alik plugin_load fails partition_innodb_plugin : Bug#53307 2010-04-30 VasilDimov valgrind warnings -main.mysqlhotcopy_myisam : bug#54129 2010-06-04 Horst -main.mysqlhotcopy_archive: bug#54129 2010-06-04 Horst +mysqlhotcopy_myisam : bug#54129 2010-06-04 Horst +mysqlhotcopy_archive : bug#54129 2010-06-04 Horst diff --git a/mysql-test/t/errors.test b/mysql-test/t/errors.test index 5e53eaf0a52..f308c340645 100644 --- a/mysql-test/t/errors.test +++ b/mysql-test/t/errors.test @@ -140,3 +140,18 @@ SET sql_quote_show_create= _utf8 x'5452C39C45'; --error ER_WRONG_VALUE_FOR_VAR SET sql_quote_show_create=_latin1 x'5452DC45'; +--echo # +--echo # Bug#52430 Incorrect key in the error message for duplicate key error involving BINARY type +--echo # +CREATE TABLE t1(c1 BINARY(10), c2 BINARY(10), c3 BINARY(10), +PRIMARY KEY(c1,c2,c3)); +INSERT INTO t1 (c1,c2,c3) VALUES('abc','abc','abc'); +--error ER_DUP_ENTRY +INSERT INTO t1 (c1,c2,c3) VALUES('abc','abc','abc'); +DROP TABLE t1; + +CREATE TABLE t1 (f1 VARBINARY(19) PRIMARY KEY); +INSERT INTO t1 VALUES ('abc\0\0'); +--error ER_DUP_ENTRY +INSERT INTO t1 VALUES ('abc\0\0'); +DROP TABLE t1; diff --git a/mysql-test/t/innodb-master.opt b/mysql-test/t/innodb-master.opt deleted file mode 100644 index 72c88068345..00000000000 --- a/mysql-test/t/innodb-master.opt +++ /dev/null @@ -1 +0,0 @@ ---binlog_cache_size=32768 --loose_innodb_lock_wait_timeout=1 diff --git a/mysql-test/t/innodb-semi-consistent-master.opt b/mysql-test/t/innodb-semi-consistent-master.opt deleted file mode 100644 index cb48f1aaf60..00000000000 --- a/mysql-test/t/innodb-semi-consistent-master.opt +++ /dev/null @@ -1 +0,0 @@ ---loose-innodb_lock_wait_timeout=2 diff --git a/mysql-test/t/innodb_bug38231.test b/mysql-test/t/innodb_bug38231.test deleted file mode 100644 index b3fcd89f371..00000000000 --- a/mysql-test/t/innodb_bug38231.test +++ /dev/null @@ -1,75 +0,0 @@ -# -# Bug#38231 Innodb crash in lock_reset_all_on_table() on TRUNCATE + LOCK / UNLOCK -# http://bugs.mysql.com/38231 -# - --- source include/have_innodb.inc - -SET storage_engine=InnoDB; - -# we care only that the following SQL commands do not crash the server --- disable_query_log --- disable_result_log - -DROP TABLE IF EXISTS bug38231; -CREATE TABLE bug38231 (a INT); - --- connect (con1,localhost,root,,) --- connect (con2,localhost,root,,) - --- connection con1 -SET autocommit=0; -LOCK TABLE bug38231 WRITE; - --- connection con2 -SET autocommit=0; --- send -LOCK TABLE bug38231 WRITE; - --- connection default --- send -TRUNCATE TABLE bug38231; - --- connection con1 -# give time to TRUNCATE and others to be executed; without sleep, sometimes -# UNLOCK executes before TRUNCATE -# TODO: Replace with wait_condition once possible under embedded server. --- sleep 0.2 -# this crashes the server if the bug is present -UNLOCK TABLES; - -# clean up - --- connection con2 --- reap -UNLOCK TABLES; - --- connection default --- reap --- disconnect con1 --- disconnect con2 - -# test that TRUNCATE works with with row-level locks - --- enable_query_log --- enable_result_log - -INSERT INTO bug38231 VALUES (1), (10), (300); - --- connect (con4,localhost,root,,) - --- connection con4 -SET autocommit=0; -SELECT * FROM bug38231 FOR UPDATE; - --- connection default -TRUNCATE TABLE bug38231; - --- connection con4 -COMMIT; - --- connection default - --- disconnect con4 - -DROP TABLE bug38231; diff --git a/mysql-test/t/innodb_bug39438.test b/mysql-test/t/innodb_bug39438.test deleted file mode 100644 index 2a51e5fcbb8..00000000000 --- a/mysql-test/t/innodb_bug39438.test +++ /dev/null @@ -1,31 +0,0 @@ -# -# Bug#39438 Testcase for Bug#39436 crashes on 5.1 in fil_space_get_latch -# http://bugs.mysql.com/39438 -# -# This test must be run with innodb_file_per_table=1 because the crash -# only occurs if that option is turned on and DISCARD TABLESPACE only -# works with innodb_file_per_table. -# - --- source include/have_innodb.inc - ---disable_query_log -call mtr.add_suppression("InnoDB: Error: table 'test/bug39438'"); ---enable_query_log - -SET storage_engine=InnoDB; - -# we care only that the following SQL commands do not crash the server --- disable_query_log --- disable_result_log - -DROP TABLE IF EXISTS bug39438; - -CREATE TABLE bug39438 (id INT) ENGINE=INNODB; - -ALTER TABLE bug39438 DISCARD TABLESPACE; - -# this crashes the server if the bug is present -SHOW TABLE STATUS; - -DROP TABLE bug39438; diff --git a/mysql-test/t/innodb_bug42101-nonzero-master.opt b/mysql-test/t/innodb_bug42101-nonzero-master.opt deleted file mode 100644 index 455d66a06b8..00000000000 --- a/mysql-test/t/innodb_bug42101-nonzero-master.opt +++ /dev/null @@ -1 +0,0 @@ ---loose_innodb_commit_concurrency=1 diff --git a/mysql-test/t/innodb_bug44571.test b/mysql-test/t/innodb_bug44571.test deleted file mode 100644 index 685463ceff9..00000000000 --- a/mysql-test/t/innodb_bug44571.test +++ /dev/null @@ -1,17 +0,0 @@ -# -# Bug#44571 InnoDB Plugin crashes on ADD INDEX -# http://bugs.mysql.com/44571 -# --- source include/have_innodb.inc - -CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; -ALTER TABLE bug44571 CHANGE foo bar INT; --- error ER_KEY_COLUMN_DOES_NOT_EXITS -ALTER TABLE bug44571 ADD INDEX bug44571b (foo); -# The following will fail, because the CHANGE foo bar was -# not communicated to InnoDB. ---error ER_NOT_KEYFILE -ALTER TABLE bug44571 ADD INDEX bug44571b (bar); ---error ER_NOT_KEYFILE -CREATE INDEX bug44571b ON bug44571 (bar); -DROP TABLE bug44571; diff --git a/mysql-test/t/innodb_mysql_lock.test b/mysql-test/t/innodb_mysql_lock.test index 6469ef2d229..36d09b4c411 100644 --- a/mysql-test/t/innodb_mysql_lock.test +++ b/mysql-test/t/innodb_mysql_lock.test @@ -170,6 +170,45 @@ connection default; disconnect con2; DROP TABLE t1; + +--echo # +--echo # Bug#53798 OPTIMIZE TABLE breaks repeatable read +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (a INT) engine=innodb; +INSERT INTO t1 VALUES (1), (2), (3); + +--echo # Connection con1 +connect (con1, localhost, root); +START TRANSACTION WITH CONSISTENT SNAPSHOT; +SELECT * FROM t1; + +--echo # Connection default +connection default; +--echo # This should block +--echo # Sending: +--send OPTIMIZE TABLE t1 + +--echo # Connection con1 +connection con1; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for table' AND info='OPTIMIZE TABLE t1'; +--source include/wait_condition.inc +SELECT * FROM t1; +COMMIT; + +--echo # Connection default +connection default; +--echo # Reaping OPTIMIZE TABLE t1 +--reap +disconnect con1; +DROP TABLE t1; + + # Check that all connections opened by test cases in this file are really # gone so execution of other tests won't be affected by their presence. --source include/wait_until_count_sessions.inc diff --git a/mysql-test/t/innodb_mysql_lock2.test b/mysql-test/t/innodb_mysql_lock2.test new file mode 100644 index 00000000000..5111d56225a --- /dev/null +++ b/mysql-test/t/innodb_mysql_lock2.test @@ -0,0 +1,765 @@ +# This test covers behavior for InnoDB tables. +--source include/have_innodb.inc +# This test requires statement/mixed mode binary logging. +# Row-based mode puts weaker serializability requirements +# so weaker locks are acquired for it. +--source include/have_binlog_format_mixed_or_statement.inc +# Save the initial number of concurrent sessions. +--source include/count_sessions.inc + +--echo # +--echo # Test how do we handle locking in various cases when +--echo # we read data from InnoDB tables. +--echo # +--echo # In fact by performing this test we check two things: +--echo # 1) That SQL-layer correctly determine type of thr_lock.c +--echo # lock to be acquired/passed to InnoDB engine. +--echo # 2) That InnoDB engine correctly interprets this lock +--echo # type and takes necessary row locks or does not +--echo # take them if they are not necessary. +--echo # + +--echo # This test makes sense only in REPEATABLE-READ mode as +--echo # in SERIALIZABLE mode all statements that read data take +--echo # shared lock on them to enforce its semantics. +select @@session.tx_isolation; + +--echo # Prepare playground by creating tables, views, +--echo # routines and triggers used in tests. +connect (con1, localhost, root,,); +connection default; +--disable_warnings +drop table if exists t0, t1, t2, t3, t4, t5; +drop view if exists v1, v2; +drop procedure if exists p1; +drop procedure if exists p2; +drop function if exists f1; +drop function if exists f2; +drop function if exists f3; +drop function if exists f4; +drop function if exists f5; +drop function if exists f6; +drop function if exists f7; +drop function if exists f8; +drop function if exists f9; +drop function if exists f10; +drop function if exists f11; +drop function if exists f12; +drop function if exists f13; +drop function if exists f14; +drop function if exists f15; +--enable_warnings +create table t1 (i int primary key) engine=innodb; +insert into t1 values (1), (2), (3), (4), (5); +create table t2 (j int primary key) engine=innodb; +insert into t2 values (1), (2), (3), (4), (5); +create table t3 (k int primary key) engine=innodb; +insert into t3 values (1), (2), (3); +create table t4 (l int primary key) engine=innodb; +insert into t4 values (1); +create table t5 (l int primary key) engine=innodb; +insert into t5 values (1); +create view v1 as select i from t1; +create view v2 as select j from t2 where j in (select i from t1); +create procedure p1(k int) insert into t2 values (k); +delimiter |; +create function f1() returns int +begin + declare j int; + select i from t1 where i = 1 into j; + return j; +end| +create function f2() returns int +begin + declare k int; + select i from t1 where i = 1 into k; + insert into t2 values (k + 5); + return 0; +end| +create function f3() returns int +begin + return (select i from t1 where i = 3); +end| +create function f4() returns int +begin + if (select i from t1 where i = 3) then + return 1; + else + return 0; + end if; +end| +create function f5() returns int +begin + insert into t2 values ((select i from t1 where i = 1) + 5); + return 0; +end| +create function f6() returns int +begin + declare k int; + select i from v1 where i = 1 into k; + return k; +end| +create function f7() returns int +begin + declare k int; + select j from v2 where j = 1 into k; + return k; +end| +create function f8() returns int +begin + declare k int; + select i from v1 where i = 1 into k; + insert into t2 values (k+5); + return k; +end| +create function f9() returns int +begin + update v2 set j=j+10 where j=1; + return 1; +end| +create function f10() returns int +begin + return f1(); +end| +create function f11() returns int +begin + declare k int; + set k= f1(); + insert into t2 values (k+5); + return k; +end| +create function f12(p int) returns int +begin + insert into t2 values (p); + return p; +end| +create function f13(p int) returns int +begin + return p; +end| +create procedure p2(inout p int) +begin + select i from t1 where i = 1 into p; +end| +create function f14() returns int +begin + declare k int; + call p2(k); + insert into t2 values (k+5); + return k; +end| +create function f15() returns int +begin + declare k int; + call p2(k); + return k; +end| +create trigger t4_bi before insert on t4 for each row +begin + declare k int; + select i from t1 where i=1 into k; + set new.l= k+1; +end| +create trigger t4_bu before update on t4 for each row +begin + if (select i from t1 where i=1) then + set new.l= 2; + end if; +end| +create trigger t4_bd before delete on t4 for each row +begin + if !(select i from v1 where i=1) then + signal sqlstate '45000'; + end if; +end| +create trigger t5_bi before insert on t5 for each row +begin + set new.l= f1()+1; +end| +create trigger t5_bu before update on t5 for each row +begin + declare j int; + call p2(j); + set new.l= j + 1; +end| +delimiter ;| + +--echo # +--echo # Set common variables to be used by scripts called below. +--echo # +let $con_aux= con1; +let $table= t1; + + +--echo # +--echo # 1. Statements that read tables and do not use subqueries. +--echo # + +--echo # +--echo # 1.1 Simple SELECT statement. +--echo # +--echo # No locks are necessary as this statement won't be written +--echo # to the binary log and thanks to how MyISAM works SELECT +--echo # will see version of the table prior to concurrent insert. +let $statement= select * from t1; +--source include/check_no_row_lock.inc + +--echo # +--echo # 1.2 Multi-UPDATE statement. +--echo # +--echo # Has to take shared locks on rows in the table being read as this +--echo # statement will be written to the binary log and therefore should +--echo # be serialized with concurrent statements. +let $statement= update t2, t1 set j= j - 1 where i = j; +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 1.3 Multi-DELETE statement. +--echo # +--echo # The above is true for this statement as well. +let $statement= delete t2 from t1, t2 where i = j; +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 1.4 DESCRIBE statement. +--echo # +--echo # This statement does not really read data from the +--echo # target table and thus does not take any lock on it. +--echo # We check this for completeness of coverage. +let $statement= describe t1; +--source include/check_no_row_lock.inc + +--echo # +--echo # 1.5 SHOW statements. +--echo # +--echo # The above is true for SHOW statements as well. +let $statement= show create table t1; +--source include/check_no_row_lock.inc +let $statement= show keys from t1; +--source include/check_no_row_lock.inc + + +--echo # +--echo # 2. Statements which read tables through subqueries. +--echo # + +--echo # +--echo # 2.1 CALL with a subquery. +--echo # +--echo # A strong lock is not necessary as this statement is not +--echo # written to the binary log as a whole (it is written +--echo # statement-by-statement) and thanks to MVCC we can always get +--echo # versions of rows prior to the update that has locked them. +--echo # But in practice InnoDB does locking reads for all statements +--echo # other than SELECT (unless it is a READ-COMITTED mode or +--echo # innodb_locks_unsafe_for_binlog is ON). +let $statement= call p1((select i + 5 from t1 where i = 1)); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 2.2 CREATE TABLE with a subquery. +--echo # +--echo # Has to take shared locks on rows in the table being read as +--echo # this statement is written to the binary log and therefore +--echo # should be serialized with concurrent statements. +let $statement= create table t0 engine=innodb select * from t1; +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc +drop table t0; +let $statement= create table t0 engine=innodb select j from t2 where j in (select i from t1); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc +drop table t0; + +--echo # +--echo # 2.3 DELETE with a subquery. +--echo # +--echo # The above is true for this statement as well. +let $statement= delete from t2 where j in (select i from t1); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 2.4 MULTI-DELETE with a subquery. +--echo # +--echo # Same is true for this statement as well. +let $statement= delete t2 from t3, t2 where k = j and j in (select i from t1); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 2.5 DO with a subquery. +--echo # +--echo # In theory should not take row locks as it is not logged. +--echo # In practice InnoDB takes shared row locks. +let $statement= do (select i from t1 where i = 1); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 2.6 INSERT with a subquery. +--echo # +--echo # Has to take shared locks on rows in the table being read as +--echo # this statement is written to the binary log and therefore +--echo # should be serialized with concurrent statements. +let $statement= insert into t2 select i+5 from t1; +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc +let $statement= insert into t2 values ((select i+5 from t1 where i = 4)); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 2.7 LOAD DATA with a subquery. +--echo # +--echo # The above is true for this statement as well. +let $statement= load data infile '../../std_data/rpl_loaddata.dat' into table t2 (@a, @b) set j= @b + (select i from t1 where i = 1); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 2.8 REPLACE with a subquery. +--echo # +--echo # Same is true for this statement as well. +let $statement= replace into t2 select i+5 from t1; +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc +let $statement= replace into t2 values ((select i+5 from t1 where i = 4)); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 2.9 SELECT with a subquery. +--echo # +--echo # Locks are not necessary as this statement is not written +--echo # to the binary log and thanks to MVCC we can always get +--echo # versions of rows prior to the update that has locked them. +--echo # +--echo # Also serves as a test case for bug #46947 "Embedded SELECT +--echo # without FOR UPDATE is causing a lock". +let $statement= select * from t2 where j in (select i from t1); +--source include/check_no_row_lock.inc + +--echo # +--echo # 2.10 SET with a subquery. +--echo # +--echo # In theory should not require locking as it is not written +--echo # to the binary log. In practice InnoDB acquires shared row +--echo # locks. +let $statement= set @a:= (select i from t1 where i = 1); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 2.11 SHOW with a subquery. +--echo # +--echo # Similarly to the previous case, in theory should not require locking +--echo # as it is not written to the binary log. In practice InnoDB +--echo # acquires shared row locks. +let $statement= show tables from test where Tables_in_test = 't2' and (select i from t1 where i = 1); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc +let $statement= show columns from t2 where (select i from t1 where i = 1); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 2.12 UPDATE with a subquery. +--echo # +--echo # Has to take shared locks on rows in the table being read as +--echo # this statement is written to the binary log and therefore +--echo # should be serialized with concurrent statements. +let $statement= update t2 set j= j-10 where j in (select i from t1); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 2.13 MULTI-UPDATE with a subquery. +--echo # +--echo # Same is true for this statement as well. +let $statement= update t2, t3 set j= j -10 where j=k and j in (select i from t1); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + + +--echo # +--echo # 3. Statements which read tables through a view. +--echo # + +--echo # +--echo # 3.1 SELECT statement which uses some table through a view. +--echo # +--echo # Since this statement is not written to the binary log +--echo # and old version of rows are accessible thanks to MVCC, +--echo # no locking is necessary. +let $statement= select * from v1; +--source include/check_no_row_lock.inc +let $statement= select * from v2; +--source include/check_no_row_lock.inc +let $statement= select * from t2 where j in (select i from v1); +--source include/check_no_row_lock.inc +let $statement= select * from t3 where k in (select j from v2); +--source include/check_no_row_lock.inc + +--echo # +--echo # 3.2 Statements which modify a table and use views. +--echo # +--echo # Since such statements are going to be written to the binary +--echo # log they need to be serialized against concurrent statements +--echo # and therefore should take shared row locks on data read. +let $statement= update t2 set j= j-10 where j in (select i from v1); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc +let $statement= update t3 set k= k-10 where k in (select j from v2); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc +let $statement= update t2, v1 set j= j-10 where j = i; +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc +let $statement= update v2 set j= j-10 where j = 3; +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + + +--echo # +--echo # 4. Statements which read tables through stored functions. +--echo # + +--echo # +--echo # 4.1 SELECT/SET with a stored function which does not +--echo # modify data and uses SELECT in its turn. +--echo # +--echo # In theory there is no need to take row locks on the table +--echo # being selected from in SF as the call to such function +--echo # won't get into the binary log. In practice, however, we +--echo # discover that fact too late in the process to be able to +--echo # affect the decision what locks should be taken. +--echo # Hence, strong locks are taken in this case. +let $statement= select f1(); +let $wait_statement= select i from t1 where i = 1 into j; +--source include/check_shared_row_lock.inc +let $statement= set @a:= f1(); +let $wait_statement= select i from t1 where i = 1 into j; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 4.2 INSERT (or other statement which modifies data) with +--echo # a stored function which does not modify data and uses +--echo # SELECT. +--echo # +--echo # Since such statement is written to the binary log it should +--echo # be serialized with concurrent statements affecting the data +--echo # it uses. Therefore it should take row locks on the data +--echo # it reads. +let $statement= insert into t2 values (f1() + 5); +let $wait_statement= select i from t1 where i = 1 into j; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 4.3 SELECT/SET with a stored function which +--echo # reads and modifies data. +--echo # +--echo # Since a call to such function is written to the binary log, +--echo # it should be serialized with concurrent statements affecting +--echo # the data it uses. Hence, row locks on the data read +--echo # should be taken. +let $statement= select f2(); +let $wait_statement= select i from t1 where i = 1 into k; +--source include/check_shared_row_lock.inc +let $statement= set @a:= f2(); +let $wait_statement= select i from t1 where i = 1 into k; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 4.4. SELECT/SET with a stored function which does not +--echo # modify data and reads a table through subselect +--echo # in a control construct. +--echo # +--echo # Again, in theory a call to this function won't get to the +--echo # binary log and thus no locking is needed. But in practice +--echo # we don't detect this fact early enough (get_lock_type_for_table()) +--echo # to avoid taking row locks. +let $statement= select f3(); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc +let $statement= set @a:= f3(); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc +let $statement= select f4(); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc +let $statement= set @a:= f4(); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 4.5. INSERT (or other statement which modifies data) with +--echo # a stored function which does not modify data and reads +--echo # the table through a subselect in one of its control +--echo # constructs. +--echo # +--echo # Since such statement is written to the binary log it should +--echo # be serialized with concurrent statements affecting data it +--echo # uses. Therefore it should take row locks on the data +--echo # it reads. +let $statement= insert into t2 values (f3() + 5); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc +let $statement= insert into t2 values (f4() + 6); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 4.6 SELECT/SET which uses a stored function with +--echo # DML which reads a table via a subquery. +--echo # +--echo # Since call to such function is written to the binary log +--echo # it should be serialized with concurrent statements. +--echo # Hence reads should take row locks. +let $statement= select f5(); +let $wait_statement= insert into t2 values ((select i from t1 where i = 1) + 5); +--source include/check_shared_row_lock.inc +let $statement= set @a:= f5(); +let $wait_statement= insert into t2 values ((select i from t1 where i = 1) + 5); +--source include/check_shared_row_lock.inc + +--echo # +--echo # 4.7 SELECT/SET which uses a stored function which +--echo # doesn't modify data and reads tables through +--echo # a view. +--echo # +--echo # Once again, in theory, calls to such functions won't +--echo # get into the binary log and thus don't need row +--echo # locks. But in practice this fact is discovered +--echo # too late to have any effect. +let $statement= select f6(); +let $wait_statement= select i from v1 where i = 1 into k; +--source include/check_shared_row_lock.inc +let $statement= set @a:= f6(); +let $wait_statement= select i from v1 where i = 1 into k; +--source include/check_shared_row_lock.inc +let $statement= select f7(); +let $wait_statement= select j from v2 where j = 1 into k; +--source include/check_shared_row_lock.inc +let $statement= set @a:= f7(); +let $wait_statement= select j from v2 where j = 1 into k; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 4.8 INSERT which uses stored function which +--echo # doesn't modify data and reads a table +--echo # through a view. +--echo # +--echo # Since such statement is written to the binary log and +--echo # should be serialized with concurrent statements affecting +--echo # the data it uses. Therefore it should take row locks on +--echo # the rows it reads. +let $statement= insert into t3 values (f6() + 5); +let $wait_statement= select i from v1 where i = 1 into k; +--source include/check_shared_row_lock.inc +let $statement= insert into t3 values (f7() + 5); +let $wait_statement= select j from v2 where j = 1 into k; +--source include/check_shared_row_lock.inc + + +--echo # +--echo # 4.9 SELECT which uses a stored function which +--echo # modifies data and reads tables through a view. +--echo # +--echo # Since a call to such function is written to the binary log +--echo # it should be serialized with concurrent statements. +--echo # Hence, reads should take row locks. +let $statement= select f8(); +let $wait_statement= select i from v1 where i = 1 into k; +--source include/check_shared_row_lock.inc +let $statement= select f9(); +let $wait_statement= update v2 set j=j+10 where j=1; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 4.10 SELECT which uses stored function which doesn't modify +--echo # data and reads a table indirectly, by calling another +--echo # function. +--echo # +--echo # In theory, calls to such functions won't get into the binary +--echo # log and thus don't need to acquire row locks. But in practice +--echo # this fact is discovered too late to have any effect. +let $statement= select f10(); +let $wait_statement= select i from t1 where i = 1 into j; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 4.11 INSERT which uses a stored function which doesn't modify +--echo # data and reads a table indirectly, by calling another +--echo # function. +--echo # +--echo # Since such statement is written to the binary log, it should +--echo # be serialized with concurrent statements affecting the data it +--echo # uses. Therefore it should take row locks on data it reads. +let $statement= insert into t2 values (f10() + 5); +let $wait_statement= select i from t1 where i = 1 into j; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 4.12 SELECT which uses a stored function which modifies +--echo # data and reads a table indirectly, by calling another +--echo # function. +--echo # +--echo # Since a call to such function is written to the binary log +--echo # it should be serialized from concurrent statements. +--echo # Hence, reads should take row locks. +let $statement= select f11(); +let $wait_statement= select i from t1 where i = 1 into j; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 4.13 SELECT that reads a table through a subquery passed +--echo # as a parameter to a stored function which modifies +--echo # data. +--echo # +--echo # Even though a call to this function is written to the +--echo # binary log, values of its parameters are written as literals. +--echo # So there is no need to acquire row locks on rows used in +--echo # the subquery. +let $statement= select f12((select i+10 from t1 where i=1)); +--source include/check_no_row_lock.inc + +--echo # +--echo # 4.14 INSERT that reads a table via a subquery passed +--echo # as a parameter to a stored function which doesn't +--echo # modify data. +--echo # +--echo # Since this statement is written to the binary log it should +--echo # be serialized with concurrent statements affecting the data it +--echo # uses. Therefore it should take row locks on the data it reads. +let $statement= insert into t2 values (f13((select i+10 from t1 where i=1))); +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + + +--echo # +--echo # 5. Statements that read tables through stored procedures. +--echo # + +--echo # +--echo # 5.1 CALL statement which reads a table via SELECT. +--echo # +--echo # Since neither this statement nor its components are +--echo # written to the binary log, there is no need to take +--echo # row locks on the data it reads. +let $statement= call p2(@a); +--source include/check_no_row_lock.inc + +--echo # +--echo # 5.2 Function that modifes data and uses CALL, +--echo # which reads a table through SELECT. +--echo # +--echo # Since a call to such function is written to the binary +--echo # log, it should be serialized with concurrent statements. +--echo # Hence, in this case reads should take row locks on data. +let $statement= select f14(); +let $wait_statement= select i from t1 where i = 1 into p; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 5.3 SELECT that calls a function that doesn't modify data and +--echo # uses a CALL statement that reads a table via SELECT. +--echo # +--echo # In theory, calls to such functions won't get into the binary +--echo # log and thus don't need to acquire row locks. But in practice +--echo # this fact is discovered too late to have any effect. +let $statement= select f15(); +let $wait_statement= select i from t1 where i = 1 into p; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 5.4 INSERT which calls function which doesn't modify data and +--echo # uses CALL statement which reads table through SELECT. +--echo # +--echo # Since such statement is written to the binary log it should +--echo # be serialized with concurrent statements affecting data it +--echo # uses. Therefore it should take row locks on data it reads. +let $statement= insert into t2 values (f15()+5); +let $wait_statement= select i from t1 where i = 1 into p; +--source include/check_shared_row_lock.inc + + +--echo # +--echo # 6. Statements that use triggers. +--echo # + +--echo # +--echo # 6.1 Statement invoking a trigger that reads table via SELECT. +--echo # +--echo # Since this statement is written to the binary log it should +--echo # be serialized with concurrent statements affecting the data +--echo # it uses. Therefore, it should take row locks on the data +--echo # it reads. +let $statement= insert into t4 values (2); +let $wait_statement= select i from t1 where i=1 into k; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 6.2 Statement invoking a trigger that reads table through +--echo # a subquery in a control construct. +--echo # +--echo # The above is true for this statement as well. +let $statement= update t4 set l= 2 where l = 1; +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 6.3 Statement invoking a trigger that reads a table through +--echo # a view. +--echo # +--echo # And for this statement. +let $statement= delete from t4 where l = 1; +let $wait_statement= $statement; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 6.4 Statement invoking a trigger that reads a table through +--echo # a stored function. +--echo # +--echo # And for this statement. +let $statement= insert into t5 values (2); +let $wait_statement= select i from t1 where i = 1 into j; +--source include/check_shared_row_lock.inc + +--echo # +--echo # 6.5 Statement invoking a trigger that reads a table through +--echo # stored procedure. +--echo # +--echo # And for this statement. +let $statement= update t5 set l= 2 where l = 1; +let $wait_statement= select i from t1 where i = 1 into p; +--source include/check_shared_row_lock.inc + +--echo # Clean-up. +drop function f1; +drop function f2; +drop function f3; +drop function f4; +drop function f5; +drop function f6; +drop function f7; +drop function f8; +drop function f9; +drop function f10; +drop function f11; +drop function f12; +drop function f13; +drop function f14; +drop function f15; +drop view v1, v2; +drop procedure p1; +drop procedure p2; +drop table t1, t2, t3, t4, t5; +disconnect con1; + +# Check that all connections opened by test cases in this file are really +# gone so execution of other tests won't be affected by their presence. +--source include/wait_until_count_sessions.inc diff --git a/mysql-test/t/lock_sync.test b/mysql-test/t/lock_sync.test index 3cbe3342acc..921ce991652 100644 --- a/mysql-test/t/lock_sync.test +++ b/mysql-test/t/lock_sync.test @@ -4,10 +4,10 @@ --source include/have_debug_sync.inc # We need InnoDB to be able use TL_WRITE_ALLOW_WRITE type of locks in our tests. --source include/have_innodb.inc -# The test for Bug#50821 requires binary logging turned on. -# With binary logging on, sub-queries in DML statements acquire -# TL_READ_NO_INSERT which was needed to reproduce this deadlock bug. ---source include/have_log_bin.inc +# This test requires statement/mixed mode binary logging. +# Row-based mode puts weaker serializability requirements +# so weaker locks are acquired for it. +--source include/have_binlog_format_mixed_or_statement.inc # Until bug#41971 'Thread state on embedded server is always "Writing to net"' # is fixed this test can't be run on embedded version of server. --source include/not_embedded.inc @@ -17,6 +17,818 @@ --echo # +--echo # Test how we handle locking in various cases when +--echo # we read data from MyISAM tables. +--echo # +--echo # In this test we mostly check that the SQL-layer correctly +--echo # determines the type of thr_lock.c lock for a table being +--echo # read. +--echo # I.e. that it disallows concurrent inserts when the statement +--echo # is going to be written to the binary log and therefore +--echo # should be serialized, and allows concurrent inserts when +--echo # such serialization is not necessary (e.g. when +--echo # the statement is not written to binary log). +--echo # + +--echo # Force concurrent inserts to be performed even if the table +--echo # has gaps. This allows to simplify clean up in scripts +--echo # used below (instead of backing up table being inserted +--echo # into and then restoring it from backup at the end of the +--echo # script we can simply delete rows which were inserted). +set @old_concurrent_insert= @@global.concurrent_insert; +set @@global.concurrent_insert= 2; +select @@global.concurrent_insert; + +--echo # Prepare playground by creating tables, views, +--echo # routines and triggers used in tests. +connect (con1, localhost, root,,); +connect (con2, localhost, root,,); +connection default; +--disable_warnings +drop table if exists t0, t1, t2, t3, t4, t5; +drop view if exists v1, v2; +drop procedure if exists p1; +drop procedure if exists p2; +drop function if exists f1; +drop function if exists f2; +drop function if exists f3; +drop function if exists f4; +drop function if exists f5; +drop function if exists f6; +drop function if exists f7; +drop function if exists f8; +drop function if exists f9; +drop function if exists f10; +drop function if exists f11; +drop function if exists f12; +drop function if exists f13; +drop function if exists f14; +drop function if exists f15; +--enable_warnings +create table t1 (i int primary key); +insert into t1 values (1), (2), (3), (4), (5); +create table t2 (j int primary key); +insert into t2 values (1), (2), (3), (4), (5); +create table t3 (k int primary key); +insert into t3 values (1), (2), (3); +create table t4 (l int primary key); +insert into t4 values (1); +create table t5 (l int primary key); +insert into t5 values (1); +create view v1 as select i from t1; +create view v2 as select j from t2 where j in (select i from t1); +create procedure p1(k int) insert into t2 values (k); +delimiter |; +create function f1() returns int +begin + declare j int; + select i from t1 where i = 1 into j; + return j; +end| +create function f2() returns int +begin + declare k int; + select i from t1 where i = 1 into k; + insert into t2 values (k + 5); + return 0; +end| +create function f3() returns int +begin + return (select i from t1 where i = 3); +end| +create function f4() returns int +begin + if (select i from t1 where i = 3) then + return 1; + else + return 0; + end if; +end| +create function f5() returns int +begin + insert into t2 values ((select i from t1 where i = 1) + 5); + return 0; +end| +create function f6() returns int +begin + declare k int; + select i from v1 where i = 1 into k; + return k; +end| +create function f7() returns int +begin + declare k int; + select j from v2 where j = 1 into k; + return k; +end| +create function f8() returns int +begin + declare k int; + select i from v1 where i = 1 into k; + insert into t2 values (k+5); + return k; +end| +create function f9() returns int +begin + update v2 set j=j+10 where j=1; + return 1; +end| +create function f10() returns int +begin + return f1(); +end| +create function f11() returns int +begin + declare k int; + set k= f1(); + insert into t2 values (k+5); + return k; +end| +create function f12(p int) returns int +begin + insert into t2 values (p); + return p; +end| +create function f13(p int) returns int +begin + return p; +end| +create procedure p2(inout p int) +begin + select i from t1 where i = 1 into p; +end| +create function f14() returns int +begin + declare k int; + call p2(k); + insert into t2 values (k+5); + return k; +end| +create function f15() returns int +begin + declare k int; + call p2(k); + return k; +end| +create trigger t4_bi before insert on t4 for each row +begin + declare k int; + select i from t1 where i=1 into k; + set new.l= k+1; +end| +create trigger t4_bu before update on t4 for each row +begin + if (select i from t1 where i=1) then + set new.l= 2; + end if; +end| +create trigger t4_bd before delete on t4 for each row +begin + if !(select i from v1 where i=1) then + signal sqlstate '45000'; + end if; +end| +create trigger t5_bi before insert on t5 for each row +begin + set new.l= f1()+1; +end| +create trigger t5_bu before update on t5 for each row +begin + declare j int; + call p2(j); + set new.l= j + 1; +end| +delimiter ;| + +--echo # +--echo # Set common variables to be used by the scripts +--echo # called below. +--echo # +let $con_aux1= con1; +let $con_aux2= con2; +let $table= t1; + +--echo # Switch to connection 'con1'. +connection con1; +--echo # Cache all functions used in the tests below so statements +--echo # calling them won't need to open and lock mysql.proc table +--echo # and we can assume that each statement locks its tables +--echo # once during its execution. +--disable_result_log +show create procedure p1; +show create procedure p2; +show create function f1; +show create function f2; +show create function f3; +show create function f4; +show create function f5; +show create function f6; +show create function f7; +show create function f8; +show create function f9; +show create function f10; +show create function f11; +show create function f12; +show create function f13; +show create function f14; +show create function f15; +--enable_result_log +--echo # Switch back to connection 'default'. +connection default; + +--echo # +--echo # 1. Statements that read tables and do not use subqueries. +--echo # + +--echo # +--echo # 1.1 Simple SELECT statement. +--echo # +--echo # No locks are necessary as this statement won't be written +--echo # to the binary log and thanks to how MyISAM works SELECT +--echo # will see version of the table prior to concurrent insert. +let $statement= select * from t1; +let $restore_table= ; +--source include/check_concurrent_insert.inc + +--echo # +--echo # 1.2 Multi-UPDATE statement. +--echo # +--echo # Has to take shared locks on rows in the table being read as this +--echo # statement will be written to the binary log and therefore should +--echo # be serialized with concurrent statements. +let $statement= update t2, t1 set j= j - 1 where i = j; +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 1.3 Multi-DELETE statement. +--echo # +--echo # The above is true for this statement as well. +let $statement= delete t2 from t1, t2 where i = j; +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 1.4 DESCRIBE statement. +--echo # +--echo # This statement does not really read data from the +--echo # target table and thus does not take any lock on it. +--echo # We check this for completeness of coverage. +lock table t1 write; +--echo # Switching to connection 'con1'. +connection con1; +--echo # This statement should not be blocked. +--disable_result_log +describe t1; +--enable_result_log +--echo # Switching to connection 'default'. +connection default; +unlock tables; + +--echo # +--echo # 1.5 SHOW statements. +--echo # +--echo # The above is true for SHOW statements as well. +lock table t1 write; +--echo # Switching to connection 'con1'. +connection con1; +--echo # These statements should not be blocked. +# The below test for SHOW CREATE TABLE is disabled until bug 52593 +# "SHOW CREATE TABLE is blocked if table is locked for write by another +# connection" is fixed. +--disable_parsing +show create table t1; +--enable_parsing +--disable_result_log +show keys from t1; +--enable_result_log +--echo # Switching to connection 'default'. +connection default; +unlock tables; + + +--echo # +--echo # 2. Statements which read tables through subqueries. +--echo # + +--echo # +--echo # 2.1 CALL with a subquery. +--echo # +--echo # A strong lock is not necessary as this statement is not +--echo # written to the binary log as a whole (it is written +--echo # statement-by-statement). +let $statement= call p1((select i + 5 from t1 where i = 1)); +let $restore_table= t2; +--source include/check_concurrent_insert.inc + +--echo # +--echo # 2.2 CREATE TABLE with a subquery. +--echo # +--echo # Has to take a strong lock on the table being read as +--echo # this statement is written to the binary log and therefore +--echo # should be serialized with concurrent statements. +let $statement= create table t0 select * from t1; +let $restore_table= ; +--source include/check_no_concurrent_insert.inc +drop table t0; +let $statement= create table t0 select j from t2 where j in (select i from t1); +let $restore_table= ; +--source include/check_no_concurrent_insert.inc +drop table t0; + +--echo # +--echo # 2.3 DELETE with a subquery. +--echo # +--echo # The above is true for this statement as well. +let $statement= delete from t2 where j in (select i from t1); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 2.4 MULTI-DELETE with a subquery. +--echo # +--echo # Same is true for this statement as well. +let $statement= delete t2 from t3, t2 where k = j and j in (select i from t1); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + + +--echo # +--echo # 2.5 DO with a subquery. +--echo # +--echo # A strong lock is not necessary as it is not logged. +let $statement= do (select i from t1 where i = 1); +let $restore_table= ; +--source include/check_concurrent_insert.inc + +--echo # +--echo # 2.6 INSERT with a subquery. +--echo # +--echo # Has to take a strong lock on the table being read as +--echo # this statement is written to the binary log and therefore +--echo # should be serialized with concurrent inserts. +let $statement= insert into t2 select i+5 from t1; +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc +let $statement= insert into t2 values ((select i+5 from t1 where i = 4)); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 2.7 LOAD DATA with a subquery. +--echo # +--echo # The above is true for this statement as well. +let $statement= load data infile '../../std_data/rpl_loaddata.dat' into table t2 (@a, @b) set j= @b + (select i from t1 where i = 1); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 2.8 REPLACE with a subquery. +--echo # +--echo # Same is true for this statement as well. +let $statement= replace into t2 select i+5 from t1; +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc +let $statement= replace into t2 values ((select i+5 from t1 where i = 4)); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 2.9 SELECT with a subquery. +--echo # +--echo # Strong locks are not necessary as this statement is not written +--echo # to the binary log and thanks to how MyISAM works this statement +--echo # sees a version of the table prior to the concurrent insert. +let $statement= select * from t2 where j in (select i from t1); +let $restore_table= ; +--source include/check_concurrent_insert.inc + +--echo # +--echo # 2.10 SET with a subquery. +--echo # +--echo # The same is true for this statement as well. +let $statement= set @a:= (select i from t1 where i = 1); +let $restore_table= ; +--source include/check_concurrent_insert.inc + +--echo # +--echo # 2.11 SHOW with a subquery. +--echo # +--echo # And for this statement too. +let $statement= show tables from test where Tables_in_test = 't2' and (select i from t1 where i = 1); +let $restore_table= ; +--source include/check_concurrent_insert.inc +let $statement= show columns from t2 where (select i from t1 where i = 1); +let $restore_table= ; +--source include/check_concurrent_insert.inc + +--echo # +--echo # 2.12 UPDATE with a subquery. +--echo # +--echo # Has to take a strong lock on the table being read as +--echo # this statement is written to the binary log and therefore +--echo # should be serialized with concurrent inserts. +let $statement= update t2 set j= j-10 where j in (select i from t1); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 2.13 MULTI-UPDATE with a subquery. +--echo # +--echo # Same is true for this statement as well. +let $statement= update t2, t3 set j= j -10 where j=k and j in (select i from t1); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + + +--echo # +--echo # 3. Statements which read tables through a view. +--echo # + +--echo # +--echo # 3.1 SELECT statement which uses some table through a view. +--echo # +--echo # Since this statement is not written to the binary log and +--echo # an old version of the table is accessible thanks to how MyISAM +--echo # handles concurrent insert, no locking is necessary. +let $statement= select * from v1; +let $restore_table= ; +--source include/check_concurrent_insert.inc +let $statement= select * from v2; +let $restore_table= ; +--source include/check_concurrent_insert.inc +let $statement= select * from t2 where j in (select i from v1); +let $restore_table= ; +--source include/check_concurrent_insert.inc +let $statement= select * from t3 where k in (select j from v2); +let $restore_table= ; +--source include/check_concurrent_insert.inc + +--echo # +--echo # 3.2 Statements which modify a table and use views. +--echo # +--echo # Since such statements are going to be written to the binary +--echo # log they need to be serialized against concurrent statements +--echo # and therefore should take strong locks on the data read. +let $statement= update t2 set j= j-10 where j in (select i from v1); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc +let $statement= update t3 set k= k-10 where k in (select j from v2); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc +let $statement= update t2, v1 set j= j-10 where j = i; +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc +let $statement= update v2 set j= j-10 where j = 3; +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + + +--echo # +--echo # 4. Statements which read tables through stored functions. +--echo # + +--echo # +--echo # 4.1 SELECT/SET with a stored function which does not +--echo # modify data and uses SELECT in its turn. +--echo # +--echo # In theory there is no need to take strong locks on the table +--echo # being selected from in SF as the call to such function +--echo # won't get into the binary log. In practice, however, we +--echo # discover that fact too late in the process to be able to +--echo # affect the decision what locks should be taken. +--echo # Hence, strong locks are taken in this case. +let $statement= select f1(); +let $restore_table= ; +--source include/check_no_concurrent_insert.inc +let $statement= set @a:= f1(); +let $restore_table= ; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 4.2 INSERT (or other statement which modifies data) with +--echo # a stored function which does not modify data and uses +--echo # SELECT. +--echo # +--echo # Since such statement is written to the binary log it should +--echo # be serialized with concurrent statements affecting the data +--echo # it uses. Therefore it should take strong lock on the data +--echo # it reads. +let $statement= insert into t2 values (f1() + 5); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 4.3 SELECT/SET with a stored function which +--echo # reads and modifies data. +--echo # +--echo # Since a call to such function is written to the binary log, +--echo # it should be serialized with concurrent statements affecting +--echo # the data it uses. Hence, a strong lock on the data read +--echo # should be taken. +let $statement= select f2(); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc +let $statement= set @a:= f2(); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 4.4. SELECT/SET with a stored function which does not +--echo # modify data and reads a table through subselect +--echo # in a control construct. +--echo # +--echo # Again, in theory a call to this function won't get to the +--echo # binary log and thus no strong lock is needed. But in practice +--echo # we don't detect this fact early enough (get_lock_type_for_table()) +--echo # to avoid taking a strong lock. +let $statement= select f3(); +let $restore_table= ; +--source include/check_no_concurrent_insert.inc +let $statement= set @a:= f3(); +let $restore_table= ; +--source include/check_no_concurrent_insert.inc +let $statement= select f4(); +let $restore_table= ; +--source include/check_no_concurrent_insert.inc +let $statement= set @a:= f4(); +let $restore_table= ; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 4.5. INSERT (or other statement which modifies data) with +--echo # a stored function which does not modify data and reads +--echo # the table through a subselect in one of its control +--echo # constructs. +--echo # +--echo # Since such statement is written to the binary log it should +--echo # be serialized with concurrent statements affecting data it +--echo # uses. Therefore it should take a strong lock on the data +--echo # it reads. +let $statement= insert into t2 values (f3() + 5); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc +let $statement= insert into t2 values (f4() + 6); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 4.6 SELECT/SET which uses a stored function with +--echo # DML which reads a table via a subquery. +--echo # +--echo # Since call to such function is written to the binary log +--echo # it should be serialized with concurrent statements. +--echo # Hence reads should take a strong lock. +let $statement= select f5(); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc +let $statement= set @a:= f5(); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 4.7 SELECT/SET which uses a stored function which +--echo # doesn't modify data and reads tables through +--echo # a view. +--echo # +--echo # Once again, in theory, calls to such functions won't +--echo # get into the binary log and thus don't need strong +--echo # locks. But in practice this fact is discovered +--echo # too late to have any effect. +let $statement= select f6(); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc +let $statement= set @a:= f6(); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc +let $statement= select f7(); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc +let $statement= set @a:= f7(); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 4.8 INSERT which uses stored function which +--echo # doesn't modify data and reads a table +--echo # through a view. +--echo # +--echo # Since such statement is written to the binary log and +--echo # should be serialized with concurrent statements affecting +--echo # the data it uses. Therefore it should take a strong lock on +--echo # the table it reads. +let $statement= insert into t3 values (f6() + 5); +let $restore_table= t3; +--source include/check_no_concurrent_insert.inc +let $statement= insert into t3 values (f7() + 5); +let $restore_table= t3; +--source include/check_no_concurrent_insert.inc + + +--echo # +--echo # 4.9 SELECT which uses a stored function which +--echo # modifies data and reads tables through a view. +--echo # +--echo # Since a call to such function is written to the binary log +--echo # it should be serialized with concurrent statements. +--echo # Hence, reads should take strong locks. +let $statement= select f8(); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc +let $statement= select f9(); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 4.10 SELECT which uses a stored function which doesn't modify +--echo # data and reads a table indirectly, by calling another +--echo # function. +--echo # +--echo # In theory, calls to such functions won't get into the binary +--echo # log and thus don't need to acquire strong locks. But in practice +--echo # this fact is discovered too late to have any effect. +let $statement= select f10(); +let $restore_table= ; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 4.11 INSERT which uses a stored function which doesn't modify +--echo # data and reads a table indirectly, by calling another +--echo # function. +--echo # +--echo # Since such statement is written to the binary log, it should +--echo # be serialized with concurrent statements affecting the data it +--echo # uses. Therefore it should take strong locks on data it reads. +let $statement= insert into t2 values (f10() + 5); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 4.12 SELECT which uses a stored function which modifies +--echo # data and reads a table indirectly, by calling another +--echo # function. +--echo # +--echo # Since a call to such function is written to the binary log +--echo # it should be serialized from concurrent statements. +--echo # Hence, read should take a strong lock. +let $statement= select f11(); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 4.13 SELECT that reads a table through a subquery passed +--echo # as a parameter to a stored function which modifies +--echo # data. +--echo # +--echo # Even though a call to this function is written to the +--echo # binary log, values of its parameters are written as literals. +--echo # So there is no need to acquire strong locks for tables used in +--echo # the subquery. +let $statement= select f12((select i+10 from t1 where i=1)); +let $restore_table= t2; +--source include/check_concurrent_insert.inc + +--echo # +--echo # 4.14 INSERT that reads a table via a subquery passed +--echo # as a parameter to a stored function which doesn't +--echo # modify data. +--echo # +--echo # Since this statement is written to the binary log it should +--echo # be serialized with concurrent statements affecting the data it +--echo # uses. Therefore it should take strong locks on the data it reads. +let $statement= insert into t2 values (f13((select i+10 from t1 where i=1))); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + + +--echo # +--echo # 5. Statements that read tables through stored procedures. +--echo # + +--echo # +--echo # 5.1 CALL statement which reads a table via SELECT. +--echo # +--echo # Since neither this statement nor its components are +--echo # written to the binary log, there is no need to take +--echo # strong locks on the data it reads. +let $statement= call p2(@a); +let $restore_table= ; +--source include/check_concurrent_insert.inc + +--echo # +--echo # 5.2 Function that modifes data and uses CALL, +--echo # which reads a table through SELECT. +--echo # +--echo # Since a call to such function is written to the binary +--echo # log, it should be serialized with concurrent statements. +--echo # Hence, in this case reads should take strong locks on data. +let $statement= select f14(); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 5.3 SELECT that calls a function that doesn't modify data and +--echo # uses a CALL statement that reads a table via SELECT. +--echo # +--echo # In theory, calls to such functions won't get into the binary +--echo # log and thus don't need to acquire strong locks. But in practice +--echo # this fact is discovered too late to have any effect. +let $statement= select f15(); +let $restore_table= ; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 5.4 INSERT which calls function which doesn't modify data and +--echo # uses CALL statement which reads table through SELECT. +--echo # +--echo # Since such statement is written to the binary log it should +--echo # be serialized with concurrent statements affecting data it +--echo # uses. Therefore it should take strong locks on data it reads. +let $statement= insert into t2 values (f15()+5); +let $restore_table= t2; +--source include/check_no_concurrent_insert.inc + + +--echo # +--echo # 6. Statements that use triggers. +--echo # + +--echo # +--echo # 6.1 Statement invoking a trigger that reads table via SELECT. +--echo # +--echo # Since this statement is written to the binary log it should +--echo # be serialized with concurrent statements affecting the data +--echo # it uses. Therefore, it should take strong locks on the data +--echo # it reads. +let $statement= insert into t4 values (2); +let $restore_table= t4; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 6.2 Statement invoking a trigger that reads table through +--echo # a subquery in a control construct. +--echo # +--echo # The above is true for this statement as well. +let $statement= update t4 set l= 2 where l = 1; +let $restore_table= t4; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 6.3 Statement invoking a trigger that reads a table through +--echo # a view. +--echo # +--echo # And for this statement. +let $statement= delete from t4 where l = 1; +let $restore_table= t4; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 6.4 Statement invoking a trigger that reads a table through +--echo # a stored function. +--echo # +--echo # And for this statement. +let $statement= insert into t5 values (2); +let $restore_table= t5; +--source include/check_no_concurrent_insert.inc + +--echo # +--echo # 6.5 Statement invoking a trigger that reads a table through +--echo # stored procedure. +--echo # +--echo # And for this statement. +let $statement= update t5 set l= 2 where l = 1; +let $restore_table= t5; +--source include/check_no_concurrent_insert.inc + + +--echo # Clean-up. +drop function f1; +drop function f2; +drop function f3; +drop function f4; +drop function f5; +drop function f6; +drop function f7; +drop function f8; +drop function f9; +drop function f10; +drop function f11; +drop function f12; +drop function f13; +drop function f14; +drop function f15; +drop view v1, v2; +drop procedure p1; +drop procedure p2; +drop table t1, t2, t3, t4, t5; + +disconnect con1; +disconnect con2; + +set @@global.concurrent_insert= @old_concurrent_insert; + + +--echo # --echo # Test for bug #45143 "All connections hang on concurrent ALTER TABLE". --echo # --echo # Concurrent execution of statements which required weak write lock diff --git a/mysql-test/t/mdl_sync.test b/mysql-test/t/mdl_sync.test index ef434e33cfa..0b4b9af5bc6 100644 --- a/mysql-test/t/mdl_sync.test +++ b/mysql-test/t/mdl_sync.test @@ -3468,6 +3468,27 @@ connection default; set debug_sync= 'RESET'; drop table t1; +--echo # +--echo # Bug#52856 concurrent show columns or show full columns causes a crash!!! +--echo # +CREATE TABLE t1(a CHAR(255)); + +connect(con1, localhost, root); +SET DEBUG_SYNC= "get_schema_column SIGNAL waiting WAIT_FOR completed"; +--send SHOW FULL COLUMNS FROM t1 + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR waiting"; +--replace_column 8 # +SHOW FULL COLUMNS FROM t1; +SET DEBUG_SYNC= "now SIGNAL completed"; +--replace_column 8 # +connection con1; +--reap +connection default; +DROP TABLE t1; +disconnect con1; + # Check that all connections opened by test cases in this file are really # gone so execution of other tests won't be affected by their presence. diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index ab901185e43..a9d98da0403 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -126,7 +126,6 @@ drop table t3,t2,t1; # Test table without unions # create table t1 (a int not null, key(a)) engine=merge; ---error 1030 select * from t1; drop table t1; @@ -616,6 +615,14 @@ SHOW CREATE TABLE m1; DROP TABLE t1, m1; # +# BUG#35274 - merge table doesn't need any base tables, gives error 124 when +# key accessed +# +CREATE TABLE t1(a INT, KEY(a)) ENGINE=merge; +SELECT MAX(a) FROM t1; +DROP TABLE t1; + +# # BUG#32047 - 'Spurious' errors while opening MERGE tables # CREATE TABLE t1(a INT); diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 36b6015c5d8..2ea169d950d 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -1468,3 +1468,27 @@ SELECT * FROM t1 FORCE INDEX FOR JOIN (a), t2 WHERE t1.a < 2 ORDER BY t1.a; DROP TABLE t1, t2; --echo End of 5.1 tests + + +--echo # +--echo # Bug #38745: MySQL 5.1 optimizer uses filesort for ORDER BY +--echo # when it should use index +--echo # + +CREATE TABLE t1 (i1 integer NOT NULL PRIMARY KEY); +CREATE TABLE t2 (i2 integer NOT NULL PRIMARY KEY); +CREATE TABLE t3 (i3 integer); + +INSERT INTO t1 VALUES (1), (2), (3), (4), (5), (6), (7), (8), (9), (10), (11), (12); +INSERT INTO t2 SELECT * FROM t1; + +EXPLAIN EXTENDED +SELECT t1.*, t2.* FROM t1 JOIN t2 ON t1.i1 = t2.i2 + LEFT JOIN t3 ON t2.i2 = t3.i3 + ORDER BY t1.i1 LIMIT 5; + +SELECT t1.*, t2.* FROM t1 JOIN t2 ON t1.i1 = t2.i2 + LEFT JOIN t3 ON t2.i2 = t3.i3 + ORDER BY t1.i1 LIMIT 5; + +DROP TABLE t1, t2, t3; diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test index a2e3e43cdb9..1224dee24ed 100644 --- a/mysql-test/t/partition.test +++ b/mysql-test/t/partition.test @@ -14,6 +14,28 @@ drop table if exists t1, t2; --enable_warnings +--echo # Bug#39338: Fieldnames in +--echo # INFORMATIONSCHEMA.PARTITIONS.PARTITION_EXPRESSION become unescaped +--echo # NOTE: the partition expression is saved as a string, so changing from +--echo # normal quotes to ansi quotes does not change the expression, only +--echo # for partition by KEY. +CREATE TABLE t1 ( + ID int(11) NOT NULL, + `aaaa,aaaaa` tinyint(3) UNSIGNED NOT NULL DEFAULT '0', + ddddddddd int(11) NOT NULL DEFAULT '0', + new_field0 varchar(50), + PRIMARY KEY(ID, `aaaa,aaaaa`, ddddddddd)) +PARTITION BY RANGE(ID) +PARTITIONS 3 +SUBPARTITION BY LINEAR KEY(ID,`aaaa,aaaaa`) +SUBPARTITIONS 2 ( + PARTITION p01 VALUES LESS THAN(100), + PARTITION p11 VALUES LESS THAN(200), + PARTITION p21 VALUES LESS THAN MAXVALUE); +SELECT PARTITION_EXPRESSION, SUBPARTITION_EXPRESSION FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='t1'; +show create table t1; +drop table t1; + # # Bug#48276: can't add column if subpartition exists CREATE TABLE t1 (a INT, b INT) diff --git a/mysql-test/t/partition_binlog_stmt.test b/mysql-test/t/partition_binlog_stmt.test new file mode 100644 index 00000000000..bb52c2210f3 --- /dev/null +++ b/mysql-test/t/partition_binlog_stmt.test @@ -0,0 +1,28 @@ +--source include/have_partition.inc +--source include/have_binlog_format_statement.inc + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +--echo # +--echo # Bug#51851: Server with SBR locks mutex twice on LOAD DATA into +--echo # partitioned MyISAM table +perl; +open( INIT, ">init_file.txt"); +print INIT "abcd\n"; +close( INIT ); +EOF + +CREATE TABLE t1 +(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, + name TINYBLOB NOT NULL, + modified TIMESTAMP DEFAULT '0000-00-00 00:00:00', + INDEX namelocs (name(255))) ENGINE = MyISAM +PARTITION BY HASH(id) PARTITIONS 2; + +LOAD DATA LOCAL INFILE 'init_file.txt' +INTO TABLE t1 (name); + +--remove_file init_file.txt +DROP TABLE t1; diff --git a/mysql-test/t/partition_column.test b/mysql-test/t/partition_column.test index d1d2d666a39..95a2be36395 100644 --- a/mysql-test/t/partition_column.test +++ b/mysql-test/t/partition_column.test @@ -8,6 +8,32 @@ drop table if exists t1; --enable_warnings +--echo # +--echo # Bug#52815: LIST COLUMNS doesn't insert rows in correct partition +--echo # if muliple columns used +CREATE TABLE t1 ( +id INT NOT NULL, +name VARCHAR(255), +department VARCHAR(10), +country VARCHAR(255) +) PARTITION BY LIST COLUMNS (department, country) ( +PARTITION first_office VALUES IN (('dep1', 'Russia'), ('dep1', 'Croatia')), +PARTITION second_office VALUES IN (('dep2', 'Russia')) +); + +INSERT INTO t1 VALUES(1, 'Ann', 'dep1', 'Russia'); +INSERT INTO t1 VALUES(2, 'Bob', 'dep1', 'Croatia'); +INSERT INTO t1 VALUES(3, 'Cecil', 'dep2', 'Russia'); +--error ER_NO_PARTITION_FOR_GIVEN_VALUE +INSERT INTO t1 VALUES(3, 'Dan', 'dep2', 'Croatia'); +SELECT PARTITION_NAME,TABLE_ROWS +FROM INFORMATION_SCHEMA.PARTITIONS +WHERE TABLE_NAME = 't1'; +SHOW CREATE TABLE t1; +SELECT * FROM t1 WHERE department = 'dep2' and country = 'Croatia'; +SELECT * FROM t1 WHERE department = 'dep1' and country = 'Croatia'; +DROP TABLE t1; + # # Bug#51347: assertion with show create table + partition by columns # on decimal column diff --git a/mysql-test/t/partition_error.test b/mysql-test/t/partition_error.test index fe4829ad5d1..1496a626796 100644 --- a/mysql-test/t/partition_error.test +++ b/mysql-test/t/partition_error.test @@ -36,6 +36,38 @@ CREATE TABLE t1 (a INT) PARTITION BY HASH(a); --error ER_PARTITION_NO_TEMPORARY CREATE TEMPORARY TABLE tmp_t1 LIKE t1; DROP TABLE t1; +--echo # +--echo # Bug#42954: SQL MODE 'NO_DIR_IN_CREATE' does not work with +--echo # subpartitions +SET @org_mode=@@sql_mode; +SET @@sql_mode='NO_DIR_IN_CREATE'; +SELECT @@sql_mode; +CREATE TABLE t1 (id INT, purchased DATE) +PARTITION BY RANGE(YEAR(purchased)) +SUBPARTITION BY HASH(TO_DAYS(purchased)) +(PARTITION p0 VALUES LESS THAN MAXVALUE + DATA DIRECTORY = '/tmp/not-existing' + INDEX DIRECTORY = '/tmp/not-existing'); +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (id INT, purchased DATE) +PARTITION BY RANGE(YEAR(purchased)) +SUBPARTITION BY HASH(TO_DAYS(purchased)) SUBPARTITIONS 2 +(PARTITION p0 VALUES LESS THAN MAXVALUE + (SUBPARTITION sp0 + DATA DIRECTORY = '/tmp/not-existing' + INDEX DIRECTORY = '/tmp/not-existing', + SUBPARTITION sp1)); +SHOW CREATE TABLE t1; +DROP TABLE t1; +CREATE TABLE t1 (id INT, purchased DATE) +PARTITION BY RANGE(YEAR(purchased)) +(PARTITION p0 VALUES LESS THAN MAXVALUE + DATA DIRECTORY = '/tmp/not-existing' + INDEX DIRECTORY = '/tmp/not-existing'); +SHOW CREATE TABLE t1; +DROP TABLE t1; +SET @@sql_mode= @org_mode; --echo # --echo # Bug#50392: insert_id is not reset for partitioned tables diff --git a/mysql-test/t/ps_3innodb.test b/mysql-test/t/ps_3innodb.test index e25a8b1f469..10d2e7a9ae5 100644 --- a/mysql-test/t/ps_3innodb.test +++ b/mysql-test/t/ps_3innodb.test @@ -8,6 +8,10 @@ # NOTE: PLEASE SEE ps_1general.test (bottom) # BEFORE ADDING NEW TEST CASES HERE !!! +# See Bug#38999 valgrind warnings for update statement in function +# compare_record() +-- source include/not_valgrind.inc + use test; -- source include/have_innodb.inc diff --git a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test index ce75d02a1cc..fa003c2fe69 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -1170,6 +1170,14 @@ DROP TABLE t1; DROP EVENT ev1; # +# Bug#30036 SHOW TABLE TYPES causes the debug client to crash +# +--disable_result_log +SHOW STORAGE ENGINES; +--enable_result_log + + +# # Bug#32710 SHOW INNODB STATUS requires SUPER # diff --git a/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index 5d9a2aaa5f4..1d4ef345747 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -542,3 +542,44 @@ select max(case 1 when 1 then c else null end) from t1 group by c; drop table t1; --echo End of 5.0 tests + +# +# Bug#52168 decimal casting catastrophes: +# crashes and valgrind errors on simple casts +# + +# Uninitialized read when calling Item_cache_decimal::val_int() +CREATE TABLE t1 (a INTEGER); +INSERT INTO t1 VALUES (NULL); +CREATE TABLE t2 (b INTEGER); +INSERT INTO t2 VALUES (NULL), (NULL); +SELECT b FROM t1 JOIN t2 WHERE CONVERT(a, DECIMAL)|CONVERT(b, DECIMAL); +DROP TABLE t1, t2; + +# +# Bug#52122 crash when converting derived table column to decimal +# +CREATE TABLE t1 (col0 INTEGER, col1 REAL); +CREATE TABLE t2 (col0 INTEGER); +INSERT INTO t1 VALUES (0, 0.0), (NULL, NULL); +INSERT INTO t2 VALUES (1); + +# Uninitialized read when calling Item_cache_decimal::val_real() +SELECT 1 FROM t1 +JOIN +( + SELECT t2.col0 FROM t2 RIGHT JOIN t1 USING(col0) + GROUP BY t2.col0 +) AS subq +WHERE t1.col1 + CAST(subq.col0 AS DECIMAL); + +# Uninitialized read when calling Item_cache_decimal::val_str() +SELECT 1 FROM t1 +JOIN +( + SELECT t2.col0 FROM t2 RIGHT JOIN t1 USING(col0) + GROUP BY t2.col0 +) AS subq +WHERE CONCAT(t1.col1, CAST(subq.col0 AS DECIMAL)); + +DROP TABLE t1, t2; diff --git a/mysql-test/valgrind.supp b/mysql-test/valgrind.supp index 6b10e4cb544..83896378883 100644 --- a/mysql-test/valgrind.supp +++ b/mysql-test/valgrind.supp @@ -174,6 +174,24 @@ } { + libz longest_match called from btr_store_big_rec_extern_fields + Memcheck:Cond + fun:longest_match + fun:deflate_slow + fun:deflate + fun:btr_store_big_rec_extern_fields +} + +{ + libz longest_match called from page_zip_compress + Memcheck:Cond + fun:longest_match + fun:deflate_slow + fun:deflate + fun:page_zip_compress +} + +{ libz longest_match2 Memcheck:Cond fun:longest_match @@ -722,3 +740,8 @@ fun:pthread_create* } +{ + buf_buddy_relocate peeking (space,page) in potentially free blocks + Memcheck:Addr1 + fun:buf_buddy_relocate +} diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 2fbaac7fe72..4c93f5ffd57 100755 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -27,7 +27,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c checksum.c default.c default_ my_clock.c my_compress.c my_copy.c my_crc32.c my_create.c my_delete.c my_div.c my_error.c my_file.c my_fopen.c my_fstream.c my_gethostbyname.c my_gethwaddr.c my_getopt.c my_getsystime.c my_getwd.c my_handler.c my_init.c - my_lib.c my_lock.c my_lockmem.c my_malloc.c my_messnc.c + my_lib.c my_lock.c my_lockmem.c my_malloc.c my_mess.c my_mkdir.c my_mmap.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_sleep.c my_static.c my_symlink.c my_symlink2.c my_sync.c my_thr_init.c diff --git a/mysys/Makefile.am b/mysys/Makefile.am index ad7f244e0fb..d5bffd874b2 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -34,7 +34,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c my_mmap.c \ my_vle.c my_atomic.c lf_hash.c \ lf_dynarray.c lf_alloc-pin.c \ my_fopen.c my_fstream.c my_getsystime.c \ - my_error.c errors.c my_div.c my_messnc.c \ + my_error.c errors.c my_div.c my_mess.c \ mf_format.c mf_same.c mf_dirname.c mf_fn_ext.c \ my_symlink.c my_symlink2.c \ mf_pack.c mf_unixpath.c mf_arr_appstr.c \ diff --git a/mysys/lf_alloc-pin.c b/mysys/lf_alloc-pin.c index fda9b97791d..7fd10703871 100644 --- a/mysys/lf_alloc-pin.c +++ b/mysys/lf_alloc-pin.c @@ -329,10 +329,9 @@ static void _lf_pinbox_real_free(LF_PINS *pins) { int npins, alloca_size; void *list, **addr; - void *first, *last= NULL; + void *first= NULL, *last= NULL; LF_PINBOX *pinbox= pins->pinbox; - LINT_INIT(first); npins= pinbox->pins_in_array+1; #ifdef HAVE_ALLOCA diff --git a/mysys/make-ccc b/mysys/make-ccc deleted file mode 100755 index b34bd80e1d1..00000000000 --- a/mysys/make-ccc +++ /dev/null @@ -1,4 +0,0 @@ -rm -f .deps/* raid.o mf_iocache.o libmysys.a -ccc -DDEFAULT_BASEDIR="\"/usr/local/mysql\"" -DDATADIR="\"/usr/local/mysql/var\"" -DHAVE_CONFIG_H -I./../include -I../include -I.. -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c array.c checksum.c default.c errors.c getopt.c getopt1.c getvar.c hash.c list.c mf_brkhant.c mf_cache.c mf_casecnv.c mf_dirname.c mf_fn_ext.c mf_format.c mf_getdate.c mf_keycache.c mf_loadpath.c mf_pack.c mf_pack2.c mf_path.c mf_qsort.c mf_qsort2.c mf_radix.c mf_reccache.c mf_same.c mf_sort.c mf_soundex.c mf_stripp.c mf_unixpath.c mf_wcomp.c mf_wfile.c mulalloc.c my_alarm.c my_alloc.c my_append.c my_chsize.c my_clock.c my_compress.c my_copy.c my_create.c my_delete.c my_div.c my_error.c my_fopen.c my_fstream.c my_getwd.c my_init.c my_lib.c my_lockmem.c my_malloc.c my_messnc.c my_mkdir.c my_net.c my_once.c my_open.c my_pread.c my_pthread.c my_quick.c my_read.c my_realloc.c my_redel.c my_rename.c my_seek.c my_static.c my_tempnam.c my_thr_init.c my_write.c ptr_cmp.c queues.c safemalloc.c string.c thr_alarm.c thr_lock.c thr_mutex.c thr_rwlock.c tree.c typelib.c -make raid.o mf_iocache.o my_lock.o -ar -cr libmysys.a array.o raid.o mf_iocache.o my_lock.o diff --git a/mysys/my_gethwaddr.c b/mysys/my_gethwaddr.c index 38fa0313c5d..c6a7af58f57 100644 --- a/mysys/my_gethwaddr.c +++ b/mysys/my_gethwaddr.c @@ -102,47 +102,49 @@ err: } #elif defined(__WIN__) -
-/* Workaround for BUG#32082 (Definition of VOID in my_global.h conflicts with
-windows headers) */
-#ifdef VOID
-#undef VOID
-#define VOID void
-#endif
+ +/* + Workaround for BUG#32082 (Definition of VOID in my_global.h conflicts with + windows headers) +*/ +#ifdef VOID +#undef VOID +#define VOID void +#endif #include <iphlpapi.h> -/* - The following typedef is for dynamically loading - iphlpapi.dll / GetAdaptersAddresses. Dynamic loading is - used because GetAdaptersAddresses is not available on Windows 2000 - which MySQL still supports. Static linking would cause an unresolved export. +/* + The following typedef is for dynamically loading iphlpapi.dll / + GetAdaptersAddresses. Dynamic loading is used because + GetAdaptersAddresses is not available on Windows 2000 which MySQL + still supports. Static linking would cause an unresolved export. */ typedef DWORD (WINAPI *pfnGetAdaptersAddresses)(IN ULONG Family, IN DWORD Flags,IN PVOID Reserved, - OUT PIP_ADAPTER_ADDRESSES pAdapterAddresses, + OUT PIP_ADAPTER_ADDRESSES pAdapterAddresses, IN OUT PULONG pOutBufLen); /* - my_gethwaddr - Windows version + my_gethwaddr - Windows version @brief Retrieve MAC address from network hardware - + @param[out] to MAC address exactly six bytes - + @return Operation status @retval 0 OK - @retval <>0 FAILED + @retval <>0 FAILED */ my_bool my_gethwaddr(uchar *to) -{ +{ PIP_ADAPTER_ADDRESSES pAdapterAddresses; PIP_ADAPTER_ADDRESSES pCurrAddresses; IP_ADAPTER_ADDRESSES adapterAddresses; ULONG address_len; - my_bool return_val= 1; - static pfnGetAdaptersAddresses fnGetAdaptersAddresses= - (pfnGetAdaptersAddresses)-1; + my_bool return_val= 1; + static pfnGetAdaptersAddresses fnGetAdaptersAddresses= + (pfnGetAdaptersAddresses)-1; if(fnGetAdaptersAddresses == (pfnGetAdaptersAddresses)-1) { @@ -156,7 +158,7 @@ my_bool my_gethwaddr(uchar *to) address_len= sizeof (IP_ADAPTER_ADDRESSES); /* Get the required size for the address data. */ - if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, &adapterAddresses, &address_len) + if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, &adapterAddresses, &address_len) == ERROR_BUFFER_OVERFLOW) { pAdapterAddresses= my_malloc(address_len, 0); @@ -167,29 +169,29 @@ my_bool my_gethwaddr(uchar *to) pAdapterAddresses= &adapterAddresses; /* one is enough don't alloc */ /* Get the hardware info. */ - if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, pAdapterAddresses, &address_len) + if (fnGetAdaptersAddresses(AF_UNSPEC, 0, 0, pAdapterAddresses, &address_len) == NO_ERROR) { pCurrAddresses= pAdapterAddresses; - while (pCurrAddresses) + while (pCurrAddresses) { /* Look for ethernet cards. */ if (pCurrAddresses->IfType == IF_TYPE_ETHERNET_CSMACD) { /* check for a good address */ if (pCurrAddresses->PhysicalAddressLength < 6) - continue; /* bad address */ + continue; /* bad address */ /* save 6 bytes of the address in the 'to' parameter */ memcpy(to, pCurrAddresses->PhysicalAddress, 6); /* Network card found, we're done. */ return_val= 0; - break; + break; } pCurrAddresses= pCurrAddresses->Next; - } + } } /* Clean up memory allocation. */ diff --git a/mysys/my_init.c b/mysys/my_init.c index 80f9a493bb0..f27f3f7b3e8 100644 --- a/mysys/my_init.c +++ b/mysys/my_init.c @@ -204,7 +204,7 @@ void my_end(int infoflag) char ebuff[512]; my_snprintf(ebuff, sizeof(ebuff), EE(EE_OPEN_WARNING), my_file_opened, my_stream_opened); - my_message_no_curses(EE_OPEN_WARNING, ebuff, ME_BELL); + my_message_stderr(EE_OPEN_WARNING, ebuff, ME_BELL); DBUG_PRINT("error", ("%s", ebuff)); my_print_open_files(); } diff --git a/mysys/my_messnc.c b/mysys/my_mess.c index e2dee3f6710..0ec97525ae8 100644 --- a/mysys/my_messnc.c +++ b/mysys/my_mess.c @@ -15,10 +15,10 @@ #include "mysys_priv.h" -void my_message_no_curses(uint error __attribute__((unused)), - const char *str, myf MyFlags) +void my_message_stderr(uint error __attribute__((unused)), + const char *str, myf MyFlags) { - DBUG_ENTER("my_message_no_curses"); + DBUG_ENTER("my_message_stderr"); DBUG_PRINT("enter",("message: %s",str)); (void) fflush(stdout); if (MyFlags & ME_BELL) diff --git a/mysys/my_pthread.c b/mysys/my_pthread.c index b6b7e7db857..3019e4bc5c1 100644 --- a/mysys/my_pthread.c +++ b/mysys/my_pthread.c @@ -492,11 +492,6 @@ int my_pthread_mutex_trylock(pthread_mutex_t *mutex) /* Some help functions */ -int pthread_no_free(void *not_used __attribute__((unused))) -{ - return 0; -} - int pthread_dummy(int ret) { return ret; diff --git a/mysys/my_static.c b/mysys/my_static.c index a86fe6c7ab7..ff5abba29d3 100644 --- a/mysys/my_static.c +++ b/mysys/my_static.c @@ -87,10 +87,10 @@ ulong my_time_to_wait_for_lock=2; /* In seconds */ char * NEAR globerrs[GLOBERRS]; /* my_error_messages is here */ #endif void (*my_abort_hook)(int) = (void(*)(int)) exit; -void (*error_handler_hook)(uint error,const char *str,myf MyFlags)= - my_message_no_curses; -void (*fatal_error_handler_hook)(uint error,const char *str,myf MyFlags)= - my_message_no_curses; +void (*error_handler_hook)(uint error, const char *str, myf MyFlags)= + my_message_stderr; +void (*fatal_error_handler_hook)(uint error, const char *str, myf MyFlags)= + my_message_stderr; static const char *proc_info_dummy(void *a __attribute__((unused)), const char *b __attribute__((unused)), @@ -123,7 +123,6 @@ my_bool NEAR my_disable_locking=0; my_bool NEAR my_disable_async_io=0; my_bool NEAR my_disable_flush_key_blocks=0; my_bool NEAR my_disable_symlinks=0; -my_bool NEAR mysys_uses_curses=0; /* Note that PSI_hook and PSI_server are unconditionally diff --git a/mysys/safemalloc.c b/mysys/safemalloc.c index efe281ba1bb..936248677f5 100644 --- a/mysys/safemalloc.c +++ b/mysys/safemalloc.c @@ -190,9 +190,12 @@ void *_mymalloc(size_t size, const char *filename, uint lineno, myf MyFlags) sf_malloc_count++; mysql_mutex_unlock(&THR_LOCK_malloc); + MEM_CHECK_ADDRESSABLE(data, size); /* Set the memory to the aribtrary wierd value */ if ((MyFlags & MY_ZEROFILL) || !sf_malloc_quick) bfill(data, size, (char) (MyFlags & MY_ZEROFILL ? 0 : ALLOC_VAL)); + if (!(MyFlags & MY_ZEROFILL)) + MEM_UNDEFINED(data, size); /* Return a pointer to the real data */ DBUG_PRINT("exit",("ptr: %p", data)); if (sf_min_adress > data) @@ -309,7 +312,9 @@ void _myfree(void *ptr, const char *filename, uint lineno, myf myflags) if (!sf_malloc_quick) bfill(ptr, irem->datasize, (pchar) FREE_VAL); #endif + MEM_NOACCESS(ptr, irem->datasize); *((uint32*) ((char*) ptr- sizeof(uint32)))= ~MAGICKEY; + MEM_NOACCESS((char*) ptr - sizeof(uint32), sizeof(uint32)); /* Actually free the memory */ free((char*) irem); DBUG_VOID_RETURN; diff --git a/plugin/daemon_example/daemon_example.cc b/plugin/daemon_example/daemon_example.cc index 2a41179974d..43138f0655f 100644 --- a/plugin/daemon_example/daemon_example.cc +++ b/plugin/daemon_example/daemon_example.cc @@ -13,12 +13,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <my_global.h> #include <sql_priv.h> #include <stdlib.h> #include <ctype.h> #include <mysql_version.h> #include <mysql/plugin.h> -#include <my_global.h> #include <my_dir.h> #include "my_pthread.h" // pthread_handler_t #include "my_sys.h" // my_write, my_malloc diff --git a/plugin/semisync/semisync_master.cc b/plugin/semisync/semisync_master.cc index cdf01854442..2701c575b7a 100644 --- a/plugin/semisync/semisync_master.cc +++ b/plugin/semisync/semisync_master.cc @@ -147,7 +147,8 @@ int ActiveTranx::insert_tranx_node(const char *log_file_name, } /* insert the binlog position in the active transaction list. */ - strcpy(ins_node->log_name_, log_file_name); + strncpy(ins_node->log_name_, log_file_name, FN_REFLEN-1); + ins_node->log_name_[FN_REFLEN-1] = 0; /* make sure it ends properly */ ins_node->log_pos_ = log_file_pos; if (!trx_front_) @@ -1009,13 +1010,15 @@ int ReplSemiSyncMaster::writeTranxInBinlog(const char* log_file_name, if (cmp > 0) { /* This is a larger position, let's update the maximum info. */ - strcpy(commit_file_name_, log_file_name); + strncpy(commit_file_name_, log_file_name, FN_REFLEN-1); + commit_file_name_[FN_REFLEN-1] = 0; /* make sure it ends properly */ commit_file_pos_ = log_file_pos; } } else { - strcpy(commit_file_name_, log_file_name); + strncpy(commit_file_name_, log_file_name, FN_REFLEN-1); + commit_file_name_[FN_REFLEN-1] = 0; /* make sure it ends properly */ commit_file_pos_ = log_file_pos; commit_file_name_inited_ = true; } @@ -1048,6 +1051,7 @@ int ReplSemiSyncMaster::readSlaveReply(NET *net, uint32 server_id, const unsigned char *packet; char log_file_name[FN_REFLEN]; my_off_t log_file_pos; + ulong log_file_len = 0; ulong packet_len; int result = -1; @@ -1123,7 +1127,14 @@ int ReplSemiSyncMaster::readSlaveReply(NET *net, uint32 server_id, } log_file_pos = uint8korr(packet + REPLY_BINLOG_POS_OFFSET); - strcpy(log_file_name, (const char*)packet + REPLY_BINLOG_NAME_OFFSET); + log_file_len = packet_len - REPLY_BINLOG_NAME_OFFSET; + if (log_file_len >= FN_REFLEN) + { + sql_print_error("Read semi-sync reply binlog file length too large"); + goto l_end; + } + strncpy(log_file_name, (const char*)packet + REPLY_BINLOG_NAME_OFFSET, log_file_len); + log_file_name[log_file_len] = 0; if (trc_level & kTraceDetail) sql_print_information("%s: Got reply (%s, %lu)", diff --git a/plugin/semisync/semisync_master.h b/plugin/semisync/semisync_master.h index e1ad28cd9f6..1a562e8bb77 100644 --- a/plugin/semisync/semisync_master.h +++ b/plugin/semisync/semisync_master.h @@ -153,7 +153,7 @@ public: int free_nodes_before(TranxNode* node) { Block *block; - Block *prev_block; + Block *prev_block= NULL; block= first_block; while (block != current_block->next) diff --git a/plugin/semisync/semisync_master_plugin.cc b/plugin/semisync/semisync_master_plugin.cc index d6cc23a43b7..a55ba184a17 100644 --- a/plugin/semisync/semisync_master_plugin.cc +++ b/plugin/semisync/semisync_master_plugin.cc @@ -20,6 +20,8 @@ ReplSemiSyncMaster repl_semisync; +C_MODE_START + int repl_semi_report_binlog_update(Binlog_storage_param *param, const char *log_file, my_off_t log_pos, uint32 flags) @@ -145,6 +147,8 @@ int repl_semi_reset_master(Binlog_transmit_param *param) return 0; } +C_MODE_END + /* semisync system variables */ diff --git a/plugin/semisync/semisync_slave_plugin.cc b/plugin/semisync/semisync_slave_plugin.cc index 66073f8a5e6..5aa32cdfd5f 100644 --- a/plugin/semisync/semisync_slave_plugin.cc +++ b/plugin/semisync/semisync_slave_plugin.cc @@ -29,6 +29,8 @@ ReplSemiSyncSlave repl_semisync; */ bool semi_sync_need_reply= false; +C_MODE_START + int repl_semi_reset_slave(Binlog_relay_IO_param *param) { // TODO: reset semi-sync slave status here @@ -124,6 +126,7 @@ int repl_semi_slave_io_end(Binlog_relay_IO_param *param) return repl_semisync.slaveStop(param); } +C_MODE_END static void fix_rpl_semi_sync_slave_enabled(MYSQL_THD thd, SYS_VAR *var, diff --git a/regex/make-ccc b/regex/make-ccc deleted file mode 100755 index 561c5a9bddc..00000000000 --- a/regex/make-ccc +++ /dev/null @@ -1,3 +0,0 @@ -ccc -DHAVE_CONFIG_H -I. -I. -I.. -I./../include -I../include -O -DDBUG_OFF -fast -O3 -c regerror.c regcomp.c regexec.c regfree.c reginit.c -rm libregex.a -ar -cr libregex.a regerror.o diff --git a/sql/debug_sync.cc b/sql/debug_sync.cc index d16fa4b2468..dde6267331f 100644 --- a/sql/debug_sync.cc +++ b/sql/debug_sync.cc @@ -387,6 +387,13 @@ static st_debug_sync_globals debug_sync_global; /* All globals in one object */ */ extern "C" void (*debug_sync_C_callback_ptr)(const char *, size_t); +/** + Callbacks from C files. +*/ +C_MODE_START +static void debug_sync_C_callback(const char *, size_t); +static int debug_sync_qsort_cmp(const void *, const void *); +C_MODE_END /** Callback for debug sync, to be used by C files. See thr_lock.c for example. @@ -422,8 +429,8 @@ extern "C" void (*debug_sync_C_callback_ptr)(const char *, size_t); static void debug_sync_C_callback(const char *sync_point_name, size_t name_len) { - if (unlikely(opt_debug_sync_timeout)) - debug_sync(current_thd, sync_point_name, name_len); + if (unlikely(opt_debug_sync_timeout)) + debug_sync(current_thd, sync_point_name, name_len); } #ifdef HAVE_PSI_INTERFACE diff --git a/sql/derror.cc b/sql/derror.cc index 04a82860d45..7f1435e89c1 100644 --- a/sql/derror.cc +++ b/sql/derror.cc @@ -32,11 +32,12 @@ static void init_myfunc_errs(void); -const char **get_server_errmsgs() +C_MODE_START +static const char **get_server_errmsgs() { return CURRENT_THD_ERRMSGS; } - +C_MODE_END /** Read messages from errorfile. diff --git a/sql/field.cc b/sql/field.cc index d3de8bf6c6d..bfaaf10b141 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1009,17 +1009,20 @@ test_if_important_data(CHARSET_INFO *cs, const char *str, const char *strend) Used below. In an anonymous namespace to not clash with definitions in other files. */ -namespace { - int compare(unsigned int a, unsigned int b) - { - if (a < b) - return -1; - if (b < a) - return 1; - return 0; -} + +CPP_UNNAMED_NS_START + +int compare(unsigned int a, unsigned int b) +{ + if (a < b) + return -1; + if (b < a) + return 1; + return 0; } +CPP_UNNAMED_NS_END + /** Detect Item_result by given field type of UNION merge result. @@ -9112,7 +9115,7 @@ void Create_field::create_length_to_internal_length(void) void Create_field::init_for_tmp_table(enum_field_types sql_type_arg, uint32 length_arg, uint32 decimals_arg, bool maybe_null, bool is_unsigned, - uint pack_length) + uint pack_length_arg) { DBUG_ENTER("Create_field::init_for_tmp_table"); @@ -9125,7 +9128,7 @@ void Create_field::init_for_tmp_table(enum_field_types sql_type_arg, geom_type= Field::GEOM_GEOMETRY; DBUG_PRINT("enter", ("sql_type: %d, length: %u, pack_length: %u", - sql_type_arg, length_arg, pack_length)); + sql_type_arg, length_arg, pack_length_arg)); /* These pack flags are crafted to get it correctly through the @@ -9189,8 +9192,8 @@ void Create_field::init_for_tmp_table(enum_field_types sql_type_arg, case MYSQL_TYPE_GEOMETRY: // If you are going to use the above types, you have to pass a // pack_length as parameter. Assert that is really done. - DBUG_ASSERT(pack_length != ~0U); - pack_flag|= pack_length_to_packflag(pack_length); + DBUG_ASSERT(pack_length_arg != ~0U); + pack_flag|= pack_length_to_packflag(pack_length_arg); break; default: /* Nothing */ @@ -9944,6 +9947,39 @@ Create_field::Create_field(Field *old_field,Field *orig_field) /** + maximum possible character length for blob. + + This method is used in Item_field::set_field to calculate + max_length for Item. + + For example: + CREATE TABLE t2 SELECT CONCAT(tinyblob_utf8_column) FROM t1; + must create a "VARCHAR(255) CHARACTER SET utf8" column. + + @return + length +*/ + +uint32 Field_blob::char_length() +{ + switch (packlength) + { + case 1: + return 255; + case 2: + return 65535; + case 3: + return 16777215; + case 4: + return (uint32) 4294967295U; + default: + DBUG_ASSERT(0); // we should never go here + return 0; + } +} + + +/** maximum possible display length for blob. @return diff --git a/sql/field.h b/sql/field.h index 66b13d02b89..46d8a2aa6d9 100644 --- a/sql/field.h +++ b/sql/field.h @@ -499,7 +499,7 @@ public: longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag, int *err); /* The max. number of characters */ - inline uint32 char_length() const + virtual uint32 char_length() { return field_length / charset()->mbmaxlen; } @@ -1813,6 +1813,7 @@ public: bool has_charset(void) const { return charset() == &my_charset_bin ? FALSE : TRUE; } uint32 max_display_length(); + uint32 char_length(); uint is_equal(Create_field *new_field); inline bool in_read_set() { return bitmap_is_set(table->read_set, field_index); } inline bool in_write_set() { return bitmap_is_set(table->write_set, field_index); } diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 38324f3cf19..9f003174d2e 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -4249,7 +4249,7 @@ int ha_ndbcluster::info(uint flag) } -void ha_ndbcluster::get_dynamic_partition_info(PARTITION_INFO *stat_info, +void ha_ndbcluster::get_dynamic_partition_info(PARTITION_STATS *stat_info, uint part_id) { /* @@ -4257,7 +4257,7 @@ void ha_ndbcluster::get_dynamic_partition_info(PARTITION_INFO *stat_info, implement ndb function which retrives the statistics about ndb partitions. */ - bzero((char*) stat_info, sizeof(PARTITION_INFO)); + bzero((char*) stat_info, sizeof(PARTITION_STATS)); return; } @@ -4628,7 +4628,7 @@ int ha_ndbcluster::start_statement(THD *thd, trans_register_ha(thd, FALSE, ndbcluster_hton); if (!thd_ndb->trans) { - if (thd->in_multi_stmt_transaction()) + if (thd->in_multi_stmt_transaction_mode()) trans_register_ha(thd, TRUE, ndbcluster_hton); DBUG_PRINT("trans",("Starting transaction")); thd_ndb->trans= ndb->startTransaction(); @@ -4698,7 +4698,7 @@ int ha_ndbcluster::init_handler_for_statement(THD *thd, Thd_ndb *thd_ndb) } #endif - if (thd->in_multi_stmt_transaction()) + if (thd->in_multi_stmt_transaction_mode()) { const void *key= m_table; HASH_SEARCH_STATE state; @@ -4782,7 +4782,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) if (opt_ndb_cache_check_time && m_rows_changed) { DBUG_PRINT("info", ("Rows has changed and util thread is running")); - if (thd->in_multi_stmt_transaction()) + if (thd->in_multi_stmt_transaction_mode()) { DBUG_PRINT("info", ("Add share to list of tables to be invalidated")); /* NOTE push_back allocates memory using transactions mem_root! */ @@ -4801,7 +4801,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) DBUG_PRINT("trans", ("Last external_lock")); PRINT_OPTION_FLAGS(thd); - if (!thd->in_multi_stmt_transaction()) + if (!thd->in_multi_stmt_transaction_mode()) { if (thd_ndb->trans) { @@ -4911,7 +4911,7 @@ static int ndbcluster_commit(handlerton *hton, THD *thd, bool all) PRINT_OPTION_FLAGS(thd); DBUG_PRINT("enter", ("Commit %s", (all ? "all" : "stmt"))); thd_ndb->start_stmt_count= 0; - if (trans == NULL || (!all && thd->in_multi_stmt_transaction())) + if (trans == NULL || (!all && thd->in_multi_stmt_transaction_mode())) { /* An odditity in the handler interface is that commit on handlerton @@ -4981,7 +4981,7 @@ static int ndbcluster_rollback(handlerton *hton, THD *thd, bool all) DBUG_ASSERT(ndb); thd_ndb->start_stmt_count= 0; if (trans == NULL || (!all && - thd->in_multi_stmt_transaction())) + thd->in_multi_stmt_transaction_mode())) { /* Ignore end-of-statement until real rollback or commit is called */ DBUG_PRINT("info", ("Rollback before start or end-of-statement only")); @@ -8271,7 +8271,7 @@ ndbcluster_cache_retrieval_allowed(THD *thd, DBUG_ENTER("ndbcluster_cache_retrieval_allowed"); DBUG_PRINT("enter", ("dbname: %s, tabname: %s", dbname, tabname)); - if (thd->in_multi_stmt_transaction()) + if (thd->in_multi_stmt_transaction_mode()) { DBUG_PRINT("exit", ("No, don't use cache in transaction")); DBUG_RETURN(FALSE); @@ -8339,7 +8339,7 @@ ha_ndbcluster::register_query_cache_table(THD *thd, DBUG_ENTER("ha_ndbcluster::register_query_cache_table"); DBUG_PRINT("enter",("dbname: %s, tabname: %s", m_dbname, m_tabname)); - if (thd->in_multi_stmt_transaction()) + if (thd->in_multi_stmt_transaction_mode()) { DBUG_PRINT("exit", ("Can't register table during transaction")); DBUG_RETURN(FALSE); diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 17ba7451538..de1e36b61d2 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -275,7 +275,7 @@ class ha_ndbcluster: public handler ha_rows estimate_rows_upper_bound() { return HA_POS_ERROR; } int info(uint); - void get_dynamic_partition_info(PARTITION_INFO *stat_info, uint part_id); + void get_dynamic_partition_info(PARTITION_STATS *stat_info, uint part_id); int extra(enum ha_extra_function operation); int extra_opt(enum ha_extra_function operation, ulong cache_size); int reset(); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index ac05a699c7d..a6f106be3be 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -59,6 +59,7 @@ #include "sql_table.h" // tablename_to_filename #include "key.h" #include "sql_plugin.h" +#include "table.h" /* HA_DATA_PARTITION */ #include "debug_sync.h" @@ -2510,12 +2511,11 @@ err1: A destructor for partition-specific TABLE_SHARE data. */ -void ha_data_partition_destroy(void *ha_data) +void ha_data_partition_destroy(HA_DATA_PARTITION* ha_part_data) { - if (ha_data) + if (ha_part_data) { - HA_DATA_PARTITION *ha_data_partition= (HA_DATA_PARTITION*) ha_data; - pthread_mutex_destroy(&ha_data_partition->mutex); + mysql_mutex_destroy(&ha_part_data->LOCK_auto_inc); } } @@ -2655,28 +2655,30 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked) goto err_handler; /* - Use table_share->ha_data to share auto_increment_value among all handlers - for the same table. + Use table_share->ha_part_data to share auto_increment_value among + all handlers for the same table. */ if (is_not_tmp_table) mysql_mutex_lock(&table_share->LOCK_ha_data); - if (!table_share->ha_data) + if (!table_share->ha_part_data) { - HA_DATA_PARTITION *ha_data; /* currently only needed for auto_increment */ - table_share->ha_data= ha_data= (HA_DATA_PARTITION*) + table_share->ha_part_data= (HA_DATA_PARTITION*) alloc_root(&table_share->mem_root, sizeof(HA_DATA_PARTITION)); - if (!ha_data) + if (!table_share->ha_part_data) { if (is_not_tmp_table) mysql_mutex_unlock(&table_share->LOCK_ha_data); goto err_handler; } - DBUG_PRINT("info", ("table_share->ha_data 0x%p", ha_data)); - bzero(ha_data, sizeof(HA_DATA_PARTITION)); - table_share->ha_data_destroy= ha_data_partition_destroy; - pthread_mutex_init(&ha_data->mutex, MY_MUTEX_INIT_FAST); + DBUG_PRINT("info", ("table_share->ha_part_data 0x%p", + table_share->ha_part_data)); + bzero(table_share->ha_part_data, sizeof(HA_DATA_PARTITION)); + table_share->ha_part_data_destroy= ha_data_partition_destroy; + mysql_mutex_init(key_PARTITION_LOCK_auto_inc, + &table_share->ha_part_data->LOCK_auto_inc, + MY_MUTEX_INIT_FAST); } if (is_not_tmp_table) mysql_mutex_unlock(&table_share->LOCK_ha_data); @@ -3101,7 +3103,6 @@ int ha_partition::write_row(uchar * buf) longlong func_value; bool have_auto_increment= table->next_number_field && buf == table->record[0]; my_bitmap_map *old_map; - HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; THD *thd= ha_thd(); timestamp_auto_set_type orig_timestamp_type= table->timestamp_field_type; #ifdef NOT_NEEDED @@ -3121,8 +3122,8 @@ int ha_partition::write_row(uchar * buf) */ if (have_auto_increment) { - if (!ha_data->auto_inc_initialized && - !table->s->next_number_keypart) + if (!table_share->ha_part_data->auto_inc_initialized && + !table_share->next_number_keypart) { /* If auto_increment in table_share is not initialized, start by @@ -3262,7 +3263,7 @@ int ha_partition::update_row(const uchar *old_data, uchar *new_data) exit: /* if updating an auto_increment column, update - table_share->ha_data->next_auto_inc_val if needed. + table_share->ha_part_data->next_auto_inc_val if needed. (not to be used if auto_increment on secondary field in a multi-column index) mysql_update does not set table->next_number_field, so we use @@ -3271,8 +3272,7 @@ exit: if (table->found_next_number_field && new_data == table->record[0] && !table->s->next_number_keypart) { - HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; - if (!ha_data->auto_inc_initialized) + if (!table_share->ha_part_data->auto_inc_initialized) info(HA_STATUS_AUTO); set_auto_increment_if_higher(table->found_next_number_field); } @@ -3364,11 +3364,10 @@ int ha_partition::delete_all_rows() if (thd->lex->sql_command == SQLCOM_TRUNCATE) { Alter_info *alter_info= &thd->lex->alter_info; - HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; /* TRUNCATE also means resetting auto_increment */ lock_auto_increment(); - ha_data->next_auto_inc_val= 0; - ha_data->auto_inc_initialized= FALSE; + table_share->ha_part_data->next_auto_inc_val= 0; + table_share->ha_part_data->auto_inc_initialized= FALSE; unlock_auto_increment(); if (alter_info->flags & ALTER_ADMIN_PARTITION) { @@ -4195,10 +4194,9 @@ int ha_partition::index_read_map(uchar *buf, const uchar *key, int ha_partition::common_index_read(uchar *buf, bool have_start_key) { int error; - uint key_len; + uint UNINIT_VAR(key_len); /* used if have_start_key==TRUE */ bool reverse_order= FALSE; DBUG_ENTER("ha_partition::common_index_read"); - LINT_INIT(key_len); /* used if have_start_key==TRUE */ DBUG_PRINT("info", ("m_ordered %u m_ordered_scan_ong %u have_start_key %u", m_ordered, m_ordered_scan_ongoing, have_start_key)); @@ -5084,22 +5082,22 @@ int ha_partition::info(uint flag) if (flag & HA_STATUS_AUTO) { bool auto_inc_is_first_in_idx= (table_share->next_number_keypart == 0); - HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; DBUG_PRINT("info", ("HA_STATUS_AUTO")); if (!table->found_next_number_field) stats.auto_increment_value= 0; - else if (ha_data->auto_inc_initialized) + else if (table_share->ha_part_data->auto_inc_initialized) { lock_auto_increment(); - stats.auto_increment_value= ha_data->next_auto_inc_val; + stats.auto_increment_value= table_share->ha_part_data->next_auto_inc_val; unlock_auto_increment(); } else { lock_auto_increment(); /* to avoid two concurrent initializations, check again when locked */ - if (ha_data->auto_inc_initialized) - stats.auto_increment_value= ha_data->next_auto_inc_val; + if (table_share->ha_part_data->auto_inc_initialized) + stats.auto_increment_value= + table_share->ha_part_data->next_auto_inc_val; else { handler *file, **file_array; @@ -5119,10 +5117,11 @@ int ha_partition::info(uint flag) stats.auto_increment_value= auto_increment_value; if (auto_inc_is_first_in_idx) { - set_if_bigger(ha_data->next_auto_inc_val, auto_increment_value); - ha_data->auto_inc_initialized= TRUE; + set_if_bigger(table_share->ha_part_data->next_auto_inc_val, + auto_increment_value); + table_share->ha_part_data->auto_inc_initialized= TRUE; DBUG_PRINT("info", ("initializing next_auto_inc_val to %lu", - (ulong) ha_data->next_auto_inc_val)); + (ulong) table_share->ha_part_data->next_auto_inc_val)); } } unlock_auto_increment(); @@ -5297,7 +5296,7 @@ int ha_partition::info(uint flag) } -void ha_partition::get_dynamic_partition_info(PARTITION_INFO *stat_info, +void ha_partition::get_dynamic_partition_info(PARTITION_STATS *stat_info, uint part_id) { handler *file= m_file[part_id]; @@ -6512,11 +6511,10 @@ int ha_partition::reset_auto_increment(ulonglong value) { handler **file= m_file; int res; - HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; DBUG_ENTER("ha_partition::reset_auto_increment"); lock_auto_increment(); - ha_data->auto_inc_initialized= FALSE; - ha_data->next_auto_inc_val= 0; + table_share->ha_part_data->auto_inc_initialized= FALSE; + table_share->ha_part_data->next_auto_inc_val= 0; do { if ((res= (*file)->ha_reset_auto_increment(value)) != 0) @@ -6530,7 +6528,7 @@ int ha_partition::reset_auto_increment(ulonglong value) /** This method is called by update_auto_increment which in turn is called by the individual handlers as part of write_row. We use the - table_share->ha_data->next_auto_inc_val, or search all + table_share->ha_part_data->next_auto_inc_val, or search all partitions for the highest auto_increment_value if not initialized or if auto_increment field is a secondary part of a key, we must search every partition when holding a mutex to be sure of correctness. @@ -6583,13 +6581,12 @@ void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment, else { THD *thd= ha_thd(); - HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; /* This is initialized in the beginning of the first write_row call. */ - DBUG_ASSERT(ha_data->auto_inc_initialized); + DBUG_ASSERT(table_share->ha_part_data->auto_inc_initialized); /* - Get a lock for handling the auto_increment in table_share->ha_data + Get a lock for handling the auto_increment in table_share->ha_part_data for avoiding two concurrent statements getting the same number. */ @@ -6616,8 +6613,9 @@ void ha_partition::get_auto_increment(ulonglong offset, ulonglong increment, } /* this gets corrected (for offset/increment) in update_auto_increment */ - *first_value= ha_data->next_auto_inc_val; - ha_data->next_auto_inc_val+= nb_desired_values * increment; + *first_value= table_share->ha_part_data->next_auto_inc_val; + table_share->ha_part_data->next_auto_inc_val+= + nb_desired_values * increment; unlock_auto_increment(); DBUG_PRINT("info", ("*first_value: %lu", (ulong) *first_value)); @@ -6637,10 +6635,9 @@ void ha_partition::release_auto_increment() } else if (next_insert_id) { - HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; ulonglong next_auto_inc_val; lock_auto_increment(); - next_auto_inc_val= ha_data->next_auto_inc_val; + next_auto_inc_val= table_share->ha_part_data->next_auto_inc_val; /* If the current auto_increment values is lower than the reserved value, and the reserved value was reserved by this thread, @@ -6655,10 +6652,10 @@ void ha_partition::release_auto_increment() with SET INSERT_ID, i.e. forced/non generated values. */ if (thd->auto_inc_intervals_forced.maximum() < next_insert_id) - ha_data->next_auto_inc_val= next_insert_id; + table_share->ha_part_data->next_auto_inc_val= next_insert_id; } - DBUG_PRINT("info", ("ha_data->next_auto_inc_val: %lu", - (ulong) ha_data->next_auto_inc_val)); + DBUG_PRINT("info", ("table_share->ha_part_data->next_auto_inc_val: %lu", + (ulong) table_share->ha_part_data->next_auto_inc_val)); /* Unlock the multi row statement lock taken in get_auto_increment */ if (auto_increment_safe_stmt_log_lock) @@ -6758,127 +6755,6 @@ int ha_partition::indexes_are_disabled(void) } -/**************************************************************************** - MODULE Partition Share -****************************************************************************/ -/* - Service routines for ... methods. -------------------------------------------------------------------------- - Variables for partition share methods. A hash used to track open tables. - A mutex for the hash table and an init variable to check if hash table - is initialized. - There is also a constant ending of the partition handler file name. -*/ - -#ifdef NOT_USED -static HASH partition_open_tables; -static mysql_mutex_t partition_mutex; -static int partition_init= 0; - - -/* - Function we use in the creation of our hash to get key. -*/ - -static uchar *partition_get_key(PARTITION_SHARE *share, size_t *length, - my_bool not_used __attribute__ ((unused))) -{ - *length= share->table_name_length; - return (uchar *) share->table_name; -} - -/* - Example of simple lock controls. The "share" it creates is structure we - will pass to each partition handler. Do you have to have one of these? - Well, you have pieces that are used for locking, and they are needed to - function. -*/ - -static PARTITION_SHARE *get_share(const char *table_name, TABLE *table) -{ - PARTITION_SHARE *share; - uint length; - char *tmp_name; - - /* - So why does this exist? There is no way currently to init a storage - engine. - Innodb and BDB both have modifications to the server to allow them to - do this. Since you will not want to do this, this is probably the next - best method. - */ - if (!partition_init) - { - /* Hijack a mutex for init'ing the storage engine */ - mysql_mutex_lock(&LOCK_mysql_create_db); - if (!partition_init) - { - partition_init++; - mysql_mutex_init(INSTRUMENT_ME, &partition_mutex, MY_MUTEX_INIT_FAST); - (void) hash_init(&partition_open_tables, system_charset_info, 32, 0, 0, - (hash_get_key) partition_get_key, 0, 0); - } - mysql_mutex_unlock(&LOCK_mysql_create_db); - } - mysql_mutex_lock(&partition_mutex); - length= (uint) strlen(table_name); - - if (!(share= (PARTITION_SHARE *) hash_search(&partition_open_tables, - (uchar *) table_name, length))) - { - if (!(share= (PARTITION_SHARE *) - my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), - &share, (uint) sizeof(*share), - &tmp_name, (uint) length + 1, NullS))) - { - mysql_mutex_unlock(&partition_mutex); - return NULL; - } - - share->use_count= 0; - share->table_name_length= length; - share->table_name= tmp_name; - strmov(share->table_name, table_name); - if (my_hash_insert(&partition_open_tables, (uchar *) share)) - goto error; - thr_lock_init(&share->lock); - mysql_mutex_init(INSTRUMENT_ME, &share->mutex, MY_MUTEX_INIT_FAST); - } - share->use_count++; - mysql_mutex_unlock(&partition_mutex); - - return share; - -error: - mysql_mutex_unlock(&partition_mutex); - my_free((uchar*) share, MYF(0)); - - return NULL; -} - - -/* - Free lock controls. We call this whenever we close a table. If the table - had the last reference to the share then we free memory associated with - it. -*/ - -static int free_share(PARTITION_SHARE *share) -{ - mysql_mutex_lock(&partition_mutex); - if (!--share->use_count) - { - hash_delete(&partition_open_tables, (uchar *) share); - thr_lock_delete(&share->lock); - mysql_mutex_destroy(&share->mutex); - my_free((uchar*) share, MYF(0)); - } - mysql_mutex_unlock(&partition_mutex); - - return 0; -} -#endif /* NOT_USED */ - struct st_mysql_storage_engine partition_storage_engine= { MYSQL_HANDLERTON_INTERFACE_VERSION }; diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 9f499e7b4a9..eec3cb71537 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -29,31 +29,6 @@ enum partition_keywords PKW_COLUMNS }; -/* - PARTITION_SHARE is a structure that will be shared amoung all open handlers - The partition implements the minimum of what you will probably need. -*/ - -#ifdef NOT_USED -typedef struct st_partition_share -{ - char *table_name; - uint table_name_length, use_count; - mysql_mutex_t mutex; - THR_LOCK lock; -} PARTITION_SHARE; -#endif - -/** - Partition specific ha_data struct. - @todo: move all partition specific data from TABLE_SHARE here. -*/ -typedef struct st_ha_data_partition -{ - ulonglong next_auto_inc_val; /**< first non reserved value */ - bool auto_inc_initialized; - pthread_mutex_t mutex; -} HA_DATA_PARTITION; #define PARTITION_BYTES_IN_POS 2 #define PARTITION_ENABLED_TABLE_FLAGS (HA_FILE_BASED | HA_REC_NOT_IN_SEQ) @@ -522,7 +497,7 @@ public: ------------------------------------------------------------------------- */ virtual int info(uint); - void get_dynamic_partition_info(PARTITION_INFO *stat_info, + void get_dynamic_partition_info(PARTITION_STATS *stat_info, uint part_id); virtual int extra(enum ha_extra_function operation); virtual int extra_opt(enum ha_extra_function operation, ulong cachesize); @@ -944,16 +919,16 @@ private: /* lock already taken */ if (auto_increment_safe_stmt_log_lock) return; - DBUG_ASSERT(table_share->ha_data && !auto_increment_lock); + DBUG_ASSERT(table_share->ha_part_data && !auto_increment_lock); if(table_share->tmp_table == NO_TMP_TABLE) { auto_increment_lock= TRUE; - mysql_mutex_lock(&table_share->LOCK_ha_data); + mysql_mutex_lock(&table_share->ha_part_data->LOCK_auto_inc); } } virtual void unlock_auto_increment() { - DBUG_ASSERT(table_share->ha_data); + DBUG_ASSERT(table_share->ha_part_data); /* If auto_increment_safe_stmt_log_lock is true, we have to keep the lock. It will be set to false and thus unlocked at the end of the statement by @@ -961,20 +936,19 @@ private: */ if(auto_increment_lock && !auto_increment_safe_stmt_log_lock) { - mysql_mutex_unlock(&table_share->LOCK_ha_data); + mysql_mutex_unlock(&table_share->ha_part_data->LOCK_auto_inc); auto_increment_lock= FALSE; } } virtual void set_auto_increment_if_higher(Field *field) { - HA_DATA_PARTITION *ha_data= (HA_DATA_PARTITION*) table_share->ha_data; ulonglong nr= (((Field_num*) field)->unsigned_flag || field->val_int() > 0) ? field->val_int() : 0; lock_auto_increment(); - DBUG_ASSERT(ha_data->auto_inc_initialized == TRUE); + DBUG_ASSERT(table_share->ha_part_data->auto_inc_initialized == TRUE); /* must check when the mutex is taken */ - if (nr >= ha_data->next_auto_inc_val) - ha_data->next_auto_inc_val= nr + 1; + if (nr >= table_share->ha_part_data->next_auto_inc_val) + table_share->ha_part_data->next_auto_inc_val= nr + 1; unlock_auto_increment(); } diff --git a/sql/handler.cc b/sql/handler.cc index d641133c57a..11f684a8010 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -299,13 +299,14 @@ handler *get_ha_partition(partition_info *part_info) #endif -const char **handler_errmsgs; +static const char **handler_errmsgs; - -const char **get_handler_errmsgs() +C_MODE_START +static const char **get_handler_errmsgs() { return handler_errmsgs; } +C_MODE_END /** @@ -1249,7 +1250,14 @@ end: /** @note This function does not care about global read lock. A caller should. + + @param[in] all Is set in case of explicit commit + (COMMIT statement), or implicit commit + issued by DDL. Is not set when called + at the end of statement, even if + autocommit=1. */ + int ha_commit_one_phase(THD *thd, bool all) { int error=0; @@ -1257,9 +1265,15 @@ int ha_commit_one_phase(THD *thd, bool all) /* "real" is a nick name for a transaction for which a commit will make persistent changes. E.g. a 'stmt' transaction inside a 'all' - transation is not 'real': even though it's possible to commit it, + transaction is not 'real': even though it's possible to commit it, the changes are not durable as they might be rolled back if the enclosing 'all' transaction is rolled back. + We establish the value of 'is_real_trans' by checking + if it's an explicit COMMIT/BEGIN statement, or implicit + commit issued by DDL (all == TRUE), or if we're running + in autocommit mode (it's only in the autocommit mode + ha_commit_one_phase() can be called with an empty + transaction.all.ha_list, see why in trans_register_ha()). */ bool is_real_trans=all || thd->transaction.all.ha_list == 0; Ha_trx_info *ha_info= trans->ha_list, *ha_info_next; @@ -1307,9 +1321,15 @@ int ha_rollback_trans(THD *thd, bool all) /* "real" is a nick name for a transaction for which a commit will make persistent changes. E.g. a 'stmt' transaction inside a 'all' - transation is not 'real': even though it's possible to commit it, + transaction is not 'real': even though it's possible to commit it, the changes are not durable as they might be rolled back if the enclosing 'all' transaction is rolled back. + We establish the value of 'is_real_trans' by checking + if it's an explicit COMMIT or BEGIN statement, or implicit + commit issued by DDL (in these cases all == TRUE), + or if we're running in autocommit mode (it's only in the autocommit mode + ha_commit_one_phase() is called with an empty + transaction.all.ha_list, see why in trans_register_ha()). */ bool is_real_trans=all || thd->transaction.all.ha_list == 0; DBUG_ENTER("ha_rollback_trans"); @@ -1362,7 +1382,7 @@ int ha_rollback_trans(THD *thd, bool all) if (all) thd->variables.tx_isolation=thd->session_tx_isolation; } - /* Always cleanup. Even if there nht==0. There may be savepoints. */ + /* Always cleanup. Even if nht==0. There may be savepoints. */ if (is_real_trans) thd->transaction.cleanup(); if (all) @@ -3533,7 +3553,7 @@ int handler::index_next_same(uchar *buf, const uchar *key, uint keylen) } -void handler::get_dynamic_partition_info(PARTITION_INFO *stat_info, +void handler::get_dynamic_partition_info(PARTITION_STATS *stat_info, uint part_id) { info(HA_STATUS_CONST | HA_STATUS_TIME | HA_STATUS_VARIABLE | diff --git a/sql/handler.h b/sql/handler.h index 4464f4f3920..ad26534d91d 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -961,7 +961,7 @@ typedef struct { ulong check_time; ulong update_time; ulonglong check_sum; -} PARTITION_INFO; +} PARTITION_STATS; #define UNDEF_NODEGROUP 65535 class Item; @@ -1560,7 +1560,7 @@ public: { return (ha_rows) 10; } virtual void position(const uchar *record)=0; virtual int info(uint)=0; // see my_base.h for full description - virtual void get_dynamic_partition_info(PARTITION_INFO *stat_info, + virtual void get_dynamic_partition_info(PARTITION_STATS *stat_info, uint part_id); virtual int extra(enum ha_extra_function operation) { return 0; } diff --git a/sql/init.cc b/sql/init.cc index c72787300b7..e43b12787ab 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -33,7 +33,7 @@ void unireg_init(ulong options) { DBUG_ENTER("unireg_init"); - MYSYS_PROGRAM_DONT_USE_CURSES(); + error_handler_hook = my_message_stderr; abort_loop=0; my_disable_async_io=1; /* aioread is only in shared library */ diff --git a/sql/item.cc b/sql/item.cc index 5905c3ee090..c59a17a0ea3 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1,4 +1,4 @@ -/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc. +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. 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 @@ -3434,9 +3434,9 @@ Item_param::set_param_type_and_swap_value(Item_param *src) bool Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it) { - Item *value= *it; + Item *arg= *it; - if (value->is_null()) + if (arg->is_null()) { set_null(); return FALSE; @@ -3444,12 +3444,12 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it) null_value= FALSE; - switch (value->result_type()) { + switch (arg->result_type()) { case STRING_RESULT: { char str_buffer[STRING_BUFFER_USUAL_SIZE]; String sv_buffer(str_buffer, sizeof(str_buffer), &my_charset_bin); - String *sv= value->val_str(&sv_buffer); + String *sv= arg->val_str(&sv_buffer); if (!sv) return TRUE; @@ -3466,19 +3466,19 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it) } case REAL_RESULT: - set_double(value->val_real()); + set_double(arg->val_real()); param_type= MYSQL_TYPE_DOUBLE; break; case INT_RESULT: - set_int(value->val_int(), value->max_length); + set_int(arg->val_int(), arg->max_length); param_type= MYSQL_TYPE_LONG; break; case DECIMAL_RESULT: { my_decimal dv_buf; - my_decimal *dv= value->val_decimal(&dv_buf); + my_decimal *dv= arg->val_decimal(&dv_buf); if (!dv) return TRUE; @@ -3498,8 +3498,8 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it) return FALSE; } - item_result_type= value->result_type(); - item_type= value->type(); + item_result_type= arg->result_type(); + item_type= arg->type(); return FALSE; } @@ -7431,7 +7431,7 @@ void Item_cache_int::store(Item *item, longlong val_arg) String *Item_cache_int::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if (!has_value()) return NULL; str->set(value, default_charset()); return str; @@ -7441,7 +7441,7 @@ String *Item_cache_int::val_str(String *str) my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if (!has_value()) return NULL; int2my_decimal(E_DEC_FATAL_ERROR, value, unsigned_flag, decimal_val); return decimal_val; @@ -7450,7 +7450,7 @@ my_decimal *Item_cache_int::val_decimal(my_decimal *decimal_val) double Item_cache_int::val_real() { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if (!has_value()) return 0.0; return (double) value; } @@ -7458,7 +7458,7 @@ double Item_cache_int::val_real() longlong Item_cache_int::val_int() { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if (!has_value()) return 0; return value; } @@ -7514,7 +7514,7 @@ String *Item_cache_datetime::val_str(String *str) my_decimal *Item_cache_datetime::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value_int()) + if (!has_value()) return NULL; int2my_decimal(E_DEC_FATAL_ERROR, int_value, unsigned_flag, decimal_val); return decimal_val; @@ -7550,7 +7550,7 @@ bool Item_cache_real::cache_value() double Item_cache_real::val_real() { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if (!has_value()) return 0.0; return value; } @@ -7558,7 +7558,7 @@ double Item_cache_real::val_real() longlong Item_cache_real::val_int() { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if (!has_value()) return 0; return (longlong) rint(value); } @@ -7567,7 +7567,7 @@ longlong Item_cache_real::val_int() String* Item_cache_real::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if (!has_value()) return NULL; str->set_real(value, decimals, default_charset()); return str; @@ -7577,7 +7577,7 @@ String* Item_cache_real::val_str(String *str) my_decimal *Item_cache_real::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if (!has_value()) return NULL; double2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); return decimal_val; @@ -7599,7 +7599,7 @@ double Item_cache_decimal::val_real() { DBUG_ASSERT(fixed); double res; - if (!value_cached && !cache_value()) + if (!has_value()) return 0.0; my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &res); return res; @@ -7609,7 +7609,7 @@ longlong Item_cache_decimal::val_int() { DBUG_ASSERT(fixed); longlong res; - if (!value_cached && !cache_value()) + if (!has_value()) return 0; my_decimal2int(E_DEC_FATAL_ERROR, &decimal_value, unsigned_flag, &res); return res; @@ -7618,7 +7618,7 @@ longlong Item_cache_decimal::val_int() String* Item_cache_decimal::val_str(String *str) { DBUG_ASSERT(fixed); - if (!value_cached && !cache_value()) + if (!has_value()) return NULL; my_decimal_round(E_DEC_FATAL_ERROR, &decimal_value, decimals, FALSE, &decimal_value); @@ -7629,7 +7629,7 @@ String* Item_cache_decimal::val_str(String *str) my_decimal *Item_cache_decimal::val_decimal(my_decimal *val) { DBUG_ASSERT(fixed); - if (!value_cached && !cache_value()) + if (!has_value()) return NULL; return &decimal_value; } @@ -7665,7 +7665,7 @@ double Item_cache_str::val_real() DBUG_ASSERT(fixed == 1); int err_not_used; char *end_not_used; - if (!value_cached && !cache_value()) + if (!has_value()) return 0.0; if (value) return my_strntod(value->charset(), (char*) value->ptr(), @@ -7678,7 +7678,7 @@ longlong Item_cache_str::val_int() { DBUG_ASSERT(fixed == 1); int err; - if (!value_cached && !cache_value()) + if (!has_value()) return 0; if (value) return my_strntoll(value->charset(), value->ptr(), @@ -7691,7 +7691,7 @@ longlong Item_cache_str::val_int() String* Item_cache_str::val_str(String *str) { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if (!has_value()) return 0; return value; } @@ -7700,7 +7700,7 @@ String* Item_cache_str::val_str(String *str) my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) { DBUG_ASSERT(fixed == 1); - if (!value_cached && !cache_value()) + if (!has_value()) return NULL; if (value) string2my_decimal(E_DEC_FATAL_ERROR, value, decimal_val); @@ -7712,7 +7712,7 @@ my_decimal *Item_cache_str::val_decimal(my_decimal *decimal_val) int Item_cache_str::save_in_field(Field *field, bool no_conversions) { - if (!value_cached && !cache_value()) + if (!has_value()) return 0; int res= Item_cache::save_in_field(field, no_conversions); return (is_varbinary && field->type() == MYSQL_TYPE_STRING && diff --git a/sql/item.h b/sql/item.h index 5f4f96f97d3..e18fa43037a 100644 --- a/sql/item.h +++ b/sql/item.h @@ -34,6 +34,15 @@ void item_init(void); /* Init item functions */ class Item_field; class user_var_entry; + +static inline uint32 +char_to_byte_length_safe(uint32 char_length_arg, uint32 mbmaxlen_arg) +{ + ulonglong tmp= ((ulonglong) char_length_arg) * mbmaxlen_arg; + return (tmp > UINT_MAX32) ? (uint32) UINT_MAX32 : (uint32) tmp; +} + + /* "Declared Type Collation" A combination of collation and its derivation. @@ -1171,16 +1180,23 @@ public: { return max_length / collation.collation->mbmaxlen; } void fix_length_and_charset(uint32 max_char_length_arg, CHARSET_INFO *cs) { - max_length= max_char_length_arg * cs->mbmaxlen; + max_length= char_to_byte_length_safe(max_char_length_arg, cs->mbmaxlen); collation.collation= cs; } void fix_char_length(uint32 max_char_length_arg) - { max_length= max_char_length_arg * collation.collation->mbmaxlen; } + { + max_length= char_to_byte_length_safe(max_char_length_arg, + collation.collation->mbmaxlen); + } void fix_length_and_charset_datetime(uint32 max_char_length_arg) { collation.set(&my_charset_numeric, DERIVATION_NUMERIC, MY_REPERTOIRE_ASCII); fix_char_length(max_char_length_arg); } + /* + Return TRUE if the item points to a column of an outer-joined table. + */ + virtual bool is_outer_field() const { DBUG_ASSERT(fixed); return FALSE; } }; @@ -1694,6 +1710,11 @@ public: int fix_outer_field(THD *thd, Field **field, Item **reference); virtual Item *update_value_transformer(uchar *select_arg); virtual void print(String *str, enum_query_type query_type); + bool is_outer_field() const + { + DBUG_ASSERT(fixed); + return field->table->pos_in_table_list->outer_join; + } Field::geometry_type get_geometry_type() const { DBUG_ASSERT(field_type() == MYSQL_TYPE_GEOMETRY); @@ -2506,7 +2527,13 @@ public: DBUG_ASSERT(fixed); return (*ref)->get_time(ltime); } - bool basic_const_item() { return (*ref)->basic_const_item(); } + virtual bool basic_const_item() const { return (*ref)->basic_const_item(); } + bool is_outer_field() const + { + DBUG_ASSERT(fixed); + DBUG_ASSERT(ref); + return (*ref)->is_outer_field(); + } }; @@ -3191,6 +3218,15 @@ public: { return this == item; } + /** + Check if saved item has a non-NULL value. + Will cache value of saved item if not already done. + @return TRUE if cached value is non-NULL. + */ + bool has_value() + { + return (value_cached || cache_value()) && !null_value; + } virtual void store(Item *item); virtual bool cache_value()= 0; bool basic_const_item() const @@ -3358,6 +3394,7 @@ public: cmp_context= STRING_RESULT; } + virtual void store(Item *item) { Item_cache::store(item); } void store(Item *item, longlong val_arg); double val_real(); longlong val_int(); diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 19e8385539f..3c871bc0663 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -5466,7 +5466,21 @@ void Item_equal::update_const() Item *item; while ((item= it++)) { - if (item->const_item()) + if (item->const_item() && + /* + Don't propagate constant status of outer-joined column. + Such a constant status here is a result of: + a) empty outer-joined table: in this case such a column has a + value of NULL; but at the same time other arguments of + Item_equal don't have to be NULLs and the value of the whole + multiple equivalence expression doesn't have to be NULL or FALSE + because of the outer join nature; + or + b) outer-joined table contains only 1 row: the result of + this column is equal to a row field value *or* NULL. + Both values are inacceptable as Item_equal constants. + */ + !item->is_outer_field()) { it.remove(); add(item); @@ -5505,7 +5519,8 @@ void Item_equal::update_used_tables() { item->update_used_tables(); used_tables_cache|= item->used_tables(); - const_item_cache&= item->const_item(); + /* see commentary at Item_equal::update_const() */ + const_item_cache&= item->const_item() && !item->is_outer_field(); } } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 917acb0e908..15927c4b11e 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2827,6 +2827,7 @@ String *Item_sum_udf_str::val_str(String *str) @retval 1 : key1 > key2 */ +extern "C" int group_concat_key_cmp_with_distinct(void* arg, const void* key1, const void* key2) { @@ -2861,6 +2862,7 @@ int group_concat_key_cmp_with_distinct(void* arg, const void* key1, function of sort for syntax: GROUP_CONCAT(expr,... ORDER BY col,... ) */ +extern "C" int group_concat_key_cmp_with_order(void* arg, const void* key1, const void* key2) { @@ -2905,13 +2907,16 @@ int group_concat_key_cmp_with_order(void* arg, const void* key1, Append data from current leaf to item->result. */ -int dump_leaf_key(uchar* key, element_count count __attribute__((unused)), - Item_func_group_concat *item) +extern "C" +int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)), + void* item_arg) { + Item_func_group_concat *item= (Item_func_group_concat *) item_arg; TABLE *table= item->table; String tmp((char *)table->record[1], table->s->reclength, default_charset_info); String tmp2; + uchar *key= (uchar *) key_arg; String *result= &item->result; Item **arg= item->args, **arg_end= item->args + item->arg_count_field; uint old_length= result->length(); @@ -3385,8 +3390,7 @@ String* Item_func_group_concat::val_str(String* str) return 0; if (no_appended && tree) /* Tree is used for sorting as in ORDER BY */ - tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this, - left_root_right); + tree_walk(tree, &dump_leaf_key, this, left_root_right); return &result; } diff --git a/sql/item_sum.h b/sql/item_sum.h index 5f2c4f166e6..99fcb14d160 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -303,6 +303,8 @@ class st_select_lex; class Item_sum :public Item_result_field { + friend class Aggregator_distinct; + protected: /** Aggregator class instance. Not set initially. Allocated only after @@ -1317,6 +1319,16 @@ public: #endif /* HAVE_DLOPEN */ +C_MODE_START +int group_concat_key_cmp_with_distinct(void* arg, const void* key1, + const void* key2); +int group_concat_key_cmp_with_order(void* arg, const void* key1, + const void* key2); +int dump_leaf_key(void* key_arg, + element_count count __attribute__((unused)), + void* item_arg); +C_MODE_END + class Item_func_group_concat : public Item_sum { TMP_TABLE_PARAM *tmp_table_param; @@ -1356,9 +1368,9 @@ class Item_func_group_concat : public Item_sum const void* key2); friend int group_concat_key_cmp_with_order(void* arg, const void* key1, const void* key2); - friend int dump_leaf_key(uchar* key, + friend int dump_leaf_key(void* key_arg, element_count count __attribute__((unused)), - Item_func_group_concat *group_concat_item); + void* item_arg); public: Item_func_group_concat(Name_resolution_context *context_arg, diff --git a/sql/key.cc b/sql/key.cc index d593850ca10..582334620ad 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -354,6 +354,16 @@ void key_unpack(String *to,TABLE *table,uint idx) { CHARSET_INFO *cs= field->charset(); field->val_str(&tmp); + /* + For BINARY(N) strip trailing zeroes to make + the error message nice-looking + */ + if (field->binary() && field->type() == MYSQL_TYPE_STRING && tmp.length()) + { + const char *tmp_end= tmp.ptr() + tmp.length(); + while (tmp_end > tmp.ptr() && !*--tmp_end); + tmp.length(tmp_end - tmp.ptr() + 1); + } if (cs->mbmaxlen > 1 && table->field[key_part->fieldnr - 1]->field_length != key_part->length) diff --git a/sql/lock.cc b/sql/lock.cc index 758ea6cf914..3f13f15454a 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -533,20 +533,6 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table) } } -/* Downgrade all locks on a table to new WRITE level from WRITE_ONLY */ - -void mysql_lock_downgrade_write(THD *thd, TABLE *table, - thr_lock_type new_lock_type) -{ - MYSQL_LOCK *locked; - if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK))) - { - for (uint i=0; i < locked->lock_count; i++) - thr_downgrade_write_lock(locked->locks[i], new_lock_type); - my_free((uchar*) locked,MYF(0)); - } -} - /** Abort all other threads waiting to get lock in table. */ diff --git a/sql/lock.h b/sql/lock.h index 19b23f1f42b..f7c19913675 100644 --- a/sql/lock.h +++ b/sql/lock.h @@ -53,52 +53,22 @@ typedef struct st_mysql_lock MYSQL_LOCK; MYSQL_OPEN_HAS_MDL_LOCK) -#include "thr_lock.h" /* thr_lock_type */ - -struct TABLE_LIST; -class THD; -struct TABLE; -typedef struct st_mysql_lock MYSQL_LOCK; - MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags); void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count); void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table); void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock); -void mysql_lock_downgrade_write(THD *thd, TABLE *table, - thr_lock_type new_lock_type); bool mysql_lock_abort_for_thread(THD *thd, TABLE *table); MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b); TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle, TABLE_LIST *haystack); -bool lock_global_read_lock(THD *thd); -void unlock_global_read_lock(THD *thd); -bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, - bool is_not_commit); -void start_waiting_global_read_lock(THD *thd); -bool make_global_read_lock_block_commit(THD *thd); -bool set_protect_against_global_read_lock(void); -void unset_protect_against_global_read_lock(void); -/* Lock based on stored routine name */ -bool lock_routine_name(THD *thd, bool is_function, const char *db, - const char *name); void broadcast_refresh(void); - /* Lock based on name */ -int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list); -int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use); -void unlock_table_name(THD *thd, TABLE_LIST *table_list); -bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list); bool lock_table_names(THD *thd, TABLE_LIST *table_list); void unlock_table_names(THD *thd); -bool lock_table_names_exclusively(THD *thd, TABLE_LIST *table_list); -bool is_table_name_exclusively_locked_by_this_thread(THD *thd, - TABLE_LIST *table_list); -bool is_table_name_exclusively_locked_by_this_thread(THD *thd, uchar *key, - int key_length); -void broadcast_refresh(void); - - +/* Lock based on stored routine name */ +bool lock_routine_name(THD *thd, bool is_function, const char *db, + const char *name); #endif /* LOCK_INCLUDED */ diff --git a/sql/log.cc b/sql/log.cc index a80e054178f..fd17e04b212 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1669,7 +1669,7 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all) DBUG_PRINT("debug", ("all: %d, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s", all, - YESNO(thd->in_multi_stmt_transaction()), + YESNO(thd->in_multi_stmt_transaction_mode()), YESNO(thd->transaction.all.modified_non_trans_table), YESNO(thd->transaction.stmt.modified_non_trans_table))); @@ -4254,7 +4254,7 @@ bool use_trans_cache(const THD* thd, bool is_transactional) */ bool ending_trans(THD* thd, const bool all) { - return (all || (!all && !thd->in_multi_stmt_transaction())); + return (all || (!all && !thd->in_multi_stmt_transaction_mode())); } /** @@ -4357,7 +4357,7 @@ THD::binlog_start_trans_and_stmt() cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF) { this->binlog_set_stmt_begin(); - if (in_multi_stmt_transaction()) + if (in_multi_stmt_transaction_mode()) trans_register_ha(this, TRUE, binlog_hton); trans_register_ha(this, FALSE, binlog_hton); /* diff --git a/sql/log_event.cc b/sql/log_event.cc index 5b2b86a9e42..cefc49f8c8a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -2465,95 +2465,62 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, else time_zone_len= 0; + LEX *lex= thd->lex; /* - In what follows, we decide whether to write to the binary log or to use a - cache. + TRUE defines that either a trx-cache or stmt-cache must be used + and wrapped by a BEGIN...COMMIT. Otherwise, the statement will + be written directly to the binary log without being wrapped by + a BEGIN...COMMIT. + + Note that a cache will not be used if the parameter direct is + TRUE. */ - LEX *lex= thd->lex; - bool implicit_commit= FALSE; - bool force_trans= FALSE; + bool use_cache= FALSE; + /* + TRUE defines that the trx-cache must be used and by consequence + the use_cache is TRUE. + + Note that a cache will not be used if the parameter direct is + TRUE. + */ + bool trx_cache= FALSE; cache_type= Log_event::EVENT_INVALID_CACHE; + switch (lex->sql_command) { - case SQLCOM_ALTER_DB: - case SQLCOM_CREATE_FUNCTION: - case SQLCOM_DROP_FUNCTION: - case SQLCOM_DROP_PROCEDURE: - case SQLCOM_INSTALL_PLUGIN: - case SQLCOM_UNINSTALL_PLUGIN: - case SQLCOM_ALTER_TABLESPACE: - implicit_commit= TRUE; - break; case SQLCOM_DROP_TABLE: - force_trans= lex->drop_temporary && thd->in_multi_stmt_transaction(); - implicit_commit= !force_trans; - break; - case SQLCOM_ALTER_TABLE: + use_cache= trx_cache= (lex->drop_temporary && + thd->in_multi_stmt_transaction_mode()); + break; + case SQLCOM_CREATE_TABLE: - force_trans= (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) && - thd->in_multi_stmt_transaction(); - implicit_commit= !force_trans && - !(lex->select_lex.item_list.elements && - thd->is_current_stmt_binlog_format_row()); + use_cache= trx_cache= + ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) && + thd->in_multi_stmt_transaction_mode()) || + (lex->select_lex.item_list.elements && + thd->is_current_stmt_binlog_format_row()); break; case SQLCOM_SET_OPTION: - implicit_commit= (lex->autocommit ? TRUE : FALSE); - break; - /* - Replace what follows after CF_AUTO_COMMIT_TRANS is backported by: - - default: - implicit_commit= ((sql_command_flags[lex->sql_command] & - CF_AUTO_COMMIT_TRANS)); + use_cache= trx_cache= (lex->autocommit ? FALSE : TRUE); break; - */ - case SQLCOM_CREATE_INDEX: - case SQLCOM_TRUNCATE: - case SQLCOM_CREATE_DB: - case SQLCOM_DROP_DB: - case SQLCOM_ALTER_DB_UPGRADE: - case SQLCOM_RENAME_TABLE: - case SQLCOM_DROP_INDEX: - case SQLCOM_CREATE_VIEW: - case SQLCOM_DROP_VIEW: - case SQLCOM_CREATE_TRIGGER: - case SQLCOM_DROP_TRIGGER: - case SQLCOM_CREATE_EVENT: - case SQLCOM_ALTER_EVENT: - case SQLCOM_DROP_EVENT: - case SQLCOM_REPAIR: - case SQLCOM_OPTIMIZE: - case SQLCOM_ANALYZE: - case SQLCOM_CREATE_USER: - case SQLCOM_DROP_USER: - case SQLCOM_RENAME_USER: - case SQLCOM_REVOKE_ALL: - case SQLCOM_REVOKE: - case SQLCOM_GRANT: - case SQLCOM_CREATE_PROCEDURE: - case SQLCOM_CREATE_SPFUNCTION: - case SQLCOM_ALTER_PROCEDURE: - case SQLCOM_ALTER_FUNCTION: - case SQLCOM_ASSIGN_TO_KEYCACHE: - case SQLCOM_PRELOAD_KEYS: - case SQLCOM_FLUSH: - case SQLCOM_RESET: - case SQLCOM_CHECK: - implicit_commit= TRUE; + case SQLCOM_RELEASE_SAVEPOINT: + case SQLCOM_ROLLBACK_TO_SAVEPOINT: + case SQLCOM_SAVEPOINT: + use_cache= trx_cache= TRUE; break; default: - implicit_commit= FALSE; + use_cache= sqlcom_can_generate_row_events(thd); break; } - if (implicit_commit || direct) + if (!use_cache || direct) { cache_type= Log_event::EVENT_NO_CACHE; } else { - cache_type= ((using_trans || stmt_has_updated_trans_table(thd) || - force_trans || thd->thread_temporary_used) + cache_type= ((using_trans || stmt_has_updated_trans_table(thd) + || trx_cache || thd->thread_temporary_used) ? Log_event::EVENT_TRANSACTIONAL_CACHE : Log_event::EVENT_STMT_CACHE); } @@ -3351,11 +3318,12 @@ compare_errors: */ actual_error= thd->is_error() ? thd->stmt_da->sql_errno() : 0; DBUG_PRINT("info",("expected_error: %d sql_errno: %d", - expected_error, actual_error)); + expected_error, actual_error)); + if ((expected_error && expected_error != actual_error && !concurrency_error_code(expected_error)) && - !ignored_error_code(actual_error) && - !ignored_error_code(expected_error)) + !ignored_error_code(actual_error) && + !ignored_error_code(expected_error)) { rli->report(ERROR_LEVEL, 0, "\ @@ -3373,9 +3341,9 @@ Default database: '%s'. Query: '%s'", If we get the same error code as expected and it is not a concurrency issue, or should be ignored. */ - else if ((expected_error == actual_error && + else if ((expected_error == actual_error && !concurrency_error_code(expected_error)) || - ignored_error_code(actual_error)) + ignored_error_code(actual_error)) { DBUG_PRINT("info",("error ignored")); clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); @@ -3394,7 +3362,7 @@ Default database: '%s'. Query: '%s'", If we expected a non-zero error code and get nothing and, it is a concurrency issue or should be ignored. */ - else if (expected_error && !actual_error && + else if (expected_error && !actual_error && (concurrency_error_code(expected_error) || ignored_error_code(expected_error))) trans_rollback_stmt(thd); @@ -3435,12 +3403,13 @@ Default database: '%s'. Query: '%s'", */ } /* End of if (db_ok(... */ - {/** - The following failure injecion works in cooperation with tests + { + /** + The following failure injecion works in cooperation with tests setting @@global.debug= 'd,stop_slave_middle_group'. - The sql thread receives the killed status and will proceed + The sql thread receives the killed status and will proceed to shutdown trying to finish incomplete events group. - */ + */ DBUG_EXECUTE_IF("stop_slave_middle_group", if (strcmp("COMMIT", query) != 0 && strcmp("BEGIN", query) != 0) @@ -3455,7 +3424,7 @@ end: Probably we have set thd->query, thd->db, thd->catalog to point to places in the data_buf of this event. Now the event is going to be deleted probably, so data_buf will be freed, so the thd->... listed above will be - pointers to freed memory. + pointers to freed memory. So we must set them to 0, so that those bad pointers values are not later used. Note that "cleanup" queries like automatic DROP TEMPORARY TABLE don't suffer from these assignments to 0 as DROP TEMPORARY @@ -3465,7 +3434,7 @@ end: thd->set_db(NULL, 0); /* will free the current database */ thd->set_query(NULL, 0); DBUG_PRINT("info", ("end: query= 0")); - close_thread_tables(thd); + close_thread_tables(thd); /* As a disk space optimization, future masters will not log an event for LAST_INSERT_ID() if that function returned 0 (and thus they will be able @@ -3767,7 +3736,7 @@ Format_description_log_event(uint8 binlog_ver, const char* server_ver) */ if (post_header_len) { -#ifndef DBUG_OFF +#ifndef DBUG_OFF // Allows us to sanity-check that all events initialized their // events (see the end of this 'if' block). memset(post_header_len, 255, number_of_event_types*sizeof(uint8)); @@ -4223,7 +4192,7 @@ void Load_log_event::print_query(bool need_db, const char *cs, char *buf, pos= strmov(pos, "LOAD DATA "); - if (thd->lex->lock_option == TL_WRITE_CONCURRENT_INSERT) + if (is_concurrent) pos= strmov(pos, "CONCURRENT "); if (fn_start) @@ -4365,6 +4334,7 @@ bool Load_log_event::write_data_body(IO_CACHE* file) Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex, const char *db_arg, const char *table_name_arg, List<Item> &fields_arg, + bool is_concurrent_arg, enum enum_duplicates handle_dup, bool ignore, bool using_trans) :Log_event(thd_arg, @@ -4375,7 +4345,8 @@ Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex, num_fields(0),fields(0), field_lens(0),field_block_len(0), table_name(table_name_arg ? table_name_arg : ""), - db(db_arg), fname(ex->file_name), local_fname(FALSE) + db(db_arg), fname(ex->file_name), local_fname(FALSE), + is_concurrent(is_concurrent_arg) { time_t end_time; time(&end_time); @@ -4456,7 +4427,13 @@ Load_log_event::Load_log_event(const char *buf, uint event_len, const Format_description_log_event *description_event) :Log_event(buf, description_event), num_fields(0), fields(0), field_lens(0),field_block_len(0), - table_name(0), db(0), fname(0), local_fname(FALSE) + table_name(0), db(0), fname(0), local_fname(FALSE), + /* + Load_log_event which comes from the binary log does not contain + information about the type of insert which was used on the master. + Assume that it was an ordinary, non-concurrent LOAD DATA. + */ + is_concurrent(FALSE) { DBUG_ENTER("Load_log_event"); /* @@ -4613,9 +4590,9 @@ void Load_log_event::print(FILE* file_arg, PRINT_EVENT_INFO* print_event_info, for (i = 0; i < num_fields; i++) { if (i) - my_b_printf(&cache, ","); + my_b_printf(&cache, ","); my_b_printf(&cache, "%s", field); - + field += field_lens[i] + 1; } my_b_printf(&cache, ")"); @@ -4785,9 +4762,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, thd->set_query(load_data_query, (uint) (end - load_data_query)); if (sql_ex.opt_flags & REPLACE_FLAG) - { - handle_dup= DUP_REPLACE; - } + handle_dup= DUP_REPLACE; else if (sql_ex.opt_flags & IGNORE_FLAG) { ignore= 1; @@ -4796,14 +4771,14 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, else { /* - When replication is running fine, if it was DUP_ERROR on the + When replication is running fine, if it was DUP_ERROR on the master then we could choose IGNORE here, because if DUP_ERROR suceeded on master, and data is identical on the master and slave, then there should be no uniqueness errors on slave, so IGNORE is the same as DUP_ERROR. But in the unlikely case of uniqueness errors (because the data on the master and slave happen to be different - (user error or bug), we want LOAD DATA to print an error message on - the slave to discover the problem. + (user error or bug), we want LOAD DATA to print an error message on + the slave to discover the problem. If reading from net (a 3.23 master), mysql_load() will change this to IGNORE. @@ -4835,7 +4810,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG); if (sql_ex.empty_flags & FIELD_TERM_EMPTY) - ex.field_term->length(0); + ex.field_term->length(0); ex.skip_lines = skip_lines; List<Item> field_list; @@ -4844,12 +4819,10 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, thd->variables.pseudo_thread_id= thread_id; if (net) { - // mysql_load will use thd->net to read the file - thd->net.vio = net->vio; - /* - Make sure the client does not get confused about the packet sequence - */ - thd->net.pkt_nr = net->pkt_nr; + // mysql_load will use thd->net to read the file + thd->net.vio = net->vio; + // Make sure the client does not get confused about the packet sequence + thd->net.pkt_nr = net->pkt_nr; } /* It is safe to use tmp_list twice because we are not going to @@ -4861,7 +4834,7 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, thd->is_slave_error= 1; if (thd->cuted_fields) { - /* log_pos is the position of the LOAD event in the master log */ + /* log_pos is the position of the LOAD event in the master log */ sql_print_warning("Slave: load data infile on table '%s' at " "log position %s in log '%s' produced %ld " "warning(s). Default database: '%s'", @@ -5609,10 +5582,10 @@ User_var_log_event(const char* buf, { type= (Item_result) buf[UV_VAL_IS_NULL]; charset_number= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE); - val_len= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + - UV_CHARSET_NUMBER_SIZE); + val_len= uint4korr(buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + + UV_CHARSET_NUMBER_SIZE); val= (char *) (buf + UV_VAL_IS_NULL + UV_VAL_TYPE_SIZE + - UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE); + UV_CHARSET_NUMBER_SIZE + UV_VAL_LEN_SIZE); /** We need to check if this is from an old server @@ -5696,9 +5669,9 @@ bool User_var_log_event::write(IO_CACHE* file) return (write_header(file, event_length) || my_b_safe_write(file, (uchar*) buf, sizeof(buf)) || - my_b_safe_write(file, (uchar*) name, name_len) || - my_b_safe_write(file, (uchar*) buf1, buf1_length) || - my_b_safe_write(file, pos, val_len) || + my_b_safe_write(file, (uchar*) name, name_len) || + my_b_safe_write(file, (uchar*) buf1, buf1_length) || + my_b_safe_write(file, pos, val_len) || my_b_safe_write(file, &flags, unsigned_len)); } #endif @@ -5972,7 +5945,7 @@ Slave_log_event::Slave_log_event(THD* thd_arg, master_log_len = strlen(rli->group_master_log_name); // on OOM, just do not initialize the structure and print the error if ((mem_pool = (char*)my_malloc(get_data_size() + 1, - MYF(MY_WME)))) + MYF(MY_WME)))) { master_host = mem_pool + SL_MASTER_HOST_OFFSET ; memcpy(master_host, mi->host, master_host_len + 1); @@ -5981,7 +5954,7 @@ Slave_log_event::Slave_log_event(THD* thd_arg, master_port = mi->port; master_pos = rli->group_master_log_pos; DBUG_PRINT("info", ("master_log: %s pos: %lu", master_log, - (ulong) master_pos)); + (ulong) master_pos)); } else sql_print_error("Out of memory while recording slave event"); @@ -6146,11 +6119,14 @@ int Stop_log_event::do_update_pos(Relay_log_info *rli) Create_file_log_event:: Create_file_log_event(THD* thd_arg, sql_exchange* ex, const char* db_arg, const char* table_name_arg, - List<Item>& fields_arg, enum enum_duplicates handle_dup, + List<Item>& fields_arg, + bool is_concurrent_arg, + enum enum_duplicates handle_dup, bool ignore, uchar* block_arg, uint block_len_arg, bool using_trans) - :Load_log_event(thd_arg,ex,db_arg,table_name_arg,fields_arg,handle_dup, ignore, - using_trans), + :Load_log_event(thd_arg, ex, db_arg, table_name_arg, fields_arg, + is_concurrent_arg, + handle_dup, ignore, using_trans), fake_base(0), block(block_arg), event_buf(0), block_len(block_len_arg), file_id(thd_arg->file_id = mysql_bin_log.next_file_id()) { diff --git a/sql/log_event.h b/sql/log_event.h index 1b5c8968210..bd95c74b6c5 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -2091,6 +2091,17 @@ public: uint32 skip_lines; sql_ex_info sql_ex; bool local_fname; + /** + Indicates that this event corresponds to LOAD DATA CONCURRENT, + + @note Since Load_log_event event coming from the binary log + lacks information whether LOAD DATA on master was concurrent + or not, this flag is only set to TRUE for an auxiliary + Load_log_event object which is used in mysql_load() to + re-construct LOAD DATA statement from function parameters, + for logging. + */ + bool is_concurrent; /* fname doesn't point to memory inside Log_event::temp_buf */ void set_fname_outside_temp_buf(const char *afname, uint alen) @@ -2111,7 +2122,9 @@ public: Load_log_event(THD* thd, sql_exchange* ex, const char* db_arg, const char* table_name_arg, - List<Item>& fields_arg, enum enum_duplicates handle_dup, bool ignore, + List<Item>& fields_arg, + bool is_concurrent_arg, + enum enum_duplicates handle_dup, bool ignore, bool using_trans); void set_fields(const char* db, List<Item> &fields_arg, Name_resolution_context *context); @@ -2730,6 +2743,7 @@ public: Create_file_log_event(THD* thd, sql_exchange* ex, const char* db_arg, const char* table_name_arg, List<Item>& fields_arg, + bool is_concurrent_arg, enum enum_duplicates handle_dup, bool ignore, uchar* block_arg, uint block_len_arg, bool using_trans); diff --git a/sql/mdl.h b/sql/mdl.h index 2fb21a5aa18..89a679be264 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -718,7 +718,7 @@ void mdl_destroy(); extern bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use, bool needs_thr_lock_abort); extern void mysql_ha_flush(THD *thd); -extern "C" const char *set_thd_proc_info(THD *thd, const char *info, +extern "C" const char *set_thd_proc_info(void *thd_arg, const char *info, const char *calling_function, const char *calling_file, const unsigned int calling_line); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 20a168dc5ae..2770f056938 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -857,12 +857,15 @@ void Buffered_logs::print() /** Logs reported before a logger is available. */ static Buffered_logs buffered_logs; +#ifndef EMBEDDED_LIBRARY /** Error reporter that buffer log messages. @param level log message level @param format log message format string */ -void buffered_option_error_reporter(enum loglevel level, const char *format, ...) +C_MODE_START +static void buffered_option_error_reporter(enum loglevel level, + const char *format, ...) { va_list args; char buffer[1024]; @@ -872,6 +875,8 @@ void buffered_option_error_reporter(enum loglevel level, const char *format, ... va_end(args); buffered_logs.buffer(level, buffer); } +C_MODE_END +#endif /* !EMBEDDED_LIBRARY */ #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ static my_socket unix_sock,ip_sock; @@ -973,7 +978,6 @@ uint connection_count= 0; pthread_handler_t signal_hand(void *arg); static int mysql_init_variables(void); -extern "C" void option_error_reporter(enum loglevel level, const char *format, ...); static int get_options(int *argc_ptr, char ***argv_ptr); static bool add_terminator(DYNAMIC_ARRAY *options); extern "C" my_bool mysqld_get_one_option(int, const struct my_option *, char *); @@ -3608,7 +3612,6 @@ static int init_common_variables() if (item_create_init()) return 1; item_init(); - mysys_uses_curses=0; #ifdef USE_REGEX my_regex_init(&my_charset_latin1); #endif @@ -4028,9 +4031,8 @@ static int init_server_components() } } - proc_info_hook= (const char *(*)(void *, const char *, const char *, - const char *, const unsigned int)) - set_thd_proc_info; + proc_info_hook= set_thd_proc_info; + #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE /* Parsing the performance schema command line option may have reported @@ -5351,11 +5353,11 @@ inline void kill_broken_server() void handle_connections_sockets() { - my_socket sock,new_sock; + my_socket UNINIT_VAR(sock), UNINIT_VAR(new_sock); uint error_count=0; THD *thd; struct sockaddr_storage cAddr; - int ip_flags=0,socket_flags=0,flags,retval; + int ip_flags=0,socket_flags=0,flags=0,retval; st_vio *vio_tmp; #ifdef HAVE_POLL int socket_count= 0; @@ -5367,8 +5369,6 @@ void handle_connections_sockets() DBUG_ENTER("handle_connections_sockets"); - LINT_INIT(new_sock); - #ifndef HAVE_POLL FD_ZERO(&clientFDs); #endif @@ -7430,10 +7430,7 @@ mysqld_get_one_option(int optid, /** Handle arguments for multiple key caches. */ -extern "C" int mysql_getopt_value(uchar **value, - const char *keyname, uint key_length, - const struct my_option *option, - int *error); +C_MODE_START static uchar* * mysql_getopt_value(const char *keyname, uint key_length, @@ -7469,7 +7466,7 @@ mysql_getopt_value(const char *keyname, uint key_length, return option->value; } -void option_error_reporter(enum loglevel level, const char *format, ...) +static void option_error_reporter(enum loglevel level, const char *format, ...) { va_list args; va_start(args, format); @@ -7483,6 +7480,7 @@ void option_error_reporter(enum loglevel level, const char *format, ...) va_end(args); } +C_MODE_END /** Get server options from the command line, @@ -7983,8 +7981,9 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids, key_master_info_data_lock, key_master_info_run_lock, key_mutex_slave_reporting_capability_err_lock, key_relay_log_info_data_lock, key_relay_log_info_log_space_lock, key_relay_log_info_run_lock, - key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data, key_LOCK_error_messages, - key_LOG_INFO_lock, key_LOCK_thread_count; + key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data, + key_LOCK_error_messages, key_LOG_INFO_lock, key_LOCK_thread_count, + key_PARTITION_LOCK_auto_inc; static PSI_mutex_info all_server_mutexes[]= { @@ -8038,7 +8037,8 @@ static PSI_mutex_info all_server_mutexes[]= { &key_TABLE_SHARE_LOCK_ha_data, "TABLE_SHARE::LOCK_ha_data", 0}, { &key_LOCK_error_messages, "LOCK_error_messages", PSI_FLAG_GLOBAL}, { &key_LOG_INFO_lock, "LOG_INFO::lock", 0}, - { &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL} + { &key_LOCK_thread_count, "LOCK_thread_count", PSI_FLAG_GLOBAL}, + { &key_PARTITION_LOCK_auto_inc, "HA_DATA_PARTITION::LOCK_auto_inc", 0} }; PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger, diff --git a/sql/mysqld.h b/sql/mysqld.h index 9a6e43e4321..e14cd15ceb8 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -242,8 +242,8 @@ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids, key_master_info_data_lock, key_master_info_run_lock, key_mutex_slave_reporting_capability_err_lock, key_relay_log_info_data_lock, key_relay_log_info_log_space_lock, key_relay_log_info_run_lock, - key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data, key_LOCK_error_messages, - key_LOCK_thread_count; + key_structure_guard_mutex, key_TABLE_SHARE_LOCK_ha_data, + key_LOCK_error_messages, key_LOCK_thread_count, key_PARTITION_LOCK_auto_inc; extern PSI_rwlock_key key_rwlock_LOCK_grant, key_rwlock_LOCK_logger, key_rwlock_LOCK_sys_init_connect, key_rwlock_LOCK_sys_init_slave, diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 5e985625c78..9363b637862 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1539,6 +1539,29 @@ QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param, /* + Comparison function to be used QUICK_ROR_UNION_SELECT::queue priority + queue. + + SYNPOSIS + QUICK_ROR_UNION_SELECT_queue_cmp() + arg Pointer to QUICK_ROR_UNION_SELECT + val1 First merged select + val2 Second merged select +*/ + +C_MODE_START + +static int QUICK_ROR_UNION_SELECT_queue_cmp(void *arg, uchar *val1, uchar *val2) +{ + QUICK_ROR_UNION_SELECT *self= (QUICK_ROR_UNION_SELECT*)arg; + return self->head->file->cmp_ref(((QUICK_SELECT_I*)val1)->last_rowid, + ((QUICK_SELECT_I*)val2)->last_rowid); +} + +C_MODE_END + + +/* Do post-constructor initialization. SYNOPSIS QUICK_ROR_UNION_SELECT::init() @@ -1552,7 +1575,7 @@ int QUICK_ROR_UNION_SELECT::init() { DBUG_ENTER("QUICK_ROR_UNION_SELECT::init"); if (init_queue(&queue, quick_selects.elements, 0, - FALSE , QUICK_ROR_UNION_SELECT::queue_cmp, + FALSE , QUICK_ROR_UNION_SELECT_queue_cmp, (void*) this)) { bzero(&queue, sizeof(QUEUE)); @@ -1567,25 +1590,6 @@ int QUICK_ROR_UNION_SELECT::init() /* - Comparison function to be used QUICK_ROR_UNION_SELECT::queue priority - queue. - - SYNPOSIS - QUICK_ROR_UNION_SELECT::queue_cmp() - arg Pointer to QUICK_ROR_UNION_SELECT - val1 First merged select - val2 Second merged select -*/ - -int QUICK_ROR_UNION_SELECT::queue_cmp(void *arg, uchar *val1, uchar *val2) -{ - QUICK_ROR_UNION_SELECT *self= (QUICK_ROR_UNION_SELECT*)arg; - return self->head->file->cmp_ref(((QUICK_SELECT_I*)val1)->last_rowid, - ((QUICK_SELECT_I*)val2)->last_rowid); -} - - -/* Initialize quick select for row retrieval. SYNOPSIS reset() diff --git a/sql/opt_range.h b/sql/opt_range.h index 85d59671b42..72f2eb4b51d 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -657,7 +657,6 @@ public: bool have_prev_rowid; /* true if prev_rowid has valid data */ uint rowid_length; /* table rowid length */ private: - static int queue_cmp(void *arg, uchar *val1, uchar *val2); bool scans_inited; }; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index b6189ed3fc4..5b0b681c3a6 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2006-2008 MySQL AB, Sun Microsystems Inc. 2008-2009 +/* Copyright (c) 2006, 2010 Oracle and/or its affiliates. All rights reserved. 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 @@ -603,12 +603,12 @@ bool partition_info::check_engine_mix(handlerton *engine_type, { handlerton *old_engine_type= engine_type; bool first= TRUE; - uint num_parts= partitions.elements; + uint n_parts= partitions.elements; DBUG_ENTER("partition_info::check_engine_mix"); DBUG_PRINT("info", ("in: engine_type = %s, table_engine_set = %u", ha_resolve_storage_engine_name(engine_type), table_engine_set)); - if (num_parts) + if (n_parts) { List_iterator<partition_element> part_it(partitions); uint i= 0; @@ -621,7 +621,7 @@ bool partition_info::check_engine_mix(handlerton *engine_type, if (is_sub_partitioned() && part_elem->subpartitions.elements) { - uint num_subparts= part_elem->subpartitions.elements; + uint n_subparts= part_elem->subpartitions.elements; uint j= 0; List_iterator<partition_element> sub_it(part_elem->subpartitions); do @@ -633,7 +633,7 @@ bool partition_info::check_engine_mix(handlerton *engine_type, if (check_engine_condition(sub_elem, table_engine_set, &engine_type, &first)) goto error; - } while (++j < num_subparts); + } while (++j < n_subparts); /* ensure that the partition also has correct engine */ if (check_engine_condition(part_elem, table_engine_set, &engine_type, &first)) @@ -642,7 +642,7 @@ bool partition_info::check_engine_mix(handlerton *engine_type, else if (check_engine_condition(part_elem, table_engine_set, &engine_type, &first)) goto error; - } while (++i < num_parts); + } while (++i < n_parts); } DBUG_PRINT("info", ("engine_type = %s", ha_resolve_storage_engine_name(engine_type))); @@ -701,12 +701,11 @@ bool partition_info::check_range_constants(THD *thd) if (column_list) { part_column_list_val *loc_range_col_array; - part_column_list_val *current_largest_col_val; + part_column_list_val *UNINIT_VAR(current_largest_col_val); uint num_column_values= part_field_list.elements; uint size_entries= sizeof(part_column_list_val) * num_column_values; range_col_array= (part_column_list_val*)sql_calloc(num_parts * size_entries); - LINT_INIT(current_largest_col_val); if (unlikely(range_col_array == NULL)) { mem_alloc_error(num_parts * size_entries); @@ -739,12 +738,10 @@ bool partition_info::check_range_constants(THD *thd) } else { - longlong current_largest; + longlong UNINIT_VAR(current_largest); longlong part_range_value; bool signed_flag= !part_expr->unsigned_flag; - LINT_INIT(current_largest); - part_result_type= INT_RESULT; range_int_array= (longlong*)sql_alloc(num_parts * sizeof(longlong)); if (unlikely(range_int_array == NULL)) @@ -805,7 +802,8 @@ range_not_increasing_error: -1 a < b */ -int partition_info::list_part_cmp(const void* a, const void* b) +extern "C" +int partition_info_list_part_cmp(const void* a, const void* b) { longlong a1= ((LIST_PART_ENTRY*)a)->list_value; longlong b1= ((LIST_PART_ENTRY*)b)->list_value; @@ -817,7 +815,14 @@ int partition_info::list_part_cmp(const void* a, const void* b) return 0; } - /* + +int partition_info::list_part_cmp(const void* a, const void* b) +{ + return partition_info_list_part_cmp(a, b); +} + + +/* Compare two lists of column values in RANGE/LIST partitioning SYNOPSIS compare_column_values() @@ -829,8 +834,9 @@ int partition_info::list_part_cmp(const void* a, const void* b) +1 First argument is larger */ -int partition_info::compare_column_values(const void *first_arg, - const void *second_arg) +extern "C" +int partition_info_compare_column_values(const void *first_arg, + const void *second_arg) { const part_column_list_val *first= (part_column_list_val*)first_arg; const part_column_list_val *second= (part_column_list_val*)second_arg; @@ -866,6 +872,14 @@ int partition_info::compare_column_values(const void *first_arg, return 0; } + +int partition_info::compare_column_values(const void *first_arg, + const void *second_arg) +{ + return partition_info_compare_column_values(first_arg, second_arg); +} + + /* This routine allocates an array for all list constants to achieve a fast check what partition a certain value belongs to. At the same time it does @@ -894,10 +908,11 @@ bool partition_info::check_list_constants(THD *thd) part_elem_value *list_value; bool result= TRUE; longlong type_add, calc_value; - void *curr_value, *prev_value; + void *curr_value; + void *UNINIT_VAR(prev_value); partition_element* part_def; bool found_null= FALSE; - int (*compare_func)(const void *, const void*); + qsort_cmp compare_func; void *ptr; List_iterator<partition_element> list_func_it(partitions); DBUG_ENTER("partition_info::check_list_constants"); @@ -954,7 +969,7 @@ bool partition_info::check_list_constants(THD *thd) part_column_list_val *loc_list_col_array; loc_list_col_array= (part_column_list_val*)ptr; list_col_array= (part_column_list_val*)ptr; - compare_func= compare_column_values; + compare_func= partition_info_compare_column_values; i= 0; do { @@ -974,7 +989,7 @@ bool partition_info::check_list_constants(THD *thd) } else { - compare_func= list_part_cmp; + compare_func= partition_info_list_part_cmp; list_array= (LIST_PART_ENTRY*)ptr; i= 0; /* @@ -1009,7 +1024,6 @@ bool partition_info::check_list_constants(THD *thd) compare_func); i= 0; - LINT_INIT(prev_value); do { DBUG_ASSERT(i < num_list_values); @@ -1032,6 +1046,30 @@ end: DBUG_RETURN(result); } +/** + Check if we allow DATA/INDEX DIRECTORY, if not warn and set them to NULL. + + @param thd THD also containing sql_mode (looks from MODE_NO_DIR_IN_CREATE). + @param part_elem partition_element to check. +*/ +static void warn_if_dir_in_part_elem(THD *thd, partition_element *part_elem) +{ +#ifdef HAVE_READLINK + if (!my_use_symdir || (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)) +#endif + { + if (part_elem->data_file_name) + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED), + "DATA DIRECTORY"); + if (part_elem->index_file_name) + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED), + "INDEX DIRECTORY"); + part_elem->data_file_name= part_elem->index_file_name= NULL; + } +} + /* This code is used early in the CREATE TABLE and ALTER TABLE process. @@ -1169,20 +1207,7 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, do { partition_element *part_elem= part_it++; -#ifdef HAVE_READLINK - if (!my_use_symdir || (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE)) -#endif - { - if (part_elem->data_file_name) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED), - "DATA DIRECTORY"); - if (part_elem->index_file_name) - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - WARN_OPTION_IGNORED, ER(WARN_OPTION_IGNORED), - "INDEX DIRECTORY"); - part_elem->data_file_name= part_elem->index_file_name= NULL; - } + warn_if_dir_in_part_elem(thd, part_elem); if (!is_sub_partitioned()) { if (part_elem->engine_type == NULL) @@ -1208,6 +1233,7 @@ bool partition_info::check_partition_info(THD *thd, handlerton **eng_type, do { sub_elem= sub_it++; + warn_if_dir_in_part_elem(thd, sub_elem); if (check_table_name(sub_elem->partition_name, strlen(sub_elem->partition_name), FALSE)) { @@ -1306,15 +1332,15 @@ end: RETURN VALUES */ -void partition_info::print_no_partition_found(TABLE *table) +void partition_info::print_no_partition_found(TABLE *table_arg) { char buf[100]; char *buf_ptr= (char*)&buf; TABLE_LIST table_list; bzero(&table_list, sizeof(table_list)); - table_list.db= table->s->db.str; - table_list.table_name= table->s->table_name.str; + table_list.db= table_arg->s->db.str; + table_list.table_name= table_arg->s->table_name.str; if (check_single_table_access(current_thd, SELECT_ACL, &table_list, TRUE)) @@ -1328,13 +1354,13 @@ void partition_info::print_no_partition_found(TABLE *table) buf_ptr= (char*)"from column_list"; else { - my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); + my_bitmap_map *old_map= dbug_tmp_use_all_columns(table_arg, table_arg->read_set); if (part_expr->null_value) buf_ptr= (char*)"NULL"; else longlong2str(err_value, buf, part_expr->unsigned_flag ? 10 : -10); - dbug_tmp_restore_column_map(table->read_set, old_map); + dbug_tmp_restore_column_map(table_arg->read_set, old_map); } my_error(ER_NO_PARTITION_FOR_GIVEN_VALUE, MYF(0), buf_ptr); } @@ -1994,7 +2020,7 @@ bool partition_info::fix_column_value_functions(THD *thd, part_elem_value *val, uint part_id) { - uint num_columns= part_field_list.elements; + uint n_columns= part_field_list.elements; bool result= FALSE; uint i; part_column_list_val *col_val= val->col_val_array; @@ -2004,7 +2030,7 @@ bool partition_info::fix_column_value_functions(THD *thd, { DBUG_RETURN(FALSE); } - for (i= 0; i < num_columns; col_val++, i++) + for (i= 0; i < n_columns; col_val++, i++) { Item *column_item= col_val->item_expression; Field *field= part_field_array[i]; diff --git a/sql/partition_info.h b/sql/partition_info.h index 479714a3928..b196d0b59a2 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -151,8 +151,6 @@ public: char *part_func_string; char *subpart_func_string; - const char *part_state; - partition_element *curr_part_elem; partition_element *current_partition; part_elem_value *curr_list_val; @@ -173,7 +171,6 @@ public: partition_type subpart_type; uint part_info_len; - uint part_state_len; uint part_func_len; uint subpart_func_len; @@ -226,13 +223,12 @@ public: list_array(NULL), err_value(0), part_info_string(NULL), part_func_string(NULL), subpart_func_string(NULL), - part_state(NULL), curr_part_elem(NULL), current_partition(NULL), curr_list_object(0), num_columns(0), default_engine_type(NULL), part_result_type(INT_RESULT), part_type(NOT_A_PARTITION), subpart_type(NOT_A_PARTITION), - part_info_len(0), part_state_len(0), + part_info_len(0), part_func_len(0), subpart_func_len(0), num_parts(0), num_subparts(0), count_curr_subparts(0), part_error_code(0), diff --git a/sql/protocol.cc b/sql/protocol.cc index eeb248012ab..ac78ac88ec6 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -747,8 +747,7 @@ bool Protocol::send_result_set_metadata(List<Item> *list, uint flags) else { /* With conversion */ - ulonglong max_length; - uint32 field_length; + uint32 field_length, max_length; int2store(pos, thd_charset->number); /* For TEXT/BLOB columns, field_length describes the maximum data @@ -771,9 +770,8 @@ bool Protocol::send_result_set_metadata(List<Item> *list, uint flags) field.type <= MYSQL_TYPE_BLOB) ? field.length / item->collation.collation->mbminlen : field.length / item->collation.collation->mbmaxlen; - max_length*= thd_charset->mbmaxlen; - field_length= (max_length > UINT_MAX32) ? - UINT_MAX32 : (uint32) max_length; + field_length= char_to_byte_length_safe(max_length, + thd_charset->mbmaxlen); int4store(pos + 2, field_length); } pos[6]= field.type; diff --git a/sql/rpl_handler.cc b/sql/rpl_handler.cc index 9cb5391075d..be0a61bcae2 100644 --- a/sql/rpl_handler.cc +++ b/sql/rpl_handler.cc @@ -89,21 +89,24 @@ int get_user_var_str(const char *name, char *value, int delegates_init() { - static unsigned long trans_mem[sizeof(Trans_delegate) / sizeof(unsigned long) + 1]; - static unsigned long storage_mem[sizeof(Binlog_storage_delegate) / sizeof(unsigned long) + 1]; + static Aligned_char_array<sizeof(Trans_delegate)> trans_mem; + static Aligned_char_array<sizeof(Binlog_storage_delegate)> storage_mem; #ifdef HAVE_REPLICATION - static unsigned long transmit_mem[sizeof(Binlog_transmit_delegate) / sizeof(unsigned long) + 1]; - static unsigned long relay_io_mem[sizeof(Binlog_relay_IO_delegate)/ sizeof(unsigned long) + 1]; + static Aligned_char_array<sizeof(Binlog_transmit_delegate)> transmit_mem; + static Aligned_char_array<sizeof(Binlog_relay_IO_delegate)> relay_io_mem; #endif - - if (!(transaction_delegate= new (trans_mem) Trans_delegate) + + if (!(transaction_delegate= new (trans_mem.arr()) Trans_delegate) || (!transaction_delegate->is_inited()) - || !(binlog_storage_delegate= new (storage_mem) Binlog_storage_delegate) + || !(binlog_storage_delegate= + new (storage_mem.arr()) Binlog_storage_delegate) || (!binlog_storage_delegate->is_inited()) #ifdef HAVE_REPLICATION - || !(binlog_transmit_delegate= new (transmit_mem) Binlog_transmit_delegate) + || !(binlog_transmit_delegate= + new (transmit_mem.arr()) Binlog_transmit_delegate) || (!binlog_transmit_delegate->is_inited()) - || !(binlog_relay_io_delegate= new (relay_io_mem) Binlog_relay_IO_delegate) + || !(binlog_relay_io_delegate= + new (relay_io_mem.arr()) Binlog_relay_IO_delegate) || (!binlog_relay_io_delegate->is_inited()) #endif /* HAVE_REPLICATION */ ) diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index 10bf752e140..9b0450b3f02 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -131,8 +131,10 @@ enum { LINE_FOR_MASTER_SSL_VERIFY_SERVER_CERT= 15, /* 6.0 added value of master_heartbeat_period */ LINE_FOR_MASTER_HEARTBEAT_PERIOD= 16, + /* MySQL Cluster 6.3 added master_bind */ + LINE_FOR_MASTER_BIND = 17, /* 6.0 added value of master_ignore_server_id */ - LINE_FOR_REPLICATE_IGNORE_SERVER_IDS= 17, + LINE_FOR_REPLICATE_IGNORE_SERVER_IDS= 18, /* Number of lines currently used when saving master info file */ LINES_IN_MASTER_INFO= LINE_FOR_REPLICATE_IGNORE_SERVER_IDS }; @@ -240,6 +242,7 @@ file '%s')", fname); int ssl= 0, ssl_verify_server_cert= 0; float master_heartbeat_period= 0.0; char *first_non_digit; + char dummy_buf[HOSTNAME_LENGTH+1]; /* Starting from 4.1.x master.info has new format. Now its @@ -329,6 +332,13 @@ file '%s')", fname); init_floatvar_from_file(&master_heartbeat_period, &mi->file, 0.0)) goto errwithmsg; /* + Starting from MySQL Cluster 6.3 master_bind might be in the file + (this is just a reservation to avoid future upgrade problems) + */ + if (lines >= LINE_FOR_MASTER_BIND && + init_strvar_from_file(dummy_buf, sizeof(dummy_buf), &mi->file, "")) + goto errwithmsg; + /* Starting from 6.0 list of server_id of ignorable servers might be in the file */ @@ -480,14 +490,14 @@ int flush_master_info(Master_info* mi, my_sprintf(heartbeat_buf, (heartbeat_buf, "%.3f", mi->heartbeat_period)); my_b_seek(file, 0L); my_b_printf(file, - "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n", + "%u\n%s\n%s\n%s\n%s\n%s\n%d\n%d\n%d\n%s\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n%s\n", LINES_IN_MASTER_INFO, mi->master_log_name, llstr(mi->master_log_pos, lbuf), mi->host, mi->user, mi->password, mi->port, mi->connect_retry, (int)(mi->ssl), mi->ssl_ca, mi->ssl_capath, mi->ssl_cert, mi->ssl_cipher, mi->ssl_key, mi->ssl_verify_server_cert, - heartbeat_buf, ignore_server_ids_buf); + heartbeat_buf, "", ignore_server_ids_buf); my_free(ignore_server_ids_buf, MYF(0)); err= flush_io_cache(file); if (sync_masterinfo_period && !err && diff --git a/sql/rpl_utility.h b/sql/rpl_utility.h index cf28d2c8e29..25f2a60bece 100644 --- a/sql/rpl_utility.h +++ b/sql/rpl_utility.h @@ -233,7 +233,7 @@ struct RPL_TABLE_LIST /* Anonymous namespace for template functions/classes */ -namespace { +CPP_UNNAMED_NS_START /* Smart pointer that will automatically call my_afree (a macro) when @@ -260,7 +260,7 @@ namespace { Obj* get() { return m_ptr; } }; -} +CPP_UNNAMED_NS_END #endif // NB. number of printed bit values is limited to sizeof(buf) - 1 diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index e5ab2332e20..9e7fdbfeae5 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -6335,7 +6335,13 @@ ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE eng "Mixing self-logging and non-self-logging engines in a statement is unsafe." ER_BINLOG_UNSAFE_MIXED_STATEMENT - eng "Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe." + eng "Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them." + +ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN + eng "Cannot modify @@session.sql_log_bin inside a transaction" + +ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN + eng "Cannot change the sql_log_bin inside a stored function or trigger" ER_FAILED_READ_FROM_PAR_FILE eng "Failed to read from the .par file" diff --git a/sql/sp_head.cc b/sql/sp_head.cc index e833a540032..9395146f18f 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -125,10 +125,10 @@ sp_get_item_value(THD *thd, Item *item, String *str) case STRING_RESULT: { String *result= item->val_str(str); - + if (!result) return NULL; - + { char buf_holder[STRING_BUFFER_USUAL_SIZE]; String buf(buf_holder, sizeof(buf_holder), result->charset()); @@ -366,7 +366,7 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr) Save original values and restore them after save. */ - + thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL; thd->abort_on_warning= thd->variables.sql_mode & @@ -465,7 +465,7 @@ check_routine_name(LEX_STRING *ident) { if (!ident || !ident->str || !ident->str[0] || ident->str[ident->length-1] == ' ') - { + { my_error(ER_SP_WRONG_NAME, MYF(0), ident->str); return TRUE; } @@ -502,7 +502,7 @@ sp_head::operator new(size_t size) throw() DBUG_RETURN(sp); } -void +void sp_head::operator delete(void *ptr, size_t size) throw() { DBUG_ENTER("sp_head::operator delete"); @@ -718,7 +718,7 @@ create_typelib(MEM_ROOT *mem_root, Create_field *field_def, List<String> *src) String *tmp= it++; if (String::needs_conversion(tmp->length(), tmp->charset(), - cs, &dummy)) + cs, &dummy)) { uint cnv_errs; conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs); @@ -815,7 +815,7 @@ sp_head::create_result_field(uint field_max_length, const char *field_name, if (field) field->init(table); - + DBUG_RETURN(field); } @@ -844,7 +844,7 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) Statements that have is_update_query(stmt) == FALSE (e.g. SELECTs) are not written into binary log. Instead we catch function calls the statement makes and write it into binary log separately (see #3). - + 2. PROCEDURE calls CALL statements are not written into binary log. Instead @@ -857,8 +857,8 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) This substitution is done in subst_spvars(). 3. FUNCTION calls - - In sp_head::execute_function(), we check + + In sp_head::execute_function(), we check * If this function invocation is done from a statement that is written into the binary log. * If there were any attempts to write events to the binary log during @@ -866,28 +866,28 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) If the answers are No and Yes, we write the function call into the binary log as "SELECT spfunc(<param1value>, <param2value>, ...)" - - + + 4. Miscellaneous issues. - - 4.1 User variables. + + 4.1 User variables. When we call mysql_bin_log.write() for an SP statement, thd->user_var_events - must hold set<{var_name, value}> pairs for all user variables used during + must hold set<{var_name, value}> pairs for all user variables used during the statement execution. This set is produced by tracking user variable reads during statement - execution. + execution. For SPs, this has the following implications: - 1) thd->user_var_events may contain events from several SP statements and - needs to be valid after exection of these statements was finished. In + 1) thd->user_var_events may contain events from several SP statements and + needs to be valid after exection of these statements was finished. In order to achieve that, we * Allocate user_var_events array elements on appropriate mem_root (grep for user_var_events_alloc). * Use is_query_in_union() to determine if user_var_event is created. - + 2) We need to empty thd->user_var_events after we have wrote a function - call. This is currently done by making + call. This is currently done by making reset_dynamic(&thd->user_var_events); calls in several different places. (TODO cosider moving this into mysql_bin_log.write() function) @@ -906,7 +906,7 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) Replace thd->query{_length} with a string that one can write to the binlog. - The binlog-suitable string is produced by replacing references to SP local + The binlog-suitable string is produced by replacing references to SP local variables with NAME_CONST('sp_var_name', value) calls. @param thd Current thread. @@ -943,11 +943,11 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) } if (!sp_vars_uses.elements()) DBUG_RETURN(FALSE); - + /* Sort SP var refs by their occurences in the query */ sp_vars_uses.sort(cmp_splocal_locations); - /* + /* Construct a statement string where SP local var refs are replaced with "NAME_CONST(name, value)" */ @@ -955,7 +955,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) cur= query_str->str; prev_pos= res= 0; thd->query_name_consts= 0; - + for (Item_splocal **splocal= sp_vars_uses.front(); splocal < sp_vars_uses.back(); splocal++) { @@ -965,13 +965,13 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) String str_value_holder(str_buffer, sizeof(str_buffer), &my_charset_latin1); String *str_value; - + /* append the text between sp ref occurences */ res|= qbuf.append(cur + prev_pos, (*splocal)->pos_in_query - prev_pos); prev_pos= (*splocal)->pos_in_query + (*splocal)->len_in_query; - + res|= (*splocal)->fix_fields(thd, (Item **) splocal); - if (res) + if (res) break; if ((*splocal)->limit_clause_param) @@ -998,7 +998,7 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) res|= qbuf.append(')'); if (res) break; - + thd->query_name_consts++; } res|= qbuf.append(cur + prev_pos, query_str->length - prev_pos); @@ -1024,16 +1024,14 @@ subst_spvars(THD *thd, sp_instr *instr, LEX_STRING *query_str) } -/* +/** Return appropriate error about recursion limit reaching - SYNOPSIS - sp_head::recursion_level_error() - thd Thread handle + @param thd Thread handle - NOTE - For functions and triggers we return error about prohibited recursion. - For stored procedures we return about reaching recursion limit. + @remark For functions and triggers we return error about + prohibited recursion. For stored procedures we + return about reaching recursion limit. */ void sp_head::recursion_level_error(THD *thd) @@ -1053,7 +1051,7 @@ void sp_head::recursion_level_error(THD *thd) Execute the routine. The main instruction jump loop is there. Assume the parameters already set. @todo - - Will write this SP statement into binlog separately + - Will write this SP statement into binlog separately (TODO: consider changing the condition to "not inside event union") @retval @@ -1217,10 +1215,10 @@ sp_head::execute(THD *thd) do { sp_instr *i; - uint hip; // Handler ip + uint hip; #if defined(ENABLED_PROFILING) - /* + /* Treat each "instr" of a routine as discrete unit that could be profiled. Profiling only records information for segments of code that set the source of the query, and almost all kinds of instructions in s-p do not. @@ -1229,7 +1227,8 @@ sp_head::execute(THD *thd) thd->profiling.start_new_query("continuing inside routine"); #endif - i = get_instr(ip); // Returns NULL when we're done. + /* get_instr returns NULL when we're done. */ + i = get_instr(ip); if (i == NULL) { #if defined(ENABLED_PROFILING) @@ -1240,10 +1239,13 @@ sp_head::execute(THD *thd) DBUG_PRINT("execute", ("Instruction %u", ip)); - /* Don't change NOW() in FUNCTION or TRIGGER */ + /* + Make current_time() et al work. But don't change NOW() in FUNCTION + or TRIGGER. + */ if (!thd->in_sub_stmt) - thd->set_time(); // Make current_time() et al work - + thd->set_time(); + /* We have to set thd->stmt_arena before executing the instruction to store in the instruction free_list all new items, created @@ -1251,10 +1253,10 @@ sp_head::execute(THD *thd) items made during other permanent subquery transformations). */ thd->stmt_arena= i; - - /* - Will write this SP statement into binlog separately - (TODO: consider changing the condition to "not inside event union") + + /* + Will write this SP statement into binlog separately. + TODO: consider changing the condition to "not inside event union". */ if (thd->locked_tables_mode <= LTM_LOCK_TABLES) thd->user_var_events_alloc= thd->mem_root; @@ -1263,8 +1265,8 @@ sp_head::execute(THD *thd) if (i->free_list) cleanup_items(i->free_list); - - /* + + /* If we've set thd->user_var_events_alloc to mem_root of this SP statement, clean all the events allocated in it. */ @@ -1276,7 +1278,7 @@ sp_head::execute(THD *thd) /* we should cleanup free_list and memroot, used by instruction */ thd->cleanup_after_query(); - free_root(&execute_mem_root, MYF(0)); + free_root(&execute_mem_root, MYF(0)); /* Check if an exception has occurred and a handler has been found @@ -1291,7 +1293,7 @@ sp_head::execute(THD *thd) switch (ctx->found_handler(& hip, & handler_index)) { case SP_HANDLER_NONE: - break; + break; case SP_HANDLER_CONTINUE: thd->restore_active_arena(&execute_arena, &backup_arena); thd->set_n_backup_active_arena(&execute_arena, &backup_arena); @@ -1300,15 +1302,15 @@ sp_head::execute(THD *thd) default: if (ctx->end_partial_result_set) thd->protocol->end_partial_result_set(thd); - ip= hip; - err_status= FALSE; - ctx->clear_handler(); - ctx->enter_handler(hip, handler_index); + ip= hip; + err_status= FALSE; + ctx->clear_handler(); + ctx->enter_handler(hip, handler_index); thd->clear_error(); thd->is_fatal_error= 0; - thd->killed= THD::NOT_KILLED; + thd->killed= THD::NOT_KILLED; thd->mysys_var->abort= 0; - continue; + continue; } ctx->end_partial_result_set= FALSE; @@ -1351,7 +1353,7 @@ sp_head::execute(THD *thd) done: DBUG_PRINT("info", ("err_status: %d killed: %d is_slave_error: %d report_error: %d", - err_status, thd->killed, thd->is_slave_error, + err_status, thd->killed, thd->is_slave_error, thd->is_error())); if (thd->killed) @@ -1839,10 +1841,10 @@ err_with_cleanup: /** - Execute a procedure. + Execute a procedure. The function does the following steps: - - Set all parameters + - Set all parameters - changes security context for SUID routines - call sp_head::execute - copy back values of INOUT and OUT parameters @@ -1880,14 +1882,14 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) save_spcont= octx= thd->spcont; if (! octx) - { // Create a temporary old context - if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) || - octx->init(thd)) + { + /* Create a temporary old context. */ + if (!(octx= new sp_rcontext(m_pcont, NULL, octx)) || octx->init(thd)) { delete octx; /* Delete octx if it was init() that failed. */ DBUG_RETURN(TRUE); } - + #ifndef DBUG_OFF octx->sp= 0; #endif @@ -2119,6 +2121,9 @@ sp_head::reset_lex(THD *thd) sublex->interval_list.empty(); sublex->type= 0; + /* Reset part of parser state which needs this. */ + thd->m_parser_state->m_yacc.reset_before_substatement(); + DBUG_RETURN(FALSE); } @@ -2144,7 +2149,7 @@ sp_head::restore_lex(THD *thd) oldlex= (LEX *)m_lex.pop(); if (! oldlex) - DBUG_RETURN(FALSE); // Nothing to restore + DBUG_RETURN(FALSE); // Nothing to restore oldlex->trg_table_fields.push_back(&sublex->trg_table_fields); @@ -2297,7 +2302,7 @@ sp_head::do_cont_backpatch() void sp_head::set_info(longlong created, longlong modified, - st_sp_chistics *chistics, ulong sql_mode) + st_sp_chistics *chistics, ulong sql_mode) { m_created= created; m_modified= modified; @@ -2307,8 +2312,8 @@ sp_head::set_info(longlong created, longlong modified, m_chistics->comment.str= 0; else m_chistics->comment.str= strmake_root(mem_root, - m_chistics->comment.str, - m_chistics->comment.length); + m_chistics->comment.str, + m_chistics->comment.length); m_sql_mode= sql_mode; } @@ -2349,7 +2354,7 @@ sp_head::reset_thd_mem_root(THD *thd) DBUG_PRINT("info", ("mem_root 0x%lx moved to thd mem root 0x%lx", (ulong) &mem_root, (ulong) &thd->mem_root)); free_list= thd->free_list; // Keep the old list - thd->free_list= NULL; // Start a new one + thd->free_list= NULL; // Start a new one m_thd= thd; DBUG_VOID_RETURN; } @@ -2358,13 +2363,13 @@ void sp_head::restore_thd_mem_root(THD *thd) { DBUG_ENTER("sp_head::restore_thd_mem_root"); - Item *flist= free_list; // The old list + Item *flist= free_list; // The old list set_query_arena(thd); // Get new free_list and mem_root state= INITIALIZED_FOR_SP; DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx", (ulong) &mem_root, (ulong) &thd->mem_root)); - thd->free_list= flist; // Restore the old one + thd->free_list= flist; // Restore the old one thd->mem_root= m_thd_root; m_thd= NULL; DBUG_VOID_RETURN; @@ -2374,10 +2379,10 @@ sp_head::restore_thd_mem_root(THD *thd) /** Check if a user has access right to a routine. - @param thd Thread handler - @param sp SP - @param full_access Set to 1 if the user has SELECT right to the - 'mysql.proc' able or is the owner of the routine + @param thd Thread handler + @param sp SP + @param full_access Set to 1 if the user has SELECT right to the + 'mysql.proc' able or is the owner of the routine @retval false ok @retval @@ -2506,8 +2511,6 @@ sp_head::show_create_routine(THD *thd, int type) } - - /** Add instruction to SP. @@ -2567,11 +2570,11 @@ void sp_head::optimize() if (src != dst) { /* Move the instruction and update prev. jumps */ - sp_instr *ibp; - List_iterator_fast<sp_instr> li(bp); + sp_instr *ibp; + List_iterator_fast<sp_instr> li(bp); - set_dynamic(&m_instr, (uchar*)&i, dst); - while ((ibp= li++)) + set_dynamic(&m_instr, (uchar*)&i, dst); + while ((ibp= li++)) { sp_instr_opt_meta *im= static_cast<sp_instr_opt_meta *>(ibp); im->set_destination(src, dst); @@ -2666,7 +2669,7 @@ sp_head::show_routine_code(THD *thd) for (ip= 0; (i = get_instr(ip)) ; ip++) { - /* + /* Consistency check. If these are different something went wrong during optimization. */ @@ -2729,7 +2732,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, int res= 0; DBUG_ENTER("reset_lex_and_exec_core"); - /* + /* The flag is saved at the entry to the following substatement. It's reset further in the common code part. It's merged with the saved parent's value at the exit of this func. @@ -2891,9 +2894,8 @@ sp_instr_stmt::execute(THD *thd, uint *nextp) if (unlikely((thd->variables.option_bits & OPTION_LOG_OFF)==0)) general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); - if (query_cache_send_result_to_client(thd, - thd->query(), - thd->query_length()) <= 0) + if (query_cache_send_result_to_client(thd, thd->query(), + thd->query_length()) <= 0) { res= m_lex_keeper.reset_lex_and_exec_core(thd, nextp, FALSE, this); @@ -2996,7 +2998,7 @@ sp_instr_set::exec_core(THD *thd, uint *nextp) /* If this also failed, let's abort. */ sp_rcontext *spcont= thd->spcont; - + thd->spcont= NULL; /* Avoid handlers */ my_error(ER_OUT_OF_RESOURCES, MYF(0)); spcont->clear_handler(); @@ -3100,7 +3102,7 @@ uint sp_instr_jump::opt_mark(sp_head *sp, List<sp_instr> *leads) { m_dest= opt_shortcut_jump(sp, this); - if (m_dest != m_ip+1) /* Jumping to following instruction? */ + if (m_dest != m_ip+1) /* Jumping to following instruction? */ marked= 1; m_optdest= sp->get_instr(m_dest); return m_dest; @@ -3130,9 +3132,9 @@ void sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp) { if (m_dest > m_ip) - bp->push_back(this); // Forward + bp->push_back(this); // Forward else if (m_optdest) - m_dest= m_optdest->m_ip; // Backward + m_dest= m_optdest->m_ip; // Backward m_ip= dst; } @@ -3405,7 +3407,7 @@ uint sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads) { marked= 1; - + if (m_dest) { /* @@ -3413,7 +3415,7 @@ sp_instr_hreturn::opt_mark(sp_head *sp, List<sp_instr> *leads) */ return m_dest; } - + /* This is a CONTINUE handler; next instruction step will come from the handler stack and not from opt_mark. @@ -3730,14 +3732,14 @@ sp_instr_set_case_expr::exec_core(THD *thd, uint *nextp) */ Item *null_item= new Item_null(); - + if (!null_item || thd->spcont->set_case_expr(thd, m_case_expr_id, &null_item)) { /* If this also failed, we have to abort. */ sp_rcontext *spcont= thd->spcont; - + thd->spcont= NULL; /* Avoid handlers */ my_error(ER_OUT_OF_RESOURCES, MYF(0)); spcont->clear_handler(); @@ -3903,13 +3905,13 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) } else { - if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE)))) - return FALSE; - if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE && - lex_for_tmp_check->query_tables == table && - lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE) + if (!(tab= (SP_TABLE *)thd->calloc(sizeof(SP_TABLE)))) + return FALSE; + if (lex_for_tmp_check->sql_command == SQLCOM_CREATE_TABLE && + lex_for_tmp_check->query_tables == table && + lex_for_tmp_check->create_info.options & HA_LEX_CREATE_TMP_TABLE) { - tab->temp= TRUE; + tab->temp= TRUE; tab->qname.length= tlen - alen - 1; } else @@ -3922,7 +3924,7 @@ sp_head::merge_table_list(THD *thd, TABLE_LIST *table, LEX *lex_for_tmp_check) tab->lock_type= table->lock_type; tab->lock_count= tab->query_lock_count= 1; tab->trg_event_map= table->trg_event_map; - if (my_hash_insert(&m_sptabs, (uchar *)tab)) + if (my_hash_insert(&m_sptabs, (uchar *)tab)) return FALSE; } } @@ -4029,8 +4031,8 @@ sp_head::add_used_tables_to_table_list(THD *thd, TABLE_LIST * sp_add_to_query_tables(THD *thd, LEX *lex, - const char *db, const char *name, - thr_lock_type locktype) + const char *db, const char *name, + thr_lock_type locktype) { TABLE_LIST *table; diff --git a/sql/spatial.cc b/sql/spatial.cc index 34b1f3d1f0c..fcf06119db9 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -128,6 +128,16 @@ Geometry::Class_info *Geometry::find_class(const char *name, uint32 len) } +Geometry *Geometry::create_by_typeid(Geometry_buffer *buffer, int type_id) +{ + Class_info *ci; + if (!(ci= find_class((int) type_id))) + return NULL; + (*ci->m_create_func)(buffer->buf.arr()); + return my_reinterpret_cast(Geometry *)(buffer->buf.arr()); +} + + Geometry *Geometry::construct(Geometry_buffer *buffer, const char *data, uint32 data_len) { diff --git a/sql/spatial.h b/sql/spatial.h index a4bce47d0e5..aabbb7a1b97 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -267,14 +267,7 @@ public: virtual int geometry_n(uint32 num, String *result) const { return -1; } public: - static Geometry *create_by_typeid(Geometry_buffer *buffer, int type_id) - { - Class_info *ci; - if (!(ci= find_class((int) type_id))) - return NULL; - (*ci->m_create_func)((void *)buffer); - return my_reinterpret_cast(Geometry *)(buffer); - } + static Geometry *create_by_typeid(Geometry_buffer *buffer, int type_id); static Geometry *construct(Geometry_buffer *buffer, const char *data, uint32 data_len); @@ -532,10 +525,9 @@ public: const Class_info *get_class_info() const; }; -const int geometry_buffer_size= sizeof(Gis_point); struct Geometry_buffer { - void *arr[(geometry_buffer_size - 1)/sizeof(void *) + 1]; + Aligned_char_array<sizeof(Gis_point)> buf; }; #endif /*HAVE_SPATAIAL*/ diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 5a7fb7f154a..ec25e4cb68b 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -3159,6 +3159,12 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, */ Query_tables_list backup; thd->lex->reset_n_backup_query_tables_list(&backup); + /* + Restore Query_tables_list::sql_command value, which was reset + above, as the code writing query to the binary log assumes that + this value corresponds to the statement being executed. + */ + thd->lex->sql_command= backup.sql_command; if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // Should never happen close_thread_tables(thd); /* purecov: deadcode */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index fd0dfc5189a..325f054db02 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1564,7 +1564,7 @@ void close_thread_tables(THD *thd) - If in autocommit mode, or outside a transactional context, automatically release metadata locks of the current statement. */ - if (! thd->in_multi_stmt_transaction() && + if (! thd->in_multi_stmt_transaction_mode() && ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)) { thd->mdl_context.release_transactional_locks(); @@ -3789,7 +3789,7 @@ end_with_lock_open: Open_table_context::Open_table_context(THD *thd, ulong timeout) :m_action(OT_NO_ACTION), m_start_of_statement_svp(thd->mdl_context.mdl_savepoint()), - m_has_locks((thd->in_multi_stmt_transaction() && + m_has_locks((thd->in_multi_stmt_transaction_mode() && thd->mdl_context.has_locks()) || thd->mdl_context.trans_sentinel()), m_global_mdl_request(NULL), @@ -3969,7 +3969,8 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request, Return a appropriate read lock type given a table object. @param thd Thread context - @param table TABLE object for table to be locked + @param prelocking_ctx Prelocking context. + @param table_list Table list element for table to be locked. @remark Due to a statement-based replication limitation, statements such as INSERT INTO .. SELECT FROM .. and CREATE TABLE .. SELECT FROM need @@ -3978,20 +3979,44 @@ recover_from_failed_open(THD *thd, MDL_request *mdl_request, source table. If such a statement gets applied on the slave before the INSERT .. SELECT statement finishes, data on the master could differ from data on the slave and end-up with a discrepancy between - the binary log and table state. Furthermore, this does not apply to - I_S and log tables as it's always unsafe to replicate such tables - under statement-based replication as the table on the slave might - contain other data (ie: general_log is enabled on the slave). The - statement will be marked as unsafe for SBR in decide_logging_format(). + the binary log and table state. + This also applies to SELECT/SET/DO statements which use stored + functions. Calls to such functions are going to be logged as a + whole and thus should be serialized against concurrent changes + to tables used by those functions. This can be avoided if functions + only read data but doing so requires more complex analysis than it + is done now. + Furthermore, this does not apply to I_S and log tables as it's + always unsafe to replicate such tables under statement-based + replication as the table on the slave might contain other data + (ie: general_log is enabled on the slave). The statement will + be marked as unsafe for SBR in decide_logging_format(). + @remark Note that even in prelocked mode it is important to correctly + determine lock type value. In this mode lock type is passed to + handler::start_stmt() method and can be used by storage engine, + for example, to determine what kind of row locks it should acquire + when reading data from the table. */ -thr_lock_type read_lock_type_for_table(THD *thd, TABLE *table) +thr_lock_type read_lock_type_for_table(THD *thd, + Query_tables_list *prelocking_ctx, + TABLE_LIST *table_list) { - bool log_on= mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG); + /* + In cases when this function is called for a sub-statement executed in + prelocked mode we can't rely on OPTION_BIN_LOG flag in THD::options + bitmap to determine that binary logging is turned on as this bit can + be cleared before executing sub-statement. So instead we have to look + at THD::variables::sql_log_bin member. + */ + bool log_on= mysql_bin_log.is_open() && thd->variables.sql_log_bin; ulong binlog_format= thd->variables.binlog_format; if ((log_on == FALSE) || (binlog_format == BINLOG_FORMAT_ROW) || - (table->s->table_category == TABLE_CATEGORY_LOG) || - (table->s->table_category == TABLE_CATEGORY_PERFORMANCE)) + (table_list->table->s->table_category == TABLE_CATEGORY_LOG) || + (table_list->table->s->table_category == TABLE_CATEGORY_PERFORMANCE) || + !(is_update_query(prelocking_ctx->sql_command) || + table_list->prelocking_placeholder || + (thd->locked_tables_mode > LTM_LOCK_TABLES))) return TL_READ; else return TL_READ_NO_INSERT; @@ -4342,7 +4367,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables, tables->table->reginfo.lock_type= thd->update_lock_default; else if (tables->lock_type == TL_READ_DEFAULT) tables->table->reginfo.lock_type= - read_lock_type_for_table(thd, tables->table); + read_lock_type_for_table(thd, lex, tables); else tables->table->reginfo.lock_type= tables->lock_type; } @@ -4995,35 +5020,49 @@ handle_view(THD *thd, Query_tables_list *prelocking_ctx, } -/* +/** Check that lock is ok for tables; Call start stmt if ok - SYNOPSIS - check_lock_and_start_stmt() - thd Thread handle - table_list Table to check - lock_type Lock used for table + @param thd Thread handle. + @param prelocking_ctx Prelocking context. + @param table_list Table list element for table to be checked. - RETURN VALUES - 0 ok - 1 error + @retval FALSE - Ok. + @retval TRUE - Error. */ -static bool check_lock_and_start_stmt(THD *thd, TABLE *table, - thr_lock_type lock_type) +static bool check_lock_and_start_stmt(THD *thd, + Query_tables_list *prelocking_ctx, + TABLE_LIST *table_list) { int error; + thr_lock_type lock_type; DBUG_ENTER("check_lock_and_start_stmt"); + /* + TL_WRITE_DEFAULT and TL_READ_DEFAULT are supposed to be parser only + types of locks so they should be converted to appropriate other types + to be passed to storage engine. The exact lock type passed to the + engine is important as, for example, InnoDB uses it to determine + what kind of row locks should be acquired when executing statement + in prelocked mode or under LOCK TABLES with @@innodb_table_locks = 0. + */ + if (table_list->lock_type == TL_WRITE_DEFAULT) + lock_type= thd->update_lock_default; + else if (table_list->lock_type == TL_READ_DEFAULT) + lock_type= read_lock_type_for_table(thd, prelocking_ctx, table_list); + else + lock_type= table_list->lock_type; + if ((int) lock_type >= (int) TL_WRITE_ALLOW_READ && - (int) table->reginfo.lock_type < (int) TL_WRITE_ALLOW_READ) + (int) table_list->table->reginfo.lock_type < (int) TL_WRITE_ALLOW_READ) { - my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),table->alias); + my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), table_list->alias); DBUG_RETURN(1); } - if ((error=table->file->start_stmt(thd, lock_type))) + if ((error= table_list->table->file->start_stmt(thd, lock_type))) { - table->file->print_error(error,MYF(0)); + table_list->table->file->print_error(error, MYF(0)); DBUG_RETURN(1); } DBUG_RETURN(0); @@ -5168,7 +5207,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type, table->grant= table_list->grant; if (thd->locked_tables_mode) { - if (check_lock_and_start_stmt(thd, table, lock_type)) + if (check_lock_and_start_stmt(thd, thd->lex, table_list)) table= 0; } else @@ -5396,7 +5435,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, if (!table->placeholder()) { table->table->query_id= thd->query_id; - if (check_lock_and_start_stmt(thd, table->table, table->lock_type)) + if (check_lock_and_start_stmt(thd, thd->lex, table)) { mysql_unlock_tables(thd, thd->lock); thd->lock= 0; @@ -5450,7 +5489,7 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count, } } - if (check_lock_and_start_stmt(thd, table->table, table->lock_type)) + if (check_lock_and_start_stmt(thd, thd->lex, table)) { DBUG_RETURN(TRUE); } diff --git a/sql/sql_base.h b/sql/sql_base.h index 4d6be93b532..0fe70e4bc9d 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -56,9 +56,6 @@ enum enum_resolution_type { RESOLVED_AGAINST_ALIAS }; -enum enum_open_table_action {OT_NO_ACTION= 0, OT_BACK_OFF_AND_RETRY, - OT_DISCOVER, OT_REPAIR}; - enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND, IGNORE_ERRORS, REPORT_EXCEPT_NON_UNIQUE, IGNORE_EXCEPT_NON_UNIQUE}; @@ -123,7 +120,9 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db, TABLE *find_locked_table(TABLE *list, const char *db, const char *table_name); TABLE *find_write_locked_table(TABLE *list, const char *db, const char *table_name); -thr_lock_type read_lock_type_for_table(THD *thd, TABLE *table); +thr_lock_type read_lock_type_for_table(THD *thd, + Query_tables_list *prelocking_ctx, + TABLE_LIST *table_list); my_bool mysql_rm_tmp_tables(void); bool rm_temporary_table(handlerton *base, char *path); diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 1e4161dfa1c..92d54c8e71b 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1177,7 +1177,7 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used) DBUG_ASSERT(flags.protocol_type != (unsigned int) Protocol::PROTOCOL_LOCAL); flags.more_results_exists= test(thd->server_status & SERVER_MORE_RESULTS_EXISTS); - flags.in_trans= test(thd->server_status & SERVER_STATUS_IN_TRANS); + flags.in_trans= thd->in_active_multi_stmt_transaction(); flags.autocommit= test(thd->server_status & SERVER_STATUS_AUTOCOMMIT); flags.pkt_nr= net->pkt_nr; flags.character_set_client_num= @@ -1470,7 +1470,7 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length) flags.protocol_type= (unsigned int) thd->protocol->type(); flags.more_results_exists= test(thd->server_status & SERVER_MORE_RESULTS_EXISTS); - flags.in_trans= test(thd->server_status & SERVER_STATUS_IN_TRANS); + flags.in_trans= thd->in_active_multi_stmt_transaction(); flags.autocommit= test(thd->server_status & SERVER_STATUS_AUTOCOMMIT); flags.pkt_nr= thd->net.pkt_nr; flags.character_set_client_num= thd->variables.character_set_client->number; @@ -1541,7 +1541,7 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", } DBUG_PRINT("qcache", ("Query have result 0x%lx", (ulong) query)); - if (thd->in_multi_stmt_transaction() && + if (thd->in_multi_stmt_transaction_mode() && (query->tables_type() & HA_CACHE_TBL_TRANSACT)) { DBUG_PRINT("qcache", @@ -1698,7 +1698,7 @@ void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used, if (is_disabled()) DBUG_VOID_RETURN; - using_transactions= using_transactions && thd->in_multi_stmt_transaction(); + using_transactions= using_transactions && thd->in_multi_stmt_transaction_mode(); for (; tables_used; tables_used= tables_used->next_local) { DBUG_ASSERT(!using_transactions || tables_used->table!=0); @@ -1782,7 +1782,7 @@ void Query_cache::invalidate(THD *thd, TABLE *table, if (is_disabled()) DBUG_VOID_RETURN; - using_transactions= using_transactions && thd->in_multi_stmt_transaction(); + using_transactions= using_transactions && thd->in_multi_stmt_transaction_mode(); if (using_transactions && (table->file->table_cache_type() == HA_CACHE_TBL_TRANSACT)) thd->add_changed_table(table); @@ -1800,7 +1800,7 @@ void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length, if (is_disabled()) DBUG_VOID_RETURN; - using_transactions= using_transactions && thd->in_multi_stmt_transaction(); + using_transactions= using_transactions && thd->in_multi_stmt_transaction_mode(); if (using_transactions) // used for innodb => has_transactions() is TRUE thd->add_changed_table(key, key_length); else @@ -3572,7 +3572,7 @@ Query_cache::is_cacheable(THD *thd, size_t query_len, const char *query, tables_type))) DBUG_RETURN(0); - if (thd->in_multi_stmt_transaction() && + if (thd->in_multi_stmt_transaction_mode() && ((*tables_type)&HA_CACHE_TBL_TRANSACT)) { DBUG_PRINT("qcache", ("not in autocommin mode")); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 049975bccd9..ac092756a74 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -261,11 +261,13 @@ int thd_tablespace_op(const THD *thd) extern "C" -const char *set_thd_proc_info(THD *thd, const char *info, +const char *set_thd_proc_info(void *thd_arg, const char *info, const char *calling_function, const char *calling_file, const unsigned int calling_line) { + THD *thd= (THD *) thd_arg; + if (!thd) thd= current_thd; @@ -491,7 +493,6 @@ THD::THD() rli_fake(0), lock_id(&main_lock_id), user_time(0), in_sub_stmt(0), - sql_log_bin_toplevel(false), binlog_unsafe_warning_flags(0), binlog_table_maps(0), table_map_for_update(0), arg_of_last_insert_id_function(FALSE), @@ -960,7 +961,11 @@ void THD::init(void) update_charset(); reset_current_stmt_binlog_format_row(); bzero((char *) &status_var, sizeof(status_var)); - sql_log_bin_toplevel= variables.option_bits & OPTION_BIN_LOG; + + if (variables.sql_log_bin) + variables.option_bits|= OPTION_BIN_LOG; + else + variables.option_bits&= ~OPTION_BIN_LOG; #if defined(ENABLED_DEBUG_SYNC) /* Initialize the Debug Sync Facility. See debug_sync.cc. */ @@ -1474,7 +1479,7 @@ void THD::add_changed_table(TABLE *table) { DBUG_ENTER("THD::add_changed_table(table)"); - DBUG_ASSERT(in_multi_stmt_transaction() && table->file->has_transactions()); + DBUG_ASSERT(in_multi_stmt_transaction_mode() && table->file->has_transactions()); add_changed_table(table->s->table_cache_key.str, (long) table->s->table_cache_key.length); DBUG_VOID_RETURN; @@ -3189,6 +3194,11 @@ extern "C" bool thd_binlog_filter_ok(const MYSQL_THD thd) { return binlog_filter->db_ok(thd->db); } + +extern "C" bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd) +{ + return sqlcom_can_generate_row_events(thd); +} #endif // INNODB_COMPATIBILITY_HOOKS */ /**************************************************************************** @@ -3914,7 +3924,8 @@ int THD::decide_logging_format(TABLE_LIST *tables) */ my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0)); } - else if (variables.binlog_format == BINLOG_FORMAT_ROW) + else if (variables.binlog_format == BINLOG_FORMAT_ROW && + sqlcom_can_generate_row_events(this)) { /* 2. Error: Cannot modify table that uses a storage engine @@ -3952,7 +3963,8 @@ int THD::decide_logging_format(TABLE_LIST *tables) */ my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0)); } - else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0) + else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0 && + sqlcom_can_generate_row_events(this)) { /* 5. Error: Cannot modify table that uses a storage engine @@ -4197,7 +4209,9 @@ field_type_name(enum_field_types type) #endif -namespace { +/* Declare in unnamed namespace. */ +CPP_UNNAMED_NS_START + /** Class to handle temporary allocation of memory for row data. @@ -4316,8 +4330,8 @@ namespace { uchar *m_memory; uchar *m_ptr[2]; }; -} +CPP_UNNAMED_NS_END int THD::binlog_write_row(TABLE* table, bool is_trans, MY_BITMAP const* cols, size_t colcnt, @@ -4608,8 +4622,13 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg, because the warnings should be printed only if the statement is actually logged. When executing decide_logging_format(), we cannot know for sure if the statement will be logged. + + Besides, we should not try to print these warnings if it is not + possible to write statements to the binary log as it happens when + the execution is inside a function, or generaly speaking, when + the variables.option_bits & OPTION_BIN_LOG is false. */ - if (sql_log_bin_toplevel) + if (variables.option_bits & OPTION_BIN_LOG) issue_unsafe_warnings(); switch (qtype) { diff --git a/sql/sql_class.h b/sql/sql_class.h index 93433ff85c8..25b136bc4ca 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -428,6 +428,7 @@ typedef struct system_variables uint binlog_format; ///< binlog format for this thd (see enum_binlog_format) my_bool binlog_direct_non_trans_update; + my_bool sql_log_bin; uint completion_type; uint query_cache_type; uint tx_isolation; @@ -1672,8 +1673,6 @@ public: /* <> 0 if we are inside of trigger or stored function. */ uint in_sub_stmt; - /* TRUE when the current top has SQL_LOG_BIN ON */ - bool sql_log_bin_toplevel; /* container for handler's private per-connection data */ Ha_data ha_data[MAX_HA]; @@ -2119,8 +2118,6 @@ public: char scramble[SCRAMBLE_LENGTH+1]; bool slave_thread, one_shot_set; - bool locked, some_tables_deleted; - bool last_cuted_field; bool no_errors, password; /** Set to TRUE if execution of the current compound statement @@ -2369,10 +2366,6 @@ public: { return limit_found_rows; } - inline bool active_transaction() - { - return server_status & SERVER_STATUS_IN_TRANS; - } /** Returns TRUE if session is in a multi-statement transaction mode. @@ -2383,11 +2376,60 @@ public: OPTION_BEGIN: Regardless of the autocommit status, a multi-statement transaction can be explicitly started with the statements "START TRANSACTION", "BEGIN [WORK]", "[COMMIT | ROLLBACK] AND CHAIN", etc. + + Note: this doesn't tell you whether a transaction is active. + A session can be in multi-statement transaction mode, and yet + have no active transaction, e.g., in case of: + set @@autocommit=0; + set @a= 3; <-- these statements don't + set transaction isolation level serializable; <-- start an active + flush tables; <-- transaction + + I.e. for the above scenario this function returns TRUE, even + though no active transaction has begun. + @sa in_active_multi_stmt_transaction() */ - inline bool in_multi_stmt_transaction() + inline bool in_multi_stmt_transaction_mode() { return variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN); } + /** + TRUE if the session is in a multi-statement transaction mode + (@sa in_multi_stmt_transaction_mode()) *and* there is an + active transaction, i.e. there is an explicit start of a + transaction with BEGIN statement, or implicit with a + statement that uses a transactional engine. + + For example, these scenarios don't start an active transaction + (even though the server is in multi-statement transaction mode): + + set @@autocommit=0; + select * from nontrans_table; + set @var=TRUE; + flush tables; + + Note, that even for a statement that starts a multi-statement + transaction (i.e. select * from trans_table), this + flag won't be set until we open the statement's tables + and the engines register themselves for the transaction + (see trans_register_ha()), + hence this method is reliable to use only after + open_tables() has completed. + + Why do we need a flag? + ---------------------- + We need to maintain a (at first glance redundant) + session flag, rather than looking at thd->transaction.all.ha_list + because of explicit start of a transaction with BEGIN. + + I.e. in case of + BEGIN; + select * from nontrans_t1; <-- in_active_multi_stmt_transaction() is true + */ + inline bool in_active_multi_stmt_transaction() + { + return server_status & SERVER_STATUS_IN_TRANS; + } inline bool fill_derived_tables() { return !stmt_arena->is_stmt_prepare() && !lex->only_view_structure(); @@ -3582,6 +3624,12 @@ public: */ #define CF_PROTECT_AGAINST_GRL (1U << 10) +/** + Identifies statements that may generate row events + and that may end up in the binary log. +*/ +#define CF_CAN_GENERATE_ROW_EVENTS (1U << 11) + /* Bits in server_command_flags */ /** @@ -3642,7 +3690,7 @@ inline bool add_group_to_list(THD *thd, Item *item, bool asc) three calling-info parameters. */ extern "C" -const char *set_thd_proc_info(THD *thd, const char *info, +const char *set_thd_proc_info(void *thd_arg, const char *info, const char *calling_func, const char *calling_file, const unsigned int calling_line); diff --git a/sql/sql_const.h b/sql/sql_const.h index 72f34ed6be8..dca66628ddb 100644 --- a/sql/sql_const.h +++ b/sql/sql_const.h @@ -136,7 +136,6 @@ #ifndef MYSQLD_NET_RETRY_COUNT #define MYSQLD_NET_RETRY_COUNT 10 ///< Abort read after this many int. #endif -#define TEMP_POOL_SIZE 128 #define QUERY_ALLOC_BLOCK_SIZE 8192 #define QUERY_ALLOC_PREALLOC_SIZE 8192 @@ -146,11 +145,8 @@ #define ACL_ALLOC_BLOCK_SIZE 1024 #define UDF_ALLOC_BLOCK_SIZE 1024 #define TABLE_ALLOC_BLOCK_SIZE 1024 -#define BDB_LOG_ALLOC_BLOCK_SIZE 1024 #define WARN_ALLOC_BLOCK_SIZE 2048 #define WARN_ALLOC_PREALLOC_SIZE 1024 -#define PROFILE_ALLOC_BLOCK_SIZE 2048 -#define PROFILE_ALLOC_PREALLOC_SIZE 1024 /* The following parameters is to decide when to use an extra cache to @@ -194,8 +190,6 @@ */ #define MATCHING_ROWS_IN_OTHER_TABLE 10 -#define RAID_BLOCK_SIZE 1024 - #define MY_CHARSET_BIN_MB_MAXLEN 1 /** Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used). */ diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 25e470f56ea..2e86315d072 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -25,8 +25,7 @@ #include "sql_cache.h" // query_cache_* #include "sql_base.h" // open_temprary_table #include "sql_table.h" // build_table_filename -#include "lock.h" // lock_and_wait_for_table_name, - // unlock_table_name +#include "lock.h" // unlock_table_name #include "sql_view.h" // check_key_in_view, mysql_frm_type #include "sql_parse.h" // mysql_init_select #include "sql_acl.h" // *_ACL diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index b8971811f15..88cba22d115 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -377,7 +377,6 @@ void lex_start(THD *thd) lex->subqueries= FALSE; lex->view_prepare_mode= FALSE; lex->derived_tables= 0; - lex->lock_option= TL_READ; lex->safe_to_cache_query= 1; lex->leaf_tables_insert= 0; lex->parsing_options.reset(); @@ -390,7 +389,6 @@ void lex_start(THD *thd) lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc; lex->select_lex.group_list.empty(); lex->select_lex.order_list.empty(); - lex->sql_command= SQLCOM_END; lex->duplicates= DUP_ERROR; lex->ignore= 0; lex->spname= NULL; @@ -1735,7 +1733,6 @@ void st_select_lex::init_query() exclude_from_table_unique_test= no_wrap_view_item= FALSE; nest_level= 0; link_next= 0; - lock_option= TL_READ_DEFAULT; } void st_select_lex::init_select() @@ -2247,6 +2244,7 @@ void LEX::cleanup_lex_after_parse_error(THD *thd) void Query_tables_list::reset_query_tables_list(bool init) { + sql_command= SQLCOM_END; if (!init && query_tables) { TABLE_LIST *table= query_tables; @@ -2309,8 +2307,7 @@ void Query_tables_list::destroy_query_tables_list() */ LEX::LEX() - :result(0), - sql_command(SQLCOM_END), option_type(OPT_DEFAULT), is_lex_started(0) + :result(0), option_type(OPT_DEFAULT), is_lex_started(0) { my_init_dynamic_array2(&plugins, sizeof(plugin_ref), diff --git a/sql/sql_lex.h b/sql/sql_lex.h index e9b5ca00953..40bd3875793 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -739,14 +739,6 @@ public: List<udf_func> udf_list; /* udf function calls stack */ - /** - Per sub-query locking strategy. - Note: This variable might interfer with the corresponding statement-level - variable Lex::lock_option because on how different parser rules depend - on eachother. - */ - thr_lock_type lock_option; - /* This is a copy of the original JOIN USING list that comes from the parser. The parser : @@ -1005,8 +997,11 @@ extern const LEX_STRING empty_lex_str; /* - Class representing list of all tables used by statement. - It also contains information about stored functions used by statement + Class representing list of all tables used by statement and other + information which is necessary for opening and locking its tables, + like SQL command for this statement. + + Also contains information about stored functions used by statement since during its execution we may have to add all tables used by its stored functions/triggers to this list in order to pre-open and lock them. @@ -1018,6 +1013,13 @@ extern const LEX_STRING empty_lex_str; class Query_tables_list { public: + /** + SQL command for this statement. Part of this class since the + process of opening and locking tables for the statement needs + this information to determine correct type of lock for some of + the tables. + */ + enum_sql_command sql_command; /* Global list of all tables used by this statement */ TABLE_LIST *query_tables; /* Pointer to next_global member of last element in the previous list. */ @@ -1920,7 +1922,6 @@ struct LEX: public Query_tables_list the variable can contain 0 or 1 for each nest level. */ nesting_map allow_sum_func; - enum_sql_command sql_command; Sql_statement *m_stmt; @@ -1932,7 +1933,6 @@ struct LEX: public Query_tables_list */ bool expr_allows_subselect; - thr_lock_type lock_option; enum SSL_type ssl_type; /* defined in violite.h */ enum enum_duplicates duplicates; enum enum_tx_isolation tx_isolation; @@ -2249,11 +2249,21 @@ public: yacc_yyss= NULL; yacc_yyvs= NULL; m_set_signal_info.clear(); + m_lock_type= TL_READ_DEFAULT; } ~Yacc_state(); /** + Reset part of the state which needs resetting before parsing + substatement. + */ + void reset_before_substatement() + { + m_lock_type= TL_READ_DEFAULT; + } + + /** Bison internal state stack, yyss, when dynamically allocated using my_yyoverflow(). */ @@ -2271,6 +2281,25 @@ public: */ Set_signal_information m_set_signal_info; + /** + Type of lock to be used for tables being added to the statement's + table list in table_factor, table_alias_ref, single_multi and + table_wild_one rules. + Statements which use these rules but require lock type different + from one specified by this member have to override it by using + st_select_lex::set_lock_for_tables() method. + + The default value of this member is TL_READ_DEFAULT. The only two + cases in which we change it are: + - When parsing SELECT HIGH_PRIORITY. + - Rule for DELETE. In which we use this member to pass information + about type of lock from delete to single_multi part of rule. + + We should try to avoid introducing new use cases as we would like + to get rid of this member eventually. + */ + thr_lock_type m_lock_type; + /* TODO: move more attributes from the LEX structure here. */ diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 6e8913b171d..2c42f29ae71 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2006 MySQL AB, 2008-2009 Sun Microsystems, Inc +/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved. 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 @@ -132,6 +132,7 @@ static int read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, const char* db_arg, /* table's database */ const char* table_name_arg, + bool is_concurrent, enum enum_duplicates duplicates, bool ignore, bool transactional_table, @@ -184,6 +185,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, char *tdb= thd->db ? thd->db : db; // Result is never null ulong skip_lines= ex->skip_lines; bool transactional_table; + bool is_concurrent; THD::killed_state killed_status= THD::NOT_KILLED; DBUG_ENTER("mysql_load"); @@ -245,6 +247,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, table= table_list->table; transactional_table= table->file->has_transactions(); + is_concurrent= (table_list->lock_type == TL_WRITE_CONCURRENT_INSERT); if (!fields_vars.elements) { @@ -557,6 +560,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, (void) write_execute_load_query_log_event(thd, ex, table_list->db, table_list->table_name, + is_concurrent, handle_duplicates, ignore, transactional_table, errcode); @@ -604,6 +608,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); error= write_execute_load_query_log_event(thd, ex, table_list->db, table_list->table_name, + is_concurrent, handle_duplicates, ignore, transactional_table, errcode); @@ -632,6 +637,7 @@ err: static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, const char* db_arg, /* table's database */ const char* table_name_arg, + bool is_concurrent, enum enum_duplicates duplicates, bool ignore, bool transactional_table, @@ -667,8 +673,8 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, tbl= string_buf.c_ptr_safe(); } - Load_log_event lle(thd, ex, tdb, tbl, fv, duplicates, - ignore, transactional_table); + Load_log_event lle(thd, ex, tdb, tbl, fv, is_concurrent, + duplicates, ignore, transactional_table); /* force in a LOCAL if there was one in the original. @@ -1702,7 +1708,7 @@ bool READ_INFO::find_start_of_fields() /* Clear taglist from tags with a specified level */ -int READ_INFO::clear_level(int level) +int READ_INFO::clear_level(int level_arg) { DBUG_ENTER("READ_INFO::read_xml clear_level"); List_iterator<XML_TAG> xmlit(taglist); @@ -1711,7 +1717,7 @@ int READ_INFO::clear_level(int level) while ((tag= xmlit++)) { - if(tag->level >= level) + if(tag->level >= level_arg) { xmlit.remove(); delete tag; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 90302c0f7ac..80a41fae9b9 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -247,8 +247,19 @@ void init_update_queries(void) /* Initialize the sql command flags array. */ memset(sql_command_flags, 0, sizeof(sql_command_flags)); + /* + In general, DDL statements do not generate row events and do not go + through a cache before being written to the binary log. However, the + CREATE TABLE...SELECT is an exception because it may generate row + events. For that reason, the SQLCOM_CREATE_TABLE which represents + a CREATE TABLE, including the CREATE TABLE...SELECT, has the + CF_CAN_GENERATE_ROW_EVENTS flag. The distinction between a regular + CREATE TABLE and the CREATE TABLE...SELECT is made in other parts of + the code, in particular in the Query_log_event's constructor. + */ sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL; + CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL | + CF_CAN_GENERATE_ROW_EVENTS; sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND | CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL; @@ -256,7 +267,8 @@ void init_update_queries(void) CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_PROTECT_AGAINST_GRL; + CF_PROTECT_AGAINST_GRL | + CF_CAN_GENERATE_ROW_EVENTS; sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS; @@ -275,22 +287,32 @@ void init_update_queries(void) sql_command_flags[SQLCOM_DROP_TRIGGER]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_PROTECT_AGAINST_GRL; + CF_PROTECT_AGAINST_GRL | + CF_CAN_GENERATE_ROW_EVENTS; sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_PROTECT_AGAINST_GRL; + CF_PROTECT_AGAINST_GRL | + CF_CAN_GENERATE_ROW_EVENTS; sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_PROTECT_AGAINST_GRL; + CF_PROTECT_AGAINST_GRL | + CF_CAN_GENERATE_ROW_EVENTS; sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_PROTECT_AGAINST_GRL; + CF_PROTECT_AGAINST_GRL | + CF_CAN_GENERATE_ROW_EVENTS; sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_PROTECT_AGAINST_GRL; + CF_PROTECT_AGAINST_GRL | + CF_CAN_GENERATE_ROW_EVENTS; sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | - CF_PROTECT_AGAINST_GRL; - sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE; - sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE; - sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE; + CF_PROTECT_AGAINST_GRL | + CF_CAN_GENERATE_ROW_EVENTS; + sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | + CF_CAN_GENERATE_ROW_EVENTS; + sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | + CF_CAN_GENERATE_ROW_EVENTS; + sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE | + CF_CAN_GENERATE_ROW_EVENTS; sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS; - sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE | + CF_CAN_GENERATE_ROW_EVENTS; sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE; @@ -365,7 +387,9 @@ void init_update_queries(void) last called (or executed) statement is preserved. See mysql_execute_command() for how CF_ROW_COUNT is used. */ - sql_command_flags[SQLCOM_CALL]= CF_REEXECUTION_FRAGILE; + sql_command_flags[SQLCOM_CALL]= CF_REEXECUTION_FRAGILE | + CF_CAN_GENERATE_ROW_EVENTS; + sql_command_flags[SQLCOM_EXECUTE]= CF_CAN_GENERATE_ROW_EVENTS; /* The following admin table operations are allowed @@ -390,7 +414,12 @@ void init_update_queries(void) sql_command_flags[SQLCOM_CHECK]= CF_AUTO_COMMIT_TRANS; } - +bool sqlcom_can_generate_row_events(const THD *thd) +{ + return (sql_command_flags[thd->lex->sql_command] & + CF_CAN_GENERATE_ROW_EVENTS); +} + bool is_update_query(enum enum_sql_command command) { DBUG_ASSERT(command >= 0 && command <= SQLCOM_END); @@ -2682,6 +2711,10 @@ case SQLCOM_PREPARE: */ lex->unlink_first_table(&link_to_local); + /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */ + if (create_info.options & HA_LEX_CREATE_TMP_TABLE) + thd->variables.option_bits|= OPTION_KEEP_LOG; + /* select_create is currently not re-execution friendly and needs to be created for every execution of a PS/SP. @@ -2792,7 +2825,7 @@ end_with_restore_list: client thread has locked tables */ if (thd->locked_tables_mode || - thd->active_transaction() || thd->global_read_lock.is_acquired()) + thd->in_active_multi_stmt_transaction() || thd->global_read_lock.is_acquired()) { my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); @@ -3300,7 +3333,7 @@ end_with_restore_list: Don't allow this within a transaction because we want to use re-generate table */ - if (thd->active_transaction()) + if (thd->in_active_multi_stmt_transaction()) { my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); @@ -4730,6 +4763,9 @@ finish: thd->global_read_lock.start_waiting_global_read_lock(thd); } + DBUG_ASSERT(!thd->in_active_multi_stmt_transaction() || + thd->in_multi_stmt_transaction_mode()); + if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END)) { /* If commit fails, we should be able to reset the OK status. */ @@ -5543,7 +5579,7 @@ void THD::reset_for_next_command() OPTION_STATUS_NO_TRANS_UPDATE | OPTION_KEEP_LOG to not get warnings in ha_rollback_trans() about some tables couldn't be rolled back. */ - if (!thd->in_multi_stmt_transaction()) + if (!thd->in_multi_stmt_transaction_mode()) { thd->variables.option_bits&= ~OPTION_KEEP_LOG; thd->transaction.all.modified_non_trans_table= FALSE; @@ -5729,7 +5765,6 @@ void mysql_init_multi_delete(LEX *lex) lex->select_lex.select_limit= 0; lex->unit.select_limit_cnt= HA_POS_ERROR; lex->select_lex.table_list.save_and_clear(&lex->auxiliary_table_list); - lex->lock_option= TL_READ_DEFAULT; lex->query_tables= 0; lex->query_tables_last= &lex->query_tables; } diff --git a/sql/sql_parse.h b/sql/sql_parse.h index e1543a09549..6d968033ccd 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -79,6 +79,7 @@ bool check_host_name(LEX_STRING *str); bool check_identifier_name(LEX_STRING *str, uint max_char_length, uint err_code, const char *param_for_err_msg); bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length); +bool sqlcom_can_generate_row_events(const THD *thd); bool is_update_query(enum enum_sql_command command); bool is_log_table_write_query(enum enum_sql_command command); bool alloc_query(THD *thd, const char *packet, uint packet_length); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index a3007d1875c..fa9c698622b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -3096,7 +3096,7 @@ int get_partition_id_list_col(partition_info *part_info, } else { - *part_id= (uint32)list_col_array[list_index].partition_id; + *part_id= (uint32)list_col_array[list_index*num_columns].partition_id; DBUG_RETURN(0); } } @@ -4186,7 +4186,6 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index, bool mysql_unpack_partition(THD *thd, const char *part_buf, uint part_info_len, - const char *part_state, uint part_state_len, TABLE* table, bool is_create_table_ind, handlerton *default_db_type, bool *work_part_info_used) @@ -4222,8 +4221,6 @@ bool mysql_unpack_partition(THD *thd, goto end; } part_info= lex.part_info; - part_info->part_state= part_state; - part_info->part_state_len= part_state_len; DBUG_PRINT("info", ("Parse: %s", part_buf)); if (parse_sql(thd, & parser_state, NULL) || part_info->fix_parser_data(thd)) @@ -4587,7 +4584,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, partition_info *tab_part_info= table->part_info; partition_info *alt_part_info= thd->work_part_info; uint flags= 0; - bool is_last_partition_reorged; + bool is_last_partition_reorged= FALSE; part_elem_value *tab_max_elem_val= NULL; part_elem_value *alt_max_elem_val= NULL; longlong tab_max_range= 0, alt_max_range= 0; @@ -7647,7 +7644,7 @@ uint32 get_next_partition_id_range(PARTITION_ITERATOR* part_iter) DESCRIPTION This implementation of PARTITION_ITERATOR::get_next() is special for LIST partitioning: it enumerates partition ids in - part_info->list_array[i] (list_col_array[i] for COLUMNS LIST + part_info->list_array[i] (list_col_array[i*cols] for COLUMNS LIST partitioning) where i runs over [min_idx, max_idx] interval. The function conforms to partition_iter_func type. @@ -7673,9 +7670,12 @@ uint32 get_next_partition_id_list(PARTITION_ITERATOR *part_iter) { partition_info *part_info= part_iter->part_info; uint32 num_part= part_iter->part_nums.cur++; - return part_info->column_list ? - part_info->list_col_array[num_part].partition_id : - part_info->list_array[num_part].partition_id; + if (part_info->column_list) + { + uint num_columns= part_info->part_field_list.elements; + return part_info->list_col_array[num_part*num_columns].partition_id; + } + return part_info->list_array[num_part].partition_id; } } diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 8542074e718..2e0ea740555 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -64,20 +64,6 @@ typedef struct st_lock_param_type partition_info *part_info; } ALTER_PARTITION_PARAM_TYPE; - -/*typedef struct { - ulonglong data_file_length; - ulonglong max_data_file_length; - ulonglong index_file_length; - ulonglong delete_length; - ha_rows records; - ulong mean_rec_length; - time_t create_time; - time_t check_time; - time_t update_time; - ulonglong check_sum; -} PARTITION_INFO; -*/ typedef struct { longlong list_value; uint32 partition_id; @@ -126,7 +112,6 @@ void get_full_part_id_from_key(const TABLE *table, uchar *buf, part_id_range *part_spec); bool mysql_unpack_partition(THD *thd, const char *part_buf, uint part_info_len, - const char *part_state, uint part_state_len, TABLE *table, bool is_create_table_ind, handlerton *default_db_type, bool *work_part_info_used); diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 739b6576a99..c2d3c595d95 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1708,7 +1708,7 @@ static bool mysql_test_create_table(Prepared_statement *stmt) res= select_like_stmt_test(stmt, 0, 0); - lex->link_first_table_back(create_table, &link_to_local); + lex->link_first_table_back(create_table, link_to_local); } else { @@ -3246,7 +3246,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) locks have already been released and our savepoint points to ticket which has been released as well. */ - if (thd->in_multi_stmt_transaction()) + if (thd->in_multi_stmt_transaction_mode()) thd->mdl_context.rollback_to_savepoint(mdl_savepoint); thd->restore_backup_statement(this, &stmt_backup); thd->stmt_arena= old_stmt_arena; diff --git a/sql/sql_priv.h b/sql/sql_priv.h index eeefd3cac04..8601b10b9bf 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -129,6 +129,12 @@ extern char err_shared_dir[]; */ #define TMP_TABLE_FORCE_MYISAM (1ULL << 32) #define OPTION_PROFILING (1ULL << 33) +/** + Indicates that this is a HIGH_PRIORITY SELECT. + Currently used only for printing of such selects. + Type of locks to be acquired is specified directly. +*/ +#define SELECT_HIGH_PRIORITY (1ULL << 34) // SELECT, user /* The rest of the file is included in the server only */ @@ -181,10 +187,6 @@ extern char err_shared_dir[]; #define BINLOG_DUMP_NON_BLOCK 1 -/* sql_show.cc:show_log_files() */ -#define SHOW_LOG_STATUS_FREE "FREE" -#define SHOW_LOG_STATUS_INUSE "IN USE" - /* Some defines for exit codes for ::is_equal class functions. */ diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index d387010141c..ea95b59b0c2 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -54,7 +54,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) if the user is trying to to do this in a transcation context */ - if (thd->locked_tables_mode || thd->active_transaction()) + if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction()) { my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3f04adf066c..45e30bb5be3 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -44,7 +44,7 @@ #include "sql_partition.h" // make_used_partitions_str #include "sql_acl.h" // *_ACL #include "sql_test.h" // print_where, print_keyuse_array, - // print_sjm, print_plan + // print_sjm, print_plan, TEST_join #include "records.h" // init_read_record, end_read_record #include "filesort.h" // filesort_free_buffers #include "sql_union.h" // mysql_union @@ -90,8 +90,10 @@ static bool best_extension_by_limited_search(JOIN *join, double read_time, uint depth, uint prune_level); static uint determine_search_depth(JOIN* join); +C_MODE_START static int join_tab_cmp(const void* ptr1, const void* ptr2); static int join_tab_cmp_straight(const void* ptr1, const void* ptr2); +C_MODE_END /* TODO: 'find_best' is here only temporarily until 'greedy_search' is tested and approved. @@ -17252,8 +17254,7 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type) /* First add options */ if (options & SELECT_STRAIGHT_JOIN) str->append(STRING_WITH_LEN("straight_join ")); - if ((thd->lex->lock_option == TL_READ_HIGH_PRIORITY) && - (this == &thd->lex->select_lex)) + if (options & SELECT_HIGH_PRIORITY) str->append(STRING_WITH_LEN("high_priority ")); if (options & SELECT_DISTINCT) str->append(STRING_WITH_LEN("distinct ")); diff --git a/sql/sql_select.h b/sql/sql_select.h index ccf88c2cc5c..2c44dba74c3 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -597,7 +597,6 @@ typedef struct st_select_check { } SELECT_CHECK; extern const char *join_type_str[]; -void TEST_join(JOIN *join); /* Extern functions in sql_select.cc */ bool store_val_in_field(Field *field, Item *val, enum_check_fields check_flag); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 8daf7a73a80..16a17744279 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -18,6 +18,7 @@ #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" +#include "debug_sync.h" #include "unireg.h" #include "sql_acl.h" // fill_schema_*_privileges #include "sql_select.h" // For select_describe @@ -1944,10 +1945,13 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond) static DYNAMIC_ARRAY all_status_vars; static bool status_vars_inited= 0; + +C_MODE_START static int show_var_cmp(const void *var1, const void *var2) { return strcmp(((SHOW_VAR*)var1)->name, ((SHOW_VAR*)var2)->name); } +C_MODE_END /* deletes all the SHOW_UNDEF elements from the array and calls @@ -3296,12 +3300,17 @@ static int fill_schema_table_from_frm(THD *thd, TABLE_LIST *tables, goto end_share; } + if (!open_table_from_share(thd, share, table_name->str, 0, + (EXTRA_RECORD | OPEN_FRM_FILE_ONLY), + thd->open_options, &tbl, FALSE)) { tbl.s= share; table_list.table= &tbl; table_list.view= (LEX*) share->is_view; res= schema_table->process_table(thd, &table_list, table, res, db_name, table_name); + free_root(&tbl.mem_root, MYF(0)); + my_free((char*) tbl.alias, MYF(MY_ALLOW_ZERO_PTR)); } end_share: @@ -3345,7 +3354,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) LEX *lex= thd->lex; TABLE *table= tables->table; SELECT_LEX *old_all_select_lex= lex->all_selects_list; - enum_sql_command save_sql_command= lex->sql_command; SELECT_LEX *lsel= tables->schema_select_lex; ST_SCHEMA_TABLE *schema_table= tables->schema_table; SELECT_LEX sel; @@ -3381,6 +3389,12 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) lex->view_prepare_mode= TRUE; lex->reset_n_backup_query_tables_list(&query_tables_list_backup); + /* + Restore Query_tables_list::sql_command value, which was reset + above, as ST_SCHEMA_TABLE::process_table() functions often rely + that this value reflects which SHOW statement is executed. + */ + lex->sql_command= query_tables_list_backup.sql_command; /* We should not introduce deadlocks even if we already have some @@ -3544,7 +3558,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) (MYSQL_OPEN_IGNORE_FLUSH | MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL | (can_deadlock ? MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0))); - lex->sql_command= save_sql_command; + lex->sql_command= query_tables_list_backup.sql_command; /* XXX: show_table_list has a flag i_is_requested, and when it's set, open_normal_and_derived_tables() @@ -3603,7 +3617,6 @@ err: lex->derived_tables= derived_tables; lex->all_selects_list= old_all_select_lex; lex->view_prepare_mode= save_view_prepare_mode; - lex->sql_command= save_sql_command; DBUG_RETURN(error); } @@ -3751,7 +3764,7 @@ static int get_schema_tables_record(THD *thd, TABLE_LIST *tables, } #ifdef WITH_PARTITION_STORAGE_ENGINE if (share->db_type() == partition_hton && - share->partition_info_len) + share->partition_info_str_len) { tmp_db_type= share->default_part_db_type; is_partitioned= TRUE; @@ -4025,7 +4038,6 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, const char *wild= lex->wild ? lex->wild->ptr() : NullS; CHARSET_INFO *cs= system_charset_info; TABLE *show_table; - TABLE_SHARE *show_table_share; Field **ptr, *field, *timestamp_field; int count; DBUG_ENTER("get_schema_column_record"); @@ -4048,37 +4060,11 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, } show_table= tables->table; - show_table_share= show_table->s; count= 0; - - if (tables->view || tables->schema_table) - { - ptr= show_table->field; - timestamp_field= show_table->timestamp_field; - show_table->use_all_columns(); // Required for default - } - else - { - ptr= show_table_share->field; - timestamp_field= show_table_share->timestamp_field; - /* - read_set may be inited in case of - temporary table - */ - if (!show_table->read_set) - { - /* to satisfy 'field->val_str' ASSERTs */ - uchar *bitmaps; - uint bitmap_size= show_table_share->column_bitmap_size; - if (!(bitmaps= (uchar*) alloc_root(thd->mem_root, bitmap_size))) - DBUG_RETURN(0); - bitmap_init(&show_table->def_read_set, - (my_bitmap_map*) bitmaps, show_table_share->fields, FALSE); - bitmap_set_all(&show_table->def_read_set); - show_table->read_set= &show_table->def_read_set; - } - bitmap_set_all(show_table->read_set); - } + ptr= show_table->field; + timestamp_field= show_table->timestamp_field; + show_table->use_all_columns(); // Required for default + restore_record(show_table, s->default_values); for (; (field= *ptr) ; ptr++) { @@ -4087,9 +4073,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, String type(tmp,sizeof(tmp), system_charset_info); char *end; - /* to satisfy 'field->val_str' ASSERTs */ - field->table= show_table; - show_table->in_use= thd; + DEBUG_SYNC(thd, "get_schema_column"); if (wild && wild[0] && wild_case_compare(system_charset_info, field->field_name,wild)) @@ -5240,7 +5224,8 @@ static int get_schema_key_column_usage_record(THD *thd, #ifdef WITH_PARTITION_STORAGE_ENGINE -static void collect_partition_expr(List<char> &field_list, String *str) +static void collect_partition_expr(THD *thd, List<char> &field_list, + String *str) { List_iterator<char> part_it(field_list); ulong no_fields= field_list.elements; @@ -5248,7 +5233,7 @@ static void collect_partition_expr(List<char> &field_list, String *str) str->length(0); while ((field_str= part_it++)) { - str->append(field_str); + append_identifier(thd, str, field_str, strlen(field_str)); if (--no_fields != 0) str->append(","); } @@ -5315,7 +5300,7 @@ static void store_schema_partitions_record(THD *thd, TABLE *schema_table, { TABLE* table= schema_table; CHARSET_INFO *cs= system_charset_info; - PARTITION_INFO stat_info; + PARTITION_STATS stat_info; MYSQL_TIME time; file->get_dynamic_partition_info(&stat_info, part_id); table->field[0]->store(STRING_WITH_LEN("def"), cs); @@ -5515,7 +5500,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, } else if (part_info->list_of_part_fields) { - collect_partition_expr(part_info->part_field_list, &tmp_str); + collect_partition_expr(thd, part_info->part_field_list, &tmp_str); table->field[9]->store(tmp_str.ptr(), tmp_str.length(), cs); } table->field[9]->set_notnull(); @@ -5544,7 +5529,7 @@ static int get_schema_partitions_record(THD *thd, TABLE_LIST *tables, } else if (part_info->list_of_subpart_fields) { - collect_partition_expr(part_info->subpart_field_list, &tmp_str); + collect_partition_expr(thd, part_info->subpart_field_list, &tmp_str); table->field[10]->store(tmp_str.ptr(), tmp_str.length(), cs); } table->field[10]->set_notnull(); diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 9fbc06b7529..762eebba031 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -24,13 +24,6 @@ #include <m_string.h> #include <m_ctype.h> #include <mysql_com.h> -/* - The following extern declarations are ok as these are interface functions - required by the string function -*/ - -extern uchar* sql_alloc(unsigned size); -extern void sql_element_free(void *ptr); #include "sql_string.h" diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 9177573971e..5052e29ac30 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1782,11 +1782,12 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) error= 1; goto err; } - share->partition_info= tmp_part_syntax_str; + share->partition_info_str= tmp_part_syntax_str; } else - memcpy((char*) share->partition_info, part_syntax_buf, syntax_len + 1); - share->partition_info_len= part_info->part_info_len= syntax_len; + memcpy((char*) share->partition_info_str, part_syntax_buf, + syntax_len + 1); + share->partition_info_str_len= part_info->part_info_len= syntax_len; part_info->part_info_string= part_syntax_buf; } #endif @@ -1929,8 +1930,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, bool dont_log_query) { TABLE_LIST *table; - char path[FN_REFLEN + 1], *alias; - uint path_length; + char path[FN_REFLEN + 1], *alias= NULL; + uint path_length= 0; String wrong_tables; int error= 0; int non_temp_tables_count= 0; @@ -1939,9 +1940,6 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, String built_tmp_query; DBUG_ENTER("mysql_rm_table_part2"); - LINT_INIT(alias); - LINT_INIT(path_length); - if (thd->is_current_stmt_binlog_format_row() && !dont_log_query) { built_query.set_charset(system_charset_info); @@ -4839,6 +4837,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, /* purecov: begin inspected */ char buff[FN_REFLEN + MYSQL_ERRMSG_SIZE]; size_t length; + enum_sql_command save_sql_command= lex->sql_command; DBUG_PRINT("admin", ("sending error message")); protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); @@ -4852,6 +4851,11 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, close_thread_tables(thd); thd->mdl_context.release_transactional_locks(); lex->reset_query_tables_list(FALSE); + /* + Restore Query_tables_list::sql_command value to make statement + safe for re-execution. + */ + lex->sql_command= save_sql_command; table->table=0; // For query cache if (protocol->write()) goto err; @@ -5049,7 +5053,7 @@ send_result_message: /* Clear the ticket released in close_thread_tables(). */ table->mdl_request.ticket= NULL; DEBUG_SYNC(thd, "ha_admin_open_ltable"); - if (table->table= open_ltable(thd, table, lock_type, 0)) + if ((table->table= open_ltable(thd, table, lock_type, 0))) { result_code= table->table->file->ha_analyze(thd, check_opt); if (result_code == HA_ADMIN_ALREADY_DONE) @@ -6584,7 +6588,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, if the user is trying to to do this in a transcation context */ - if (thd->locked_tables_mode || thd->active_transaction()) + if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction()) { my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); diff --git a/sql/sql_test.cc b/sql/sql_test.cc index d34aee854d0..43d203e6498 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -76,7 +76,7 @@ print_where(COND *cond,const char *info, enum_query_type query_type) /* This is for debugging purposes */ -void print_cached_tables(void) +static void print_cached_tables(void) { uint idx,count,unused; TABLE_SHARE *share; @@ -341,6 +341,11 @@ print_plan(JOIN* join, uint idx, double record_count, double read_time, #endif +C_MODE_START +static int dl_compare(const void *p1, const void *p2); +static int print_key_cache_status(const char *name, KEY_CACHE *key_cache); +C_MODE_END + typedef struct st_debug_lock { ulong thread_id; @@ -350,8 +355,13 @@ typedef struct st_debug_lock enum thr_lock_type type; } TABLE_LOCK_INFO; -static int dl_compare(TABLE_LOCK_INFO *a,TABLE_LOCK_INFO *b) +static int dl_compare(const void *p1, const void *p2) { + TABLE_LOCK_INFO *a, *b; + + a= (TABLE_LOCK_INFO *) p1; + b= (TABLE_LOCK_INFO *) p2; + if (a->thread_id > b->thread_id) return 1; if (a->thread_id < b->thread_id) @@ -401,9 +411,10 @@ static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data, function so that we can easily add this if we ever need this. */ -static void display_table_locks(void) +static void display_table_locks(void) { LIST *list; + void *saved_base; DYNAMIC_ARRAY saved_table_locks; (void) my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO), table_cache_count + 20,50); @@ -424,13 +435,17 @@ static void display_table_locks(void) mysql_mutex_unlock(&lock->mutex); } mysql_mutex_unlock(&THR_LOCK_lock); - if (!saved_table_locks.elements) goto end; - - qsort((uchar*) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare); + + if (!saved_table_locks.elements) + goto end; + + saved_base= dynamic_element(&saved_table_locks, 0, TABLE_LOCK_INFO *); + my_qsort(saved_base, saved_table_locks.elements, sizeof(TABLE_LOCK_INFO), + dl_compare); freeze_size(&saved_table_locks); puts("\nThread database.table_name Locked/Waiting Lock_type\n"); - + unsigned int i; for (i=0 ; i < saved_table_locks.elements ; i++) { diff --git a/sql/sql_test.h b/sql/sql_test.h index 539e89ec949..d7fcc126cb2 100644 --- a/sql/sql_test.h +++ b/sql/sql_test.h @@ -26,8 +26,8 @@ typedef struct st_sort_field SORT_FIELD; #ifndef DBUG_OFF void print_where(COND *cond,const char *info, enum_query_type query_type); -void print_cached_tables(void); void TEST_filesort(SORT_FIELD *sortorder,uint s_length); +void TEST_join(JOIN *join); void print_plan(JOIN* join,uint idx, double record_count, double read_time, double current_read_time, const char *info); void dump_TABLE_LIST_graph(SELECT_LEX *select_lex, TABLE_LIST* tl); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 701a2ec93c2..9ce62d9f2a4 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -411,6 +411,13 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) destructive changes necessary to open the trigger's table. */ thd->lex->reset_n_backup_query_tables_list(&backup); + /* + Restore Query_tables_list::sql_command, which was + reset above, as the code that writes the query to the + binary log assumes that this value corresponds to the + statement that is being executed. + */ + thd->lex->sql_command= backup.sql_command; if (add_table_for_trigger(thd, thd->lex->spname, if_exists, & tables)) goto end; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index fe6e0994959..e7cc133e01b 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1056,7 +1056,7 @@ int mysql_multi_update_prepare(THD *thd) be write-locked (for example, trigger to be invoked might try to update this table). */ - tl->lock_type= read_lock_type_for_table(thd, table); + tl->lock_type= read_lock_type_for_table(thd, lex, tl); tl->updating= 0; /* Update TABLE::lock_type accordingly. */ if (!tl->placeholder() && !using_lock_tables) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f9478b8c5f5..9f20a4ccf71 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -29,6 +29,7 @@ #define YYLEX_PARAM yythd #define YYTHD ((THD *)yythd) #define YYLIP (& YYTHD->m_parser_state->m_lip) +#define YYPS (& YYTHD->m_parser_state->m_yacc) #define MYSQL_YACC #define YYINITDEPTH 100 @@ -4937,7 +4938,6 @@ create_select: SELECT_SYM { LEX *lex=Lex; - lex->lock_option= TL_READ_DEFAULT; if (lex->sql_command == SQLCOM_INSERT) lex->sql_command= SQLCOM_INSERT_SELECT; else if (lex->sql_command == SQLCOM_REPLACE) @@ -7302,7 +7302,6 @@ select_lock_type: { LEX *lex=Lex; lex->current_select->set_lock_for_tables(TL_WRITE); - lex->current_select->lock_option= TL_WRITE; lex->safe_to_cache_query=0; lex->protect_against_global_read_lock= TRUE; } @@ -7311,7 +7310,6 @@ select_lock_type: LEX *lex=Lex; lex->current_select-> set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS); - lex->current_select->lock_option= TL_READ_WITH_SHARED_LOCKS; lex->safe_to_cache_query=0; } ; @@ -9221,7 +9219,7 @@ table_factor: { if (!($$= Select->add_table_to_list(YYTHD, $2, $3, Select->get_table_join_options(), - Lex->lock_option, + YYPS->m_lock_type, Select->pop_index_hints()))) MYSQL_YYABORT; Select->add_joined_table($$); @@ -10278,7 +10276,7 @@ table_alias_ref: { if (!Select->add_table_to_list(YYTHD, $1, NULL, TL_OPTION_UPDATING | TL_OPTION_ALIAS, - Lex->lock_option )) + YYPS->m_lock_type)) MYSQL_YYABORT; } ; @@ -10303,8 +10301,6 @@ insert: lex->sql_command= SQLCOM_INSERT; lex->duplicates= DUP_ERROR; mysql_init_select(lex); - /* for subselects */ - lex->lock_option= TL_READ_DEFAULT; } insert_lock_option opt_ignore insert2 @@ -10495,7 +10491,6 @@ update: LEX *lex= Lex; mysql_init_select(lex); lex->sql_command= SQLCOM_UPDATE; - lex->lock_option= TL_UNLOCK; /* Will be set later */ lex->duplicates= DUP_ERROR; } opt_low_priority opt_ignore join_table_list @@ -10562,7 +10557,7 @@ delete: LEX *lex= Lex; lex->sql_command= SQLCOM_DELETE; mysql_init_select(lex); - lex->lock_option= TL_WRITE_DEFAULT; + YYPS->m_lock_type= TL_WRITE_DEFAULT; lex->ignore= 0; lex->select_lex.init_order(); } @@ -10573,20 +10568,27 @@ single_multi: FROM table_ident { if (!Select->add_table_to_list(YYTHD, $2, NULL, TL_OPTION_UPDATING, - Lex->lock_option)) + YYPS->m_lock_type)) MYSQL_YYABORT; + YYPS->m_lock_type= TL_READ_DEFAULT; } where_clause opt_order_clause delete_limit_clause {} | table_wild_list - { mysql_init_multi_delete(Lex); } + { + mysql_init_multi_delete(Lex); + YYPS->m_lock_type= TL_READ_DEFAULT; + } FROM join_table_list where_clause { if (multi_delete_set_locks_and_link_aux_tables(Lex)) MYSQL_YYABORT; } | FROM table_alias_ref_list - { mysql_init_multi_delete(Lex); } + { + mysql_init_multi_delete(Lex); + YYPS->m_lock_type= TL_READ_DEFAULT; + } USING join_table_list where_clause { if (multi_delete_set_locks_and_link_aux_tables(Lex)) @@ -10609,7 +10611,7 @@ table_wild_one: ti, NULL, TL_OPTION_UPDATING | TL_OPTION_ALIAS, - Lex->lock_option)) + YYPS->m_lock_type)) MYSQL_YYABORT; } | ident '.' ident opt_wild @@ -10621,7 +10623,7 @@ table_wild_one: ti, NULL, TL_OPTION_UPDATING | TL_OPTION_ALIAS, - Lex->lock_option)) + YYPS->m_lock_type)) MYSQL_YYABORT; } ; @@ -10638,7 +10640,7 @@ opt_delete_options: opt_delete_option: QUICK { Select->options|= OPTION_QUICK; } - | LOW_PRIORITY { Lex->lock_option= TL_WRITE_LOW_PRIORITY; } + | LOW_PRIORITY { YYPS->m_lock_type= TL_WRITE_LOW_PRIORITY; } | IGNORE_SYM { Lex->ignore= 1; } ; @@ -10724,7 +10726,6 @@ show: { LEX *lex=Lex; lex->wild=0; - lex->lock_option= TL_READ; mysql_init_select(lex); lex->current_select->parsing_place= SELECT_LIST; bzero((char*) &lex->create_info,sizeof(lex->create_info)); @@ -11077,7 +11078,6 @@ describe: describe_command table_ident { LEX *lex= Lex; - lex->lock_option= TL_READ; mysql_init_select(lex); lex->current_select->parsing_place= SELECT_LIST; lex->sql_command= SQLCOM_SHOW_FIELDS; @@ -11291,7 +11291,6 @@ load: { LEX *lex=Lex; lex->sql_command= SQLCOM_LOAD; - lex->lock_option= $4; lex->local_file= $5; lex->duplicates= DUP_ERROR; lex->ignore= 0; @@ -11302,7 +11301,7 @@ load: { LEX *lex=Lex; if (!Select->add_table_to_list(YYTHD, $12, NULL, TL_OPTION_UPDATING, - lex->lock_option)) + $4)) MYSQL_YYABORT; lex->field_list.empty(); lex->update_list.empty(); @@ -13734,17 +13733,6 @@ subselect_start: subselect_end: { LEX *lex=Lex; - /* - Set the required lock level for the tables associated with the - current sub-select. This will overwrite previous lock options set - using st_select_lex::add_table_to_list in any of the following - rules: single_multi, table_wild_one, load_data, table_alias_ref, - table_factor. - The default lock level is TL_READ_DEFAULT but it can be modified - with query options specific for a certain (sub-)SELECT. - */ - lex->current_select-> - set_lock_for_tables(lex->current_select->lock_option); lex->pop_context(); SELECT_LEX *child= lex->current_select; @@ -13776,8 +13764,8 @@ query_expression_option: { if (check_simple_select()) MYSQL_YYABORT; - Lex->lock_option= TL_READ_HIGH_PRIORITY; - Lex->current_select->lock_option= TL_READ_HIGH_PRIORITY; + YYPS->m_lock_type= TL_READ_HIGH_PRIORITY; + Select->options|= SELECT_HIGH_PRIORITY; } | DISTINCT { Select->options|= SELECT_DISTINCT; } | SQL_SMALL_RESULT { Select->options|= SELECT_SMALL_RESULT; } diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 5f75dd4adf5..34a9401a41e 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -295,7 +295,7 @@ static bool binlog_format_check(sys_var *self, THD *thd, set_var *var) /* Make the session variable 'binlog_format' read-only inside a transaction. */ - if (thd->active_transaction()) + if (thd->in_active_multi_stmt_transaction()) { my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0)); return true; @@ -348,7 +348,7 @@ static bool binlog_direct_check(sys_var *self, THD *thd, set_var *var) Makes the session variable 'binlog_direct_non_transactional_updates' read-only inside a transaction. */ - if (thd->active_transaction()) + if (thd->in_active_multi_stmt_transaction()) { my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_DIRECT, MYF(0)); return true; @@ -1428,7 +1428,7 @@ static my_bool read_only; static bool check_read_only(sys_var *self, THD *thd, set_var *var) { /* Prevent self dead-lock */ - if (thd->locked_tables_mode || thd->active_transaction()) + if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction()) { my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); return true; @@ -2013,15 +2013,20 @@ static Sys_var_ulong Sys_thread_pool_size( VALID_RANGE(1, 16384), DEFAULT(20), BLOCK_SIZE(0)); #endif -// Can't change the 'next' tx_isolation if we are already in a transaction +/** + Can't change the 'next' tx_isolation if we are already in a + transaction. +*/ + static bool check_tx_isolation(sys_var *self, THD *thd, set_var *var) { - if (var->type == OPT_DEFAULT && (thd->server_status & SERVER_STATUS_IN_TRANS)) + if (var->type == OPT_DEFAULT && thd->in_active_multi_stmt_transaction()) { + DBUG_ASSERT(thd->in_multi_stmt_transaction_mode()); my_error(ER_CANT_CHANGE_TX_ISOLATION, MYF(0)); - return true; + return TRUE; } - return false; + return FALSE; } /* @@ -2034,6 +2039,7 @@ static bool fix_tx_isolation(sys_var *self, THD *thd, enum_var_type type) thd->session_tx_isolation= (enum_tx_isolation)thd->variables.tx_isolation; return false; } + // NO_CMD_LINE - different name of the option static Sys_var_enum Sys_tx_isolation( "tx_isolation", "Default transaction isolation level", @@ -2237,17 +2243,69 @@ static Sys_var_bit Sys_log_off( SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_LOG_OFF, DEFAULT(FALSE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super)); -static bool fix_sql_log_bin(sys_var *self, THD *thd, enum_var_type type) +/** + This function sets the session variable thd->variables.sql_log_bin + to reflect changes to @@session.sql_log_bin. + + @param[IN] self A pointer to the sys_var, i.e. Sys_log_binlog. + @param[IN] type The type either session or global. + + @return @c FALSE. +*/ +static bool fix_sql_log_bin_after_update(sys_var *self, THD *thd, + enum_var_type type) { - if (type != OPT_GLOBAL && !thd->in_sub_stmt) - thd->sql_log_bin_toplevel= thd->variables.option_bits & OPTION_BIN_LOG; - return false; + if (type == OPT_SESSION) + { + if (thd->variables.sql_log_bin) + thd->variables.option_bits |= OPTION_BIN_LOG; + else + thd->variables.option_bits &= ~OPTION_BIN_LOG; + } + return FALSE; } -static Sys_var_bit Sys_log_binlog( + +/** + This function checks if the sql_log_bin can be changed, + what is possible if: + - the user is a super user; + - the set is not called from within a function/trigger; + - there is no on-going transaction. + + @param[IN] self A pointer to the sys_var, i.e. Sys_log_binlog. + @param[IN] var A pointer to the set_var created by the parser. + + @return @c FALSE if the change is allowed, otherwise @c TRUE. +*/ +static bool check_sql_log_bin(sys_var *self, THD *thd, set_var *var) +{ + if (check_has_super(self, thd, var)) + return TRUE; + + if (var->type == OPT_GLOBAL) + return FALSE; + + /* If in a stored function/trigger, it's too late to change sql_log_bin. */ + if (thd->in_sub_stmt) + { + my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_SQL_LOG_BIN, MYF(0)); + return TRUE; + } + /* Make the session variable 'sql_log_bin' read-only inside a transaction. */ + if (thd->in_active_multi_stmt_transaction()) + { + my_error(ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_SQL_LOG_BIN, MYF(0)); + return TRUE; + } + + return FALSE; +} + +static Sys_var_mybool Sys_log_binlog( "sql_log_bin", "sql_log_bin", - SESSION_VAR(option_bits), NO_CMD_LINE, OPTION_BIN_LOG, - DEFAULT(TRUE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_has_super), - ON_UPDATE(fix_sql_log_bin)); + SESSION_VAR(sql_log_bin), NO_CMD_LINE, + DEFAULT(TRUE), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(check_sql_log_bin), + ON_UPDATE(fix_sql_log_bin_after_update)); static Sys_var_bit Sys_sql_warnings( "sql_warnings", "sql_warnings", @@ -2746,8 +2804,8 @@ static Sys_var_mybool Sys_log_slow( static bool fix_log_state(sys_var *self, THD *thd, enum_var_type type) { bool res; - my_bool *newvalptr, newval, oldval; - uint log_type; + my_bool *UNINIT_VAR(newvalptr), newval, UNINIT_VAR(oldval); + uint UNINIT_VAR(log_type); if (self == &Sys_general_log || self == &Sys_log) { diff --git a/sql/table.cc b/sql/table.cc index 12ac8b11f97..6c0a4a4c674 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -976,28 +976,28 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, } if (next_chunk + 5 < buff_end) { - uint32 partition_info_len = uint4korr(next_chunk); + uint32 partition_info_str_len = uint4korr(next_chunk); #ifdef WITH_PARTITION_STORAGE_ENGINE if ((share->partition_info_buffer_size= - share->partition_info_len= partition_info_len)) + share->partition_info_str_len= partition_info_str_len)) { - if (!(share->partition_info= (char*) + if (!(share->partition_info_str= (char*) memdup_root(&share->mem_root, next_chunk + 4, - partition_info_len + 1))) + partition_info_str_len + 1))) { my_free(buff, MYF(0)); goto err; } } #else - if (partition_info_len) + if (partition_info_str_len) { DBUG_PRINT("info", ("WITH_PARTITION_STORAGE_ENGINE is not defined")); my_free(buff, MYF(0)); goto err; } #endif - next_chunk+= 5 + partition_info_len; + next_chunk+= 5 + partition_info_str_len; } #if MYSQL_VERSION_ID < 50200 if (share->mysql_version >= 50106 && share->mysql_version <= 50109) @@ -1660,6 +1660,10 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, my_hash_free(&share->name_hash); if (share->ha_data_destroy) share->ha_data_destroy(share->ha_data); +#ifdef WITH_PARTITION_STORAGE_ENGINE + if (share->ha_part_data_destroy) + share->ha_part_data_destroy(share->ha_part_data); +#endif open_table_error(share, error, share->open_errno, errarg); DBUG_RETURN(error); @@ -1851,7 +1855,7 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, } #ifdef WITH_PARTITION_STORAGE_ENGINE - if (share->partition_info_len && outparam->file) + if (share->partition_info_str_len && outparam->file) { /* In this execution we must avoid calling thd->change_item_tree since @@ -1872,10 +1876,8 @@ int open_table_from_share(THD *thd, TABLE_SHARE *share, const char *alias, bool tmp; bool work_part_info_used; - tmp= mysql_unpack_partition(thd, share->partition_info, - share->partition_info_len, - share->part_state, - share->part_state_len, + tmp= mysql_unpack_partition(thd, share->partition_info_str, + share->partition_info_str_len, outparam, is_create_table, share->default_part_db_type, &work_part_info_used); diff --git a/sql/table.h b/sql/table.h index 0725d62b286..34f71d6bba4 100644 --- a/sql/table.h +++ b/sql/table.h @@ -488,6 +488,19 @@ typedef struct st_table_field_def } TABLE_FIELD_DEF; +#ifdef WITH_PARTITION_STORAGE_ENGINE +/** + Partition specific ha_data struct. +*/ +typedef struct st_ha_data_partition +{ + bool auto_inc_initialized; + mysql_mutex_t LOCK_auto_inc; /**< protecting auto_inc val */ + ulonglong next_auto_inc_val; /**< first non reserved value */ +} HA_DATA_PARTITION; +#endif + + class Table_check_intact { protected: @@ -627,13 +640,11 @@ struct TABLE_SHARE int cached_row_logging_check; #ifdef WITH_PARTITION_STORAGE_ENGINE - /** @todo: Move into *ha_data for partitioning */ + /* filled in when reading from frm */ bool auto_partitioned; - const char *partition_info; - uint partition_info_len; + const char *partition_info_str; + uint partition_info_str_len; uint partition_info_buffer_size; - const char *part_state; - uint part_state_len; handlerton *default_part_db_type; #endif @@ -653,6 +664,14 @@ struct TABLE_SHARE void *ha_data; void (*ha_data_destroy)(void *); /* An optional destructor for ha_data */ +#ifdef WITH_PARTITION_STORAGE_ENGINE + /** place to store partition specific data, LOCK_ha_data hold while init. */ + HA_DATA_PARTITION *ha_part_data; + /* Destructor for ha_part_data */ + void (*ha_part_data_destroy)(HA_DATA_PARTITION *); +#endif + + /** Instrumentation for this table share. */ PSI_table_share *m_psi; diff --git a/sql/thr_malloc.cc b/sql/thr_malloc.cc index 638f3bbb9f1..7696f28081d 100644 --- a/sql/thr_malloc.cc +++ b/sql/thr_malloc.cc @@ -109,10 +109,6 @@ void* sql_memdup(const void *ptr, size_t len) return pos; } -void sql_element_free(void *ptr __attribute__((unused))) -{} /* purecov: deadcode */ - - char *sql_strmake_with_convert(const char *str, size_t arg_length, CHARSET_INFO *from_cs, diff --git a/sql/thr_malloc.h b/sql/thr_malloc.h index a655884b8b4..6b372a285a2 100644 --- a/sql/thr_malloc.h +++ b/sql/thr_malloc.h @@ -27,7 +27,6 @@ void *sql_calloc(size_t); char *sql_strdup(const char *str); char *sql_strmake(const char *str, size_t len); void *sql_memdup(const void * ptr, size_t size); -void sql_element_free(void *ptr); char *sql_strmake_with_convert(const char *str, size_t arg_length, CHARSET_INFO *from_cs, size_t max_res_length, diff --git a/sql/transaction.cc b/sql/transaction.cc index ff4eabc2b0f..5047de1ccdc 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -169,7 +169,7 @@ bool trans_commit_implicit(THD *thd) if (trans_check(thd)) DBUG_RETURN(TRUE); - if (thd->in_multi_stmt_transaction() || + if (thd->in_multi_stmt_transaction_mode() || (thd->variables.option_bits & OPTION_TABLE_LOCK)) { /* Safety if one did "drop table" on locked tables */ @@ -305,7 +305,7 @@ bool trans_savepoint(THD *thd, LEX_STRING name) SAVEPOINT **sv, *newsv; DBUG_ENTER("trans_savepoint"); - if (!(thd->in_multi_stmt_transaction() || thd->in_sub_stmt) || + if (!(thd->in_multi_stmt_transaction_mode() || thd->in_sub_stmt) || !opt_using_transactions) DBUG_RETURN(FALSE); @@ -467,7 +467,7 @@ bool trans_xa_start(THD *thd) my_error(ER_XAER_INVAL, MYF(0)); else if (xa_state != XA_NOTR) my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]); - else if (thd->locked_tables_mode || thd->active_transaction()) + else if (thd->locked_tables_mode || thd->in_active_multi_stmt_transaction()) my_error(ER_XAER_OUTSIDE, MYF(0)); else if (xid_cache_search(thd->lex->xid)) my_error(ER_XAER_DUPID, MYF(0)); diff --git a/storage/heap/make-ccc b/storage/heap/make-ccc deleted file mode 100755 index 192647298ad..00000000000 --- a/storage/heap/make-ccc +++ /dev/null @@ -1,4 +0,0 @@ -ccc -I./../include -I../include -DDBUG_OFF -fast -O3 -c _check.c _rectest.c hp_block.c hp_clear.c hp_close.c hp_create.c hp_delete.c hp_extra.c hp_hash.c hp_info.c hp_open.c hp_panic.c hp_rename.c hp_rfirst.c hp_rkey.c hp_rlast.c hp_rnext.c hp_rprev.c hp_rrnd.c hp_rsame.c hp_scan.c hp_static.c hp_update.c hp_write.c -rm libheap.a -ar -cr libheap.a _check.o - diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index e4f7da5e5f3..6aec52032f3 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -22,13 +22,21 @@ INCLUDE(CheckCSourceRuns) # OS tests IF(UNIX) IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") + CHECK_INCLUDE_FILES (libaio.h HAVE_LIBAIO_H) + CHECK_LIBRARY_EXISTS(aio io_queue_init "" HAVE_LIBAIO) ADD_DEFINITIONS("-DUNIV_LINUX -D_GNU_SOURCE=1") + IF(HAVE_LIBAIO_H AND HAVE_LIBAIO) + ADD_DEFINITIONS(-DLINUX_NATIVE_AIO=1) + LINK_LIBRARIES(aio) + ENDIF() ELSEIF(CMAKE_SYSTEM_NAME MATCHES "HP*") ADD_DEFINITIONS("-DUNIV_HPUX -DUNIV_MUST_NOT_INLINE") ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "AIX") ADD_DEFINITIONS("-DUNIV_AIX -DUNIX_MUST_NOT_INLINE") ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "SunOS") ADD_DEFINITIONS("-DUNIV_SOLARIS") + ELSE() + ADD_DEFINITIONS("-DUNIV_MUST_NOT_INLINE") ENDIF() ENDIF() @@ -174,7 +182,11 @@ IF(SIZEOF_PTHREAD_T) ENDIF() IF(MSVC) - ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DHAVE_IB_PAUSE_INSTRUCTION) + # Windows atomics do not perform well. Disable Windows atomics by default. + # See bug#52102 for details. + + #ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DINNODB_RW_LOCKS_USE_ATOMICS -DHAVE_IB_PAUSE_INSTRUCTION) + ADD_DEFINITIONS(-DHAVE_IB_PAUSE_INSTRUCTION) ENDIF() @@ -224,14 +236,14 @@ SET(INNOBASE_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c rem/rem0cmp.c rem/rem0rec.c row/row0ext.c row/row0ins.c row/row0merge.c row/row0mysql.c row/row0purge.c row/row0row.c row/row0sel.c row/row0uins.c row/row0umod.c row/row0undo.c row/row0upd.c row/row0vers.c - srv/srv0que.c srv/srv0srv.c srv/srv0start.c + srv/srv0srv.c srv/srv0start.c sync/sync0arr.c sync/sync0rw.c sync/sync0sync.c thr/thr0loc.c trx/trx0i_s.c trx/trx0purge.c trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c usr/usr0sess.c - ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c - ut/ut0list.c ut/ut0wqueue.c) + ut/ut0byte.c ut/ut0dbg.c ut/ut0list.c ut/ut0mem.c ut/ut0rbt.c ut/ut0rnd.c + ut/ut0ut.c ut/ut0vec.c ut/ut0wqueue.c) IF(WITH_INNODB) # Legacy option diff --git a/storage/innobase/ChangeLog b/storage/innobase/ChangeLog deleted file mode 100644 index 1a6e07fd147..00000000000 --- a/storage/innobase/ChangeLog +++ /dev/null @@ -1,1465 +0,0 @@ -2009-11-20 The InnoDB Team - - * handler/ha_innodb.cc: - Add a workaround to prevent a crash due to Bug#45961 DDL on - partitioned innodb tables leaves data dictionary in an inconsistent - state - -2009-11-19 The InnoDB Team - - * btr/btr0btr.c: - Fix Bug#48469 when innodb tablespace is configured too small, crash - and corruption! - -2009-11-19 The InnoDB Team - - * data/data0type.c: - Fix Bug#48526 Data type for float and double is incorrectly reported - in InnoDB table monitor - -2009-11-19 The InnoDB Team - - * CMakeLists.txt: - Fix Bug#48317 cannot build innodb as static library - -2009-11-18 The InnoDB Team - - * handler/handler0alter.cc: - Fix Bug#48782 On lock wait timeout, CREATE INDEX (creating primary key) - attempts DROP TABLE - -2009-11-17 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb.result, - mysql-test/innodb.test, mysql-test/innodb_bug44369.result, - mysql-test/innodb_bug44369.test, mysql-test/patches/innodb-index.diff, - row/row0mysql.c: - Report duplicate table names to the client connection, not to the - error log. - -2009-11-12 The InnoDB Team - - * handler/ha_innodb.cc, include/db0err.h, row/row0merge.c, - row/row0mysql.c: - Allow CREATE INDEX to be interrupted. - Also, when CHECK TABLE is interrupted, report ER_QUERY_INTERRUPTED. - -2009-11-11 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb_bug47167.result, - mysql-test/innodb_bug47167.test, mysql-test/innodb_file_format.result: - Fix Bug#47167 "set global innodb_file_format_check" cannot set value - by User-Defined Variable - -2009-11-11 The InnoDB Team - - * include/os0file.h, os/os0file.c: - Fix Bug#3139 Mysql crashes: 'windows error 995' after several selects - on a large DB - -2009-11-04 The InnoDB Team - - * handler/ha_innodb.cc: - Fix Bug#32430 'show innodb status' causes errors - Invalid (old?) table or database name in logs - -2009-11-02 The InnoDB Team - - * btr/btr0sea.c, buf/buf0buf.c, dict/dict0dict.c, fil/fil0fil.c, - ibuf/ibuf0ibuf.c, include/btr0sea.h, include/dict0dict.h, - include/fil0fil.h, include/ibuf0ibuf.h, include/lock0lock.h, - include/log0log.h, include/log0recv.h, include/mem0mem.h, - include/mem0pool.h, include/os0file.h, include/pars0pars.h, - include/srv0srv.h, include/thr0loc.h, include/trx0i_s.h, - include/trx0purge.h, include/trx0rseg.h, include/trx0sys.h, - include/trx0undo.h, include/usr0sess.h, lock/lock0lock.c, - log/log0log.c, log/log0recv.c, mem/mem0dbg.c, mem/mem0pool.c, - os/os0file.c, os/os0sync.c, os/os0thread.c, pars/lexyy.c, - pars/pars0lex.l, que/que0que.c, srv/srv0srv.c, srv/srv0start.c, - sync/sync0arr.c, sync/sync0sync.c, thr/thr0loc.c, trx/trx0i_s.c, - trx/trx0purge.c, trx/trx0rseg.c, trx/trx0sys.c, trx/trx0undo.c, - usr/usr0sess.c, ut/ut0mem.c: - Fix Bug #45992 innodb memory not freed after shutdown - Fix Bug #46656 InnoDB plugin: memory leaks (Valgrind) - -2009-10-29 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result, - mysql-test/innodb-autoinc.test: - Fix Bug#47125 auto_increment start value is ignored if an index is - created and engine=innodb - -2009-10-29 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb_bug47777.result, - mysql-test/innodb_bug47777.test: - Fix Bug#47777 innodb dies with spatial pk: Failing assertion: buf <= - original_buf + buf_len - -2009-10-29 The InnoDB Team - - * handler/ha_innodb.cc: - Fix Bug#38996 Race condition in ANALYZE TABLE - -2009-10-29 The InnoDB Team - - * handler/ha_innodb.cc: - Fix bug#42383: Can't create table 'test.bug39438' - -2009-10-29 The InnoDB Team - - * os/os0proc.c: - Fix Bug#48237 Error handling in os_mem_alloc_large appears to - be incorrect - -2009-10-29 The InnoDB Team - - * buf/buf0buf.c, buf/buf0lru.c, include/buf0buf.h, include/buf0buf.ic: - Fix corruption of the buf_pool->LRU_old list and improve debug - assertions. - -2009-10-28 The InnoDB Team - - * srv/srv0start.c: - Fix Bug#41490 After enlargement of InnoDB page size, the error message - become inaccurate - -2009-10-26 The InnoDB Team - - * row/row0ins.c: - When allocating a data tuple, zero out the system fields in order - to avoid Valgrind warnings about uninitialized fields in - dtuple_validate(). - -2009-10-22 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb-zip.result, - mysql-test/innodb-zip.test, mysql-test/innodb_bug44369.result, - mysql-test/innodb_bug44369.test: - Fix Bug#47233 Innodb calls push_warning(MYSQL_ERROR::WARN_LEVEL_ERROR) - -2009-10-19 The InnoDB Team - - * mysql-test/innodb_information_schema.test: - Fix Bug#47808 innodb_information_schema.test fails when run under - valgrind - -2009-10-15 The InnoDB Team - - * include/page0page.ic: - Fix Bug#47058 Failure to compile innodb_plugin on solaris 10u7 + spro - cc/CC 5.10 - -2009-10-13 The InnoDB Team - - * buf/buf0flu.c: - Call fsync() on datafiles after a batch of pages is written to disk - even when skip_innodb_doublewrite is set. - -2009-10-05 The InnoDB Team - - * buf/buf0buf.c: - Do not invalidate buffer pool while an LRU batch is active. Added code - to buf_pool_invalidate() to wait for the running batches to finish. - -2009-10-01 The InnoDB Team - - * handler/ha_innodb.cc: - Fix Bug#47763 typo in error message: Failed to open table %s after %lu - attemtps. - -2009-10-01 The InnoDB Team - - * fsp/fsp0fsp.c, row/row0merge.c: - Clean up after a crash during DROP INDEX. When InnoDB crashes - while dropping an index, ensure that the index will be completely - dropped during crash recovery. The MySQL .frm file may still - contain the dropped index, but there is little that we can do - about it. - -2009-09-28 The InnoDB Team - - * handler/ha_innodb.cc: - When a secondary index exists in the MySQL .frm file but not in - the InnoDB data dictionary, return an error instead of letting an - assertion fail in index_read. - -2009-09-28 The InnoDB Team - - * btr/btr0btr.c, buf/buf0buf.c, include/page0page.h, - include/page0zip.h, page/page0cur.c, page/page0page.c, - page/page0zip.c: - Do not write to PAGE_INDEX_ID when restoring an uncompressed page - after a compression failure. The field should only be written - when creating a B-tree page. This fix addresses a race condition - in a debug assertion. - -2009-09-28 The InnoDB Team - - * fil/fil0fil.c: - Try to prevent the reuse of tablespace identifiers after InnoDB - has crashed during table creation. Also, refuse to start if files - with duplicate tablespace identifiers are encountered. - -2009-09-25 The InnoDB Team - - * include/os0file.h, os/os0file.c: - Fix Bug#47055 unconditional exit(1) on ERROR_WORKING_SET_QUOTA - 1453 (0x5AD) for InnoDB backend - -2009-09-19 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb-consistent-master.opt, - mysql-test/innodb-consistent.result, - mysql-test/innodb-consistent.test: - Fix Bug#37232 Innodb might get too many read locks for DML with - repeatable-read - -2009-09-19 The InnoDB Team - - * fsp/fsp0fsp.c: - Fix Bug#31183 Tablespace full problems not reported in error log, - error message unclear - -2009-09-17 The InnoDB Team - - * mysql-test/innodb-zip.result, mysql-test/innodb-zip.test: - Make the test pass with zlib 1.2.3.3. Apparently, the definition - of compressBound() has changed between zlib versions, and the - maximum record size of a table with 1K compressed page size has - been reduced by one byte. This is an arbitrary test. In practical - applications, for good write performance, the compressed page size - should be chosen to be bigger than the absolute minimum. - -2009-09-16 The InnoDB Team - - * handler/ha_innodb.cc: - Fix Bug#46256 drop table with unknown collation crashes innodb - -2009-09-16 The InnoDB Team - - * dict/dict0dict.c, handler/ha_innodb.cc, - mysql-test/innodb_bug44369.result, mysql-test/innodb_bug44369.test, - row/row0mysql.c: - Fix Bug#44369 InnoDB: Does not uniformly disallow disallowed column - names - -2009-09-16 The InnoDB Team - - * handler/ha_innodb.cc, include/db0err.h, - mysql-test/innodb_bug46000.result, mysql-test/innodb_bug46000.test: - Fix Bug#46000 using index called GEN_CLUST_INDEX crashes server - -2009-09-02 The InnoDB Team - - * include/lock0lock.h, include/row0mysql.h, lock/lock0lock.c, - row/row0mysql.c: - Fix a regression introduced by the fix for MySQL bug#26316. We check - whether a transaction holds any AUTOINC locks before we acquire - the kernel mutex and release those locks. - -2009-08-27 The InnoDB Team - - * dict/dict0dict.c, include/dict0dict.h, - mysql-test/innodb_bug44571.result, mysql-test/innodb_bug44571.test: - Fix Bug#44571 InnoDB Plugin crashes on ADD INDEX - -2009-08-27 The InnoDB Team - - * row/row0merge.c: - Fix a bug in the merge sort that can corrupt indexes in fast index - creation. Add some consistency checks. Check that the number of - records remains constant in every merge sort pass. - -2009-08-27 The InnoDB Team - - * buf/buf0buf.c, buf/buf0lru.c, buf/buf0rea.c, handler/ha_innodb.cc, - include/buf0buf.h, include/buf0buf.ic, include/buf0lru.h, - include/ut0ut.h, ut/ut0ut.c: - Make it possible to tune the buffer pool LRU eviction policy to be - more resistant against index scans. Introduce the settable global - variables innodb_old_blocks_pct and innodb_old_blocks_time for - controlling the buffer pool eviction policy. The parameter - innodb_old_blocks_pct (5..95) controls the desired amount of "old" - blocks in the LRU list. The default is 37, corresponding to the - old fixed ratio of 3/8. Each time a block is accessed, it will be - moved to the "new" blocks if its first access was at least - innodb_old_blocks_time milliseconds ago (default 0, meaning every - block). The idea is that in index scans, blocks will be accessed - a few times within innodb_old_blocks_time, and they will remain in - the "old" section of the LRU list. Thus, when innodb_old_blocks_time - is nonzero, blocks retrieved for one-time index scans will be more - likely candidates for eviction than blocks that are accessed in - random patterns. - -2009-08-26 The InnoDB Team - - * handler/ha_innodb.cc, os/os0file.c: - Fix Bug#42885 buf_read_ahead_random, buf_read_ahead_linear counters, - thread wakeups - -2009-08-20 The InnoDB Team - - * lock/lock0lock.c: - Fix Bug#46650 Innodb assertion autoinc_lock == lock in - lock_table_remove_low on INSERT SELECT - -2009-08-13 The InnoDB Team - - * handler/handler0alter.cc: - Fix Bug#46657 InnoDB plugin: invalid read in index_merge_innodb test - (Valgrind) - -2009-08-11 The InnoDB Team - - InnoDB Plugin 1.0.4 released - -2009-07-20 The InnoDB Team - - * buf/buf0rea.c, handler/ha_innodb.cc, include/srv0srv.h, - srv/srv0srv.c: - Change the read ahead parameter name to innodb_read_ahead_threshold. - Change the meaning of this parameter to signify the number of pages - that must be sequentially accessed for InnoDB to trigger a readahead - request. - -2009-07-20 The InnoDB Team - - * handler/ha_innodb.cc: - Fix Bug#39802 On Windows, 32-bit time_t should be enforced - -2009-07-16 The InnoDB Team - - * include/univ.i: - Support inlining of functions and prefetch with Sun Studio. - These changes are based on contribution from Sun Microsystems Inc. - under a BSD license. - -2009-07-14 The InnoDB Team - - * fil/fil0fil.c: - Fix Bug#45814 URL reference in InnoDB server errors needs adjusting to - match documentation - -2009-07-14 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb_bug21704.result, - mysql-test/innodb_bug21704.test: - Fix Bug#21704 Renaming column does not update FK definition - -2009-07-10 The InnoDB Team - - * handler/ha_innodb.cc, srv/srv0srv.c: - Change the defaults for - innodb_sync_spin_loops: 20 -> 30 - innodb_spin_wait_delay: 5 -> 6 - -2009-07-08 The InnoDB Team - - * buf/buf0flu.c, handler/ha_innodb.cc, include/buf0flu.h, - include/log0log.h, include/log0log.ic, include/srv0srv.h, - srv/srv0srv.c: - Implement the adaptive flushing of dirty pages, which uses - a heuristics based flushing rate of dirty pages to avoid IO - bursts at checkpoint. Expose new configure knob - innodb_adaptive_flushing to control whether the new flushing - algorithm should be used. - -2009-07-07 The InnoDB Team - - * handler/ha_innodb.cc, include/srv0srv.h, log/log0log.c, - srv/srv0srv.c: - Implement IO capacity tuning. Expose new configure knob - innodb_io_capacity to control the master threads IO rate. The - ibuf merge is also changed from synchronous to asynchronous. - These changes are based on contribution from Google Inc. - under a BSD license. - -2009-07-02 The InnoDB Team - - * include/ut0ut.h, plug.in, ut/ut0ut.c: - Use the PAUSE instruction inside the spinloop if it is available, - Thanks to Mikael Ronstrom <mikael@mysql.com>. - -2009-06-29 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb_file_format.test, - mysql-test/innodb_file_format.result: - Do not crash on SET GLOBAL innodb_file_format=DEFAULT - or SET GLOBAL innodb_file_format_check=DEFAULT. - -2009-06-29 The InnoDB Team - - * buf/buf0buf.c, buf/buf0rea.c, lock/lock0lock.c: - Tolerate missing tablespaces during crash recovery and when - printing information on locks. - -2009-06-29 The InnoDB Team - - * buf/buf0buf.c: - Fix a race condition when reading buf_fix_count. - Currently, it is not being protected by the buffer pool mutex, - but by the block mutex. - -2009-06-29 The InnoDB Team - - * handler/handler0alter.cc: - Start the user transaction prebuilt->trx if it was not started - before adding or dropping an index. Without this fix, the - table could be locked outside an active transaction. - -2009-06-25 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb_bug42101.test, - mysql-test/innodb_bug42101.result, - mysql-test/innodb_bug42101-nonzero.test, - mysql-test/innodb_bug42101-nonzero.result: - Fix Bug#45749 Race condition in SET GLOBAL - innodb_commit_concurrency=DEFAULT - -2009-06-25 The InnoDB Team - - * dict/dict0dict.c: - When an index column cannot be found in the table during index - creation, display additional diagnostic before an assertion failure. - This does NOT fix Bug #44571 InnoDB Plugin crashes on ADD INDEX, - but it helps understand the reason of the crash. - -2009-06-17 The InnoDB Team - - * row/row0merge.c: - Fix Bug#45426 UNIV_DEBUG build cause assertion error at CREATE INDEX - -2009-06-17 The InnoDB Team - - * mysql-test/innodb_bug45357.result, mysql-test/innodb_bug45357.test, - row/row0mysql.c: - Fix Bug#45357 5.1.35 crashes with Failing assertion: index->type & - DICT_CLUSTERED - -2009-06-17 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result, - mysql-test/innodb-autoinc.test: - Fix Bug#44030 Error: (1500) Couldn't read the MAX(ID) autoinc value - from the index (PRIMARY) - -2009-06-11 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb.result, srv/srv0srv.c: - Change the following defaults: - max_dirty_pages_pct: from 90 to 75, max allowed from 100 to 99 - additional_mem_pool_size: from 1 to 8 MB - buffer_pool_size: from 8 to 128 MB - log_buffer_size: from 1 to 8 MB - read_io_threads/write_io_threads: from 1 to 4 - -2009-06-09 The InnoDB Team - - * handler/ha_innodb.cc, include/trx0trx.h, trx/trx0trx.c: - Enable Group Commit functionality that was broken in 5.0 when - distributed transactions were introduced. - -2009-06-05 The InnoDB Team - - * handler/ha_innodb.cc, include/os0file.h, include/srv0srv.h, - os/os0file.c, srv/srv0srv.c, srv/srv0start.c: - Enable functionality to have multiple background IO helper threads. - Expose new configure knobs innodb_read_io_threads and - innodb_write_io_threads and deprecate innodb_file_io_threads (this - parameter was relevant only on windows). Internally this allows - multiple segments for read and write IO request arrays where one - thread works on one segment. - -2009-06-05 The InnoDB Team - - * buf/buf0lru.c, buf/buf0rea.c, handler/ha_innodb.cc, - include/srv0srv.h, srv/srv0srv.c: - Fix a bug in linear read ahead: - 1) Take into account access pattern when deciding whether or not to - do linear read ahead. - 2) Expose a knob innodb_read_ahead_factor = [0-64] default (8), - dynamic, global to control linear read ahead behavior. This is the - value of the number of pages that InnoDB will tolerate within a - 64 page extent even if they are accessed out of order or have - not been accessed at all. This number (which varies from 0 to 64) - is indicative of the slack that we have when deciding about linear - readahead. - 3) Disable random read ahead. Keep the code for now. - -2009-06-03 The InnoDB Team - - * dict/dict0dict.c, mysql-test/t/innodb_mysql.test, - mysql-test/r/innodb_mysql.result: - Fix Bug#39793 Foreign keys not constructed when column - has a '#' in a comment or default value - -2009-05-27 The InnoDB Team - - * Doxyfile: - Allow the extraction of documentation from the code base with the - Doxygen tool. Convert and add many (but not yet all) comments to - Doxygen format. - -2009-05-19 The InnoDB Team - - * btr/btr0btr.c, btr/btr0cur.c, lock/lock0lock.c, - include/page0page.ic, include/lock0lock.h, include/dict0dict.h, - include/page0page.h, include/dict0dict.ic, ibuf/ibuf0ibuf.c, - page/page0zip.c, page/page0page.c: - Write updates of PAGE_MAX_TRX_ID to the redo log and add debug - assertions for checking that PAGE_MAX_TRX_ID is valid on leaf - pages of secondary indexes and the insert buffer B-tree. This bug - could cause failures in secondary index lookups in consistent - reads right after crash recovery. - -2009-05-18 The InnoDB Team - - * btr/btr0cur.c: - Correctly estimate the space needed on the compressed page when - performing an update by delete-and-insert. - -2009-05-14 The InnoDB Team - - * handler/ha_innodb.cc, include/srv0srv.h, - mysql-test/innodb_bug42101-nonzero-master.opt, - mysql-test/innodb_bug42101-nonzero.result, - mysql-test/innodb_bug42101-nonzero.test, - mysql-test/innodb_bug42101.result, mysql-test/innodb_bug42101.test, - srv/srv0srv.c: - Fix Bug#42101 Race condition in innodb_commit_concurrency - -2009-05-13 The InnoDB Team - - * dict/dict0dict.c: - Fix Bug#44320 InnoDB: missing DB_ROLL_PTR in Table Monitor COLUMNS - output - -2009-04-23 The InnoDB Team - - * row/row0mysql.c: - When scanning indexes, report in the error log any error codes - returned by the search function. These error codes will still be - ignored in CHECK TABLE. - -2009-04-23 The InnoDB Team - - * include/trx0types.h: - Define the logical type names trx_id_t, roll_ptr_t, and undo_no_t - and use them in place of dulint everywhere. - -2009-04-18 The InnoDB Team - - * handler/ha_innodb.cc, include/pars0pars.h: - Fix Bug#29125 Windows Server X64: so many compiler warnings - -2009-04-16 The InnoDB Team - - * include/univ.i: - Define REFMAN as the base URL of the MySQL Reference Manual and - use the macro in all diagnostic output. - -2009-04-16 The InnoDB Team - - * CMakeLists.txt, include/os0sync.h, include/sync0sync.h, - include/sync0sync.ic, include/univ.i, srv/srv0start.c, - sync/sync0sync.c: - Use the Windows Interlocked functions for atomic memory - access. - -2009-04-15 The InnoDB Team - - * mysql-test/innodb.result, mysql-test/innodb.test: - Fix Bug#43309 Test main.innodb can't be run twice - -2009-04-14 The InnoDB Team - - * CMakeLists.txt, handler/win_delay_loader.cc, - win-plugin/win-plugin.diff: - Remove statically linked libraries from MySQL (zlib and strings). - -2009-04-11 The InnoDB Team - - * CMakeLists.txt, win-plugin/README, win-plugin/win-plugin.diff: - Rewrite CMakeLists.txt. - -2009-04-07 The InnoDB Team - - * include/os0sync.h, include/sync0rw.ic, include/sync0sync.h, - include/sync0sync.ic, include/univ.i, plug.in, srv/srv0srv.c, - srv/srv0start.c, sync/sync0arr.c, sync/sync0sync.c: - Enable atomics on Solaris (using the libc functions as defined in - atomic.h) if GCC atomic builtins are not present. - -2009-04-07 The InnoDB Team - - * btr/btr0btr.c, dict/dict0dict.c, ibuf/ibuf0ibuf.c, - include/data0data.h, include/data0data.ic, include/data0type.h, - include/data0type.ic, include/dict0dict.h, include/dict0dict.ic, - include/rem0rec.ic, mysql-test/innodb.result, mysql-test/innodb.test, - pars/pars0pars.c, rem/rem0rec.c, row/row0upd.c: - Fix Bug#44032 In ROW_FORMAT=REDUNDANT, update UTF-8 CHAR - to/from NULL is not in-place - -2009-04-07 The InnoDB Team - - * page/page0cur.c: - Fix Bug#43660 SHOW INDEXES/ANALYZE does NOT update cardinality for - indexes of InnoDB table - -2009-04-06 The InnoDB Team - - * handler/ha_innodb.cc: - Make the parameter innodb_change_buffering settable by the - configuration file or mysqld command line options. Before this - fix, the initial value specified for this parameter was ignored. - -2009-04-06 The InnoDB Team - - * sync/sync0rw.c: - Avoid a bogus failure in UNIV_SYNC_DEBUG diagnostics. - -2009-04-02 The InnoDB Team - - * handler/ha_innodb.cc, include/srv0srv.h, srv/srv0srv.c: - Add new parameter innodb_spin_wait_delay to set the maximum delay - between polling for a spin lock. - -2009-04-02 The InnoDB Team - - * dict/dict0crea.c, handler/ha_innodb.cc, handler/ha_innodb.h, - include/dict0mem.h, include/row0merge.h, include/row0mysql.h, - mysql-test/innodb-index.result, mysql-test/innodb-index.test, - row/row0merge.c, row/row0sel.c: - In consistent reads, refuse to use newly created indexes that may - lack history. - -2009-03-25 The InnoDB Team - - * buf/buf0buf.c, handler/ha_innodb.cc, include/buf0buf.h: - In SHOW ENGINE INNODB MUTEX do not show the status of block->mutex, - block->lock, block->lock->mutex (if applicable) and all mutexes and - rw-locks for which number of os-waits are zero because this can - be overwhelming particularly when the buffer pool is very large. - -2009-03-20 The InnoDB Team - - * buf/buf0buf.c, include/log0recv.h, log/log0recv.c: - Remove the compile-time constant parameters of - recv_recover_page(), recv_scan_log_recs(), and recv_sys_init(). - -2009-03-20 The InnoDB Team - - * data/data0type.c, handler/ha_innodb.cc, include/ha_prototypes.h: - Declare innobase_get_at_most_n_mbchars() in ha_prototypes.h. - -2009-03-20 The InnoDB Team - - * fil/fil0fil.h, fil/fil0fil.c, srv/srv0start.c: - Add the parameter hash_size to fil_init(). - -2009-03-20 The InnoDB Team - - * fil/fil0fil.c: - Refer to fil_system directly, not via local variables. - -2009-03-20 The InnoDB Team - - * page/page0page.c: - In page_validate(), always report the space id, page number and - the name of the index when corruption is noticed. - -2009-03-20 The InnoDB Team - - * include/log0log.h, include/log0log.ic, log/log0log.c: - Add in/out comments or const qualifiers to some function - parameters as appropriate. - -2009-03-20 The InnoDB Team - - * dict/dict0boot.c, dict/dict0dict.c, fsp/fsp0fsp.c, - include/dict0dict.h, include/srv0srv.h, srv/srv0srv.c, - page/page0page.c: - Replace srv_sys->dummy_ind1 and srv_sys->dummy_ind2 with - dict_ind_redundant and dict_ind_compact, which are - initialized by dict_init(). - -2009-03-11 The InnoDB Team - - InnoDB Plugin 1.0.3 released - -2009-03-05 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result, - mysql-test/innodb-autoinc.test: - Fix Bug#43203 Overflow from auto incrementing causes server segv - -2009-02-25 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result, - mysql-test/innodb-autoinc.test: - Fix Bug#42714 AUTO_INCREMENT errors in 5.1.31 - -2009-02-23 The InnoDB Team - - * btr/btr0cur.c: - Fix Bug#43043 Crash on BLOB delete operation - -2009-02-20 The InnoDB Team - - * handler/ha_innodb.cc: - Make innodb_use_sys_malloc=ON the default. - -2009-02-20 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result, - mysql-test/innodb-autoinc.test: - Fix Bug#42400 InnoDB autoinc code can't handle floating-point columns - -2009-02-18 The InnoDB Team - - * include/ut0mem.h, os/os0proc.c, ut/ut0mem.c: - Protect ut_total_allocated_memory with ut_list_mutex in - os_mem_alloc_large() and os_mem_free_large(). The lack of this mutex - protection could cause an assertion failure during fast index - creation. Also, add UNIV_MEM_ALLOC and UNIV_MEM_FREE instrumentation - to os_mem_alloc_large() and os_mem_free_large(), so that Valgrind can - detect more errors. - -2009-02-11 The InnoDB Team - - * handler/ha_innodb.cc: - Make innodb_thread_concurrency=0 the default. The old default value - was 8. A non-zero setting may be useful when InnoDB is showing severe - scalability problems under multiple concurrent connections. - -2009-02-10 The InnoDB Team - - * handler/ha_innodb.cc, handler/ha_innodb.h: - Fix Bug#41676 Table names are case insensitive in locking - -2009-02-10 The InnoDB Team - - * mem/mem0dbg.c, mem/mem0mem.c, mem/mem0pool.c: - When innodb_use_sys_malloc is set, ignore - innodb_additional_mem_pool_size, because nothing will be allocated - from mem_comm_pool. - -2009-02-10 The InnoDB Team - - * ut/ut0mem.c: - Map ut_malloc_low(), ut_realloc(), and ut_free() directly to malloc(), - realloc(), and free() when innodb_use_sys_malloc is set. As a side - effect, ut_total_allocated_memory ("Total memory allocated" in the - "BUFFER POOL AND MEMORY" section of SHOW ENGINE INNODB STATUS) will - exclude any memory allocated by these functions when - innodb_use_sys_malloc is set. - -2009-02-10 The InnoDB Team - - * btr/btr0cur.c, btr/btr0sea.c, buf/buf0buf.c, handler/ha_innodb.cc, - include/buf0buf.ic, include/os0sync.h, include/srv0srv.h, - include/sync0rw.h, include/sync0rw.ic, include/sync0sync.h, - include/sync0sync.ic, include/univ.i, row/row0sel.c, srv/srv0srv.c, - srv/srv0start.c, sync/sync0arr.c, sync/sync0rw.c, sync/sync0sync.c: - On those platforms that support it, implement the synchronization - primitives of InnoDB mutexes and read/write locks with GCC atomic - builtins instead of Pthreads mutexes and InnoDB mutexes. These changes - are based on a patch supplied by Mark Callaghan of Google under a BSD - license. - -2009-01-30 The InnoDB Team - - * btr/btr0cur.c, btr/btr0sea.c, buf/buf0buf.c, handler/ha_innodb.cc, - include/btr0sea.h, include/buf0buf.h, include/sync0sync.h, - sync/sync0sync.c: - Make the configuration parameter innodb_adaptive_hash_index dynamic, - so that it can be changed at runtime. - -2009-01-29 The InnoDB Team - - * handler/ha_innodb.cc, ibuf/ibuf0ibuf.c, include/ibuf0ibuf.h, - include/ibuf0ibuf.ic: - Implement the settable global variable innodb_change_buffering, - with the allowed values 'none' and 'inserts'. The default value - 'inserts' enables the buffering of inserts to non-unique secondary - index trees when the B-tree leaf page is not in the buffer pool. - -2009-01-27 The InnoDB Team - - * buf/buf0lru.c: - Fix a race condition in buf_LRU_invalidate_tablespace(): The - compressed page size (zip_size) was read while the block descriptor - was no longer protected by a mutex. This could lead to corruption - when a table is dropped on a busy system that contains compressed - tables. - -2009-01-26 The InnoDB Team - - * btr/btr0sea.c, buf/buf0buf.c, include/buf0buf.h, include/buf0buf.ic, - include/mtr0log.ic, include/row0upd.ic, mtr/mtr0mtr.c: - Implement buf_block_align() with pointer arithmetics, as it is in the - built-in InnoDB distributed with MySQL. Do not acquire the buffer pool - mutex before buf_block_align(). This removes a scalability bottleneck - in the adaptive hash index lookup. In CHECK TABLE, check that - buf_pool->page_hash is consistent with buf_block_align(). - -2009-01-23 The InnoDB Team - - * btr/btr0sea.c: - Fix Bug#42279 Race condition in btr_search_drop_page_hash_when_freed() - -2009-01-23 The InnoDB Team - - * buf/buf0buf.c, include/buf0buf.h: - Remove the unused mode BUF_GET_NOWAIT of buf_page_get_gen() - -2009-01-20 The InnoDB Team - - * include/rem0rec.h, include/rem0rec.ic: - Fix Bug#41571 MySQL segfaults after innodb recovery - -2009-01-20 The InnoDB Team - - * lock/lock0lock.c: - Fix Bug#42152 Race condition in lock_is_table_exclusive() - -2009-01-14 The InnoDB Team - - * include/trx0roll.h, trx/trx0roll.c, trx/trx0trx.c: - Fix Bug#38187 Error 153 when creating savepoints - -2009-01-14 The InnoDB Team - - * dict/dict0load.c: - Fix Bug#42075 dict_load_indexes failure in dict_load_table will - corrupt the dictionary cache - -2009-01-13 The InnoDB Team - - * buf/buf0buddy.c, dict/dict0dict.c, dict/dict0mem.c, fil/fil0fil.c, - ha/ha0storage.c, handler/ha_innodb.cc, handler/win_delay_loader.cc, - include/buf0buf.ic, include/dict0dict.ic, include/hash0hash.h, - thr/thr0loc.c, trx/trx0i_s.c: - Add the parameter ASSERTION to HASH_SEARCH() macro, and use it for - light validation of the traversed items in hash table lookups when - UNIV_DEBUG is enabled. - -2009-01-09 The InnoDB Team - - * buf/buf0flu.c, include/buf0flu.h, include/buf0flu.ic: - Remove unused code from the functions - buf_flush_insert_into_flush_list() and - buf_flush_insert_sorted_into_flush_list(). - -2009-01-09 The InnoDB Team - - * buf/buf0flu.c: - Simplify the functions buf_flush_try_page() and buf_flush_batch(). Add - debug assertions and an explanation to buf_flush_write_block_low(). - -2009-01-07 The InnoDB Team - - * row/row0merge.c: - Fix a bug in recovery when dropping temporary indexes. - -2009-01-07 The InnoDB Team - - * handler/ha_innodb.cc, handler/ha_innodb.h, handler/handler0alter.cc: - Fix Bug#41680 calls to trx_allocate_for_mysql are not consistent - -2009-01-07 The InnoDB Team - - * mysql-test/innodb_bug41904.result, mysql-test/innodb_bug41904.test, - row/row0merge.c: - Fix Bug#41904 create unique index problem - -2009-01-02 The InnoDB Team - - * handler/ha_innodb.cc, include/srv0srv.h, mem/mem0pool.c, - mysql-test/innodb-use-sys-malloc-master.opt, - mysql-test/innodb-use-sys-malloc.result, - mysql-test/innodb-use-sys-malloc.test, srv/srv0srv.c, srv/srv0start.c: - Implement the configuration parameter innodb_use_sys_malloc (false by - default), for disabling InnoDB's internal memory allocator and using - system malloc/free instead. The "BUFFER POOL AND MEMORY" section of - SHOW ENGINE INNODB STATUS will report "in additional pool allocated - allocated 0" when innodb_use_sys_malloc is set. - -2008-12-30 The InnoDB Team - - * btr/btr0btr.c: - When setting the PAGE_LEVEL of a compressed B-tree page from or to 0, - compress the page at the same time. This is necessary, because the - column information stored on the compressed page will differ between - leaf and non-leaf pages. Leaf pages are identified by PAGE_LEVEL=0. - This bug can make InnoDB crash when all rows of a compressed table are - deleted. - -2008-12-17 The InnoDB Team - - * include/row0sel.h, include/row0upd.h, pars/pars0pars.c, - row/row0mysql.c, row/row0sel.c, row/row0upd.c: - Remove update-in-place select from the internal SQL interpreter. It - was only used for updating the InnoDB internal data dictionary when - renaming or dropping tables. It could have caused deadlocks when - acquiring latches on insert buffer bitmap pages. - -2008-12-17 The InnoDB Team - - * btr/btr0sea.c, buf/buf0buf.c, buf/buf0lru.c, ha/ha0ha.c, - ha/hash0hash.c, include/buf0buf.h, include/ha0ha.h, include/ha0ha.ic, - include/hash0hash.h, include/univ.i: - Introduce the preprocessor symbol UNIV_AHI_DEBUG for enabling adaptive - hash index debugging independently of UNIV_DEBUG. - -2008-12-16 The InnoDB Team - - * btr/btr0cur.c: - Do not update the free bits in the insert buffer bitmap when inserting - or deleting from the insert buffer B-tree. Assert that records in the - insert buffer B-tree are never updated. - -2008-12-12 The InnoDB Team - - * buf/buf0buf.c, fil/fil0fil.c, fsp/fsp0fsp.c, ibuf/ibuf0ibuf.c, - include/fil0fil.h, include/ibuf0ibuf.h, include/ibuf0ibuf.ic, - include/ibuf0types.h: - Clean up the insert buffer subsystem so that only one insert - buffer B-tree exists. - Originally, there were provisions in InnoDB for multiple insert - buffer B-trees, apparently one for each tablespace. - When Heikki Tuuri implemented multiple InnoDB tablespaces in - MySQL/InnoDB 4.1, he made the insert buffer live only in the - system tablespace (space 0) but left the provisions in the code. - -2008-12-11 The InnoDB Team - - * include/srv0srv.h, os/os0proc.c, srv/srv0srv.c: - Fix the issue that the InnoDB plugin fails if innodb_buffer_pool_size - is defined bigger than 4096M on 64-bit Windows. This bug should not - have affected other 64-bit systems. - -2008-12-09 The InnoDB Team - - * handler/ha_innodb.cc: - Fix Bug#40386 Not flushing query cache after truncate. - -2008-12-09 The InnoDB Team - - * handler/ha_innodb.cc, srv/srv0srv.c, trx/trx0trx.c: - Fix Bug#40760 "set global innodb_thread_concurrency = 0;" is not safe - -2008-12-04 The InnoDB Team - - * handler/ha_innodb.cc, handler/mysql_addons.cc, - include/mysql_addons.h, trx/trx0i_s.c, win-plugin/win-plugin.diff: - Remove dependencies to MySQL internals (defining MYSQL_SERVER). - -2008-12-02 The InnoDB Team - - * page/page0cur.c: - When allocating space for a record from the free list of previously - purged records, zero out the DB_TRX_ID and DB_ROLL_PTR of the purged - record if the new record would not overwrite these fields. This fixes - a harmless content mismatch reported by page_zip_validate(). - -2008-12-02 The InnoDB Team - - * row/row0merge.c: - Replace the WHILE 1 with WHILE 1=1 in the SQL procedure, so that the - loop will actually be entered and temporary indexes be dropped during - crash recovery. - -2008-12-01 The InnoDB Team - - InnoDB Plugin 1.0.2 released - -2008-10-31 The InnoDB Team - - * dict/dict0mem.c, include/dict0mem.h, include/lock0lock.h, - include/row0mysql.h, include/trx0trx.h, include/univ.i, - include/ut0vec.h, include/ut0vec.ic, lock/lock0lock.c, - row/row0mysql.c, trx/trx0trx.c: - Fix Bug#26316 Triggers create duplicate entries on auto-increment - columns - -2008-10-30 The InnoDB Team - - * handler/ha_innodb.cc, handler/handler0vars.h, - handler/win_delay_loader.cc, mysql-test/innodb_bug40360.result, - mysql-test/innodb_bug40360.test: - Fix Bug#40360 Binlog related errors with binlog off - -2008-10-29 The InnoDB Team - - * include/data0type.ic: - Fix Bug#40369 dtype_get_sql_null_size() returns 0 or 1, not the size - -2008-10-29 The InnoDB Team - - * handler/ha_innodb.cc, include/srv0srv.h, srv/srv0srv.c: - Fix Bug#38189 innodb_stats_on_metadata missing - -2008-10-28 The InnoDB Team - - * CMakeLists.txt, ha_innodb.def, handler/ha_innodb.cc, - handler/handler0alter.cc, handler/handler0vars.h, handler/i_s.cc, - handler/win_delay_loader.cc, win-plugin/*: - Implemented the delayloading of externals for the plugin on Windows. - This makes it possible to build a dynamic plugin (ha_innodb.dll) on - Windows. - -2008-10-27 The InnoDB Team - - * CMakeLists.txt: - Fix Bug#19424 InnoDB: Possibly a memory overrun of the buffer being - freed (64-bit Visual C) - -2008-10-23 The InnoDB Team - - * ibuf/ibuf0ibuf.c: - ibuf_delete_rec(): When the cursor to the insert buffer record - cannot be restored, do not complain if the tablespace does not - exist, because the insert buffer record may have been discarded by - some other thread. This bug has existed in MySQL/InnoDB since - version 4.1, when innodb_file_per_table was implemented. - This may fix Bug#27276 InnoDB Error: ibuf cursor restoration fails. - -2008-10-22 The InnoDB Team - - * dict/dict0dict.c, dict/dict0mem.c, handler/ha_innodb.cc, - handler/ha_innodb.h, include/dict0dict.h, include/dict0mem.h, - row/row0mysql.c: - Fix Bug#39830 Table autoinc value not updated on first insert - Fix Bug#35498 Cannot get table test/table1 auto-inccounter value in - ::info - Fix Bug#36411 "Failed to read auto-increment value from storage - engine" in 5.1.24 auto-inc - -2008-10-22 The InnoDB Team - - * handler/ha_innodb.cc, include/row0mysql.h, row/row0mysql.c: - Fix Bug#40224 New AUTOINC changes mask reporting of deadlock/timeout - errors - -2008-10-16 The InnoDB Team - - * dict/dict0dict.c, mysql-test/innodb-index.result, - mysql-test/innodb-index.test: - Skip the undo log size check when creating REDUNDANT and COMPACT - tables. In ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED, column - prefix indexes require that prefixes of externally stored columns - be written to the undo log. This may make the undo log record - bigger than the record on the B-tree page. The maximum size of an - undo log record is the page size. That must be checked for, in - dict_index_add_to_cache(). However, this restriction must not - be enforced on REDUNDANT or COMPACT tables. - -2008-10-15 The InnoDB Team - - * btr/btr0cur.c, include/btr0cur.h, row/row0ext.c, row/row0sel.c, - row/row0upd.c: - When the server crashes while freeing an externally stored column - of a compressed table, the BTR_EXTERN_LEN field in the BLOB - pointer will be written as 0. Tolerate this in the functions that - deal with externally stored columns. This fixes problems after - crash recovery, in the rollback of incomplete transactions, and in - the purge of delete-marked records. - -2008-10-15 The InnoDB Team - - * btr/btr0btr.c, include/page0zip.h, page/page0zip.c, include/univ.i: - When a B-tree node of a compressed table is split or merged, the - compression may fail. In this case, the entire compressed page - will be copied and the excess records will be deleted. However, - page_zip_copy(), now renamed to page_zip_copy_recs(), copied too - many fields in the page header, overwriting PAGE_BTR_SEG_LEAF and - PAGE_BTR_SEG_TOP when splitting the B-tree root. This caused - corruption of compressed tables. Furthermore, the lock table and - the adaptive hash index would be corrupted, because we forgot to - update them when invoking page_zip_copy_recs(). - - Introduce the symbol UNIV_ZIP_DEBUG for triggering the copying of - compressed pages more often, for debugging purposes. - -2008-10-10 The InnoDB Team - - * handler/handler0alter.cc, include/row0merge.h, row/row0merge.c, - row/row0mysql.c: - Fix some locking issues, mainly in fast index creation. The - InnoDB data dictionary cache should be latched whenever a - transaction is holding locks on any data dictionary tables. - Otherwise, lock waits or deadlocks could occur. Furthermore, the - data dictionary transaction must be committed (and the locks - released) before the data dictionary latch is released. - - ha_innobase::add_index(): Lock the data dictionary before renaming - or dropping the created indexes, because neither operation will - commit the data dictionary transaction. - - ha_innobase::final_drop_index(): Commit the transactions before - unlocking the data dictionary. - -2008-10-09 The InnoDB Team - - * buf/buf0lru.c: - Fix Bug#39939 DROP TABLE/DISCARD TABLESPACE takes long time in - buf_LRU_invalidate_tablespace() - -2008-10-08 The InnoDB Team - - * dict/dict0crea.c, trx/trx0roll.c, include/row0mysql.h, - row/row0merge.c, row/row0mysql.c: - When dropping a table, hold the data dictionary latch until the - transaction has been committed. The data dictionary latch is - supposed to prevent lock waits and deadlocks in the data - dictionary tables. Due to this bug, DROP TABLE could cause a - deadlock or hang. Note that because of Bug#33650 and Bug#39833, - MySQL may also drop a (temporary) table when executing CREATE INDEX - or ALTER TABLE ... ADD INDEX. - -2008-10-04 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb_bug39438-master.opt, - mysql-test/innodb_bug39438.result, mysql-test/innodb_bug39438.test: - Fix Bug#39438 Testcase for Bug#39436 crashes on 5.1 in - fil_space_get_latch - -2008-10-04 The InnoDB Team - - * include/lock0lock.h, lock/lock0lock.c, - mysql-test/innodb_bug38231.result, mysql-test/innodb_bug38231.test, - row/row0mysql.c: - Fix Bug#38231 Innodb crash in lock_reset_all_on_table() on TRUNCATE + - LOCK / UNLOCK - -2008-10-04 The InnoDB Team - - * handler/ha_innodb.cc: - Fix Bug#35498 Cannot get table test/table1 auto-inccounter value in - ::info - -2008-10-04 The InnoDB Team - - * handler/ha_innodb.cc, handler/ha_innodb.h: - Fix Bug#37788 InnoDB Plugin: AUTO_INCREMENT wrong for compressed - tables - -2008-10-04 The InnoDB Team - - * dict/dict0dict.c, handler/ha_innodb.cc, handler/ha_innodb.h, - include/dict0dict.h, include/dict0mem.h, row/row0mysql.c: - Fix Bug#39830 Table autoinc value not updated on first insert - -2008-10-03 The InnoDB Team - - * mysql-test/innodb-index.test, mysql-test/innodb-index.result, - mysql-test/innodb-timeout.test, mysql-test/innodb-timeout.result, - srv/srv0srv.c, include/srv0srv.h, handler/ha_innodb.cc, - include/ha_prototypes.h: - Fix Bug#36285 innodb_lock_wait_timeout is not dynamic, not per session - -2008-09-19 The InnoDB Team - - * os/os0proc.c: - Fix a memory leak on Windows. The memory leak was due to wrong - parameters passed into VirtualFree() call. As the result, the - call fails with Windows error 87. - -2008-09-17 The InnoDB Team - - * mysql-test/innodb.result, mysql-test/innodb-zip.result, - mysql-test/innodb-zip.test, mysql-test/innodb.test, ibuf/ibuf0ibuf.c, - dict/dict0crea.c, dict/dict0load.c, dict/dict0boot.c, - include/dict0dict.h, include/trx0trx.h, dict/dict0dict.c, - trx/trx0trx.c, include/ha_prototypes.h, handler/ha_innodb.cc: - When creating an index in innodb_strict_mode, check that the - maximum record size will never exceed the B-tree page size limit. - For uncompressed tables, there should always be enough space for - two records in an empty B-tree page. For compressed tables, there - should be enough space for storing two node pointer records or one - data record in an empty page in uncompressed format. - The purpose of this check is to guarantee that INSERT or UPDATE - will never fail due to too big record size. - -2008-09-17 The InnoDB Team - - * btr/btr0cur.c, data/data0data.c, include/page0zip.h, - include/page0zip.ic, page/page0zip.c, mysql-test/innodb_bug36172.test: - Prevent infinite B-tree page splits in compressed tables by - ensuring that there will always be enough space for two node - pointer records in an empty B-tree page. Also, require that at - least one data record will fit in an empty compressed page. This - will reduce the maximum size of records in compressed tables. - -2008-09-09 The InnoDB Team - - * mysql-test/innodb.result: - Fix the failing innodb test by merging changes that MySQL made to - that file (r2646.12.1 in MySQL BZR repository) - -2008-09-09 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result, - mysql-test/innodb-autoinc.test: - Fix Bug#38839 auto increment does not work properly with InnoDB after - update - -2008-09-09 The InnoDB Team - - * dict/dict0dict.c, handler/handler0alter.cc, include/dict0dict.h, - mysql-test/innodb-index.result, mysql-test/innodb-index.test: - Fix Bug#38786 InnoDB plugin crashes on drop table/create table with FK - -2008-08-21 The InnoDB Team - - * handler/ha_innodb.cc, include/ha_prototypes.h, row/row0sel.c: - Fix Bug#37885 row_search_for_mysql may gap lock unnecessarily with SQL - comments in query - -2008-08-21 The InnoDB Team - - * handler/ha_innodb.cc: - Fix Bug#38185 ha_innobase::info can hold locks even when called with - HA_STATUS_NO_LOCK - -2008-08-18 The InnoDB Team - - * buf/buf0buf.c, buf/buf0lru.c, include/buf0buf.ic, include/univ.i: - Introduce UNIV_LRU_DEBUG for debugging the LRU buffer pool cache - -2008-08-08 The InnoDB Team - - * buf/buf0lru.c, include/buf0buf.h: - Fix two recovery bugs that could lead to a crash in debug builds with - small buffer size - -2008-08-07 The InnoDB Team - - * btr/btr0cur.c, handler/ha_innodb.cc, include/srv0srv.h, - srv/srv0srv.c: - Add a parameter innodb_stats_sample_pages to allow users to control - the number of index dives when InnoDB estimates the cardinality of - an index (ANALYZE TABLE, SHOW TABLE STATUS etc) - -2008-08-07 The InnoDB Team - - * trx/trx0i_s.c: - Fix a bug that would lead to a crash if a SELECT was issued from the - INFORMATION_SCHEMA tables and there are rolling back transactions at - the same time - -2008-08-06 The InnoDB Team - - * btr/btr0btr.c, btr/btr0cur.c, ibuf/ibuf0ibuf.c, include/btr0cur.h, - include/trx0roll.h, include/trx0types.h, row/row0purge.c, - row/row0uins.c, row/row0umod.c, trx/trx0roll.c: - In the rollback of incomplete transactions after crash recovery, - tolerate clustered index records whose externally stored columns - have not been written. - -2008-07-30 The InnoDB Team - - * trx/trx0trx.c: - Fixes a race in recovery where the recovery thread recovering a - PREPARED trx and the background rollback thread can both try - to free the trx after its status is set to COMMITTED_IN_MEMORY. - -2008-07-29 The InnoDB Team - - * include/trx0rec.h, row/row0purge.c, row/row0vers.c, trx/trx0rec.c: - Fix a BLOB corruption bug - -2008-07-15 The InnoDB Team - - * btr/btr0sea.c, dict/dict0dict.c, include/btr0sea.h: - Fixed a timing hole where a thread dropping an index can free the - in-memory index struct while another thread is still using that - structure to remove entries from adaptive hash index belonging - to one of the pages that belongs to the index being dropped. - -2008-07-04 The InnoDB Team - - * mysql-test/innodb-index.result: - Fix the failing innodb-index test by adjusting the result to a new - MySQL behavior (the change occured in BZR-r2667) - -2008-07-03 The InnoDB Team - - * mysql-test/innodb-zip.result, mysql-test/innodb-zip.test: - Remove the negative test cases that produce warnings - -2008-07-02 The InnoDB Team - - * mysql-test/innodb-replace.result, mysql-test/innodb-index.test: - Disable part of innodb-index test because MySQL changed its behavior - and is not calling ::add_index() anymore when adding primary index on - non-NULL column - -2008-07-01 The InnoDB Team - - * mysql-test/innodb-replace.result, mysql-test/innodb-replace.test: - Fix the failing innodb-replace test by merging changes that MySQL - made to that file (r2659 in MySQL BZR repository) - -2008-07-01 The InnoDB Team - - * lock/lock0lock.c: - Fix Bug#36942 Performance problem in lock_get_n_rec_locks (SHOW INNODB - STATUS) - -2008-07-01 The InnoDB Team - - * ha/ha0ha.c: - Fix Bug#36941 Performance problem in ha_print_info (SHOW INNODB - STATUS) - -2008-07-01 The InnoDB Team - - * handler/ha_innodb.cc, mysql-test/innodb-autoinc.result, - mysql-test/innodb-autoinc.test: - Fix Bug#37531 After truncate, auto_increment behaves incorrectly for - InnoDB - -2008-06-19 The InnoDB Team - - * handler/ha_innodb.cc: - Rewrite the function innodb_plugin_init() to support parameters in - different order (in static and dynamic InnoDB) and to support more - parameters in the static InnoDB - -2008-06-19 The InnoDB Team - - * handler/handler0alter.cc: - Fix a bug in ::add_index() which set the transaction state to "active" - but never restored it to the original value. This bug caused warnings - to be printed by the rpl.rpl_ddl mysql-test. - -2008-06-19 The InnoDB Team - - * mysql-test/patches: - Add a directory which contains patches, which need to be applied to - MySQL source in order to get some mysql-tests to succeed. The patches - cannot be committed in MySQL repository because they are specific to - the InnoDB plugin. - -2008-06-19 The InnoDB Team - - * mysql-test/innodb-zip.result, mysql-test/innodb-zip.test, - row/row0row.c: - Fix an anomaly when updating a record with BLOB prefix - -2008-06-18 The InnoDB Team - - * include/trx0sys.h, srv/srv0start.c, trx/trx0sys.c: - Fix a bug in recovery which was a side effect of the file_format_check - changes - -2008-06-09 The InnoDB Team - - * mysql-test/innodb.result: - Fix the failing innodb test by merging changes that MySQL made to that - file - -2008-06-06 The InnoDB Team - - * buf/buf0buf.c, handler/ha_innodb.cc, include/buf0buf.h, - include/srv0srv.h, srv/srv0srv.c: - Fix Bug#36600 SHOW STATUS takes a lot of CPU in - buf_get_latched_pages_number - - * handler/ha_innodb.cc, os/os0file.c: - Fix Bug#11894 innodb_file_per_table crashes w/ Windows .sym symbolic - link hack - - * include/ut0ut.h, srv/srv0srv.c, ut/ut0ut.c: - Fix Bug#36819 ut_usectime does not handle errors from gettimeofday - - * handler/ha_innodb.cc: - Fix Bug#35602 Failed to read auto-increment value from storage engine - - * srv/srv0start.c: - Fix Bug#36149 Read buffer overflow in srv0start.c found during "make - test" - -2008-05-08 The InnoDB Team - - * btr/btr0btr.c, mysql-test/innodb_bug36172.result, - mysql-test/innodb_bug36172.test: - Fix Bug#36172 insert into compressed innodb table crashes - -2008-05-08 The InnoDB Team - - InnoDB Plugin 1.0.1 released - -2008-05-06 The InnoDB Team - - * handler/ha_innodb.cc, include/srv0srv.h, include/sync0sync.h, - include/trx0sys.h, mysql-test/innodb-zip.result, - mysql-test/innodb-zip.test, srv/srv0srv.c, srv/srv0start.c, - sync/sync0sync.c, trx/trx0sys.c: - Implement the system tablespace tagging - - * handler/ha_innodb.cc, handler/i_s.cc, include/univ.i, - srv/srv0start.c: - Add InnoDB version in INFORMATION_SCHEMA.PLUGINS.PLUGIN_VERSION, - in the startup message and in a server variable innodb_version. - - * sync/sync0sync.c: - Fix a bug in the sync debug code where a lock with level - SYNC_LEVEL_VARYING would cause an assertion failure when a thread - tried to release it. - -2008-04-30 The InnoDB Team - - * Makefile.am: - Fix Bug#36434 ha_innodb.so is installed in the wrong directory - - * handler/ha_innodb.cc: - Merge change from MySQL (Fix Bug#35406 5.1-opt crashes on select from - I_S.REFERENTIAL_CONSTRAINTS): - ChangeSet@1.2563, 2008-03-18 19:42:04+04:00, gluh@mysql.com +1 -0 - - * scripts/install_innodb_plugins.sql: - Added - - * mysql-test/innodb.result: - Merge change from MySQL (this fixes the failing innodb test): - ChangeSet@1.1810.3601.4, 2008-02-07 02:33:21+04:00 - - * row/row0sel.c: - Fix Bug#35226 RBR event crashes slave - - * handler/ha_innodb.cc: - Change the fix for Bug#32440 to show bytes instead of kilobytes in - INFORMATION_SCHEMA.TABLES.DATA_FREE - - * handler/ha_innodb.cc, mysql-test/innodb.result, - mysql-test/innodb.test: - Fix Bug#29507 TRUNCATE shows to many rows effected - - * handler/ha_innodb.cc, mysql-test/innodb.result, - mysql-test/innodb.test: - Fix Bug#35537 Innodb doesn't increment handler_update and - handler_delete - -2008-04-29 The InnoDB Team - - * handler/i_s.cc, include/srv0start.h, srv/srv0start.c: - Fix Bug#36310 InnoDB plugin crash - -2008-04-23 The InnoDB Team - - * mysql-test/innodb_bug36169.result, mysql-test/innodb_bug36169.test, - row/row0mysql.c: - Fix Bug#36169 create innodb compressed table with too large row size - crashed - - * (outside the source tree): - Fix Bug#36222 New InnoDB plugin 1.0 has wrong MKDIR_P defined in - Makefile.in - -2008-04-15 The InnoDB Team - - InnoDB Plugin 1.0.0 released diff --git a/storage/innobase/Makefile.am b/storage/innobase/Makefile.am index 0caf623bcc2..c15c46abaf0 100644 --- a/storage/innobase/Makefile.am +++ b/storage/innobase/Makefile.am @@ -28,7 +28,6 @@ INCLUDES= -I$(top_srcdir)/include -I$(top_builddir)/include \ DEFS= @DEFS@ - noinst_HEADERS= \ handler/ha_innodb.h \ handler/i_s.h \ @@ -118,6 +117,7 @@ noinst_HEADERS= \ include/mtr0types.h \ include/mysql_addons.h \ include/os0file.h \ + include/os0file.ic \ include/os0proc.h \ include/os0proc.ic \ include/os0sync.h \ @@ -174,7 +174,6 @@ noinst_HEADERS= \ include/row0upd.ic \ include/row0vers.h \ include/row0vers.ic \ - include/srv0que.h \ include/srv0srv.h \ include/srv0srv.ic \ include/srv0start.h \ @@ -217,6 +216,7 @@ noinst_HEADERS= \ include/ut0lst.h \ include/ut0mem.h \ include/ut0mem.ic \ + include/ut0rbt.h \ include/ut0rnd.h \ include/ut0rnd.ic \ include/ut0sort.h \ @@ -298,7 +298,6 @@ libinnobase_a_SOURCES= \ row/row0undo.c \ row/row0upd.c \ row/row0vers.c \ - srv/srv0que.c \ srv/srv0srv.c \ srv/srv0start.c \ sync/sync0arr.c \ @@ -318,6 +317,7 @@ libinnobase_a_SOURCES= \ ut/ut0dbg.c \ ut/ut0list.c \ ut/ut0mem.c \ + ut/ut0rbt.c \ ut/ut0rnd.c \ ut/ut0ut.c \ ut/ut0vec.c \ diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index 086b3a0a599..05dd094b6df 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. 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 @@ -592,15 +592,18 @@ an x-latch on the tree. @return rec_get_offsets() of the node pointer record */ static ulint* -btr_page_get_father_node_ptr( -/*=========================*/ +btr_page_get_father_node_ptr_func( +/*==============================*/ ulint* offsets,/*!< in: work area for the return value */ mem_heap_t* heap, /*!< in: memory heap to use */ btr_cur_t* cursor, /*!< in: cursor pointing to user record, out: cursor on node pointer record, its page x-latched */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mtr */ { + page_t* page; dtuple_t* tuple; rec_t* user_rec; rec_t* node_ptr; @@ -617,12 +620,15 @@ btr_page_get_father_node_ptr( ut_ad(dict_index_get_page(index) != page_no); level = btr_page_get_level(btr_cur_get_page(cursor), mtr); + + page = btr_cur_get_page(cursor); user_rec = btr_cur_get_rec(cursor); ut_a(page_rec_is_user_rec(user_rec)); tuple = dict_index_build_node_ptr(index, user_rec, 0, heap, level); btr_cur_search_to_nth_level(index, level + 1, tuple, PAGE_CUR_LE, - BTR_CONT_MODIFY_TREE, cursor, 0, mtr); + BTR_CONT_MODIFY_TREE, cursor, 0, + file, line, mtr); node_ptr = btr_cur_get_rec(cursor); ut_ad(!page_rec_is_comp(node_ptr) @@ -670,6 +676,9 @@ btr_page_get_father_node_ptr( return(offsets); } +#define btr_page_get_father_node_ptr(of,heap,cur,mtr) \ + btr_page_get_father_node_ptr_func(of,heap,cur,__FILE__,__LINE__,mtr) + /************************************************************//** Returns the upper level node pointer to a page. It is assumed that mtr holds an x-latch on the tree. @@ -943,6 +952,7 @@ btr_page_reorganize_low( dict_index_t* index, /*!< in: record descriptor */ mtr_t* mtr) /*!< in: mtr */ { + buf_pool_t* buf_pool = buf_pool_from_bpage(&block->page); page_t* page = buf_block_get_frame(block); page_zip_des_t* page_zip = buf_block_get_page_zip(block); buf_block_t* temp_block; @@ -973,7 +983,7 @@ btr_page_reorganize_low( log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE); #ifndef UNIV_HOTBACKUP - temp_block = buf_block_alloc(0); + temp_block = buf_block_alloc(buf_pool, 0); #else /* !UNIV_HOTBACKUP */ ut_ad(block == back_block1); temp_block = back_block2; @@ -1445,11 +1455,11 @@ Calculates a split record such that the tuple will certainly fit on its half-page when the split is performed. We assume in this function only that the cursor page has at least one user record. @return split record, or NULL if tuple will be the first record on -upper half-page */ +the lower or upper half-page (determined by btr_page_tuple_smaller()) */ static rec_t* -btr_page_get_sure_split_rec( -/*========================*/ +btr_page_get_split_rec( +/*===================*/ btr_cur_t* cursor, /*!< in: cursor at which insert should be made */ const dtuple_t* tuple, /*!< in: tuple to insert */ ulint n_ext) /*!< in: number of externally stored columns */ @@ -1662,11 +1672,13 @@ Inserts a data tuple to a tree on a non-leaf level. It is assumed that mtr holds an x-latch on the tree. */ UNIV_INTERN void -btr_insert_on_non_leaf_level( -/*=========================*/ +btr_insert_on_non_leaf_level_func( +/*==============================*/ dict_index_t* index, /*!< in: index */ ulint level, /*!< in: level, must be > 0 */ dtuple_t* tuple, /*!< in: the record to be inserted */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mtr */ { big_rec_t* dummy_big_rec; @@ -1678,7 +1690,7 @@ btr_insert_on_non_leaf_level( btr_cur_search_to_nth_level(index, level, tuple, PAGE_CUR_LE, BTR_CONT_MODIFY_TREE, - &cursor, 0, mtr); + &cursor, 0, file, line, mtr); err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG @@ -1824,6 +1836,37 @@ btr_attach_half_pages( } /*************************************************************//** +Determine if a tuple is smaller than any record on the page. +@return TRUE if smaller */ +static +ibool +btr_page_tuple_smaller( +/*===================*/ + btr_cur_t* cursor, /*!< in: b-tree cursor */ + const dtuple_t* tuple, /*!< in: tuple to consider */ + ulint* offsets,/*!< in/out: temporary storage */ + ulint n_uniq, /*!< in: number of unique fields + in the index page records */ + mem_heap_t** heap) /*!< in/out: heap for offsets */ +{ + buf_block_t* block; + const rec_t* first_rec; + page_cur_t pcur; + + /* Read the first user record in the page. */ + block = btr_cur_get_block(cursor); + page_cur_set_before_first(block, &pcur); + page_cur_move_to_next(&pcur); + first_rec = page_cur_get_rec(&pcur); + + offsets = rec_get_offsets( + first_rec, cursor->index, offsets, + n_uniq, heap); + + return(cmp_dtuple_rec(tuple, first_rec, offsets) < 0); +} + +/*************************************************************//** Splits an index page to halves and inserts the tuple. It is assumed that mtr holds an x-latch to the index tree. NOTE: the tree x-latch is released within this function! NOTE that the operation of this @@ -1893,12 +1936,17 @@ func_start: /* 1. Decide the split record; split_rec == NULL means that the tuple to be inserted should be the first record on the upper half-page */ + insert_left = FALSE; if (n_iterations > 0) { direction = FSP_UP; hint_page_no = page_no + 1; - split_rec = btr_page_get_sure_split_rec(cursor, tuple, n_ext); + split_rec = btr_page_get_split_rec(cursor, tuple, n_ext); + if (UNIV_UNLIKELY(split_rec == NULL)) { + insert_left = btr_page_tuple_smaller( + cursor, tuple, offsets, n_uniq, &heap); + } } else if (btr_page_get_split_rec_to_right(cursor, &split_rec)) { direction = FSP_UP; hint_page_no = page_no + 1; @@ -1906,37 +1954,24 @@ func_start: } else if (btr_page_get_split_rec_to_left(cursor, &split_rec)) { direction = FSP_DOWN; hint_page_no = page_no - 1; + ut_ad(split_rec); } else { direction = FSP_UP; hint_page_no = page_no + 1; - if (page_get_n_recs(page) == 1) { - page_cur_t pcur; - - /* There is only one record in the index page - therefore we can't split the node in the middle - by default. We need to determine whether the - new record will be inserted to the left or right. */ + /* If there is only one record in the index page, we + can't split the node in the middle by default. We need + to determine whether the new record will be inserted + to the left or right. */ - /* Read the first (and only) record in the page. */ - page_cur_set_before_first(block, &pcur); - page_cur_move_to_next(&pcur); - first_rec = page_cur_get_rec(&pcur); - - offsets = rec_get_offsets( - first_rec, cursor->index, offsets, - n_uniq, &heap); - - /* If the new record is less than the existing record - the split in the middle will copy the existing - record to the new node. */ - if (cmp_dtuple_rec(tuple, first_rec, offsets) < 0) { - split_rec = page_get_middle_rec(page); - } else { - split_rec = NULL; - } - } else { + if (page_get_n_recs(page) > 1) { split_rec = page_get_middle_rec(page); + } else if (btr_page_tuple_smaller(cursor, tuple, + offsets, n_uniq, &heap)) { + split_rec = page_rec_get_next( + page_get_infimum_rec(page)); + } else { + split_rec = NULL; } } @@ -1966,11 +2001,16 @@ func_start: avoid further splits by inserting the record to an empty page. */ split_rec = NULL; - goto insert_right; + goto insert_empty; } + } else if (UNIV_UNLIKELY(insert_left)) { + ut_a(n_iterations > 0); + first_rec = page_rec_get_next(page_get_infimum_rec(page)); + move_limit = page_rec_get_next(btr_cur_get_rec(cursor)); } else { -insert_right: - insert_left = FALSE; +insert_empty: + ut_ad(!split_rec); + ut_ad(!insert_left); buf = mem_alloc(rec_get_converted_size(cursor->index, tuple, n_ext)); @@ -1994,7 +2034,11 @@ insert_right: && btr_page_insert_fits(cursor, split_rec, offsets, tuple, n_ext, heap); } else { - mem_free(buf); + if (!insert_left) { + mem_free(buf); + buf = NULL; + } + insert_will_fit = !new_page_zip && btr_page_insert_fits(cursor, NULL, NULL, tuple, n_ext, heap); diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 46dfb5d1a46..31e1a2d4b12 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -57,6 +57,8 @@ Created 10/16/1994 Heikki Tuuri #include "buf0lru.h" #include "btr0btr.h" #include "btr0sea.h" +#include "row0purge.h" +#include "row0upd.h" #include "trx0rec.h" #include "trx0roll.h" /* trx_is_recv() */ #include "que0que.h" @@ -66,6 +68,15 @@ Created 10/16/1994 Heikki Tuuri #include "lock0lock.h" #include "zlib.h" +/** Buffered B-tree operation types, introduced as part of delete buffering. */ +typedef enum btr_op_enum { + BTR_NO_OP = 0, /*!< Not buffered */ + BTR_INSERT_OP, /*!< Insert, do not ignore UNIQUE */ + BTR_INSERT_IGNORE_UNIQUE_OP, /*!< Insert, ignoring UNIQUE */ + BTR_DELETE_OP, /*!< Purge a delete-marked record */ + BTR_DELMARK_OP /*!< Mark a record for deletion */ +} btr_op_t; + #ifdef UNIV_DEBUG /** If the following is set to TRUE, this module prints a lot of trace information of individual record operations */ @@ -328,7 +339,8 @@ btr_cur_search_to_nth_level( Inserts should always be made using PAGE_CUR_LE to search the position! */ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ..., ORed with - BTR_INSERT and BTR_ESTIMATE; + at most one of BTR_INSERT, BTR_DELETE_MARK, + BTR_DELETE, or BTR_ESTIMATE; cursor->left_block is used to store a pointer to the left neighbor page, in the cases BTR_SEARCH_PREV and BTR_MODIFY_PREV; @@ -342,25 +354,30 @@ btr_cur_search_to_nth_level( ulint has_search_latch,/*!< in: info on the latch mode the caller currently has on btr_search_latch: RW_S_LATCH, or 0 */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mtr */ { - page_cur_t* page_cursor; page_t* page; + buf_block_t* block; + ulint space; buf_block_t* guess; - rec_t* node_ptr; + ulint height; ulint page_no; - ulint space; ulint up_match; ulint up_bytes; ulint low_match; ulint low_bytes; - ulint height; ulint savepoint; + ulint rw_latch; ulint page_mode; - ulint insert_planned; + ulint buf_mode; ulint estimate; - ulint ignore_sec_unique; + ulint zip_size; + page_cur_t* page_cursor; + btr_op_t btr_op; ulint root_height = 0; /* remove warning */ + #ifdef BTR_CUR_ADAPT btr_search_t* info; #endif @@ -380,17 +397,53 @@ btr_cur_search_to_nth_level( cursor->up_match = ULINT_UNDEFINED; cursor->low_match = ULINT_UNDEFINED; #endif - insert_planned = latch_mode & BTR_INSERT; + + /* These flags are mutually exclusive, they are lumped together + with the latch mode for historical reasons. It's possible for + none of the flags to be set. */ + switch (UNIV_EXPECT(latch_mode + & (BTR_INSERT | BTR_DELETE | BTR_DELETE_MARK), + 0)) { + case 0: + btr_op = BTR_NO_OP; + break; + case BTR_INSERT: + btr_op = (latch_mode & BTR_IGNORE_SEC_UNIQUE) + ? BTR_INSERT_IGNORE_UNIQUE_OP + : BTR_INSERT_OP; + break; + case BTR_DELETE: + btr_op = BTR_DELETE_OP; + ut_a(cursor->purge_node); + break; + case BTR_DELETE_MARK: + btr_op = BTR_DELMARK_OP; + break; + default: + /* only one of BTR_INSERT, BTR_DELETE, BTR_DELETE_MARK + should be specified at a time */ + ut_error; + } + + /* Operations on the insert buffer tree cannot be buffered. */ + ut_ad(btr_op == BTR_NO_OP || !dict_index_is_ibuf(index)); + /* Operations on the clustered index cannot be buffered. */ + ut_ad(btr_op == BTR_NO_OP || !dict_index_is_clust(index)); + estimate = latch_mode & BTR_ESTIMATE; - ignore_sec_unique = latch_mode & BTR_IGNORE_SEC_UNIQUE; - latch_mode = latch_mode & ~(BTR_INSERT | BTR_ESTIMATE - | BTR_IGNORE_SEC_UNIQUE); - ut_ad(!insert_planned || (mode == PAGE_CUR_LE)); + /* Turn the flags unrelated to the latch mode off. */ + latch_mode &= ~(BTR_INSERT + | BTR_DELETE_MARK + | BTR_DELETE + | BTR_ESTIMATE + | BTR_IGNORE_SEC_UNIQUE); cursor->flag = BTR_CUR_BINARY; cursor->index = index; + cursor->ibuf_cnt = ULINT_UNDEFINED; + #ifndef BTR_CUR_ADAPT guess = NULL; #else @@ -404,7 +457,8 @@ btr_cur_search_to_nth_level( info->n_searches++; #endif if (rw_lock_get_writer(&btr_search_latch) == RW_LOCK_NOT_LOCKED - && latch_mode <= BTR_MODIFY_LEAF && info->last_hash_succ + && latch_mode <= BTR_MODIFY_LEAF + && info->last_hash_succ && !estimate #ifdef PAGE_CUR_LE_OR_EXTENDS && mode != PAGE_CUR_LE_OR_EXTENDS @@ -493,156 +547,219 @@ btr_cur_search_to_nth_level( /* Loop and search until we arrive at the desired level */ - for (;;) { - ulint zip_size; - buf_block_t* block; - ulint rw_latch; - ulint buf_mode; - - zip_size = dict_table_zip_size(index->table); - rw_latch = RW_NO_LATCH; - buf_mode = BUF_GET; - - if (height == 0 && latch_mode <= BTR_MODIFY_LEAF) { +search_loop: + buf_mode = BUF_GET; + rw_latch = RW_NO_LATCH; - rw_latch = latch_mode; + if (height != 0) { + /* We are about to fetch the root or a non-leaf page. */ + } else if (latch_mode <= BTR_MODIFY_LEAF) { + rw_latch = latch_mode; - if (insert_planned - && ibuf_should_try(index, ignore_sec_unique)) { + if (btr_op != BTR_NO_OP + && ibuf_should_try(index, btr_op != BTR_INSERT_OP)) { - /* Try insert to the insert buffer if the - page is not in the buffer pool */ + /* Try to buffer the operation if the leaf + page is not in the buffer pool. */ - buf_mode = BUF_GET_IF_IN_POOL; - } + buf_mode = btr_op == BTR_DELETE_OP + ? BUF_GET_IF_IN_POOL_OR_WATCH + : BUF_GET_IF_IN_POOL; } + } + + zip_size = dict_table_zip_size(index->table); retry_page_get: - block = buf_page_get_gen(space, zip_size, page_no, - rw_latch, guess, buf_mode, - __FILE__, __LINE__, mtr); - if (block == NULL) { - /* This must be a search to perform an insert; - try insert to the insert buffer */ + block = buf_page_get_gen( + space, zip_size, page_no, rw_latch, guess, buf_mode, + file, line, mtr); + + if (block == NULL) { + /* This must be a search to perform an insert/delete + mark/ delete; try using the insert/delete buffer */ + ut_ad(height == 0); + ut_ad(cursor->thr); + + switch (btr_op) { + case BTR_INSERT_OP: + case BTR_INSERT_IGNORE_UNIQUE_OP: ut_ad(buf_mode == BUF_GET_IF_IN_POOL); - ut_ad(insert_planned); - ut_ad(cursor->thr); - if (ibuf_insert(tuple, index, space, zip_size, - page_no, cursor->thr)) { - /* Insertion to the insert buffer succeeded */ + if (ibuf_insert(IBUF_OP_INSERT, tuple, index, + space, zip_size, page_no, + cursor->thr)) { + cursor->flag = BTR_CUR_INSERT_TO_IBUF; - if (UNIV_LIKELY_NULL(heap)) { - mem_heap_free(heap); - } + goto func_exit; } + break; - /* Insert to the insert buffer did not succeed: - retry page get */ + case BTR_DELMARK_OP: + ut_ad(buf_mode == BUF_GET_IF_IN_POOL); - buf_mode = BUF_GET; + if (ibuf_insert(IBUF_OP_DELETE_MARK, tuple, + index, space, zip_size, + page_no, cursor->thr)) { - goto retry_page_get; + cursor->flag = BTR_CUR_DEL_MARK_IBUF; + + goto func_exit; + } + + break; + + case BTR_DELETE_OP: + ut_ad(buf_mode == BUF_GET_IF_IN_POOL_OR_WATCH); + + if (!row_purge_poss_sec(cursor->purge_node, + index, tuple)) { + + /* The record cannot be purged yet. */ + cursor->flag = BTR_CUR_DELETE_REF; + } else if (ibuf_insert(IBUF_OP_DELETE, tuple, + index, space, zip_size, + page_no, + cursor->thr)) { + + /* The purge was buffered. */ + cursor->flag = BTR_CUR_DELETE_IBUF; + } else { + /* The purge could not be buffered. */ + buf_pool_watch_unset(space, page_no); + break; + } + + buf_pool_watch_unset(space, page_no); + goto func_exit; + + default: + ut_error; } - page = buf_block_get_frame(block); + /* Insert to the insert/delete buffer did not succeed, we + must read the page from disk. */ - block->check_index_page_at_flush = TRUE; + buf_mode = BUF_GET; + + goto retry_page_get; + } - if (rw_latch != RW_NO_LATCH) { + block->check_index_page_at_flush = TRUE; + page = buf_block_get_frame(block); + + if (rw_latch != RW_NO_LATCH) { #ifdef UNIV_ZIP_DEBUG - const page_zip_des_t* page_zip - = buf_block_get_page_zip(block); - ut_a(!page_zip || page_zip_validate(page_zip, page)); + const page_zip_des_t* page_zip + = buf_block_get_page_zip(block); + ut_a(!page_zip || page_zip_validate(page_zip, page)); #endif /* UNIV_ZIP_DEBUG */ - buf_block_dbg_add_level(block, SYNC_TREE_NODE); - } + buf_block_dbg_add_level(block, SYNC_TREE_NODE); + } - ut_ad(0 == ut_dulint_cmp(index->id, - btr_page_get_index_id(page))); + ut_ad(0 == ut_dulint_cmp(index->id, btr_page_get_index_id(page))); - if (UNIV_UNLIKELY(height == ULINT_UNDEFINED)) { - /* We are in the root node */ + if (UNIV_UNLIKELY(height == ULINT_UNDEFINED)) { + /* We are in the root node */ + + height = btr_page_get_level(page, mtr); + root_height = height; + cursor->tree_height = root_height + 1; - height = btr_page_get_level(page, mtr); - root_height = height; - cursor->tree_height = root_height + 1; #ifdef BTR_CUR_ADAPT - if (block != guess) { - info->root_guess = block; - } -#endif + if (block != guess) { + info->root_guess = block; } +#endif + } - if (height == 0) { - if (rw_latch == RW_NO_LATCH) { - - btr_cur_latch_leaves(page, space, zip_size, - page_no, latch_mode, - cursor, mtr); - } + if (height == 0) { + if (rw_latch == RW_NO_LATCH) { - if ((latch_mode != BTR_MODIFY_TREE) - && (latch_mode != BTR_CONT_MODIFY_TREE)) { + btr_cur_latch_leaves( + page, space, zip_size, page_no, latch_mode, + cursor, mtr); + } - /* Release the tree s-latch */ + if (latch_mode != BTR_MODIFY_TREE + && latch_mode != BTR_CONT_MODIFY_TREE) { - mtr_release_s_latch_at_savepoint( - mtr, savepoint, - dict_index_get_lock(index)); - } + /* Release the tree s-latch */ - page_mode = mode; + mtr_release_s_latch_at_savepoint( + mtr, savepoint, dict_index_get_lock(index)); } - page_cur_search_with_match(block, index, tuple, page_mode, - &up_match, &up_bytes, - &low_match, &low_bytes, - page_cursor); + page_mode = mode; + } - if (estimate) { - btr_cur_add_path_info(cursor, height, root_height); - } + page_cur_search_with_match( + block, index, tuple, page_mode, &up_match, &up_bytes, + &low_match, &low_bytes, page_cursor); - /* If this is the desired level, leave the loop */ + if (estimate) { + btr_cur_add_path_info(cursor, height, root_height); + } - ut_ad(height == btr_page_get_level( - page_cur_get_page(page_cursor), mtr)); + /* If this is the desired level, leave the loop */ - if (level == height) { + ut_ad(height == btr_page_get_level(page_cur_get_page(page_cursor), + mtr)); - if (level > 0) { - /* x-latch the page */ - page = btr_page_get(space, zip_size, - page_no, RW_X_LATCH, mtr); - ut_a((ibool)!!page_is_comp(page) - == dict_table_is_comp(index->table)); - } - - break; - } + if (level != height) { + const rec_t* node_ptr; ut_ad(height > 0); height--; - guess = NULL; node_ptr = page_cur_get_rec(page_cursor); - offsets = rec_get_offsets(node_ptr, cursor->index, offsets, - ULINT_UNDEFINED, &heap); + + offsets = rec_get_offsets( + node_ptr, index, offsets, ULINT_UNDEFINED, &heap); + /* Go to the child node */ page_no = btr_node_ptr_get_child_page_no(node_ptr, offsets); - } - if (UNIV_LIKELY_NULL(heap)) { - mem_heap_free(heap); + if (UNIV_UNLIKELY(height == 0 && dict_index_is_ibuf(index))) { + /* We're doing a search on an ibuf tree and we're one + level above the leaf page. */ + + ulint is_min_rec; + + ut_ad(level == 0); + + is_min_rec = rec_get_info_bits(node_ptr, 0) + & REC_INFO_MIN_REC_FLAG; + + if (!is_min_rec) { + cursor->ibuf_cnt + = ibuf_rec_get_counter(node_ptr); + + ut_a(cursor->ibuf_cnt <= 0xFFFF + || cursor->ibuf_cnt == ULINT_UNDEFINED); + } + + buf_mode = BUF_GET; + rw_latch = RW_NO_LATCH; + goto retry_page_get; + } + + goto search_loop; } - if (level == 0) { + if (level != 0) { + /* x-latch the page */ + page = btr_page_get( + space, zip_size, page_no, RW_X_LATCH, mtr); + + ut_a((ibool)!!page_is_comp(page) + == dict_table_is_comp(index->table)); + } else { cursor->low_match = low_match; cursor->low_bytes = low_bytes; cursor->up_match = up_match; @@ -667,6 +784,11 @@ retry_page_get: } func_exit: + + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + if (has_search_latch) { rw_lock_s_lock(&btr_search_latch); @@ -677,13 +799,15 @@ func_exit: Opens a cursor at either end of an index. */ UNIV_INTERN void -btr_cur_open_at_index_side( -/*=======================*/ +btr_cur_open_at_index_side_func( +/*============================*/ ibool from_left, /*!< in: TRUE if open to the low end, FALSE if to the high end */ dict_index_t* index, /*!< in: index */ ulint latch_mode, /*!< in: latch mode */ btr_cur_t* cursor, /*!< in: cursor */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mtr */ { page_cur_t* page_cursor; @@ -728,7 +852,7 @@ btr_cur_open_at_index_side( page_t* page; block = buf_page_get_gen(space, zip_size, page_no, RW_NO_LATCH, NULL, BUF_GET, - __FILE__, __LINE__, mtr); + file, line, mtr); page = buf_block_get_frame(block); ut_ad(0 == ut_dulint_cmp(index->id, btr_page_get_index_id(page))); @@ -808,11 +932,13 @@ btr_cur_open_at_index_side( Positions a cursor at a randomly chosen position within a B-tree. */ UNIV_INTERN void -btr_cur_open_at_rnd_pos( -/*====================*/ +btr_cur_open_at_rnd_pos_func( +/*=========================*/ dict_index_t* index, /*!< in: index */ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */ btr_cur_t* cursor, /*!< in/out: B-tree cursor */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mtr */ { page_cur_t* page_cursor; @@ -847,7 +973,7 @@ btr_cur_open_at_rnd_pos( block = buf_page_get_gen(space, zip_size, page_no, RW_NO_LATCH, NULL, BUF_GET, - __FILE__, __LINE__, mtr); + file, line, mtr); page = buf_block_get_frame(block); ut_ad(0 == ut_dulint_cmp(index->id, btr_page_get_index_id(page))); @@ -1058,7 +1184,6 @@ btr_cur_optimistic_insert( ibool inherit; ulint zip_size; ulint rec_size; - mem_heap_t* heap = NULL; ulint err; *big_rec = NULL; @@ -1138,10 +1263,6 @@ btr_cur_optimistic_insert( index, entry, big_rec_vec); } - if (heap) { - mem_heap_free(heap); - } - return(DB_TOO_BIG_RECORD); } } @@ -1164,15 +1285,11 @@ fail_err: dtuple_convert_back_big_rec(index, entry, big_rec_vec); } - if (UNIV_LIKELY_NULL(heap)) { - mem_heap_free(heap); - } - return(err); } if (UNIV_UNLIKELY(max_size < BTR_CUR_PAGE_REORGANIZE_LIMIT - || max_size < rec_size) + || max_size < rec_size) && UNIV_LIKELY(page_get_n_recs(page) > 1) && page_get_max_insert_size(page, 1) < rec_size) { @@ -1238,10 +1355,6 @@ fail_err: } } - if (UNIV_LIKELY_NULL(heap)) { - mem_heap_free(heap); - } - #ifdef BTR_CUR_HASH_ADAPT if (!reorg && leaf && (cursor->flag == BTR_CUR_HASH)) { btr_search_update_hash_node_on_insert(cursor); @@ -1966,9 +2079,8 @@ any_extern: err = btr_cur_upd_lock_and_undo(flags, cursor, update, cmpl_info, thr, mtr, &roll_ptr); if (err != DB_SUCCESS) { -err_exit: - mem_heap_free(heap); - return(err); + + goto err_exit; } /* Ok, we may do the replacement. Store on the page infimum the @@ -2014,9 +2126,10 @@ err_exit: page_cur_move_to_next(page_cursor); + err = DB_SUCCESS; +err_exit: mem_heap_free(heap); - - return(DB_SUCCESS); + return(err); } /*************************************************************//** @@ -2729,25 +2842,26 @@ btr_cur_del_mark_set_sec_rec( } /***********************************************************//** -Clear a secondary index record's delete mark. This function is only -used by the insert buffer insert merge mechanism. */ +Sets a secondary index record's delete mark to the given value. This +function is only used by the insert buffer merge mechanism. */ UNIV_INTERN void -btr_cur_del_unmark_for_ibuf( -/*========================*/ - rec_t* rec, /*!< in/out: record to delete unmark */ +btr_cur_set_deleted_flag_for_ibuf( +/*==============================*/ + rec_t* rec, /*!< in/out: record */ page_zip_des_t* page_zip, /*!< in/out: compressed page corresponding to rec, or NULL when the tablespace is uncompressed */ + ibool val, /*!< in: value to set */ mtr_t* mtr) /*!< in: mtr */ { /* We do not need to reserve btr_search_latch, as the page has just been read to the buffer pool and there cannot be a hash index to it. */ - btr_rec_set_deleted_flag(rec, page_zip, FALSE); + btr_rec_set_deleted_flag(rec, page_zip, val); - btr_cur_del_mark_set_sec_rec_log(rec, FALSE, mtr); + btr_cur_del_mark_set_sec_rec_log(rec, val, mtr); } /*==================== B-TREE RECORD REMOVE =========================*/ @@ -3100,7 +3214,8 @@ btr_estimate_n_rows_in_range( btr_cur_search_to_nth_level(index, 0, tuple1, mode1, BTR_SEARCH_LEAF | BTR_ESTIMATE, - &cursor, 0, &mtr); + &cursor, 0, + __FILE__, __LINE__, &mtr); } else { btr_cur_open_at_index_side(TRUE, index, BTR_SEARCH_LEAF | BTR_ESTIMATE, @@ -3117,7 +3232,8 @@ btr_estimate_n_rows_in_range( btr_cur_search_to_nth_level(index, 0, tuple2, mode2, BTR_SEARCH_LEAF | BTR_ESTIMATE, - &cursor, 0, &mtr); + &cursor, 0, + __FILE__, __LINE__, &mtr); } else { btr_cur_open_at_index_side(FALSE, index, BTR_SEARCH_LEAF | BTR_ESTIMATE, @@ -3361,6 +3477,8 @@ btr_estimate_number_of_different_key_vals( also the pages used for external storage of fields (those pages are included in index->stat_n_leaf_pages) */ + dict_index_stat_mutex_enter(index); + for (j = 0; j <= n_cols; j++) { index->stat_n_diff_key_vals[j] = ((n_diff[j] @@ -3390,6 +3508,8 @@ btr_estimate_number_of_different_key_vals( index->stat_n_diff_key_vals[j] += add_on; } + dict_index_stat_mutex_exit(index); + mem_free(n_diff); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); @@ -3753,14 +3873,15 @@ btr_blob_free( if there is one */ mtr_t* mtr) /*!< in: mini-transaction to commit */ { - ulint space = buf_block_get_space(block); - ulint page_no = buf_block_get_page_no(block); + buf_pool_t* buf_pool = buf_pool_from_block(block); + ulint space = buf_block_get_space(block); + ulint page_no = buf_block_get_page_no(block); ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)); mtr_commit(mtr); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); mutex_enter(&block->mutex); /* Only free the block if it is still allocated to @@ -3781,7 +3902,7 @@ btr_blob_free( } } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); mutex_exit(&block->mutex); } @@ -3872,6 +3993,8 @@ btr_store_big_rec_extern_fields( field_ref += local_len; } extern_len = big_rec_vec->fields[i].len; + UNIV_MEM_ASSERT_RW(big_rec_vec->fields[i].data, + extern_len); ut_a(extern_len > 0); @@ -4252,7 +4375,7 @@ btr_free_externally_stored_field( /* In the rollback of uncommitted transactions, we may encounter a clustered index record whose BLOBs have not been written. There is nothing to free then. */ - ut_a(rb_ctx == RB_RECOVERY); + ut_a(rb_ctx == RB_RECOVERY || rb_ctx == RB_RECOVERY_PURGE_REC); return; } @@ -4298,7 +4421,7 @@ btr_free_externally_stored_field( || (mach_read_from_1(field_ref + BTR_EXTERN_LEN) & BTR_EXTERN_OWNER_FLAG) /* Rollback and inherited field */ - || (rb_ctx != RB_NONE + || ((rb_ctx == RB_NORMAL || rb_ctx == RB_RECOVERY) && (mach_read_from_1(field_ref + BTR_EXTERN_LEN) & BTR_EXTERN_INHERITED_FLAG))) { @@ -4508,6 +4631,7 @@ btr_copy_blob_prefix( mtr_commit(&mtr); if (page_no == FIL_NULL || copy_len != part_len) { + UNIV_MEM_ASSERT_RW(buf, copied_len); return(copied_len); } @@ -4691,6 +4815,7 @@ btr_copy_externally_stored_field_prefix_low( space_id, page_no, offset); inflateEnd(&d_stream); mem_heap_free(heap); + UNIV_MEM_ASSERT_RW(buf, d_stream.total_out); return(d_stream.total_out); } else { return(btr_copy_blob_prefix(buf, len, space_id, diff --git a/storage/innobase/btr/btr0pcur.c b/storage/innobase/btr/btr0pcur.c index ec98692c35b..658901208ef 100644 --- a/storage/innobase/btr/btr0pcur.c +++ b/storage/innobase/btr/btr0pcur.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -205,10 +205,12 @@ record and it can be restored on a user record whose ordering fields are identical to the ones of the original user record */ UNIV_INTERN ibool -btr_pcur_restore_position( -/*======================*/ +btr_pcur_restore_position_func( +/*===========================*/ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */ btr_pcur_t* cursor, /*!< in: detached persistent cursor */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mtr */ { dict_index_t* index; @@ -217,6 +219,9 @@ btr_pcur_restore_position( ulint old_mode; mem_heap_t* heap; + ut_ad(mtr); + ut_ad(mtr->state == MTR_ACTIVE); + index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor)); if (UNIV_UNLIKELY(cursor->old_stored != BTR_PCUR_OLD_STORED) @@ -257,7 +262,8 @@ btr_pcur_restore_position( if (UNIV_LIKELY(buf_page_optimistic_get( latch_mode, cursor->block_when_stored, - cursor->modify_clock, mtr))) { + cursor->modify_clock, + file, line, mtr))) { cursor->pos_state = BTR_PCUR_IS_POSITIONED; buf_block_dbg_add_level(btr_pcur_get_block(cursor), @@ -312,8 +318,8 @@ btr_pcur_restore_position( mode = PAGE_CUR_L; } - btr_pcur_open_with_no_init(index, tuple, mode, latch_mode, - cursor, 0, mtr); + btr_pcur_open_with_no_init_func(index, tuple, mode, latch_mode, + cursor, 0, file, line, mtr); /* Restore the old search mode */ cursor->search_mode = old_mode; @@ -553,8 +559,8 @@ before first in tree. The latching mode must be BTR_SEARCH_LEAF or BTR_MODIFY_LEAF. */ UNIV_INTERN void -btr_pcur_open_on_user_rec( -/*======================*/ +btr_pcur_open_on_user_rec_func( +/*===========================*/ dict_index_t* index, /*!< in: index */ const dtuple_t* tuple, /*!< in: tuple on which search done */ ulint mode, /*!< in: PAGE_CUR_L, ... */ @@ -562,9 +568,12 @@ btr_pcur_open_on_user_rec( BTR_MODIFY_LEAF */ btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mtr */ { - btr_pcur_open(index, tuple, mode, latch_mode, cursor, mtr); + btr_pcur_open_func(index, tuple, mode, latch_mode, cursor, + file, line, mtr); if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) { diff --git a/storage/innobase/btr/btr0sea.c b/storage/innobase/btr/btr0sea.c index ef7afeb1039..98a321bdb80 100644 --- a/storage/innobase/btr/btr0sea.c +++ b/storage/innobase/btr/btr0sea.c @@ -50,6 +50,11 @@ UNIV_INTERN char btr_search_enabled = TRUE; /** Mutex protecting btr_search_enabled */ static mutex_t btr_search_enabled_mutex; +#ifdef UNIV_PFS_MUTEX +/* Key to register btr_search_enabled_mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t btr_search_enabled_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + /** A dummy variable to fool the compiler */ UNIV_INTERN ulint btr_search_this_is_zero = 0; @@ -82,6 +87,11 @@ UNIV_INTERN byte btr_sea_pad2[64]; /** The adaptive hash index */ UNIV_INTERN btr_search_sys_t* btr_search_sys; +#ifdef UNIV_PFS_RWLOCK +/* Key to register btr_search_sys with performance schema */ +UNIV_INTERN mysql_pfs_key_t btr_search_latch_key; +#endif /* UNIV_PFS_RWLOCK */ + /** If the number of records on the page divided by this parameter would have been successfully accessed using a hash index, the index is then built on the page, assuming the global limit has been reached */ @@ -140,7 +150,7 @@ btr_search_check_free_space_in_heap(void) be enough free space in the hash table. */ if (heap->free_block == NULL) { - buf_block_t* block = buf_block_alloc(0); + buf_block_t* block = buf_block_alloc(NULL, 0); rw_lock_x_lock(&btr_search_latch); @@ -167,8 +177,10 @@ btr_search_sys_create( btr_search_latch_temp = mem_alloc(sizeof(rw_lock_t)); - rw_lock_create(&btr_search_latch, SYNC_SEARCH_SYS); - mutex_create(&btr_search_enabled_mutex, SYNC_SEARCH_SYS_CONF); + rw_lock_create(btr_search_latch_key, &btr_search_latch, + SYNC_SEARCH_SYS); + mutex_create(btr_search_enabled_mutex_key, + &btr_search_enabled_mutex, SYNC_SEARCH_SYS_CONF); btr_search_sys = mem_alloc(sizeof(btr_search_sys_t)); @@ -182,6 +194,7 @@ void btr_search_sys_free(void) /*=====================*/ { + rw_lock_free(&btr_search_latch); mem_free(btr_search_latch_temp); btr_search_latch_temp = NULL; mem_heap_free(btr_search_sys->hash_index->heap); @@ -813,6 +826,7 @@ btr_search_guess_on_hash( RW_S_LATCH, RW_X_LATCH, or 0 */ mtr_t* mtr) /*!< in: mtr */ { + buf_pool_t* buf_pool; buf_block_t* block; rec_t* rec; ulint fold; @@ -971,7 +985,7 @@ btr_search_guess_on_hash( /* Increment the page get statistics though we did not really fix the page: for user info only */ - + buf_pool = buf_pool_from_bpage(&block->page); buf_pool->stat.n_page_gets++; return(TRUE); @@ -1748,7 +1762,7 @@ btr_search_validate(void) rec_offs_init(offsets_); rw_lock_x_lock(&btr_search_latch); - buf_pool_mutex_enter(); + buf_pool_mutex_enter_all(); cell_count = hash_get_n_cells(btr_search_sys->hash_index); @@ -1756,11 +1770,11 @@ btr_search_validate(void) /* We release btr_search_latch every once in a while to give other queries a chance to run. */ if ((i != 0) && ((i % chunk_size) == 0)) { - buf_pool_mutex_exit(); + buf_pool_mutex_exit_all(); rw_lock_x_unlock(&btr_search_latch); os_thread_yield(); rw_lock_x_lock(&btr_search_latch); - buf_pool_mutex_enter(); + buf_pool_mutex_enter_all(); } node = hash_get_nth_cell(btr_search_sys->hash_index, i)->node; @@ -1769,6 +1783,9 @@ btr_search_validate(void) const buf_block_t* block = buf_block_align(node->data); const buf_block_t* hash_block; + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_bpage((buf_page_t*) block); if (UNIV_LIKELY(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE)) { @@ -1779,6 +1796,7 @@ btr_search_validate(void) (BUF_BLOCK_REMOVE_HASH, see the assertion and the comment below) */ hash_block = buf_block_hash_get( + buf_pool, buf_block_get_space(block), buf_block_get_page_no(block)); } else { @@ -1867,11 +1885,11 @@ btr_search_validate(void) /* We release btr_search_latch every once in a while to give other queries a chance to run. */ if (i != 0) { - buf_pool_mutex_exit(); + buf_pool_mutex_exit_all(); rw_lock_x_unlock(&btr_search_latch); os_thread_yield(); rw_lock_x_lock(&btr_search_latch); - buf_pool_mutex_enter(); + buf_pool_mutex_enter_all(); } if (!ha_validate(btr_search_sys->hash_index, i, end_index)) { @@ -1879,7 +1897,7 @@ btr_search_validate(void) } } - buf_pool_mutex_exit(); + buf_pool_mutex_exit_all(); rw_lock_x_unlock(&btr_search_latch); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); diff --git a/storage/innobase/buf/buf0buddy.c b/storage/innobase/buf/buf0buddy.c index f0e1395c307..5dc0780cbdd 100644 --- a/storage/innobase/buf/buf0buddy.c +++ b/storage/innobase/buf/buf0buddy.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 2006, 2010, Innobase Oy. All Rights Reserved. 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 @@ -34,17 +34,6 @@ Created December 2006 by Marko Makela #include "buf0flu.h" #include "page0zip.h" -/* Statistic counters */ - -#ifdef UNIV_DEBUG -/** Number of frames allocated from the buffer pool to the buddy system. -Protected by buf_pool_mutex. */ -static ulint buf_buddy_n_frames; -#endif /* UNIV_DEBUG */ -/** Statistics of the buddy system, indexed by block size. -Protected by buf_pool_mutex. */ -UNIV_INTERN buf_buddy_stat_t buf_buddy_stat[BUF_BUDDY_SIZES + 1]; - /**********************************************************************//** Get the offset of the buddy of a compressed page frame. @return the buddy relative of page */ @@ -73,8 +62,10 @@ UNIV_INLINE void buf_buddy_add_to_free( /*==================*/ - buf_page_t* bpage, /*!< in,own: block to be freed */ - ulint i) /*!< in: index of buf_pool->zip_free[] */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + buf_page_t* bpage, /*!< in,own: block to be freed */ + ulint i) /*!< in: index of + buf_pool->zip_free[] */ { #ifdef UNIV_DEBUG_VALGRIND buf_page_t* b = UT_LIST_GET_FIRST(buf_pool->zip_free[i]); @@ -82,7 +73,7 @@ buf_buddy_add_to_free( if (b) UNIV_MEM_VALID(b, BUF_BUDDY_LOW << i); #endif /* UNIV_DEBUG_VALGRIND */ - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE); ut_ad(buf_pool->zip_free[i].start != bpage); UT_LIST_ADD_FIRST(list, buf_pool->zip_free[i], bpage); @@ -99,8 +90,10 @@ UNIV_INLINE void buf_buddy_remove_from_free( /*=======================*/ - buf_page_t* bpage, /*!< in: block to be removed */ - ulint i) /*!< in: index of buf_pool->zip_free[] */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + buf_page_t* bpage, /*!< in: block to be removed */ + ulint i) /*!< in: index of + buf_pool->zip_free[] */ { #ifdef UNIV_DEBUG_VALGRIND buf_page_t* prev = UT_LIST_GET_PREV(list, bpage); @@ -113,7 +106,7 @@ buf_buddy_remove_from_free( ut_ad(!next || buf_page_get_state(next) == BUF_BLOCK_ZIP_FREE); #endif /* UNIV_DEBUG_VALGRIND */ - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE); UT_LIST_REMOVE(list, buf_pool->zip_free[i], bpage); @@ -130,11 +123,12 @@ static void* buf_buddy_alloc_zip( /*================*/ - ulint i) /*!< in: index of buf_pool->zip_free[] */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint i) /*!< in: index of buf_pool->zip_free[] */ { buf_page_t* bpage; - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_a(i < BUF_BUDDY_SIZES); #ifndef UNIV_DEBUG_VALGRIND @@ -149,19 +143,19 @@ buf_buddy_alloc_zip( UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i); ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE); - buf_buddy_remove_from_free(bpage, i); + buf_buddy_remove_from_free(buf_pool, bpage, i); } else if (i + 1 < BUF_BUDDY_SIZES) { /* Attempt to split. */ - bpage = buf_buddy_alloc_zip(i + 1); + bpage = buf_buddy_alloc_zip(buf_pool, i + 1); if (bpage) { buf_page_t* buddy = (buf_page_t*) (((char*) bpage) + (BUF_BUDDY_LOW << i)); - ut_ad(!buf_pool_contains_zip(buddy)); + ut_ad(!buf_pool_contains_zip(buf_pool, buddy)); ut_d(memset(buddy, i, BUF_BUDDY_LOW << i)); buddy->state = BUF_BLOCK_ZIP_FREE; - buf_buddy_add_to_free(buddy, i); + buf_buddy_add_to_free(buf_pool, buddy, i); } } @@ -182,14 +176,15 @@ static void buf_buddy_block_free( /*=================*/ - void* buf) /*!< in: buffer frame to deallocate */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + void* buf) /*!< in: buffer frame to deallocate */ { const ulint fold = BUF_POOL_ZIP_FOLD_PTR(buf); buf_page_t* bpage; buf_block_t* block; - ut_ad(buf_pool_mutex_own()); - ut_ad(!mutex_own(&buf_pool_zip_mutex)); + ut_ad(buf_pool_mutex_own(buf_pool)); + ut_ad(!mutex_own(&buf_pool->zip_mutex)); ut_a(!ut_align_offset(buf, UNIV_PAGE_SIZE)); HASH_SEARCH(hash, buf_pool->zip_hash, fold, buf_page_t*, bpage, @@ -211,8 +206,8 @@ buf_buddy_block_free( buf_LRU_block_free_non_file_page(block); mutex_exit(&block->mutex); - ut_ad(buf_buddy_n_frames > 0); - ut_d(buf_buddy_n_frames--); + ut_ad(buf_pool->buddy_n_frames > 0); + ut_d(buf_pool->buddy_n_frames--); } /**********************************************************************//** @@ -223,9 +218,10 @@ buf_buddy_block_register( /*=====================*/ buf_block_t* block) /*!< in: buffer frame to allocate */ { + buf_pool_t* buf_pool = buf_pool_from_block(block); const ulint fold = BUF_POOL_ZIP_FOLD(block); - ut_ad(buf_pool_mutex_own()); - ut_ad(!mutex_own(&buf_pool_zip_mutex)); + ut_ad(buf_pool_mutex_own(buf_pool)); + ut_ad(!mutex_own(&buf_pool->zip_mutex)); ut_ad(buf_block_get_state(block) == BUF_BLOCK_READY_FOR_USE); buf_block_set_state(block, BUF_BLOCK_MEMORY); @@ -238,7 +234,7 @@ buf_buddy_block_register( ut_d(block->page.in_zip_hash = TRUE); HASH_INSERT(buf_page_t, hash, buf_pool->zip_hash, fold, &block->page); - ut_d(buf_buddy_n_frames++); + ut_d(buf_pool->buddy_n_frames++); } /**********************************************************************//** @@ -248,10 +244,12 @@ static void* buf_buddy_alloc_from( /*=================*/ - void* buf, /*!< in: a block that is free to use */ - ulint i, /*!< in: index of buf_pool->zip_free[] */ - ulint j) /*!< in: size of buf as an index - of buf_pool->zip_free[] */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + void* buf, /*!< in: a block that is free to use */ + ulint i, /*!< in: index of + buf_pool->zip_free[] */ + ulint j) /*!< in: size of buf as an index + of buf_pool->zip_free[] */ { ulint offs = BUF_BUDDY_LOW << j; ut_ad(j <= BUF_BUDDY_SIZES); @@ -275,7 +273,7 @@ buf_buddy_alloc_from( ut_list_node_313) == BUF_BLOCK_ZIP_FREE))); #endif /* !UNIV_DEBUG_VALGRIND */ - buf_buddy_add_to_free(bpage, j); + buf_buddy_add_to_free(buf_pool, bpage, j); } return(buf); @@ -283,37 +281,39 @@ buf_buddy_alloc_from( /**********************************************************************//** Allocate a block. The thread calling this function must hold -buf_pool_mutex and must not hold buf_pool_zip_mutex or any block->mutex. -The buf_pool_mutex may only be released and reacquired if lru != NULL. +buf_pool->mutex and must not hold buf_pool_zip_mutex or any block->mutex. +The buf_pool->mutex may only be released and reacquired if lru != NULL. @return allocated block, possibly NULL if lru==NULL */ UNIV_INTERN void* buf_buddy_alloc_low( /*================*/ - ulint i, /*!< in: index of buf_pool->zip_free[], - or BUF_BUDDY_SIZES */ - ibool* lru) /*!< in: pointer to a variable that will be assigned - TRUE if storage was allocated from the LRU list - and buf_pool_mutex was temporarily released, - or NULL if the LRU list should not be used */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint i, /*!< in: index of buf_pool->zip_free[], + or BUF_BUDDY_SIZES */ + ibool* lru) /*!< in: pointer to a variable that + will be assigned TRUE if storage was + allocated from the LRU list and + buf_pool->mutex was temporarily + released, or NULL if the LRU list + should not be used */ { buf_block_t* block; - ut_ad(buf_pool_mutex_own()); - ut_ad(!mutex_own(&buf_pool_zip_mutex)); + ut_ad(buf_pool_mutex_own(buf_pool)); + ut_ad(!mutex_own(&buf_pool->zip_mutex)); if (i < BUF_BUDDY_SIZES) { /* Try to allocate from the buddy system. */ - block = buf_buddy_alloc_zip(i); + block = buf_buddy_alloc_zip(buf_pool, i); if (block) { - goto func_exit; } } /* Try allocating from the buf_pool->free list. */ - block = buf_LRU_get_free_only(); + block = buf_LRU_get_free_only(buf_pool); if (block) { @@ -326,18 +326,19 @@ buf_buddy_alloc_low( } /* Try replacing an uncompressed page in the buffer pool. */ - buf_pool_mutex_exit(); - block = buf_LRU_get_free_block(0); + buf_pool_mutex_exit(buf_pool); + block = buf_LRU_get_free_block(buf_pool, 0); *lru = TRUE; - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); alloc_big: buf_buddy_block_register(block); - block = buf_buddy_alloc_from(block->frame, i, BUF_BUDDY_SIZES); + block = buf_buddy_alloc_from( + buf_pool, block->frame, i, BUF_BUDDY_SIZES); func_exit: - buf_buddy_stat[i].used++; + buf_pool->buddy_stat[i].used++; return(block); } @@ -352,8 +353,9 @@ buf_buddy_relocate_block( buf_page_t* dpage) /*!< in: free block to relocate to */ { buf_page_t* b; + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); switch (buf_page_get_state(bpage)) { case BUF_BLOCK_ZIP_FREE: @@ -371,10 +373,10 @@ buf_buddy_relocate_block( break; } - mutex_enter(&buf_pool_zip_mutex); + mutex_enter(&buf_pool->zip_mutex); if (!buf_page_can_relocate(bpage)) { - mutex_exit(&buf_pool_zip_mutex); + mutex_exit(&buf_pool->zip_mutex); return(FALSE); } @@ -391,7 +393,9 @@ buf_buddy_relocate_block( UT_LIST_ADD_FIRST(list, buf_pool->zip_clean, dpage); } - mutex_exit(&buf_pool_zip_mutex); + UNIV_MEM_INVALID(bpage, sizeof *bpage); + + mutex_exit(&buf_pool->zip_mutex); return(TRUE); } @@ -402,16 +406,18 @@ static ibool buf_buddy_relocate( /*===============*/ - void* src, /*!< in: block to relocate */ - void* dst, /*!< in: free block to relocate to */ - ulint i) /*!< in: index of buf_pool->zip_free[] */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + void* src, /*!< in: block to relocate */ + void* dst, /*!< in: free block to relocate to */ + ulint i) /*!< in: index of + buf_pool->zip_free[] */ { buf_page_t* bpage; const ulint size = BUF_BUDDY_LOW << i; ullint usec = ut_time_us(NULL); - ut_ad(buf_pool_mutex_own()); - ut_ad(!mutex_own(&buf_pool_zip_mutex)); + ut_ad(buf_pool_mutex_own(buf_pool)); + ut_ad(!mutex_own(&buf_pool->zip_mutex)); ut_ad(!ut_align_offset(src, size)); ut_ad(!ut_align_offset(dst, size)); UNIV_MEM_ASSERT_W(dst, size); @@ -440,11 +446,15 @@ buf_buddy_relocate( pool), so there is nothing wrong about this. The mach_read_from_4() calls here will only trigger bogus Valgrind memcheck warnings in UNIV_DEBUG_VALGRIND builds. */ - bpage = buf_page_hash_get( - mach_read_from_4((const byte*) src - + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID), - mach_read_from_4((const byte*) src - + FIL_PAGE_OFFSET)); + ulint space = mach_read_from_4( + (const byte*) src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID); + ulint page_no = mach_read_from_4( + (const byte*) src + FIL_PAGE_OFFSET); + /* Suppress Valgrind warnings about conditional jump + on uninitialized value. */ + UNIV_MEM_VALID(&space, sizeof space); + UNIV_MEM_VALID(&page_no, sizeof page_no); + bpage = buf_page_hash_get(buf_pool, space, page_no); if (!bpage || bpage->zip.data != src) { /* The block has probably been freshly @@ -455,6 +465,8 @@ buf_buddy_relocate( return(FALSE); } + ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage)); + if (page_zip_get_size(&bpage->zip) != size) { /* The block is of different size. We would have to relocate all blocks covered by src. @@ -482,7 +494,7 @@ success: UNIV_MEM_INVALID(src, size); { buf_buddy_stat_t* buddy_stat - = &buf_buddy_stat[i]; + = &buf_pool->buddy_stat[i]; buddy_stat->relocated++; buddy_stat->relocated_usec += ut_time_us(NULL) - usec; @@ -493,7 +505,12 @@ success: mutex_exit(mutex); } else if (i == buf_buddy_get_slot(sizeof(buf_page_t))) { /* This must be a buf_page_t object. */ +#if UNIV_WORD_SIZE == 4 + /* On 32-bit systems, there is no padding in + buf_page_t. On other systems, Valgrind could complain + about uninitialized pad bytes. */ UNIV_MEM_ASSERT_RW(src, size); +#endif if (buf_buddy_relocate_block(src, dst)) { goto success; @@ -509,32 +526,33 @@ UNIV_INTERN void buf_buddy_free_low( /*===============*/ - void* buf, /*!< in: block to be freed, must not be - pointed to by the buffer pool */ - ulint i) /*!< in: index of buf_pool->zip_free[], - or BUF_BUDDY_SIZES */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + void* buf, /*!< in: block to be freed, must not be + pointed to by the buffer pool */ + ulint i) /*!< in: index of buf_pool->zip_free[], + or BUF_BUDDY_SIZES */ { buf_page_t* bpage; buf_page_t* buddy; - ut_ad(buf_pool_mutex_own()); - ut_ad(!mutex_own(&buf_pool_zip_mutex)); + ut_ad(buf_pool_mutex_own(buf_pool)); + ut_ad(!mutex_own(&buf_pool->zip_mutex)); ut_ad(i <= BUF_BUDDY_SIZES); - ut_ad(buf_buddy_stat[i].used > 0); + ut_ad(buf_pool->buddy_stat[i].used > 0); - buf_buddy_stat[i].used--; + buf_pool->buddy_stat[i].used--; recombine: UNIV_MEM_ASSERT_AND_ALLOC(buf, BUF_BUDDY_LOW << i); ut_d(((buf_page_t*) buf)->state = BUF_BLOCK_ZIP_FREE); if (i == BUF_BUDDY_SIZES) { - buf_buddy_block_free(buf); + buf_buddy_block_free(buf_pool, buf); return; } ut_ad(i < BUF_BUDDY_SIZES); ut_ad(buf == ut_align_down(buf, BUF_BUDDY_LOW << i)); - ut_ad(!buf_pool_contains_zip(buf)); + ut_ad(!buf_pool_contains_zip(buf_pool, buf)); /* Try to combine adjacent blocks. */ @@ -560,10 +578,10 @@ recombine: if (bpage == buddy) { buddy_free: /* The buddy is free: recombine */ - buf_buddy_remove_from_free(bpage, i); + buf_buddy_remove_from_free(buf_pool, bpage, i); buddy_free2: ut_ad(buf_page_get_state(buddy) == BUF_BLOCK_ZIP_FREE); - ut_ad(!buf_pool_contains_zip(buddy)); + ut_ad(!buf_pool_contains_zip(buf_pool, buddy)); i++; buf = ut_align_down(buf, BUF_BUDDY_LOW << i); @@ -595,16 +613,16 @@ buddy_nonfree: buf_buddy_relocate() will overwrite bpage->list. */ UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i); - buf_buddy_remove_from_free(bpage, i); + buf_buddy_remove_from_free(buf_pool, bpage, i); /* Try to relocate the buddy of buf to the free block. */ - if (buf_buddy_relocate(buddy, bpage, i)) { + if (buf_buddy_relocate(buf_pool, buddy, bpage, i)) { ut_d(buddy->state = BUF_BLOCK_ZIP_FREE); goto buddy_free2; } - buf_buddy_add_to_free(bpage, i); + buf_buddy_add_to_free(buf_pool, bpage, i); /* Try to relocate the buddy of the free block to buf. */ buddy = (buf_page_t*) buf_buddy_get(((byte*) bpage), @@ -625,7 +643,7 @@ buddy_nonfree: && ut_list_node_313 != buddy))); #endif /* !UNIV_DEBUG_VALGRIND */ - if (buf_buddy_relocate(buddy, buf, i)) { + if (buf_buddy_relocate(buf_pool, buddy, buf, i)) { buf = bpage; UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i); @@ -688,5 +706,5 @@ buddy_nonfree: } #endif /* UNIV_DEBUG */ bpage->state = BUF_BLOCK_ZIP_FREE; - buf_buddy_add_to_free(bpage, i); + buf_buddy_add_to_free(buf_pool, bpage, i); } diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 111d396fbc5..ae228732270 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -84,21 +84,21 @@ in the file along with the file page, resides in the control block. The buffer buf_pool contains a single mutex which protects all the control data structures of the buf_pool. The content of a buffer frame is protected by a separate read-write lock in its control block, though. -These locks can be locked and unlocked without owning the buf_pool mutex. +These locks can be locked and unlocked without owning the buf_pool->mutex. The OS events in the buf_pool struct can be waited for without owning the -buf_pool mutex. +buf_pool->mutex. -The buf_pool mutex is a hot-spot in main memory, causing a lot of +The buf_pool->mutex is a hot-spot in main memory, causing a lot of memory bus traffic on multiprocessor systems when processors alternately access the mutex. On our Pentium, the mutex is accessed maybe every 10 microseconds. We gave up the solution to have mutexes for each control block, for instance, because it seemed to be complicated. -A solution to reduce mutex contention of the buf_pool mutex is to +A solution to reduce mutex contention of the buf_pool->mutex is to create a separate mutex for the page hash table. On Pentium, accessing the hash table takes 2 microseconds, about half -of the total buf_pool mutex hold time. +of the total buf_pool->mutex hold time. Control blocks -------------- @@ -153,12 +153,12 @@ list. We also keep a pointer to near the end of the LRU list, which we can use when we want to artificially age a page in the buf_pool. This is used if we know that some page is not needed again for some time: we insert the block right after the pointer, -causing it to be replaced sooner than would noramlly be the case. +causing it to be replaced sooner than would normally be the case. Currently this aging mechanism is used for read-ahead mechanism of pages, and it can also be used when there is a scan of a full table which cannot fit in the memory. Putting the pages near the -of the LRU list, we make sure that most of the buf_pool stays in the -main memory, undisturbed. +end of the LRU list, we make sure that most of the buf_pool stays +in the main memory, undisturbed. The unzip_LRU list contains a subset of the common LRU list. The blocks on the unzip_LRU list hold a compressed file page and the @@ -172,6 +172,7 @@ The chain of modified blocks (buf_pool->flush_list) contains the blocks holding file pages that have been modified in the memory but not written to disk yet. The block with the oldest modification which has not yet been written to disk is at the end of the chain. +The access to this list is protected by flush_list_mutex. The chain of unmodified compressed blocks (buf_pool->zip_clean) contains the control blocks (buf_page_t) of those compressed pages @@ -242,24 +243,16 @@ the read requests for the whole area. #ifndef UNIV_HOTBACKUP /** Value in microseconds */ static const int WAIT_FOR_READ = 5000; +/** Number of attemtps made to read in a page in the buffer pool */ +static const ulint BUF_PAGE_READ_MAX_RETRIES = 100; /** The buffer buf_pool of the database */ -UNIV_INTERN buf_pool_t* buf_pool = NULL; - -/** mutex protecting the buffer pool struct and control blocks, except the -read-write lock in them */ -UNIV_INTERN mutex_t buf_pool_mutex; -/** mutex protecting the control blocks of compressed-only pages -(of type buf_page_t, not buf_block_t) */ -UNIV_INTERN mutex_t buf_pool_zip_mutex; +UNIV_INTERN buf_pool_t* buf_pool_ptr[MAX_BUFFER_POOLS]; #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG static ulint buf_dbg_counter = 0; /*!< This is used to insert validation - operations in excution in the + operations in execution in the debug version */ -/** Flag to forbid the release of the buffer pool mutex. -Protected by buf_pool_mutex. */ -UNIV_INTERN ulint buf_pool_mutex_exit_forbidden = 0; #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ #ifdef UNIV_DEBUG /** If this is set TRUE, the program prints info whenever @@ -267,6 +260,40 @@ read-ahead or flush occurs */ UNIV_INTERN ibool buf_debug_prints = FALSE; #endif /* UNIV_DEBUG */ +#ifdef UNIV_PFS_RWLOCK +/* Keys to register buffer block related rwlocks and mutexes with +performance schema */ +UNIV_INTERN mysql_pfs_key_t buf_block_lock_key; +# ifdef UNIV_SYNC_DEBUG +UNIV_INTERN mysql_pfs_key_t buf_block_debug_latch_key; +# endif /* UNIV_SYNC_DEBUG */ +#endif /* UNIV_PFS_RWLOCK */ + +#ifdef UNIV_PFS_MUTEX +UNIV_INTERN mysql_pfs_key_t buffer_block_mutex_key; +UNIV_INTERN mysql_pfs_key_t buf_pool_mutex_key; +UNIV_INTERN mysql_pfs_key_t buf_pool_zip_mutex_key; +UNIV_INTERN mysql_pfs_key_t flush_list_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + +#if defined UNIV_PFS_MUTEX || defined UNIV_PFS_RWLOCK +# ifndef PFS_SKIP_BUFFER_MUTEX_RWLOCK + +/* Buffer block mutexes and rwlocks can be registered +in one group rather than individually. If PFS_GROUP_BUFFER_SYNC +is defined, register buffer block mutex and rwlock +in one group after their initialization. */ +# define PFS_GROUP_BUFFER_SYNC + +/* This define caps the number of mutexes/rwlocks can +be registered with performance schema. Developers can +modify this define if necessary. Please note, this would +be effective only if PFS_GROUP_BUFFER_SYNC is defined. */ +# define PFS_MAX_BUFFER_MUTEX_LOCK_REGISTER ULINT_MAX + +# endif /* !PFS_SKIP_BUFFER_MUTEX_RWLOCK */ +#endif /* UNIV_PFS_MUTEX || UNIV_PFS_RWLOCK */ + /** A chunk of buffers. The buffer pool is allocated in chunks. */ struct buf_chunk_struct{ ulint mem_size; /*!< allocated size of the chunk */ @@ -278,6 +305,140 @@ struct buf_chunk_struct{ #endif /* !UNIV_HOTBACKUP */ /********************************************************************//** +Gets the smallest oldest_modification lsn for any page in the pool. Returns +zero if all modified pages have been flushed to disk. +@return oldest modification in pool, zero if none */ +UNIV_INTERN +ib_uint64_t +buf_pool_get_oldest_modification(void) +/*==================================*/ +{ + ulint i; + buf_page_t* bpage; + ib_uint64_t lsn = 0; + ib_uint64_t oldest_lsn = 0; + + /* When we traverse all the flush lists we don't want another + thread to add a dirty page to any flush list. */ + log_flush_order_mutex_enter(); + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + buf_flush_list_mutex_enter(buf_pool); + + bpage = UT_LIST_GET_LAST(buf_pool->flush_list); + + if (bpage != NULL) { + ut_ad(bpage->in_flush_list); + lsn = bpage->oldest_modification; + } + + buf_flush_list_mutex_exit(buf_pool); + + if (!oldest_lsn || oldest_lsn > lsn) { + oldest_lsn = lsn; + } + } + + log_flush_order_mutex_exit(); + + /* The returned answer may be out of date: the flush_list can + change after the mutex has been released. */ + + return(oldest_lsn); +} + +/********************************************************************//** +Get total buffer pool statistics. */ +UNIV_INTERN +void +buf_get_total_list_len( +/*===================*/ + ulint* LRU_len, /*!< out: length of all LRU lists */ + ulint* free_len, /*!< out: length of all free lists */ + ulint* flush_list_len) /*!< out: length of all flush lists */ +{ + ulint i; + + *LRU_len = 0; + *free_len = 0; + *flush_list_len = 0; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + *LRU_len += UT_LIST_GET_LEN(buf_pool->LRU); + *free_len += UT_LIST_GET_LEN(buf_pool->free); + *flush_list_len += UT_LIST_GET_LEN(buf_pool->flush_list); + } +} + +/********************************************************************//** +Get total buffer pool statistics. */ +UNIV_INTERN +void +buf_get_total_stat( +/*===============*/ + buf_pool_stat_t* tot_stat) /*!< out: buffer pool stats */ +{ + ulint i; + + memset(tot_stat, 0, sizeof(*tot_stat)); + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_stat_t*buf_stat; + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + buf_stat = &buf_pool->stat; + tot_stat->n_page_gets += buf_stat->n_page_gets; + tot_stat->n_pages_read += buf_stat->n_pages_read; + tot_stat->n_pages_written += buf_stat->n_pages_written; + tot_stat->n_pages_created += buf_stat->n_pages_created; + tot_stat->n_ra_pages_read += buf_stat->n_ra_pages_read; + tot_stat->n_ra_pages_evicted += buf_stat->n_ra_pages_evicted; + tot_stat->n_pages_made_young += buf_stat->n_pages_made_young; + + tot_stat->n_pages_not_made_young += + buf_stat->n_pages_not_made_young; + } +} + +/********************************************************************//** +Allocates a buffer block. +@return own: the allocated block, in state BUF_BLOCK_MEMORY */ +UNIV_INTERN +buf_block_t* +buf_block_alloc( +/*============*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint zip_size) /*!< in: compressed page size in bytes, + or 0 if uncompressed tablespace */ +{ + buf_block_t* block; + ulint index; + static ulint buf_pool_index; + + if (buf_pool == NULL) { + /* We are allocating memory from any buffer pool, ensure + we spread the grace on all buffer pool instances. */ + index = buf_pool_index++ % srv_buf_pool_instances; + buf_pool = buf_pool_from_array(index); + } + + block = buf_LRU_get_free_block(buf_pool, zip_size); + + buf_block_set_state(block, BUF_BLOCK_MEMORY); + + return(block); +} + +/********************************************************************//** Calculates a page checksum which is stored to the page when it is written to a file. Note that we must be careful to calculate the same value on 32-bit and 64-bit architectures. @@ -636,19 +797,68 @@ buf_page_print( } #ifndef UNIV_HOTBACKUP + +# ifdef PFS_GROUP_BUFFER_SYNC +/********************************************************************//** +This function registers mutexes and rwlocks in buffer blocks with +performance schema. If PFS_MAX_BUFFER_MUTEX_LOCK_REGISTER is +defined to be a value less than chunk->size, then only mutexes +and rwlocks in the first PFS_MAX_BUFFER_MUTEX_LOCK_REGISTER +blocks are registered. */ +static +void +pfs_register_buffer_block( +/*======================*/ + buf_chunk_t* chunk) /*!< in/out: chunk of buffers */ +{ + ulint i; + ulint num_to_register; + buf_block_t* block; + + block = chunk->blocks; + + num_to_register = ut_min(chunk->size, + PFS_MAX_BUFFER_MUTEX_LOCK_REGISTER); + + for (i = 0; i < num_to_register; i++) { + mutex_t* mutex; + rw_lock_t* rwlock; + +# ifdef UNIV_PFS_MUTEX + mutex = &block->mutex; + ut_a(!mutex->pfs_psi); + mutex->pfs_psi = (PSI_server) + ? PSI_server->init_mutex(buffer_block_mutex_key, mutex) + : NULL; +# endif /* UNIV_PFS_MUTEX */ + +# ifdef UNIV_PFS_RWLOCK + rwlock = &block->lock; + ut_a(!rwlock->pfs_psi); + rwlock->pfs_psi = (PSI_server) + ? PSI_server->init_rwlock(buf_block_lock_key, rwlock) + : NULL; +# endif /* UNIV_PFS_RWLOCK */ + block++; + } +} +# endif /* PFS_GROUP_BUFFER_SYNC */ + /********************************************************************//** Initializes a buffer control block when the buf_pool is created. */ static void buf_block_init( /*===========*/ - buf_block_t* block, /*!< in: pointer to control block */ - byte* frame) /*!< in: pointer to buffer frame */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + buf_block_t* block, /*!< in: pointer to control block */ + byte* frame) /*!< in: pointer to buffer frame */ { UNIV_MEM_DESC(frame, UNIV_PAGE_SIZE, block); block->frame = frame; + block->page.buf_pool = buf_pool; block->page.state = BUF_BLOCK_NOT_USED; block->page.buf_fix_count = 0; block->page.io_fix = BUF_IO_NONE; @@ -662,6 +872,8 @@ buf_block_init( block->check_index_page_at_flush = FALSE; block->index = NULL; + block->is_hashed = FALSE; + #ifdef UNIV_DEBUG block->page.in_page_hash = FALSE; block->page.in_zip_hash = FALSE; @@ -675,13 +887,25 @@ buf_block_init( #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ page_zip_des_init(&block->page.zip); - mutex_create(&block->mutex, SYNC_BUF_BLOCK); +#if defined PFS_SKIP_BUFFER_MUTEX_RWLOCK || defined PFS_GROUP_BUFFER_SYNC + /* If PFS_SKIP_BUFFER_MUTEX_RWLOCK is defined, skip registration + of buffer block mutex/rwlock with performance schema. If + PFS_GROUP_BUFFER_SYNC is defined, skip the registration + since buffer block mutex/rwlock will be registered later in + pfs_register_buffer_block() */ + + mutex_create(PFS_NOT_INSTRUMENTED, &block->mutex, SYNC_BUF_BLOCK); + rw_lock_create(PFS_NOT_INSTRUMENTED, &block->lock, SYNC_LEVEL_VARYING); +#else /* PFS_SKIP_BUFFER_MUTEX_RWLOCK || PFS_GROUP_BUFFER_SYNC */ + mutex_create(buffer_block_mutex_key, &block->mutex, SYNC_BUF_BLOCK); + rw_lock_create(buf_block_lock_key, &block->lock, SYNC_LEVEL_VARYING); +#endif /* PFS_SKIP_BUFFER_MUTEX_RWLOCK || PFS_GROUP_BUFFER_SYNC */ - rw_lock_create(&block->lock, SYNC_LEVEL_VARYING); ut_ad(rw_lock_validate(&(block->lock))); #ifdef UNIV_SYNC_DEBUG - rw_lock_create(&block->debug_latch, SYNC_NO_ORDER_CHECK); + rw_lock_create(buf_block_debug_latch_key, + &block->debug_latch, SYNC_NO_ORDER_CHECK); #endif /* UNIV_SYNC_DEBUG */ } @@ -692,6 +916,7 @@ static buf_chunk_t* buf_chunk_init( /*===========*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ buf_chunk_t* chunk, /*!< out: chunk of buffers */ ulint mem_size) /*!< in: requested size in bytes */ { @@ -747,7 +972,7 @@ buf_chunk_init( for (i = chunk->size; i--; ) { - buf_block_init(block, frame); + buf_block_init(buf_pool, block, frame); #ifdef HAVE_purify /* Wipe contents of frame to eliminate a Purify warning */ @@ -755,12 +980,17 @@ buf_chunk_init( #endif /* Add the block to the free list */ UT_LIST_ADD_LAST(list, buf_pool->free, (&block->page)); + ut_d(block->page.in_free_list = TRUE); + ut_ad(buf_pool_from_block(block) == buf_pool); block++; frame += UNIV_PAGE_SIZE; } +#ifdef PFS_GROUP_BUFFER_SYNC + pfs_register_buffer_block(chunk); +#endif return(chunk); } @@ -779,9 +1009,6 @@ buf_chunk_contains_zip( buf_block_t* block; ulint i; - ut_ad(buf_pool); - ut_ad(buf_pool_mutex_own()); - block = chunk->blocks; for (i = chunk->size; i--; block++) { @@ -802,12 +1029,16 @@ UNIV_INTERN buf_block_t* buf_pool_contains_zip( /*==================*/ - const void* data) /*!< in: pointer to compressed page */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + const void* data) /*!< in: pointer to compressed page */ { ulint n; buf_chunk_t* chunk = buf_pool->chunks; + ut_ad(buf_pool); + ut_ad(buf_pool_mutex_own(buf_pool)); for (n = buf_pool->n_chunks; n--; chunk++) { + buf_block_t* block = buf_chunk_contains_zip(chunk, data); if (block) { @@ -831,9 +1062,6 @@ buf_chunk_not_freed( buf_block_t* block; ulint i; - ut_ad(buf_pool); - ut_ad(buf_pool_mutex_own()); - block = chunk->blocks; for (i = chunk->size; i--; block++) { @@ -883,9 +1111,6 @@ buf_chunk_all_free( const buf_block_t* block; ulint i; - ut_ad(buf_pool); - ut_ad(buf_pool_mutex_own()); - block = chunk->blocks; for (i = chunk->size; i--; block++) { @@ -905,12 +1130,13 @@ static void buf_chunk_free( /*===========*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ buf_chunk_t* chunk) /*!< out: chunk of buffers */ { buf_block_t* block; const buf_block_t* block_end; - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); block_end = chunk->blocks + chunk->size; @@ -938,75 +1164,106 @@ buf_chunk_free( } /********************************************************************//** -Creates the buffer pool. -@return own: buf_pool object, NULL if not enough memory or error */ +Set buffer pool size variables after resizing it */ +static +void +buf_pool_set_sizes(void) +/*====================*/ +{ + ulint i; + ulint curr_size = 0; + + buf_pool_mutex_enter_all(); + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + curr_size += buf_pool->curr_pool_size; + } + + srv_buf_pool_curr_size = curr_size; + srv_buf_pool_old_size = srv_buf_pool_size; + + buf_pool_mutex_exit_all(); +} + +/********************************************************************//** +Initialize a buffer pool instance. +@return DB_SUCCESS if all goes well. */ UNIV_INTERN -buf_pool_t* -buf_pool_init(void) -/*===============*/ +ulint +buf_pool_init_instance( +/*===================*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint buf_pool_size, /*!< in: size in bytes */ + ulint instance_no) /*!< in: id of the instance */ { - buf_chunk_t* chunk; ulint i; - - buf_pool = mem_zalloc(sizeof(buf_pool_t)); + buf_chunk_t* chunk; /* 1. Initialize general fields ------------------------------- */ - mutex_create(&buf_pool_mutex, SYNC_BUF_POOL); - mutex_create(&buf_pool_zip_mutex, SYNC_BUF_BLOCK); + mutex_create(buf_pool_mutex_key, + &buf_pool->mutex, SYNC_BUF_POOL); + mutex_create(buf_pool_zip_mutex_key, + &buf_pool->zip_mutex, SYNC_BUF_BLOCK); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); - buf_pool->n_chunks = 1; - buf_pool->chunks = chunk = mem_alloc(sizeof *chunk); + if (buf_pool_size > 0) { + buf_pool->n_chunks = 1; + buf_pool->chunks = chunk = mem_zalloc(sizeof *chunk); - UT_LIST_INIT(buf_pool->free); + UT_LIST_INIT(buf_pool->free); - if (!buf_chunk_init(chunk, srv_buf_pool_size)) { - mem_free(chunk); - mem_free(buf_pool); - buf_pool = NULL; - return(NULL); - } + if (!buf_chunk_init(buf_pool, chunk, buf_pool_size)) { + mem_free(chunk); + mem_free(buf_pool); - srv_buf_pool_old_size = srv_buf_pool_size; - buf_pool->curr_size = chunk->size; - srv_buf_pool_curr_size = buf_pool->curr_size * UNIV_PAGE_SIZE; + buf_pool_mutex_exit(buf_pool); - buf_pool->page_hash = hash_create(2 * buf_pool->curr_size); - buf_pool->zip_hash = hash_create(2 * buf_pool->curr_size); + return(DB_ERROR); + } - buf_pool->last_printout_time = time(NULL); + buf_pool->instance_no = instance_no; + buf_pool->old_pool_size = buf_pool_size; + buf_pool->curr_size = chunk->size; + buf_pool->curr_pool_size = buf_pool->curr_size * UNIV_PAGE_SIZE; + buf_pool->page_hash = hash_create(2 * buf_pool->curr_size); + buf_pool->zip_hash = hash_create(2 * buf_pool->curr_size); + + buf_pool->last_printout_time = ut_time(); + } /* 2. Initialize flushing fields -------------------------------- */ + mutex_create(flush_list_mutex_key, &buf_pool->flush_list_mutex, + SYNC_BUF_FLUSH_LIST); + for (i = BUF_FLUSH_LRU; i < BUF_FLUSH_N_TYPES; i++) { buf_pool->no_flush[i] = os_event_create(NULL); } /* 3. Initialize LRU fields --------------------------- */ - /* All fields are initialized by mem_zalloc(). */ - - buf_pool_mutex_exit(); - btr_search_sys_create(buf_pool->curr_size - * UNIV_PAGE_SIZE / sizeof(void*) / 64); - - /* 4. Initialize the buddy allocator fields */ /* All fields are initialized by mem_zalloc(). */ - return(buf_pool); + buf_pool_mutex_exit(buf_pool); + + return(DB_SUCCESS); } /********************************************************************//** -Frees the buffer pool at shutdown. This must not be invoked before -freeing all mutexes. */ -UNIV_INTERN +free one buffer pool instance */ +static void -buf_pool_free(void) -/*===============*/ +buf_pool_free_instance( +/*===================*/ + buf_pool_t* buf_pool) /* in,own: buffer pool instance + to free */ { buf_chunk_t* chunk; buf_chunk_t* chunks; @@ -1028,6 +1285,139 @@ buf_pool_free(void) } /********************************************************************//** +Creates the buffer pool. +@return DB_SUCCESS if success, DB_ERROR if not enough memory or error */ +UNIV_INTERN +ulint +buf_pool_init( +/*==========*/ + ulint total_size, /*!< in: size of the total pool in bytes */ + ulint n_instances) /*!< in: number of instances */ +{ + ulint i; + + /* We create an extra buffer pool instance, this instance is used + for flushing the flush lists, to keep track of n_flush for all + the buffer pools and also used as a waiting object during flushing. */ + for (i = 0; i < n_instances; i++) { + buf_pool_t* ptr; + ulint size; + + ptr = mem_zalloc(sizeof(*ptr)); + + size = total_size / n_instances; + + buf_pool_ptr[i] = ptr; + + if (buf_pool_init_instance(ptr, size, i) != DB_SUCCESS) { + + mem_free(buf_pool_ptr[i]); + + /* Free all the instances created so far. */ + buf_pool_free(i); + + return(DB_ERROR); + } + } + + buf_pool_set_sizes(); + buf_LRU_old_ratio_update(100 * 3/ 8, FALSE); + + btr_search_sys_create(buf_pool_get_curr_size() / sizeof(void*) / 64); + + return(DB_SUCCESS); +} + +/********************************************************************//** +Frees the buffer pool at shutdown. This must not be invoked before +freeing all mutexes. */ +UNIV_INTERN +void +buf_pool_free( +/*==========*/ + ulint n_instances) /*!< in: numbere of instances to free */ +{ + ulint i; + + for (i = 0; i < n_instances; i++) { + buf_pool_free_instance(buf_pool_from_array(i)); + buf_pool_ptr[i] = NULL; + } +} + +/********************************************************************//** +Drops adaptive hash index for a buffer pool instance. */ +static +void +buf_pool_drop_hash_index_instance( +/*==============================*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ibool* released_search_latch) /*!< out: flag for signalling + whether the search latch was + released */ +{ + buf_chunk_t* chunks = buf_pool->chunks; + buf_chunk_t* chunk = chunks + buf_pool->n_chunks; + + while (--chunk >= chunks) { + ulint i; + buf_block_t* block = chunk->blocks; + + for (i = chunk->size; i--; block++) { + /* block->is_hashed cannot be modified + when we have an x-latch on btr_search_latch; + see the comment in buf0buf.h */ + + if (!block->is_hashed) { + continue; + } + + /* To follow the latching order, we + have to release btr_search_latch + before acquiring block->latch. */ + rw_lock_x_unlock(&btr_search_latch); + /* When we release the search latch, + we must rescan all blocks, because + some may become hashed again. */ + *released_search_latch = TRUE; + + rw_lock_x_lock(&block->lock); + + /* This should be guaranteed by the + callers, which will be holding + btr_search_enabled_mutex. */ + ut_ad(!btr_search_enabled); + + /* Because we did not buffer-fix the + block by calling buf_block_get_gen(), + it is possible that the block has been + allocated for some other use after + btr_search_latch was released above. + We do not care which file page the + block is mapped to. All we want to do + is to drop any hash entries referring + to the page. */ + + /* It is possible that + block->page.state != BUF_FILE_PAGE. + Even that does not matter, because + btr_search_drop_page_hash_index() will + check block->is_hashed before doing + anything. block->is_hashed can only + be set on uncompressed file pages. */ + + btr_search_drop_page_hash_index(block); + + rw_lock_x_unlock(&block->lock); + + rw_lock_x_lock(&btr_search_latch); + + ut_ad(!btr_search_enabled); + } + } +} + +/********************************************************************//** Drops the adaptive hash index. To prevent a livelock, this function is only to be called while holding btr_search_latch and while btr_search_enabled == FALSE. */ @@ -1044,67 +1434,19 @@ buf_pool_drop_hash_index(void) ut_ad(!btr_search_enabled); do { - buf_chunk_t* chunks = buf_pool->chunks; - buf_chunk_t* chunk = chunks + buf_pool->n_chunks; + ulint i; released_search_latch = FALSE; - while (--chunk >= chunks) { - buf_block_t* block = chunk->blocks; - ulint i = chunk->size; + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; - for (; i--; block++) { - /* block->is_hashed cannot be modified - when we have an x-latch on btr_search_latch; - see the comment in buf0buf.h */ - - if (!block->is_hashed) { - continue; - } + buf_pool = buf_pool_from_array(i); - /* To follow the latching order, we - have to release btr_search_latch - before acquiring block->latch. */ - rw_lock_x_unlock(&btr_search_latch); - /* When we release the search latch, - we must rescan all blocks, because - some may become hashed again. */ - released_search_latch = TRUE; - - rw_lock_x_lock(&block->lock); - - /* This should be guaranteed by the - callers, which will be holding - btr_search_enabled_mutex. */ - ut_ad(!btr_search_enabled); - - /* Because we did not buffer-fix the - block by calling buf_block_get_gen(), - it is possible that the block has been - allocated for some other use after - btr_search_latch was released above. - We do not care which file page the - block is mapped to. All we want to do - is to drop any hash entries referring - to the page. */ - - /* It is possible that - block->page.state != BUF_FILE_PAGE. - Even that does not matter, because - btr_search_drop_page_hash_index() will - check block->is_hashed before doing - anything. block->is_hashed can only - be set on uncompressed file pages. */ - - btr_search_drop_page_hash_index(block); - - rw_lock_x_unlock(&block->lock); - - rw_lock_x_lock(&btr_search_latch); - - ut_ad(!btr_search_enabled); - } + buf_pool_drop_hash_index_instance( + buf_pool, &released_search_latch); } + } while (released_search_latch); } @@ -1123,15 +1465,18 @@ buf_relocate( { buf_page_t* b; ulint fold; + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(mutex_own(buf_page_get_mutex(bpage))); ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE); ut_a(bpage->buf_fix_count == 0); ut_ad(bpage->in_LRU_list); ut_ad(!bpage->in_zip_hash); ut_ad(bpage->in_page_hash); - ut_ad(bpage == buf_page_hash_get(bpage->space, bpage->offset)); + ut_ad(bpage == buf_page_hash_get(buf_pool, + bpage->space, bpage->offset)); + ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage)); #ifdef UNIV_DEBUG switch (buf_page_get_state(bpage)) { case BUF_BLOCK_ZIP_FREE: @@ -1187,17 +1532,16 @@ buf_relocate( HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, bpage); HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold, dpage); - - UNIV_MEM_INVALID(bpage, sizeof *bpage); } /********************************************************************//** -Shrinks the buffer pool. */ +Shrinks a buffer pool instance. */ static void -buf_pool_shrink( -/*============*/ - ulint chunk_size) /*!< in: number of pages to remove */ +buf_pool_shrink_instance( +/*=====================*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint chunk_size) /*!< in: number of pages to remove */ { buf_chunk_t* chunks; buf_chunk_t* chunk; @@ -1206,11 +1550,11 @@ buf_pool_shrink( buf_chunk_t* max_chunk; buf_chunk_t* max_free_chunk; - ut_ad(!buf_pool_mutex_own()); + ut_ad(!buf_pool_mutex_own(buf_pool)); try_again: btr_search_disable(); /* Empty the adaptive hash index again */ - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); shrink_again: if (buf_pool->n_chunks <= 1) { @@ -1273,7 +1617,7 @@ shrink_again: mutex_enter(&block->mutex); /* The following calls will temporarily - release block->mutex and buf_pool_mutex. + release block->mutex and buf_pool->mutex. Therefore, we have to always retry, even if !dirty && !nonfree. */ @@ -1289,7 +1633,7 @@ shrink_again: mutex_exit(&block->mutex); } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); /* Request for a flush of the chunk if it helps. Do not flush if there are non-free blocks, since @@ -1298,10 +1642,10 @@ shrink_again: /* Avoid busy-waiting. */ os_thread_sleep(100000); } else if (dirty - && buf_flush_batch(BUF_FLUSH_LRU, dirty, 0) - == ULINT_UNDEFINED) { + && buf_flush_LRU(buf_pool, dirty) + == ULINT_UNDEFINED) { - buf_flush_wait_batch_end(BUF_FLUSH_LRU); + buf_flush_wait_batch_end(buf_pool, BUF_FLUSH_LRU); } goto try_again; @@ -1310,7 +1654,7 @@ shrink_again: max_size = max_free_size; max_chunk = max_free_chunk; - srv_buf_pool_old_size = srv_buf_pool_size; + buf_pool->old_pool_size = buf_pool->curr_pool_size; /* Rewrite buf_pool->chunks. Copy everything but max_chunk. */ chunks = mem_alloc((buf_pool->n_chunks - 1) * sizeof *chunks); @@ -1322,9 +1666,9 @@ shrink_again: - (max_chunk + 1)); ut_a(buf_pool->curr_size > max_chunk->size); buf_pool->curr_size -= max_chunk->size; - srv_buf_pool_curr_size = buf_pool->curr_size * UNIV_PAGE_SIZE; + buf_pool->curr_pool_size = buf_pool->curr_size * UNIV_PAGE_SIZE; chunk_size -= max_chunk->size; - buf_chunk_free(max_chunk); + buf_chunk_free(buf_pool, max_chunk); mem_free(buf_pool->chunks); buf_pool->chunks = chunks; buf_pool->n_chunks--; @@ -1334,29 +1678,53 @@ shrink_again: goto shrink_again; } + goto func_exit; func_done: - srv_buf_pool_old_size = srv_buf_pool_size; + buf_pool->old_pool_size = buf_pool->curr_pool_size; func_exit: - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); btr_search_enable(); } /********************************************************************//** -Rebuild buf_pool->page_hash. */ +Shrinks the buffer pool. */ static void -buf_pool_page_hash_rebuild(void) -/*============================*/ +buf_pool_shrink( +/*============*/ + ulint chunk_size) /*!< in: number of pages to remove */ +{ + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + ulint instance_chunk_size; + + instance_chunk_size = chunk_size / srv_buf_pool_instances; + buf_pool = buf_pool_from_array(i); + buf_pool_shrink_instance(buf_pool, instance_chunk_size); + } + + buf_pool_set_sizes(); +} + +/********************************************************************//** +Rebuild buf_pool->page_hash for a buffer pool instance. */ +static +void +buf_pool_page_hash_rebuild_instance( +/*================================*/ + buf_pool_t* buf_pool) /*!< in: buffer pool instance */ { ulint i; - ulint n_chunks; + buf_page_t* b; buf_chunk_t* chunk; - hash_table_t* page_hash; + ulint n_chunks; hash_table_t* zip_hash; - buf_page_t* b; + hash_table_t* page_hash; - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); /* Free, create, and populate the hash table. */ hash_table_free(buf_pool->page_hash); @@ -1409,6 +1777,7 @@ buf_pool_page_hash_rebuild(void) buf_page_address_fold(b->space, b->offset), b); } + buf_flush_list_mutex_enter(buf_pool); for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b; b = UT_LIST_GET_NEXT(list, b)) { ut_ad(b->in_flush_list); @@ -1436,7 +1805,180 @@ buf_pool_page_hash_rebuild(void) } } - buf_pool_mutex_exit(); + buf_flush_list_mutex_exit(buf_pool); + buf_pool_mutex_exit(buf_pool); +} + +/******************************************************************** +Determine if a block is a sentinel for a buffer pool watch. +@return TRUE if a sentinel for a buffer pool watch, FALSE if not */ +UNIV_INTERN +ibool +buf_pool_watch_is_sentinel( +/*=======================*/ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + const buf_page_t* bpage) /*!< in: block */ +{ + ut_ad(buf_page_in_file(bpage)); + + if (bpage < &buf_pool->watch[0] + || bpage >= &buf_pool->watch[BUF_POOL_WATCH_SIZE]) { + + ut_ad(buf_page_get_state(bpage) != BUF_BLOCK_ZIP_PAGE + || bpage->zip.data != NULL); + + return(FALSE); + } + + ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_PAGE); + ut_ad(!bpage->in_zip_hash); + ut_ad(bpage->in_page_hash); + ut_ad(bpage->zip.data == NULL); + ut_ad(bpage->buf_fix_count > 0); + return(TRUE); +} + +/****************************************************************//** +Add watch for the given page to be read in. Caller must have the buffer pool +mutex reserved. +@return NULL if watch set, block if the page is in the buffer pool */ +UNIV_INTERN +buf_page_t* +buf_pool_watch_set( +/*===============*/ + ulint space, /*!< in: space id */ + ulint offset, /*!< in: page number */ + ulint fold) /*!< in: buf_page_address_fold(space, offset) */ +{ + buf_page_t* bpage; + ulint i; + buf_pool_t* buf_pool = buf_pool_get(space, offset); + + ut_ad(buf_pool_mutex_own(buf_pool)); + + bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); + + if (UNIV_LIKELY_NULL(bpage)) { + if (!buf_pool_watch_is_sentinel(buf_pool, bpage)) { + /* The page was loaded meanwhile. */ + return(bpage); + } + /* Add to an existing watch. */ + bpage->buf_fix_count++; + return(NULL); + } + + for (i = 0; i < BUF_POOL_WATCH_SIZE; i++) { + bpage = &buf_pool->watch[i]; + + ut_ad(bpage->access_time == 0); + ut_ad(bpage->newest_modification == 0); + ut_ad(bpage->oldest_modification == 0); + ut_ad(bpage->zip.data == NULL); + ut_ad(!bpage->in_zip_hash); + + switch (bpage->state) { + case BUF_BLOCK_POOL_WATCH: + ut_ad(!bpage->in_page_hash); + ut_ad(bpage->buf_fix_count == 0); + + /* bpage is pointing to buf_pool_watch[], + which is protected by buf_pool_mutex. + Normally, buf_page_t objects are protected by + buf_block_t::mutex or buf_pool->zip_mutex or both. */ + + bpage->state = BUF_BLOCK_ZIP_PAGE; + bpage->space = space; + bpage->offset = offset; + bpage->buf_fix_count = 1; + + ut_d(bpage->in_page_hash = TRUE); + HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, + fold, bpage); + return(NULL); + case BUF_BLOCK_ZIP_PAGE: + ut_ad(bpage->in_page_hash); + ut_ad(bpage->buf_fix_count > 0); + break; + default: + ut_error; + } + } + + /* Allocation failed. Either the maximum number of purge + threads should never exceed BUF_POOL_WATCH_SIZE, or this code + should be modified to return a special non-NULL value and the + caller should purge the record directly. */ + ut_error; + + /* Fix compiler warning */ + return(NULL); +} + +/********************************************************************//** +Rebuild buf_pool->page_hash. */ +static +void +buf_pool_page_hash_rebuild(void) +/*============================*/ +{ + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_page_hash_rebuild_instance(buf_pool_from_array(i)); + } +} + +/********************************************************************//** +Increase the buffer pool size of one buffer pool instance. */ +static +void +buf_pool_increase_instance( +/*=======================*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instane */ + ulint change_size) /*!< in: new size of the pool */ +{ + buf_chunk_t* chunks; + buf_chunk_t* chunk; + + buf_pool_mutex_enter(buf_pool); + chunks = mem_alloc((buf_pool->n_chunks + 1) * sizeof *chunks); + + memcpy(chunks, buf_pool->chunks, buf_pool->n_chunks * sizeof *chunks); + + chunk = &chunks[buf_pool->n_chunks]; + + if (!buf_chunk_init(buf_pool, chunk, change_size)) { + mem_free(chunks); + } else { + buf_pool->old_pool_size = buf_pool->curr_pool_size; + buf_pool->curr_size += chunk->size; + buf_pool->curr_pool_size = buf_pool->curr_size * UNIV_PAGE_SIZE; + mem_free(buf_pool->chunks); + buf_pool->chunks = chunks; + buf_pool->n_chunks++; + } + + buf_pool_mutex_exit(buf_pool); +} + +/********************************************************************//** +Increase the buffer pool size. */ +static +void +buf_pool_increase( +/*==============*/ + ulint change_size) +{ + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_increase_instance( + buf_pool_from_array(i), + change_size / srv_buf_pool_instances); + } + + buf_pool_set_sizes(); } /********************************************************************//** @@ -1446,54 +1988,137 @@ void buf_pool_resize(void) /*=================*/ { - buf_pool_mutex_enter(); + ulint change_size; + ulint min_change_size = 1048576 * srv_buf_pool_instances; + + buf_pool_mutex_enter_all(); + + if (srv_buf_pool_old_size == srv_buf_pool_size) { + + buf_pool_mutex_exit_all(); + + return; + + } else if (srv_buf_pool_curr_size + min_change_size + > srv_buf_pool_size) { + + change_size = (srv_buf_pool_curr_size - srv_buf_pool_size) + / UNIV_PAGE_SIZE; + + buf_pool_mutex_exit_all(); + + /* Disable adaptive hash indexes and empty the index + in order to free up memory in the buffer pool chunks. */ + buf_pool_shrink(change_size); + + } else if (srv_buf_pool_curr_size + min_change_size + < srv_buf_pool_size) { + + /* Enlarge the buffer pool by at least one megabyte */ + + change_size = srv_buf_pool_size - srv_buf_pool_curr_size; + + buf_pool_mutex_exit_all(); + + buf_pool_increase(change_size); + } else { + srv_buf_pool_size = srv_buf_pool_old_size; - if (srv_buf_pool_old_size == srv_buf_pool_size) { + buf_pool_mutex_exit_all(); - buf_pool_mutex_exit(); return; } + + buf_pool_page_hash_rebuild(); +} + +/****************************************************************//** +Remove the sentinel block for the watch before replacing it with a real block. +buf_page_watch_clear() or buf_page_watch_occurred() will notice that +the block has been replaced with the real block. +@return reference count, to be added to the replacement block */ +static +void +buf_pool_watch_remove( +/*==================*/ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + ulint fold, /*!< in: buf_page_address_fold( + space, offset) */ + buf_page_t* watch) /*!< in/out: sentinel for watch */ +{ + ut_ad(buf_pool_mutex_own(buf_pool)); - if (srv_buf_pool_curr_size + 1048576 > srv_buf_pool_size) { - - buf_pool_mutex_exit(); - - /* Disable adaptive hash indexes and empty the index - in order to free up memory in the buffer pool chunks. */ - buf_pool_shrink((srv_buf_pool_curr_size - srv_buf_pool_size) - / UNIV_PAGE_SIZE); - } else if (srv_buf_pool_curr_size + 1048576 < srv_buf_pool_size) { - - /* Enlarge the buffer pool by at least one megabyte */ + HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, watch); + ut_d(watch->in_page_hash = FALSE); + watch->buf_fix_count = 0; + watch->state = BUF_BLOCK_POOL_WATCH; +} - ulint mem_size - = srv_buf_pool_size - srv_buf_pool_curr_size; - buf_chunk_t* chunks; - buf_chunk_t* chunk; +/****************************************************************//** +Stop watching if the page has been read in. +buf_pool_watch_set(space,offset) must have returned NULL before. */ +UNIV_INTERN +void +buf_pool_watch_unset( +/*=================*/ + ulint space, /*!< in: space id */ + ulint offset) /*!< in: page number */ +{ + buf_page_t* bpage; + buf_pool_t* buf_pool = buf_pool_get(space, offset); + ulint fold = buf_page_address_fold(space, offset); + + buf_pool_mutex_enter(buf_pool); + bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); + /* The page must exist because buf_pool_watch_set() + increments buf_fix_count. */ + ut_a(bpage); + + if (UNIV_UNLIKELY(!buf_pool_watch_is_sentinel(buf_pool, bpage))) { + mutex_t* mutex = buf_page_get_mutex(bpage); + + mutex_enter(mutex); + ut_a(bpage->buf_fix_count > 0); + bpage->buf_fix_count--; + mutex_exit(mutex); + } else { + ut_a(bpage->buf_fix_count > 0); - chunks = mem_alloc((buf_pool->n_chunks + 1) * sizeof *chunks); + if (UNIV_LIKELY(!--bpage->buf_fix_count)) { + buf_pool_watch_remove(buf_pool, fold, bpage); + } + } - memcpy(chunks, buf_pool->chunks, buf_pool->n_chunks - * sizeof *chunks); + buf_pool_mutex_exit(buf_pool); +} - chunk = &chunks[buf_pool->n_chunks]; +/****************************************************************//** +Check if the page has been read in. +This may only be called after buf_pool_watch_set(space,offset) +has returned NULL and before invoking buf_pool_watch_unset(space,offset). +@return FALSE if the given page was not read in, TRUE if it was */ +UNIV_INTERN +ibool +buf_pool_watch_occurred( +/*====================*/ + ulint space, /*!< in: space id */ + ulint offset) /*!< in: page number */ +{ + ibool ret; + buf_page_t* bpage; + buf_pool_t* buf_pool = buf_pool_get(space, offset); + ulint fold = buf_page_address_fold(space, offset); - if (!buf_chunk_init(chunk, mem_size)) { - mem_free(chunks); - } else { - buf_pool->curr_size += chunk->size; - srv_buf_pool_curr_size = buf_pool->curr_size - * UNIV_PAGE_SIZE; - mem_free(buf_pool->chunks); - buf_pool->chunks = chunks; - buf_pool->n_chunks++; - } + buf_pool_mutex_enter(buf_pool); - srv_buf_pool_old_size = srv_buf_pool_size; - buf_pool_mutex_exit(); - } + bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); + /* The page must exist because buf_pool_watch_set() + increments buf_fix_count. */ + ut_a(bpage); + ret = !buf_pool_watch_is_sentinel(buf_pool, bpage); + buf_pool_mutex_exit(buf_pool); - buf_pool_page_hash_rebuild(); + return(ret); } /********************************************************************//** @@ -1506,13 +2131,15 @@ buf_page_make_young( /*================*/ buf_page_t* bpage) /*!< in: buffer block of a file page */ { - buf_pool_mutex_enter(); + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + + buf_pool_mutex_enter(buf_pool); ut_a(buf_page_in_file(bpage)); buf_LRU_make_block_young(bpage); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); } /********************************************************************//** @@ -1530,18 +2157,20 @@ buf_page_set_accessed_make_young( read under mutex protection, or 0 if unknown */ { - ut_ad(!buf_pool_mutex_own()); + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + + ut_ad(!buf_pool_mutex_own(buf_pool)); ut_a(buf_page_in_file(bpage)); if (buf_page_peek_if_too_old(bpage)) { - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); buf_LRU_make_block_young(bpage); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); } else if (!access_time) { ulint time_ms = ut_time_ms(); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); buf_page_set_accessed(bpage, time_ms); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); } } @@ -1556,16 +2185,18 @@ buf_reset_check_index_page_at_flush( ulint offset) /*!< in: page number */ { buf_block_t* block; + buf_pool_t* buf_pool = buf_pool_get(space, offset); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); - block = (buf_block_t*) buf_page_hash_get(space, offset); + block = (buf_block_t*) buf_page_hash_get(buf_pool, space, offset); if (block && buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE) { + ut_ad(!buf_pool_watch_is_sentinel(buf_pool, &block->page)); block->check_index_page_at_flush = FALSE; } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); } /********************************************************************//** @@ -1582,18 +2213,20 @@ buf_page_peek_if_search_hashed( { buf_block_t* block; ibool is_hashed; + buf_pool_t* buf_pool = buf_pool_get(space, offset); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); - block = (buf_block_t*) buf_page_hash_get(space, offset); + block = (buf_block_t*) buf_page_hash_get(buf_pool, space, offset); if (!block || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) { is_hashed = FALSE; } else { + ut_ad(!buf_pool_watch_is_sentinel(buf_pool, &block->page)); is_hashed = block->is_hashed; } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); return(is_hashed); } @@ -1613,16 +2246,18 @@ buf_page_set_file_page_was_freed( ulint offset) /*!< in: page number */ { buf_page_t* bpage; + buf_pool_t* buf_pool = buf_pool_get(space, offset); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); - bpage = buf_page_hash_get(space, offset); + bpage = buf_page_hash_get(buf_pool, space, offset); if (bpage) { + ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage)); bpage->file_page_was_freed = TRUE; } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); return(bpage); } @@ -1641,16 +2276,18 @@ buf_page_reset_file_page_was_freed( ulint offset) /*!< in: page number */ { buf_page_t* bpage; + buf_pool_t* buf_pool = buf_pool_get(space, offset); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); - bpage = buf_page_hash_get(space, offset); + bpage = buf_page_hash_get(buf_pool, space, offset); if (bpage) { + ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage)); bpage->file_page_was_freed = FALSE; } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); return(bpage); } @@ -1677,6 +2314,7 @@ buf_page_get_zip( mutex_t* block_mutex; ibool must_read; unsigned access_time; + buf_pool_t* buf_pool = buf_pool_get(space, offset); #ifndef UNIV_LOG_DEBUG ut_ad(!ibuf_inside()); @@ -1684,16 +2322,17 @@ buf_page_get_zip( buf_pool->stat.n_page_gets++; for (;;) { - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); lookup: - bpage = buf_page_hash_get(space, offset); + bpage = buf_page_hash_get(buf_pool, space, offset); if (bpage) { + ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage)); break; } /* Page not in buf_pool: needs to be read from file */ - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); buf_read_page(space, zip_size, offset); @@ -1705,10 +2344,12 @@ lookup: if (UNIV_UNLIKELY(!bpage->zip.data)) { /* There is no compressed page. */ err_exit: - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); return(NULL); } + ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage)); + switch (buf_page_get_state(bpage)) { case BUF_BLOCK_NOT_USED: case BUF_BLOCK_READY_FOR_USE: @@ -1718,7 +2359,7 @@ err_exit: break; case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_DIRTY: - block_mutex = &buf_pool_zip_mutex; + block_mutex = &buf_pool->zip_mutex; mutex_enter(block_mutex); bpage->buf_fix_count++; goto got_block; @@ -1746,7 +2387,7 @@ got_block: must_read = buf_page_get_io_fix(bpage) == BUF_IO_READ; access_time = buf_page_is_accessed(bpage); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); mutex_exit(block_mutex); @@ -1818,14 +2459,14 @@ buf_zip_decompress( buf_block_t* block, /*!< in/out: block */ ibool check) /*!< in: TRUE=verify the page checksum */ { - const byte* frame = block->page.zip.data; + const byte* frame = block->page.zip.data; + ulint stamp_checksum = mach_read_from_4( + frame + FIL_PAGE_SPACE_OR_CHKSUM); ut_ad(buf_block_get_zip_size(block)); ut_a(buf_block_get_space(block) != 0); - if (UNIV_LIKELY(check)) { - ulint stamp_checksum = mach_read_from_4( - frame + FIL_PAGE_SPACE_OR_CHKSUM); + if (UNIV_LIKELY(check && stamp_checksum != BUF_NO_CHECKSUM_MAGIC)) { ulint calc_checksum = page_zip_calc_checksum( frame, page_zip_get_size(&block->page.zip)); @@ -1876,13 +2517,16 @@ buf_zip_decompress( #ifndef UNIV_HOTBACKUP /*******************************************************************//** -Gets the block to whose frame the pointer is pointing to. -@return pointer to block, never NULL */ +Gets the block to whose frame the pointer is pointing to if found +in this buffer pool instance. +@return pointer to block */ UNIV_INTERN buf_block_t* -buf_block_align( -/*============*/ - const byte* ptr) /*!< in: pointer to a frame */ +buf_block_align_instance( +/*=====================*/ + buf_pool_t* buf_pool, /*!< in: buffer in which the block + resides */ + const byte* ptr) /*!< in: pointer to a frame */ { buf_chunk_t* chunk; ulint i; @@ -1908,7 +2552,7 @@ buf_block_align( ut_ad(block->frame == page_align(ptr)); #ifdef UNIV_DEBUG /* A thread that updates these fields must - hold buf_pool_mutex and block->mutex. Acquire + hold buf_pool->mutex and block->mutex. Acquire only the latter. */ mutex_enter(&block->mutex); @@ -1957,6 +2601,30 @@ buf_block_align( } } + return(NULL); +} + +/*******************************************************************//** +Gets the block to whose frame the pointer is pointing to. +@return pointer to block, never NULL */ +UNIV_INTERN +buf_block_t* +buf_block_align( +/*============*/ + const byte* ptr) /*!< in: pointer to a frame */ +{ + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_block_t* block; + + block = buf_block_align_instance( + buf_pool_from_array(i), ptr); + if (block) { + return(block); + } + } + /* The block should always be found. */ ut_error; return(NULL); @@ -1964,14 +2632,15 @@ buf_block_align( /********************************************************************//** Find out if a pointer belongs to a buf_block_t. It can be a pointer to -the buf_block_t itself or a member of it +the buf_block_t itself or a member of it. This functions checks one of +the buffer pool instances. @return TRUE if ptr belongs to a buf_block_t struct */ -UNIV_INTERN +static ibool -buf_pointer_is_block_field( -/*=======================*/ - const void* ptr) /*!< in: pointer not - dereferenced */ +buf_pointer_is_block_field_instance( +/*================================*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + const void* ptr) /*!< in: pointer not dereferenced */ { const buf_chunk_t* chunk = buf_pool->chunks; const buf_chunk_t* const echunk = chunk + buf_pool->n_chunks; @@ -1992,23 +2661,49 @@ buf_pointer_is_block_field( } /********************************************************************//** +Find out if a pointer belongs to a buf_block_t. It can be a pointer to +the buf_block_t itself or a member of it +@return TRUE if ptr belongs to a buf_block_t struct */ +UNIV_INTERN +ibool +buf_pointer_is_block_field( +/*=======================*/ + const void* ptr) /*!< in: pointer not dereferenced */ +{ + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + ibool found; + + found = buf_pointer_is_block_field_instance( + buf_pool_from_array(i), ptr); + if (found) { + return(TRUE); + } + } + + return(FALSE); +} + +/********************************************************************//** Find out if a buffer block was created by buf_chunk_init(). @return TRUE if "block" has been added to buf_pool->free by buf_chunk_init() */ static ibool buf_block_is_uncompressed( /*======================*/ - const buf_block_t* block) /*!< in: pointer to block, - not dereferenced */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + const buf_block_t* block) /*!< in: pointer to block, + not dereferenced */ { - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); if (UNIV_UNLIKELY((((ulint) block) % sizeof *block) != 0)) { /* The pointer should be aligned. */ return(FALSE); } - return(buf_pointer_is_block_field((void *)block)); + return(buf_pointer_is_block_field_instance(buf_pool, (void *)block)); } /********************************************************************//** @@ -2025,32 +2720,40 @@ buf_page_get_gen( ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ buf_block_t* guess, /*!< in: guessed block or NULL */ ulint mode, /*!< in: BUF_GET, BUF_GET_IF_IN_POOL, - BUF_GET_NO_LATCH */ + BUF_GET_NO_LATCH, or + BUF_GET_IF_IN_POOL_OR_WATCH */ const char* file, /*!< in: file name */ ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mini-transaction */ { buf_block_t* block; + ulint fold; unsigned access_time; ulint fix_type; ibool must_read; + ulint retries = 0; + buf_pool_t* buf_pool = buf_pool_get(space, offset); ut_ad(mtr); + ut_ad(mtr->state == MTR_ACTIVE); ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH) || (rw_latch == RW_NO_LATCH)); ut_ad((mode != BUF_GET_NO_LATCH) || (rw_latch == RW_NO_LATCH)); - ut_ad((mode == BUF_GET) || (mode == BUF_GET_IF_IN_POOL) - || (mode == BUF_GET_NO_LATCH)); + ut_ad(mode == BUF_GET + || mode == BUF_GET_IF_IN_POOL + || mode == BUF_GET_NO_LATCH + || mode == BUF_GET_IF_IN_POOL_OR_WATCH); ut_ad(zip_size == fil_space_get_zip_size(space)); ut_ad(ut_is_2pow(zip_size)); #ifndef UNIV_LOG_DEBUG ut_ad(!ibuf_inside() || ibuf_page(space, zip_size, offset, NULL)); #endif buf_pool->stat.n_page_gets++; + fold = buf_page_address_fold(space, offset); loop: block = guess; - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); if (block) { /* If the guess is a compressed page descriptor that @@ -2061,7 +2764,7 @@ loop: the guess may be pointing to a buffer pool chunk that has been released when resizing the buffer pool. */ - if (!buf_block_is_uncompressed(block) + if (!buf_block_is_uncompressed(buf_pool, block) || offset != block->page.offset || space != block->page.space || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) { @@ -2074,21 +2777,59 @@ loop: } if (block == NULL) { - block = (buf_block_t*) buf_page_hash_get(space, offset); + block = (buf_block_t*) buf_page_hash_get_low( + buf_pool, space, offset, fold); } loop2: + if (block && buf_pool_watch_is_sentinel(buf_pool, &block->page)) { + block = NULL; + } + if (block == NULL) { /* Page not in buf_pool: needs to be read from file */ - buf_pool_mutex_exit(); + if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) { + block = (buf_block_t*) buf_pool_watch_set( + space, offset, fold); + + if (UNIV_LIKELY_NULL(block)) { - if (mode == BUF_GET_IF_IN_POOL) { + goto got_block; + } + } + + buf_pool_mutex_exit(buf_pool); + + if (mode == BUF_GET_IF_IN_POOL + || mode == BUF_GET_IF_IN_POOL_OR_WATCH) { return(NULL); } - buf_read_page(space, zip_size, offset); + if (buf_read_page(space, zip_size, offset)) { + retries = 0; + } else if (retries < BUF_PAGE_READ_MAX_RETRIES) { + ++retries; + } else { + fprintf(stderr, "InnoDB: Error: Unable" + " to read tablespace %lu page no" + " %lu into the buffer pool after" + " %lu attempts\n" + "InnoDB: The most probable cause" + " of this error may be that the" + " table has been corrupted.\n" + "InnoDB: You can try to fix this" + " problem by using" + " innodb_force_recovery.\n" + "InnoDB: Please see reference manual" + " for more details.\n" + "InnoDB: Aborting...\n", + space, offset, + BUF_PAGE_READ_MAX_RETRIES); + + ut_error; + } #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG ut_a(++buf_dbg_counter % 37 || buf_validate()); @@ -2096,13 +2837,17 @@ loop2: goto loop; } +got_block: ut_ad(page_zip_get_size(&block->page.zip) == zip_size); must_read = buf_block_get_io_fix(block) == BUF_IO_READ; if (must_read && mode == BUF_GET_IF_IN_POOL) { - /* The page is only being read to buffer */ - buf_pool_mutex_exit(); + + /* The page is being read to buffer pool, + but we cannot wait around for the read to + complete. */ + buf_pool_mutex_exit(buf_pool); return(NULL); } @@ -2118,40 +2863,42 @@ loop2: case BUF_BLOCK_ZIP_DIRTY: bpage = &block->page; /* Protect bpage->buf_fix_count. */ - mutex_enter(&buf_pool_zip_mutex); + mutex_enter(&buf_pool->zip_mutex); if (bpage->buf_fix_count || buf_page_get_io_fix(bpage) != BUF_IO_NONE) { /* This condition often occurs when the buffer is not buffer-fixed, but I/O-fixed by buf_page_init_for_read(). */ - mutex_exit(&buf_pool_zip_mutex); + mutex_exit(&buf_pool->zip_mutex); wait_until_unfixed: /* The block is buffer-fixed or I/O-fixed. Try again later. */ - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); os_thread_sleep(WAIT_FOR_READ); - + goto loop; } /* Allocate an uncompressed page. */ - buf_pool_mutex_exit(); - mutex_exit(&buf_pool_zip_mutex); + buf_pool_mutex_exit(buf_pool); + mutex_exit(&buf_pool->zip_mutex); - block = buf_LRU_get_free_block(0); + block = buf_LRU_get_free_block(buf_pool, 0); ut_a(block); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); mutex_enter(&block->mutex); { - buf_page_t* hash_bpage - = buf_page_hash_get(space, offset); + buf_page_t* hash_bpage; + + hash_bpage = buf_page_hash_get_low( + buf_pool, space, offset, fold); if (UNIV_UNLIKELY(bpage != hash_bpage)) { /* The buf_pool->page_hash was modified - while buf_pool_mutex was released. + while buf_pool->mutex was released. Free the block that was allocated. */ buf_LRU_block_free_non_file_page(block); @@ -2167,7 +2914,7 @@ wait_until_unfixed: || buf_page_get_io_fix(bpage) != BUF_IO_NONE)) { /* The block was buffer-fixed or I/O-fixed - while buf_pool_mutex was not held by this thread. + while buf_pool->mutex was not held by this thread. Free the block that was allocated and try again. This should be extremely unlikely. */ @@ -2180,7 +2927,7 @@ wait_until_unfixed: /* Move the compressed page from bpage to block, and uncompress it. */ - mutex_enter(&buf_pool_zip_mutex); + mutex_enter(&buf_pool->zip_mutex); buf_relocate(bpage, &block->page); buf_block_init_low(block); @@ -2196,22 +2943,8 @@ wait_until_unfixed: ut_ad(!block->page.in_flush_list); } else { /* Relocate buf_pool->flush_list. */ - buf_page_t* b; - - b = UT_LIST_GET_PREV(list, &block->page); - ut_ad(block->page.in_flush_list); - UT_LIST_REMOVE(list, buf_pool->flush_list, - &block->page); - - if (b) { - UT_LIST_INSERT_AFTER( - list, buf_pool->flush_list, b, - &block->page); - } else { - UT_LIST_ADD_FIRST( - list, buf_pool->flush_list, - &block->page); - } + buf_flush_relocate_on_flush_list(bpage, + &block->page); } /* Buffer-fix, I/O-fix, and X-latch the block @@ -2225,25 +2958,29 @@ wait_until_unfixed: block->page.buf_fix_count = 1; buf_block_set_io_fix(block, BUF_IO_READ); rw_lock_x_lock(&block->lock); + + UNIV_MEM_INVALID(bpage, sizeof *bpage); + mutex_exit(&block->mutex); - mutex_exit(&buf_pool_zip_mutex); + mutex_exit(&buf_pool->zip_mutex); buf_pool->n_pend_unzip++; - buf_buddy_free(bpage, sizeof *bpage); + buf_buddy_free(buf_pool, bpage, sizeof *bpage); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); /* Decompress the page and apply buffered operations - while not holding buf_pool_mutex or block->mutex. */ + while not holding buf_pool->mutex or block->mutex. */ success = buf_zip_decompress(block, srv_use_checksums); + ut_a(success); - if (UNIV_LIKELY(success)) { + if (UNIV_LIKELY(!recv_no_ibuf_operations)) { ibuf_merge_or_delete_for_page(block, space, offset, zip_size, TRUE); } /* Unfix and unlatch the block. */ - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); mutex_enter(&block->mutex); block->page.buf_fix_count--; buf_block_set_io_fix(block, BUF_IO_NONE); @@ -2251,12 +2988,6 @@ wait_until_unfixed: buf_pool->n_pend_unzip--; rw_lock_x_unlock(&block->lock); - if (UNIV_UNLIKELY(!success)) { - - buf_pool_mutex_exit(); - return(NULL); - } - break; case BUF_BLOCK_ZIP_FREE: @@ -2271,7 +3002,12 @@ wait_until_unfixed: ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); mutex_enter(&block->mutex); +#if UNIV_WORD_SIZE == 4 + /* On 32-bit systems, there is no padding in buf_page_t. On + other systems, Valgrind could complain about uninitialized pad + bytes. */ UNIV_MEM_ASSERT_RW(&block->page, sizeof block->page); +#endif buf_block_buf_fix_inc(block, file, line); @@ -2281,7 +3017,7 @@ wait_until_unfixed: access_time = buf_page_is_accessed(&block->page); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); buf_page_set_accessed_make_young(&block->page, access_time); @@ -2356,8 +3092,8 @@ page. @return TRUE if success */ UNIV_INTERN ibool -buf_page_optimistic_get_func( -/*=========================*/ +buf_page_optimistic_get( +/*====================*/ ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH */ buf_block_t* block, /*!< in: guessed buffer block */ ib_uint64_t modify_clock,/*!< in: modify clock value if mode is @@ -2366,11 +3102,14 @@ buf_page_optimistic_get_func( ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mini-transaction */ { + buf_pool_t* buf_pool; unsigned access_time; ibool success; ulint fix_type; - ut_ad(mtr && block); + ut_ad(block); + ut_ad(mtr); + ut_ad(mtr->state == MTR_ACTIVE); ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH)); mutex_enter(&block->mutex); @@ -2457,6 +3196,7 @@ buf_page_optimistic_get_func( ut_a(ibuf_count_get(buf_block_get_space(block), buf_block_get_page_no(block)) == 0); #endif + buf_pool = buf_pool_from_block(block); buf_pool->stat.n_page_gets++; return(TRUE); @@ -2478,10 +3218,12 @@ buf_page_get_known_nowait( ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mini-transaction */ { + buf_pool_t* buf_pool; ibool success; ulint fix_type; ut_ad(mtr); + ut_ad(mtr->state == MTR_ACTIVE); ut_ad((rw_latch == RW_S_LATCH) || (rw_latch == RW_X_LATCH)); mutex_enter(&block->mutex); @@ -2505,10 +3247,12 @@ buf_page_get_known_nowait( mutex_exit(&block->mutex); + buf_pool = buf_pool_from_block(block); + if (mode == BUF_MAKE_YOUNG && buf_page_peek_if_too_old(&block->page)) { - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); buf_LRU_make_block_young(&block->page); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); } else if (!buf_page_is_accessed(&block->page)) { /* Above, we do a dirty read on purpose, to avoid mutex contention. The field buf_page_t::access_time @@ -2516,9 +3260,9 @@ buf_page_get_known_nowait( field must be protected by mutex, however. */ ulint time_ms = ut_time_ms(); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); buf_page_set_accessed(&block->page, time_ms); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); } ut_ad(!ibuf_inside() || (mode == BUF_KEEP_OLD)); @@ -2580,17 +3324,23 @@ buf_page_try_get_func( buf_block_t* block; ibool success; ulint fix_type; + buf_pool_t* buf_pool = buf_pool_get(space_id, page_no); + + ut_ad(mtr); + ut_ad(mtr->state == MTR_ACTIVE); - buf_pool_mutex_enter(); - block = buf_block_hash_get(space_id, page_no); + buf_pool_mutex_enter(buf_pool); + block = buf_block_hash_get(buf_pool, space_id, page_no); - if (!block) { - buf_pool_mutex_exit(); + if (!block || buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE) { + buf_pool_mutex_exit(buf_pool); return(NULL); } + ut_ad(!buf_pool_watch_is_sentinel(buf_pool, &block->page)); + mutex_enter(&block->mutex); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); @@ -2673,11 +3423,13 @@ buf_page_init( ulint space, /*!< in: space id */ ulint offset, /*!< in: offset of the page within space in units of a page */ + ulint fold, /*!< in: buf_page_address_fold(space,offset) */ buf_block_t* block) /*!< in: block to init */ { buf_page_t* hash_page; + buf_pool_t* buf_pool = buf_pool_get(space, offset); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(mutex_own(&(block->mutex))); ut_a(buf_block_get_state(block) != BUF_BLOCK_FILE_PAGE); @@ -2695,13 +3447,23 @@ buf_page_init( buf_block_init_low(block); - block->lock_hash_val = lock_rec_hash(space, offset); + block->lock_hash_val = lock_rec_hash(space, offset); + + buf_page_init_low(&block->page); /* Insert into the hash table of file pages */ - hash_page = buf_page_hash_get(space, offset); + hash_page = buf_page_hash_get_low(buf_pool, space, offset, fold); - if (UNIV_LIKELY_NULL(hash_page)) { + if (UNIV_LIKELY(!hash_page)) { + } else if (buf_pool_watch_is_sentinel(buf_pool, hash_page)) { + /* Preserve the reference count. */ + ulint buf_fix_count = hash_page->buf_fix_count; + + ut_a(buf_fix_count > 0); + block->page.buf_fix_count += buf_fix_count; + buf_pool_watch_remove(buf_pool, fold, hash_page); + } else { fprintf(stderr, "InnoDB: Error: page %lu %lu already found" " in the hash table: %p, %p\n", @@ -2710,7 +3472,7 @@ buf_page_init( (const void*) hash_page, (const void*) block); #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG mutex_exit(&block->mutex); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); buf_print(); buf_LRU_print(); buf_validate(); @@ -2719,13 +3481,11 @@ buf_page_init( ut_error; } - buf_page_init_low(&block->page); - ut_ad(!block->page.in_zip_hash); ut_ad(!block->page.in_page_hash); ut_d(block->page.in_page_hash = TRUE); HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, - buf_page_address_fold(space, offset), &block->page); + fold, &block->page); } /********************************************************************//** @@ -2747,16 +3507,20 @@ buf_page_init_for_read( ulint space, /*!< in: space id */ ulint zip_size,/*!< in: compressed page size, or 0 */ ibool unzip, /*!< in: TRUE=request uncompressed page */ - ib_int64_t tablespace_version,/*!< in: prevents reading from a wrong + ib_int64_t tablespace_version, + /*!< in: prevents reading from a wrong version of the tablespace in case we have done DISCARD + IMPORT */ ulint offset) /*!< in: page number */ { buf_block_t* block; - buf_page_t* bpage; + buf_page_t* bpage = NULL; + buf_page_t* watch_page; mtr_t mtr; + ulint fold; ibool lru = FALSE; void* data; + buf_pool_t* buf_pool = buf_pool_get(space, offset); ut_ad(buf_pool); @@ -2785,14 +3549,19 @@ buf_page_init_for_read( && UNIV_LIKELY(!recv_recovery_is_on())) { block = NULL; } else { - block = buf_LRU_get_free_block(0); + block = buf_LRU_get_free_block(buf_pool, 0); ut_ad(block); + ut_ad(buf_pool_from_block(block) == buf_pool); } - buf_pool_mutex_enter(); + fold = buf_page_address_fold(space, offset); + + buf_pool_mutex_enter(buf_pool); - if (buf_page_hash_get(space, offset)) { + watch_page = buf_page_hash_get_low(buf_pool, space, offset, fold); + if (watch_page && !buf_pool_watch_is_sentinel(buf_pool, watch_page)) { /* The page is already in the buffer pool. */ + watch_page = NULL; err_exit: if (block) { mutex_enter(&block->mutex); @@ -2816,7 +3585,10 @@ err_exit: if (block) { bpage = &block->page; mutex_enter(&block->mutex); - buf_page_init(space, offset, block); + + ut_ad(buf_pool_from_bpage(bpage) == buf_pool); + + buf_page_init(space, offset, fold, block); /* The block must be put to the LRU list, to the old blocks */ buf_LRU_add_block(bpage, TRUE/* to old blocks */); @@ -2836,16 +3608,16 @@ err_exit: if (UNIV_UNLIKELY(zip_size)) { page_zip_set_size(&block->page.zip, zip_size); - /* buf_pool_mutex may be released and + /* buf_pool->mutex may be released and reacquired by buf_buddy_alloc(). Thus, we must release block->mutex in order not to break the latching order in the reacquisition - of buf_pool_mutex. We also must defer this + of buf_pool->mutex. We also must defer this operation until after the block descriptor has been added to buf_pool->LRU and buf_pool->page_hash. */ mutex_exit(&block->mutex); - data = buf_buddy_alloc(zip_size, &lru); + data = buf_buddy_alloc(buf_pool, zip_size, &lru); mutex_enter(&block->mutex); block->page.zip.data = data; @@ -2869,35 +3641,49 @@ err_exit: control block (bpage), in order to avoid the invocation of buf_buddy_relocate_block() on uninitialized data. */ - data = buf_buddy_alloc(zip_size, &lru); - bpage = buf_buddy_alloc(sizeof *bpage, &lru); + data = buf_buddy_alloc(buf_pool, zip_size, &lru); + bpage = buf_buddy_alloc(buf_pool, sizeof *bpage, &lru); + + /* Initialize the buf_pool pointer. */ + bpage->buf_pool = buf_pool; /* If buf_buddy_alloc() allocated storage from the LRU list, - it released and reacquired buf_pool_mutex. Thus, we must + it released and reacquired buf_pool->mutex. Thus, we must check the page_hash again, as it may have been modified. */ - if (UNIV_UNLIKELY(lru) - && UNIV_LIKELY_NULL(buf_page_hash_get(space, offset))) { + if (UNIV_UNLIKELY(lru)) { - /* The block was added by some other thread. */ - buf_buddy_free(bpage, sizeof *bpage); - buf_buddy_free(data, zip_size); + watch_page = buf_page_hash_get_low( + buf_pool, space, offset, fold); - bpage = NULL; - goto func_exit; + if (watch_page + && !buf_pool_watch_is_sentinel(buf_pool, + watch_page)) { + + /* The block was added by some other thread. */ + watch_page = NULL; + buf_buddy_free(buf_pool, bpage, sizeof *bpage); + buf_buddy_free(buf_pool, data, zip_size); + + bpage = NULL; + goto func_exit; + } } page_zip_des_init(&bpage->zip); page_zip_set_size(&bpage->zip, zip_size); bpage->zip.data = data; - mutex_enter(&buf_pool_zip_mutex); + mutex_enter(&buf_pool->zip_mutex); UNIV_MEM_DESC(bpage->zip.data, page_zip_get_size(&bpage->zip), bpage); + buf_page_init_low(bpage); + bpage->state = BUF_BLOCK_ZIP_PAGE; bpage->space = space; bpage->offset = offset; + #ifdef UNIV_DEBUG bpage->in_page_hash = FALSE; bpage->in_zip_hash = FALSE; @@ -2907,8 +3693,18 @@ err_exit: #endif /* UNIV_DEBUG */ ut_d(bpage->in_page_hash = TRUE); - HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, - buf_page_address_fold(space, offset), bpage); + + if (UNIV_LIKELY_NULL(watch_page)) { + /* Preserve the reference count. */ + ulint buf_fix_count = watch_page->buf_fix_count; + ut_a(buf_fix_count > 0); + bpage->buf_fix_count += buf_fix_count; + ut_ad(buf_pool_watch_is_sentinel(buf_pool, watch_page)); + buf_pool_watch_remove(buf_pool, fold, watch_page); + } + + HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold, + bpage); /* The block must be put to the LRU list, to the old blocks */ buf_LRU_add_block(bpage, TRUE/* to old blocks */); @@ -2916,12 +3712,12 @@ err_exit: buf_page_set_io_fix(bpage, BUF_IO_READ); - mutex_exit(&buf_pool_zip_mutex); + mutex_exit(&buf_pool->zip_mutex); } buf_pool->n_pend_reads++; func_exit: - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); if (mode == BUF_READ_IBUF_PAGES_ONLY) { @@ -2950,19 +3746,27 @@ buf_page_create( { buf_frame_t* frame; buf_block_t* block; + ulint fold; buf_block_t* free_block = NULL; ulint time_ms = ut_time_ms(); + buf_pool_t* buf_pool = buf_pool_get(space, offset); ut_ad(mtr); + ut_ad(mtr->state == MTR_ACTIVE); ut_ad(space || !zip_size); - free_block = buf_LRU_get_free_block(0); + free_block = buf_LRU_get_free_block(buf_pool, 0); + + fold = buf_page_address_fold(space, offset); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); - block = (buf_block_t*) buf_page_hash_get(space, offset); + block = (buf_block_t*) buf_page_hash_get_low( + buf_pool, space, offset, fold); - if (block && buf_page_in_file(&block->page)) { + if (block + && buf_page_in_file(&block->page) + && !buf_pool_watch_is_sentinel(buf_pool, &block->page)) { #ifdef UNIV_IBUF_COUNT_DEBUG ut_a(ibuf_count_get(space, offset) == 0); #endif @@ -2971,7 +3775,7 @@ buf_page_create( #endif /* UNIV_DEBUG_FILE_ACCESSES */ /* Page can be found in buf_pool */ - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); buf_block_free(free_block); @@ -2992,7 +3796,7 @@ buf_page_create( mutex_enter(&block->mutex); - buf_page_init(space, offset, block); + buf_page_init(space, offset, fold, block); /* The block must be put to the LRU list */ buf_LRU_add_block(&block->page, FALSE); @@ -3005,7 +3809,7 @@ buf_page_create( ibool lru; /* Prevent race conditions during buf_buddy_alloc(), - which may release and reacquire buf_pool_mutex, + which may release and reacquire buf_pool->mutex, by IO-fixing and X-latching the block. */ buf_page_set_io_fix(&block->page, BUF_IO_READ); @@ -3013,13 +3817,13 @@ buf_page_create( page_zip_set_size(&block->page.zip, zip_size); mutex_exit(&block->mutex); - /* buf_pool_mutex may be released and reacquired by + /* buf_pool->mutex may be released and reacquired by buf_buddy_alloc(). Thus, we must release block->mutex in order not to break the latching order in - the reacquisition of buf_pool_mutex. We also must + the reacquisition of buf_pool->mutex. We also must defer this operation until after the block descriptor has been added to buf_pool->LRU and buf_pool->page_hash. */ - data = buf_buddy_alloc(zip_size, &lru); + data = buf_buddy_alloc(buf_pool, zip_size, &lru); mutex_enter(&block->mutex); block->page.zip.data = data; @@ -3037,7 +3841,7 @@ buf_page_create( buf_page_set_accessed(&block->page, time_ms); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); mtr_memo_push(mtr, block, MTR_MEMO_BUF_FIX); @@ -3049,7 +3853,7 @@ buf_page_create( ibuf_merge_or_delete_for_page(NULL, space, offset, zip_size, TRUE); /* Flush pages from the end of the LRU list if necessary */ - buf_flush_free_margin(); + buf_flush_free_margin(buf_pool); frame = block->frame; @@ -3085,6 +3889,7 @@ buf_page_io_complete( buf_page_t* bpage) /*!< in: pointer to the block in question */ { enum buf_io_fix io_type; + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); const ibool uncompressed = (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); @@ -3220,7 +4025,7 @@ corrupt: } } - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); mutex_enter(buf_page_get_mutex(bpage)); #ifdef UNIV_IBUF_COUNT_DEBUG @@ -3284,22 +4089,57 @@ corrupt: #endif /* UNIV_DEBUG */ mutex_exit(buf_page_get_mutex(bpage)); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); } /*********************************************************************//** -Invalidates the file pages in the buffer pool when an archive recovery is -completed. All the file pages buffered must be in a replaceable state when -this function is called: not latched and not modified. */ -UNIV_INTERN +Asserts that all file pages in the buffer are in a replaceable state. +@return TRUE */ +static +ibool +buf_all_freed_instance( +/*===================*/ + buf_pool_t* buf_pool) /*!< in: buffer pool instancce */ +{ + ulint i; + buf_chunk_t* chunk; + + ut_ad(buf_pool); + + buf_pool_mutex_enter(buf_pool); + + chunk = buf_pool->chunks; + + for (i = buf_pool->n_chunks; i--; chunk++) { + + const buf_block_t* block = buf_chunk_not_freed(chunk); + + if (UNIV_LIKELY_NULL(block)) { + fprintf(stderr, + "Page %lu %lu still fixed or dirty\n", + (ulong) block->page.space, + (ulong) block->page.offset); + ut_error; + } + } + + buf_pool_mutex_exit(buf_pool); + + return(TRUE); +} + +/*********************************************************************//** +Invalidates file pages in one buffer pool instance */ +static void -buf_pool_invalidate(void) -/*=====================*/ +buf_pool_invalidate_instance( +/*=========================*/ + buf_pool_t* buf_pool) /*!< in: buffer pool instance */ { ibool freed; enum buf_flush i; - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); for (i = BUF_FLUSH_LRU; i < BUF_FLUSH_N_TYPES; i++) { @@ -3315,23 +4155,23 @@ buf_pool_invalidate(void) pool invalidation to proceed we must ensure there is NO write activity happening. */ if (buf_pool->n_flush[i] > 0) { - buf_pool_mutex_exit(); - buf_flush_wait_batch_end(i); - buf_pool_mutex_enter(); + buf_pool_mutex_exit(buf_pool); + buf_flush_wait_batch_end(buf_pool, i); + buf_pool_mutex_enter(buf_pool); } } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); - ut_ad(buf_all_freed()); + ut_ad(buf_all_freed_instance(buf_pool)); freed = TRUE; while (freed) { - freed = buf_LRU_search_and_free_block(100); + freed = buf_LRU_search_and_free_block(buf_pool, 100); } - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); ut_ad(UT_LIST_GET_LEN(buf_pool->LRU) == 0); ut_ad(UT_LIST_GET_LEN(buf_pool->unzip_LRU) == 0); @@ -3342,19 +4182,36 @@ buf_pool_invalidate(void) buf_pool->LRU_flush_ended = 0; memset(&buf_pool->stat, 0x00, sizeof(buf_pool->stat)); - buf_refresh_io_stats(); + buf_refresh_io_stats(buf_pool); + + buf_pool_mutex_exit(buf_pool); +} + +/*********************************************************************//** +Invalidates the file pages in the buffer pool when an archive recovery is +completed. All the file pages buffered must be in a replaceable state when +this function is called: not latched and not modified. */ +UNIV_INTERN +void +buf_pool_invalidate(void) +/*=====================*/ +{ + ulint i; - buf_pool_mutex_exit(); + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_invalidate_instance(buf_pool_from_array(i)); + } } #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /*********************************************************************//** -Validates the buffer buf_pool data structure. +Validates data in one buffer pool instance @return TRUE */ -UNIV_INTERN +static ibool -buf_validate(void) -/*==============*/ +buf_pool_validate_instance( +/*=======================*/ + buf_pool_t* buf_pool) /*!< in: buffer pool instance */ { buf_page_t* b; buf_chunk_t* chunk; @@ -3369,7 +4226,7 @@ buf_validate(void) ut_ad(buf_pool); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); chunk = buf_pool->chunks; @@ -3394,7 +4251,8 @@ buf_validate(void) break; case BUF_BLOCK_FILE_PAGE: - ut_a(buf_page_hash_get(buf_block_get_space( + ut_a(buf_page_hash_get(buf_pool, + buf_block_get_space( block), buf_block_get_page_no( block)) @@ -3441,11 +4299,6 @@ buf_validate(void) } n_lru++; - - if (block->page.oldest_modification > 0) { - n_flush++; - } - break; case BUF_BLOCK_NOT_USED: @@ -3463,7 +4316,7 @@ buf_validate(void) } } - mutex_enter(&buf_pool_zip_mutex); + mutex_enter(&buf_pool->zip_mutex); /* Check clean compressed-only blocks. */ @@ -3484,30 +4337,34 @@ buf_validate(void) ut_error; break; } + + /* It is OK to read oldest_modification here because + we have acquired buf_pool->zip_mutex above which acts + as the 'block->mutex' for these bpages. */ ut_a(!b->oldest_modification); - ut_a(buf_page_hash_get(b->space, b->offset) == b); + ut_a(buf_page_hash_get(buf_pool, b->space, b->offset) == b); n_lru++; n_zip++; } - /* Check dirty compressed-only blocks. */ + /* Check dirty blocks. */ + buf_flush_list_mutex_enter(buf_pool); for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b; b = UT_LIST_GET_NEXT(list, b)) { ut_ad(b->in_flush_list); + ut_a(b->oldest_modification); + n_flush++; switch (buf_page_get_state(b)) { case BUF_BLOCK_ZIP_DIRTY: - ut_a(b->oldest_modification); n_lru++; - n_flush++; n_zip++; switch (buf_page_get_io_fix(b)) { case BUF_IO_NONE: case BUF_IO_READ: break; - case BUF_IO_WRITE: switch (buf_page_get_flush_type(b)) { case BUF_FLUSH_LRU: @@ -3537,10 +4394,14 @@ buf_validate(void) ut_error; break; } - ut_a(buf_page_hash_get(b->space, b->offset) == b); + ut_a(buf_page_hash_get(buf_pool, b->space, b->offset) == b); } - mutex_exit(&buf_pool_zip_mutex); + ut_a(UT_LIST_GET_LEN(buf_pool->flush_list) == n_flush); + + buf_flush_list_mutex_exit(buf_pool); + + mutex_exit(&buf_pool->zip_mutex); if (n_lru + n_free > buf_pool->curr_size + n_zip) { fprintf(stderr, "n LRU %lu, n free %lu, pool %lu zip %lu\n", @@ -3556,28 +4417,49 @@ buf_validate(void) (ulong) n_free); ut_error; } - ut_a(UT_LIST_GET_LEN(buf_pool->flush_list) == n_flush); ut_a(buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE] == n_single_flush); ut_a(buf_pool->n_flush[BUF_FLUSH_LIST] == n_list_flush); ut_a(buf_pool->n_flush[BUF_FLUSH_LRU] == n_lru_flush); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); ut_a(buf_LRU_validate()); - ut_a(buf_flush_validate()); + ut_a(buf_flush_validate(buf_pool)); + + return(TRUE); +} + +/*********************************************************************//** +Validates the buffer buf_pool data structure. +@return TRUE */ +UNIV_INTERN +ibool +buf_validate(void) +/*==============*/ +{ + ulint i; + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + buf_pool_validate_instance(buf_pool); + } return(TRUE); } + #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ #if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /*********************************************************************//** -Prints info of the buffer buf_pool data structure. */ -UNIV_INTERN +Prints info of the buffer buf_pool data structure for one instance. */ +static void -buf_print(void) -/*===========*/ +buf_print_instance( +/*===============*/ + buf_pool_t* buf_pool) { dulint* index_ids; ulint* counts; @@ -3596,7 +4478,8 @@ buf_print(void) index_ids = mem_alloc(sizeof(dulint) * size); counts = mem_alloc(sizeof(ulint) * size); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); + buf_flush_list_mutex_enter(buf_pool); fprintf(stderr, "buf_pool size %lu\n" @@ -3623,6 +4506,8 @@ buf_print(void) (ulong) buf_pool->stat.n_pages_created, (ulong) buf_pool->stat.n_pages_written); + buf_flush_list_mutex_exit(buf_pool); + /* Count the number of blocks belonging to each index in the buffer */ n_found = 0; @@ -3663,7 +4548,7 @@ buf_print(void) } } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); for (i = 0; i < n_found; i++) { index = dict_index_get_if_in_cache(index_ids[i]); @@ -3684,7 +4569,24 @@ buf_print(void) mem_free(index_ids); mem_free(counts); - ut_a(buf_validate()); + ut_a(buf_pool_validate_instance(buf_pool)); +} + +/*********************************************************************//** +Prints info of the buffer buf_pool data structure. */ +UNIV_INTERN +void +buf_print(void) +/*===========*/ +{ + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + buf_print_instance(buf_pool); + } } #endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */ @@ -3694,15 +4596,16 @@ Returns the number of latched pages in the buffer pool. @return number of latched pages */ UNIV_INTERN ulint -buf_get_latched_pages_number(void) -/*==============================*/ +buf_get_latched_pages_number_instance( +/*==================================*/ + buf_pool_t* buf_pool) /*!< in: buffer pool instance */ { - buf_chunk_t* chunk; buf_page_t* b; ulint i; + buf_chunk_t* chunk; ulint fixed_pages_number = 0; - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); chunk = buf_pool->chunks; @@ -3731,7 +4634,7 @@ buf_get_latched_pages_number(void) } } - mutex_enter(&buf_pool_zip_mutex); + mutex_enter(&buf_pool->zip_mutex); /* Traverse the lists of clean and dirty compressed-only blocks. */ @@ -3746,6 +4649,7 @@ buf_get_latched_pages_number(void) } } + buf_flush_list_mutex_enter(buf_pool); for (b = UT_LIST_GET_FIRST(buf_pool->flush_list); b; b = UT_LIST_GET_NEXT(list, b)) { ut_ad(b->in_flush_list); @@ -3771,11 +4675,36 @@ buf_get_latched_pages_number(void) } } - mutex_exit(&buf_pool_zip_mutex); - buf_pool_mutex_exit(); + buf_flush_list_mutex_exit(buf_pool); + mutex_exit(&buf_pool->zip_mutex); + buf_pool_mutex_exit(buf_pool); return(fixed_pages_number); } + +/*********************************************************************//** +Returns the number of latched pages in all the buffer pools. +@return number of latched pages */ +UNIV_INTERN +ulint +buf_get_latched_pages_number(void) +/*==============================*/ +{ + ulint i; + ulint total_latched_pages = 0; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + total_latched_pages += buf_get_latched_pages_number_instance( + buf_pool); + } + + return(total_latched_pages); +} + #endif /* UNIV_DEBUG */ /*********************************************************************//** @@ -3786,10 +4715,22 @@ ulint buf_get_n_pending_ios(void) /*=======================*/ { - return(buf_pool->n_pend_reads - + buf_pool->n_flush[BUF_FLUSH_LRU] - + buf_pool->n_flush[BUF_FLUSH_LIST] - + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]); + ulint i; + ulint pend_ios = 0; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + pend_ios += + buf_pool->n_pend_reads + + buf_pool->n_flush[BUF_FLUSH_LRU] + + buf_pool->n_flush[BUF_FLUSH_LIST] + + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]; + } + + return(pend_ios); } /*********************************************************************//** @@ -3801,18 +4742,17 @@ ulint buf_get_modified_ratio_pct(void) /*============================*/ { - ulint ratio; + ulint ratio; + ulint lru_len = 0; + ulint free_len = 0; + ulint flush_list_len = 0; - buf_pool_mutex_enter(); - - ratio = (100 * UT_LIST_GET_LEN(buf_pool->flush_list)) - / (1 + UT_LIST_GET_LEN(buf_pool->LRU) - + UT_LIST_GET_LEN(buf_pool->free)); + buf_get_total_list_len(&lru_len, &free_len, &flush_list_len); + ratio = (100 * flush_list_len) / (1 + lru_len + free_len); + /* 1 + is there to avoid division by zero */ - buf_pool_mutex_exit(); - return(ratio); } @@ -3820,9 +4760,10 @@ buf_get_modified_ratio_pct(void) Prints info of the buffer i/o. */ UNIV_INTERN void -buf_print_io( -/*=========*/ - FILE* file) /*!< in/out: buffer where to print */ +buf_print_io_instance( +/*==================*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + FILE* file) /*!< in/out: buffer where to print */ { time_t current_time; double time_elapsed; @@ -3830,7 +4771,8 @@ buf_print_io( ut_ad(buf_pool); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); + buf_flush_list_mutex_enter(buf_pool); fprintf(file, "Buffer pool size %lu\n" @@ -3852,6 +4794,8 @@ buf_print_io( + buf_pool->init_flush[BUF_FLUSH_LIST], (ulong) buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]); + buf_flush_list_mutex_exit(buf_pool); + current_time = time(NULL); time_elapsed = 0.001 + difftime(current_time, buf_pool->last_printout_time); @@ -3882,7 +4826,8 @@ buf_print_io( - buf_pool->old_stat.n_pages_written) / time_elapsed); - n_gets_diff = buf_pool->stat.n_page_gets - buf_pool->old_stat.n_page_gets; + n_gets_diff = buf_pool->stat.n_page_gets + - buf_pool->old_stat.n_page_gets; if (n_gets_diff) { fprintf(file, @@ -3926,56 +4871,81 @@ buf_print_io( buf_LRU_stat_sum.io, buf_LRU_stat_cur.io, buf_LRU_stat_sum.unzip, buf_LRU_stat_cur.unzip); - buf_refresh_io_stats(); - buf_pool_mutex_exit(); + buf_refresh_io_stats(buf_pool); + buf_pool_mutex_exit(buf_pool); +} + +/*********************************************************************//** +Prints info of the buffer i/o. */ +UNIV_INTERN +void +buf_print_io( +/*=========*/ + FILE* file) /*!< in/out: buffer where to print */ +{ + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + buf_print_io_instance(buf_pool, file); + } } /**********************************************************************//** Refreshes the statistics used to print per-second averages. */ UNIV_INTERN void -buf_refresh_io_stats(void) -/*======================*/ +buf_refresh_io_stats( +/*=================*/ + buf_pool_t* buf_pool) /*!< in: buffer pool instance */ { - buf_pool->last_printout_time = time(NULL); + buf_pool->last_printout_time = ut_time(); buf_pool->old_stat = buf_pool->stat; } -/*********************************************************************//** -Asserts that all file pages in the buffer are in a replaceable state. -@return TRUE */ +/**********************************************************************//** +Refreshes the statistics used to print per-second averages. */ UNIV_INTERN -ibool -buf_all_freed(void) -/*===============*/ +void +buf_refresh_io_stats_all(void) +/*==========================*/ { - buf_chunk_t* chunk; ulint i; - ut_ad(buf_pool); + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; - buf_pool_mutex_enter(); + buf_pool = buf_pool_from_array(i); - chunk = buf_pool->chunks; + buf_refresh_io_stats(buf_pool); + } +} - for (i = buf_pool->n_chunks; i--; chunk++) { +/**********************************************************************//** +Check if all pages in all buffer pools are in a replacable state. +@return FALSE if not */ +UNIV_INTERN +ibool +buf_all_freed(void) +/*===============*/ +{ + ulint i; - const buf_block_t* block = buf_chunk_not_freed(chunk); + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; - if (UNIV_LIKELY_NULL(block)) { - fprintf(stderr, - "Page %lu %lu still fixed or dirty\n", - (ulong) block->page.space, - (ulong) block->page.offset); - ut_error; - } - } + buf_pool = buf_pool_from_array(i); - buf_pool_mutex_exit(); + if (!buf_all_freed_instance(buf_pool)) { + return(FALSE); + } + } return(TRUE); } - + /*********************************************************************//** Checks that there currently are no pending i/o-operations for the buffer pool. @@ -3985,23 +4955,32 @@ ibool buf_pool_check_no_pending_io(void) /*==============================*/ { - ibool ret; + ulint i; + ibool ret = TRUE; - buf_pool_mutex_enter(); + buf_pool_mutex_enter_all(); - if (buf_pool->n_pend_reads + buf_pool->n_flush[BUF_FLUSH_LRU] - + buf_pool->n_flush[BUF_FLUSH_LIST] - + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]) { - ret = FALSE; - } else { - ret = TRUE; + for (i = 0; i < srv_buf_pool_instances && ret; i++) { + const buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + if (buf_pool->n_pend_reads + + buf_pool->n_flush[BUF_FLUSH_LRU] + + buf_pool->n_flush[BUF_FLUSH_LIST] + + buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]) { + + ret = FALSE; + } } - buf_pool_mutex_exit(); + buf_pool_mutex_exit_all(); return(ret); } +#if 0 +Code currently not used /*********************************************************************//** Gets the current length of the free list of buffer blocks. @return length of the free list */ @@ -4012,14 +4991,16 @@ buf_get_free_list_len(void) { ulint len; - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); len = UT_LIST_GET_LEN(buf_pool->free); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); return(len); } +#endif + #else /* !UNIV_HOTBACKUP */ /********************************************************************//** Inits a page to the buffer buf_pool, for use in ibbackup --restore. */ diff --git a/storage/innobase/buf/buf0flu.c b/storage/innobase/buf/buf0flu.c index 8b614ce90e5..046f1ed51e8 100644 --- a/storage/innobase/buf/buf0flu.c +++ b/storage/innobase/buf/buf0flu.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. 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 @@ -83,34 +83,210 @@ Validates the flush list. @return TRUE if ok */ static ibool -buf_flush_validate_low(void); -/*========================*/ +buf_flush_validate_low( +/*===================*/ + buf_pool_t* buf_pool); /*!< in: Buffer pool instance */ +#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ + +/******************************************************************//** +Insert a block in the flush_rbt and returns a pointer to its +predecessor or NULL if no predecessor. The ordering is maintained +on the basis of the <oldest_modification, space, offset> key. +@return pointer to the predecessor or NULL if no predecessor. */ +static +buf_page_t* +buf_flush_insert_in_flush_rbt( +/*==========================*/ + buf_page_t* bpage) /*!< in: bpage to be inserted. */ +{ + const ib_rbt_node_t* c_node; + const ib_rbt_node_t* p_node; + buf_page_t* prev = NULL; + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + + ut_ad(buf_flush_list_mutex_own(buf_pool)); + + /* Insert this buffer into the rbt. */ + c_node = rbt_insert(buf_pool->flush_rbt, &bpage, &bpage); + ut_a(c_node != NULL); + + /* Get the predecessor. */ + p_node = rbt_prev(buf_pool->flush_rbt, c_node); + + if (p_node != NULL) { + prev = *rbt_value(buf_page_t*, p_node); + ut_a(prev != NULL); + } + + return(prev); +} + +/*********************************************************//** +Delete a bpage from the flush_rbt. */ +static +void +buf_flush_delete_from_flush_rbt( +/*============================*/ + buf_page_t* bpage) /*!< in: bpage to be removed. */ +{ + ibool ret = FALSE; + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + + ut_ad(buf_flush_list_mutex_own(buf_pool)); + + ret = rbt_delete(buf_pool->flush_rbt, &bpage); + ut_ad(ret); +} + +/*****************************************************************//** +Compare two modified blocks in the buffer pool. The key for comparison +is: +key = <oldest_modification, space, offset> +This comparison is used to maintian ordering of blocks in the +buf_pool->flush_rbt. +Note that for the purpose of flush_rbt, we only need to order blocks +on the oldest_modification. The other two fields are used to uniquely +identify the blocks. +@return < 0 if b2 < b1, 0 if b2 == b1, > 0 if b2 > b1 */ +static +int +buf_flush_block_cmp( +/*================*/ + const void* p1, /*!< in: block1 */ + const void* p2) /*!< in: block2 */ +{ + int ret; + const buf_page_t* b1 = *(const buf_page_t**) p1; + const buf_page_t* b2 = *(const buf_page_t**) p2; +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(b1); +#endif /* UNIV_DEBUG */ + + ut_ad(b1 != NULL); + ut_ad(b2 != NULL); + + ut_ad(buf_flush_list_mutex_own(buf_pool)); + + ut_ad(b1->in_flush_list); + ut_ad(b2->in_flush_list); + + if (b2->oldest_modification > b1->oldest_modification) { + return(1); + } else if (b2->oldest_modification < b1->oldest_modification) { + return(-1); + } + + /* If oldest_modification is same then decide on the space. */ + ret = (int)(b2->space - b1->space); + + /* Or else decide ordering on the offset field. */ + return(ret ? ret : (int)(b2->offset - b1->offset)); +} + +/********************************************************************//** +Initialize the red-black tree to speed up insertions into the flush_list +during recovery process. Should be called at the start of recovery +process before any page has been read/written. */ +UNIV_INTERN +void +buf_flush_init_flush_rbt(void) +/*==========================*/ +{ + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + buf_flush_list_mutex_enter(buf_pool); + + /* Create red black tree for speedy insertions in flush list. */ + buf_pool->flush_rbt = rbt_create( + sizeof(buf_page_t*), buf_flush_block_cmp); + + buf_flush_list_mutex_exit(buf_pool); + } +} + +/********************************************************************//** +Frees up the red-black tree. */ +UNIV_INTERN +void +buf_flush_free_flush_rbt(void) +/*==========================*/ +{ + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + buf_flush_list_mutex_enter(buf_pool); + +#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG + ut_a(buf_flush_validate_low(buf_pool)); #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ + rbt_free(buf_pool->flush_rbt); + buf_pool->flush_rbt = NULL; + + buf_flush_list_mutex_exit(buf_pool); + } +} + /********************************************************************//** Inserts a modified block into the flush list. */ UNIV_INTERN void buf_flush_insert_into_flush_list( /*=============================*/ - buf_block_t* block) /*!< in/out: block which is modified */ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + buf_block_t* block, /*!< in/out: block which is modified */ + ib_uint64_t lsn) /*!< in: oldest modification */ { - ut_ad(buf_pool_mutex_own()); + ut_ad(!buf_pool_mutex_own(buf_pool)); + ut_ad(log_flush_order_mutex_own()); + ut_ad(mutex_own(&block->mutex)); + + buf_flush_list_mutex_enter(buf_pool); + ut_ad((UT_LIST_GET_FIRST(buf_pool->flush_list) == NULL) || (UT_LIST_GET_FIRST(buf_pool->flush_list)->oldest_modification - <= block->page.oldest_modification)); + <= lsn)); + + /* If we are in the recovery then we need to update the flush + red-black tree as well. */ + if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) { + buf_flush_list_mutex_exit(buf_pool); + buf_flush_insert_sorted_into_flush_list(buf_pool, block, lsn); + return; + } ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); - ut_ad(block->page.in_LRU_list); - ut_ad(block->page.in_page_hash); - ut_ad(!block->page.in_zip_hash); ut_ad(!block->page.in_flush_list); + ut_d(block->page.in_flush_list = TRUE); + block->page.oldest_modification = lsn; UT_LIST_ADD_FIRST(list, buf_pool->flush_list, &block->page); +#ifdef UNIV_DEBUG_VALGRIND + { + ulint zip_size = buf_block_get_zip_size(block); + + if (UNIV_UNLIKELY(zip_size)) { + UNIV_MEM_ASSERT_RW(block->page.zip.data, zip_size); + } else { + UNIV_MEM_ASSERT_RW(block->frame, UNIV_PAGE_SIZE); + } + } +#endif /* UNIV_DEBUG_VALGRIND */ #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG - ut_a(buf_flush_validate_low()); + ut_a(buf_flush_validate_low(buf_pool)); #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ + + buf_flush_list_mutex_exit(buf_pool); } /********************************************************************//** @@ -121,27 +297,74 @@ UNIV_INTERN void buf_flush_insert_sorted_into_flush_list( /*====================================*/ - buf_block_t* block) /*!< in/out: block which is modified */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + buf_block_t* block, /*!< in/out: block which is modified */ + ib_uint64_t lsn) /*!< in: oldest modification */ { buf_page_t* prev_b; buf_page_t* b; - ut_ad(buf_pool_mutex_own()); + ut_ad(!buf_pool_mutex_own(buf_pool)); + ut_ad(log_flush_order_mutex_own()); + ut_ad(mutex_own(&block->mutex)); ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); + buf_flush_list_mutex_enter(buf_pool); + + /* The field in_LRU_list is protected by buf_pool_mutex, which + we are not holding. However, while a block is in the flush + list, it is dirty and cannot be discarded, not from the + page_hash or from the LRU list. At most, the uncompressed + page frame of a compressed block may be discarded or created + (copying the block->page to or from a buf_page_t that is + dynamically allocated from buf_buddy_alloc()). Because those + transitions hold block->mutex and the flush list mutex (via + buf_flush_relocate_on_flush_list()), there is no possibility + of a race condition in the assertions below. */ ut_ad(block->page.in_LRU_list); ut_ad(block->page.in_page_hash); + /* buf_buddy_block_register() will take a block in the + BUF_BLOCK_MEMORY state, not a file page. */ ut_ad(!block->page.in_zip_hash); + ut_ad(!block->page.in_flush_list); ut_d(block->page.in_flush_list = TRUE); + block->page.oldest_modification = lsn; + +#ifdef UNIV_DEBUG_VALGRIND + { + ulint zip_size = buf_block_get_zip_size(block); + + if (UNIV_UNLIKELY(zip_size)) { + UNIV_MEM_ASSERT_RW(block->page.zip.data, zip_size); + } else { + UNIV_MEM_ASSERT_RW(block->frame, UNIV_PAGE_SIZE); + } + } +#endif /* UNIV_DEBUG_VALGRIND */ prev_b = NULL; - b = UT_LIST_GET_FIRST(buf_pool->flush_list); - while (b && b->oldest_modification > block->page.oldest_modification) { - ut_ad(b->in_flush_list); - prev_b = b; - b = UT_LIST_GET_NEXT(list, b); + /* For the most part when this function is called the flush_rbt + should not be NULL. In a very rare boundary case it is possible + that the flush_rbt has already been freed by the recovery thread + before the last page was hooked up in the flush_list by the + io-handler thread. In that case we'll just do a simple + linear search in the else block. */ + if (buf_pool->flush_rbt) { + + prev_b = buf_flush_insert_in_flush_rbt(&block->page); + + } else { + + b = UT_LIST_GET_FIRST(buf_pool->flush_list); + + while (b && b->oldest_modification + > block->page.oldest_modification) { + ut_ad(b->in_flush_list); + prev_b = b; + b = UT_LIST_GET_NEXT(list, b); + } } if (prev_b == NULL) { @@ -152,8 +375,10 @@ buf_flush_insert_sorted_into_flush_list( } #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG - ut_a(buf_flush_validate_low()); + ut_a(buf_flush_validate_low(buf_pool)); #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ + + buf_flush_list_mutex_exit(buf_pool); } /********************************************************************//** @@ -167,7 +392,10 @@ buf_flush_ready_for_replace( buf_page_t* bpage) /*!< in: buffer control block, must be buf_page_in_file(bpage) and in the LRU list */ { - ut_ad(buf_pool_mutex_own()); +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(buf_pool_mutex_own(buf_pool)); +#endif ut_ad(mutex_own(buf_page_get_mutex(bpage))); ut_ad(bpage->in_LRU_list); @@ -200,8 +428,11 @@ buf_flush_ready_for_flush( buf_page_in_file(bpage) */ enum buf_flush flush_type)/*!< in: BUF_FLUSH_LRU or BUF_FLUSH_LIST */ { +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(buf_pool_mutex_own(buf_pool)); +#endif ut_a(buf_page_in_file(bpage)); - ut_ad(buf_pool_mutex_own()); ut_ad(mutex_own(buf_page_get_mutex(bpage))); ut_ad(flush_type == BUF_FLUSH_LRU || BUF_FLUSH_LIST); @@ -234,14 +465,17 @@ buf_flush_remove( /*=============*/ buf_page_t* bpage) /*!< in: pointer to the block in question */ { - ut_ad(buf_pool_mutex_own()); + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + + ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(mutex_own(buf_page_get_mutex(bpage))); ut_ad(bpage->in_flush_list); - ut_d(bpage->in_flush_list = FALSE); + + buf_flush_list_mutex_enter(buf_pool); switch (buf_page_get_state(bpage)) { case BUF_BLOCK_ZIP_PAGE: - /* clean compressed pages should not be on the flush list */ + /* Clean compressed pages should not be on the flush list */ case BUF_BLOCK_ZIP_FREE: case BUF_BLOCK_NOT_USED: case BUF_BLOCK_READY_FOR_USE: @@ -259,10 +493,100 @@ buf_flush_remove( break; } + /* If the flush_rbt is active then delete from there as well. */ + if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) { + buf_flush_delete_from_flush_rbt(bpage); + } + + /* Must be done after we have removed it from the flush_rbt + because we assert on in_flush_list in comparison function. */ + ut_d(bpage->in_flush_list = FALSE); + bpage->oldest_modification = 0; - ut_d(UT_LIST_VALIDATE(list, buf_page_t, buf_pool->flush_list, - ut_ad(ut_list_node_313->in_flush_list))); +#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG + ut_a(buf_flush_validate_low(buf_pool)); +#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ + + buf_flush_list_mutex_exit(buf_pool); +} + +/*******************************************************************//** +Relocates a buffer control block on the flush_list. +Note that it is assumed that the contents of bpage have already been +copied to dpage. +IMPORTANT: When this function is called bpage and dpage are not +exact copies of each other. For example, they both will have different +::state. Also the ::list pointers in dpage may be stale. We need to +use the current list node (bpage) to do the list manipulation because +the list pointers could have changed between the time that we copied +the contents of bpage to the dpage and the flush list manipulation +below. */ +UNIV_INTERN +void +buf_flush_relocate_on_flush_list( +/*=============================*/ + buf_page_t* bpage, /*!< in/out: control block being moved */ + buf_page_t* dpage) /*!< in/out: destination block */ +{ + buf_page_t* prev; + buf_page_t* prev_b = NULL; + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + + ut_ad(buf_pool_mutex_own(buf_pool)); + /* Must reside in the same buffer pool. */ + ut_ad(buf_pool == buf_pool_from_bpage(dpage)); + + ut_ad(mutex_own(buf_page_get_mutex(bpage))); + + buf_flush_list_mutex_enter(buf_pool); + + /* FIXME: At this point we have both buf_pool and flush_list + mutexes. Theoretically removal of a block from flush list is + only covered by flush_list mutex but currently we do + have buf_pool mutex in buf_flush_remove() therefore this block + is guaranteed to be in the flush list. We need to check if + this will work without the assumption of block removing code + having the buf_pool mutex. */ + ut_ad(bpage->in_flush_list); + ut_ad(dpage->in_flush_list); + + /* If recovery is active we must swap the control blocks in + the flush_rbt as well. */ + if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) { + buf_flush_delete_from_flush_rbt(bpage); + prev_b = buf_flush_insert_in_flush_rbt(dpage); + } + + /* Must be done after we have removed it from the flush_rbt + because we assert on in_flush_list in comparison function. */ + ut_d(bpage->in_flush_list = FALSE); + + prev = UT_LIST_GET_PREV(list, bpage); + UT_LIST_REMOVE(list, buf_pool->flush_list, bpage); + + if (prev) { + ut_ad(prev->in_flush_list); + UT_LIST_INSERT_AFTER( + list, + buf_pool->flush_list, + prev, dpage); + } else { + UT_LIST_ADD_FIRST( + list, + buf_pool->flush_list, + dpage); + } + + /* Just an extra check. Previous in flush_list + should be the same control block as in flush_rbt. */ + ut_a(!buf_pool->flush_rbt || prev_b == prev); + +#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG + ut_a(buf_flush_validate_low(buf_pool)); +#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ + + buf_flush_list_mutex_exit(buf_pool); } /********************************************************************//** @@ -274,6 +598,7 @@ buf_flush_write_complete( buf_page_t* bpage) /*!< in: pointer to the block in question */ { enum buf_flush flush_type; + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); ut_ad(bpage); @@ -294,8 +619,8 @@ buf_flush_write_complete( /* fprintf(stderr, "n pending flush %lu\n", buf_pool->n_flush[flush_type]); */ - if ((buf_pool->n_flush[flush_type] == 0) - && (buf_pool->init_flush[flush_type] == FALSE)) { + if (buf_pool->n_flush[flush_type] == 0 + && buf_pool->init_flush[flush_type] == FALSE) { /* The running flush batch has ended */ @@ -588,6 +913,7 @@ try_again: zip_size = buf_page_get_zip_size(bpage); if (UNIV_UNLIKELY(zip_size)) { + UNIV_MEM_ASSERT_RW(bpage->zip.data, zip_size); /* Copy the compressed page and clear the rest. */ memcpy(trx_doublewrite->write_buf + UNIV_PAGE_SIZE * trx_doublewrite->first_free, @@ -597,6 +923,8 @@ try_again: + zip_size, 0, UNIV_PAGE_SIZE - zip_size); } else { ut_a(buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); + UNIV_MEM_ASSERT_RW(((buf_block_t*) bpage)->frame, + UNIV_PAGE_SIZE); memcpy(trx_doublewrite->write_buf + UNIV_PAGE_SIZE * trx_doublewrite->first_free, @@ -711,6 +1039,12 @@ buf_flush_write_block_low( { ulint zip_size = buf_page_get_zip_size(bpage); page_t* frame = NULL; + +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(!buf_pool_mutex_own(buf_pool)); +#endif + #ifdef UNIV_LOG_DEBUG static ibool univ_log_debug_warned; #endif /* UNIV_LOG_DEBUG */ @@ -722,7 +1056,8 @@ buf_flush_write_block_low( io_fixed and oldest_modification != 0. Thus, it cannot be relocated in the buffer pool or removed from flush_list or LRU_list. */ - ut_ad(!buf_pool_mutex_own()); + ut_ad(!buf_pool_mutex_own(buf_pool)); + ut_ad(!buf_flush_list_mutex_own(buf_pool)); ut_ad(!mutex_own(buf_page_get_mutex(bpage))); ut_ad(buf_page_get_io_fix(bpage) == BUF_IO_WRITE); ut_ad(bpage->oldest_modification != 0); @@ -791,13 +1126,14 @@ buf_flush_write_block_low( Writes a flushable page asynchronously from the buffer pool to a file. NOTE: in simulated aio we must call os_aio_simulated_wake_handler_threads after we have posted a batch of -writes! NOTE: buf_pool_mutex and buf_page_get_mutex(bpage) must be +writes! NOTE: buf_pool->mutex and buf_page_get_mutex(bpage) must be held upon entering this function, and they will be released by this function. */ static void buf_flush_page( /*===========*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ buf_page_t* bpage, /*!< in: buffer control block */ enum buf_flush flush_type) /*!< in: BUF_FLUSH_LRU or BUF_FLUSH_LIST */ @@ -806,7 +1142,7 @@ buf_flush_page( ibool is_uncompressed; ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(buf_page_in_file(bpage)); block_mutex = buf_page_get_mutex(bpage); @@ -826,7 +1162,7 @@ buf_flush_page( buf_pool->n_flush[flush_type]++; is_uncompressed = (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE); - ut_ad(is_uncompressed == (block_mutex != &buf_pool_zip_mutex)); + ut_ad(is_uncompressed == (block_mutex != &buf_pool->zip_mutex)); switch (flush_type) { ibool is_s_latched; @@ -842,7 +1178,7 @@ buf_flush_page( } mutex_exit(block_mutex); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); /* Even though bpage is not protected by any mutex at this point, it is safe to access bpage, because it is @@ -879,7 +1215,7 @@ buf_flush_page( immediately. */ mutex_exit(block_mutex); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); break; default: @@ -913,25 +1249,30 @@ buf_flush_try_neighbors( enum buf_flush flush_type) /*!< in: BUF_FLUSH_LRU or BUF_FLUSH_LIST */ { - buf_page_t* bpage; - ulint low, high; - ulint count = 0; ulint i; + ulint low; + ulint high; + ulint count = 0; + buf_pool_t* buf_pool = buf_pool_get(space, offset); ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST); if (UT_LIST_GET_LEN(buf_pool->LRU) < BUF_LRU_OLD_MIN_LEN) { - /* If there is little space, it is better not to flush any - block except from the end of the LRU list */ + /* If there is little space, it is better not to flush + any block except from the end of the LRU list */ low = offset; high = offset + 1; } else { - /* When flushed, dirty blocks are searched in neighborhoods of - this size, and flushed along with the original page. */ + /* When flushed, dirty blocks are searched in + neighborhoods of this size, and flushed along with the + original page. */ - ulint buf_flush_area = ut_min(BUF_READ_AHEAD_AREA, - buf_pool->curr_size / 16); + ulint buf_flush_area; + + buf_flush_area = ut_min( + BUF_READ_AHEAD_AREA(buf_pool), + buf_pool->curr_size / 16); low = (offset / buf_flush_area) * buf_flush_area; high = (offset / buf_flush_area + 1) * buf_flush_area; @@ -943,14 +1284,20 @@ buf_flush_try_neighbors( high = fil_space_get_size(space); } - buf_pool_mutex_enter(); - for (i = low; i < high; i++) { - bpage = buf_page_hash_get(space, i); + buf_page_t* bpage; + + buf_pool = buf_pool_get(space, i); + + buf_pool_mutex_enter(buf_pool); + + /* We only want to flush pages from this buffer pool. */ + bpage = buf_page_hash_get(buf_pool, space, i); if (!bpage) { + buf_pool_mutex_exit(buf_pool); continue; } @@ -969,25 +1316,231 @@ buf_flush_try_neighbors( if (buf_flush_ready_for_flush(bpage, flush_type) && (i == offset || !bpage->buf_fix_count)) { /* We only try to flush those - neighbors != offset where the buf fix count is - zero, as we then know that we probably can - latch the page without a semaphore wait. - Semaphore waits are expensive because we must - flush the doublewrite buffer before we start + neighbors != offset where the buf fix + count is zero, as we then know that we + probably can latch the page without a + semaphore wait. Semaphore waits are + expensive because we must flush the + doublewrite buffer before we start waiting. */ - buf_flush_page(bpage, flush_type); + buf_flush_page(buf_pool, bpage, flush_type); ut_ad(!mutex_own(block_mutex)); + ut_ad(!buf_pool_mutex_own(buf_pool)); count++; - - buf_pool_mutex_enter(); + continue; } else { mutex_exit(block_mutex); } } + buf_pool_mutex_exit(buf_pool); } - buf_pool_mutex_exit(); + return(count); +} + +/********************************************************************//** +Check if the block is modified and ready for flushing. If the the block +is ready to flush then flush the page and try o flush its neighbors. + +@return TRUE if buf_pool mutex was not released during this function. +This does not guarantee that some pages were written as well. +Number of pages written are incremented to the count. */ +static +ibool +buf_flush_page_and_try_neighbors( +/*=============================*/ + buf_page_t* bpage, /*!< in: buffer control block, + must be + buf_page_in_file(bpage) */ + enum buf_flush flush_type, /*!< in: BUF_FLUSH_LRU + or BUF_FLUSH_LIST */ + ulint* count) /*!< in/out: number of pages + flushed */ +{ + mutex_t* block_mutex; + ibool flushed = FALSE; +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); +#endif /* UNIV_DEBUG */ + + ut_ad(buf_pool_mutex_own(buf_pool)); + + block_mutex = buf_page_get_mutex(bpage); + mutex_enter(block_mutex); + + ut_a(buf_page_in_file(bpage)); + + if (buf_flush_ready_for_flush(bpage, flush_type)) { + ulint space; + ulint offset; + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_bpage(bpage); + + buf_pool_mutex_exit(buf_pool); + + /* These fields are protected by both the + buffer pool mutex and block mutex. */ + space = buf_page_get_space(bpage); + offset = buf_page_get_page_no(bpage); + + mutex_exit(block_mutex); + + /* Try to flush also all the neighbors */ + *count += buf_flush_try_neighbors(space, offset, flush_type); + + buf_pool_mutex_enter(buf_pool); + flushed = TRUE; + } else { + mutex_exit(block_mutex); + } + + ut_ad(buf_pool_mutex_own(buf_pool)); + + return(flushed); +} + +/*******************************************************************//** +This utility flushes dirty blocks from the end of the LRU list. +In the case of an LRU flush the calling thread may own latches to +pages: to avoid deadlocks, this function must be written so that it +cannot end up waiting for these latches! +@return number of blocks for which the write request was queued. */ +static +ulint +buf_flush_LRU_list_batch( +/*=====================*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint max) /*!< in: max of blocks to flush */ +{ + buf_page_t* bpage; + ulint count = 0; + + ut_ad(buf_pool_mutex_own(buf_pool)); + + do { + /* Start from the end of the list looking for a + suitable block to be flushed. */ + bpage = UT_LIST_GET_LAST(buf_pool->LRU); + + /* Iterate backwards over the flush list till we find + a page that isn't ready for flushing. */ + while (bpage != NULL + && !buf_flush_page_and_try_neighbors( + bpage, BUF_FLUSH_LRU, &count)) { + + bpage = UT_LIST_GET_PREV(LRU, bpage); + } + } while (bpage != NULL && count < max); + + /* We keep track of all flushes happening as part of LRU + flush. When estimating the desired rate at which flush_list + should be flushed, we factor in this value. */ + buf_lru_flush_page_count += count; + + ut_ad(buf_pool_mutex_own(buf_pool)); + + return(count); +} + +/*******************************************************************//** +This utility flushes dirty blocks from the end of the flush_list. +the calling thread is not allowed to own any latches on pages! +@return number of blocks for which the write request was queued; +ULINT_UNDEFINED if there was a flush of the same type already +running */ +static +ulint +buf_flush_flush_list_batch( +/*=======================*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint min_n, /*!< in: wished minimum mumber + of blocks flushed (it is not + guaranteed that the actual + number is that big, though) */ + ib_uint64_t lsn_limit) /*!< all blocks whose + oldest_modification is smaller + than this should be flushed (if + their number does not exceed + min_n) */ +{ + ulint len; + buf_page_t* bpage; + ulint count = 0; + + ut_ad(buf_pool_mutex_own(buf_pool)); + + /* If we have flushed enough, leave the loop */ + do { + /* Start from the end of the list looking for a suitable + block to be flushed. */ + + buf_flush_list_mutex_enter(buf_pool); + + /* We use len here because theoretically insertions can + happen in the flush_list below while we are traversing + it for a suitable candidate for flushing. We'd like to + set a limit on how farther we are willing to traverse + the list. */ + len = UT_LIST_GET_LEN(buf_pool->flush_list); + bpage = UT_LIST_GET_LAST(buf_pool->flush_list); + + if (bpage) { + ut_a(bpage->oldest_modification > 0); + } + + if (!bpage || bpage->oldest_modification >= lsn_limit) { + + /* We have flushed enough */ + buf_flush_list_mutex_exit(buf_pool); + break; + } + + ut_a(bpage->oldest_modification > 0); + + ut_ad(bpage->in_flush_list); + + buf_flush_list_mutex_exit(buf_pool); + + /* The list may change during the flushing and we cannot + safely preserve within this function a pointer to a + block in the list! */ + while (bpage != NULL + && len > 0 + && !buf_flush_page_and_try_neighbors( + bpage, BUF_FLUSH_LIST, &count)) { + + buf_flush_list_mutex_enter(buf_pool); + + /* If we are here that means that buf_pool->mutex + was not released in buf_flush_page_and_try_neighbors() + above and this guarantees that bpage didn't get + relocated since we released the flush_list + mutex above. There is a chance, however, that + the bpage got removed from flush_list (not + currently possible because flush_list_remove() + also obtains buf_pool mutex but that may change + in future). To avoid this scenario we check + the oldest_modification and if it is zero + we start all over again. */ + if (bpage->oldest_modification == 0) { + buf_flush_list_mutex_exit(buf_pool); + break; + } + + bpage = UT_LIST_GET_PREV(list, bpage); + + ut_ad(!bpage || bpage->in_flush_list); + + buf_flush_list_mutex_exit(buf_pool); + + --len; + } + + } while (count < min_n && bpage != NULL && len > 0); + + ut_ad(buf_pool_mutex_own(buf_pool)); return(count); } @@ -1000,10 +1553,11 @@ end up waiting for these latches! NOTE 2: in the case of a flush list flush, the calling thread is not allowed to own any latches on pages! @return number of blocks for which the write request was queued; ULINT_UNDEFINED if there was a flush of the same type already running */ -UNIV_INTERN +static ulint buf_flush_batch( /*============*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ enum buf_flush flush_type, /*!< in: BUF_FLUSH_LRU or BUF_FLUSH_LIST; if BUF_FLUSH_LIST, then the caller must not own any @@ -1011,113 +1565,125 @@ buf_flush_batch( ulint min_n, /*!< in: wished minimum mumber of blocks flushed (it is not guaranteed that the actual number is that big, though) */ - ib_uint64_t lsn_limit) /*!< in the case BUF_FLUSH_LIST all - blocks whose oldest_modification is + ib_uint64_t lsn_limit) /*!< in: in the case of BUF_FLUSH_LIST + all blocks whose oldest_modification is smaller than this should be flushed (if their number does not exceed min_n), otherwise ignored */ { - buf_page_t* bpage; - ulint page_count = 0; - ulint old_page_count; - ulint space; - ulint offset; + ulint count = 0; - ut_ad((flush_type == BUF_FLUSH_LRU) - || (flush_type == BUF_FLUSH_LIST)); + ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST); #ifdef UNIV_SYNC_DEBUG ut_ad((flush_type != BUF_FLUSH_LIST) || sync_thread_levels_empty_gen(TRUE)); #endif /* UNIV_SYNC_DEBUG */ - buf_pool_mutex_enter(); - if ((buf_pool->n_flush[flush_type] > 0) - || (buf_pool->init_flush[flush_type] == TRUE)) { - - /* There is already a flush batch of the same type running */ + buf_pool_mutex_enter(buf_pool); - buf_pool_mutex_exit(); - - return(ULINT_UNDEFINED); + /* Note: The buffer pool mutex is released and reacquired within + the flush functions. */ + switch(flush_type) { + case BUF_FLUSH_LRU: + count = buf_flush_LRU_list_batch(buf_pool, min_n); + break; + case BUF_FLUSH_LIST: + count = buf_flush_flush_list_batch(buf_pool, min_n, lsn_limit); + break; + default: + ut_error; } - buf_pool->init_flush[flush_type] = TRUE; + buf_pool_mutex_exit(buf_pool); - for (;;) { -flush_next: - /* If we have flushed enough, leave the loop */ - if (page_count >= min_n) { + buf_flush_buffered_writes(); - break; - } +#ifdef UNIV_DEBUG + if (buf_debug_prints && count > 0) { + fprintf(stderr, flush_type == BUF_FLUSH_LRU + ? "Flushed %lu pages in LRU flush\n" + : "Flushed %lu pages in flush list flush\n", + (ulong) count); + } +#endif /* UNIV_DEBUG */ - /* Start from the end of the list looking for a suitable - block to be flushed. */ + srv_buf_pool_flushed += count; - if (flush_type == BUF_FLUSH_LRU) { - bpage = UT_LIST_GET_LAST(buf_pool->LRU); - } else { - ut_ad(flush_type == BUF_FLUSH_LIST); - - bpage = UT_LIST_GET_LAST(buf_pool->flush_list); - if (!bpage - || bpage->oldest_modification >= lsn_limit) { - /* We have flushed enough */ + return(count); +} - break; - } - ut_ad(bpage->in_flush_list); - } +/******************************************************************//** +Gather the aggregated stats for both flush list and LRU list flushing */ +static +void +buf_flush_common( +/*=============*/ + enum buf_flush flush_type, /*!< in: type of flush */ + ulint page_count) /*!< in: number of pages flushed */ +{ + buf_flush_buffered_writes(); - /* Note that after finding a single flushable page, we try to - flush also all its neighbors, and after that start from the - END of the LRU list or flush list again: the list may change - during the flushing and we cannot safely preserve within this - function a pointer to a block in the list! */ + ut_a(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST); - do { - mutex_t*block_mutex = buf_page_get_mutex(bpage); - ibool ready; +#ifdef UNIV_DEBUG + if (buf_debug_prints && page_count > 0) { + fprintf(stderr, flush_type == BUF_FLUSH_LRU + ? "Flushed %lu pages in LRU flush\n" + : "Flushed %lu pages in flush list flush\n", + (ulong) page_count); + } +#endif /* UNIV_DEBUG */ - ut_a(buf_page_in_file(bpage)); + srv_buf_pool_flushed += page_count; - mutex_enter(block_mutex); - ready = buf_flush_ready_for_flush(bpage, flush_type); - mutex_exit(block_mutex); + if (flush_type == BUF_FLUSH_LRU) { + /* We keep track of all flushes happening as part of LRU + flush. When estimating the desired rate at which flush_list + should be flushed we factor in this value. */ + buf_lru_flush_page_count += page_count; + } +} - if (ready) { - space = buf_page_get_space(bpage); - offset = buf_page_get_page_no(bpage); +/******************************************************************//** +Start a buffer flush batch for LRU or flush list */ +static +ibool +buf_flush_start( +/*============*/ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + enum buf_flush flush_type) /*!< in: BUF_FLUSH_LRU + or BUF_FLUSH_LIST */ +{ + buf_pool_mutex_enter(buf_pool); - buf_pool_mutex_exit(); + if (buf_pool->n_flush[flush_type] > 0 + || buf_pool->init_flush[flush_type] == TRUE) { - old_page_count = page_count; + /* There is already a flush batch of the same type running */ - /* Try to flush also all the neighbors */ - page_count += buf_flush_try_neighbors( - space, offset, flush_type); - /* fprintf(stderr, - "Flush type %lu, page no %lu, neighb %lu\n", - flush_type, offset, - page_count - old_page_count); */ + buf_pool_mutex_exit(buf_pool); - buf_pool_mutex_enter(); - goto flush_next; + return(FALSE); + } - } else if (flush_type == BUF_FLUSH_LRU) { - bpage = UT_LIST_GET_PREV(LRU, bpage); - } else { - ut_ad(flush_type == BUF_FLUSH_LIST); + buf_pool->init_flush[flush_type] = TRUE; - bpage = UT_LIST_GET_PREV(list, bpage); - ut_ad(!bpage || bpage->in_flush_list); - } - } while (bpage != NULL); + buf_pool_mutex_exit(buf_pool); - /* If we could not find anything to flush, leave the loop */ + return(TRUE); +} - break; - } +/******************************************************************//** +End a buffer flush batch for LRU or flush list */ +static +void +buf_flush_end( +/*==========*/ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + enum buf_flush flush_type) /*!< in: BUF_FLUSH_LRU + or BUF_FLUSH_LIST */ +{ + buf_pool_mutex_enter(buf_pool); buf_pool->init_flush[flush_type] = FALSE; @@ -1128,46 +1694,136 @@ flush_next: os_event_set(buf_pool->no_flush[flush_type]); } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); +} - buf_flush_buffered_writes(); +/******************************************************************//** +Waits until a flush batch of the given type ends */ +UNIV_INTERN +void +buf_flush_wait_batch_end( +/*=====================*/ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + enum buf_flush type) /*!< in: BUF_FLUSH_LRU + or BUF_FLUSH_LIST */ +{ + ut_ad(type == BUF_FLUSH_LRU || type == BUF_FLUSH_LIST); -#ifdef UNIV_DEBUG - if (buf_debug_prints && page_count > 0) { - ut_a(flush_type == BUF_FLUSH_LRU - || flush_type == BUF_FLUSH_LIST); - fprintf(stderr, flush_type == BUF_FLUSH_LRU - ? "Flushed %lu pages in LRU flush\n" - : "Flushed %lu pages in flush list flush\n", - (ulong) page_count); + if (buf_pool == NULL) { + ulint i; + + for (i = 0; i < srv_buf_pool_instances; ++i) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + os_event_wait(buf_pool->no_flush[type]); + } + } else { + os_event_wait(buf_pool->no_flush[type]); } -#endif /* UNIV_DEBUG */ +} - srv_buf_pool_flushed += page_count; +/*******************************************************************//** +This utility flushes dirty blocks from the end of the LRU list. +NOTE: The calling thread may own latches to pages: to avoid deadlocks, +this function must be written so that it cannot end up waiting for these +latches! +@return number of blocks for which the write request was queued; +ULINT_UNDEFINED if there was a flush of the same type already running */ +UNIV_INTERN +ulint +buf_flush_LRU( +/*==========*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint min_n) /*!< in: wished minimum mumber of blocks + flushed (it is not guaranteed that the + actual number is that big, though) */ +{ + ulint page_count; - /* We keep track of all flushes happening as part of LRU - flush. When estimating the desired rate at which flush_list - should be flushed we factor in this value. */ - if (flush_type == BUF_FLUSH_LRU) { - buf_lru_flush_page_count += page_count; + if (!buf_flush_start(buf_pool, BUF_FLUSH_LRU)) { + return(ULINT_UNDEFINED); } + page_count = buf_flush_batch(buf_pool, BUF_FLUSH_LRU, min_n, 0); + + buf_flush_end(buf_pool, BUF_FLUSH_LRU); + + buf_flush_common(BUF_FLUSH_LRU, page_count); + return(page_count); } -/******************************************************************//** -Waits until a flush batch of the given type ends */ +/*******************************************************************//** +This utility flushes dirty blocks from the end of the flush list of +all buffer pool instances. +NOTE: The calling thread is not allowed to own any latches on pages! +@return number of blocks for which the write request was queued; +ULINT_UNDEFINED if there was a flush of the same type already running */ UNIV_INTERN -void -buf_flush_wait_batch_end( -/*=====================*/ - enum buf_flush type) /*!< in: BUF_FLUSH_LRU or BUF_FLUSH_LIST */ +ulint +buf_flush_list( +/*===========*/ + ulint min_n, /*!< in: wished minimum mumber of blocks + flushed (it is not guaranteed that the + actual number is that big, though) */ + ib_uint64_t lsn_limit) /*!< in the case BUF_FLUSH_LIST all + blocks whose oldest_modification is + smaller than this should be flushed + (if their number does not exceed + min_n), otherwise ignored */ { - ut_ad((type == BUF_FLUSH_LRU) || (type == BUF_FLUSH_LIST)); + ulint i; + ulint total_page_count = 0; + ibool skipped = FALSE; + + if (min_n != ULINT_MAX) { + /* Ensure that flushing is spread evenly amongst the + buffer pool instances. When min_n is ULINT_MAX + we need to flush everything up to the lsn limit + so no limit here. */ + min_n = (min_n + srv_buf_pool_instances - 1) + / srv_buf_pool_instances; + } - os_event_wait(buf_pool->no_flush[type]); -} + /* Flush to lsn_limit in all buffer pool instances */ + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + ulint page_count = 0; + + buf_pool = buf_pool_from_array(i); + + if (!buf_flush_start(buf_pool, BUF_FLUSH_LIST)) { + /* We have two choices here. If lsn_limit was + specified then skipping an instance of buffer + pool means we cannot guarantee that all pages + up to lsn_limit has been flushed. We can + return right now with failure or we can try + to flush remaining buffer pools up to the + lsn_limit. We attempt to flush other buffer + pools based on the assumption that it will + help in the retry which will follow the + failure. */ + skipped = TRUE; + + continue; + } + + page_count = buf_flush_batch( + buf_pool, BUF_FLUSH_LIST, min_n, lsn_limit); + + buf_flush_end(buf_pool, BUF_FLUSH_LIST); + buf_flush_common(BUF_FLUSH_LIST, page_count); + + total_page_count += page_count; + } + + return(lsn_limit != IB_ULONGLONG_MAX && skipped + ? ULINT_UNDEFINED : total_page_count); +} + /******************************************************************//** Gives a recommendation of how many blocks should be flushed to establish a big enough margin of replaceable blocks near the end of the LRU list @@ -1176,23 +1832,24 @@ and in the free list. LRU list */ static ulint -buf_flush_LRU_recommendation(void) -/*==============================*/ +buf_flush_LRU_recommendation( +/*=========================*/ + buf_pool_t* buf_pool) /*!< in: Buffer pool instance */ { buf_page_t* bpage; ulint n_replaceable; ulint distance = 0; - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); n_replaceable = UT_LIST_GET_LEN(buf_pool->free); bpage = UT_LIST_GET_LAST(buf_pool->LRU); while ((bpage != NULL) - && (n_replaceable < BUF_FLUSH_FREE_BLOCK_MARGIN - + BUF_FLUSH_EXTRA_MARGIN) - && (distance < BUF_LRU_FREE_SEARCH_LEN)) { + && (n_replaceable < BUF_FLUSH_FREE_BLOCK_MARGIN(buf_pool) + + BUF_FLUSH_EXTRA_MARGIN(buf_pool)) + && (distance < BUF_LRU_FREE_SEARCH_LEN(buf_pool))) { mutex_t* block_mutex = buf_page_get_mutex(bpage); @@ -1209,14 +1866,15 @@ buf_flush_LRU_recommendation(void) bpage = UT_LIST_GET_PREV(LRU, bpage); } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); - if (n_replaceable >= BUF_FLUSH_FREE_BLOCK_MARGIN) { + if (n_replaceable >= BUF_FLUSH_FREE_BLOCK_MARGIN(buf_pool)) { return(0); } - return(BUF_FLUSH_FREE_BLOCK_MARGIN + BUF_FLUSH_EXTRA_MARGIN + return(BUF_FLUSH_FREE_BLOCK_MARGIN(buf_pool) + + BUF_FLUSH_EXTRA_MARGIN(buf_pool) - n_replaceable); } @@ -1228,25 +1886,46 @@ flush only pages such that the s-lock required for flushing can be acquired immediately, without waiting. */ UNIV_INTERN void -buf_flush_free_margin(void) -/*=======================*/ +buf_flush_free_margin( +/*==================*/ + buf_pool_t* buf_pool) /*!< in: Buffer pool instance */ { ulint n_to_flush; - ulint n_flushed; - n_to_flush = buf_flush_LRU_recommendation(); + n_to_flush = buf_flush_LRU_recommendation(buf_pool); if (n_to_flush > 0) { - n_flushed = buf_flush_batch(BUF_FLUSH_LRU, n_to_flush, 0); + ulint n_flushed; + + n_flushed = buf_flush_LRU(buf_pool, n_to_flush); + if (n_flushed == ULINT_UNDEFINED) { /* There was an LRU type flush batch already running; let us wait for it to end */ - buf_flush_wait_batch_end(BUF_FLUSH_LRU); + buf_flush_wait_batch_end(buf_pool, BUF_FLUSH_LRU); } } } +/*********************************************************************//** +Flushes pages from the end of all the LRU lists. */ +UNIV_INTERN +void +buf_flush_free_margins(void) +/*========================*/ +{ + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + buf_flush_free_margin(buf_pool); + } +} + /********************************************************************* Update the historical stats that we are collecting for flush rate heuristics at the end of each interval. @@ -1307,22 +1986,28 @@ ulint buf_flush_get_desired_flush_rate(void) /*==================================*/ { - ulint redo_avg; - ulint lru_flush_avg; - ulint n_dirty; - ulint n_flush_req; - lint rate; - ib_uint64_t lsn = log_get_lsn(); - ulint log_capacity = log_get_capacity(); + ulint i; + lint rate; + ulint redo_avg; + ulint n_dirty = 0; + ulint n_flush_req; + ulint lru_flush_avg; + ib_uint64_t lsn = log_get_lsn(); + ulint log_capacity = log_get_capacity(); /* log_capacity should never be zero after the initialization of log subsystem. */ ut_ad(log_capacity != 0); /* Get total number of dirty pages. It is OK to access - flush_list without holding any mtex as we are using this + flush_list without holding any mutex as we are using this only for heuristics. */ - n_dirty = UT_LIST_GET_LEN(buf_pool->flush_list); + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + n_dirty += UT_LIST_GET_LEN(buf_pool->flush_list); + } /* An overflow can happen if we generate more than 2^32 bytes of redo in this interval i.e.: 4G of redo in 1 second. We can @@ -1364,27 +2049,64 @@ Validates the flush list. @return TRUE if ok */ static ibool -buf_flush_validate_low(void) -/*========================*/ +buf_flush_validate_low( +/*===================*/ + buf_pool_t* buf_pool) /*!< in: Buffer pool instance */ { - buf_page_t* bpage; + buf_page_t* bpage; + const ib_rbt_node_t* rnode = NULL; + + ut_ad(buf_flush_list_mutex_own(buf_pool)); UT_LIST_VALIDATE(list, buf_page_t, buf_pool->flush_list, ut_ad(ut_list_node_313->in_flush_list)); bpage = UT_LIST_GET_FIRST(buf_pool->flush_list); + /* If we are in recovery mode i.e.: flush_rbt != NULL + then each block in the flush_list must also be present + in the flush_rbt. */ + if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) { + rnode = rbt_first(buf_pool->flush_rbt); + } + while (bpage != NULL) { const ib_uint64_t om = bpage->oldest_modification; + + ut_ad(buf_pool_from_bpage(bpage) == buf_pool); + ut_ad(bpage->in_flush_list); - ut_a(buf_page_in_file(bpage)); + + /* A page in flush_list can be in BUF_BLOCK_REMOVE_HASH + state. This happens when a page is in the middle of + being relocated. In that case the original descriptor + can have this state and still be in the flush list + waiting to acquire the flush_list_mutex to complete + the relocation. */ + ut_a(buf_page_in_file(bpage) + || buf_page_get_state(bpage) == BUF_BLOCK_REMOVE_HASH); ut_a(om > 0); + if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) { + buf_page_t* rpage; + + ut_a(rnode); + rpage = *rbt_value(buf_page_t*, rnode); + + ut_a(rpage); + ut_a(rpage == bpage); + rnode = rbt_next(buf_pool->flush_rbt, rnode); + } + bpage = UT_LIST_GET_NEXT(list, bpage); ut_a(!bpage || om >= bpage->oldest_modification); } + /* By this time we must have exhausted the traversal of + flush_rbt (if active) as well. */ + ut_a(rnode == NULL); + return(TRUE); } @@ -1393,16 +2115,17 @@ Validates the flush list. @return TRUE if ok */ UNIV_INTERN ibool -buf_flush_validate(void) -/*====================*/ +buf_flush_validate( +/*===============*/ + buf_pool_t* buf_pool) /*!< buffer pool instance */ { ibool ret; - buf_pool_mutex_enter(); + buf_flush_list_mutex_enter(buf_pool); - ret = buf_flush_validate_low(); + ret = buf_flush_validate_low(buf_pool); - buf_pool_mutex_exit(); + buf_flush_list_mutex_exit(buf_pool); return(ret); } diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c index 4f19fd13fa5..a539c4e894b 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/buf/buf0lru.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. 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 @@ -50,7 +50,7 @@ Created 11/5/1995 Heikki Tuuri #include "srv0srv.h" /** The number of blocks from the LRU_old pointer onward, including -the block pointed to, must be buf_LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV +the block pointed to, must be buf_pool->LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV of the whole LRU list length, except that the tolerance defined below is allowed. Note that the tolerance must be small enough such that for even the BUF_LRU_OLD_MIN_LEN long LRU list, the LRU_old pointer is not @@ -96,8 +96,9 @@ with page_zip_decompress() operations. */ #define BUF_LRU_IO_TO_UNZIP_FACTOR 50 /** Sampled values buf_LRU_stat_cur. -Protected by buf_pool_mutex. Updated by buf_LRU_stat_update(). */ +Not protected by any mutex. Updated by buf_LRU_stat_update(). */ static buf_LRU_stat_t buf_LRU_stat_arr[BUF_LRU_STAT_N_INTERVAL]; + /** Cursor to buf_LRU_stat_arr[] that is updated in a round-robin fashion. */ static ulint buf_LRU_stat_arr_ind; @@ -106,15 +107,12 @@ by buf_LRU_stat_update(). */ UNIV_INTERN buf_LRU_stat_t buf_LRU_stat_cur; /** Running sum of past values of buf_LRU_stat_cur. -Updated by buf_LRU_stat_update(). Protected by buf_pool_mutex. */ +Updated by buf_LRU_stat_update(). Not Protected by any mutex. */ UNIV_INTERN buf_LRU_stat_t buf_LRU_stat_sum; /* @} */ /** @name Heuristics for detecting index scan @{ */ -/** Reserve this much/BUF_LRU_OLD_RATIO_DIV of the buffer pool for -"old" blocks. Protected by buf_pool_mutex. */ -UNIV_INTERN uint buf_LRU_old_ratio; /** Move blocks to "new" LRU list only if the first access was at least this many milliseconds ago. Not protected by any mutex or latch. */ UNIV_INTERN uint buf_LRU_old_threshold_ms; @@ -123,7 +121,7 @@ UNIV_INTERN uint buf_LRU_old_threshold_ms; /******************************************************************//** Takes a block out of the LRU list and page hash table. If the block is compressed-only (BUF_BLOCK_ZIP_PAGE), -the object will be freed and buf_pool_zip_mutex will be released. +the object will be freed and buf_pool->zip_mutex will be released. If a compressed page or a compressed-only block descriptor is freed, other compressed pages or compressed-only block descriptors may be @@ -154,13 +152,14 @@ instead of the general LRU list. @return TRUE if should use unzip_LRU */ UNIV_INLINE ibool -buf_LRU_evict_from_unzip_LRU(void) -/*==============================*/ +buf_LRU_evict_from_unzip_LRU( +/*=========================*/ + buf_pool_t* buf_pool) { ulint io_avg; ulint unzip_avg; - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); /* If the unzip_LRU list is empty, we can only use the LRU. */ if (UT_LIST_GET_LEN(buf_pool->unzip_LRU) == 0) { @@ -228,7 +227,8 @@ static void buf_LRU_drop_page_hash_for_tablespace( /*==================================*/ - ulint id) /*!< in: space id */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint id) /*!< in: space id */ { buf_page_t* bpage; ulint* page_arr; @@ -243,9 +243,10 @@ buf_LRU_drop_page_hash_for_tablespace( return; } - page_arr = ut_malloc(sizeof(ulint) - * BUF_LRU_DROP_SEARCH_HASH_SIZE); - buf_pool_mutex_enter(); + page_arr = ut_malloc( + sizeof(ulint) * BUF_LRU_DROP_SEARCH_HASH_SIZE); + + buf_pool_mutex_enter(buf_pool); scan_again: num_entries = 0; @@ -283,14 +284,17 @@ scan_again: if (num_entries < BUF_LRU_DROP_SEARCH_HASH_SIZE) { goto next_page; } - /* Array full. We release the buf_pool_mutex to + + /* Array full. We release the buf_pool->mutex to obey the latching order. */ - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); + + buf_LRU_drop_page_hash_batch( + id, zip_size, page_arr, num_entries); - buf_LRU_drop_page_hash_batch(id, zip_size, page_arr, - num_entries); num_entries = 0; - buf_pool_mutex_enter(); + + buf_pool_mutex_enter(buf_pool); } else { mutex_exit(block_mutex); } @@ -315,7 +319,7 @@ next_page: } } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); /* Drop any remaining batch of search hashed pages. */ buf_LRU_drop_page_hash_batch(id, zip_size, page_arr, num_entries); @@ -323,44 +327,52 @@ next_page: } /******************************************************************//** -Invalidates all pages belonging to a given tablespace when we are deleting -the data file(s) of that tablespace. */ -UNIV_INTERN +Invalidates all pages belonging to a given tablespace inside a specific +buffer pool instance when we are deleting the data file(s) of that +tablespace. */ +static void -buf_LRU_invalidate_tablespace( -/*==========================*/ - ulint id) /*!< in: space id */ +buf_LRU_invalidate_tablespace_buf_pool_instance( +/*============================================*/ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + ulint id) /*!< in: space id */ { buf_page_t* bpage; ibool all_freed; - /* Before we attempt to drop pages one by one we first - attempt to drop page hash index entries in batches to make - it more efficient. The batching attempt is a best effort - attempt and does not guarantee that all pages hash entries - will be dropped. We get rid of remaining page hash entries - one by one below. */ - buf_LRU_drop_page_hash_for_tablespace(id); - scan_again: - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); all_freed = TRUE; bpage = UT_LIST_GET_LAST(buf_pool->LRU); while (bpage != NULL) { - mutex_t* block_mutex = buf_page_get_mutex(bpage); buf_page_t* prev_bpage; + ibool prev_bpage_buf_fix = FALSE; ut_a(buf_page_in_file(bpage)); - mutex_enter(block_mutex); prev_bpage = UT_LIST_GET_PREV(LRU, bpage); - if (buf_page_get_space(bpage) == id) { - if (bpage->buf_fix_count > 0 - || buf_page_get_io_fix(bpage) != BUF_IO_NONE) { + /* bpage->space and bpage->io_fix are protected by + buf_pool_mutex and block_mutex. It is safe to check + them while holding buf_pool_mutex only. */ + + if (buf_page_get_space(bpage) != id) { + /* Skip this block, as it does not belong to + the space that is being invalidated. */ + } else if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) { + /* We cannot remove this page during this scan + yet; maybe the system is currently reading it + in, or flushing the modifications to the file */ + + all_freed = FALSE; + } else { + mutex_t* block_mutex = buf_page_get_mutex(bpage); + mutex_enter(block_mutex); + + if (bpage->buf_fix_count > 0) { /* We cannot remove this page during this scan yet; maybe the system is @@ -380,12 +392,44 @@ scan_again: (ulong) buf_page_get_page_no(bpage)); } #endif - if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE - && ((buf_block_t*) bpage)->is_hashed) { + if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) { + /* This is a compressed-only block + descriptor. Ensure that prev_bpage + cannot be relocated when bpage is freed. */ + if (UNIV_LIKELY(prev_bpage != NULL)) { + switch (buf_page_get_state( + prev_bpage)) { + case BUF_BLOCK_FILE_PAGE: + /* Descriptors of uncompressed + blocks will not be relocated, + because we are holding the + buf_pool_mutex. */ + break; + case BUF_BLOCK_ZIP_PAGE: + case BUF_BLOCK_ZIP_DIRTY: + /* Descriptors of compressed- + only blocks can be relocated, + unless they are buffer-fixed. + Because both bpage and + prev_bpage are protected by + buf_pool_zip_mutex, it is + not necessary to acquire + further mutexes. */ + ut_ad(&buf_pool->zip_mutex + == block_mutex); + ut_ad(mutex_own(block_mutex)); + prev_bpage_buf_fix = TRUE; + prev_bpage->buf_fix_count++; + break; + default: + ut_error; + } + } + } else if (((buf_block_t*) bpage)->is_hashed) { ulint page_no; ulint zip_size; - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); zip_size = buf_page_get_zip_size(bpage); page_no = buf_page_get_page_no(bpage); @@ -405,7 +449,8 @@ scan_again: buf_flush_remove(bpage); } - /* Remove from the LRU list */ + /* Remove from the LRU list. */ + if (buf_LRU_block_remove_hashed_page(bpage, TRUE) != BUF_BLOCK_ZIP_FREE) { buf_LRU_block_free_hashed_page((buf_block_t*) @@ -414,25 +459,34 @@ scan_again: /* The block_mutex should have been released by buf_LRU_block_remove_hashed_page() when it returns BUF_BLOCK_ZIP_FREE. */ - ut_ad(block_mutex == &buf_pool_zip_mutex); + ut_ad(block_mutex == &buf_pool->zip_mutex); ut_ad(!mutex_own(block_mutex)); - /* The compressed block descriptor - (bpage) has been deallocated and - block_mutex released. Also, - buf_buddy_free() may have relocated - prev_bpage. Rescan the LRU list. */ + if (prev_bpage_buf_fix) { + /* We temporarily buffer-fixed + prev_bpage, so that + buf_buddy_free() could not + relocate it, in case it was a + compressed-only block + descriptor. */ + + mutex_enter(block_mutex); + ut_ad(prev_bpage->buf_fix_count > 0); + prev_bpage->buf_fix_count--; + mutex_exit(block_mutex); + } - bpage = UT_LIST_GET_LAST(buf_pool->LRU); - continue; + goto next_page_no_mutex; } - } next_page: - mutex_exit(block_mutex); + mutex_exit(block_mutex); + } + +next_page_no_mutex: bpage = prev_bpage; } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); if (!all_freed) { os_thread_sleep(20000); @@ -441,6 +495,32 @@ next_page: } } +/******************************************************************//** +Invalidates all pages belonging to a given tablespace when we are deleting +the data file(s) of that tablespace. */ +UNIV_INTERN +void +buf_LRU_invalidate_tablespace( +/*==========================*/ + ulint id) /*!< in: space id */ +{ + ulint i; + + /* Before we attempt to drop pages one by one we first + attempt to drop page hash index entries in batches to make + it more efficient. The batching attempt is a best effort + attempt and does not guarantee that all pages hash entries + will be dropped. We get rid of remaining page hash entries + one by one below. */ + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + buf_LRU_drop_page_hash_for_tablespace(buf_pool, id); + buf_LRU_invalidate_tablespace_buf_pool_instance(buf_pool, id); + } +} + /********************************************************************//** Insert a compressed block into buf_pool->zip_clean in the LRU order. */ UNIV_INTERN @@ -450,8 +530,9 @@ buf_LRU_insert_zip_clean( buf_page_t* bpage) /*!< in: pointer to the block in question */ { buf_page_t* b; + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_PAGE); /* Find the first successor of bpage in the LRU list @@ -481,16 +562,19 @@ UNIV_INLINE ibool buf_LRU_free_from_unzip_LRU_list( /*=============================*/ - ulint n_iterations) /*!< in: how many times this has been called - repeatedly without result: a high value means - that we should search farther; we will search - n_iterations / 5 of the unzip_LRU list, - or nothing if n_iterations >= 5 */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint n_iterations) /*!< in: how many times this has + been called repeatedly without + result: a high value means that + we should search farther; we will + search n_iterations / 5 of the + unzip_LRU list, or nothing if + n_iterations >= 5 */ { buf_block_t* block; ulint distance; - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); /* Theoratically it should be much easier to find a victim from unzip_LRU as we can choose even a dirty block (as we'll @@ -500,7 +584,7 @@ buf_LRU_free_from_unzip_LRU_list( if we have done five iterations so far. */ if (UNIV_UNLIKELY(n_iterations >= 5) - || !buf_LRU_evict_from_unzip_LRU()) { + || !buf_LRU_evict_from_unzip_LRU(buf_pool)) { return(FALSE); } @@ -552,7 +636,9 @@ UNIV_INLINE ibool buf_LRU_free_from_common_LRU_list( /*==============================*/ - ulint n_iterations) /*!< in: how many times this has been called + buf_pool_t* buf_pool, + ulint n_iterations) + /*!< in: how many times this has been called repeatedly without result: a high value means that we should search farther; if n_iterations < 10, then we search @@ -562,7 +648,7 @@ buf_LRU_free_from_common_LRU_list( buf_page_t* bpage; ulint distance; - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); distance = 100 + (n_iterations * buf_pool->curr_size) / 10; @@ -619,7 +705,10 @@ UNIV_INTERN ibool buf_LRU_search_and_free_block( /*==========================*/ - ulint n_iterations) /*!< in: how many times this has been called + buf_pool_t* buf_pool, + /*!< in: buffer pool instance */ + ulint n_iterations) + /*!< in: how many times this has been called repeatedly without result: a high value means that we should search farther; if n_iterations < 10, then we search @@ -630,12 +719,13 @@ buf_LRU_search_and_free_block( { ibool freed = FALSE; - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); - freed = buf_LRU_free_from_unzip_LRU_list(n_iterations); + freed = buf_LRU_free_from_unzip_LRU_list(buf_pool, n_iterations); if (!freed) { - freed = buf_LRU_free_from_common_LRU_list(n_iterations); + freed = buf_LRU_free_from_common_LRU_list( + buf_pool, n_iterations); } if (!freed) { @@ -644,7 +734,7 @@ buf_LRU_search_and_free_block( buf_pool->LRU_flush_ended--; } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); return(freed); } @@ -659,44 +749,64 @@ operations need new buffer blocks, and the i/o work done in flushing would be wasted. */ UNIV_INTERN void -buf_LRU_try_free_flushed_blocks(void) -/*=================================*/ +buf_LRU_try_free_flushed_blocks( +/*============================*/ + buf_pool_t* buf_pool) /*!< in: buffer pool instance */ { - buf_pool_mutex_enter(); - while (buf_pool->LRU_flush_ended > 0) { + if (buf_pool == NULL) { + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool = buf_pool_from_array(i); + buf_LRU_try_free_flushed_blocks(buf_pool); + } + } else { + buf_pool_mutex_enter(buf_pool); - buf_pool_mutex_exit(); + while (buf_pool->LRU_flush_ended > 0) { - buf_LRU_search_and_free_block(1); + buf_pool_mutex_exit(buf_pool); - buf_pool_mutex_enter(); - } + buf_LRU_search_and_free_block(buf_pool, 1); - buf_pool_mutex_exit(); + buf_pool_mutex_enter(buf_pool); + } + + buf_pool_mutex_exit(buf_pool); + } } /******************************************************************//** -Returns TRUE if less than 25 % of the buffer pool is available. This can be -used in heuristics to prevent huge transactions eating up the whole buffer -pool for their locks. +Returns TRUE if less than 25 % of the buffer pool in any instance is +available. This can be used in heuristics to prevent huge transactions +eating up the whole buffer pool for their locks. @return TRUE if less than 25 % of buffer pool left */ UNIV_INTERN ibool buf_LRU_buf_pool_running_out(void) /*==============================*/ { - ibool ret = FALSE; + ulint i; + ibool ret = FALSE; - buf_pool_mutex_enter(); + for (i = 0; i < srv_buf_pool_instances && !ret; i++) { + buf_pool_t* buf_pool; - if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) - + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->curr_size / 4) { + buf_pool = buf_pool_from_array(i); - ret = TRUE; - } + buf_pool_mutex_enter(buf_pool); + + if (!recv_recovery_on + && UT_LIST_GET_LEN(buf_pool->free) + + UT_LIST_GET_LEN(buf_pool->LRU) + < buf_pool->curr_size / 4) { + + ret = TRUE; + } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); + } return(ret); } @@ -707,16 +817,18 @@ free list. If it is empty, returns NULL. @return a free control block, or NULL if the buf_block->free list is empty */ UNIV_INTERN buf_block_t* -buf_LRU_get_free_only(void) -/*=======================*/ +buf_LRU_get_free_only( +/*==================*/ + buf_pool_t* buf_pool) { buf_block_t* block; - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); block = (buf_block_t*) UT_LIST_GET_FIRST(buf_pool->free); if (block) { + ut_ad(block->page.in_free_list); ut_d(block->page.in_free_list = FALSE); ut_ad(!block->page.in_flush_list); @@ -729,6 +841,8 @@ buf_LRU_get_free_only(void) buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE); UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE); + ut_ad(buf_pool_from_block(block) == buf_pool); + mutex_exit(&block->mutex); } @@ -744,8 +858,9 @@ UNIV_INTERN buf_block_t* buf_LRU_get_free_block( /*===================*/ - ulint zip_size) /*!< in: compressed page size in bytes, - or 0 if uncompressed tablespace */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint zip_size) /*!< in: compressed page size in bytes, + or 0 if uncompressed tablespace */ { buf_block_t* block = NULL; ibool freed; @@ -753,7 +868,7 @@ buf_LRU_get_free_block( ibool mon_value_was = FALSE; ibool started_monitor = FALSE; loop: - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); if (!recv_recovery_on && UT_LIST_GET_LEN(buf_pool->free) + UT_LIST_GET_LEN(buf_pool->LRU) < buf_pool->curr_size / 20) { @@ -820,9 +935,11 @@ loop: } /* If there is a block in the free list, take it */ - block = buf_LRU_get_free_only(); + block = buf_LRU_get_free_only(buf_pool); if (block) { + ut_ad(buf_pool_from_block(block) == buf_pool); + #ifdef UNIV_DEBUG block->page.zip.m_start = #endif /* UNIV_DEBUG */ @@ -833,14 +950,17 @@ loop: if (UNIV_UNLIKELY(zip_size)) { ibool lru; page_zip_set_size(&block->page.zip, zip_size); - block->page.zip.data = buf_buddy_alloc(zip_size, &lru); + + block->page.zip.data = buf_buddy_alloc( + buf_pool, zip_size, &lru); + UNIV_MEM_DESC(block->page.zip.data, zip_size, block); } else { page_zip_set_size(&block->page.zip, 0); block->page.zip.data = NULL; } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); if (started_monitor) { srv_print_innodb_monitor = mon_value_was; @@ -852,9 +972,9 @@ loop: /* If no block was in the free list, search from the end of the LRU list and try to free a block there */ - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); - freed = buf_LRU_search_and_free_block(n_iterations); + freed = buf_LRU_search_and_free_block(buf_pool, n_iterations); if (freed > 0) { goto loop; @@ -896,23 +1016,23 @@ loop: /* No free block was found: try to flush the LRU list */ - buf_flush_free_margin(); + buf_flush_free_margin(buf_pool); ++srv_buf_pool_wait_free; os_aio_simulated_wake_handler_threads(); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); if (buf_pool->LRU_flush_ended > 0) { /* We have written pages in an LRU flush. To make the insert buffer more efficient, we try to move these pages to the free list. */ - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); - buf_LRU_try_free_flushed_blocks(); + buf_LRU_try_free_flushed_blocks(buf_pool); } else { - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); } if (n_iterations > 10) { @@ -930,16 +1050,17 @@ Moves the LRU_old pointer so that the length of the old blocks list is inside the allowed limits. */ UNIV_INLINE void -buf_LRU_old_adjust_len(void) -/*========================*/ +buf_LRU_old_adjust_len( +/*===================*/ + buf_pool_t* buf_pool) /*!< in: buffer pool instance */ { ulint old_len; ulint new_len; ut_a(buf_pool->LRU_old); - ut_ad(buf_pool_mutex_own()); - ut_ad(buf_LRU_old_ratio >= BUF_LRU_OLD_RATIO_MIN); - ut_ad(buf_LRU_old_ratio <= BUF_LRU_OLD_RATIO_MAX); + ut_ad(buf_pool_mutex_own(buf_pool)); + ut_ad(buf_pool->LRU_old_ratio >= BUF_LRU_OLD_RATIO_MIN); + ut_ad(buf_pool->LRU_old_ratio <= BUF_LRU_OLD_RATIO_MAX); #if BUF_LRU_OLD_RATIO_MIN * BUF_LRU_OLD_MIN_LEN <= BUF_LRU_OLD_RATIO_DIV * (BUF_LRU_OLD_TOLERANCE + 5) # error "BUF_LRU_OLD_RATIO_MIN * BUF_LRU_OLD_MIN_LEN <= BUF_LRU_OLD_RATIO_DIV * (BUF_LRU_OLD_TOLERANCE + 5)" #endif @@ -955,7 +1076,7 @@ buf_LRU_old_adjust_len(void) old_len = buf_pool->LRU_old_len; new_len = ut_min(UT_LIST_GET_LEN(buf_pool->LRU) - * buf_LRU_old_ratio / BUF_LRU_OLD_RATIO_DIV, + * buf_pool->LRU_old_ratio / BUF_LRU_OLD_RATIO_DIV, UT_LIST_GET_LEN(buf_pool->LRU) - (BUF_LRU_OLD_TOLERANCE + BUF_LRU_NON_OLD_MIN_LEN)); @@ -997,12 +1118,13 @@ Initializes the old blocks pointer in the LRU list. This function should be called when the LRU list grows to BUF_LRU_OLD_MIN_LEN length. */ static void -buf_LRU_old_init(void) -/*==================*/ +buf_LRU_old_init( +/*=============*/ + buf_pool_t* buf_pool) { buf_page_t* bpage; - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_a(UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN); /* We first initialize all blocks in the LRU list as old and then use @@ -1021,7 +1143,7 @@ buf_LRU_old_init(void) buf_pool->LRU_old = UT_LIST_GET_FIRST(buf_pool->LRU); buf_pool->LRU_old_len = UT_LIST_GET_LEN(buf_pool->LRU); - buf_LRU_old_adjust_len(); + buf_LRU_old_adjust_len(buf_pool); } /******************************************************************//** @@ -1032,10 +1154,12 @@ buf_unzip_LRU_remove_block_if_needed( /*=================================*/ buf_page_t* bpage) /*!< in/out: control block */ { + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(buf_pool); ut_ad(bpage); ut_ad(buf_page_in_file(bpage)); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); if (buf_page_belongs_to_unzip_LRU(bpage)) { buf_block_t* block = (buf_block_t*) bpage; @@ -1055,9 +1179,11 @@ buf_LRU_remove_block( /*=================*/ buf_page_t* bpage) /*!< in: control block */ { + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(buf_pool); ut_ad(bpage); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_a(buf_page_in_file(bpage)); @@ -1071,7 +1197,7 @@ buf_LRU_remove_block( /* Below: the previous block is guaranteed to exist, because the LRU_old pointer is only allowed to differ by BUF_LRU_OLD_TOLERANCE from strict - buf_LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV of the LRU + buf_pool->LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV of the LRU list length. */ buf_page_t* prev_bpage = UT_LIST_GET_PREV(LRU, bpage); @@ -1117,7 +1243,7 @@ buf_LRU_remove_block( } /* Adjust the length of the old block list if necessary */ - buf_LRU_old_adjust_len(); + buf_LRU_old_adjust_len(buf_pool); } /******************************************************************//** @@ -1130,9 +1256,11 @@ buf_unzip_LRU_add_block( ibool old) /*!< in: TRUE if should be put to the end of the list, else put to the start */ { + buf_pool_t* buf_pool = buf_pool_from_block(block); + ut_ad(buf_pool); ut_ad(block); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_a(buf_page_belongs_to_unzip_LRU(&block->page)); @@ -1154,9 +1282,11 @@ buf_LRU_add_block_to_end_low( /*=========================*/ buf_page_t* bpage) /*!< in: control block */ { + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(buf_pool); ut_ad(bpage); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_a(buf_page_in_file(bpage)); @@ -1172,14 +1302,14 @@ buf_LRU_add_block_to_end_low( buf_page_set_old(bpage, TRUE); buf_pool->LRU_old_len++; - buf_LRU_old_adjust_len(); + buf_LRU_old_adjust_len(buf_pool); } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) { /* The LRU list is now long enough for LRU_old to become defined: init it */ - buf_LRU_old_init(); + buf_LRU_old_init(buf_pool); } else { buf_page_set_old(bpage, buf_pool->LRU_old != NULL); } @@ -1203,9 +1333,11 @@ buf_LRU_add_block_low( LRU list is very short, the block is added to the start, regardless of this parameter */ { + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(buf_pool); ut_ad(bpage); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_a(buf_page_in_file(bpage)); ut_ad(!bpage->in_LRU_list); @@ -1239,14 +1371,14 @@ buf_LRU_add_block_low( /* Adjust the length of the old block list if necessary */ buf_page_set_old(bpage, old); - buf_LRU_old_adjust_len(); + buf_LRU_old_adjust_len(buf_pool); } else if (UT_LIST_GET_LEN(buf_pool->LRU) == BUF_LRU_OLD_MIN_LEN) { /* The LRU list is now long enough for LRU_old to become defined: init it */ - buf_LRU_old_init(); + buf_LRU_old_init(buf_pool); } else { buf_page_set_old(bpage, buf_pool->LRU_old != NULL); } @@ -1282,7 +1414,9 @@ buf_LRU_make_block_young( /*=====================*/ buf_page_t* bpage) /*!< in: control block */ { - ut_ad(buf_pool_mutex_own()); + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + + ut_ad(buf_pool_mutex_own(buf_pool)); if (bpage->old) { buf_pool->stat.n_pages_made_young++; @@ -1308,7 +1442,7 @@ buf_LRU_make_block_old( Try to free a block. If bpage is a descriptor of a compressed-only page, the descriptor object will be freed as well. -NOTE: If this function returns BUF_LRU_FREED, it will not temporarily +NOTE: If this function returns BUF_LRU_FREED, it will temporarily release buf_pool_mutex. Furthermore, the page frame will no longer be accessible via bpage. @@ -1330,14 +1464,20 @@ buf_LRU_free_block( was temporarily released, or NULL */ { buf_page_t* b = NULL; + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); mutex_t* block_mutex = buf_page_get_mutex(bpage); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(mutex_own(block_mutex)); ut_ad(buf_page_in_file(bpage)); ut_ad(bpage->in_LRU_list); ut_ad(!bpage->in_flush_list == !bpage->oldest_modification); +#if UNIV_WORD_SIZE == 4 + /* On 32-bit systems, there is no padding in buf_page_t. On + other systems, Valgrind could complain about uninitialized pad + bytes. */ UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage); +#endif if (!buf_page_can_relocate(bpage)) { @@ -1371,9 +1511,9 @@ buf_LRU_free_block( If it cannot be allocated (without freeing a block from the LRU list), refuse to free bpage. */ alloc: - buf_pool_mutex_exit_forbid(); - b = buf_buddy_alloc(sizeof *b, NULL); - buf_pool_mutex_exit_allow(); + buf_pool_mutex_exit_forbid(buf_pool); + b = buf_buddy_alloc(buf_pool, sizeof *b, NULL); + buf_pool_mutex_exit_allow(buf_pool); if (UNIV_UNLIKELY(!b)) { return(BUF_LRU_CANNOT_RELOCATE); @@ -1395,11 +1535,16 @@ alloc: ut_a(bpage->buf_fix_count == 0); if (b) { + buf_page_t* hash_b; buf_page_t* prev_b = UT_LIST_GET_PREV(LRU, b); - const ulint fold = buf_page_address_fold( + + const ulint fold = buf_page_address_fold( bpage->space, bpage->offset); - ut_a(!buf_page_hash_get(bpage->space, bpage->offset)); + hash_b = buf_page_hash_get_low( + buf_pool, bpage->space, bpage->offset, fold); + + ut_a(!hash_b); b->state = b->oldest_modification ? BUF_BLOCK_ZIP_DIRTY @@ -1433,8 +1578,13 @@ alloc: ut_ad(prev_b->in_LRU_list); ut_ad(buf_page_in_file(prev_b)); +#if UNIV_WORD_SIZE == 4 + /* On 32-bit systems, there is no + padding in buf_page_t. On other + systems, Valgrind could complain about + uninitialized pad bytes. */ UNIV_MEM_ASSERT_RW(prev_b, sizeof *prev_b); - +#endif UT_LIST_INSERT_AFTER(LRU, buf_pool->LRU, prev_b, b); @@ -1454,12 +1604,12 @@ alloc: ut_ad(buf_pool->LRU_old); /* Adjust the length of the old block list if necessary */ - buf_LRU_old_adjust_len(); + buf_LRU_old_adjust_len(buf_pool); } else if (lru_len == BUF_LRU_OLD_MIN_LEN) { /* The LRU list is now long enough for LRU_old to become defined: init it */ - buf_LRU_old_init(); + buf_LRU_old_init(buf_pool); } #ifdef UNIV_LRU_DEBUG /* Check that the "old" flag is consistent @@ -1474,26 +1624,8 @@ alloc: if (b->state == BUF_BLOCK_ZIP_PAGE) { buf_LRU_insert_zip_clean(b); } else { - buf_page_t* prev; - - ut_ad(b->in_flush_list); - ut_d(bpage->in_flush_list = FALSE); - - prev = UT_LIST_GET_PREV(list, b); - UT_LIST_REMOVE(list, buf_pool->flush_list, b); - - if (prev) { - ut_ad(prev->in_flush_list); - UT_LIST_INSERT_AFTER( - list, - buf_pool->flush_list, - prev, b); - } else { - UT_LIST_ADD_FIRST( - list, - buf_pool->flush_list, - b); - } + /* Relocate on buf_pool->flush_list. */ + buf_flush_relocate_on_flush_list(bpage, b); } bpage->zip.data = NULL; @@ -1501,7 +1633,7 @@ alloc: /* Prevent buf_page_get_gen() from decompressing the block while we release - buf_pool_mutex and block_mutex. */ + buf_pool->mutex and block_mutex. */ b->buf_fix_count++; b->io_fix = BUF_IO_READ; } @@ -1510,7 +1642,7 @@ alloc: *buf_pool_mutex_released = TRUE; } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); mutex_exit(block_mutex); /* Remove possible adaptive hash index on the page. @@ -1542,14 +1674,14 @@ alloc: : BUF_NO_CHECKSUM_MAGIC); } - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); mutex_enter(block_mutex); if (b) { - mutex_enter(&buf_pool_zip_mutex); + mutex_enter(&buf_pool->zip_mutex); b->buf_fix_count--; buf_page_set_io_fix(b, BUF_IO_NONE); - mutex_exit(&buf_pool_zip_mutex); + mutex_exit(&buf_pool->zip_mutex); } buf_LRU_block_free_hashed_page((buf_block_t*) bpage); @@ -1557,7 +1689,7 @@ alloc: /* The block_mutex should have been released by buf_LRU_block_remove_hashed_page() when it returns BUF_BLOCK_ZIP_FREE. */ - ut_ad(block_mutex == &buf_pool_zip_mutex); + ut_ad(block_mutex == &buf_pool->zip_mutex); mutex_enter(block_mutex); } @@ -1572,10 +1704,11 @@ buf_LRU_block_free_non_file_page( /*=============================*/ buf_block_t* block) /*!< in: block, must not contain a file page */ { - void* data; + void* data; + buf_pool_t* buf_pool = buf_pool_from_block(block); ut_ad(block); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(mutex_own(&block->mutex)); switch (buf_block_get_state(block)) { @@ -1609,9 +1742,12 @@ buf_LRU_block_free_non_file_page( if (data) { block->page.zip.data = NULL; mutex_exit(&block->mutex); - buf_pool_mutex_exit_forbid(); - buf_buddy_free(data, page_zip_get_size(&block->page.zip)); - buf_pool_mutex_exit_allow(); + buf_pool_mutex_exit_forbid(buf_pool); + + buf_buddy_free( + buf_pool, data, page_zip_get_size(&block->page.zip)); + + buf_pool_mutex_exit_allow(buf_pool); mutex_enter(&block->mutex); page_zip_set_size(&block->page.zip, 0); } @@ -1625,7 +1761,7 @@ buf_LRU_block_free_non_file_page( /******************************************************************//** Takes a block out of the LRU list and page hash table. If the block is compressed-only (BUF_BLOCK_ZIP_PAGE), -the object will be freed and buf_pool_zip_mutex will be released. +the object will be freed and buf_pool->zip_mutex will be released. If a compressed page or a compressed-only block descriptor is freed, other compressed pages or compressed-only block descriptors may be @@ -1642,15 +1778,23 @@ buf_LRU_block_remove_hashed_page( ibool zip) /*!< in: TRUE if should remove also the compressed page of an uncompressed page */ { + ulint fold; const buf_page_t* hashed_bpage; + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(bpage); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(mutex_own(buf_page_get_mutex(bpage))); ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE); ut_a(bpage->buf_fix_count == 0); +#if UNIV_WORD_SIZE == 4 + /* On 32-bit systems, there is no padding in + buf_page_t. On other systems, Valgrind could complain + about uninitialized pad bytes. */ UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage); +#endif buf_LRU_remove_block(bpage); @@ -1725,7 +1869,9 @@ buf_LRU_block_remove_hashed_page( break; } - hashed_bpage = buf_page_hash_get(bpage->space, bpage->offset); + fold = buf_page_address_fold(bpage->space, bpage->offset); + hashed_bpage = buf_page_hash_get_low( + buf_pool, bpage->space, bpage->offset, fold); if (UNIV_UNLIKELY(bpage != hashed_bpage)) { fprintf(stderr, @@ -1745,7 +1891,7 @@ buf_LRU_block_remove_hashed_page( #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG mutex_exit(buf_page_get_mutex(bpage)); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); buf_print(); buf_LRU_print(); buf_validate(); @@ -1757,9 +1903,7 @@ buf_LRU_block_remove_hashed_page( ut_ad(!bpage->in_zip_hash); ut_ad(bpage->in_page_hash); ut_d(bpage->in_page_hash = FALSE); - HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, - buf_page_address_fold(bpage->space, bpage->offset), - bpage); + HASH_DELETE(buf_page_t, hash, buf_pool->page_hash, fold, bpage); switch (buf_page_get_state(bpage)) { case BUF_BLOCK_ZIP_PAGE: ut_ad(!bpage->in_free_list); @@ -1770,12 +1914,16 @@ buf_LRU_block_remove_hashed_page( UT_LIST_REMOVE(list, buf_pool->zip_clean, bpage); - mutex_exit(&buf_pool_zip_mutex); - buf_pool_mutex_exit_forbid(); - buf_buddy_free(bpage->zip.data, - page_zip_get_size(&bpage->zip)); - buf_buddy_free(bpage, sizeof(*bpage)); - buf_pool_mutex_exit_allow(); + mutex_exit(&buf_pool->zip_mutex); + buf_pool_mutex_exit_forbid(buf_pool); + + buf_buddy_free( + buf_pool, bpage->zip.data, + page_zip_get_size(&bpage->zip)); + + buf_buddy_free(buf_pool, bpage, sizeof(*bpage)); + buf_pool_mutex_exit_allow(buf_pool); + UNIV_MEM_UNDESC(bpage); return(BUF_BLOCK_ZIP_FREE); @@ -1797,9 +1945,13 @@ buf_LRU_block_remove_hashed_page( ut_ad(!bpage->in_flush_list); ut_ad(!bpage->in_LRU_list); mutex_exit(&((buf_block_t*) bpage)->mutex); - buf_pool_mutex_exit_forbid(); - buf_buddy_free(data, page_zip_get_size(&bpage->zip)); - buf_pool_mutex_exit_allow(); + buf_pool_mutex_exit_forbid(buf_pool); + + buf_buddy_free( + buf_pool, data, + page_zip_get_size(&bpage->zip)); + + buf_pool_mutex_exit_allow(buf_pool); mutex_enter(&((buf_block_t*) bpage)->mutex); page_zip_set_size(&bpage->zip, 0); } @@ -1828,7 +1980,10 @@ buf_LRU_block_free_hashed_page( buf_block_t* block) /*!< in: block, must contain a file page and be in a state where it can be freed */ { - ut_ad(buf_pool_mutex_own()); +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_block(block); + ut_ad(buf_pool_mutex_own(buf_pool)); +#endif ut_ad(mutex_own(&block->mutex)); buf_block_set_state(block, BUF_BLOCK_MEMORY); @@ -1837,17 +1992,18 @@ buf_LRU_block_free_hashed_page( } /**********************************************************************//** -Updates buf_LRU_old_ratio. +Updates buf_pool->LRU_old_ratio for one buffer pool instance. @return updated old_pct */ -UNIV_INTERN +static uint -buf_LRU_old_ratio_update( -/*=====================*/ - uint old_pct,/*!< in: Reserve this percentage of - the buffer pool for "old" blocks. */ - ibool adjust) /*!< in: TRUE=adjust the LRU list; - FALSE=just assign buf_LRU_old_ratio - during the initialization of InnoDB */ +buf_LRU_old_ratio_update_instance( +/*==============================*/ + buf_pool_t* buf_pool,/*!< in: buffer pool instance */ + uint old_pct,/*!< in: Reserve this percentage of + the buffer pool for "old" blocks. */ + ibool adjust) /*!< in: TRUE=adjust the LRU list; + FALSE=just assign buf_pool->LRU_old_ratio + during the initialization of InnoDB */ { uint ratio; @@ -1859,27 +2015,55 @@ buf_LRU_old_ratio_update( } if (adjust) { - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); - if (ratio != buf_LRU_old_ratio) { - buf_LRU_old_ratio = ratio; + if (ratio != buf_pool->LRU_old_ratio) { + buf_pool->LRU_old_ratio = ratio; if (UT_LIST_GET_LEN(buf_pool->LRU) - >= BUF_LRU_OLD_MIN_LEN) { - buf_LRU_old_adjust_len(); + >= BUF_LRU_OLD_MIN_LEN) { + + buf_LRU_old_adjust_len(buf_pool); } } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); } else { - buf_LRU_old_ratio = ratio; + buf_pool->LRU_old_ratio = ratio; } - /* the reverse of ratio = old_pct * BUF_LRU_OLD_RATIO_DIV / 100 */ return((uint) (ratio * 100 / (double) BUF_LRU_OLD_RATIO_DIV + 0.5)); } +/**********************************************************************//** +Updates buf_pool->LRU_old_ratio. +@return updated old_pct */ +UNIV_INTERN +ulint +buf_LRU_old_ratio_update( +/*=====================*/ + uint old_pct,/*!< in: Reserve this percentage of + the buffer pool for "old" blocks. */ + ibool adjust) /*!< in: TRUE=adjust the LRU list; + FALSE=just assign buf_pool->LRU_old_ratio + during the initialization of InnoDB */ +{ + ulint i; + ulint new_ratio = 0; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + + new_ratio = buf_LRU_old_ratio_update_instance( + buf_pool, old_pct, adjust); + } + + return(new_ratio); +} + /********************************************************************//** Update the historical stats that we are collecting for LRU eviction policy at the end of each interval. */ @@ -1888,14 +2072,25 @@ void buf_LRU_stat_update(void) /*=====================*/ { + ulint i; buf_LRU_stat_t* item; + buf_pool_t* buf_pool; + ibool evict_started = FALSE; /* If we haven't started eviction yet then don't update stats. */ - if (buf_pool->freed_page_clock == 0) { - goto func_exit; + for (i = 0; i < srv_buf_pool_instances; i++) { + + buf_pool = buf_pool_from_array(i); + + if (buf_pool->freed_page_clock != 0) { + evict_started = TRUE; + break; + } } - buf_pool_mutex_enter(); + if (!evict_started) { + goto func_exit; + } /* Update the index. */ item = &buf_LRU_stat_arr[buf_LRU_stat_arr_ind]; @@ -1909,8 +2104,6 @@ buf_LRU_stat_update(void) /* Put current entry in the array. */ memcpy(item, &buf_LRU_stat_cur, sizeof *item); - buf_pool_mutex_exit(); - func_exit: /* Clear the current entry. */ memset(&buf_LRU_stat_cur, 0, sizeof buf_LRU_stat_cur); @@ -1918,12 +2111,12 @@ func_exit: #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /**********************************************************************//** -Validates the LRU list. -@return TRUE */ -UNIV_INTERN -ibool -buf_LRU_validate(void) -/*==================*/ +Validates the LRU list for one buffer pool instance. */ +static +void +buf_LRU_validate_instance( +/*======================*/ + buf_pool_t* buf_pool) { buf_page_t* bpage; buf_block_t* block; @@ -1931,14 +2124,15 @@ buf_LRU_validate(void) ulint new_len; ut_ad(buf_pool); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); if (UT_LIST_GET_LEN(buf_pool->LRU) >= BUF_LRU_OLD_MIN_LEN) { ut_a(buf_pool->LRU_old); old_len = buf_pool->LRU_old_len; new_len = ut_min(UT_LIST_GET_LEN(buf_pool->LRU) - * buf_LRU_old_ratio / BUF_LRU_OLD_RATIO_DIV, + * buf_pool->LRU_old_ratio + / BUF_LRU_OLD_RATIO_DIV, UT_LIST_GET_LEN(buf_pool->LRU) - (BUF_LRU_OLD_TOLERANCE + BUF_LRU_NON_OLD_MIN_LEN)); @@ -2014,28 +2208,49 @@ buf_LRU_validate(void) ut_a(buf_page_belongs_to_unzip_LRU(&block->page)); } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); +} + +/**********************************************************************//** +Validates the LRU list. +@return TRUE */ +UNIV_INTERN +ibool +buf_LRU_validate(void) +/*==================*/ +{ + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + buf_LRU_validate_instance(buf_pool); + } + return(TRUE); } #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ #if defined UNIV_DEBUG_PRINT || defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /**********************************************************************//** -Prints the LRU list. */ +Prints the LRU list for one buffer pool instance. */ UNIV_INTERN void -buf_LRU_print(void) -/*===============*/ +buf_LRU_print_instance( +/*===================*/ + buf_pool_t* buf_pool) { const buf_page_t* bpage; ut_ad(buf_pool); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); bpage = UT_LIST_GET_FIRST(buf_pool->LRU); while (bpage != NULL) { + mutex_enter(buf_page_get_mutex(bpage)); fprintf(stderr, "BLOCK space %lu page %lu ", (ulong) buf_page_get_space(bpage), (ulong) buf_page_get_page_no(bpage)); @@ -2084,9 +2299,26 @@ buf_LRU_print(void) break; } + mutex_exit(buf_page_get_mutex(bpage)); bpage = UT_LIST_GET_NEXT(LRU, bpage); } - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); +} + +/**********************************************************************//** +Prints the LRU list. */ +UNIV_INTERN +void +buf_LRU_print(void) +/*===============*/ +{ + ulint i; + buf_pool_t* buf_pool; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool = buf_pool_from_array(i); + buf_LRU_print_instance(buf_pool); + } } #endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */ diff --git a/storage/innobase/buf/buf0rea.c b/storage/innobase/buf/buf0rea.c index dd98ea17eb5..99a56bf91bc 100644 --- a/storage/innobase/buf/buf0rea.c +++ b/storage/innobase/buf/buf0rea.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. 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 @@ -171,6 +171,7 @@ buf_read_page( ulint zip_size,/*!< in: compressed page size in bytes, or 0 */ ulint offset) /*!< in: page number */ { + buf_pool_t* buf_pool = buf_pool_get(space, offset); ib_int64_t tablespace_version; ulint count; ulint err; @@ -195,7 +196,7 @@ buf_read_page( } /* Flush pages from the end of the LRU list if necessary */ - buf_flush_free_margin(); + buf_flush_free_margin(buf_pool); /* Increment number of I/O operations used for LRU policy. */ buf_LRU_stat_inc_io(); @@ -236,6 +237,7 @@ buf_read_ahead_linear( ulint offset) /*!< in: page number of a page; NOTE: the current thread must want access to this page (see NOTE 3 above) */ { + buf_pool_t* buf_pool = buf_pool_get(space, offset); ib_int64_t tablespace_version; buf_page_t* bpage; buf_frame_t* frame; @@ -251,7 +253,7 @@ buf_read_ahead_linear( ulint err; ulint i; const ulint buf_read_ahead_linear_area - = BUF_READ_AHEAD_LINEAR_AREA; + = BUF_READ_AHEAD_LINEAR_AREA(buf_pool); ulint threshold; if (UNIV_UNLIKELY(srv_startup_is_before_trx_rollback_phase)) { @@ -286,10 +288,10 @@ buf_read_ahead_linear( tablespace_version = fil_space_get_version(space); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); if (high > fil_space_get_size(space)) { - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); /* The area is not whole, return */ return(0); @@ -297,7 +299,7 @@ buf_read_ahead_linear( if (buf_pool->n_pend_reads > buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) { - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); return(0); } @@ -315,14 +317,14 @@ buf_read_ahead_linear( /* How many out of order accessed pages can we ignore when working out the access pattern for linear readahead */ threshold = ut_min((64 - srv_read_ahead_threshold), - BUF_READ_AHEAD_AREA); + BUF_READ_AHEAD_AREA(buf_pool)); fail_count = 0; for (i = low; i < high; i++) { - bpage = buf_page_hash_get(space, i); + bpage = buf_page_hash_get(buf_pool, space, i); - if ((bpage == NULL) || !buf_page_is_accessed(bpage)) { + if (bpage == NULL || !buf_page_is_accessed(bpage)) { /* Not accessed */ fail_count++; @@ -346,7 +348,7 @@ buf_read_ahead_linear( if (fail_count > threshold) { /* Too many failures: return */ - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); return(0); } @@ -358,10 +360,10 @@ buf_read_ahead_linear( /* If we got this far, we know that enough pages in the area have been accessed in the right order: linear read-ahead can be sensible */ - bpage = buf_page_hash_get(space, offset); + bpage = buf_page_hash_get(buf_pool, space, offset); if (bpage == NULL) { - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); return(0); } @@ -387,7 +389,7 @@ buf_read_ahead_linear( pred_offset = fil_page_get_prev(frame); succ_offset = fil_page_get_next(frame); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); if ((offset == low) && (succ_offset == offset + 1)) { @@ -466,7 +468,7 @@ buf_read_ahead_linear( os_aio_simulated_wake_handler_threads(); /* Flush pages from the end of the LRU list if necessary */ - buf_flush_free_margin(); + buf_flush_free_margin(buf_pool); #ifdef UNIV_DEBUG if (buf_debug_prints && (count > 0)) { @@ -518,14 +520,18 @@ buf_read_ibuf_merge_pages( #ifdef UNIV_IBUF_DEBUG ut_a(n_stored < UNIV_PAGE_SIZE); #endif - while (buf_pool->n_pend_reads - > buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) { - os_thread_sleep(500000); - } for (i = 0; i < n_stored; i++) { - ulint zip_size = fil_space_get_zip_size(space_ids[i]); - ulint err; + ulint err; + buf_pool_t* buf_pool; + ulint zip_size = fil_space_get_zip_size(space_ids[i]); + + buf_pool = buf_pool_get(space_ids[i], space_versions[i]); + + while (buf_pool->n_pend_reads + > buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) { + os_thread_sleep(500000); + } if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) { @@ -550,8 +556,8 @@ tablespace_deleted: os_aio_simulated_wake_handler_threads(); - /* Flush pages from the end of the LRU list if necessary */ - buf_flush_free_margin(); + /* Flush pages from the end of all the LRU lists if necessary */ + buf_flush_free_margins(); #ifdef UNIV_DEBUG if (buf_debug_prints) { @@ -600,22 +606,23 @@ buf_read_recv_pages( tablespace_version = fil_space_get_version(space); for (i = 0; i < n_stored; i++) { + buf_pool_t* buf_pool; count = 0; os_aio_print_debug = FALSE; - + buf_pool = buf_pool_get(space, page_nos[i]); while (buf_pool->n_pend_reads >= recv_n_pool_free_frames / 2) { os_aio_simulated_wake_handler_threads(); - os_thread_sleep(500000); + os_thread_sleep(10000); count++; - if (count > 100) { + if (count > 1000) { fprintf(stderr, "InnoDB: Error: InnoDB has waited for" - " 50 seconds for pending\n" + " 10 seconds for pending\n" "InnoDB: reads to the buffer pool to" " be finished.\n" "InnoDB: Number of pending reads %lu," @@ -643,8 +650,8 @@ buf_read_recv_pages( os_aio_simulated_wake_handler_threads(); - /* Flush pages from the end of the LRU list if necessary */ - buf_flush_free_margin(); + /* Flush pages from the end of all the LRU lists if necessary */ + buf_flush_free_margins(); #ifdef UNIV_DEBUG if (buf_debug_prints) { diff --git a/storage/innobase/compile-innodb b/storage/innobase/compile-innodb index 82601f03ae9..23e7f98e50c 100755 --- a/storage/innobase/compile-innodb +++ b/storage/innobase/compile-innodb @@ -1,24 +1,25 @@ -#! /bin/sh +#!/bin/sh +# +# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. # -# Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved. -# # 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; 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, write to the Free Software Foundation, Inc., 59 Temple # Place, Suite 330, Boston, MA 02111-1307 USA # -path=`dirname $0` -. "$path/SETUP.sh" +# we assume this script is in storage/innobase/ + +MYSQL_ROOT="$(dirname ${0})/../.." -extra_flags="$pentium_cflags $fast_cflags -g" -extra_configs="$pentium_configs $static_link --with-plugins=innobase" +cd ${MYSQL_ROOT} -. "$path/FINISH.sh" +cmake -DWITH_INNOBASE_STORAGE_ENGINE:BOOL=ON +make -j4 diff --git a/storage/innobase/compile-innodb-debug b/storage/innobase/compile-innodb-debug deleted file mode 100755 index efb4abf88d5..00000000000 --- a/storage/innobase/compile-innodb-debug +++ /dev/null @@ -1,24 +0,0 @@ -#! /bin/sh -# -# Copyright (c) 2005, 2009, Innobase Oy. All Rights Reserved. -# -# 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; 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, write to the Free Software Foundation, Inc., 59 Temple -# Place, Suite 330, Boston, MA 02111-1307 USA -# - -path=`dirname $0` -. "$path/SETUP.sh" $@ --with-debug=full - -extra_flags="$pentium_cflags $debug_cflags" -extra_configs="$pentium_configs $debug_configs --with-plugins=innobase" - -. "$path/FINISH.sh" diff --git a/storage/innobase/data/data0data.c b/storage/innobase/data/data0data.c index e3c1f1b4f23..0715b49bf9c 100644 --- a/storage/innobase/data/data0data.c +++ b/storage/innobase/data/data0data.c @@ -666,6 +666,21 @@ dtuple_convert_big_rec( goto skip_field; } + /* In DYNAMIC and COMPRESSED format, store + locally any non-BLOB columns whose maximum + length does not exceed 256 bytes. This is + because there is no room for the "external + storage" flag when the maximum length is 255 + bytes or less. This restriction trivially + holds in REDUNDANT and COMPACT format, because + there we always store locally columns whose + length is up to local_len == 788 bytes. + @see rec_init_offsets_comp_ordinary */ + if (ifield->col->mtype != DATA_BLOB + && ifield->col->len < 256) { + goto skip_field; + } + longest_i = i; longest = savings; diff --git a/storage/innobase/dict/dict0boot.c b/storage/innobase/dict/dict0boot.c index e55de30481b..e63c1dc94b9 100644 --- a/storage/innobase/dict/dict0boot.c +++ b/storage/innobase/dict/dict0boot.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -62,32 +62,47 @@ dict_hdr_get( } /**********************************************************************//** -Returns a new table, index, or tree id. -@return the new id */ +Returns a new table, index, or space id. */ UNIV_INTERN -dulint +void dict_hdr_get_new_id( /*================*/ - ulint type) /*!< in: DICT_HDR_ROW_ID, ... */ + dulint* table_id, /*!< out: table id (not assigned if NULL) */ + dulint* index_id, /*!< out: index id (not assigned if NULL) */ + ulint* space_id) /*!< out: space id (not assigned if NULL) */ { dict_hdr_t* dict_hdr; dulint id; mtr_t mtr; - ut_ad((type == DICT_HDR_TABLE_ID) || (type == DICT_HDR_INDEX_ID)); - mtr_start(&mtr); dict_hdr = dict_hdr_get(&mtr); - id = mtr_read_dulint(dict_hdr + type, &mtr); - id = ut_dulint_add(id, 1); + if (table_id) { + id = mtr_read_dulint(dict_hdr + DICT_HDR_TABLE_ID, &mtr); + id = ut_dulint_add(id, 1); + mlog_write_dulint(dict_hdr + DICT_HDR_TABLE_ID, id, &mtr); + *table_id = id; + } - mlog_write_dulint(dict_hdr + type, id, &mtr); + if (index_id) { + id = mtr_read_dulint(dict_hdr + DICT_HDR_INDEX_ID, &mtr); + id = ut_dulint_add(id, 1); + mlog_write_dulint(dict_hdr + DICT_HDR_INDEX_ID, id, &mtr); + *index_id = id; + } - mtr_commit(&mtr); + if (space_id) { + *space_id = mtr_read_ulint(dict_hdr + DICT_HDR_MAX_SPACE_ID, + MLOG_4BYTES, &mtr); + if (fil_assign_new_space_id(space_id)) { + mlog_write_ulint(dict_hdr + DICT_HDR_MAX_SPACE_ID, + *space_id, MLOG_4BYTES, &mtr); + } + } - return(id); + mtr_commit(&mtr); } /**********************************************************************//** @@ -151,9 +166,12 @@ dict_hdr_create( mlog_write_dulint(dict_header + DICT_HDR_INDEX_ID, ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); - /* Obsolete, but we must initialize it to 0 anyway. */ - mlog_write_dulint(dict_header + DICT_HDR_MIX_ID, - ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); + mlog_write_ulint(dict_header + DICT_HDR_MAX_SPACE_ID, + 0, MLOG_4BYTES, mtr); + + /* Obsolete, but we must initialize it anyway. */ + mlog_write_ulint(dict_header + DICT_HDR_MIX_ID_LOW, + DICT_HDR_FIRST_ID, MLOG_4BYTES, mtr); /* Create the B-tree roots for the clustered indexes of the basic system tables */ @@ -274,6 +292,9 @@ dict_boot(void) and (TYPE & DICT_TF_FORMAT_MASK) are nonzero and TYPE = table->flags */ dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "MIX_ID", DATA_BINARY, 0, 0); + /* MIX_LEN may contain additional table flags when + ROW_FORMAT!=REDUNDANT. Currently, these flags include + DICT_TF2_TEMPORARY. */ dict_mem_table_add_col(table, heap, "MIX_LEN", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "CLUSTER_NAME", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4); @@ -355,7 +376,7 @@ dict_boot(void) dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "PAGE_NO", DATA_INT, 0, 4); - /* The '+ 2' below comes from the 2 system fields */ + /* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */ #if DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2 #error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2" #endif @@ -365,6 +386,9 @@ dict_boot(void) #if DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2 #error "DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2" #endif +#if DICT_SYS_INDEXES_NAME_FIELD != 2 + 2 +#error "DICT_SYS_INDEXES_NAME_FIELD != 2 + 2" +#endif table->id = DICT_INDEXES_ID; dict_table_add_to_cache(table, heap); diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c index 96a9bd8152e..f185371bfca 100644 --- a/storage/innobase/dict/dict0crea.c +++ b/storage/innobase/dict/dict0crea.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -51,16 +51,18 @@ static dtuple_t* dict_create_sys_tables_tuple( /*=========================*/ - dict_table_t* table, /*!< in: table */ - mem_heap_t* heap) /*!< in: memory heap from which the memory for - the built tuple is allocated */ + const dict_table_t* table, /*!< in: table */ + mem_heap_t* heap) /*!< in: memory heap from + which the memory for the built + tuple is allocated */ { dict_table_t* sys_tables; dtuple_t* entry; dfield_t* dfield; byte* ptr; - ut_ad(table && heap); + ut_ad(table); + ut_ad(heap); sys_tables = dict_sys->sys_tables; @@ -69,18 +71,18 @@ dict_create_sys_tables_tuple( dict_table_copy_types(entry, sys_tables); /* 0: NAME -----------------------------*/ - dfield = dtuple_get_nth_field(entry, 0); + dfield = dtuple_get_nth_field(entry, 0/*NAME*/); dfield_set_data(dfield, table->name, ut_strlen(table->name)); /* 3: ID -------------------------------*/ - dfield = dtuple_get_nth_field(entry, 1); + dfield = dtuple_get_nth_field(entry, 1/*ID*/); ptr = mem_heap_alloc(heap, 8); mach_write_to_8(ptr, table->id); dfield_set_data(dfield, ptr, 8); /* 4: N_COLS ---------------------------*/ - dfield = dtuple_get_nth_field(entry, 2); + dfield = dtuple_get_nth_field(entry, 2/*N_COLS*/); #if DICT_TF_COMPACT != 1 #error @@ -91,40 +93,41 @@ dict_create_sys_tables_tuple( | ((table->flags & DICT_TF_COMPACT) << 31)); dfield_set_data(dfield, ptr, 4); /* 5: TYPE -----------------------------*/ - dfield = dtuple_get_nth_field(entry, 3); + dfield = dtuple_get_nth_field(entry, 3/*TYPE*/); ptr = mem_heap_alloc(heap, 4); - if (table->flags & ~DICT_TF_COMPACT) { + if (table->flags & (~DICT_TF_COMPACT & ~(~0 << DICT_TF_BITS))) { ut_a(table->flags & DICT_TF_COMPACT); ut_a(dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP); ut_a((table->flags & DICT_TF_ZSSIZE_MASK) <= (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT)); - ut_a(!(table->flags & (~0 << DICT_TF_BITS))); - mach_write_to_4(ptr, table->flags); + ut_a(!(table->flags & (~0 << DICT_TF2_BITS))); + mach_write_to_4(ptr, table->flags & ~(~0 << DICT_TF_BITS)); } else { mach_write_to_4(ptr, DICT_TABLE_ORDINARY); } dfield_set_data(dfield, ptr, 4); /* 6: MIX_ID (obsolete) ---------------------------*/ - dfield = dtuple_get_nth_field(entry, 4); + dfield = dtuple_get_nth_field(entry, 4/*MIX_ID*/); ptr = mem_heap_zalloc(heap, 8); dfield_set_data(dfield, ptr, 8); - /* 7: MIX_LEN (obsolete) --------------------------*/ + /* 7: MIX_LEN (additional flags) --------------------------*/ - dfield = dtuple_get_nth_field(entry, 5); + dfield = dtuple_get_nth_field(entry, 5/*MIX_LEN*/); - ptr = mem_heap_zalloc(heap, 4); + ptr = mem_heap_alloc(heap, 4); + mach_write_to_4(ptr, table->flags >> DICT_TF2_SHIFT); dfield_set_data(dfield, ptr, 4); /* 8: CLUSTER_NAME ---------------------*/ - dfield = dtuple_get_nth_field(entry, 6); + dfield = dtuple_get_nth_field(entry, 6/*CLUSTER_NAME*/); dfield_set_null(dfield); /* not supported */ /* 9: SPACE ----------------------------*/ - dfield = dtuple_get_nth_field(entry, 7); + dfield = dtuple_get_nth_field(entry, 7/*SPACE*/); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, table->space); @@ -143,19 +146,21 @@ static dtuple_t* dict_create_sys_columns_tuple( /*==========================*/ - dict_table_t* table, /*!< in: table */ - ulint i, /*!< in: column number */ - mem_heap_t* heap) /*!< in: memory heap from which the memory for - the built tuple is allocated */ + const dict_table_t* table, /*!< in: table */ + ulint i, /*!< in: column number */ + mem_heap_t* heap) /*!< in: memory heap from + which the memory for the built + tuple is allocated */ { dict_table_t* sys_columns; dtuple_t* entry; const dict_col_t* column; dfield_t* dfield; byte* ptr; - const char* col_name; + const char* col_name; - ut_ad(table && heap); + ut_ad(table); + ut_ad(heap); column = dict_table_get_nth_col(table, i); @@ -166,47 +171,47 @@ dict_create_sys_columns_tuple( dict_table_copy_types(entry, sys_columns); /* 0: TABLE_ID -----------------------*/ - dfield = dtuple_get_nth_field(entry, 0); + dfield = dtuple_get_nth_field(entry, 0/*TABLE_ID*/); ptr = mem_heap_alloc(heap, 8); mach_write_to_8(ptr, table->id); dfield_set_data(dfield, ptr, 8); /* 1: POS ----------------------------*/ - dfield = dtuple_get_nth_field(entry, 1); + dfield = dtuple_get_nth_field(entry, 1/*POS*/); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, i); dfield_set_data(dfield, ptr, 4); /* 4: NAME ---------------------------*/ - dfield = dtuple_get_nth_field(entry, 2); + dfield = dtuple_get_nth_field(entry, 2/*NAME*/); col_name = dict_table_get_col_name(table, i); dfield_set_data(dfield, col_name, ut_strlen(col_name)); /* 5: MTYPE --------------------------*/ - dfield = dtuple_get_nth_field(entry, 3); + dfield = dtuple_get_nth_field(entry, 3/*MTYPE*/); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, column->mtype); dfield_set_data(dfield, ptr, 4); /* 6: PRTYPE -------------------------*/ - dfield = dtuple_get_nth_field(entry, 4); + dfield = dtuple_get_nth_field(entry, 4/*PRTYPE*/); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, column->prtype); dfield_set_data(dfield, ptr, 4); /* 7: LEN ----------------------------*/ - dfield = dtuple_get_nth_field(entry, 5); + dfield = dtuple_get_nth_field(entry, 5/*LEN*/); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, column->len); dfield_set_data(dfield, ptr, 4); /* 8: PREC ---------------------------*/ - dfield = dtuple_get_nth_field(entry, 6); + dfield = dtuple_get_nth_field(entry, 6/*PREC*/); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, 0/* unused */); @@ -230,19 +235,26 @@ dict_build_table_def_step( dict_table_t* table; dtuple_t* row; ulint error; + ulint flags; const char* path_or_name; ibool is_path; mtr_t mtr; + ulint space = 0; ut_ad(mutex_own(&(dict_sys->mutex))); table = node->table; - table->id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); + dict_hdr_get_new_id(&table->id, NULL, + srv_file_per_table ? &space : NULL); thr_get_trx(thr)->table_id = table->id; if (srv_file_per_table) { + if (UNIV_UNLIKELY(space == ULINT_UNDEFINED)) { + return(DB_ERROR); + } + /* We create a new single-table tablespace for the table. We initially let it be 4 pages: - page 0 is the fsp header and an extent descriptor page, @@ -251,8 +263,6 @@ dict_build_table_def_step( - page 3 will contain the root of the clustered index of the table we create here. */ - ulint space = 0; /* reset to zero for the call below */ - if (table->dir_path_of_temp_table) { /* We place tables created with CREATE TEMPORARY TABLE in the tmp dir of mysqld server */ @@ -268,9 +278,10 @@ dict_build_table_def_step( ut_ad(!dict_table_zip_size(table) || dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP); + flags = table->flags & ~(~0 << DICT_TF_BITS); error = fil_create_new_single_table_tablespace( - &space, path_or_name, is_path, - table->flags == DICT_TF_COMPACT ? 0 : table->flags, + space, path_or_name, is_path, + flags == DICT_TF_COMPACT ? 0 : flags, FIL_IBD_FILE_INITIAL_SIZE); table->space = (unsigned int) space; @@ -286,7 +297,7 @@ dict_build_table_def_step( mtr_commit(&mtr); } else { /* Create in the system tablespace: disallow new features */ - table->flags &= DICT_TF_COMPACT; + table->flags &= (~0 << DICT_TF_BITS) | DICT_TF_COMPACT; } row = dict_create_sys_tables_tuple(table, node->heap); @@ -322,9 +333,10 @@ static dtuple_t* dict_create_sys_indexes_tuple( /*==========================*/ - dict_index_t* index, /*!< in: index */ - mem_heap_t* heap) /*!< in: memory heap from which the memory for - the built tuple is allocated */ + const dict_index_t* index, /*!< in: index */ + mem_heap_t* heap) /*!< in: memory heap from + which the memory for the built + tuple is allocated */ { dict_table_t* sys_indexes; dict_table_t* table; @@ -333,7 +345,8 @@ dict_create_sys_indexes_tuple( byte* ptr; ut_ad(mutex_own(&(dict_sys->mutex))); - ut_ad(index && heap); + ut_ad(index); + ut_ad(heap); sys_indexes = dict_sys->sys_indexes; @@ -344,32 +357,32 @@ dict_create_sys_indexes_tuple( dict_table_copy_types(entry, sys_indexes); /* 0: TABLE_ID -----------------------*/ - dfield = dtuple_get_nth_field(entry, 0); + dfield = dtuple_get_nth_field(entry, 0/*TABLE_ID*/); ptr = mem_heap_alloc(heap, 8); mach_write_to_8(ptr, table->id); dfield_set_data(dfield, ptr, 8); /* 1: ID ----------------------------*/ - dfield = dtuple_get_nth_field(entry, 1); + dfield = dtuple_get_nth_field(entry, 1/*ID*/); ptr = mem_heap_alloc(heap, 8); mach_write_to_8(ptr, index->id); dfield_set_data(dfield, ptr, 8); /* 4: NAME --------------------------*/ - dfield = dtuple_get_nth_field(entry, 2); + dfield = dtuple_get_nth_field(entry, 2/*NAME*/); dfield_set_data(dfield, index->name, ut_strlen(index->name)); /* 5: N_FIELDS ----------------------*/ - dfield = dtuple_get_nth_field(entry, 3); + dfield = dtuple_get_nth_field(entry, 3/*N_FIELDS*/); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, index->n_fields); dfield_set_data(dfield, ptr, 4); /* 6: TYPE --------------------------*/ - dfield = dtuple_get_nth_field(entry, 4); + dfield = dtuple_get_nth_field(entry, 4/*TYPE*/); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, index->type); @@ -381,7 +394,7 @@ dict_create_sys_indexes_tuple( #error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 7" #endif - dfield = dtuple_get_nth_field(entry, 5); + dfield = dtuple_get_nth_field(entry, 5/*SPACE*/); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, index->space); @@ -393,7 +406,7 @@ dict_create_sys_indexes_tuple( #error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 8" #endif - dfield = dtuple_get_nth_field(entry, 6); + dfield = dtuple_get_nth_field(entry, 6/*PAGE_NO*/); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, FIL_NULL); @@ -412,10 +425,11 @@ static dtuple_t* dict_create_sys_fields_tuple( /*=========================*/ - dict_index_t* index, /*!< in: index */ - ulint i, /*!< in: field number */ - mem_heap_t* heap) /*!< in: memory heap from which the memory for - the built tuple is allocated */ + const dict_index_t* index, /*!< in: index */ + ulint i, /*!< in: field number */ + mem_heap_t* heap) /*!< in: memory heap from + which the memory for the built + tuple is allocated */ { dict_table_t* sys_fields; dtuple_t* entry; @@ -425,7 +439,8 @@ dict_create_sys_fields_tuple( ibool index_contains_column_prefix_field = FALSE; ulint j; - ut_ad(index && heap); + ut_ad(index); + ut_ad(heap); for (j = 0; j < index->n_fields; j++) { if (dict_index_get_nth_field(index, j)->prefix_len > 0) { @@ -443,7 +458,7 @@ dict_create_sys_fields_tuple( dict_table_copy_types(entry, sys_fields); /* 0: INDEX_ID -----------------------*/ - dfield = dtuple_get_nth_field(entry, 0); + dfield = dtuple_get_nth_field(entry, 0/*INDEX_ID*/); ptr = mem_heap_alloc(heap, 8); mach_write_to_8(ptr, index->id); @@ -451,7 +466,7 @@ dict_create_sys_fields_tuple( dfield_set_data(dfield, ptr, 8); /* 1: POS + PREFIX LENGTH ----------------------------*/ - dfield = dtuple_get_nth_field(entry, 1); + dfield = dtuple_get_nth_field(entry, 1/*POS*/); ptr = mem_heap_alloc(heap, 4); @@ -471,7 +486,7 @@ dict_create_sys_fields_tuple( dfield_set_data(dfield, ptr, 4); /* 4: COL_NAME -------------------------*/ - dfield = dtuple_get_nth_field(entry, 2); + dfield = dtuple_get_nth_field(entry, 2/*COL_NAME*/); dfield_set_data(dfield, field->name, ut_strlen(field->name)); @@ -550,7 +565,7 @@ dict_build_index_def_step( ut_ad((UT_LIST_GET_LEN(table->indexes) > 0) || dict_index_is_clust(index)); - index->id = dict_hdr_get_new_id(DICT_HDR_INDEX_ID); + dict_hdr_get_new_id(NULL, &index->id, NULL); /* Inherit the space id from the table; we store all indexes of a table in the same tablespace */ @@ -602,6 +617,7 @@ dict_create_index_tree_step( dict_table_t* sys_indexes; dict_table_t* table; dtuple_t* search_tuple; + ulint zip_size; btr_pcur_t pcur; mtr_t mtr; @@ -626,8 +642,9 @@ dict_create_index_tree_step( btr_pcur_move_to_next_user_rec(&pcur, &mtr); - node->page_no = btr_create(index->type, index->space, - dict_table_zip_size(index->table), + zip_size = dict_table_zip_size(index->table); + + node->page_no = btr_create(index->type, index->space, zip_size, index->id, index, &mtr); /* printf("Created a new index tree in space %lu root page %lu\n", index->space, index->page_no); */ @@ -1092,8 +1109,11 @@ dict_create_index_step( dulint index_id = node->index->id; - err = dict_index_add_to_cache(node->table, node->index, - FIL_NULL, TRUE); + err = dict_index_add_to_cache( + node->table, node->index, FIL_NULL, + trx_is_strict(trx) + || dict_table_get_format(node->table) + >= DICT_TF_FORMAT_ZIP); node->index = dict_index_get_if_in_cache_low(index_id); ut_a(!node->index == (err != DB_SUCCESS)); diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index 2e524a5a2e3..a298d785449 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -70,6 +70,17 @@ we need this; NOTE: a transaction which reserves this must keep book on the mode in trx_struct::dict_operation_lock_mode */ UNIV_INTERN rw_lock_t dict_operation_lock; +/* Keys to register rwlocks and mutexes with performance schema */ +#ifdef UNIV_PFS_RWLOCK +UNIV_INTERN mysql_pfs_key_t dict_operation_lock_key; +UNIV_INTERN mysql_pfs_key_t index_tree_rw_lock_key; +#endif /* UNIV_PFS_RWLOCK */ + +#ifdef UNIV_PFS_MUTEX +UNIV_INTERN mysql_pfs_key_t dict_sys_mutex_key; +UNIV_INTERN mysql_pfs_key_t dict_foreign_err_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + #define DICT_HEAP_SIZE 100 /*!< initial memory heap size when creating a table or index object */ #define DICT_POOL_PER_TABLE_HASH 512 /*!< buffer pool max size per table @@ -80,6 +91,10 @@ UNIV_INTERN rw_lock_t dict_operation_lock; /** Identifies generated InnoDB foreign key names */ static char dict_ibfk[] = "_ibfk_"; +/** array of mutexes protecting dict_index_t::stat_n_diff_key_vals[] */ +#define DICT_INDEX_STAT_MUTEX_SIZE 32 +mutex_t dict_index_stat_mutex[DICT_INDEX_STAT_MUTEX_SIZE]; + /*******************************************************************//** Tries to find column names for the index and sets the col field of the index. @@ -140,7 +155,7 @@ static void dict_field_print_low( /*=================*/ - dict_field_t* field); /*!< in: field */ + const dict_field_t* field); /*!< in: field */ /*********************************************************************//** Frees a foreign key struct. */ static @@ -239,6 +254,45 @@ dict_mutex_exit_for_mysql(void) mutex_exit(&(dict_sys->mutex)); } +/** Get the mutex that protects index->stat_n_diff_key_vals[] */ +#define GET_INDEX_STAT_MUTEX(index) \ + (&dict_index_stat_mutex[ut_fold_dulint(index->id) \ + % DICT_INDEX_STAT_MUTEX_SIZE]) + +/**********************************************************************//** +Lock the appropriate mutex to protect index->stat_n_diff_key_vals[]. +index->id is used to pick the right mutex and it should not change +before dict_index_stat_mutex_exit() is called on this index. */ +UNIV_INTERN +void +dict_index_stat_mutex_enter( +/*========================*/ + const dict_index_t* index) /*!< in: index */ +{ + ut_ad(index != NULL); + ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + ut_ad(index->cached); + ut_ad(!index->to_be_dropped); + + mutex_enter(GET_INDEX_STAT_MUTEX(index)); +} + +/**********************************************************************//** +Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */ +UNIV_INTERN +void +dict_index_stat_mutex_exit( +/*=======================*/ + const dict_index_t* index) /*!< in: index */ +{ + ut_ad(index != NULL); + ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); + ut_ad(index->cached); + ut_ad(!index->to_be_dropped); + + mutex_exit(GET_INDEX_STAT_MUTEX(index)); +} + /********************************************************************//** Decrements the count of open MySQL handles to a table. */ UNIV_INTERN @@ -605,9 +659,11 @@ void dict_init(void) /*===========*/ { + int i; + dict_sys = mem_alloc(sizeof(dict_sys_t)); - mutex_create(&dict_sys->mutex, SYNC_DICT); + mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT); dict_sys->table_hash = hash_create(buf_pool_get_curr_size() / (DICT_POOL_PER_TABLE_HASH @@ -619,12 +675,19 @@ dict_init(void) UT_LIST_INIT(dict_sys->table_LRU); - rw_lock_create(&dict_operation_lock, SYNC_DICT_OPERATION); + rw_lock_create(dict_operation_lock_key, + &dict_operation_lock, SYNC_DICT_OPERATION); dict_foreign_err_file = os_file_create_tmpfile(); ut_a(dict_foreign_err_file); - mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH); + mutex_create(dict_foreign_err_mutex_key, + &dict_foreign_err_mutex, SYNC_ANY_LATCH); + + for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) { + mutex_create(PFS_NOT_INSTRUMENTED, + &dict_index_stat_mutex[i], SYNC_INDEX_TREE); + } } /**********************************************************************//** @@ -1460,6 +1523,7 @@ dict_index_add_to_cache( if (!dict_index_find_cols(table, index)) { + dict_mem_index_free(index); return(DB_CORRUPTION); } @@ -1566,7 +1630,8 @@ undo_size_ok: new_index->stat_n_leaf_pages = 1; new_index->page = page_no; - rw_lock_create(&new_index->lock, SYNC_INDEX_TREE); + rw_lock_create(index_tree_rw_lock_key, &new_index->lock, + SYNC_INDEX_TREE); if (!UNIV_UNLIKELY(new_index->type & DICT_UNIVERSAL)) { @@ -2958,25 +3023,28 @@ static char* dict_strip_comments( /*================*/ - const char* sql_string) /*!< in: SQL string */ + const char* sql_string, /*!< in: SQL string */ + size_t sql_length) /*!< in: length of sql_string */ { char* str; const char* sptr; + const char* eptr = sql_string + sql_length; char* ptr; /* unclosed quote character (0 if none) */ char quote = 0; - str = mem_alloc(strlen(sql_string) + 1); + str = mem_alloc(sql_length + 1); sptr = sql_string; ptr = str; for (;;) { scan_more: - if (*sptr == '\0') { + if (sptr >= eptr || *sptr == '\0') { +end_of_string: *ptr = '\0'; - ut_a(ptr <= str + strlen(sql_string)); + ut_a(ptr <= str + sql_length); return(str); } @@ -2995,30 +3063,35 @@ scan_more: || (sptr[0] == '-' && sptr[1] == '-' && sptr[2] == ' ')) { for (;;) { + if (++sptr >= eptr) { + goto end_of_string; + } + /* In Unix a newline is 0x0A while in Windows it is 0x0D followed by 0x0A */ - if (*sptr == (char)0x0A - || *sptr == (char)0x0D - || *sptr == '\0') { - + switch (*sptr) { + case (char) 0X0A: + case (char) 0x0D: + case '\0': goto scan_more; } - - sptr++; } } else if (!quote && *sptr == '/' && *(sptr + 1) == '*') { + sptr += 2; for (;;) { - if (*sptr == '*' && *(sptr + 1) == '/') { - - sptr += 2; - - goto scan_more; + if (sptr >= eptr) { + goto end_of_string; } - if (*sptr == '\0') { - + switch (*sptr) { + case '\0': goto scan_more; + case '*': + if (sptr[1] == '/') { + sptr += 2; + goto scan_more; + } } sptr++; @@ -3699,6 +3772,7 @@ dict_create_foreign_constraints( name before it: test.table2; the default database id the database of parameter name */ + size_t sql_length, /*!< in: length of sql_string */ const char* name, /*!< in: table full name in the normalized form database_name/table_name */ @@ -3713,7 +3787,7 @@ dict_create_foreign_constraints( ut_a(trx); ut_a(trx->mysql_thd); - str = dict_strip_comments(sql_string); + str = dict_strip_comments(sql_string, sql_length); heap = mem_heap_create(10000); err = dict_create_foreign_constraints_low( @@ -3746,6 +3820,7 @@ dict_foreign_parse_drop_constraints( dict_foreign_t* foreign; ibool success; char* str; + size_t len; const char* ptr; const char* id; FILE* ef = dict_foreign_err_file; @@ -3760,7 +3835,10 @@ dict_foreign_parse_drop_constraints( *constraints_to_drop = mem_heap_alloc(heap, 1000 * sizeof(char*)); - str = dict_strip_comments(*(trx->mysql_query_str)); + ptr = innobase_get_stmt(trx->mysql_thd, &len); + + str = dict_strip_comments(ptr, len); + ptr = str; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -4170,9 +4248,13 @@ dict_update_statistics_low( index = dict_table_get_first_index(table); + dict_index_stat_mutex_enter(index); + table->stat_n_rows = index->stat_n_diff_key_vals[ dict_index_get_n_unique(index)]; + dict_index_stat_mutex_exit(index); + table->stat_clustered_index_size = index->stat_index_size; table->stat_sum_of_other_index_sizes = sum_of_index_sizes @@ -4350,6 +4432,8 @@ dict_index_print_low( ut_ad(mutex_own(&(dict_sys->mutex))); + dict_index_stat_mutex_enter(index); + if (index->n_user_defined_cols > 0) { n_vals = index->stat_n_diff_key_vals[ index->n_user_defined_cols]; @@ -4357,6 +4441,8 @@ dict_index_print_low( n_vals = index->stat_n_diff_key_vals[1]; } + dict_index_stat_mutex_exit(index); + if (dict_index_is_clust(index)) { type_string = "clustered index"; } else if (dict_index_is_unique(index)) { @@ -4402,7 +4488,7 @@ static void dict_field_print_low( /*=================*/ - dict_field_t* field) /*!< in: field */ + const dict_field_t* field) /*!< in: field */ { ut_ad(mutex_own(&(dict_sys->mutex))); @@ -4766,8 +4852,10 @@ UNIV_INTERN void dict_table_check_for_dup_indexes( /*=============================*/ - const dict_table_t* table) /*!< in: Check for dup indexes + const dict_table_t* table, /*!< in: Check for dup indexes in this table */ + ibool tmp_ok) /*!< in: TRUE=allow temporary + index names */ { /* Check for duplicates, ignoring indexes that are marked as to be dropped */ @@ -4775,13 +4863,17 @@ dict_table_check_for_dup_indexes( const dict_index_t* index1; const dict_index_t* index2; + ut_ad(mutex_own(&dict_sys->mutex)); + /* The primary index _must_ exist */ ut_a(UT_LIST_GET_LEN(table->indexes) > 0); index1 = UT_LIST_GET_FIRST(table->indexes); - index2 = UT_LIST_GET_NEXT(indexes, index1); - while (index1 && index2) { + do { + ut_ad(tmp_ok || *index1->name != TEMP_INDEX_PREFIX); + + index2 = UT_LIST_GET_NEXT(indexes, index1); while (index2) { @@ -4793,8 +4885,7 @@ dict_table_check_for_dup_indexes( } index1 = UT_LIST_GET_NEXT(indexes, index1); - index2 = UT_LIST_GET_NEXT(indexes, index1); - } + } while (index1); } #endif /* UNIV_DEBUG */ @@ -4847,5 +4938,9 @@ dict_close(void) mem_free(dict_sys); dict_sys = NULL; + + for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) { + mutex_free(&dict_index_stat_mutex[i]); + } } #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index 842a129c1a6..b061fe696c1 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -41,6 +41,16 @@ Created 4/24/1996 Heikki Tuuri #include "srv0start.h" #include "srv0srv.h" + +/** Following are six InnoDB system tables */ +static const char* SYSTEM_TABLE_NAME[] = { + "SYS_TABLES", + "SYS_INDEXES", + "SYS_COLUMNS", + "SYS_FIELDS", + "SYS_FOREIGN", + "SYS_FOREIGN_COLS" +}; /****************************************************************//** Compare the name of an index column. @return TRUE if the i'th column of index is 'name'. */ @@ -151,13 +161,10 @@ void dict_print(void) /*============*/ { - dict_table_t* sys_tables; - dict_index_t* sys_index; dict_table_t* table; btr_pcur_t pcur; const rec_t* rec; - const byte* field; - ulint len; + mem_heap_t* heap; mtr_t mtr; /* Enlarge the fatal semaphore wait timeout during the InnoDB table @@ -167,76 +174,397 @@ dict_print(void) srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */ mutex_exit(&kernel_mutex); + heap = mem_heap_create(1000); mutex_enter(&(dict_sys->mutex)); - mtr_start(&mtr); - sys_tables = dict_table_get_low("SYS_TABLES"); - sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); + rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES); - btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur, - TRUE, &mtr); -loop: - btr_pcur_move_to_next_user_rec(&pcur, &mtr); + while (rec) { + const char* err_msg; - rec = btr_pcur_get_rec(&pcur); + err_msg = dict_process_sys_tables_rec( + heap, rec, &table, DICT_TABLE_LOAD_FROM_CACHE + | DICT_TABLE_UPDATE_STATS); - if (!btr_pcur_is_on_user_rec(&pcur)) { - /* end of index */ - - btr_pcur_close(&pcur); mtr_commit(&mtr); - mutex_exit(&(dict_sys->mutex)); + if (!err_msg) { + dict_table_print_low(table); + } else { + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: %s\n", err_msg); + } - /* Restore the fatal semaphore wait timeout */ + mem_heap_empty(heap); - mutex_enter(&kernel_mutex); - srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */ - mutex_exit(&kernel_mutex); + mtr_start(&mtr); + rec = dict_getnext_system(&pcur, &mtr); + } - return; + mtr_commit(&mtr); + mutex_exit(&(dict_sys->mutex)); + mem_heap_free(heap); + + /* Restore the fatal semaphore wait timeout */ + mutex_enter(&kernel_mutex); + srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */ + mutex_exit(&kernel_mutex); +} + + +/********************************************************************//** +This function gets the next system table record as it scans the table. +@return the next record if found, NULL if end of scan */ +static +const rec_t* +dict_getnext_system_low( +/*====================*/ + btr_pcur_t* pcur, /*!< in/out: persistent cursor to the + record*/ + mtr_t* mtr) /*!< in: the mini-transaction */ +{ + rec_t* rec = NULL; + + while (!rec || rec_get_deleted_flag(rec, 0)) { + btr_pcur_move_to_next_user_rec(pcur, mtr); + + rec = btr_pcur_get_rec(pcur); + + if (!btr_pcur_is_on_user_rec(pcur)) { + /* end of index */ + btr_pcur_close(pcur); + + return(NULL); + } } - field = rec_get_nth_field_old(rec, 0, &len); + /* Get a record, let's save the position */ + btr_pcur_store_position(pcur, mtr); - if (!rec_get_deleted_flag(rec, 0)) { + return(rec); +} - /* We found one */ +/********************************************************************//** +This function opens a system table, and return the first record. +@return first record of the system table */ +UNIV_INTERN +const rec_t* +dict_startscan_system( +/*==================*/ + btr_pcur_t* pcur, /*!< out: persistent cursor to + the record */ + mtr_t* mtr, /*!< in: the mini-transaction */ + dict_system_id_t system_id) /*!< in: which system table to open */ +{ + dict_table_t* system_table; + dict_index_t* clust_index; + const rec_t* rec; - char* table_name = mem_strdupl((char*) field, len); + ut_a(system_id < SYS_NUM_SYSTEM_TABLES); - btr_pcur_store_position(&pcur, &mtr); + system_table = dict_table_get_low(SYSTEM_TABLE_NAME[system_id]); - mtr_commit(&mtr); + clust_index = UT_LIST_GET_FIRST(system_table->indexes); - table = dict_table_get_low(table_name); - mem_free(table_name); + btr_pcur_open_at_index_side(TRUE, clust_index, BTR_SEARCH_LEAF, pcur, + TRUE, mtr); - if (table == NULL) { - fputs("InnoDB: Failed to load table ", stderr); - ut_print_namel(stderr, NULL, TRUE, (char*) field, len); - putc('\n', stderr); - } else { - /* The table definition was corrupt if there - is no index */ + rec = dict_getnext_system_low(pcur, mtr); - if (dict_table_get_first_index(table)) { - dict_update_statistics_low(table, TRUE); - } + return(rec); +} - dict_table_print_low(table); +/********************************************************************//** +This function gets the next system table record as it scans the table. +@return the next record if found, NULL if end of scan */ +UNIV_INTERN +const rec_t* +dict_getnext_system( +/*================*/ + btr_pcur_t* pcur, /*!< in/out: persistent cursor + to the record */ + mtr_t* mtr) /*!< in: the mini-transaction */ +{ + const rec_t* rec; + + /* Restore the position */ + btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr); + + /* Get the next record */ + rec = dict_getnext_system_low(pcur, mtr); + + return(rec); +} +/********************************************************************//** +This function processes one SYS_TABLES record and populate the dict_table_t +struct for the table. Extracted out of dict_print() to be used by +both monitor table output and information schema innodb_sys_tables output. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_tables_rec( +/*========================*/ + mem_heap_t* heap, /*!< in/out: temporary memory heap */ + const rec_t* rec, /*!< in: SYS_TABLES record */ + dict_table_t** table, /*!< out: dict_table_t to fill */ + dict_table_info_t status) /*!< in: status bit controls + options such as whether we shall + look for dict_table_t from cache + first */ +{ + ulint len; + const char* field; + const char* err_msg = NULL; + char* table_name; + + field = (const char*) rec_get_nth_field_old(rec, 0, &len); + + ut_a(!rec_get_deleted_flag(rec, 0)); + + /* Get the table name */ + table_name = mem_heap_strdupl(heap, field, len); + + /* If DICT_TABLE_LOAD_FROM_CACHE is set, first check + whether there is cached dict_table_t struct first */ + if (status & DICT_TABLE_LOAD_FROM_CACHE) { + *table = dict_table_get_low(table_name); + + if (!(*table)) { + err_msg = "Table not found in cache"; } + } else { + err_msg = dict_load_table_low(table_name, rec, table); + } - mtr_start(&mtr); + if (err_msg) { + return(err_msg); + } - btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); + if ((status & DICT_TABLE_UPDATE_STATS) + && dict_table_get_first_index(*table)) { + + /* Update statistics if DICT_TABLE_UPDATE_STATS + is set */ + dict_update_statistics_low(*table, TRUE); } - goto loop; + return(NULL); } /********************************************************************//** +This function parses a SYS_INDEXES record and populate a dict_index_t +structure with the information from the record. For detail information +about SYS_INDEXES fields, please refer to dict_boot() function. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_indexes_rec( +/*=========================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_INDEXES rec */ + dict_index_t* index, /*!< out: index to be filled */ + dulint* table_id) /*!< out: index table id */ +{ + const char* err_msg; + byte* buf; + + buf = mem_heap_alloc(heap, 8); + + /* Parse the record, and get "dict_index_t" struct filled */ + err_msg = dict_load_index_low(buf, NULL, + heap, rec, FALSE, &index); + + *table_id = mach_read_from_8(buf); + + return(err_msg); +} +/********************************************************************//** +This function parses a SYS_COLUMNS record and populate a dict_column_t +structure with the information from the record. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_columns_rec( +/*=========================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_COLUMNS rec */ + dict_col_t* column, /*!< out: dict_col_t to be filled */ + dulint* table_id, /*!< out: table id */ + const char** col_name) /*!< out: column name */ +{ + const char* err_msg; + + /* Parse the record, and get "dict_col_t" struct filled */ + err_msg = dict_load_column_low(NULL, heap, column, + table_id, col_name, rec); + + return(err_msg); +} +/********************************************************************//** +This function parses a SYS_FIELDS record and populates a dict_field_t +structure with the information from the record. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_fields_rec( +/*========================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_FIELDS rec */ + dict_field_t* sys_field, /*!< out: dict_field_t to be + filled */ + ulint* pos, /*!< out: Field position */ + dulint* index_id, /*!< out: current index id */ + dulint last_id) /*!< in: previous index id */ +{ + byte* buf; + byte* last_index_id; + const char* err_msg; + + buf = mem_heap_alloc(heap, 8); + + last_index_id = mem_heap_alloc(heap, 8); + mach_write_to_8(last_index_id, last_id); + + err_msg = dict_load_field_low(buf, NULL, sys_field, + pos, last_index_id, heap, rec); + + *index_id = mach_read_from_8(buf); + + return(err_msg); + +} +/********************************************************************//** +This function parses a SYS_FOREIGN record and populate a dict_foreign_t +structure with the information from the record. For detail information +about SYS_FOREIGN fields, please refer to dict_load_foreign() function +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_foreign_rec( +/*=========================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_FOREIGN rec */ + dict_foreign_t* foreign) /*!< out: dict_foreign_t struct + to be filled */ +{ + ulint len; + const byte* field; + ulint n_fields_and_type; + + if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) { + return("delete-marked record in SYS_FOREIGN"); + } + + if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) { + return("wrong number of columns in SYS_FOREIGN record"); + } + + field = rec_get_nth_field_old(rec, 0/*ID*/, &len); + if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) { +err_len: + return("incorrect column length in SYS_FOREIGN"); + } + foreign->id = mem_heap_strdupl(heap, (const char*) field, len); + + rec_get_nth_field_offs_old(rec, 1/*DB_TRX_ID*/, &len); + if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) { + goto err_len; + } + rec_get_nth_field_offs_old(rec, 2/*DB_ROLL_PTR*/, &len); + if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) { + goto err_len; + } + + field = rec_get_nth_field_old(rec, 3/*FOR_NAME*/, &len); + if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) { + goto err_len; + } + foreign->foreign_table_name = mem_heap_strdupl( + heap, (const char*) field, len); + + field = rec_get_nth_field_old(rec, 4/*REF_NAME*/, &len); + if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) { + goto err_len; + } + foreign->referenced_table_name = mem_heap_strdupl( + heap, (const char*) field, len); + + field = rec_get_nth_field_old(rec, 5/*N_COLS*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + n_fields_and_type = mach_read_from_4(field); + + foreign->type = (unsigned int) (n_fields_and_type >> 24); + foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL); + + return(NULL); +} +/********************************************************************//** +This function parses a SYS_FOREIGN_COLS record and extract necessary +information from the record and return to caller. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_foreign_col_rec( +/*=============================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_FOREIGN_COLS rec */ + const char** name, /*!< out: foreign key constraint name */ + const char** for_col_name, /*!< out: referencing column name */ + const char** ref_col_name, /*!< out: referenced column name + in referenced table */ + ulint* pos) /*!< out: column position */ +{ + ulint len; + const byte* field; + + if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) { + return("delete-marked record in SYS_FOREIGN_COLS"); + } + + if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 6)) { + return("wrong number of columns in SYS_FOREIGN_COLS record"); + } + + field = rec_get_nth_field_old(rec, 0/*ID*/, &len); + if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) { +err_len: + return("incorrect column length in SYS_FOREIGN_COLS"); + } + *name = mem_heap_strdupl(heap, (char*) field, len); + + field = rec_get_nth_field_old(rec, 1/*POS*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + *pos = mach_read_from_4(field); + + rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len); + if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) { + goto err_len; + } + rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len); + if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) { + goto err_len; + } + + field = rec_get_nth_field_old(rec, 4/*FOR_COL_NAME*/, &len); + if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) { + goto err_len; + } + *for_col_name = mem_heap_strdupl(heap, (char*) field, len); + + field = rec_get_nth_field_old(rec, 5/*REF_COL_NAME*/, &len); + if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) { + goto err_len; + } + *ref_col_name = mem_heap_strdupl(heap, (char*) field, len); + + return(NULL); +} +/********************************************************************//** Determine the flags of a table described in SYS_TABLES. @return compressed page size in kilobytes; or 0 if the tablespace is uncompressed, ULINT_UNDEFINED on error */ @@ -260,7 +588,7 @@ dict_sys_tables_get_flags( return(0); } - field = rec_get_nth_field_old(rec, 4, &len); + field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len); n_cols = mach_read_from_4(field); if (UNIV_UNLIKELY(!(n_cols & 0x80000000UL))) { @@ -390,15 +718,35 @@ loop: mtr_commit(&mtr); - if (space_id != 0 && in_crash_recovery) { + if (space_id == 0) { + /* The system tablespace always exists. */ + } else if (in_crash_recovery) { /* Check that the tablespace (the .ibd file) really - exists; print a warning to the .err log if not */ - - fil_space_for_table_exists_in_mem(space_id, name, - FALSE, TRUE, TRUE); - } + exists; print a warning to the .err log if not. + Do not print warnings for temporary tables. */ + ibool is_temp; + + field = rec_get_nth_field_old(rec, 4, &len); + if (0x80000000UL & mach_read_from_4(field)) { + /* ROW_FORMAT=COMPACT: read the is_temp + flag from SYS_TABLES.MIX_LEN. */ + field = rec_get_nth_field_old(rec, 7, &len); + is_temp = mach_read_from_4(field) + & DICT_TF2_TEMPORARY; + } else { + /* For tables created with old versions + of InnoDB, SYS_TABLES.MIX_LEN may contain + garbage. Such tables would always be + in ROW_FORMAT=REDUNDANT. Pretend that + all such tables are non-temporary. That is, + do not suppress error printouts about + temporary tables not being found. */ + is_temp = FALSE; + } - if (space_id != 0 && !in_crash_recovery) { + fil_space_for_table_exists_in_mem( + space_id, name, is_temp, TRUE, !is_temp); + } else { /* It is a normal database startup: create the space object and check that the .ibd file exists. */ @@ -421,13 +769,149 @@ loop: } /********************************************************************//** +Loads a table column definition from a SYS_COLUMNS record to +dict_table_t. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_load_column_low( +/*=================*/ + dict_table_t* table, /*!< in/out: table, could be NULL + if we just polulate a dict_column_t + struct with information from + a SYS_COLUMNS record */ + mem_heap_t* heap, /*!< in/out: memory heap + for temporary storage */ + dict_col_t* column, /*!< out: dict_column_t to fill */ + dulint* table_id, /*!< out: table id */ + const char** col_name, /*!< out: column name */ + const rec_t* rec) /*!< in: SYS_COLUMNS record */ +{ + char* name; + const byte* field; + ulint len; + ulint mtype; + ulint prtype; + ulint col_len; + ulint pos; + + if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) { + return("delete-marked record in SYS_COLUMNS"); + } + + if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) { + return("wrong number of columns in SYS_COLUMNS record"); + } + + field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len); + if (UNIV_UNLIKELY(len != 8)) { +err_len: + return("incorrect column length in SYS_COLUMNS"); + } + + if (table_id) { + *table_id = mach_read_from_8(field); + } else if (UNIV_UNLIKELY(ut_dulint_cmp(table->id, + mach_read_from_8(field)))) { + return("SYS_COLUMNS.TABLE_ID mismatch"); + } + + field = rec_get_nth_field_old(rec, 1/*POS*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + + goto err_len; + } + + if (!table) { + pos = mach_read_from_4(field); + } else if (UNIV_UNLIKELY(table->n_def != mach_read_from_4(field))) { + return("SYS_COLUMNS.POS mismatch"); + } + + rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len); + if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) { + goto err_len; + } + rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len); + if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) { + goto err_len; + } + + field = rec_get_nth_field_old(rec, 4/*NAME*/, &len); + if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) { + goto err_len; + } + + name = mem_heap_strdupl(heap, (const char*) field, len); + + if (col_name) { + *col_name = name; + } + + field = rec_get_nth_field_old(rec, 5/*MTYPE*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + + mtype = mach_read_from_4(field); + + field = rec_get_nth_field_old(rec, 6/*PRTYPE*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + prtype = mach_read_from_4(field); + + if (dtype_get_charset_coll(prtype) == 0 + && dtype_is_string_type(mtype)) { + /* The table was created with < 4.1.2. */ + + if (dtype_is_binary_string_type(mtype, prtype)) { + /* Use the binary collation for + string columns of binary type. */ + + prtype = dtype_form_prtype( + prtype, + DATA_MYSQL_BINARY_CHARSET_COLL); + } else { + /* Use the default charset for + other than binary columns. */ + + prtype = dtype_form_prtype( + prtype, + data_mysql_default_charset_coll); + } + } + + field = rec_get_nth_field_old(rec, 7/*LEN*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + col_len = mach_read_from_4(field); + field = rec_get_nth_field_old(rec, 8/*PREC*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + + if (!column) { + dict_mem_table_add_col(table, heap, name, mtype, + prtype, col_len); + } else { + dict_mem_fill_column_struct(column, pos, mtype, + prtype, col_len); + } + + return(NULL); +} + +/********************************************************************//** Loads definitions for table columns. */ static void dict_load_columns( /*==============*/ - dict_table_t* table, /*!< in: table */ - mem_heap_t* heap) /*!< in: memory heap for temporary storage */ + dict_table_t* table, /*!< in/out: table */ + mem_heap_t* heap) /*!< in/out: memory heap + for temporary storage */ { dict_table_t* sys_columns; dict_index_t* sys_index; @@ -435,13 +919,7 @@ dict_load_columns( dtuple_t* tuple; dfield_t* dfield; const rec_t* rec; - const byte* field; - ulint len; byte* buf; - char* name; - ulint mtype; - ulint prtype; - ulint col_len; ulint i; mtr_t mtr; @@ -453,6 +931,9 @@ dict_load_columns( sys_index = UT_LIST_GET_FIRST(sys_columns->indexes); ut_a(!dict_table_is_comp(sys_columns)); + ut_a(name_of_col_is(sys_columns, sys_index, 4, "NAME")); + ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC")); + tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); @@ -465,74 +946,156 @@ dict_load_columns( btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) { + const char* err_msg; rec = btr_pcur_get_rec(&pcur); ut_a(btr_pcur_is_on_user_rec(&pcur)); - ut_a(!rec_get_deleted_flag(rec, 0)); + err_msg = dict_load_column_low(table, heap, NULL, NULL, + NULL, rec); - field = rec_get_nth_field_old(rec, 0, &len); - ut_ad(len == 8); - ut_a(ut_dulint_cmp(table->id, mach_read_from_8(field)) == 0); + if (err_msg) { + fprintf(stderr, "InnoDB: %s\n", err_msg); + ut_error; + } - field = rec_get_nth_field_old(rec, 1, &len); - ut_ad(len == 4); - ut_a(i == mach_read_from_4(field)); + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + } - ut_a(name_of_col_is(sys_columns, sys_index, 4, "NAME")); + btr_pcur_close(&pcur); + mtr_commit(&mtr); +} - field = rec_get_nth_field_old(rec, 4, &len); - name = mem_heap_strdupl(heap, (char*) field, len); +/** Error message for a delete-marked record in dict_load_field_low() */ +static const char* dict_load_field_del = "delete-marked record in SYS_FIELDS"; - field = rec_get_nth_field_old(rec, 5, &len); - mtype = mach_read_from_4(field); +/********************************************************************//** +Loads an index field definition from a SYS_FIELDS record to +dict_index_t. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_load_field_low( +/*================*/ + byte* index_id, /*!< in/out: index id (8 bytes) + an "in" value if index != NULL + and "out" if index == NULL */ + dict_index_t* index, /*!< in/out: index, could be NULL + if we just populate a dict_field_t + struct with information from + a SYS_FIELDSS record */ + dict_field_t* sys_field, /*!< out: dict_field_t to be + filled */ + ulint* pos, /*!< out: Field position */ + byte* last_index_id, /*!< in: last index id */ + mem_heap_t* heap, /*!< in/out: memory heap + for temporary storage */ + const rec_t* rec) /*!< in: SYS_FIELDS record */ +{ + const byte* field; + ulint len; + ulint pos_and_prefix_len; + ulint prefix_len; + ibool first_field; + ulint position; - field = rec_get_nth_field_old(rec, 6, &len); - prtype = mach_read_from_4(field); + /* Either index or sys_field is supplied, not both */ + ut_a((!index) || (!sys_field)); - if (dtype_get_charset_coll(prtype) == 0 - && dtype_is_string_type(mtype)) { - /* The table was created with < 4.1.2. */ + if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) { + return(dict_load_field_del); + } - if (dtype_is_binary_string_type(mtype, prtype)) { - /* Use the binary collation for - string columns of binary type. */ + if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 5)) { + return("wrong number of columns in SYS_FIELDS record"); + } - prtype = dtype_form_prtype( - prtype, - DATA_MYSQL_BINARY_CHARSET_COLL); - } else { - /* Use the default charset for - other than binary columns. */ + field = rec_get_nth_field_old(rec, 0/*INDEX_ID*/, &len); + if (UNIV_UNLIKELY(len != 8)) { +err_len: + return("incorrect column length in SYS_FIELDS"); + } - prtype = dtype_form_prtype( - prtype, - data_mysql_default_charset_coll); - } + if (!index) { + ut_a(last_index_id); + memcpy(index_id, (const char*)field, 8); + first_field = memcmp(index_id, last_index_id, 8); + } else { + first_field = (index->n_def == 0); + if (memcmp(field, index_id, 8)) { + return("SYS_FIELDS.INDEX_ID mismatch"); } + } - field = rec_get_nth_field_old(rec, 7, &len); - col_len = mach_read_from_4(field); + field = rec_get_nth_field_old(rec, 1/*POS*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + + rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len); + if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) { + goto err_len; + } + rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len); + if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) { + goto err_len; + } - ut_a(name_of_col_is(sys_columns, sys_index, 8, "PREC")); + /* The next field stores the field position in the index and a + possible column prefix length if the index field does not + contain the whole column. The storage format is like this: if + there is at least one prefix field in the index, then the HIGH + 2 bytes contain the field number (index->n_def) and the low 2 + bytes the prefix length for the field. Otherwise the field + number (index->n_def) is contained in the 2 LOW bytes. */ - dict_mem_table_add_col(table, heap, name, - mtype, prtype, col_len); - btr_pcur_move_to_next_user_rec(&pcur, &mtr); + pos_and_prefix_len = mach_read_from_4(field); + + if (index && UNIV_UNLIKELY + ((pos_and_prefix_len & 0xFFFFUL) != index->n_def + && (pos_and_prefix_len >> 16 & 0xFFFF) != index->n_def)) { + return("SYS_FIELDS.POS mismatch"); } - btr_pcur_close(&pcur); - mtr_commit(&mtr); + if (first_field || pos_and_prefix_len > 0xFFFFUL) { + prefix_len = pos_and_prefix_len & 0xFFFFUL; + position = (pos_and_prefix_len & 0xFFFF0000UL) >> 16; + } else { + prefix_len = 0; + position = pos_and_prefix_len & 0xFFFFUL; + } + + field = rec_get_nth_field_old(rec, 4, &len); + if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) { + goto err_len; + } + + if (index) { + dict_mem_index_add_field( + index, mem_heap_strdupl(heap, (const char*) field, len), + prefix_len); + } else { + ut_a(sys_field); + ut_a(pos); + + sys_field->name = mem_heap_strdupl( + heap, (const char*) field, len); + sys_field->prefix_len = prefix_len; + *pos = position; + } + + return(NULL); } /********************************************************************//** -Loads definitions for index fields. */ +Loads definitions for index fields. +@return DB_SUCCESS if ok, DB_CORRUPTION if corruption */ static -void +ulint dict_load_fields( /*=============*/ - dict_index_t* index, /*!< in: index whose fields to load */ + dict_index_t* index, /*!< in/out: index whose fields to load */ mem_heap_t* heap) /*!< in: memory heap for temporary storage */ { dict_table_t* sys_fields; @@ -540,14 +1103,11 @@ dict_load_fields( btr_pcur_t pcur; dtuple_t* tuple; dfield_t* dfield; - ulint pos_and_prefix_len; - ulint prefix_len; const rec_t* rec; - const byte* field; - ulint len; byte* buf; ulint i; mtr_t mtr; + ulint error; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -556,6 +1116,7 @@ dict_load_fields( sys_fields = dict_table_get_low("SYS_FIELDS"); sys_index = UT_LIST_GET_FIRST(sys_fields->indexes); ut_a(!dict_table_is_comp(sys_fields)); + ut_a(name_of_col_is(sys_fields, sys_index, 4, "COL_NAME")); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); @@ -569,62 +1130,163 @@ dict_load_fields( btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); for (i = 0; i < index->n_fields; i++) { + const char* err_msg; rec = btr_pcur_get_rec(&pcur); ut_a(btr_pcur_is_on_user_rec(&pcur)); - /* There could be delete marked records in SYS_FIELDS - because SYS_FIELDS.INDEX_ID can be updated - by ALTER TABLE ADD INDEX. */ + err_msg = dict_load_field_low(buf, index, NULL, NULL, NULL, + heap, rec); - if (rec_get_deleted_flag(rec, 0)) { + if (err_msg == dict_load_field_del) { + /* There could be delete marked records in + SYS_FIELDS because SYS_FIELDS.INDEX_ID can be + updated by ALTER TABLE ADD INDEX. */ goto next_rec; + } else if (err_msg) { + fprintf(stderr, "InnoDB: %s\n", err_msg); + error = DB_CORRUPTION; + goto func_exit; } +next_rec: + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + } - field = rec_get_nth_field_old(rec, 0, &len); - ut_ad(len == 8); + error = DB_SUCCESS; +func_exit: + btr_pcur_close(&pcur); + mtr_commit(&mtr); + return(error); +} - field = rec_get_nth_field_old(rec, 1, &len); - ut_a(len == 4); +/** Error message for a delete-marked record in dict_load_index_low() */ +static const char* dict_load_index_del = "delete-marked record in SYS_INDEXES"; +/** Error message for table->id mismatch in dict_load_index_low() */ +static const char* dict_load_index_id_err = "SYS_INDEXES.TABLE_ID mismatch"; + +/********************************************************************//** +Loads an index definition from a SYS_INDEXES record to dict_index_t. +If "cached" is set to "TRUE", we will create a dict_index_t structure +and fill it accordingly. Otherwise, the dict_index_t will +be supplied by the caller and filled with information read from +the record. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_load_index_low( +/*================*/ + byte* table_id, /*!< in/out: table id (8 bytes), + an "in" value if cached=TRUE + and "out" when cached=FALSE */ + const char* table_name, /*!< in: table name */ + mem_heap_t* heap, /*!< in/out: temporary memory heap */ + const rec_t* rec, /*!< in: SYS_INDEXES record */ + ibool cached, /*!< in: TRUE = add to cache, + FALSE = do not */ + dict_index_t** index) /*!< out,own: index, or NULL */ +{ + const byte* field; + ulint len; + ulint name_len; + char* name_buf; + dulint id; + ulint n_fields; + ulint type; + ulint space; + + if (cached) { + /* If "cached" is set to TRUE, no dict_index_t will + be supplied. Initialize "*index" to NULL */ + *index = NULL; + } - /* The next field stores the field position in the index - and a possible column prefix length if the index field - does not contain the whole column. The storage format is - like this: if there is at least one prefix field in the index, - then the HIGH 2 bytes contain the field number (== i) and the - low 2 bytes the prefix length for the field. Otherwise the - field number (== i) is contained in the 2 LOW bytes. */ + if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) { + return(dict_load_index_del); + } - pos_and_prefix_len = mach_read_from_4(field); + if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 9)) { + return("wrong number of columns in SYS_INDEXES record"); + } - ut_a((pos_and_prefix_len & 0xFFFFUL) == i - || (pos_and_prefix_len & 0xFFFF0000UL) == (i << 16)); + field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len); + if (UNIV_UNLIKELY(len != 8)) { +err_len: + return("incorrect column length in SYS_INDEXES"); + } - if ((i == 0 && pos_and_prefix_len > 0) - || (pos_and_prefix_len & 0xFFFF0000UL) > 0) { + if (!cached) { + /* We are reading a SYS_INDEXES record. Copy the table_id */ + memcpy(table_id, (const char*)field, 8); + } else if (memcmp(field, table_id, 8)) { + /* Caller supplied table_id, verify it is the same + id as on the index record */ + return(dict_load_index_id_err); + } - prefix_len = pos_and_prefix_len & 0xFFFFUL; - } else { - prefix_len = 0; - } + field = rec_get_nth_field_old(rec, 1/*ID*/, &len); + if (UNIV_UNLIKELY(len != 8)) { + goto err_len; + } - ut_a(name_of_col_is(sys_fields, sys_index, 4, "COL_NAME")); + id = mach_read_from_8(field); - field = rec_get_nth_field_old(rec, 4, &len); + rec_get_nth_field_offs_old(rec, 2/*DB_TRX_ID*/, &len); + if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) { + goto err_len; + } + rec_get_nth_field_offs_old(rec, 3/*DB_ROLL_PTR*/, &len); + if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) { + goto err_len; + } + + field = rec_get_nth_field_old(rec, 4/*NAME*/, &name_len); + if (UNIV_UNLIKELY(name_len == UNIV_SQL_NULL)) { + goto err_len; + } - dict_mem_index_add_field(index, - mem_heap_strdupl(heap, - (char*) field, len), - prefix_len); + name_buf = mem_heap_strdupl(heap, (const char*) field, + name_len); -next_rec: - btr_pcur_move_to_next_user_rec(&pcur, &mtr); + field = rec_get_nth_field_old(rec, 5/*N_FIELDS*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; } + n_fields = mach_read_from_4(field); - btr_pcur_close(&pcur); - mtr_commit(&mtr); + field = rec_get_nth_field_old(rec, 6/*TYPE*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + type = mach_read_from_4(field); + + field = rec_get_nth_field_old(rec, 7/*SPACE*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + space = mach_read_from_4(field); + + field = rec_get_nth_field_old(rec, 8/*PAGE_NO*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + + if (cached) { + *index = dict_mem_index_create(table_name, name_buf, + space, type, n_fields); + } else { + ut_a(*index); + + dict_mem_fill_index_struct(*index, NULL, NULL, name_buf, + space, type, n_fields); + } + + (*index)->id = id; + (*index)->page = mach_read_from_4(field); + ut_ad((*index)->page); + + return(NULL); } /********************************************************************//** @@ -636,27 +1298,17 @@ static ulint dict_load_indexes( /*==============*/ - dict_table_t* table, /*!< in: table */ + dict_table_t* table, /*!< in/out: table */ mem_heap_t* heap) /*!< in: memory heap for temporary storage */ { dict_table_t* sys_indexes; dict_index_t* sys_index; - dict_index_t* index; btr_pcur_t pcur; dtuple_t* tuple; dfield_t* dfield; const rec_t* rec; - const byte* field; - ulint len; - ulint name_len; - char* name_buf; - ulint type; - ulint space; - ulint page_no; - ulint n_fields; byte* buf; ibool is_sys_table; - dulint id; mtr_t mtr; ulint error = DB_SUCCESS; @@ -674,6 +1326,8 @@ dict_load_indexes( sys_indexes = dict_table_get_low("SYS_INDEXES"); sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes); ut_a(!dict_table_is_comp(sys_indexes)); + ut_a(name_of_col_is(sys_indexes, sys_index, 4, "NAME")); + ut_a(name_of_col_is(sys_indexes, sys_index, 8, "PAGE_NO")); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); @@ -687,6 +1341,9 @@ dict_load_indexes( btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); for (;;) { + dict_index_t* index = NULL; + const char* err_msg; + if (!btr_pcur_is_on_user_rec(&pcur)) { break; @@ -694,90 +1351,73 @@ dict_load_indexes( rec = btr_pcur_get_rec(&pcur); - field = rec_get_nth_field_old(rec, 0, &len); - ut_ad(len == 8); + err_msg = dict_load_index_low(buf, table->name, heap, rec, + TRUE, &index); + ut_ad((index == NULL) == (err_msg != NULL)); - if (ut_memcmp(buf, field, len) != 0) { + if (err_msg == dict_load_index_id_err) { + /* TABLE_ID mismatch means that we have + run out of index definitions for the table. */ break; - } else if (rec_get_deleted_flag(rec, 0)) { - /* Skip delete marked records */ + } else if (err_msg == dict_load_index_del) { + /* Skip delete-marked records. */ goto next_rec; + } else if (err_msg) { + fprintf(stderr, "InnoDB: %s\n", err_msg); + error = DB_CORRUPTION; + goto func_exit; } - field = rec_get_nth_field_old(rec, 1, &len); - ut_ad(len == 8); - id = mach_read_from_8(field); - - ut_a(name_of_col_is(sys_indexes, sys_index, 4, "NAME")); - - field = rec_get_nth_field_old(rec, 4, &name_len); - name_buf = mem_heap_strdupl(heap, (char*) field, name_len); - - field = rec_get_nth_field_old(rec, 5, &len); - n_fields = mach_read_from_4(field); - - field = rec_get_nth_field_old(rec, 6, &len); - type = mach_read_from_4(field); - - field = rec_get_nth_field_old(rec, 7, &len); - space = mach_read_from_4(field); - - ut_a(name_of_col_is(sys_indexes, sys_index, 8, "PAGE_NO")); - - field = rec_get_nth_field_old(rec, 8, &len); - page_no = mach_read_from_4(field); + ut_ad(index); /* We check for unsupported types first, so that the subsequent checks are relevant for the supported types. */ - if (type & ~(DICT_CLUSTERED | DICT_UNIQUE)) { + if (index->type & ~(DICT_CLUSTERED | DICT_UNIQUE)) { fprintf(stderr, "InnoDB: Error: unknown type %lu" " of index %s of table %s\n", - (ulong) type, name_buf, table->name); + (ulong) index->type, index->name, table->name); error = DB_UNSUPPORTED; + dict_mem_index_free(index); goto func_exit; - } else if (page_no == FIL_NULL) { + } else if (index->page == FIL_NULL) { fprintf(stderr, "InnoDB: Error: trying to load index %s" " for table %s\n" "InnoDB: but the index tree has been freed!\n", - name_buf, table->name); + index->name, table->name); +corrupted: + dict_mem_index_free(index); error = DB_CORRUPTION; goto func_exit; - } else if ((type & DICT_CLUSTERED) == 0 - && NULL == dict_table_get_first_index(table)) { + } else if (!dict_index_is_clust(index) + && NULL == dict_table_get_first_index(table)) { fputs("InnoDB: Error: trying to load index ", stderr); - ut_print_name(stderr, NULL, FALSE, name_buf); + ut_print_name(stderr, NULL, FALSE, index->name); fputs(" for table ", stderr); ut_print_name(stderr, NULL, TRUE, table->name); fputs("\nInnoDB: but the first index" " is not clustered!\n", stderr); - error = DB_CORRUPTION; - goto func_exit; + goto corrupted; } else if (is_sys_table - && ((type & DICT_CLUSTERED) + && (dict_index_is_clust(index) || ((table == dict_sys->sys_tables) - && (name_len == (sizeof "ID_IND") - 1) - && (0 == ut_memcmp(name_buf, - "ID_IND", name_len))))) { + && !strcmp("ID_IND", index->name)))) { /* The index was created in memory already at booting of the database server */ + dict_mem_index_free(index); } else { - index = dict_mem_index_create(table->name, name_buf, - space, type, n_fields); - index->id = id; - dict_load_fields(index, heap); - error = dict_index_add_to_cache(table, index, page_no, - FALSE); + error = dict_index_add_to_cache(table, index, + index->page, FALSE); /* The data dictionary tables should never contain invalid index definitions. If we ignored this error and simply did not load this index definition, the @@ -801,6 +1441,153 @@ func_exit: } /********************************************************************//** +Loads a table definition from a SYS_TABLES record to dict_table_t. +Does not load any columns or indexes. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_load_table_low( +/*================*/ + const char* name, /*!< in: table name */ + const rec_t* rec, /*!< in: SYS_TABLES record */ + dict_table_t** table) /*!< out,own: table, or NULL */ +{ + const byte* field; + ulint len; + ulint space; + ulint n_cols; + ulint flags; + + if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) { + return("delete-marked record in SYS_TABLES"); + } + + if (UNIV_UNLIKELY(rec_get_n_fields_old(rec) != 10)) { + return("wrong number of columns in SYS_TABLES record"); + } + + rec_get_nth_field_offs_old(rec, 0/*NAME*/, &len); + if (UNIV_UNLIKELY(len < 1 || len == UNIV_SQL_NULL)) { +err_len: + return("incorrect column length in SYS_TABLES"); + } + rec_get_nth_field_offs_old(rec, 1/*DB_TRX_ID*/, &len); + if (UNIV_UNLIKELY(len != DATA_TRX_ID_LEN && len != UNIV_SQL_NULL)) { + goto err_len; + } + rec_get_nth_field_offs_old(rec, 2/*DB_ROLL_PTR*/, &len); + if (UNIV_UNLIKELY(len != DATA_ROLL_PTR_LEN && len != UNIV_SQL_NULL)) { + goto err_len; + } + + rec_get_nth_field_offs_old(rec, 3/*ID*/, &len); + if (UNIV_UNLIKELY(len != 8)) { + goto err_len; + } + + field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + + n_cols = mach_read_from_4(field); + + rec_get_nth_field_offs_old(rec, 5/*TYPE*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + + rec_get_nth_field_offs_old(rec, 6/*MIX_ID*/, &len); + if (UNIV_UNLIKELY(len != 8)) { + goto err_len; + } + + rec_get_nth_field_offs_old(rec, 7/*MIX_LEN*/, &len); + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + + rec_get_nth_field_offs_old(rec, 8/*CLUSTER_ID*/, &len); + if (UNIV_UNLIKELY(len != UNIV_SQL_NULL)) { + goto err_len; + } + + field = rec_get_nth_field_old(rec, 9/*SPACE*/, &len); + + if (UNIV_UNLIKELY(len != 4)) { + goto err_len; + } + + space = mach_read_from_4(field); + + /* Check if the tablespace exists and has the right name */ + if (space != 0) { + flags = dict_sys_tables_get_flags(rec); + + if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) { + field = rec_get_nth_field_old(rec, 5/*TYPE*/, &len); + ut_ad(len == 4); /* this was checked earlier */ + flags = mach_read_from_4(field); + + ut_print_timestamp(stderr); + fputs(" InnoDB: Error: table ", stderr); + ut_print_filename(stderr, name); + fprintf(stderr, "\n" + "InnoDB: in InnoDB data dictionary" + " has unknown type %lx.\n", + (ulong) flags); + return(NULL); + } + } else { + flags = 0; + } + + /* The high-order bit of N_COLS is the "compact format" flag. + For tables in that format, MIX_LEN may hold additional flags. */ + if (n_cols & 0x80000000UL) { + ulint flags2; + + flags |= DICT_TF_COMPACT; + + field = rec_get_nth_field_old(rec, 7, &len); + + if (UNIV_UNLIKELY(len != 4)) { + + goto err_len; + } + + flags2 = mach_read_from_4(field); + + if (flags2 & (~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT))) { + ut_print_timestamp(stderr); + fputs(" InnoDB: Warning: table ", stderr); + ut_print_filename(stderr, name); + fprintf(stderr, "\n" + "InnoDB: in InnoDB data dictionary" + " has unknown flags %lx.\n", + (ulong) flags2); + + flags2 &= ~(~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT)); + } + + flags |= flags2 << DICT_TF2_SHIFT; + } + + /* See if the tablespace is available. */ + *table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL, + flags); + + field = rec_get_nth_field_old(rec, 3/*ID*/, &len); + ut_ad(len == 8); /* this was checked earlier */ + + (*table)->id = mach_read_from_8(field); + + (*table)->ibd_file_missing = FALSE; + + return(NULL); +} + +/********************************************************************//** Loads a table definition and also all its index definitions, and also the cluster definition if the table is a member in a cluster. Also loads all foreign key constraints where the foreign key is in the table or where @@ -813,10 +1600,10 @@ UNIV_INTERN dict_table_t* dict_load_table( /*============*/ - const char* name) /*!< in: table name in the + const char* name, /*!< in: table name in the databasename/tablename format */ + ibool cached) /*!< in: TRUE=add to cache, FALSE=do not */ { - ibool ibd_file_missing = FALSE; dict_table_t* table; dict_table_t* sys_tables; btr_pcur_t pcur; @@ -827,10 +1614,8 @@ dict_load_table( const rec_t* rec; const byte* field; ulint len; - ulint space; - ulint n_cols; - ulint flags; ulint err; + const char* err_msg; mtr_t mtr; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -842,6 +1627,11 @@ dict_load_table( sys_tables = dict_table_get_low("SYS_TABLES"); sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); ut_a(!dict_table_is_comp(sys_tables)); + ut_a(name_of_col_is(sys_tables, sys_index, 3, "ID")); + ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS")); + ut_a(name_of_col_is(sys_tables, sys_index, 5, "TYPE")); + ut_a(name_of_col_is(sys_tables, sys_index, 7, "MIX_LEN")); + ut_a(name_of_col_is(sys_tables, sys_index, 9, "SPACE")); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); @@ -872,83 +1662,57 @@ err_exit: goto err_exit; } - ut_a(name_of_col_is(sys_tables, sys_index, 9, "SPACE")); + err_msg = dict_load_table_low(name, rec, &table); - field = rec_get_nth_field_old(rec, 9, &len); - space = mach_read_from_4(field); + if (err_msg) { - /* Check if the tablespace exists and has the right name */ - if (space != 0) { - flags = dict_sys_tables_get_flags(rec); - - if (UNIV_UNLIKELY(flags == ULINT_UNDEFINED)) { - field = rec_get_nth_field_old(rec, 5, &len); - flags = mach_read_from_4(field); - - ut_print_timestamp(stderr); - fputs(" InnoDB: Error: table ", stderr); - ut_print_filename(stderr, name); - fprintf(stderr, "\n" - "InnoDB: in InnoDB data dictionary" - " has unknown type %lx.\n", - (ulong) flags); - goto err_exit; - } + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: %s\n", err_msg); + goto err_exit; + } - if (fil_space_for_table_exists_in_mem(space, name, FALSE, - FALSE, FALSE)) { - /* Ok; (if we did a crash recovery then the tablespace - can already be in the memory cache) */ + if (table->space == 0) { + /* The system tablespace is always available. */ + } else if (!fil_space_for_table_exists_in_mem( + table->space, name, + (table->flags >> DICT_TF2_SHIFT) + & DICT_TF2_TEMPORARY, + FALSE, FALSE)) { + + if (table->flags & (DICT_TF2_TEMPORARY << DICT_TF2_SHIFT)) { + /* Do not bother to retry opening temporary tables. */ + table->ibd_file_missing = TRUE; } else { - /* In >= 4.1.9, InnoDB scans the data dictionary also - at a normal mysqld startup. It is an error if the - space object does not exist in memory. */ - ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB: error: space object of table %s,\n" + " InnoDB: error: space object of table "); + ut_print_filename(stderr, name); + fprintf(stderr, ",\n" "InnoDB: space id %lu did not exist in memory." " Retrying an open.\n", - name, (ulong)space); + (ulong) table->space); /* Try to open the tablespace */ if (!fil_open_single_table_tablespace( - TRUE, space, flags, name)) { - /* We failed to find a sensible tablespace - file */ + TRUE, table->space, + table->flags & ~(~0 << DICT_TF_BITS), name)) { + /* We failed to find a sensible + tablespace file */ - ibd_file_missing = TRUE; + table->ibd_file_missing = TRUE; } } - } else { - flags = 0; - } - - ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS")); - - field = rec_get_nth_field_old(rec, 4, &len); - n_cols = mach_read_from_4(field); - - /* The high-order bit of N_COLS is the "compact format" flag. */ - if (n_cols & 0x80000000UL) { - flags |= DICT_TF_COMPACT; } - table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL, - flags); - - table->ibd_file_missing = (unsigned int) ibd_file_missing; - - ut_a(name_of_col_is(sys_tables, sys_index, 3, "ID")); - - field = rec_get_nth_field_old(rec, 3, &len); - table->id = mach_read_from_8(field); - btr_pcur_close(&pcur); mtr_commit(&mtr); dict_load_columns(table, heap); - dict_table_add_to_cache(table, heap); + if (cached) { + dict_table_add_to_cache(table, heap); + } else { + dict_table_add_system_columns(table, heap); + } mem_heap_empty(heap); @@ -958,7 +1722,8 @@ err_exit: of the error condition, since the user may want to dump data from the clustered index. However we load the foreign key information only if all indexes were loaded. */ - if (err == DB_SUCCESS) { + if (!cached) { + } else if (err == DB_SUCCESS) { err = dict_load_foreigns(table->name, TRUE); } else if (!srv_force_recovery) { dict_table_remove_from_cache(table); @@ -1075,7 +1840,8 @@ dict_load_table_on_id( /* Now we get the table name from the record */ field = rec_get_nth_field_old(rec, 1, &len); /* Load the table definition to memory */ - table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len)); + table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len), + TRUE); btr_pcur_close(&pcur); mtr_commit(&mtr); diff --git a/storage/innobase/dict/dict0mem.c b/storage/innobase/dict/dict0mem.c index 6458cbab92d..b6e516783c7 100644 --- a/storage/innobase/dict/dict0mem.c +++ b/storage/innobase/dict/dict0mem.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -40,6 +40,11 @@ Created 1/8/1996 Heikki Tuuri #define DICT_HEAP_SIZE 100 /*!< initial memory heap size when creating a table or index object */ +#ifdef UNIV_PFS_MUTEX +/* Key to register autoinc_mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t autoinc_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + /**********************************************************************//** Creates a table memory object. @return own: table object */ @@ -59,7 +64,7 @@ dict_mem_table_create( mem_heap_t* heap; ut_ad(name); - ut_a(!(flags & (~0 << DICT_TF_BITS))); + ut_a(!(flags & (~0 << DICT_TF2_BITS))); heap = mem_heap_create(DICT_HEAP_SIZE); @@ -78,7 +83,8 @@ dict_mem_table_create( #ifndef UNIV_HOTBACKUP table->autoinc_lock = mem_heap_alloc(heap, lock_get_size()); - mutex_create(&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX); + mutex_create(autoinc_mutex_key, + &table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX); table->autoinc = 0; @@ -171,10 +177,6 @@ dict_mem_table_add_col( ulint len) /*!< in: precision */ { dict_col_t* col; -#ifndef UNIV_HOTBACKUP - ulint mbminlen; - ulint mbmaxlen; -#endif /* !UNIV_HOTBACKUP */ ulint i; ut_ad(table); @@ -199,19 +201,7 @@ dict_mem_table_add_col( col = dict_table_get_nth_col(table, i); - col->ind = (unsigned int) i; - col->ord_part = 0; - - col->mtype = (unsigned int) mtype; - col->prtype = (unsigned int) prtype; - col->len = (unsigned int) len; - -#ifndef UNIV_HOTBACKUP - dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen); - - col->mbminlen = (unsigned int) mbminlen; - col->mbmaxlen = (unsigned int) mbmaxlen; -#endif /* !UNIV_HOTBACKUP */ + dict_mem_fill_column_struct(col, i, mtype, prtype, len); } /**********************************************************************//** @@ -238,22 +228,9 @@ dict_mem_index_create( heap = mem_heap_create(DICT_HEAP_SIZE); index = mem_heap_zalloc(heap, sizeof(dict_index_t)); - index->heap = heap; + dict_mem_fill_index_struct(index, heap, table_name, index_name, + space, type, n_fields); - index->type = type; -#ifndef UNIV_HOTBACKUP - index->space = (unsigned int) space; -#endif /* !UNIV_HOTBACKUP */ - index->name = mem_heap_strdup(heap, index_name); - index->table_name = table_name; - index->n_fields = (unsigned int) n_fields; - index->fields = mem_heap_alloc(heap, 1 + n_fields - * sizeof(dict_field_t)); - /* The '1 +' above prevents allocation - of an empty mem block */ -#ifdef UNIV_DEBUG - index->magic_n = DICT_INDEX_MAGIC_N; -#endif /* UNIV_DEBUG */ return(index); } diff --git a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c index 112a0e27d50..0d033c37879 100644 --- a/storage/innobase/fil/fil0fil.c +++ b/storage/innobase/fil/fil0fil.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. 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 @@ -38,6 +38,7 @@ Created 10/25/1995 Heikki Tuuri #include "mtr0mtr.h" #include "mtr0log.h" #include "dict0dict.h" +#include "page0page.h" #include "page0zip.h" #ifndef UNIV_HOTBACKUP # include "buf0lru.h" @@ -120,6 +121,16 @@ UNIV_INTERN ulint fil_n_pending_tablespace_flushes = 0; /** The null file address */ UNIV_INTERN fil_addr_t fil_addr_null = {FIL_NULL, 0}; +#ifdef UNIV_PFS_MUTEX +/* Key to register fil_system_mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t fil_system_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + +#ifdef UNIV_PFS_RWLOCK +/* Key to register file space latch with performance schema */ +UNIV_INTERN mysql_pfs_key_t fil_space_latch_key; +#endif /* UNIV_PFS_RWLOCK */ + /** File node of a tablespace or the log data space */ struct fil_node_struct { fil_space_t* space; /*!< backpointer to the space where this node @@ -278,6 +289,10 @@ struct fil_system_struct { request */ UT_LIST_BASE_NODE_T(fil_space_t) space_list; /*!< list of all file spaces */ + ibool space_id_reuse_warned; + /* !< TRUE if fil_space_create() + has issued a warning about + potential space_id reuse */ }; /** The tablespace memory cache. This variable is NULL before the module is @@ -648,7 +663,8 @@ fil_node_open_file( async I/O! */ node->handle = os_file_create_simple_no_error_handling( - node->name, OS_FILE_OPEN, OS_FILE_READ_ONLY, &success); + innodb_file_data_key, node->name, OS_FILE_OPEN, + OS_FILE_READ_ONLY, &success); if (!success) { /* The following call prints an error message */ os_file_get_last_error(TRUE); @@ -766,15 +782,21 @@ add_size: os_file_create() to fall back to the normal file I/O mode. */ if (space->purpose == FIL_LOG) { - node->handle = os_file_create(node->name, OS_FILE_OPEN, - OS_FILE_AIO, OS_LOG_FILE, &ret); + node->handle = os_file_create(innodb_file_log_key, + node->name, OS_FILE_OPEN, + OS_FILE_AIO, OS_LOG_FILE, + &ret); } else if (node->is_raw_disk) { - node->handle = os_file_create(node->name, + node->handle = os_file_create(innodb_file_data_key, + node->name, OS_FILE_OPEN_RAW, - OS_FILE_AIO, OS_DATA_FILE, &ret); + OS_FILE_AIO, OS_DATA_FILE, + &ret); } else { - node->handle = os_file_create(node->name, OS_FILE_OPEN, - OS_FILE_AIO, OS_DATA_FILE, &ret); + node->handle = os_file_create(innodb_file_data_key, + node->name, OS_FILE_OPEN, + OS_FILE_AIO, OS_DATA_FILE, + &ret); } ut_a(ret); @@ -1097,10 +1119,13 @@ fil_space_create( fil_space_t* space; /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for - ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and + ROW_FORMAT=COMPACT + ((table->flags & ~(~0 << DICT_TF_BITS)) == DICT_TF_COMPACT) and ROW_FORMAT=REDUNDANT (table->flags == 0). For any other - format, the tablespace flags should equal table->flags. */ + format, the tablespace flags should equal + (table->flags & ~(~0 << DICT_TF_BITS)). */ ut_a(flags != DICT_TF_COMPACT); + ut_a(!(flags & (~0UL << DICT_TF_BITS))); try_again: /*printf( @@ -1189,7 +1214,19 @@ try_again: space->tablespace_version = fil_system->tablespace_version; space->mark = FALSE; - if (purpose == FIL_TABLESPACE && id > fil_system->max_assigned_id) { + if (UNIV_LIKELY(purpose == FIL_TABLESPACE) + && UNIV_UNLIKELY(id > fil_system->max_assigned_id)) { + if (!fil_system->space_id_reuse_warned) { + fil_system->space_id_reuse_warned = TRUE; + + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Warning: allocated tablespace %lu," + " old maximum was %lu\n", + (ulong) id, + (ulong) fil_system->max_assigned_id); + } + fil_system->max_assigned_id = id; } @@ -1208,7 +1245,7 @@ try_again: UT_LIST_INIT(space->chain); space->magic_n = FIL_SPACE_MAGIC_N; - rw_lock_create(&space->latch, SYNC_FSP); + rw_lock_create(fil_space_latch_key, &space->latch, SYNC_FSP); HASH_INSERT(fil_space_t, hash, fil_system->spaces, id, space); @@ -1227,19 +1264,25 @@ try_again: Assigns a new space id for a new single-table tablespace. This works simply by incrementing the global counter. If 4 billion id's is not enough, we may need to recycle id's. -@return new tablespace id; ULINT_UNDEFINED if could not assign an id */ -static -ulint -fil_assign_new_space_id(void) -/*=========================*/ +@return TRUE if assigned, FALSE if not */ +UNIV_INTERN +ibool +fil_assign_new_space_id( +/*====================*/ + ulint* space_id) /*!< in/out: space id */ { - ulint id; + ulint id; + ibool success; mutex_enter(&fil_system->mutex); - fil_system->max_assigned_id++; + id = *space_id; + + if (id < fil_system->max_assigned_id) { + id = fil_system->max_assigned_id; + } - id = fil_system->max_assigned_id; + id++; if (id > (SRV_LOG_SPACE_FIRST_ID / 2) && (id % 1000000UL == 0)) { ut_print_timestamp(stderr); @@ -1255,7 +1298,11 @@ fil_assign_new_space_id(void) (ulong) SRV_LOG_SPACE_FIRST_ID); } - if (id >= SRV_LOG_SPACE_FIRST_ID) { + success = (id < SRV_LOG_SPACE_FIRST_ID); + + if (success) { + *space_id = fil_system->max_assigned_id = id; + } else { ut_print_timestamp(stderr); fprintf(stderr, "InnoDB: You have run out of single-table" @@ -1265,14 +1312,12 @@ fil_assign_new_space_id(void) " have to dump all your tables and\n" "InnoDB: recreate the whole InnoDB installation.\n", (ulong) id); - fil_system->max_assigned_id--; - - id = ULINT_UNDEFINED; + *space_id = ULINT_UNDEFINED; } mutex_exit(&fil_system->mutex); - return(id); + return(success); } /*******************************************************************//** @@ -1508,25 +1553,17 @@ fil_init( ut_a(hash_size > 0); ut_a(max_n_open > 0); - fil_system = mem_alloc(sizeof(fil_system_t)); + fil_system = mem_zalloc(sizeof(fil_system_t)); - mutex_create(&fil_system->mutex, SYNC_ANY_LATCH); + mutex_create(fil_system_mutex_key, + &fil_system->mutex, SYNC_ANY_LATCH); fil_system->spaces = hash_create(hash_size); fil_system->name_hash = hash_create(hash_size); UT_LIST_INIT(fil_system->LRU); - fil_system->n_open = 0; fil_system->max_n_open = max_n_open; - - fil_system->modification_counter = 0; - fil_system->max_assigned_id = 0; - - fil_system->tablespace_version = 0; - - UT_LIST_INIT(fil_system->unflushed_spaces); - UT_LIST_INIT(fil_system->space_list); } /*******************************************************************//** @@ -2111,7 +2148,7 @@ fil_op_log_parse_or_replay( fil_create_directory_for_tablename(name); if (fil_create_new_single_table_tablespace( - &space_id, name, FALSE, flags, + space_id, name, FALSE, flags, FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) { ut_error; } @@ -2515,7 +2552,7 @@ retry: success = fil_rename_tablespace_in_mem(space, node, path); if (success) { - success = os_file_rename(old_path, path); + success = os_file_rename(innodb_file_data_key, old_path, path); if (!success) { /* We have to revert the changes we made @@ -2558,9 +2595,7 @@ UNIV_INTERN ulint fil_create_new_single_table_tablespace( /*===================================*/ - ulint* space_id, /*!< in/out: space id; if this is != 0, - then this is an input parameter, - otherwise output */ + ulint space_id, /*!< in: space id */ const char* tablename, /*!< in: the table name in the usual databasename/tablename format of InnoDB, or a dir path to a temp @@ -2580,16 +2615,22 @@ fil_create_new_single_table_tablespace( ibool success; char* path; + ut_a(space_id > 0); + ut_a(space_id < SRV_LOG_SPACE_FIRST_ID); ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE); /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for - ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and + ROW_FORMAT=COMPACT + ((table->flags & ~(~0 << DICT_TF_BITS)) == DICT_TF_COMPACT) and ROW_FORMAT=REDUNDANT (table->flags == 0). For any other - format, the tablespace flags should equal table->flags. */ + format, the tablespace flags should equal + (table->flags & ~(~0 << DICT_TF_BITS)). */ ut_a(flags != DICT_TF_COMPACT); + ut_a(!(flags & (~0UL << DICT_TF_BITS))); path = fil_make_ibd_name(tablename, is_temp); - file = os_file_create(path, OS_FILE_CREATE, OS_FILE_NORMAL, + file = os_file_create(innodb_file_data_key, path, + OS_FILE_CREATE, OS_FILE_NORMAL, OS_DATA_FILE, &ret); if (ret == FALSE) { ut_print_timestamp(stderr); @@ -2633,38 +2674,21 @@ fil_create_new_single_table_tablespace( return(DB_ERROR); } - buf2 = ut_malloc(3 * UNIV_PAGE_SIZE); - /* Align the memory for file i/o if we might have O_DIRECT set */ - page = ut_align(buf2, UNIV_PAGE_SIZE); - ret = os_file_set_size(path, file, size * UNIV_PAGE_SIZE, 0); if (!ret) { - ut_free(buf2); - os_file_close(file); - os_file_delete(path); - - mem_free(path); - return(DB_OUT_OF_FILE_SPACE); - } - - if (*space_id == 0) { - *space_id = fil_assign_new_space_id(); - } - - /* printf("Creating tablespace %s id %lu\n", path, *space_id); */ - - if (*space_id == ULINT_UNDEFINED) { - ut_free(buf2); + err = DB_OUT_OF_FILE_SPACE; error_exit: os_file_close(file); error_exit2: os_file_delete(path); mem_free(path); - return(DB_ERROR); + return(err); } + /* printf("Creating tablespace %s id %lu\n", path, space_id); */ + /* We have to write the space id to the file immediately and flush the file to disk. This is because in crash recovery we must be aware what tablespaces exist and what are their space id's, so that we can apply @@ -2674,10 +2698,14 @@ error_exit2: with zeros from the call of os_file_set_size(), until a buffer pool flush would write to it. */ + buf2 = ut_malloc(3 * UNIV_PAGE_SIZE); + /* Align the memory for file i/o if we might have O_DIRECT set */ + page = ut_align(buf2, UNIV_PAGE_SIZE); + memset(page, '\0', UNIV_PAGE_SIZE); - fsp_header_init_fields(page, *space_id, flags); - mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, *space_id); + fsp_header_init_fields(page, space_id, flags); + mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id); if (!(flags & DICT_TF_ZSSIZE_MASK)) { buf_flush_init_for_writing(page, NULL, 0); @@ -2708,6 +2736,7 @@ error_exit2: " to tablespace ", stderr); ut_print_filename(stderr, path); putc('\n', stderr); + err = DB_ERROR; goto error_exit; } @@ -2717,22 +2746,20 @@ error_exit2: fputs("InnoDB: Error: file flush of tablespace ", stderr); ut_print_filename(stderr, path); fputs(" failed\n", stderr); + err = DB_ERROR; goto error_exit; } os_file_close(file); - if (*space_id == ULINT_UNDEFINED) { - goto error_exit2; - } - - success = fil_space_create(path, *space_id, flags, FIL_TABLESPACE); + success = fil_space_create(path, space_id, flags, FIL_TABLESPACE); if (!success) { + err = DB_ERROR; goto error_exit2; } - fil_node_create(path, size, *space_id, FALSE); + fil_node_create(path, size, space_id, FALSE); #ifndef UNIV_HOTBACKUP { @@ -2743,7 +2770,7 @@ error_exit2: fil_op_write_log(flags ? MLOG_FILE_CREATE2 : MLOG_FILE_CREATE, - *space_id, + space_id, is_temp ? MLOG_FILE_FLAG_TEMP : 0, flags, tablename, NULL, &mtr); @@ -2786,11 +2813,13 @@ fil_reset_too_high_lsns( ib_int64_t offset; ulint zip_size; ibool success; + page_zip_des_t page_zip; filepath = fil_make_ibd_name(name, FALSE); file = os_file_create_simple_no_error_handling( - filepath, OS_FILE_OPEN, OS_FILE_READ_WRITE, &success); + innodb_file_data_key, filepath, OS_FILE_OPEN, + OS_FILE_READ_WRITE, &success); if (!success) { /* The following call prints an error message */ os_file_get_last_error(TRUE); @@ -2833,6 +2862,12 @@ fil_reset_too_high_lsns( space_id = fsp_header_get_space_id(page); zip_size = fsp_header_get_zip_size(page); + page_zip_des_init(&page_zip); + page_zip_set_size(&page_zip, zip_size); + if (zip_size) { + page_zip.data = page + UNIV_PAGE_SIZE; + } + ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Flush lsn in the tablespace file %lu" @@ -2867,20 +2902,23 @@ fil_reset_too_high_lsns( /* We have to reset the lsn */ if (zip_size) { - memcpy(page + UNIV_PAGE_SIZE, page, zip_size); + memcpy(page_zip.data, page, zip_size); buf_flush_init_for_writing( - page, page + UNIV_PAGE_SIZE, - current_lsn); + page, &page_zip, current_lsn); + success = os_file_write( + filepath, file, page_zip.data, + (ulint) offset & 0xFFFFFFFFUL, + (ulint) (offset >> 32), zip_size); } else { buf_flush_init_for_writing( page, NULL, current_lsn); + success = os_file_write( + filepath, file, page, + (ulint)(offset & 0xFFFFFFFFUL), + (ulint)(offset >> 32), + UNIV_PAGE_SIZE); } - success = os_file_write(filepath, file, page, - (ulint)(offset & 0xFFFFFFFFUL), - (ulint)(offset >> 32), - zip_size - ? zip_size - : UNIV_PAGE_SIZE); + if (!success) { goto func_exit; @@ -2956,13 +2994,17 @@ fil_open_single_table_tablespace( filepath = fil_make_ibd_name(name, FALSE); /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for - ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and + ROW_FORMAT=COMPACT + ((table->flags & ~(~0 << DICT_TF_BITS)) == DICT_TF_COMPACT) and ROW_FORMAT=REDUNDANT (table->flags == 0). For any other - format, the tablespace flags should equal table->flags. */ + format, the tablespace flags should equal + (table->flags & ~(~0 << DICT_TF_BITS)). */ ut_a(flags != DICT_TF_COMPACT); + ut_a(!(flags & (~0UL << DICT_TF_BITS))); file = os_file_create_simple_no_error_handling( - filepath, OS_FILE_OPEN, OS_FILE_READ_ONLY, &success); + innodb_file_data_key, filepath, OS_FILE_OPEN, + OS_FILE_READ_ONLY, &success); if (!success) { /* The following call prints an error message */ os_file_get_last_error(TRUE); @@ -3011,7 +3053,8 @@ fil_open_single_table_tablespace( ut_free(buf2); - if (UNIV_UNLIKELY(space_id != id || space_flags != flags)) { + if (UNIV_UNLIKELY(space_id != id + || space_flags != (flags & ~(~0 << DICT_TF_BITS)))) { ut_print_timestamp(stderr); fputs(" InnoDB: Error: tablespace id and flags in file ", @@ -3117,7 +3160,8 @@ fil_load_single_table_tablespace( # endif /* !UNIV_HOTBACKUP */ #endif file = os_file_create_simple_no_error_handling( - filepath, OS_FILE_OPEN, OS_FILE_READ_ONLY, &success); + innodb_file_data_key, filepath, OS_FILE_OPEN, + OS_FILE_READ_ONLY, &success); if (!success) { /* The following call prints an error message */ os_file_get_last_error(TRUE); @@ -3275,7 +3319,7 @@ fil_load_single_table_tablespace( os_file_close(file); new_path = fil_make_ibbackup_old_name(filepath); - ut_a(os_file_rename(filepath, new_path)); + ut_a(os_file_rename(innodb_file_data_key, filepath, new_path)); ut_free(buf2); mem_free(filepath); @@ -3313,7 +3357,7 @@ fil_load_single_table_tablespace( mutex_exit(&fil_system->mutex); - ut_a(os_file_rename(filepath, new_path)); + ut_a(os_file_rename(innodb_file_data_key, filepath, new_path)); ut_free(buf2); mem_free(filepath); @@ -3520,39 +3564,6 @@ next_datadir_item: return(err); } -/********************************************************************//** -If we need crash recovery, and we have called -fil_load_single_table_tablespaces() and dict_load_single_table_tablespaces(), -we can call this function to print an error message of orphaned .ibd files -for which there is not a data dictionary entry with a matching table name -and space id. */ -UNIV_INTERN -void -fil_print_orphaned_tablespaces(void) -/*================================*/ -{ - fil_space_t* space; - - mutex_enter(&fil_system->mutex); - - space = UT_LIST_GET_FIRST(fil_system->space_list); - - while (space) { - if (space->purpose == FIL_TABLESPACE && space->id != 0 - && !space->mark) { - fputs("InnoDB: Warning: tablespace ", stderr); - ut_print_filename(stderr, space->name); - fprintf(stderr, " of id %lu has no matching table in\n" - "InnoDB: the InnoDB data dictionary.\n", - (ulong) space->id); - } - - space = UT_LIST_GET_NEXT(space_list, space); - } - - mutex_exit(&fil_system->mutex); -} - /*******************************************************************//** Returns TRUE if a single-table tablespace does not exist in the memory cache, or is being deleted there. @@ -4435,11 +4446,14 @@ fil_aio_wait( ut_ad(fil_validate()); - if (os_aio_use_native_aio) { + if (srv_use_native_aio) { srv_set_io_thread_op_info(segment, "native aio handle"); #ifdef WIN_ASYNC_IO ret = os_aio_windows_handle(segment, 0, &fil_node, &message, &type); +#elif defined(LINUX_NATIVE_AIO) + ret = os_aio_linux_handle(segment, &fil_node, + &message, &type); #else ret = 0; /* Eliminate compiler warning */ ut_error; @@ -4781,8 +4795,10 @@ void fil_close(void) /*===========*/ { +#ifndef UNIV_HOTBACKUP /* The mutex should already have been freed. */ ut_ad(fil_system->mutex.magic_n == 0); +#endif /* !UNIV_HOTBACKUP */ hash_table_free(fil_system->spaces); diff --git a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c index 3cc4318fc06..2bae8481d20 100644 --- a/storage/innobase/fsp/fsp0fsp.c +++ b/storage/innobase/fsp/fsp0fsp.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. 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 @@ -386,11 +386,11 @@ UNIV_INLINE ibool xdes_get_bit( /*=========*/ - xdes_t* descr, /*!< in: descriptor */ - ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */ - ulint offset, /*!< in: page offset within extent: - 0 ... FSP_EXTENT_SIZE - 1 */ - mtr_t* mtr) /*!< in: mtr */ + const xdes_t* descr, /*!< in: descriptor */ + ulint bit, /*!< in: XDES_FREE_BIT or XDES_CLEAN_BIT */ + ulint offset, /*!< in: page offset within extent: + 0 ... FSP_EXTENT_SIZE - 1 */ + mtr_t* mtr) /*!< in: mtr */ { ulint index; ulint byte_index; @@ -527,8 +527,8 @@ UNIV_INLINE ulint xdes_get_n_used( /*============*/ - xdes_t* descr, /*!< in: descriptor */ - mtr_t* mtr) /*!< in: mtr */ + const xdes_t* descr, /*!< in: descriptor */ + mtr_t* mtr) /*!< in: mtr */ { ulint i; ulint count = 0; @@ -551,8 +551,8 @@ UNIV_INLINE ibool xdes_is_free( /*=========*/ - xdes_t* descr, /*!< in: descriptor */ - mtr_t* mtr) /*!< in: mtr */ + const xdes_t* descr, /*!< in: descriptor */ + mtr_t* mtr) /*!< in: mtr */ { if (0 == xdes_get_n_used(descr, mtr)) { @@ -569,8 +569,8 @@ UNIV_INLINE ibool xdes_is_full( /*=========*/ - xdes_t* descr, /*!< in: descriptor */ - mtr_t* mtr) /*!< in: mtr */ + const xdes_t* descr, /*!< in: descriptor */ + mtr_t* mtr) /*!< in: mtr */ { if (FSP_EXTENT_SIZE == xdes_get_n_used(descr, mtr)) { @@ -586,7 +586,7 @@ UNIV_INLINE void xdes_set_state( /*===========*/ - xdes_t* descr, /*!< in: descriptor */ + xdes_t* descr, /*!< in/out: descriptor */ ulint state, /*!< in: state to set */ mtr_t* mtr) /*!< in: mtr handle */ { @@ -605,8 +605,8 @@ UNIV_INLINE ulint xdes_get_state( /*===========*/ - xdes_t* descr, /*!< in: descriptor */ - mtr_t* mtr) /*!< in: mtr handle */ + const xdes_t* descr, /*!< in: descriptor */ + mtr_t* mtr) /*!< in: mtr handle */ { ulint state; @@ -705,7 +705,7 @@ UNIV_INLINE xdes_t* xdes_get_descriptor_with_space_hdr( /*===============================*/ - fsp_header_t* sp_header,/*!< in: space header, x-latched */ + fsp_header_t* sp_header,/*!< in/out: space header, x-latched */ ulint space, /*!< in: space id */ ulint offset, /*!< in: page offset; if equal to the free limit, @@ -869,14 +869,10 @@ fsp_init_file_page_low( return; } -#ifdef UNIV_BASIC_LOG_DEBUG - memset(page, 0xff, UNIV_PAGE_SIZE); -#endif + memset(page, 0, UNIV_PAGE_SIZE); mach_write_to_4(page + FIL_PAGE_OFFSET, buf_block_get_page_no(block)); - memset(page + FIL_PAGE_LSN, 0, 8); mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, buf_block_get_space(block)); - memset(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, 0, 8); } #ifndef UNIV_HOTBACKUP @@ -1342,7 +1338,7 @@ fsp_fill_free_list( descriptor page and ibuf bitmap page; then we do not allocate more extents */ ulint space, /*!< in: space */ - fsp_header_t* header, /*!< in: space header */ + fsp_header_t* header, /*!< in/out: space header */ mtr_t* mtr) /*!< in: mtr */ { ulint limit; diff --git a/storage/innobase/ha/ha0ha.c b/storage/innobase/ha/ha0ha.c index cb5e541b55d..9d9d341ad39 100644 --- a/storage/innobase/ha/ha0ha.c +++ b/storage/innobase/ha/ha0ha.c @@ -101,6 +101,8 @@ ha_clear( ulint i; ulint n; + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE)); #endif /* UNIV_SYNC_DEBUG */ @@ -146,7 +148,9 @@ ha_insert_for_fold_func( ha_node_t* prev_node; ulint hash; - ut_ad(table && data); + ut_ad(data); + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG ut_a(block->frame == page_align(data)); #endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */ @@ -237,6 +241,8 @@ ha_delete_hash_node( hash_table_t* table, /*!< in: hash table */ ha_node_t* del_node) /*!< in: node to be deleted */ { + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG # ifndef UNIV_HOTBACKUP if (table->adaptive) { @@ -267,6 +273,8 @@ ha_search_and_update_if_found_func( { ha_node_t* node; + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); ASSERT_HASH_MUTEX_OWN(table, fold); #if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG ut_a(new_block->frame == page_align(new_data)); @@ -304,6 +312,8 @@ ha_remove_all_nodes_to_page( { ha_node_t* node; + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); ASSERT_HASH_MUTEX_OWN(table, fold); node = ha_chain_get_first(table, fold); @@ -353,6 +363,8 @@ ha_validate( ibool ok = TRUE; ulint i; + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); ut_a(start_index <= end_index); ut_a(start_index < hash_get_n_cells(table)); ut_a(end_index < hash_get_n_cells(table)); @@ -404,6 +416,8 @@ builds, see http://bugs.mysql.com/36941 */ #endif /* PRINT_USED_CELLS */ ulint n_bufs; + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); #ifdef PRINT_USED_CELLS for (i = 0; i < hash_get_n_cells(table); i++) { diff --git a/storage/innobase/ha/hash0hash.c b/storage/innobase/ha/hash0hash.c index 2800d7793f8..9589da00454 100644 --- a/storage/innobase/ha/hash0hash.c +++ b/storage/innobase/ha/hash0hash.c @@ -31,6 +31,11 @@ Created 5/20/1997 Heikki Tuuri #include "mem0mem.h" #ifndef UNIV_HOTBACKUP + +# ifdef UNIV_PFS_MUTEX +UNIV_INTERN mysql_pfs_key_t hash_table_mutex_key; +# endif /* UNIV_PFS_MUTEX */ + /************************************************************//** Reserves the mutex for a fold value in a hash table. */ UNIV_INTERN @@ -119,7 +124,7 @@ hash_create( table->heaps = NULL; #endif /* !UNIV_HOTBACKUP */ table->heap = NULL; - table->magic_n = HASH_TABLE_MAGIC_N; + ut_d(table->magic_n = HASH_TABLE_MAGIC_N); /* Initialize the cell array */ hash_table_clear(table); @@ -135,6 +140,8 @@ hash_table_free( /*============*/ hash_table_t* table) /*!< in, own: hash table */ { + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); #ifndef UNIV_HOTBACKUP ut_a(table->mutexes == NULL); #endif /* !UNIV_HOTBACKUP */ @@ -160,13 +167,16 @@ hash_create_mutexes_func( { ulint i; + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); ut_a(n_mutexes > 0); ut_a(ut_is_2pow(n_mutexes)); table->mutexes = mem_alloc(n_mutexes * sizeof(mutex_t)); for (i = 0; i < n_mutexes; i++) { - mutex_create(table->mutexes + i, sync_level); + mutex_create(hash_table_mutex_key, + table->mutexes + i, sync_level); } table->n_mutexes = n_mutexes; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index d1cd508a674..86246e62eee 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1,7 +1,8 @@ /***************************************************************************** -Copyright (c) 2000, 2009, MySQL AB & Innobase Oy. All Rights Reserved. +Copyright (c) 2000, 2010, MySQL AB & Innobase Oy. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. +Copyright (c) 2009, Percona Inc. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -9,6 +10,13 @@ briefly in the InnoDB documentation. The contributions by Google are incorporated with their permission, and subject to the conditions contained in the file COPYING.Google. +Portions of this file contain modifications contributed and copyrighted +by Percona Inc.. Those modifications are +gratefully acknowledged and are described briefly in the InnoDB +documentation. The contributions by Percona Inc. are incorporated with +their permission, and subject to the conditions contained in the file +COPYING.Percona. + 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; version 2 of the License. @@ -22,32 +30,6 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ -/*********************************************************************** - -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. -Copyright (c) 2009, Percona Inc. - -Portions of this file contain modifications contributed and copyrighted -by Percona Inc.. Those modifications are -gratefully acknowledged and are described briefly in the InnoDB -documentation. The contributions by Percona Inc. are incorporated with -their permission, and subject to the conditions contained in the file -COPYING.Percona. - -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; 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, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -***********************************************************************/ /* TODO list for the InnoDB handler in 5.0: - Remove the flag trx->active_trans and look at trx->conc_state @@ -61,14 +43,15 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma implementation // gcc: Class implementation #endif -#include <sql_table.h> // explain_filename, nz2, EXPLAIN_PARTITIONS_AS_COMMENT, - // EXPLAIN_FILENAME_MAX_EXTRA_LENGTH +#include <sql_table.h> // explain_filename, nz2, EXPLAIN_PARTITIONS_AS_COMMENT, + // EXPLAIN_FILENAME_MAX_EXTRA_LENGTH -#include <sql_acl.h> // PROCESS_ACL +#include <sql_acl.h> // PROCESS_ACL #include <m_ctype.h> #include <mysys_err.h> #include <mysql/plugin.h> #include <mysql/innodb_priv.h> +#include <mysql/psi/psi.h> /** @file ha_innodb.cc */ @@ -118,14 +101,13 @@ bool check_global_access(THD *thd, ulong want_access); #endif /* MYSQL_VERSION_ID < 50124 */ /** to protect innobase_open_files */ -static pthread_mutex_t innobase_share_mutex; +static mysql_mutex_t innobase_share_mutex; /** to force correct commit order in binlog */ -static pthread_mutex_t prepare_commit_mutex; +static mysql_mutex_t prepare_commit_mutex; static ulong commit_threads = 0; -static pthread_mutex_t commit_threads_m; -static pthread_cond_t commit_cond; -static pthread_mutex_t commit_cond_m; -static pthread_mutex_t analyze_mutex; +static mysql_mutex_t commit_threads_m; +static mysql_cond_t commit_cond; +static mysql_mutex_t commit_cond_m; static bool innodb_inited = 0; #define INSIDE_HA_INNOBASE_CC @@ -150,6 +132,7 @@ static long innobase_mirrored_log_groups, innobase_log_files_in_group, static ulong innobase_commit_concurrency = 0; static ulong innobase_read_io_threads; static ulong innobase_write_io_threads; +static long innobase_buffer_pool_instances = 1; static long long innobase_buffer_pool_size, innobase_log_file_size; @@ -209,9 +192,137 @@ bool nw_panic = FALSE; /** Allowed values of innodb_change_buffering */ static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = { "none", /* IBUF_USE_NONE */ - "inserts" /* IBUF_USE_INSERT */ + "inserts", /* IBUF_USE_INSERT */ + "deletes", /* IBUF_USE_DELETE_MARK */ + "changes", /* IBUF_USE_INSERT_DELETE_MARK */ + "purges", /* IBUF_USE_DELETE */ + "all" /* IBUF_USE_ALL */ +}; + +#ifdef HAVE_PSI_INTERFACE +/* Keys to register pthread mutexes/cond in the current file with +performance schema */ +static mysql_pfs_key_t innobase_share_mutex_key; +static mysql_pfs_key_t prepare_commit_mutex_key; +static mysql_pfs_key_t commit_threads_m_key; +static mysql_pfs_key_t commit_cond_mutex_key; +static mysql_pfs_key_t commit_cond_key; + +static PSI_mutex_info all_pthread_mutexes[] = { + {&commit_threads_m_key, "commit_threads_m", 0}, + {&commit_cond_mutex_key, "commit_cond_mutex", 0}, + {&innobase_share_mutex_key, "innobase_share_mutex", 0}, + {&prepare_commit_mutex_key, "prepare_commit_mutex", 0} }; +static PSI_cond_info all_innodb_conds[] = { + {&commit_cond_key, "commit_cond", 0} +}; + +# ifdef UNIV_PFS_MUTEX +/* all_innodb_mutexes array contains mutexes that are +performance schema instrumented if "UNIV_PFS_MUTEX" +is defined */ +static PSI_mutex_info all_innodb_mutexes[] = { + {&autoinc_mutex_key, "autoinc_mutex", 0}, + {&btr_search_enabled_mutex_key, "btr_search_enabled_mutex", 0}, +# ifndef PFS_SKIP_BUFFER_MUTEX_RWLOCK + {&buffer_block_mutex_key, "buffer_block_mutex", 0}, +# endif /* !PFS_SKIP_BUFFER_MUTEX_RWLOCK */ + {&buf_pool_mutex_key, "buf_pool_mutex", 0}, + {&buf_pool_zip_mutex_key, "buf_pool_zip_mutex", 0}, + {&cache_last_read_mutex_key, "cache_last_read_mutex", 0}, + {&dict_foreign_err_mutex_key, "dict_foreign_err_mutex", 0}, + {&dict_sys_mutex_key, "dict_sys_mutex", 0}, + {&file_format_max_mutex_key, "file_format_max_mutex", 0}, + {&fil_system_mutex_key, "fil_system_mutex", 0}, + {&flush_list_mutex_key, "flush_list_mutex", 0}, + {&log_flush_order_mutex_key, "log_flush_order_mutex", 0}, + {&hash_table_mutex_key, "hash_table_mutex", 0}, + {&ibuf_bitmap_mutex_key, "ibuf_bitmap_mutex", 0}, + {&ibuf_mutex_key, "ibuf_mutex", 0}, + {&ibuf_pessimistic_insert_mutex_key, + "ibuf_pessimistic_insert_mutex", 0}, + {&ios_mutex_key, "ios_mutex", 0}, + {&kernel_mutex_key, "kernel_mutex", 0}, + {&log_sys_mutex_key, "log_sys_mutex", 0}, +# ifdef UNIV_MEM_DEBUG + {&mem_hash_mutex_key, "mem_hash_mutex", 0}, +# endif /* UNIV_MEM_DEBUG */ + {&mem_pool_mutex_key, "mem_pool_mutex", 0}, + {&mutex_list_mutex_key, "mutex_list_mutex", 0}, + {&purge_sys_mutex_key, "purge_sys_mutex", 0}, + {&recv_sys_mutex_key, "recv_sys_mutex", 0}, + {&rseg_mutex_key, "rseg_mutex", 0}, +# ifdef UNIV_SYNC_DEBUG + {&rw_lock_debug_mutex_key, "rw_lock_debug_mutex", 0}, +# endif /* UNIV_SYNC_DEBUG */ + {&rw_lock_list_mutex_key, "rw_lock_list_mutex", 0}, + {&rw_lock_mutex_key, "rw_lock_mutex", 0}, + {&srv_dict_tmpfile_mutex_key, "srv_dict_tmpfile_mutex", 0}, + {&srv_innodb_monitor_mutex_key, "srv_innodb_monitor_mutex", 0}, + {&srv_misc_tmpfile_mutex_key, "srv_misc_tmpfile_mutex", 0}, + {&srv_monitor_file_mutex_key, "srv_monitor_file_mutex", 0}, + {&syn_arr_mutex_key, "syn_arr_mutex", 0}, +# ifdef UNIV_SYNC_DEBUG + {&sync_thread_mutex_key, "sync_thread_mutex", 0}, +# endif /* UNIV_SYNC_DEBUG */ + {&trx_doublewrite_mutex_key, "trx_doublewrite_mutex", 0}, + {&thr_local_mutex_key, "thr_local_mutex", 0}, + {&trx_undo_mutex_key, "trx_undo_mutex", 0} +}; +# endif /* UNIV_PFS_MUTEX */ + +# ifdef UNIV_PFS_RWLOCK +/* all_innodb_rwlocks array contains rwlocks that are +performance schema instrumented if "UNIV_PFS_RWLOCK" +is defined */ +static PSI_rwlock_info all_innodb_rwlocks[] = { +# ifdef UNIV_LOG_ARCHIVE + {&archive_lock_key, "archive_lock", 0}, +# endif /* UNIV_LOG_ARCHIVE */ + {&btr_search_latch_key, "btr_search_latch", 0}, +# ifndef PFS_SKIP_BUFFER_MUTEX_RWLOCK + {&buf_block_lock_key, "buf_block_lock", 0}, +# endif /* !PFS_SKIP_BUFFER_MUTEX_RWLOCK */ +# ifdef UNIV_SYNC_DEBUG + {&buf_block_debug_latch_key, "buf_block_debug_latch", 0}, +# endif /* UNIV_SYNC_DEBUG */ + {&dict_operation_lock_key, "dict_operation_lock", 0}, + {&fil_space_latch_key, "fil_space_latch", 0}, + {&checkpoint_lock_key, "checkpoint_lock", 0}, + {&trx_i_s_cache_lock_key, "trx_i_s_cache_lock", 0}, + {&trx_purge_latch_key, "trx_purge_latch", 0}, + {&index_tree_rw_lock_key, "index_tree_rw_lock", 0} +}; +# endif /* UNIV_PFS_RWLOCK */ + +# ifdef UNIV_PFS_THREAD +/* all_innodb_threads array contains threads that are +performance schema instrumented if "UNIV_PFS_THREAD" +is defined */ +static PSI_thread_info all_innodb_threads[] = { + {&trx_rollback_clean_thread_key, "trx_rollback_clean_thread", 0}, + {&io_handler_thread_key, "io_handler_thread", 0}, + {&srv_lock_timeout_thread_key, "srv_lock_timeout_thread", 0}, + {&srv_error_monitor_thread_key, "srv_error_monitor_thread", 0}, + {&srv_monitor_thread_key, "srv_monitor_thread", 0}, + {&srv_master_thread_key, "srv_master_thread", 0}, + {&srv_purge_thread_key, "srv_purge_thread", 0} +}; +# endif /* UNIV_PFS_THREAD */ + +# ifdef UNIV_PFS_IO +/* all_innodb_files array contains the type of files that are +performance schema instrumented if "UNIV_PFS_IO" is defined */ +static PSI_file_info all_innodb_files[] = { + {&innodb_file_data_key, "innodb_data_file", 0}, + {&innodb_file_log_key, "innodb_log_file", 0}, + {&innodb_file_temp_key, "innodb_temp_file", 0} +}; +# endif /* UNIV_PFS_IO */ +#endif /* HAVE_PSI_INTERFACE */ + static INNOBASE_SHARE *get_share(const char *table_name); static void free_share(INNOBASE_SHARE *share); static int innobase_close_connection(handlerton *hton, THD* thd); @@ -333,7 +444,7 @@ static MYSQL_THDVAR_ULONG(lock_wait_timeout, PLUGIN_VAR_RQCMDARG, static handler *innobase_create_handler(handlerton *hton, - TABLE_SHARE *table, + TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_innobase(hton, table); @@ -446,8 +557,9 @@ static int innobase_start_trx_and_assign_read_view( /*====================================*/ - handlerton* hton, /*!< in: Innodb handlerton */ - THD* thd); /*!< in: MySQL thread handle of the user for whom + /* out: 0 */ + handlerton* hton, /* in: Innodb handlerton */ + THD* thd); /* in: MySQL thread handle of the user for whom the transaction should be committed */ /****************************************************************//** Flushes InnoDB logs to disk and makes a checkpoint. Really, a commit flushes @@ -1021,6 +1133,23 @@ innobase_get_charset( return(thd_charset((THD*) mysql_thd)); } +/**********************************************************************//** +Determines the current SQL statement. +@return SQL statement string */ +extern "C" UNIV_INTERN +const char* +innobase_get_stmt( +/*==============*/ + void* mysql_thd, /*!< in: MySQL thread handle */ + size_t* length) /*!< out: length of the SQL statement */ +{ + LEX_STRING* stmt; + + stmt = thd_query_string((THD*) mysql_thd); + *length = stmt->length; + return(stmt->str); +} + #if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN) extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list; /*******************************************************************//** @@ -1353,7 +1482,6 @@ innobase_trx_allocate( trx = trx_allocate_for_mysql(); trx->mysql_thd = thd; - trx->mysql_query_str = thd_query(thd); innobase_trx_init(thd, trx); @@ -1854,6 +1982,19 @@ trx_is_interrupted( return(trx && trx->mysql_thd && thd_killed((THD*) trx->mysql_thd)); } +/**********************************************************************//** +Determines if the currently running transaction is in strict mode. +@return TRUE if strict */ +extern "C" UNIV_INTERN +ibool +trx_is_strict( +/*==========*/ + trx_t* trx) /*!< in: transaction */ +{ + return(trx && trx->mysql_thd + && THDVAR((THD*) trx->mysql_thd, strict_mode)); +} + /**************************************************************//** Resets some fields of a prebuilt struct. The template is used in fast retrieval of just those column values MySQL needs in its processing. */ @@ -2166,7 +2307,7 @@ mem_free_and_error: } sql_print_error("InnoDB: invalid value " - "innodb_file_format_check=%s", + "innodb_change_buffering=%s", innobase_change_buffering); goto mem_free_and_error; } @@ -2190,6 +2331,7 @@ innobase_change_buffering_inited_ok: srv_log_buffer_size = (ulint) innobase_log_buffer_size; srv_buf_pool_size = (ulint) innobase_buffer_pool_size; + srv_buf_pool_instances = (ulint) innobase_buffer_pool_instances; srv_mem_pool_size = (ulint) innobase_additional_mem_pool_size; @@ -2233,11 +2375,47 @@ innobase_change_buffering_inited_ok: ut_a(0 == strcmp(my_charset_latin1.name, "latin1_swedish_ci")); srv_latin1_ordering = my_charset_latin1.sort_order; - innobase_old_blocks_pct = buf_LRU_old_ratio_update( - innobase_old_blocks_pct, FALSE); - innobase_commit_concurrency_init_default(); +#ifdef HAVE_PSI_INTERFACE + /* Register keys with MySQL performance schema */ + if (PSI_server) { + int count; + + count = array_elements(all_pthread_mutexes); + PSI_server->register_mutex("innodb", + all_pthread_mutexes, count); + +# ifdef UNIV_PFS_MUTEX + count = array_elements(all_innodb_mutexes); + PSI_server->register_mutex("innodb", + all_innodb_mutexes, count); +# endif /* UNIV_PFS_MUTEX */ + +# ifdef UNIV_PFS_RWLOCK + count = array_elements(all_innodb_rwlocks); + PSI_server->register_rwlock("innodb", + all_innodb_rwlocks, count); +# endif /* UNIV_PFS_MUTEX */ + +# ifdef UNIV_PFS_THREAD + count = array_elements(all_innodb_threads); + PSI_server->register_thread("innodb", + all_innodb_threads, count); +# endif /* UNIV_PFS_THREAD */ + +# ifdef UNIV_PFS_IO + count = array_elements(all_innodb_files); + PSI_server->register_file("innodb", + all_innodb_files, count); +# endif /* UNIV_PFS_IO */ + + count = array_elements(all_innodb_conds); + PSI_server->register_cond("innodb", + all_innodb_conds, count); + } +#endif /* HAVE_PSI_INTERFACE */ + /* Since we in this module access directly the fields of a trx struct, and due to different headers and flags it might happen that mutex_t has a different size in this module and in InnoDB @@ -2250,13 +2428,20 @@ innobase_change_buffering_inited_ok: goto mem_free_and_error; } + innobase_old_blocks_pct = buf_LRU_old_ratio_update( + innobase_old_blocks_pct, TRUE); + innobase_open_tables = hash_create(200); - pthread_mutex_init(&innobase_share_mutex, MY_MUTEX_INIT_FAST); - pthread_mutex_init(&prepare_commit_mutex, MY_MUTEX_INIT_FAST); - pthread_mutex_init(&commit_threads_m, MY_MUTEX_INIT_FAST); - pthread_mutex_init(&commit_cond_m, MY_MUTEX_INIT_FAST); - pthread_mutex_init(&analyze_mutex, MY_MUTEX_INIT_FAST); - pthread_cond_init(&commit_cond, NULL); + mysql_mutex_init(innobase_share_mutex_key, + &innobase_share_mutex, + MY_MUTEX_INIT_FAST); + mysql_mutex_init(prepare_commit_mutex_key, + &prepare_commit_mutex, MY_MUTEX_INIT_FAST); + mysql_mutex_init(commit_threads_m_key, + &commit_threads_m, MY_MUTEX_INIT_FAST); + mysql_mutex_init(commit_cond_mutex_key, + &commit_cond_m, MY_MUTEX_INIT_FAST); + mysql_cond_init(commit_cond_key, &commit_cond, NULL); innodb_inited= 1; #ifdef MYSQL_DYNAMIC_PLUGIN if (innobase_hton != p) { @@ -2306,12 +2491,11 @@ innobase_end( srv_free_paths_and_sizes(); my_free(internal_innobase_data_file_path, MYF(MY_ALLOW_ZERO_PTR)); - pthread_mutex_destroy(&innobase_share_mutex); - pthread_mutex_destroy(&prepare_commit_mutex); - pthread_mutex_destroy(&commit_threads_m); - pthread_mutex_destroy(&commit_cond_m); - pthread_mutex_destroy(&analyze_mutex); - pthread_cond_destroy(&commit_cond); + mysql_mutex_destroy(&innobase_share_mutex); + mysql_mutex_destroy(&prepare_commit_mutex); + mysql_mutex_destroy(&commit_threads_m); + mysql_mutex_destroy(&commit_cond_m); + mysql_cond_destroy(&commit_cond); } DBUG_RETURN(err); @@ -2476,18 +2660,18 @@ innobase_commit( prepare_commit_mutex */ retry: if (innobase_commit_concurrency > 0) { - pthread_mutex_lock(&commit_cond_m); + mysql_mutex_lock(&commit_cond_m); commit_threads++; if (commit_threads > innobase_commit_concurrency) { commit_threads--; - pthread_cond_wait(&commit_cond, + mysql_cond_wait(&commit_cond, &commit_cond_m); - pthread_mutex_unlock(&commit_cond_m); + mysql_mutex_unlock(&commit_cond_m); goto retry; } else { - pthread_mutex_unlock(&commit_cond_m); + mysql_mutex_unlock(&commit_cond_m); } } @@ -2515,15 +2699,15 @@ retry: trx->flush_log_later = FALSE; if (innobase_commit_concurrency > 0) { - pthread_mutex_lock(&commit_cond_m); + mysql_mutex_lock(&commit_cond_m); commit_threads--; - pthread_cond_signal(&commit_cond); - pthread_mutex_unlock(&commit_cond_m); + mysql_cond_signal(&commit_cond); + mysql_mutex_unlock(&commit_cond_m); } if (trx->active_trans == 2) { - pthread_mutex_unlock(&prepare_commit_mutex); + mysql_mutex_unlock(&prepare_commit_mutex); } /* Now do a write + flush of logs. */ @@ -3020,59 +3204,380 @@ normalize_table_name( } /********************************************************************//** +Get the upper limit of the MySQL integral and floating-point type. +@return maximum allowed value for the field */ +static +ulonglong +innobase_get_int_col_max_value( +/*===========================*/ + const Field* field) /*!< in: MySQL field */ +{ + ulonglong max_value = 0; + + switch(field->key_type()) { + /* TINY */ + case HA_KEYTYPE_BINARY: + max_value = 0xFFULL; + break; + case HA_KEYTYPE_INT8: + max_value = 0x7FULL; + break; + /* SHORT */ + case HA_KEYTYPE_USHORT_INT: + max_value = 0xFFFFULL; + break; + case HA_KEYTYPE_SHORT_INT: + max_value = 0x7FFFULL; + break; + /* MEDIUM */ + case HA_KEYTYPE_UINT24: + max_value = 0xFFFFFFULL; + break; + case HA_KEYTYPE_INT24: + max_value = 0x7FFFFFULL; + break; + /* LONG */ + case HA_KEYTYPE_ULONG_INT: + max_value = 0xFFFFFFFFULL; + break; + case HA_KEYTYPE_LONG_INT: + max_value = 0x7FFFFFFFULL; + break; + /* BIG */ + case HA_KEYTYPE_ULONGLONG: + max_value = 0xFFFFFFFFFFFFFFFFULL; + break; + case HA_KEYTYPE_LONGLONG: + max_value = 0x7FFFFFFFFFFFFFFFULL; + break; + case HA_KEYTYPE_FLOAT: + /* We use the maximum as per IEEE754-2008 standard, 2^24 */ + max_value = 0x1000000ULL; + break; + case HA_KEYTYPE_DOUBLE: + /* We use the maximum as per IEEE754-2008 standard, 2^53 */ + max_value = 0x20000000000000ULL; + break; + default: + ut_error; + } + + return(max_value); +} + +/*******************************************************************//** +This function checks whether the index column information +is consistent between KEY info from mysql and that from innodb index. +@return TRUE if all column types match. */ +static +ibool +innobase_match_index_columns( +/*=========================*/ + const KEY* key_info, /*!< in: Index info + from mysql */ + const dict_index_t* index_info) /*!< in: Index info + from Innodb */ +{ + const KEY_PART_INFO* key_part; + const KEY_PART_INFO* key_end; + const dict_field_t* innodb_idx_fld; + const dict_field_t* innodb_idx_fld_end; + + DBUG_ENTER("innobase_match_index_columns"); + + /* Check whether user defined index column count matches */ + if (key_info->key_parts != index_info->n_user_defined_cols) { + DBUG_RETURN(FALSE); + } + + key_part = key_info->key_part; + key_end = key_part + key_info->key_parts; + innodb_idx_fld = index_info->fields; + innodb_idx_fld_end = index_info->fields + index_info->n_fields; + + /* Check each index column's datatype. We do not check + column name because there exists case that index + column name got modified in mysql but such change does not + propagate to InnoDB. + One hidden assumption here is that the index column sequences + are matched up between those in mysql and Innodb. */ + for (; key_part != key_end; ++key_part) { + ulint col_type; + ibool is_unsigned; + ulint mtype = innodb_idx_fld->col->mtype; + + /* Need to translate to InnoDB column type before + comparison. */ + col_type = get_innobase_type_from_mysql_type(&is_unsigned, + key_part->field); + + /* Ignore Innodb specific system columns. */ + while (mtype == DATA_SYS) { + innodb_idx_fld++; + + if (innodb_idx_fld >= innodb_idx_fld_end) { + DBUG_RETURN(FALSE); + } + } + + if (col_type != mtype) { + /* Column Type mismatches */ + DBUG_RETURN(FALSE); + } + + innodb_idx_fld++; + } + + DBUG_RETURN(TRUE); +} + +/*******************************************************************//** +This function builds a translation table in INNOBASE_SHARE +structure for fast index location with mysql array number from its +table->key_info structure. This also provides the necessary translation +between the key order in mysql key_info and Innodb ib_table->indexes if +they are not fully matched with each other. +Note we do not have any mutex protecting the translation table +building based on the assumption that there is no concurrent +index creation/drop and DMLs that requires index lookup. All table +handle will be closed before the index creation/drop. +@return TRUE if index translation table built successfully */ +static +ibool +innobase_build_index_translation( +/*=============================*/ + const TABLE* table, /*!< in: table in MySQL data + dictionary */ + dict_table_t* ib_table, /*!< in: table in Innodb data + dictionary */ + INNOBASE_SHARE* share) /*!< in/out: share structure + where index translation table + will be constructed in. */ +{ + ulint mysql_num_index; + ulint ib_num_index; + dict_index_t** index_mapping; + ibool ret = TRUE; + + DBUG_ENTER("innobase_build_index_translation"); + + mutex_enter(&dict_sys->mutex); + + mysql_num_index = table->s->keys; + ib_num_index = UT_LIST_GET_LEN(ib_table->indexes); + + index_mapping = share->idx_trans_tbl.index_mapping; + + /* If there exists inconsistency between MySQL and InnoDB dictionary + (metadata) information, the number of index defined in MySQL + could exceed that in InnoDB, do not build index translation + table in such case */ + if (UNIV_UNLIKELY(ib_num_index < mysql_num_index)) { + ret = FALSE; + goto func_exit; + } + + /* If index entry count is non-zero, nothing has + changed since last update, directly return TRUE */ + if (share->idx_trans_tbl.index_count) { + /* Index entry count should still match mysql_num_index */ + ut_a(share->idx_trans_tbl.index_count == mysql_num_index); + goto func_exit; + } + + /* The number of index increased, rebuild the mapping table */ + if (mysql_num_index > share->idx_trans_tbl.array_size) { + index_mapping = (dict_index_t**) my_realloc(index_mapping, + mysql_num_index * + sizeof(*index_mapping), + MYF(MY_ALLOW_ZERO_PTR)); + + if (!index_mapping) { + /* Report an error if index_mapping continues to be + NULL and mysql_num_index is a non-zero value */ + sql_print_error("InnoDB: fail to allocate memory for " + "index translation table. Number of " + "Index:%lu, array size:%lu", + mysql_num_index, + share->idx_trans_tbl.array_size); + ret = FALSE; + goto func_exit; + } + + share->idx_trans_tbl.array_size = mysql_num_index; + } + + /* For each index in the mysql key_info array, fetch its + corresponding InnoDB index pointer into index_mapping + array. */ + for (ulint count = 0; count < mysql_num_index; count++) { + + /* Fetch index pointers into index_mapping according to mysql + index sequence */ + index_mapping[count] = dict_table_get_index_on_name( + ib_table, table->key_info[count].name); + + if (!index_mapping[count]) { + sql_print_error("Cannot find index %s in InnoDB " + "index dictionary.", + table->key_info[count].name); + ret = FALSE; + goto func_exit; + } + + /* Double check fetched index has the same + column info as those in mysql key_info. */ + if (!innobase_match_index_columns(&table->key_info[count], + index_mapping[count])) { + sql_print_error("Found index %s whose column info " + "does not match that of MySQL.", + table->key_info[count].name); + ret = FALSE; + goto func_exit; + } + } + + /* Successfully built the translation table */ + share->idx_trans_tbl.index_count = mysql_num_index; + +func_exit: + if (!ret) { + /* Build translation table failed. */ + my_free(index_mapping, MYF(MY_ALLOW_ZERO_PTR)); + + share->idx_trans_tbl.array_size = 0; + share->idx_trans_tbl.index_count = 0; + index_mapping = NULL; + } + + share->idx_trans_tbl.index_mapping = index_mapping; + + mutex_exit(&dict_sys->mutex); + + DBUG_RETURN(ret); +} + +/*******************************************************************//** +This function uses index translation table to quickly locate the +requested index structure. +Note we do not have mutex protection for the index translatoin table +access, it is based on the assumption that there is no concurrent +translation table rebuild (fter create/drop index) and DMLs that +require index lookup. +@return dict_index_t structure for requested index. NULL if +fail to locate the index structure. */ +static +dict_index_t* +innobase_index_lookup( +/*==================*/ + INNOBASE_SHARE* share, /*!< in: share structure for index + translation table. */ + uint keynr) /*!< in: index number for the requested + index */ +{ + if (!share->idx_trans_tbl.index_mapping + || keynr >= share->idx_trans_tbl.index_count) { + return(NULL); + } + + return(share->idx_trans_tbl.index_mapping[keynr]); +} + +/************************************************************************ Set the autoinc column max value. This should only be called once from -ha_innobase::open(). Therefore there's no need for a covering lock. -@return DB_SUCCESS or error code */ +ha_innobase::open(). Therefore there's no need for a covering lock. */ UNIV_INTERN -ulint +void ha_innobase::innobase_initialize_autoinc() /*======================================*/ { - dict_index_t* index; ulonglong auto_inc; - const char* col_name; - ulint error; + const Field* field = table->found_next_number_field; - col_name = table->found_next_number_field->field_name; - index = innobase_get_index(table->s->next_number_index); + if (field != NULL) { + auto_inc = innobase_get_int_col_max_value(field); + } else { + /* We have no idea what's been passed in to us as the + autoinc column. We set it to the 0, effectively disabling + updates to the table. */ + auto_inc = 0; - /* Execute SELECT MAX(col_name) FROM TABLE; */ - error = row_search_max_autoinc(index, col_name, &auto_inc); + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: Unable to determine the AUTOINC " + "column name\n"); + } - switch (error) { - case DB_SUCCESS: + if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { + /* If the recovery level is set so high that writes + are disabled we force the AUTOINC counter to 0 + value effectively disabling writes to the table. + Secondly, we avoid reading the table in case the read + results in failure due to a corrupted table/index. + + We will not return an error to the client, so that the + tables can be dumped with minimal hassle. If an error + were returned in this case, the first attempt to read + the table would fail and subsequent SELECTs would succeed. */ + auto_inc = 0; + } else if (field == NULL) { + /* This is a far more serious error, best to avoid + opening the table and return failure. */ + my_error(ER_AUTOINC_READ_FAILED, MYF(0)); + } else { + dict_index_t* index; + const char* col_name; + ulonglong read_auto_inc; + ulint err; - /* At the this stage we don't know the increment - or the offset, so use default inrement of 1. */ - ++auto_inc; - break; + update_thd(ha_thd()); - case DB_RECORD_NOT_FOUND: - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: MySQL and InnoDB data " - "dictionaries are out of sync.\n" - "InnoDB: Unable to find the AUTOINC column %s in the " - "InnoDB table %s.\n" - "InnoDB: We set the next AUTOINC column value to the " - "maximum possible value,\n" - "InnoDB: in effect disabling the AUTOINC next value " - "generation.\n" - "InnoDB: You can either set the next AUTOINC value " - "explicitly using ALTER TABLE\n" - "InnoDB: or fix the data dictionary by recreating " - "the table.\n", - col_name, index->table->name); - - auto_inc = 0xFFFFFFFFFFFFFFFFULL; - break; + ut_a(prebuilt->trx == thd_to_trx(user_thd)); - default: - return(error); + col_name = field->field_name; + index = innobase_get_index(table->s->next_number_index); + + /* Execute SELECT MAX(col_name) FROM TABLE; */ + err = row_search_max_autoinc(index, col_name, &read_auto_inc); + + switch (err) { + case DB_SUCCESS: + /* At the this stage we do not know the increment + or the offset, so use a default increment of 1. */ + auto_inc = read_auto_inc + 1; + break; + + case DB_RECORD_NOT_FOUND: + ut_print_timestamp(stderr); + fprintf(stderr, " InnoDB: MySQL and InnoDB data " + "dictionaries are out of sync.\n" + "InnoDB: Unable to find the AUTOINC column " + "%s in the InnoDB table %s.\n" + "InnoDB: We set the next AUTOINC column " + "value to 0,\n" + "InnoDB: in effect disabling the AUTOINC " + "next value generation.\n" + "InnoDB: You can either set the next " + "AUTOINC value explicitly using ALTER TABLE\n" + "InnoDB: or fix the data dictionary by " + "recreating the table.\n", + col_name, index->table->name); + + /* This will disable the AUTOINC generation. */ + auto_inc = 0; + + /* We want the open to succeed, so that the user can + take corrective action. ie. reads should succeed but + updates should fail. */ + err = DB_SUCCESS; + break; + default: + /* row_search_max_autoinc() should only return + one of DB_SUCCESS or DB_RECORD_NOT_FOUND. */ + ut_error; + } } dict_table_autoinc_initialize(prebuilt->table, auto_inc); - - return(DB_SUCCESS); } /*****************************************************************//** @@ -3206,6 +3711,11 @@ retry: primary_key = table->s->primary_key; key_used_on_scan = primary_key; + if (!innobase_build_index_translation(table, ib_table, share)) { + sql_print_error("Build InnoDB index translation table for" + " Table %s failed", name); + } + /* Allocate a buffer for a 'row reference'. A row reference is a string of bytes of length ref_length which uniquely specifies a row in our table. Note that MySQL may also compare two row @@ -3213,31 +3723,86 @@ retry: of length ref_length! */ if (!row_table_got_default_clust_index(ib_table)) { - if (primary_key >= MAX_KEY) { - sql_print_error("Table %s has a primary key in InnoDB data " - "dictionary, but not in MySQL!", name); - } prebuilt->clust_index_was_generated = FALSE; - /* MySQL allocates the buffer for ref. key_info->key_length - includes space for all key columns + one byte for each column - that may be NULL. ref_length must be as exact as possible to - save space, because all row reference buffers are allocated - based on ref_length. */ + if (UNIV_UNLIKELY(primary_key >= MAX_KEY)) { + sql_print_error("Table %s has a primary key in " + "InnoDB data dictionary, but not " + "in MySQL!", name); - ref_length = table->key_info[primary_key].key_length; + /* This mismatch could cause further problems + if not attended, bring this to the user's attention + by printing a warning in addition to log a message + in the errorlog */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_SUCH_INDEX, + "InnoDB: Table %s has a " + "primary key in InnoDB data " + "dictionary, but not in " + "MySQL!", name); + + /* If primary_key >= MAX_KEY, its (primary_key) + value could be out of bound if continue to index + into key_info[] array. Find InnoDB primary index, + and assign its key_length to ref_length. + In addition, since MySQL indexes are sorted starting + with primary index, unique index etc., initialize + ref_length to the first index key length in + case we fail to find InnoDB cluster index. + + Please note, this will not resolve the primary + index mismatch problem, other side effects are + possible if users continue to use the table. + However, we allow this table to be opened so + that user can adopt necessary measures for the + mismatch while still being accessible to the table + date. */ + ref_length = table->key_info[0].key_length; + + /* Find correspoinding cluster index + key length in MySQL's key_info[] array */ + for (ulint i = 0; i < table->s->keys; i++) { + dict_index_t* index; + index = innobase_get_index(i); + if (dict_index_is_clust(index)) { + ref_length = + table->key_info[i].key_length; + } + } + } else { + /* MySQL allocates the buffer for ref. + key_info->key_length includes space for all key + columns + one byte for each column that may be + NULL. ref_length must be as exact as possible to + save space, because all row reference buffers are + allocated based on ref_length. */ + + ref_length = table->key_info[primary_key].key_length; + } } else { if (primary_key != MAX_KEY) { - sql_print_error("Table %s has no primary key in InnoDB data " - "dictionary, but has one in MySQL! If you " - "created the table with a MySQL version < " - "3.23.54 and did not define a primary key, " - "but defined a unique key with all non-NULL " - "columns, then MySQL internally treats that " - "key as the primary key. You can fix this " - "error by dump + DROP + CREATE + reimport " - "of the table.", name); + sql_print_error( + "Table %s has no primary key in InnoDB data " + "dictionary, but has one in MySQL! If you " + "created the table with a MySQL version < " + "3.23.54 and did not define a primary key, " + "but defined a unique key with all non-NULL " + "columns, then MySQL internally treats that " + "key as the primary key. You can fix this " + "error by dump + DROP + CREATE + reimport " + "of the table.", name); + + /* This mismatch could cause further problems + if not attended, bring this to the user attention + by printing a warning in addition to log a message + in the errorlog */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NO_SUCH_INDEX, + "InnoDB: Table %s has no " + "primary key in InnoDB data " + "dictionary, but has one in " + "MySQL!", name); } prebuilt->clust_index_was_generated = TRUE; @@ -3279,8 +3844,6 @@ retry: /* Only if the table has an AUTOINC column. */ if (prebuilt->table != NULL && table->found_next_number_field != NULL) { - ulint error; - dict_table_autoinc_lock(prebuilt->table); /* Since a table can already be "open" in InnoDB's internal @@ -3289,8 +3852,7 @@ retry: autoinc value from a previous MySQL open. */ if (dict_table_autoinc_read(prebuilt->table) == 0) { - error = innobase_initialize_autoinc(); - ut_a(error == DB_SUCCESS); + innobase_initialize_autoinc(); } dict_table_autoinc_unlock(prebuilt->table); @@ -4107,67 +4669,6 @@ skip_field: } /********************************************************************//** -Get the upper limit of the MySQL integral and floating-point type. */ -UNIV_INTERN -ulonglong -ha_innobase::innobase_get_int_col_max_value( -/*========================================*/ - const Field* field) -{ - ulonglong max_value = 0; - - switch(field->key_type()) { - /* TINY */ - case HA_KEYTYPE_BINARY: - max_value = 0xFFULL; - break; - case HA_KEYTYPE_INT8: - max_value = 0x7FULL; - break; - /* SHORT */ - case HA_KEYTYPE_USHORT_INT: - max_value = 0xFFFFULL; - break; - case HA_KEYTYPE_SHORT_INT: - max_value = 0x7FFFULL; - break; - /* MEDIUM */ - case HA_KEYTYPE_UINT24: - max_value = 0xFFFFFFULL; - break; - case HA_KEYTYPE_INT24: - max_value = 0x7FFFFFULL; - break; - /* LONG */ - case HA_KEYTYPE_ULONG_INT: - max_value = 0xFFFFFFFFULL; - break; - case HA_KEYTYPE_LONG_INT: - max_value = 0x7FFFFFFFULL; - break; - /* BIG */ - case HA_KEYTYPE_ULONGLONG: - max_value = 0xFFFFFFFFFFFFFFFFULL; - break; - case HA_KEYTYPE_LONGLONG: - max_value = 0x7FFFFFFFFFFFFFFFULL; - break; - case HA_KEYTYPE_FLOAT: - /* We use the maximum as per IEEE754-2008 standard, 2^24 */ - max_value = 0x1000000ULL; - break; - case HA_KEYTYPE_DOUBLE: - /* We use the maximum as per IEEE754-2008 standard, 2^53 */ - max_value = 0x20000000000000ULL; - break; - default: - ut_error; - } - - return(max_value); -} - -/********************************************************************//** This special handling is really to overcome the limitations of MySQL's binlogging. We need to eliminate the non-determinism that will arise in INSERT ... SELECT type of statements, since MySQL binlog only stores the @@ -4392,11 +4893,17 @@ no_commit: prebuilt->autoinc_error = DB_SUCCESS; if ((error = update_auto_increment())) { - /* We don't want to mask autoinc overflow errors. */ - if (prebuilt->autoinc_error != DB_SUCCESS) { - error = (int) prebuilt->autoinc_error; + /* Handle the case where the AUTOINC sub-system + failed during initialization. */ + if (prebuilt->autoinc_error == DB_UNSUPPORTED) { + error_result = ER_AUTOINC_READ_FAILED; + /* Set the error message to report too. */ + my_error(ER_AUTOINC_READ_FAILED, MYF(0)); + goto func_exit; + } else if (prebuilt->autoinc_error != DB_SUCCESS) { + error = (int) prebuilt->autoinc_error; goto report_error; } @@ -4477,24 +4984,29 @@ no_commit: update the table upper limit. Note: last_value will be 0 if get_auto_increment() was not called.*/ - if (auto_inc <= col_max_value - && auto_inc >= prebuilt->autoinc_last_value) { + if (auto_inc >= prebuilt->autoinc_last_value) { set_max_autoinc: - ut_a(prebuilt->autoinc_increment > 0); + /* This should filter out the negative + values set explicitly by the user. */ + if (auto_inc <= col_max_value) { + ut_a(prebuilt->autoinc_increment > 0); - ulonglong need; - ulonglong offset; + ulonglong need; + ulonglong offset; - offset = prebuilt->autoinc_offset; - need = prebuilt->autoinc_increment; + offset = prebuilt->autoinc_offset; + need = prebuilt->autoinc_increment; - auto_inc = innobase_next_autoinc( - auto_inc, need, offset, col_max_value); + auto_inc = innobase_next_autoinc( + auto_inc, + need, offset, col_max_value); - err = innobase_set_max_autoinc(auto_inc); + err = innobase_set_max_autoinc( + auto_inc); - if (err != DB_SUCCESS) { - error = err; + if (err != DB_SUCCESS) { + error = err; + } } } break; @@ -4525,7 +5037,7 @@ calc_row_difference( upd_t* uvect, /*!< in/out: update vector */ uchar* old_row, /*!< in: old row in MySQL format */ uchar* new_row, /*!< in: new row in MySQL format */ - TABLE* table, /*!< in: table in MySQL data + TABLE* table, /*!< in: table in MySQL data dictionary */ uchar* upd_buff, /*!< in: buffer to use */ ulint buff_len, /*!< in: buffer length */ @@ -4840,7 +5352,7 @@ ha_innobase::unlock_row(void) case ROW_READ_WITH_LOCKS: if (!srv_locks_unsafe_for_binlog && prebuilt->trx->isolation_level - != TRX_ISO_READ_COMMITTED) { + > TRX_ISO_READ_COMMITTED) { break; } /* fall through */ @@ -4879,7 +5391,7 @@ ha_innobase::try_semi_consistent_read(bool yes) if (yes && (srv_locks_unsafe_for_binlog - || prebuilt->trx->isolation_level == TRX_ISO_READ_COMMITTED)) { + || prebuilt->trx->isolation_level <= TRX_ISO_READ_COMMITTED)) { prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT; } else { prebuilt->row_read_type = ROW_READ_WITH_LOCKS; @@ -5174,14 +5686,30 @@ ha_innobase::innobase_get_index( DBUG_ENTER("innobase_get_index"); ha_statistic_increment(&SSV::ha_read_key_count); - ut_ad(user_thd == ha_thd()); - ut_a(prebuilt->trx == thd_to_trx(user_thd)); - if (keynr != MAX_KEY && table->s->keys > 0) { key = table->key_info + keynr; - index = dict_table_get_index_on_name(prebuilt->table, - key->name); + index = innobase_index_lookup(share, keynr); + + if (index) { + ut_a(ut_strcmp(index->name, key->name) == 0); + } else { + /* Can't find index with keynr in the translation + table. Only print message if the index translation + table exists */ + if (share->idx_trans_tbl.index_mapping) { + sql_print_error("InnoDB could not find " + "index %s key no %u for " + "table %s through its " + "index translation table", + key ? key->name : "NULL", + keynr, + prebuilt->table->name); + } + + index = dict_table_get_index_on_name(prebuilt->table, + key->name); + } } else { index = dict_table_get_first_index(prebuilt->table); } @@ -5242,7 +5770,7 @@ ha_innobase::change_active_index( dtuple_set_n_fields(prebuilt->search_tuple, prebuilt->index->n_fields); dict_index_copy_types(prebuilt->search_tuple, prebuilt->index, - prebuilt->index->n_fields); + prebuilt->index->n_fields); /* MySQL changes the active index for a handle also during some queries, for example SELECT MAX(a), SUM(a) first retrieves the MAX() @@ -5743,9 +6271,11 @@ create_table_def( if (error == DB_DUPLICATE_KEY) { char buf[100]; - innobase_convert_identifier(buf, sizeof buf, - table_name, strlen(table_name), - trx->mysql_thd, TRUE); + char* buf_end = innobase_convert_identifier( + buf, sizeof buf - 1, table_name, strlen(table_name), + trx->mysql_thd, TRUE); + + *buf_end = '\0'; my_error(ER_TABLE_EXISTS_ERROR, MYF(0), buf); } @@ -6118,6 +6648,8 @@ ha_innobase::create( /* Cache the value of innodb_file_format, in case it is modified by another thread while the table is being created. */ const ulint file_format = srv_file_format; + const char* stmt; + size_t stmt_len; DBUG_ENTER("ha_innobase::create"); @@ -6334,7 +6866,7 @@ ha_innobase::create( (int) form->s->primary_key : -1); - /* Our function row_get_mysql_key_number_for_index assumes + /* Our function innobase_get_mysql_key_number_for_index assumes the primary key is always number 0, if it exists */ ut_a(primary_key_no == -1 || primary_key_no == 0); @@ -6347,6 +6879,10 @@ ha_innobase::create( goto cleanup; } + if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { + flags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT; + } + error = create_table_def(trx, form, norm_name, create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, flags); @@ -6390,9 +6926,11 @@ ha_innobase::create( } } - if (*trx->mysql_query_str) { - error = row_table_add_foreign_constraints(trx, - *trx->mysql_query_str, norm_name, + stmt = innobase_get_stmt(thd, &stmt_len); + + if (stmt) { + error = row_table_add_foreign_constraints( + trx, stmt, stmt_len, norm_name, create_info->options & HA_LEX_CREATE_TMP_TABLE); error = convert_error_code_to_mysql(error, flags, NULL); @@ -6677,7 +7215,6 @@ innobase_drop_database( /* In the Windows plugin, thd = current_thd is always NULL */ trx = trx_allocate_for_mysql(); trx->mysql_thd = NULL; - trx->mysql_query_str = NULL; #else trx = innobase_trx_allocate(thd); #endif @@ -6868,10 +7405,15 @@ ha_innobase::records_in_range( key = table->key_info + active_index; - index = dict_table_get_index_on_name(prebuilt->table, key->name); + index = innobase_get_index(keynr); - /* MySQL knows about this index and so we must be able to find it.*/ - ut_a(index); + /* There exists possibility of not being able to find requested + index due to inconsistency between MySQL and InoDB dictionary info. + Necessary message should have been printed in innobase_get_index() */ + if (UNIV_UNLIKELY(!index)) { + n_rows = HA_POS_ERROR; + goto func_exit; + } heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t) + sizeof(dtuple_t))); @@ -6916,6 +7458,7 @@ ha_innobase::records_in_range( mem_heap_free(heap); +func_exit: my_free(key_val_buff2, MYF(0)); prebuilt->trx->op_info = (char*)""; @@ -7040,6 +7583,84 @@ ha_innobase::read_time( } /*********************************************************************//** +Calculates the key number used inside MySQL for an Innobase index. We will +first check the "index translation table" for a match of the index to get +the index number. If there does not exist an "index translation table", +or not able to find the index in the translation table, then we will fall back +to the traditional way of looping through dict_index_t list to find a +match. In this case, we have to take into account if we generated a +default clustered index for the table +@return the key number used inside MySQL */ +static +unsigned int +innobase_get_mysql_key_number_for_index( +/*====================================*/ + INNOBASE_SHARE* share, /*!< in: share structure for index + translation table. */ + const TABLE* table, /*!< in: table in MySQL data + dictionary */ + dict_table_t* ib_table,/*!< in: table in Innodb data + dictionary */ + const dict_index_t* index) /*!< in: index */ +{ + const dict_index_t* ind; + unsigned int i; + + ut_a(index); + + /* If index does not belong to the table of share structure. Search + index->table instead */ + if (index->table != ib_table + && innobase_strcasecmp(index->table->name, share->table_name)) { + i = 0; + ind = dict_table_get_first_index(index->table); + + while (index != ind) { + ind = dict_table_get_next_index(ind); + i++; + } + + if (row_table_got_default_clust_index(index->table)) { + ut_a(i > 0); + i--; + } + + return(i); + } + + /* If index translation table exists, we will first check + the index through index translation table for a match. */ + if (share->idx_trans_tbl.index_mapping) { + for (i = 0; i < share->idx_trans_tbl.index_count; i++) { + if (share->idx_trans_tbl.index_mapping[i] == index) { + return(i); + } + } + + /* Print an error message if we cannot find the index + ** in the "index translation table". */ + sql_print_error("Cannot find index %s in InnoDB index " + "translation table.", index->name); + } + + /* If we do not have an "index translation table", or not able + to find the index in the translation table, we'll directly find + matching index with information from mysql TABLE structure and + InnoDB dict_index_t list */ + for (i = 0; i < table->s->keys; i++) { + ind = dict_table_get_index_on_name( + ib_table, table->key_info[i].name); + + if (index == ind) { + return(i); + } + } + + ut_error; + + return(0); +} +/*********************************************************************//** Returns statistics information of the table to the MySQL interpreter, in various fields of the handle object. */ UNIV_INTERN @@ -7057,6 +7678,7 @@ ha_innobase::info( char path[FN_REFLEN]; os_file_stat_t stat_info; + DBUG_ENTER("info"); /* If we are forcing recovery at a high level, we will suppress @@ -7217,13 +7839,29 @@ ha_innobase::info( } if (flag & HA_STATUS_CONST) { - index = dict_table_get_first_index(ib_table); + /* Verify the number of index in InnoDB and MySQL + matches up. If prebuilt->clust_index_was_generated + holds, InnoDB defines GEN_CLUST_INDEX internally */ + ulint num_innodb_index = UT_LIST_GET_LEN(ib_table->indexes) + - prebuilt->clust_index_was_generated; - if (prebuilt->clust_index_was_generated) { - index = dict_table_get_next_index(index); + if (table->s->keys != num_innodb_index) { + sql_print_error("Table %s contains %lu " + "indexes inside InnoDB, which " + "is different from the number of " + "indexes %u defined in the MySQL ", + ib_table->name, num_innodb_index, + table->s->keys); } for (i = 0; i < table->s->keys; i++) { + /* We could get index quickly through internal + index mapping with the index translation table. + The identity of index (match up index name with + that of table->key_info[i]) is already verified in + innobase_get_index(). */ + index = innobase_get_index(i); + if (index == NULL) { sql_print_error("Table %s contains fewer " "indexes inside InnoDB than " @@ -7252,6 +7890,8 @@ ha_innobase::info( break; } + dict_index_stat_mutex_enter(index); + if (index->stat_n_diff_key_vals[j + 1] == 0) { rec_per_key = stats.records; @@ -7260,6 +7900,8 @@ ha_innobase::info( index->stat_n_diff_key_vals[j + 1]); } + dict_index_stat_mutex_exit(index); + /* Since MySQL seems to favor table scans too much over index searches, we pretend index selectivity is 2 times better than @@ -7275,8 +7917,6 @@ ha_innobase::info( rec_per_key >= ~(ulong) 0 ? ~(ulong) 0 : (ulong) rec_per_key; } - - index = dict_table_get_next_index(index); } } @@ -7289,8 +7929,8 @@ ha_innobase::info( err_index = trx_get_error_info(prebuilt->trx); if (err_index) { - errkey = (unsigned int) - row_get_mysql_key_number_for_index(err_index); + errkey = innobase_get_mysql_key_number_for_index( + share, table, ib_table, err_index); } else { errkey = (unsigned int) prebuilt->trx->error_key_num; } @@ -7316,15 +7956,9 @@ ha_innobase::analyze( THD* thd, /*!< in: connection thread handle */ HA_CHECK_OPT* check_opt) /*!< in: currently ignored */ { - /* Serialize ANALYZE TABLE inside InnoDB, see - Bug#38996 Race condition in ANALYZE TABLE */ - pthread_mutex_lock(&analyze_mutex); - /* Simply call ::info() with all the flags */ info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE); - pthread_mutex_unlock(&analyze_mutex); - return(0); } @@ -7354,8 +7988,13 @@ ha_innobase::check( HA_CHECK_OPT* check_opt) /*!< in: check options, currently ignored */ { - ulint ret; + dict_index_t* index; + ulint n_rows; + ulint n_rows_in_table = ULINT_UNDEFINED; + ibool is_ok = TRUE; + ulint old_isolation_level; + DBUG_ENTER("ha_innobase::check"); DBUG_ASSERT(thd == ha_thd()); ut_a(prebuilt->trx); ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N); @@ -7368,17 +8007,140 @@ ha_innobase::check( build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW); } - ret = row_check_table_for_mysql(prebuilt); + if (prebuilt->table->ibd_file_missing) { + sql_print_error("InnoDB: Error:\n" + "InnoDB: MySQL is trying to use a table handle" + " but the .ibd file for\n" + "InnoDB: table %s does not exist.\n" + "InnoDB: Have you deleted the .ibd file" + " from the database directory under\n" + "InnoDB: the MySQL datadir, or have you" + " used DISCARD TABLESPACE?\n" + "InnoDB: Please refer to\n" + "InnoDB: " REFMAN "innodb-troubleshooting.html\n" + "InnoDB: how you can resolve the problem.\n", + prebuilt->table->name); + DBUG_RETURN(HA_ADMIN_CORRUPT); + } - switch (ret) { - case DB_SUCCESS: - return(HA_ADMIN_OK); - case DB_INTERRUPTED: + prebuilt->trx->op_info = "checking table"; + + old_isolation_level = prebuilt->trx->isolation_level; + + /* We must run the index record counts at an isolation level + >= READ COMMITTED, because a dirty read can see a wrong number + of records in some index; to play safe, we use always + REPEATABLE READ here */ + + prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ; + + /* Enlarge the fatal lock wait timeout during CHECK TABLE. */ + mutex_enter(&kernel_mutex); + srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */ + mutex_exit(&kernel_mutex); + + for (index = dict_table_get_first_index(prebuilt->table); + index != NULL; + index = dict_table_get_next_index(index)) { +#if 0 + fputs("Validating index ", stderr); + ut_print_name(stderr, trx, FALSE, index->name); + putc('\n', stderr); +#endif + + if (!btr_validate_index(index, prebuilt->trx)) { + is_ok = FALSE; + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NOT_KEYFILE, + "InnoDB: The B-tree of" + " index '%-.200s' is corrupted.", + index->name); + continue; + } + + /* Instead of invoking change_active_index(), set up + a dummy template for non-locking reads, disabling + access to the clustered index. */ + prebuilt->index = index; + + prebuilt->index_usable = row_merge_is_index_usable( + prebuilt->trx, prebuilt->index); + + if (UNIV_UNLIKELY(!prebuilt->index_usable)) { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + HA_ERR_TABLE_DEF_CHANGED, + "InnoDB: Insufficient history for" + " index '%-.200s'", + index->name); + continue; + } + + prebuilt->sql_stat_start = TRUE; + prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE; + prebuilt->n_template = 0; + prebuilt->need_to_access_clustered = FALSE; + + dtuple_set_n_fields(prebuilt->search_tuple, 0); + + prebuilt->select_lock_type = LOCK_NONE; + + if (!row_check_index_for_mysql(prebuilt, index, &n_rows)) { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NOT_KEYFILE, + "InnoDB: The B-tree of" + " index '%-.200s' is corrupted.", + index->name); + is_ok = FALSE; + } + + if (thd_killed(user_thd)) { + break; + } + +#if 0 + fprintf(stderr, "%lu entries in index %s\n", n_rows, + index->name); +#endif + + if (index == dict_table_get_first_index(prebuilt->table)) { + n_rows_in_table = n_rows; + } else if (n_rows != n_rows_in_table) { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NOT_KEYFILE, + "InnoDB: Index '%-.200s'" + " contains %lu entries," + " should be %lu.", + index->name, + (ulong) n_rows, + (ulong) n_rows_in_table); + is_ok = FALSE; + } + } + + /* Restore the original isolation level */ + prebuilt->trx->isolation_level = old_isolation_level; + + /* We validate also the whole adaptive hash index for all tables + at every CHECK TABLE */ + + if (!btr_search_validate()) { + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_NOT_KEYFILE, + "InnoDB: The adaptive hash index is corrupted."); + is_ok = FALSE; + } + + /* Restore the fatal lock wait timeout after CHECK TABLE. */ + mutex_enter(&kernel_mutex); + srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */ + mutex_exit(&kernel_mutex); + + prebuilt->trx->op_info = ""; + if (thd_killed(user_thd)) { my_error(ER_QUERY_INTERRUPTED, MYF(0)); - return(-1); - default: - return(HA_ADMIN_CORRUPT); } + + DBUG_RETURN(is_ok ? HA_ADMIN_OK : HA_ADMIN_CORRUPT); } /*************************************************************//** @@ -7918,34 +8680,24 @@ ha_innobase::external_lock( /* Statement based binlogging does not work in isolation level READ UNCOMMITTED and READ COMMITTED since the necessary locks cannot be taken. In this case, we print an - informative error message and return with an error. */ - if (lock_type == F_WRLCK) - { - ulong const binlog_format= thd_binlog_format(thd); - ulong const tx_isolation = thd_tx_isolation(ha_thd()); - if (tx_isolation <= ISO_READ_COMMITTED - && binlog_format == BINLOG_FORMAT_STMT - && !(table_flags() & HA_BINLOG_STMT_CAPABLE) -#if MYSQL_VERSION_ID > 50140 - && thd_binlog_filter_ok(thd) -#endif /* MYSQL_VERSION_ID > 50140 */ - ) - { - char buf[256]; - my_snprintf(buf, sizeof(buf), - "Transaction level '%s' in" - " InnoDB is not safe for binlog mode '%s'", - tx_isolation_names[tx_isolation], - binlog_format_names[binlog_format]); - /* The error may be suppressed by test cases, by setting - the no_innodb_binlog_errors debug symbol. */ - if (DBUG_EVALUATE_IF("no_innodb_binlog_errors", 0, 1)) { - my_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE, MYF(0), - " InnoDB is limited to row-logging when " - "transaction isolation level is " - "READ COMMITTED or READ UNCOMMITTED."); - DBUG_RETURN(HA_ERR_LOGGING_IMPOSSIBLE); - } + informative error message and return with an error. + Note: decide_logging_format would give the same error message, + except it cannot give the extra details. */ + if (lock_type == F_WRLCK + && !(table_flags() & HA_BINLOG_STMT_CAPABLE) + && thd_binlog_format(thd) == BINLOG_FORMAT_STMT + && thd_binlog_filter_ok(thd) + && thd_sqlcom_can_generate_row_events(thd)) + { + int skip = 0; + /* used by test case */ + DBUG_EXECUTE_IF("no_innodb_binlog_errors", skip = 1;); + if (!skip) { + my_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE, MYF(0), + " InnoDB is limited to row-logging when " + "transaction isolation level is " + "READ COMMITTED or READ UNCOMMITTED."); + DBUG_RETURN(HA_ERR_LOGGING_IMPOSSIBLE); } } @@ -8209,8 +8961,8 @@ innodb_show_status( mutex_enter(&srv_monitor_file_mutex); rewind(srv_monitor_file); - srv_printf_innodb_monitor(srv_monitor_file, - &trx_list_start, &trx_list_end); + srv_printf_innodb_monitor(srv_monitor_file, FALSE, + &trx_list_start, &trx_list_end); flen = ftell(srv_monitor_file); os_file_set_eof(srv_monitor_file); @@ -8228,8 +8980,8 @@ innodb_show_status( read the contents of the temporary file */ if (!(str = (char*) my_malloc(usable_len + 1, MYF(0)))) { - mutex_exit(&srv_monitor_file_mutex); - DBUG_RETURN(TRUE); + mutex_exit(&srv_monitor_file_mutex); + DBUG_RETURN(TRUE); } rewind(srv_monitor_file); @@ -8267,19 +9019,25 @@ innodb_show_status( } /************************************************************************//** -Implements the SHOW MUTEX STATUS command. . */ +Implements the SHOW MUTEX STATUS command. +@return TRUE on failure, FALSE on success. */ static bool innodb_mutex_show_status( /*=====================*/ - handlerton* hton, /*!< in: the innodb handlerton */ + handlerton* hton, /*!< in: the innodb handlerton */ THD* thd, /*!< in: the MySQL query thread of the caller */ - stat_print_fn* stat_print) + stat_print_fn* stat_print) /*!< in: function for printing + statistics */ { char buf1[IO_SIZE], buf2[IO_SIZE]; mutex_t* mutex; rw_lock_t* lock; + ulint block_mutex_oswait_count = 0; + ulint block_lock_oswait_count = 0; + mutex_t* block_mutex = NULL; + rw_lock_t* block_lock = NULL; #ifdef UNIV_DEBUG ulint rw_lock_count= 0; ulint rw_lock_count_spin_loop= 0; @@ -8294,12 +9052,16 @@ innodb_mutex_show_status( mutex_enter(&mutex_list_mutex); - mutex = UT_LIST_GET_FIRST(mutex_list); + for (mutex = UT_LIST_GET_FIRST(mutex_list); mutex != NULL; + mutex = UT_LIST_GET_NEXT(list, mutex)) { + if (mutex->count_os_wait == 0) { + continue; + } - while (mutex != NULL) { - if (mutex->count_os_wait == 0 - || buf_pool_is_block_mutex(mutex)) { - goto next_mutex; + if (buf_pool_is_block_mutex(mutex)) { + block_mutex = mutex; + block_mutex_oswait_count += mutex->count_os_wait; + continue; } #ifdef UNIV_DEBUG if (mutex->mutex_type != 1) { @@ -8326,8 +9088,7 @@ innodb_mutex_show_status( DBUG_RETURN(1); } } - } - else { + } else { rw_lock_count += mutex->count_using; rw_lock_count_spin_loop += mutex->count_spin_loop; rw_lock_count_spin_rounds += mutex->count_spin_rounds; @@ -8339,7 +9100,7 @@ innodb_mutex_show_status( buf1len= (uint) my_snprintf(buf1, sizeof(buf1), "%s:%lu", mutex->cfile_name, (ulong) mutex->cline); buf2len= (uint) my_snprintf(buf2, sizeof(buf2), "os_waits=%lu", - mutex->count_os_wait); + (ulong) mutex->count_os_wait); if (stat_print(thd, innobase_hton_name, hton_name_len, buf1, buf1len, @@ -8348,45 +9109,83 @@ innodb_mutex_show_status( DBUG_RETURN(1); } #endif /* UNIV_DEBUG */ + } + + if (block_mutex) { + buf1len = (uint) my_snprintf(buf1, sizeof buf1, + "combined %s:%lu", + block_mutex->cfile_name, + (ulong) block_mutex->cline); + buf2len = (uint) my_snprintf(buf2, sizeof buf2, + "os_waits=%lu", + (ulong) block_mutex_oswait_count); -next_mutex: - mutex = UT_LIST_GET_NEXT(list, mutex); + if (stat_print(thd, innobase_hton_name, + hton_name_len, buf1, buf1len, + buf2, buf2len)) { + mutex_exit(&mutex_list_mutex); + DBUG_RETURN(1); + } } mutex_exit(&mutex_list_mutex); mutex_enter(&rw_lock_list_mutex); - lock = UT_LIST_GET_FIRST(rw_lock_list); - - while (lock != NULL) { - if (lock->count_os_wait - && !buf_pool_is_block_lock(lock)) { - buf1len= my_snprintf(buf1, sizeof(buf1), "%s:%lu", - lock->cfile_name, (ulong) lock->cline); - buf2len= my_snprintf(buf2, sizeof(buf2), - "os_waits=%lu", lock->count_os_wait); - - if (stat_print(thd, innobase_hton_name, - hton_name_len, buf1, buf1len, - buf2, buf2len)) { - mutex_exit(&rw_lock_list_mutex); - DBUG_RETURN(1); - } + for (lock = UT_LIST_GET_FIRST(rw_lock_list); lock != NULL; + lock = UT_LIST_GET_NEXT(list, lock)) { + if (lock->count_os_wait == 0) { + continue; + } + + if (buf_pool_is_block_lock(lock)) { + block_lock = lock; + block_lock_oswait_count += lock->count_os_wait; + continue; + } + + buf1len = my_snprintf(buf1, sizeof buf1, "%s:%lu", + lock->cfile_name, (ulong) lock->cline); + buf2len = my_snprintf(buf2, sizeof buf2, "os_waits=%lu", + (ulong) lock->count_os_wait); + + if (stat_print(thd, innobase_hton_name, + hton_name_len, buf1, buf1len, + buf2, buf2len)) { + mutex_exit(&rw_lock_list_mutex); + DBUG_RETURN(1); + } + } + + if (block_lock) { + buf1len = (uint) my_snprintf(buf1, sizeof buf1, + "combined %s:%lu", + block_lock->cfile_name, + (ulong) block_lock->cline); + buf2len = (uint) my_snprintf(buf2, sizeof buf2, + "os_waits=%lu", + (ulong) block_lock_oswait_count); + + if (stat_print(thd, innobase_hton_name, + hton_name_len, buf1, buf1len, + buf2, buf2len)) { + mutex_exit(&rw_lock_list_mutex); + DBUG_RETURN(1); } - lock = UT_LIST_GET_NEXT(list, lock); } mutex_exit(&rw_lock_list_mutex); #ifdef UNIV_DEBUG - buf2len= my_snprintf(buf2, sizeof(buf2), - "count=%lu, spin_waits=%lu, spin_rounds=%lu, " - "os_waits=%lu, os_yields=%lu, os_wait_times=%lu", - rw_lock_count, rw_lock_count_spin_loop, - rw_lock_count_spin_rounds, - rw_lock_count_os_wait, rw_lock_count_os_yield, - (ulong) (rw_lock_wait_time/1000)); + buf2len = my_snprintf(buf2, sizeof buf2, + "count=%lu, spin_waits=%lu, spin_rounds=%lu, " + "os_waits=%lu, os_yields=%lu, os_wait_times=%lu", + (ulong) rw_lock_count, + (ulong) rw_lock_count_spin_loop, + (ulong) rw_lock_count_spin_rounds, + (ulong) rw_lock_count_os_wait, + (ulong) rw_lock_count_os_yield, + (ulong) (rw_lock_wait_time / 1000)); if (stat_print(thd, innobase_hton_name, hton_name_len, STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) { @@ -8422,7 +9221,7 @@ bool innobase_show_status(handlerton *hton, THD* thd, static INNOBASE_SHARE* get_share(const char* table_name) { INNOBASE_SHARE *share; - pthread_mutex_lock(&innobase_share_mutex); + mysql_mutex_lock(&innobase_share_mutex); ulint fold = ut_fold_string(table_name); @@ -8448,17 +9247,22 @@ static INNOBASE_SHARE* get_share(const char* table_name) innobase_open_tables, fold, share); thr_lock_init(&share->lock); + + /* Index translation table initialization */ + share->idx_trans_tbl.index_mapping = NULL; + share->idx_trans_tbl.index_count = 0; + share->idx_trans_tbl.array_size = 0; } share->use_count++; - pthread_mutex_unlock(&innobase_share_mutex); + mysql_mutex_unlock(&innobase_share_mutex); return(share); } static void free_share(INNOBASE_SHARE* share) { - pthread_mutex_lock(&innobase_share_mutex); + mysql_mutex_lock(&innobase_share_mutex); #ifdef UNIV_DEBUG INNOBASE_SHARE* share2; @@ -8478,13 +9282,18 @@ static void free_share(INNOBASE_SHARE* share) HASH_DELETE(INNOBASE_SHARE, table_name_hash, innobase_open_tables, fold, share); thr_lock_delete(&share->lock); + + /* Free any memory from index translation table */ + my_free(share->idx_trans_tbl.index_mapping, + MYF(MY_ALLOW_ZERO_PTR)); + my_free(share, MYF(0)); /* TODO: invoke HASH_MIGRATE if innobase_open_tables shrinks too much */ } - pthread_mutex_unlock(&innobase_share_mutex); + mysql_mutex_unlock(&innobase_share_mutex); } /*****************************************************************//** @@ -8580,7 +9389,7 @@ ha_innobase::store_lock( isolation_level = trx->isolation_level; if ((srv_locks_unsafe_for_binlog - || isolation_level == TRX_ISO_READ_COMMITTED) + || isolation_level <= TRX_ISO_READ_COMMITTED) && isolation_level != TRX_ISO_SERIALIZABLE && (lock_type == TL_READ || lock_type == TL_READ_NO_INSERT) && (sql_command == SQLCOM_INSERT_SELECT @@ -8712,7 +9521,10 @@ ha_innobase::innobase_get_autoinc( *value = dict_table_autoinc_read(prebuilt->table); /* It should have been initialized during open. */ - ut_a(*value != 0); + if (*value == 0) { + prebuilt->autoinc_error = DB_UNSUPPORTED; + dict_table_autoinc_unlock(prebuilt->table); + } } return(prebuilt->autoinc_error); @@ -8792,6 +9604,11 @@ ha_innobase::get_auto_increment( invoking this method. So we are not sure if it's guaranteed to be 0 or not. */ + /* We need the upper limit of the col type to check for + whether we update the table autoinc counter or not. */ + ulonglong col_max_value = innobase_get_int_col_max_value( + table->next_number_field); + /* Called for the first time ? */ if (trx->n_autoinc_rows == 0) { @@ -8808,6 +9625,11 @@ ha_innobase::get_auto_increment( /* Not in the middle of a mult-row INSERT. */ } else if (prebuilt->autoinc_last_value == 0) { set_if_bigger(*first_value, autoinc); + /* Check for -ve values. */ + } else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) { + /* Set to next logical value. */ + ut_a(autoinc > trx->n_autoinc_rows); + *first_value = (autoinc - trx->n_autoinc_rows) - 1; } *nb_reserved_values = trx->n_autoinc_rows; @@ -8818,12 +9640,6 @@ ha_innobase::get_auto_increment( ulonglong need; ulonglong current; ulonglong next_value; - ulonglong col_max_value; - - /* We need the upper limit of the col type to check for - whether we update the table autoinc counter or not. */ - col_max_value = innobase_get_int_col_max_value( - table->next_number_field); current = *first_value > col_max_value ? autoinc : *first_value; need = *nb_reserved_values * increment; @@ -9186,7 +10002,7 @@ innobase_xa_prepare( In this case we cannot know how many minutes or hours will be between XA PREPARE and XA COMMIT, and we don't want to block for undefined period of time. */ - pthread_mutex_lock(&prepare_commit_mutex); + mysql_mutex_lock(&prepare_commit_mutex); trx->active_trans = 2; } @@ -9320,33 +10136,60 @@ innobase_set_cursor_view( (cursor_view_t*) curview); } +/*******************************************************************//** +If col_name is not NULL, check whether the named column is being +renamed in the table. If col_name is not provided, check +whether any one of columns in the table is being renamed. +@return true if the column is being renamed */ +static +bool +check_column_being_renamed( +/*=======================*/ + const TABLE* table, /*!< in: MySQL table */ + const char* col_name) /*!< in: name of the column */ +{ + uint k; + Field* field; -/*********************************************************************** -Check whether any of the given columns is being renamed in the table. */ + for (k = 0; k < table->s->fields; k++) { + field = table->field[k]; + + if (field->flags & FIELD_IS_RENAMED) { + + /* If col_name is not provided, return + if the field is marked as being renamed. */ + if (!col_name) { + return(true); + } + + /* If col_name is provided, return only + if names match */ + if (innobase_strcasecmp(field->field_name, + col_name) == 0) { + return(true); + } + } + } + + return(false); +} + +/*******************************************************************//** +Check whether any of the given columns is being renamed in the table. +@return true if any of col_names is being renamed in table */ static bool column_is_being_renamed( /*====================*/ - /* out: true if any of col_names is - being renamed in table */ - TABLE* table, /* in: MySQL table */ - uint n_cols, /* in: number of columns */ - const char** col_names) /* in: names of the columns */ + TABLE* table, /*!< in: MySQL table */ + uint n_cols, /*!< in: number of columns */ + const char** col_names) /*!< in: names of the columns */ { uint j; - uint k; - Field* field; - const char* col_name; for (j = 0; j < n_cols; j++) { - col_name = col_names[j]; - for (k = 0; k < table->s->fields; k++) { - field = table->field[k]; - if ((field->flags & FIELD_IS_RENAMED) - && innobase_strcasecmp(field->field_name, - col_name) == 0) { - return(true); - } + if (check_column_being_renamed(table, col_names[j])) { + return(true); } } @@ -9430,6 +10273,15 @@ ha_innobase::check_if_incompatible_data( return(COMPATIBLE_DATA_NO); } + /* For column rename operation, MySQL does not supply enough + information (new column name etc.) for InnoDB to make appropriate + system metadata change. To avoid system metadata inconsistency, + currently we can just request a table rebuild/copy by returning + COMPATIBLE_DATA_NO */ + if (check_column_being_renamed(table, NULL)) { + return COMPATIBLE_DATA_NO; + } + /* Check if a column participating in a foreign key is being renamed. There is no mechanism for updating InnoDB foreign key definitions. */ if (foreign_key_column_is_being_renamed(prebuilt, table)) { @@ -9788,7 +10640,35 @@ innodb_old_blocks_pct_update( } /*************************************************************//** -Check if it is a valid value of innodb_change_buffering. This function is +Find the corresponding ibuf_use_t value that indexes into +innobase_change_buffering_values[] array for the input +change buffering option name. +@return corresponding IBUF_USE_* value for the input variable +name, or IBUF_USE_COUNT if not able to find a match */ +static +ibuf_use_t +innodb_find_change_buffering_value( +/*===============================*/ + const char* input_name) /*!< in: input change buffering + option name */ +{ + ulint use; + + for (use = 0; use < UT_ARR_SIZE(innobase_change_buffering_values); + use++) { + /* found a match */ + if (!innobase_strcasecmp( + input_name, innobase_change_buffering_values[use])) { + return((ibuf_use_t)use); + } + } + + /* Did not find any match */ + return(IBUF_USE_COUNT); +} + +/*************************************************************//** +Check if it is a valid value of innodb_change_buffering. This function is registered as a callback with MySQL. @return 0 for valid innodb_change_buffering */ static @@ -9812,19 +10692,22 @@ innodb_change_buffering_validate( change_buffering_input = value->val_str(value, buff, &len); if (change_buffering_input != NULL) { - ulint use; + ibuf_use_t use; - for (use = 0; use < UT_ARR_SIZE(innobase_change_buffering_values); - use++) { - if (!innobase_strcasecmp( - change_buffering_input, - innobase_change_buffering_values[use])) { - *(ibuf_use_t*) save = (ibuf_use_t) use; - return(0); - } + use = innodb_find_change_buffering_value( + change_buffering_input); + + if (use != IBUF_USE_COUNT) { + /* Find a matching change_buffering option value. */ + *static_cast<const char**>(save) = + innobase_change_buffering_values[use]; + + return(0); } } + /* No corresponding change buffering option for user supplied + "change_buffering_input" */ return(1); } @@ -9835,21 +10718,27 @@ static void innodb_change_buffering_update( /*===========================*/ - THD* thd, /*!< in: thread handle */ - struct st_mysql_sys_var* var, /*!< in: pointer to - system variable */ - void* var_ptr, /*!< out: where the - formal string goes */ - const void* save) /*!< in: immediate result - from check function */ + THD* thd, /*!< in: thread handle */ + struct st_mysql_sys_var* var, /*!< in: pointer to + system variable */ + void* var_ptr,/*!< out: where the + formal string goes */ + const void* save) /*!< in: immediate result + from check function */ { + ibuf_use_t use; + ut_a(var_ptr != NULL); ut_a(save != NULL); - ut_a((*(ibuf_use_t*) save) < IBUF_USE_COUNT); - ibuf_use = *(const ibuf_use_t*) save; + use = innodb_find_change_buffering_value( + *static_cast<const char*const*>(save)); - *(const char**) var_ptr = innobase_change_buffering_values[ibuf_use]; + ut_a(use < IBUF_USE_COUNT); + + ibuf_use = use; + *static_cast<const char**>(var_ptr) = + *static_cast<const char*const*>(save); } static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff) @@ -9934,6 +10823,23 @@ static MYSQL_SYSVAR_ULONG(io_capacity, srv_io_capacity, "Number of IOPs the server can do. Tunes the background IO rate", NULL, NULL, 200, 100, ~0L, 0); +static MYSQL_SYSVAR_ULONG(purge_batch_size, srv_purge_batch_size, + PLUGIN_VAR_OPCMDARG, + "Number of UNDO logs to purge in one batch from the history list. " + "Default is 20", + NULL, NULL, + 20, /* Default setting */ + 1, /* Minimum value */ + 5000, 0); /* Maximum value */ + +static MYSQL_SYSVAR_ULONG(purge_threads, srv_n_purge_threads, + PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, + "Purge threads can be either 0 or 1. Default is 0.", + NULL, NULL, + 0, /* Default setting */ + 0, /* Minimum value */ + 1, 0); /* Maximum value */ + static MYSQL_SYSVAR_ULONG(fast_shutdown, innobase_fast_shutdown, PLUGIN_VAR_OPCMDARG, "Speeds up the shutdown process of the InnoDB storage engine. Possible " @@ -10059,6 +10965,11 @@ static MYSQL_SYSVAR_LONGLONG(buffer_pool_size, innobase_buffer_pool_size, "The size of the memory buffer InnoDB uses to cache data and indexes of its tables.", NULL, NULL, 128*1024*1024L, 5*1024*1024L, LONGLONG_MAX, 1024*1024L); +static MYSQL_SYSVAR_LONG(buffer_pool_instances, innobase_buffer_pool_instances, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, + "Number of buffer pool instances, set to higher value on high-end machines to increase scalability", + NULL, NULL, 1L, 1L, MAX_BUFFER_POOLS, 1L); + static MYSQL_SYSVAR_ULONG(commit_concurrency, innobase_commit_concurrency, PLUGIN_VAR_RQCMDARG, "Helps in performance tuning in heavily concurrent environments.", @@ -10172,16 +11083,21 @@ static MYSQL_SYSVAR_BOOL(use_sys_malloc, srv_use_sys_malloc, "Use OS memory allocator instead of InnoDB's internal memory allocator", NULL, NULL, TRUE); +static MYSQL_SYSVAR_BOOL(use_native_aio, srv_use_native_aio, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, + "Use native AIO if supported on this platform.", + NULL, NULL, TRUE); + static MYSQL_SYSVAR_STR(change_buffering, innobase_change_buffering, PLUGIN_VAR_RQCMDARG, "Buffer changes to reduce random access: " "OFF, ON, inserting, deleting, changing, or purging.", innodb_change_buffering_validate, - innodb_change_buffering_update, NULL); + innodb_change_buffering_update, "all"); static MYSQL_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold, PLUGIN_VAR_RQCMDARG, - "Number of pages that must be accessed sequentially for InnoDB to" + "Number of pages that must be accessed sequentially for InnoDB to " "trigger a readahead.", NULL, NULL, 56, 0, 64, 0); @@ -10189,6 +11105,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(additional_mem_pool_size), MYSQL_SYSVAR(autoextend_increment), MYSQL_SYSVAR(buffer_pool_size), + MYSQL_SYSVAR(buffer_pool_instances), MYSQL_SYSVAR(checksums), MYSQL_SYSVAR(commit_concurrency), MYSQL_SYSVAR(concurrency_tickets), @@ -10238,9 +11155,12 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(autoinc_lock_mode), MYSQL_SYSVAR(version), MYSQL_SYSVAR(use_sys_malloc), + MYSQL_SYSVAR(use_native_aio), MYSQL_SYSVAR(change_buffering), MYSQL_SYSVAR(read_ahead_threshold), MYSQL_SYSVAR(io_capacity), + MYSQL_SYSVAR(purge_threads), + MYSQL_SYSVAR(purge_batch_size), NULL }; @@ -10265,7 +11185,15 @@ i_s_innodb_lock_waits, i_s_innodb_cmp, i_s_innodb_cmp_reset, i_s_innodb_cmpmem, -i_s_innodb_cmpmem_reset +i_s_innodb_cmpmem_reset, +i_s_innodb_sys_tables, +i_s_innodb_sys_tablestats, +i_s_innodb_sys_indexes, +i_s_innodb_sys_columns, +i_s_innodb_sys_fields, +i_s_innodb_sys_foreign, +i_s_innodb_sys_foreign_cols + mysql_declare_plugin_end; /** @brief Initialize the default value of innodb_commit_concurrency. diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 31e88ed8530..8f118199ad8 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2009, MySQL AB & Innobase Oy. All Rights Reserved. +Copyright (c) 2000, 2010, MySQL AB & Innobase Oy. All Rights Reserved. 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 @@ -27,15 +27,31 @@ Place, Suite 330, Boston, MA 02111-1307 USA #pragma interface /* gcc class implementation */ #endif +/* Structure defines translation table between mysql index and innodb +index structures */ +typedef struct innodb_idx_translate_struct { + ulint index_count; /*!< number of valid index entries + in the index_mapping array */ + ulint array_size; /*!< array size of index_mapping */ + dict_index_t** index_mapping; /*!< index pointer array directly + maps to index in Innodb from MySQL + array index */ +} innodb_idx_translate_t; + + /** InnoDB table share */ typedef struct st_innobase_share { - THR_LOCK lock; /*!< MySQL lock protecting - this structure */ - const char* table_name; /*!< InnoDB table name */ - uint use_count; /*!< reference count, - incremented in get_share() - and decremented in free_share() */ - void* table_name_hash;/*!< hash table chain node */ + THR_LOCK lock; /*!< MySQL lock protecting + this structure */ + const char* table_name; /*!< InnoDB table name */ + uint use_count; /*!< reference count, + incremented in get_share() + and decremented in + free_share() */ + void* table_name_hash;/*!< hash table chain node */ + innodb_idx_translate_t idx_trans_tbl; /*!< index translation + table between MySQL and + Innodb */ } INNOBASE_SHARE; @@ -91,9 +107,8 @@ class ha_innobase: public handler ulint innobase_reset_autoinc(ulonglong auto_inc); ulint innobase_get_autoinc(ulonglong* value); ulint innobase_update_autoinc(ulonglong auto_inc); - ulint innobase_initialize_autoinc(); + void innobase_initialize_autoinc(); dict_index_t* innobase_get_index(uint keynr); - ulonglong innobase_get_int_col_max_value(const Field* field); /* Init values for the class: */ public: @@ -216,7 +231,7 @@ the definitions are bracketed with #ifdef INNODB_COMPATIBILITY_HOOKS */ extern "C" { struct charset_info_st *thd_charset(MYSQL_THD thd); -char **thd_query(MYSQL_THD thd); +LEX_STRING *thd_query_string(MYSQL_THD thd); /** Get the file name of the MySQL binlog. * @return the name of the binlog file @@ -266,6 +281,13 @@ void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all); */ bool thd_binlog_filter_ok(const MYSQL_THD thd); #endif /* MYSQL_VERSION_ID > 50140 */ +/** + Check if the query may generate row changes which + may end up in the binary. + @param thd Thread handle + @return 1 the query may generate row changes, 0 otherwise. +*/ +bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd); } typedef struct trx_struct trx_t; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 99c1d37b04c..ec17882590c 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 2005, 2010, Innobase Oy. All Rights Reserved. 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 @@ -231,9 +231,11 @@ static int innobase_check_index_keys( /*======================*/ - const KEY* key_info, /*!< in: Indexes to be created */ - ulint num_of_keys) /*!< in: Number of indexes to - be created */ + const KEY* key_info, /*!< in: Indexes to be + created */ + ulint num_of_keys, /*!< in: Number of + indexes to be created */ + const dict_table_t* table) /*!< in: Existing indexes */ { ulint key_num; @@ -250,9 +252,22 @@ innobase_check_index_keys( const KEY& key2 = key_info[i]; if (0 == strcmp(key.name, key2.name)) { - sql_print_error("InnoDB: key name `%s` appears" - " twice in CREATE INDEX\n", - key.name); + my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), + key.name); + + return(ER_WRONG_NAME_FOR_INDEX); + } + } + + /* Check that the same index name does not already exist. */ + + for (const dict_index_t* index + = dict_table_get_first_index(table); + index; index = dict_table_get_next_index(index)) { + + if (0 == strcmp(key.name, index->name)) { + my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), + key.name); return(ER_WRONG_NAME_FOR_INDEX); } @@ -260,7 +275,7 @@ innobase_check_index_keys( /* Check that MySQL does not try to create a column prefix index field on an inappropriate data type and - that the same colum does not appear twice in the index. */ + that the same column does not appear twice in the index. */ for (ulint i = 0; i < key.key_parts; i++) { const KEY_PART_INFO& key_part1 @@ -291,14 +306,8 @@ innobase_check_index_keys( } } - sql_print_error("InnoDB: MySQL is trying to" - " create a column prefix" - " index field on an" - " inappropriate data type." - " column `%s`," - " index `%s`.\n", - field->field_name, - key.name); + my_error(ER_WRONG_KEY_COLUMN, MYF(0), + field->field_name); return(ER_WRONG_KEY_COLUMN); } @@ -311,11 +320,8 @@ innobase_check_index_keys( continue; } - sql_print_error("InnoDB: column `%s`" - " is not allowed to occur" - " twice in index `%s`.\n", - key_part1.field->field_name, - key.name); + my_error(ER_WRONG_KEY_COLUMN, MYF(0), + key_part1.field->field_name); return(ER_WRONG_KEY_COLUMN); } } @@ -524,12 +530,14 @@ innobase_create_key_def( key_info->name, "PRIMARY"); /* If there is a UNIQUE INDEX consisting entirely of NOT NULL - columns, MySQL will treat it as a PRIMARY KEY unless the - table already has one. */ + columns and if the index does not contain column prefix(es) + (only prefix/part of the column is indexed), MySQL will treat the + index as a PRIMARY KEY unless the table already has one. */ if (!new_primary && (key_info->flags & HA_NOSAME) + && (!(key_info->flags & HA_KEY_HAS_PART_KEY_SEG)) && row_table_got_default_clust_index(table)) { - uint key_part = key_info->key_parts; + uint key_part = key_info->key_parts; new_primary = TRUE; @@ -658,12 +666,18 @@ ha_innobase::add_index( innodb_table = indexed_table = dict_table_get(prebuilt->table->name, FALSE); + if (UNIV_UNLIKELY(!innodb_table)) { + error = HA_ERR_NO_SUCH_TABLE; + goto err_exit; + } + /* Check if the index name is reserved. */ if (innobase_index_name_is_reserved(trx, key_info, num_of_keys)) { error = -1; } else { /* Check that index keys are sensible */ - error = innobase_check_index_keys(key_info, num_of_keys); + error = innobase_check_index_keys(key_info, num_of_keys, + innodb_table); } if (UNIV_UNLIKELY(error)) { @@ -710,6 +724,8 @@ err_exit: row_mysql_lock_data_dictionary(trx); dict_locked = TRUE; + ut_d(dict_table_check_for_dup_indexes(innodb_table, FALSE)); + /* If a new primary key is defined for the table we need to drop the original table and rebuild all indexes. */ @@ -742,6 +758,8 @@ err_exit: user_thd); } + ut_d(dict_table_check_for_dup_indexes(innodb_table, + FALSE)); row_mysql_unlock_data_dictionary(trx); goto err_exit; } @@ -766,6 +784,10 @@ err_exit: ut_ad(error == DB_SUCCESS); + /* We will need to rebuild index translation table. Set + valid index entry count in the translation table to zero */ + share->idx_trans_tbl.index_count = 0; + /* Commit the data dictionary transaction in order to release the table locks on the system tables. This means that if MySQL crashes while creating a new primary key inside @@ -801,18 +823,6 @@ err_exit: index, num_of_idx, table); error_handling: -#ifdef UNIV_DEBUG - /* TODO: At the moment we can't handle the following statement - in our debugging code below: - - alter table t drop index b, add index (b); - - The fix will have to parse the SQL and note that the index - being added has the same name as the one being dropped and - ignore that in the dup index check.*/ - //dict_table_check_for_dup_indexes(prebuilt->table); -#endif - /* After an error, remove all those index definitions from the dictionary which were defined. */ @@ -824,6 +834,8 @@ error_handling: row_mysql_lock_data_dictionary(trx); dict_locked = TRUE; + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, TRUE)); + if (!new_primary) { error = row_merge_rename_indexes(trx, indexed_table); @@ -884,6 +896,8 @@ error: prebuilt->trx->error_info = NULL; /* fall through */ default: + trx->error_state = DB_SUCCESS; + if (new_primary) { if (indexed_table != innodb_table) { row_merge_drop_table(trx, indexed_table); @@ -911,6 +925,7 @@ convert_error: } if (dict_locked) { + ut_d(dict_table_check_for_dup_indexes(innodb_table, FALSE)); row_mysql_unlock_data_dictionary(trx); } @@ -953,6 +968,7 @@ ha_innobase::prepare_drop_index( /* Test and mark all the indexes to be dropped */ row_mysql_lock_data_dictionary(trx); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); /* Check that none of the indexes have previously been flagged for deletion. */ @@ -1118,6 +1134,7 @@ func_exit: } while (index); } + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); row_mysql_unlock_data_dictionary(trx); DBUG_RETURN(err); @@ -1164,6 +1181,7 @@ ha_innobase::final_drop_index( prebuilt->table->flags, user_thd); row_mysql_lock_data_dictionary(trx); + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); if (UNIV_UNLIKELY(err)) { @@ -1200,11 +1218,12 @@ ha_innobase::final_drop_index( ut_a(!index->to_be_dropped); } -#ifdef UNIV_DEBUG - dict_table_check_for_dup_indexes(prebuilt->table); -#endif + /* We will need to rebuild index translation table. Set + valid index entry count in the translation table to zero */ + share->idx_trans_tbl.index_count = 0; func_exit: + ut_d(dict_table_check_for_dup_indexes(prebuilt->table, FALSE)); trx_commit_for_mysql(trx); trx_commit_for_mysql(prebuilt->trx); row_mysql_unlock_data_dictionary(trx); diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index fdcec7811d0..2c15a3b87db 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -36,12 +36,17 @@ Created July 18, 2007 Vasil Dimov #include <mysql/innodb_priv.h> extern "C" { -#include "trx0i_s.h" -#include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */ +#include "btr0pcur.h" /* for file sys_tables related info. */ +#include "btr0types.h" #include "buf0buddy.h" /* for i_s_cmpmem */ #include "buf0buf.h" /* for buf_pool and PAGE_ZIP_MIN_SIZE */ +#include "dict0load.h" /* for file sys_tables related info. */ +#include "dict0mem.h" +#include "dict0types.h" #include "ha_prototypes.h" /* for innobase_convert_name() */ #include "srv0start.h" /* for srv_was_started */ +#include "trx0i_s.h" +#include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */ } static const char plugin_author[] = "Innobase Oy"; @@ -131,7 +136,6 @@ int i_s_common_deinit( /*==============*/ void* p); /*!< in/out: table schema object */ - /*******************************************************************//** Auxiliary function to store time_t value in MYSQL_TYPE_DATETIME field. @@ -288,6 +292,258 @@ static ST_FIELD_INFO innodb_trx_fields_info[] = STRUCT_FLD(old_name, ""), STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, +#define IDX_TRX_OPERATION_STATE 8 + {STRUCT_FLD(field_name, "trx_operation_state"), + STRUCT_FLD(field_length, TRX_I_S_TRX_OP_STATE_MAX_LEN), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_TABLES_IN_USE 9 + {STRUCT_FLD(field_name, "trx_tables_in_use"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_TABLES_LOCKED 10 + {STRUCT_FLD(field_name, "trx_tables_locked"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_LOCK_STRUCTS 11 + {STRUCT_FLD(field_name, "trx_lock_structs"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_LOCK_MEMORY_BYTES 12 + {STRUCT_FLD(field_name, "trx_lock_memory_bytes"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_ROWS_LOCKED 13 + {STRUCT_FLD(field_name, "trx_rows_locked"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_ROWS_MODIFIED 14 + {STRUCT_FLD(field_name, "trx_rows_modified"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_CONNCURRENCY_TICKETS 15 + {STRUCT_FLD(field_name, "trx_concurrency_tickets"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_ISOLATION_LEVEL 16 + {STRUCT_FLD(field_name, "trx_isolation_level"), + STRUCT_FLD(field_length, TRX_I_S_TRX_ISOLATION_LEVEL_MAX_LEN), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_UNIQUE_CHECKS 17 + {STRUCT_FLD(field_name, "trx_unique_checks"), + STRUCT_FLD(field_length, 1), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 1), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_FOREIGN_KEY_CHECKS 18 + {STRUCT_FLD(field_name, "trx_foreign_key_checks"), + STRUCT_FLD(field_length, 1), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 1), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_LAST_FOREIGN_KEY_ERROR 19 + {STRUCT_FLD(field_name, "trx_last_foreign_key_error"), + STRUCT_FLD(field_length, TRX_I_S_TRX_FK_ERROR_MAX_LEN), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_ADAPTIVE_HASH_LATCHED 20 + {STRUCT_FLD(field_name, "trx_apative_hash_latched"), + STRUCT_FLD(field_length, 1), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_ADAPTIVE_HASH_TIMEOUT 21 + {STRUCT_FLD(field_name, "trx_adaptive_hash_timeout"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_OPERATION_STATE 8 + {STRUCT_FLD(field_name, "trx_operation_state"), + STRUCT_FLD(field_length, TRX_I_S_TRX_OP_STATE_MAX_LEN), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_TABLES_IN_USE 9 + {STRUCT_FLD(field_name, "trx_tables_in_use"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_TABLES_LOCKED 10 + {STRUCT_FLD(field_name, "trx_tables_locked"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_LOCK_STRUCTS 11 + {STRUCT_FLD(field_name, "trx_lock_structs"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_LOCK_MEMORY_BYTES 12 + {STRUCT_FLD(field_name, "trx_lock_memory_bytes"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_ROWS_LOCKED 13 + {STRUCT_FLD(field_name, "trx_rows_locked"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_ROWS_MODIFIED 14 + {STRUCT_FLD(field_name, "trx_rows_modified"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_CONNCURRENCY_TICKETS 15 + {STRUCT_FLD(field_name, "trx_concurrency_tickets"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_ISOLATION_LEVEL 16 + {STRUCT_FLD(field_name, "trx_isolation_level"), + STRUCT_FLD(field_length, TRX_I_S_TRX_ISOLATION_LEVEL_MAX_LEN), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_UNIQUE_CHECKS 17 + {STRUCT_FLD(field_name, "trx_unique_checks"), + STRUCT_FLD(field_length, 1), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 1), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_FOREIGN_KEY_CHECKS 18 + {STRUCT_FLD(field_name, "trx_foreign_key_checks"), + STRUCT_FLD(field_length, 1), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 1), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_LAST_FOREIGN_KEY_ERROR 19 + {STRUCT_FLD(field_name, "trx_last_foreign_key_error"), + STRUCT_FLD(field_length, TRX_I_S_TRX_FK_ERROR_MAX_LEN), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_MAYBE_NULL), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_ADAPTIVE_HASH_LATCHED 20 + {STRUCT_FLD(field_name, "trx_apative_hash_latched"), + STRUCT_FLD(field_length, 1), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define IDX_TRX_ADAPTIVE_HASH_TIMEOUT 21 + {STRUCT_FLD(field_name, "trx_adaptive_hash_timeout"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + END_OF_ST_FIELD_INFO }; @@ -370,6 +626,62 @@ fill_innodb_trx_from_cache( OK(field_store_string(fields[IDX_TRX_QUERY], row->trx_query)); + /* trx_operation_state */ + OK(field_store_string(fields[IDX_TRX_OPERATION_STATE], + row->trx_operation_state)); + + /* trx_tables_in_use */ + OK(fields[IDX_TRX_TABLES_IN_USE]->store( + (longlong) row->trx_tables_in_use, true)); + + /* trx_tables_locked */ + OK(fields[IDX_TRX_TABLES_LOCKED]->store( + (longlong) row->trx_tables_locked, true)); + + /* trx_lock_structs */ + OK(fields[IDX_TRX_LOCK_STRUCTS]->store( + (longlong) row->trx_lock_structs, true)); + + /* trx_lock_memory_bytes */ + OK(fields[IDX_TRX_LOCK_MEMORY_BYTES]->store( + (longlong) row->trx_lock_memory_bytes, true)); + + /* trx_rows_locked */ + OK(fields[IDX_TRX_ROWS_LOCKED]->store( + (longlong) row->trx_rows_locked, true)); + + /* trx_rows_modified */ + OK(fields[IDX_TRX_ROWS_MODIFIED]->store( + (longlong) row->trx_rows_modified, true)); + + /* trx_concurrency_tickets */ + OK(fields[IDX_TRX_CONNCURRENCY_TICKETS]->store( + (longlong) row->trx_concurrency_tickets, true)); + + /* trx_isolation_level */ + OK(field_store_string(fields[IDX_TRX_ISOLATION_LEVEL], + row->trx_isolation_level)); + + /* trx_unique_checks */ + OK(fields[IDX_TRX_UNIQUE_CHECKS]->store( + row->trx_unique_checks)); + + /* trx_foreign_key_checks */ + OK(fields[IDX_TRX_FOREIGN_KEY_CHECKS]->store( + row->trx_foreign_key_checks)); + + /* trx_last_foreign_key_error */ + OK(field_store_string(fields[IDX_TRX_LAST_FOREIGN_KEY_ERROR], + row->trx_foreign_key_error)); + + /* trx_apative_hash_latched */ + OK(fields[IDX_TRX_ADAPTIVE_HASH_LATCHED]->store( + row->trx_has_search_latch)); + + /* trx_adaptive_hash_timeout */ + OK(fields[IDX_TRX_ADAPTIVE_HASH_TIMEOUT]->store( + (longlong) row->trx_search_latch_timeout, true)); + OK(schema_table_store_record(thd, table)); } @@ -1302,6 +1614,14 @@ static ST_FIELD_INFO i_s_cmpmem_fields_info[] = STRUCT_FLD(old_name, "Buddy Block Size"), STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + {STRUCT_FLD(field_name, "buffer_pool_instance"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, "Buffer Pool Id"), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + {STRUCT_FLD(field_name, "pages_used"), STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), STRUCT_FLD(field_type, MYSQL_TYPE_LONG), @@ -1332,7 +1652,7 @@ static ST_FIELD_INFO i_s_cmpmem_fields_info[] = STRUCT_FLD(value, 0), STRUCT_FLD(field_flags, 0), STRUCT_FLD(old_name, "Total Duration of Relocations," - " in Seconds"), + " in Seconds"), STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, END_OF_ST_FIELD_INFO @@ -1351,8 +1671,8 @@ i_s_cmpmem_fill_low( COND* cond, /*!< in: condition (ignored) */ ibool reset) /*!< in: TRUE=reset cumulated counts */ { + int status = 0; TABLE* table = (TABLE *) tables->table; - int status = 0; DBUG_ENTER("i_s_cmpmem_fill_low"); @@ -1364,33 +1684,50 @@ i_s_cmpmem_fill_low( RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name); - buf_pool_mutex_enter(); + for (ulint i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; - for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) { - buf_buddy_stat_t* buddy_stat = &buf_buddy_stat[x]; + status = 0; - table->field[0]->store(BUF_BUDDY_LOW << x); - table->field[1]->store(buddy_stat->used); - table->field[2]->store(UNIV_LIKELY(x < BUF_BUDDY_SIZES) - ? UT_LIST_GET_LEN(buf_pool->zip_free[x]) - : 0); - table->field[3]->store((longlong) buddy_stat->relocated, true); - table->field[4]->store( - (ulong) (buddy_stat->relocated_usec / 1000000)); + buf_pool = buf_pool_from_array(i); - if (reset) { - /* This is protected by buf_pool_mutex. */ - buddy_stat->relocated = 0; - buddy_stat->relocated_usec = 0; + buf_pool_mutex_enter(buf_pool); + + for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) { + buf_buddy_stat_t* buddy_stat; + + buddy_stat = &buf_pool->buddy_stat[x]; + + table->field[0]->store(BUF_BUDDY_LOW << x); + table->field[1]->store(i); + table->field[2]->store(buddy_stat->used); + table->field[3]->store(UNIV_LIKELY(x < BUF_BUDDY_SIZES) + ? UT_LIST_GET_LEN(buf_pool->zip_free[x]) + : 0); + table->field[4]->store((longlong) + buddy_stat->relocated, true); + table->field[5]->store( + (ulong) (buddy_stat->relocated_usec / 1000000)); + + if (reset) { + /* This is protected by buf_pool->mutex. */ + buddy_stat->relocated = 0; + buddy_stat->relocated_usec = 0; + } + + if (schema_table_store_record(thd, table)) { + status = 1; + break; + } } - if (schema_table_store_record(thd, table)) { - status = 1; + buf_pool_mutex_exit(buf_pool); + + if (status) { break; } } - buf_pool_mutex_exit(); DBUG_RETURN(status); } @@ -1572,3 +1909,1646 @@ i_s_common_deinit( DBUG_RETURN(0); } + +/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLES */ +static ST_FIELD_INFO innodb_sys_tables_fields_info[] = +{ +#define SYS_TABLE_ID 0 + {STRUCT_FLD(field_name, "TABLE_ID"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_TABLE_NAME 1 + {STRUCT_FLD(field_name, "NAME"), + STRUCT_FLD(field_length, NAME_LEN + 1), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_TABLE_FLAG 2 + {STRUCT_FLD(field_name, "FLAG"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_TABLE_NUM_COLUMN 3 + {STRUCT_FLD(field_name, "N_COLS"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_TABLE_SPACE 4 + {STRUCT_FLD(field_name, "SPACE"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + + END_OF_ST_FIELD_INFO +}; + +/**********************************************************************//** +Populate information_schema.innodb_sys_tables table with information +from SYS_TABLES. +@return 0 on success */ +static +int +i_s_dict_fill_sys_tables( +/*=====================*/ + THD* thd, /*!< in: thread */ + dict_table_t* table, /*!< in: table */ + TABLE* table_to_fill) /*!< in/out: fill this table */ +{ + longlong table_id; + Field** fields; + + DBUG_ENTER("i_s_dict_fill_sys_tables"); + + fields = table_to_fill->field; + + table_id = ut_conv_dulint_to_longlong(table->id); + + OK(fields[SYS_TABLE_ID]->store(table_id, TRUE)); + + OK(field_store_string(fields[SYS_TABLE_NAME], table->name)); + + OK(fields[SYS_TABLE_FLAG]->store(table->flags)); + + OK(fields[SYS_TABLE_NUM_COLUMN]->store(table->n_cols)); + + OK(fields[SYS_TABLE_SPACE]->store(table->space)); + + OK(schema_table_store_record(thd, table_to_fill)); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Function to go through each record in SYS_TABLES table, and fill the +information_schema.innodb_sys_tables table with related table information +@return 0 on success */ +static +int +i_s_sys_tables_fill_table( +/*======================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + COND* cond) /*!< in: condition (not used) */ +{ + btr_pcur_t pcur; + const rec_t* rec; + mem_heap_t* heap; + mtr_t mtr; + + DBUG_ENTER("i_s_sys_tables_fill_table"); + + /* deny access to non-superusers */ + if (check_global_access(thd, PROCESS_ACL)) { + + DBUG_RETURN(0); + } + + heap = mem_heap_create(1000); + mutex_enter(&(dict_sys->mutex)); + mtr_start(&mtr); + + rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES); + + while (rec) { + const char* err_msg; + dict_table_t* table_rec; + + /* Create and populate a dict_table_t structure with + information from SYS_TABLES row */ + err_msg = dict_process_sys_tables_rec( + heap, rec, &table_rec, DICT_TABLE_LOAD_FROM_RECORD); + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + + if (!err_msg) { + i_s_dict_fill_sys_tables(thd, table_rec, tables->table); + } else { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CANT_FIND_SYSTEM_REC, + err_msg); + } + + /* Since dict_process_sys_tables_rec() is called with + DICT_TABLE_LOAD_FROM_RECORD, the table_rec is created in + dict_process_sys_tables_rec(), we will need to free it */ + if (table_rec) { + dict_mem_table_free(table_rec); + } + + mem_heap_empty(heap); + + /* Get the next record */ + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + rec = dict_getnext_system(&pcur, &mtr); + } + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + mem_heap_free(heap); + + DBUG_RETURN(0); +} + +/*******************************************************************//** +Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_tables +@return 0 on success */ +static +int +innodb_sys_tables_init( +/*===================*/ + void* p) /*!< in/out: table schema object */ +{ + ST_SCHEMA_TABLE* schema; + + DBUG_ENTER("innodb_sys_tables_init"); + + schema = (ST_SCHEMA_TABLE*) p; + + schema->fields_info = innodb_sys_tables_fields_info; + schema->fill_table = i_s_sys_tables_fill_table; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_tables = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_SYS_TABLES"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, plugin_author), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB SYS_TABLES"), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, innodb_sys_tables_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, INNODB_VERSION_SHORT), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + /* reserved for dependency checking */ + /* void* */ + STRUCT_FLD(__reserved1, NULL) +}; + +/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_TABLESTATS */ +static ST_FIELD_INFO innodb_sys_tablestats_fields_info[] = +{ +#define SYS_TABLESTATS_ID 0 + {STRUCT_FLD(field_name, "TABLE_ID"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_TABLESTATS_NAME 1 + {STRUCT_FLD(field_name, "NAME"), + STRUCT_FLD(field_length, NAME_LEN + 1), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_TABLESTATS_INIT 2 + {STRUCT_FLD(field_name, "STATS_INITIALIZED"), + STRUCT_FLD(field_length, NAME_LEN + 1), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_TABLESTATS_NROW 3 + {STRUCT_FLD(field_name, "NUM_ROWS"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_TABLESTATS_CLUST_SIZE 4 + {STRUCT_FLD(field_name, "CLUST_INDEX_SIZE"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_TABLESTATS_INDEX_SIZE 5 + {STRUCT_FLD(field_name, "OTHER_INDEX_SIZE"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_TABLESTATS_MODIFIED 6 + {STRUCT_FLD(field_name, "MODIFIED_COUNTER"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_TABLESTATS_AUTONINC 7 + {STRUCT_FLD(field_name, "AUTOINC"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_TABLESTATS_MYSQL_OPEN_HANDLE 8 + {STRUCT_FLD(field_name, "MYSQL_HANDLES_OPENED"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + + END_OF_ST_FIELD_INFO +}; + +/**********************************************************************//** +Populate information_schema.innodb_sys_tablestats table with information +from SYS_TABLES. +@return 0 on success */ +static +int +i_s_dict_fill_sys_tablestats( +/*=========================*/ + THD* thd, /*!< in: thread */ + dict_table_t* table, /*!< in: table */ + TABLE* table_to_fill) /*!< in/out: fill this table */ +{ + longlong table_id; + Field** fields; + + DBUG_ENTER("i_s_dict_fill_sys_tablestats"); + + fields = table_to_fill->field; + + table_id = ut_conv_dulint_to_longlong(table->id); + + OK(fields[SYS_TABLESTATS_ID]->store(table_id, TRUE)); + + OK(field_store_string(fields[SYS_TABLESTATS_NAME], table->name)); + + if (table->stat_initialized) { + OK(field_store_string(fields[SYS_TABLESTATS_INIT], + "Initialized")); + } else { + OK(field_store_string(fields[SYS_TABLESTATS_INIT], + "Uninitialized")); + } + + OK(fields[SYS_TABLESTATS_NROW]->store(table->stat_n_rows, TRUE)); + + OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store( + table->stat_clustered_index_size)); + + OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store( + table->stat_sum_of_other_index_sizes)); + + OK(fields[SYS_TABLESTATS_MODIFIED]->store( + table->stat_modified_counter)); + + OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc, TRUE)); + + OK(fields[SYS_TABLESTATS_MYSQL_OPEN_HANDLE]->store( + table->n_mysql_handles_opened)); + + OK(schema_table_store_record(thd, table_to_fill)); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Function to go through each record in SYS_TABLES table, and fill the +information_schema.innodb_sys_tablestats table with table statistics +related information +@return 0 on success */ +static +int +i_s_sys_tables_fill_table_stats( +/*============================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + COND* cond) /*!< in: condition (not used) */ +{ + btr_pcur_t pcur; + const rec_t* rec; + mem_heap_t* heap; + mtr_t mtr; + + DBUG_ENTER("i_s_sys_tables_fill_table_stats"); + + /* deny access to non-superusers */ + if (check_global_access(thd, PROCESS_ACL)) { + + DBUG_RETURN(0); + } + + heap = mem_heap_create(1000); + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + + rec = dict_startscan_system(&pcur, &mtr, SYS_TABLES); + + while (rec) { + const char* err_msg; + dict_table_t* table_rec; + + /* Fetch the dict_table_t structure corresponding to + this SYS_TABLES record */ + err_msg = dict_process_sys_tables_rec( + heap, rec, &table_rec, DICT_TABLE_LOAD_FROM_CACHE); + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + + if (!err_msg) { + i_s_dict_fill_sys_tablestats(thd, table_rec, + tables->table); + } else { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CANT_FIND_SYSTEM_REC, + err_msg); + } + + mem_heap_empty(heap); + + /* Get the next record */ + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + rec = dict_getnext_system(&pcur, &mtr); + } + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + mem_heap_free(heap); + + DBUG_RETURN(0); +} + +/*******************************************************************//** +Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_tablestats +@return 0 on success */ +static +int +innodb_sys_tablestats_init( +/*=======================*/ + void* p) /*!< in/out: table schema object */ +{ + ST_SCHEMA_TABLE* schema; + + DBUG_ENTER("innodb_sys_tablestats_init"); + + schema = (ST_SCHEMA_TABLE*) p; + + schema->fields_info = innodb_sys_tablestats_fields_info; + schema->fill_table = i_s_sys_tables_fill_table_stats; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_tablestats = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_SYS_TABLESTATS"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, plugin_author), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB SYS_TABLESTATS"), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, innodb_sys_tablestats_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, INNODB_VERSION_SHORT), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + /* reserved for dependency checking */ + /* void* */ + STRUCT_FLD(__reserved1, NULL) +}; + +/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_INDEXES */ +static ST_FIELD_INFO innodb_sysindex_fields_info[] = +{ +#define SYS_INDEX_ID 0 + {STRUCT_FLD(field_name, "INDEX_ID"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_INDEX_NAME 1 + {STRUCT_FLD(field_name, "NAME"), + STRUCT_FLD(field_length, NAME_LEN + 1), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_INDEX_TABLE_ID 2 + {STRUCT_FLD(field_name, "TABLE_ID"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_INDEX_TYPE 3 + {STRUCT_FLD(field_name, "TYPE"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_INDEX_NUM_FIELDS 4 + {STRUCT_FLD(field_name, "N_FIELDS"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_INDEX_PAGE_NO 5 + {STRUCT_FLD(field_name, "PAGE_NO"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_INDEX_SPACE 6 + {STRUCT_FLD(field_name, "SPACE"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + + END_OF_ST_FIELD_INFO +}; + +/**********************************************************************//** +Function to populate the information_schema.innodb_sys_indexes table with +collected index information +@return 0 on success */ +static +int +i_s_dict_fill_sys_indexes( +/*======================*/ + THD* thd, /*!< in: thread */ + dulint tableid, /*!< in: table id */ + dict_index_t* index, /*!< in: populated dict_index_t + struct with index info */ + TABLE* table_to_fill) /*!< in/out: fill this table */ +{ + longlong table_id; + longlong index_id; + Field** fields; + + DBUG_ENTER("i_s_dict_fill_sys_indexes"); + + fields = table_to_fill->field; + + table_id = ut_conv_dulint_to_longlong(tableid); + index_id = ut_conv_dulint_to_longlong(index->id); + + OK(fields[SYS_INDEX_ID]->store(index_id, TRUE)); + + OK(field_store_string(fields[SYS_INDEX_NAME], index->name)); + + OK(fields[SYS_INDEX_TABLE_ID]->store(table_id, TRUE)); + + OK(fields[SYS_INDEX_TYPE]->store(index->type)); + + OK(fields[SYS_INDEX_NUM_FIELDS]->store(index->n_fields)); + + OK(fields[SYS_INDEX_PAGE_NO]->store(index->page)); + + OK(fields[SYS_INDEX_SPACE]->store(index->space)); + + OK(schema_table_store_record(thd, table_to_fill)); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Function to go through each record in SYS_INDEXES table, and fill the +information_schema.innodb_sys_indexes table with related index information +@return 0 on success */ +static +int +i_s_sys_indexes_fill_table( +/*=======================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + COND* cond) /*!< in: condition (not used) */ +{ + btr_pcur_t pcur; + const rec_t* rec; + mem_heap_t* heap; + mtr_t mtr; + + DBUG_ENTER("i_s_sys_indexes_fill_table"); + + /* deny access to non-superusers */ + if (check_global_access(thd, PROCESS_ACL)) { + + DBUG_RETURN(0); + } + + heap = mem_heap_create(1000); + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + + /* Start scan the SYS_INDEXES table */ + rec = dict_startscan_system(&pcur, &mtr, SYS_INDEXES); + + /* Process each record in the table */ + while (rec) { + const char* err_msg;; + dulint table_id; + dict_index_t index_rec; + + /* Populate a dict_index_t structure with information from + a SYS_INDEXES row */ + err_msg = dict_process_sys_indexes_rec(heap, rec, &index_rec, + &table_id); + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + + if (!err_msg) { + i_s_dict_fill_sys_indexes(thd, table_id, &index_rec, + tables->table); + } else { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CANT_FIND_SYSTEM_REC, + err_msg); + } + + mem_heap_empty(heap); + + /* Get the next record */ + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + rec = dict_getnext_system(&pcur, &mtr); + } + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + mem_heap_free(heap); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_indexes +@return 0 on success */ +static +int +innodb_sys_indexes_init( +/*====================*/ + void* p) /*!< in/out: table schema object */ +{ + ST_SCHEMA_TABLE* schema; + + DBUG_ENTER("innodb_sys_index_init"); + + schema = (ST_SCHEMA_TABLE*) p; + + schema->fields_info = innodb_sysindex_fields_info; + schema->fill_table = i_s_sys_indexes_fill_table; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_indexes = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_SYS_INDEXES"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, plugin_author), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB SYS_INDEXES"), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, innodb_sys_indexes_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, INNODB_VERSION_SHORT), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + /* reserved for dependency checking */ + /* void* */ + STRUCT_FLD(__reserved1, NULL) +}; + +/* Fields of the dynamic table INFORMATION_SCHEMA.SYS_COLUMNS */ +static ST_FIELD_INFO innodb_sys_columns_fields_info[] = +{ +#define SYS_COLUMN_TABLE_ID 0 + {STRUCT_FLD(field_name, "TABLE_ID"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_COLUMN_NAME 1 + {STRUCT_FLD(field_name, "NAME"), + STRUCT_FLD(field_length, NAME_LEN + 1), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_COLUMN_POSITION 2 + {STRUCT_FLD(field_name, "POS"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_COLUMN_MTYPE 3 + {STRUCT_FLD(field_name, "MTYPE"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_COLUMN__PRTYPE 4 + {STRUCT_FLD(field_name, "PRTYPE"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_COLUMN_COLUMN_LEN 5 + {STRUCT_FLD(field_name, "LEN"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + + END_OF_ST_FIELD_INFO +}; + +/**********************************************************************//** +Function to populate the information_schema.innodb_sys_columns with +related column information +@return 0 on success */ +static +int +i_s_dict_fill_sys_columns( +/*======================*/ + THD* thd, /*!< in: thread */ + dulint tableid, /*!< in: table ID */ + const char* col_name, /*!< in: column name */ + dict_col_t* column, /*!< in: dict_col_t struct holding + more column information */ + TABLE* table_to_fill) /*!< in/out: fill this table */ +{ + longlong table_id; + Field** fields; + + DBUG_ENTER("i_s_dict_fill_sys_columns"); + + fields = table_to_fill->field; + + table_id = ut_conv_dulint_to_longlong(tableid); + + OK(fields[SYS_COLUMN_TABLE_ID]->store(table_id, TRUE)); + + OK(field_store_string(fields[SYS_COLUMN_NAME], col_name)); + + OK(fields[SYS_COLUMN_POSITION]->store(column->ind)); + + OK(fields[SYS_COLUMN_MTYPE]->store(column->mtype)); + + OK(fields[SYS_COLUMN__PRTYPE]->store(column->prtype)); + + OK(fields[SYS_COLUMN_COLUMN_LEN]->store(column->len)); + + OK(schema_table_store_record(thd, table_to_fill)); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Function to fill information_schema.innodb_sys_columns with information +collected by scanning SYS_COLUMNS table. +@return 0 on success */ +static +int +i_s_sys_columns_fill_table( +/*=======================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + COND* cond) /*!< in: condition (not used) */ +{ + btr_pcur_t pcur; + const rec_t* rec; + const char* col_name; + mem_heap_t* heap; + mtr_t mtr; + + DBUG_ENTER("i_s_sys_columns_fill_table"); + + /* deny access to non-superusers */ + if (check_global_access(thd, PROCESS_ACL)) { + + DBUG_RETURN(0); + } + + heap = mem_heap_create(1000); + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + + rec = dict_startscan_system(&pcur, &mtr, SYS_COLUMNS); + + while (rec) { + const char* err_msg; + dict_col_t column_rec; + dulint table_id; + + /* populate a dict_col_t structure with information from + a SYS_COLUMNS row */ + err_msg = dict_process_sys_columns_rec(heap, rec, &column_rec, + &table_id, &col_name); + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + + if (!err_msg) { + i_s_dict_fill_sys_columns(thd, table_id, col_name, + &column_rec, + tables->table); + } else { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CANT_FIND_SYSTEM_REC, + err_msg); + } + + mem_heap_empty(heap); + + /* Get the next record */ + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + rec = dict_getnext_system(&pcur, &mtr); + } + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + mem_heap_free(heap); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_columns +@return 0 on success */ +static +int +innodb_sys_columns_init( +/*====================*/ + void* p) /*!< in/out: table schema object */ +{ + ST_SCHEMA_TABLE* schema; + + DBUG_ENTER("innodb_sys_columns_init"); + + schema = (ST_SCHEMA_TABLE*) p; + + schema->fields_info = innodb_sys_columns_fields_info; + schema->fill_table = i_s_sys_columns_fill_table; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_columns = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_SYS_COLUMNS"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, plugin_author), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB SYS_COLUMNS"), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, innodb_sys_columns_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, INNODB_VERSION_SHORT), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + /* reserved for dependency checking */ + /* void* */ + STRUCT_FLD(__reserved1, NULL) +}; +/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_fields */ +static ST_FIELD_INFO innodb_sys_fields_fields_info[] = +{ +#define SYS_FIELD_INDEX_ID 0 + {STRUCT_FLD(field_name, "INDEX_ID"), + STRUCT_FLD(field_length, MY_INT64_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONGLONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_FIELD_NAME 1 + {STRUCT_FLD(field_name, "NAME"), + STRUCT_FLD(field_length, NAME_LEN + 1), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_FIELD_POS 2 + {STRUCT_FLD(field_name, "POS"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + + END_OF_ST_FIELD_INFO +}; + +/**********************************************************************//** +Function to fill information_schema.innodb_sys_fields with information +collected by scanning SYS_FIELDS table. +@return 0 on success */ +static +int +i_s_dict_fill_sys_fields( +/*=====================*/ + THD* thd, /*!< in: thread */ + dulint indexid, /*!< in: index id for the field */ + dict_field_t* field, /*!< in: table */ + ulint pos, /*!< in: Field position */ + TABLE* table_to_fill) /*!< in/out: fill this table */ +{ + longlong index_id; + Field** fields; + + DBUG_ENTER("i_s_dict_fill_sys_fields"); + + fields = table_to_fill->field; + + index_id = ut_conv_dulint_to_longlong(indexid); + + OK(fields[SYS_FIELD_INDEX_ID]->store(index_id, TRUE)); + + OK(field_store_string(fields[SYS_FIELD_NAME], field->name)); + + OK(fields[SYS_FIELD_POS]->store(pos)); + + OK(schema_table_store_record(thd, table_to_fill)); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Function to go through each record in SYS_FIELDS table, and fill the +information_schema.innodb_sys_fields table with related index field +information +@return 0 on success */ +static +int +i_s_sys_fields_fill_table( +/*======================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + COND* cond) /*!< in: condition (not used) */ +{ + btr_pcur_t pcur; + const rec_t* rec; + mem_heap_t* heap; + dulint last_id; + mtr_t mtr; + + DBUG_ENTER("i_s_sys_fields_fill_table"); + + /* deny access to non-superusers */ + if (check_global_access(thd, PROCESS_ACL)) { + + DBUG_RETURN(0); + } + + heap = mem_heap_create(1000); + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + + /* will save last index id so that we know whether we move to + the next index. This is used to calculate prefix length */ + last_id = ut_dulint_create(0, 0); + + rec = dict_startscan_system(&pcur, &mtr, SYS_FIELDS); + + while (rec) { + ulint pos; + const char* err_msg; + dulint index_id; + dict_field_t field_rec; + + /* Populate a dict_field_t structure with information from + a SYS_FIELDS row */ + err_msg = dict_process_sys_fields_rec(heap, rec, &field_rec, + &pos, &index_id, last_id); + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + + if (!err_msg) { + i_s_dict_fill_sys_fields(thd, index_id, &field_rec, + pos, tables->table); + last_id = index_id; + } else { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CANT_FIND_SYSTEM_REC, + err_msg); + } + + mem_heap_empty(heap); + + /* Get the next record */ + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + rec = dict_getnext_system(&pcur, &mtr); + } + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + mem_heap_free(heap); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_fields +@return 0 on success */ +static +int +innodb_sys_fields_init( +/*===================*/ + void* p) /*!< in/out: table schema object */ +{ + ST_SCHEMA_TABLE* schema; + + DBUG_ENTER("innodb_sys_field_init"); + + schema = (ST_SCHEMA_TABLE*) p; + + schema->fields_info = innodb_sys_fields_fields_info; + schema->fill_table = i_s_sys_fields_fill_table; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_fields = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_SYS_FIELDS"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, plugin_author), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB SYS_FIELDS"), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, innodb_sys_fields_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, INNODB_VERSION_SHORT), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + /* reserved for dependency checking */ + /* void* */ + STRUCT_FLD(__reserved1, NULL) +}; + +/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign */ +static ST_FIELD_INFO innodb_sys_foreign_fields_info[] = +{ +#define SYS_FOREIGN_ID 0 + {STRUCT_FLD(field_name, "ID"), + STRUCT_FLD(field_length, NAME_LEN + 1), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_FOREIGN_FOR_NAME 1 + {STRUCT_FLD(field_name, "FOR_NAME"), + STRUCT_FLD(field_length, NAME_LEN + 1), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_FOREIGN_REF_NAME 2 + {STRUCT_FLD(field_name, "REF_NAME"), + STRUCT_FLD(field_length, NAME_LEN + 1), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_FOREIGN_NUM_COL 3 + {STRUCT_FLD(field_name, "N_COLS"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_FOREIGN_TYPE 4 + {STRUCT_FLD(field_name, "TYPE"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + + END_OF_ST_FIELD_INFO +}; + +/**********************************************************************//** +Function to fill information_schema.innodb_sys_foreign with information +collected by scanning SYS_FOREIGN table. +@return 0 on success */ +static +int +i_s_dict_fill_sys_foreign( +/*======================*/ + THD* thd, /*!< in: thread */ + dict_foreign_t* foreign, /*!< in: table */ + TABLE* table_to_fill) /*!< in/out: fill this table */ +{ + Field** fields; + + DBUG_ENTER("i_s_dict_fill_sys_foreign"); + + fields = table_to_fill->field; + + OK(field_store_string(fields[SYS_FOREIGN_ID], foreign->id)); + + OK(field_store_string(fields[SYS_FOREIGN_FOR_NAME], + foreign->foreign_table_name)); + + OK(field_store_string(fields[SYS_FOREIGN_REF_NAME], + foreign->referenced_table_name)); + + OK(fields[SYS_FOREIGN_NUM_COL]->store(foreign->n_fields)); + + OK(fields[SYS_FOREIGN_TYPE]->store(foreign->type)); + + OK(schema_table_store_record(thd, table_to_fill)); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Function to populate INFORMATION_SCHEMA.innodb_sys_foreign table. Loop +through each record in SYS_FOREIGN, and extract the foreign key +information. +@return 0 on success */ +static +int +i_s_sys_foreign_fill_table( +/*=======================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + COND* cond) /*!< in: condition (not used) */ +{ + btr_pcur_t pcur; + const rec_t* rec; + mem_heap_t* heap; + mtr_t mtr; + + DBUG_ENTER("i_s_sys_foreign_fill_table"); + + /* deny access to non-superusers */ + if (check_global_access(thd, PROCESS_ACL)) { + + DBUG_RETURN(0); + } + + heap = mem_heap_create(1000); + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + + rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN); + + while (rec) { + const char* err_msg; + dict_foreign_t foreign_rec; + + /* Populate a dict_foreign_t structure with information from + a SYS_FOREIGN row */ + err_msg = dict_process_sys_foreign_rec(heap, rec, &foreign_rec); + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + + if (!err_msg) { + i_s_dict_fill_sys_foreign(thd, &foreign_rec, + tables->table); + } else { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CANT_FIND_SYSTEM_REC, + err_msg); + } + + mem_heap_empty(heap); + + /* Get the next record */ + mtr_start(&mtr); + mutex_enter(&dict_sys->mutex); + rec = dict_getnext_system(&pcur, &mtr); + } + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + mem_heap_free(heap); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign +@return 0 on success */ +static +int +innodb_sys_foreign_init( +/*====================*/ + void* p) /*!< in/out: table schema object */ +{ + ST_SCHEMA_TABLE* schema; + + DBUG_ENTER("innodb_sys_foreign_init"); + + schema = (ST_SCHEMA_TABLE*) p; + + schema->fields_info = innodb_sys_foreign_fields_info; + schema->fill_table = i_s_sys_foreign_fill_table; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_foreign = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_SYS_FOREIGN"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, plugin_author), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB SYS_FOREIGN"), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, innodb_sys_foreign_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, INNODB_VERSION_SHORT), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + /* reserved for dependency checking */ + /* void* */ + STRUCT_FLD(__reserved1, NULL) +}; +/* Fields of the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign_cols */ +static ST_FIELD_INFO innodb_sys_foreign_cols_fields_info[] = +{ +#define SYS_FOREIGN_COL_ID 0 + {STRUCT_FLD(field_name, "ID"), + STRUCT_FLD(field_length, NAME_LEN + 1), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_FOREIGN_COL_FOR_NAME 1 + {STRUCT_FLD(field_name, "FOR_COL_NAME"), + STRUCT_FLD(field_length, NAME_LEN + 1), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_FOREIGN_COL_REF_NAME 2 + {STRUCT_FLD(field_name, "REF_COL_NAME"), + STRUCT_FLD(field_length, NAME_LEN + 1), + STRUCT_FLD(field_type, MYSQL_TYPE_STRING), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, 0), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + +#define SYS_FOREIGN_COL_POS 3 + {STRUCT_FLD(field_name, "POS"), + STRUCT_FLD(field_length, MY_INT32_NUM_DECIMAL_DIGITS), + STRUCT_FLD(field_type, MYSQL_TYPE_LONG), + STRUCT_FLD(value, 0), + STRUCT_FLD(field_flags, MY_I_S_UNSIGNED), + STRUCT_FLD(old_name, ""), + STRUCT_FLD(open_method, SKIP_OPEN_TABLE)}, + + END_OF_ST_FIELD_INFO +}; + +/**********************************************************************//** +Function to fill information_schema.innodb_sys_foreign_cols with information +collected by scanning SYS_FOREIGN_COLS table. +@return 0 on success */ +static +int +i_s_dict_fill_sys_foreign_cols( +/*==========================*/ + THD* thd, /*!< in: thread */ + const char* name, /*!< in: foreign key constraint name */ + const char* for_col_name, /*!< in: referencing column name*/ + const char* ref_col_name, /*!< in: referenced column + name */ + ulint pos, /*!< in: column position */ + TABLE* table_to_fill) /*!< in/out: fill this table */ +{ + Field** fields; + + DBUG_ENTER("i_s_dict_fill_sys_foreign_cols"); + + fields = table_to_fill->field; + + OK(field_store_string(fields[SYS_FOREIGN_COL_ID], name)); + + OK(field_store_string(fields[SYS_FOREIGN_COL_FOR_NAME], for_col_name)); + + OK(field_store_string(fields[SYS_FOREIGN_COL_REF_NAME], ref_col_name)); + + OK(fields[SYS_FOREIGN_COL_POS]->store(pos)); + + OK(schema_table_store_record(thd, table_to_fill)); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Function to populate INFORMATION_SCHEMA.innodb_sys_foreign_cols table. Loop +through each record in SYS_FOREIGN_COLS, and extract the foreign key column +information and fill the INFORMATION_SCHEMA.innodb_sys_foreign_cols table. +@return 0 on success */ +static +int +i_s_sys_foreign_cols_fill_table( +/*============================*/ + THD* thd, /*!< in: thread */ + TABLE_LIST* tables, /*!< in/out: tables to fill */ + COND* cond) /*!< in: condition (not used) */ +{ + btr_pcur_t pcur; + const rec_t* rec; + mem_heap_t* heap; + mtr_t mtr; + + DBUG_ENTER("i_s_sys_foreign_cols_fill_table"); + + /* deny access to non-superusers */ + if (check_global_access(thd, PROCESS_ACL)) { + DBUG_RETURN(0); + } + + heap = mem_heap_create(1000); + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + + rec = dict_startscan_system(&pcur, &mtr, SYS_FOREIGN_COLS); + + while (rec) { + const char* err_msg; + const char* name; + const char* for_col_name; + const char* ref_col_name; + ulint pos; + + /* Extract necessary information from a SYS_FOREIGN_COLS row */ + err_msg = dict_process_sys_foreign_col_rec( + heap, rec, &name, &for_col_name, &ref_col_name, &pos); + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + + if (!err_msg) { + i_s_dict_fill_sys_foreign_cols( + thd, name, for_col_name, ref_col_name, pos, + tables->table); + } else { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_CANT_FIND_SYSTEM_REC, + err_msg); + } + + mem_heap_empty(heap); + + /* Get the next record */ + mutex_enter(&dict_sys->mutex); + mtr_start(&mtr); + rec = dict_getnext_system(&pcur, &mtr); + } + + mtr_commit(&mtr); + mutex_exit(&dict_sys->mutex); + mem_heap_free(heap); + + DBUG_RETURN(0); +} +/*******************************************************************//** +Bind the dynamic table INFORMATION_SCHEMA.innodb_sys_foreign_cols +@return 0 on success */ +static +int +innodb_sys_foreign_cols_init( +/*========================*/ + void* p) /*!< in/out: table schema object */ +{ + ST_SCHEMA_TABLE* schema; + + DBUG_ENTER("innodb_sys_foreign_cols_init"); + + schema = (ST_SCHEMA_TABLE*) p; + + schema->fields_info = innodb_sys_foreign_cols_fields_info; + schema->fill_table = i_s_sys_foreign_cols_fill_table; + + DBUG_RETURN(0); +} + +UNIV_INTERN struct st_mysql_plugin i_s_innodb_sys_foreign_cols = +{ + /* the plugin type (a MYSQL_XXX_PLUGIN value) */ + /* int */ + STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN), + + /* pointer to type-specific plugin descriptor */ + /* void* */ + STRUCT_FLD(info, &i_s_info), + + /* plugin name */ + /* const char* */ + STRUCT_FLD(name, "INNODB_SYS_FOREIGN_COLS"), + + /* plugin author (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(author, plugin_author), + + /* general descriptive text (for SHOW PLUGINS) */ + /* const char* */ + STRUCT_FLD(descr, "InnoDB SYS_FOREIGN_COLS"), + + /* the plugin license (PLUGIN_LICENSE_XXX) */ + /* int */ + STRUCT_FLD(license, PLUGIN_LICENSE_GPL), + + /* the function to invoke when plugin is loaded */ + /* int (*)(void*); */ + STRUCT_FLD(init, innodb_sys_foreign_cols_init), + + /* the function to invoke when plugin is unloaded */ + /* int (*)(void*); */ + STRUCT_FLD(deinit, i_s_common_deinit), + + /* plugin version (for SHOW PLUGINS) */ + /* unsigned int */ + STRUCT_FLD(version, INNODB_VERSION_SHORT), + + /* struct st_mysql_show_var* */ + STRUCT_FLD(status_vars, NULL), + + /* struct st_mysql_sys_var** */ + STRUCT_FLD(system_vars, NULL), + + /* reserved for dependency checking */ + /* void* */ + STRUCT_FLD(__reserved1, NULL) +}; + diff --git a/storage/innobase/handler/i_s.h b/storage/innobase/handler/i_s.h index 402c88bbedb..69f5ed9dad8 100644 --- a/storage/innobase/handler/i_s.h +++ b/storage/innobase/handler/i_s.h @@ -33,5 +33,12 @@ extern struct st_mysql_plugin i_s_innodb_cmp; extern struct st_mysql_plugin i_s_innodb_cmp_reset; extern struct st_mysql_plugin i_s_innodb_cmpmem; extern struct st_mysql_plugin i_s_innodb_cmpmem_reset; +extern struct st_mysql_plugin i_s_innodb_sys_tables; +extern struct st_mysql_plugin i_s_innodb_sys_tablestats; +extern struct st_mysql_plugin i_s_innodb_sys_indexes; +extern struct st_mysql_plugin i_s_innodb_sys_columns; +extern struct st_mysql_plugin i_s_innodb_sys_fields; +extern struct st_mysql_plugin i_s_innodb_sys_foreign; +extern struct st_mysql_plugin i_s_innodb_sys_foreign_cols; #endif /* i_s_h */ diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 08986fac0ef..0397af88ff4 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved. 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 @@ -89,7 +89,28 @@ is in the compact format. The presence of this marker can be detected by looking at the length of the field modulo DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE. The high-order bit of the character set field in the type info is the -"nullable" flag for the field. */ +"nullable" flag for the field. + +In versions >= 5.5: + +The optional marker byte at the start of the fourth field is replaced by +mandatory 3 fields, totaling 4 bytes: + + 1. 2 bytes: Counter field, used to sort records within a (space id, page + no) in the order they were added. This is needed so that for example the + sequence of operations "INSERT x, DEL MARK x, INSERT x" is handled + correctly. + + 2. 1 byte: Operation type (see ibuf_op_t). + + 3. 1 byte: Flags. Currently only one flag exists, IBUF_REC_COMPACT. + +To ensure older records, which do not have counters to enforce correct +sorting, are merged before any new records, ibuf_insert checks if we're +trying to insert to a position that contains old-style records, and if so, +refuses the insert. Thus, ibuf pages are gradually converted to the new +format as their corresponding buffer pool pages are read into memory. +*/ /* PREVENTING DEADLOCKS IN THE INSERT BUFFER SYSTEM @@ -168,7 +189,7 @@ access order rules. */ #define IBUF_TABLE_NAME "SYS_IBUF_TABLE" /** Operations that can currently be buffered. */ -UNIV_INTERN ibuf_use_t ibuf_use = IBUF_USE_INSERT; +UNIV_INTERN ibuf_use_t ibuf_use = IBUF_USE_ALL; /** The insert buffer control structure */ UNIV_INTERN ibuf_t* ibuf = NULL; @@ -176,6 +197,12 @@ UNIV_INTERN ibuf_t* ibuf = NULL; /** Counter for ibuf_should_try() */ UNIV_INTERN ulint ibuf_flush_count = 0; +#ifdef UNIV_PFS_MUTEX +UNIV_INTERN mysql_pfs_key_t ibuf_pessimistic_insert_mutex_key; +UNIV_INTERN mysql_pfs_key_t ibuf_mutex_key; +UNIV_INTERN mysql_pfs_key_t ibuf_bitmap_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + #ifdef UNIV_IBUF_COUNT_DEBUG /** Number of tablespaces in the ibuf_counts array */ #define IBUF_COUNT_N_SPACES 4 @@ -221,6 +248,32 @@ ibuf_count_check( list of the ibuf */ /* @} */ +/* Various constants for checking the type of an ibuf record and extracting +data from it. For details, see the description of the record format at the +top of this file. */ + +/** @name Format of the fourth column of an insert buffer record +The fourth column in the MySQL 5.5 format contains an operation +type, counter, and some flags. */ +/* @{ */ +#define IBUF_REC_INFO_SIZE 4 /*!< Combined size of info fields at + the beginning of the fourth field */ +#if IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE +# error "IBUF_REC_INFO_SIZE >= DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE" +#endif + +/* Offsets for the fields at the beginning of the fourth field */ +#define IBUF_REC_OFFSET_COUNTER 0 /*!< Operation counter */ +#define IBUF_REC_OFFSET_TYPE 2 /*!< Type of operation */ +#define IBUF_REC_OFFSET_FLAGS 3 /*!< Additional flags */ + +/* Record flag masks */ +#define IBUF_REC_COMPACT 0x1 /*!< Set in + IBUF_REC_OFFSET_FLAGS if the + user index is in COMPACT + format or later */ + + /** The mutex used to block pessimistic inserts to ibuf trees */ static mutex_t ibuf_pessimistic_insert_mutex; @@ -461,12 +514,15 @@ ibuf_init_at_db_start(void) ibuf->max_size = buf_pool_get_curr_size() / UNIV_PAGE_SIZE / IBUF_POOL_SIZE_PER_MAX_SIZE; - mutex_create(&ibuf_pessimistic_insert_mutex, + mutex_create(ibuf_pessimistic_insert_mutex_key, + &ibuf_pessimistic_insert_mutex, SYNC_IBUF_PESS_INSERT_MUTEX); - mutex_create(&ibuf_mutex, SYNC_IBUF_MUTEX); + mutex_create(ibuf_mutex_key, + &ibuf_mutex, SYNC_IBUF_MUTEX); - mutex_create(&ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX); + mutex_create(ibuf_bitmap_mutex_key, + &ibuf_bitmap_mutex, SYNC_IBUF_BITMAP_MUTEX); mtr_start(&mtr); @@ -730,24 +786,41 @@ page containing the descriptor bits for the file page; the bitmap page is x-latched */ static page_t* -ibuf_bitmap_get_map_page( -/*=====================*/ - ulint space, /*!< in: space id of the file page */ - ulint page_no,/*!< in: page number of the file page */ - ulint zip_size,/*!< in: compressed page size in bytes; - 0 for uncompressed pages */ - mtr_t* mtr) /*!< in: mtr */ +ibuf_bitmap_get_map_page_func( +/*==========================*/ + ulint space, /*!< in: space id of the file page */ + ulint page_no,/*!< in: page number of the file page */ + ulint zip_size,/*!< in: compressed page size in bytes; + 0 for uncompressed pages */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ + mtr_t* mtr) /*!< in: mtr */ { buf_block_t* block; - block = buf_page_get(space, zip_size, - ibuf_bitmap_page_no_calc(zip_size, page_no), - RW_X_LATCH, mtr); + block = buf_page_get_gen(space, zip_size, + ibuf_bitmap_page_no_calc(zip_size, page_no), + RW_X_LATCH, NULL, BUF_GET, + file, line, mtr); buf_block_dbg_add_level(block, SYNC_IBUF_BITMAP); return(buf_block_get_frame(block)); } +/********************************************************************//** +Gets the ibuf bitmap page where the bits describing a given file page are +stored. +@return bitmap page where the file page is mapped, that is, the bitmap +page containing the descriptor bits for the file page; the bitmap page +is x-latched +@param space in: space id of the file page +@param page_no in: page number of the file page +@param zip_size in: compressed page size in bytes; 0 for uncompressed pages +@param mtr in: mini-transaction */ +#define ibuf_bitmap_get_map_page(space, page_no, zip_size, mtr) \ + ibuf_bitmap_get_map_page_func(space, page_no, zip_size, \ + __FILE__, __LINE__, mtr) + /************************************************************************//** Sets the free bits of the page in the ibuf bitmap. This is done in a separate mini-transaction, hence this operation does not restrict further work to only @@ -1133,9 +1206,185 @@ ibuf_rec_get_space( return(0); } +/****************************************************************//** +Get various information about an ibuf record in >= 4.1.x format. */ +static +void +ibuf_rec_get_info( +/*==============*/ + const rec_t* rec, /*!< in: ibuf record */ + ibuf_op_t* op, /*!< out: operation type, or NULL */ + ibool* comp, /*!< out: compact flag, or NULL */ + ulint* info_len, /*!< out: length of info fields at the + start of the fourth field, or + NULL */ + ulint* counter) /*!< in: counter value, or NULL */ +{ + const byte* types; + ulint fields; + ulint len; + + /* Local variables to shadow arguments. */ + ibuf_op_t op_local; + ibool comp_local; + ulint info_len_local; + ulint counter_local; + + ut_ad(ibuf_inside()); + fields = rec_get_n_fields_old(rec); + ut_a(fields > 4); + + types = rec_get_nth_field_old(rec, 3, &len); + + info_len_local = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE; + + switch (info_len_local) { + case 0: + case 1: + op_local = IBUF_OP_INSERT; + comp_local = info_len_local; + ut_ad(!counter); + counter_local = ULINT_UNDEFINED; + break; + + case IBUF_REC_INFO_SIZE: + op_local = (ibuf_op_t)types[IBUF_REC_OFFSET_TYPE]; + comp_local = types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT; + counter_local = mach_read_from_2( + types + IBUF_REC_OFFSET_COUNTER); + break; + + default: + ut_error; + } + + ut_a(op_local < IBUF_OP_COUNT); + ut_a((len - info_len_local) == + (fields - 4) * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); + + if (op) { + *op = op_local; + } + + if (comp) { + *comp = comp_local; + } + + if (info_len) { + *info_len = info_len_local; + } + + if (counter) { + *counter = counter_local; + } +} + +/****************************************************************//** +Returns the operation type field of an ibuf record. +@return operation type */ +static +ibuf_op_t +ibuf_rec_get_op_type( +/*=================*/ + const rec_t* rec) /*!< in: ibuf record */ +{ + ulint len; + const byte* field; + + ut_ad(ibuf_inside()); + ut_ad(rec_get_n_fields_old(rec) > 2); + + field = rec_get_nth_field_old(rec, 1, &len); + + if (len > 1) { + /* This is a < 4.1.x format record */ + + return(IBUF_OP_INSERT); + } else { + ibuf_op_t op; + + ibuf_rec_get_info(rec, &op, NULL, NULL, NULL); + + return(op); + } +} + +/****************************************************************//** +Read the first two bytes from a record's fourth field (counter field in new +records; something else in older records). +@return "counter" field, or ULINT_UNDEFINED if for some reason it +can't be read */ +UNIV_INTERN +ulint +ibuf_rec_get_counter( +/*=================*/ + const rec_t* rec) /*!< in: ibuf record */ +{ + const byte* ptr; + ulint len; + + if (rec_get_n_fields_old(rec) < 4) { + + return(ULINT_UNDEFINED); + } + + ptr = rec_get_nth_field_old(rec, 3, &len); + + if (len >= 2) { + + return(mach_read_from_2(ptr)); + } else { + + return(ULINT_UNDEFINED); + } +} + +/****************************************************************//** +Add accumulated operation counts to a permanent array. Both arrays must be +of size IBUF_OP_COUNT. */ +static +void +ibuf_add_ops( +/*=========*/ + ulint* arr, /*!< in/out: array to modify */ + const ulint* ops) /*!< in: operation counts */ + +{ + ulint i; + + for (i = 0; i < IBUF_OP_COUNT; i++) { + arr[i] += ops[i]; + } +} + +/****************************************************************//** +Print operation counts. The array must be of size IBUF_OP_COUNT. */ +static +void +ibuf_print_ops( +/*===========*/ + const ulint* ops, /*!< in: operation counts */ + FILE* file) /*!< in: file where to print */ +{ + static const char* op_names[] = { + "insert", + "delete mark", + "delete" + }; + ulint i; + + ut_a(UT_ARR_SIZE(op_names) == IBUF_OP_COUNT); + + for (i = 0; i < IBUF_OP_COUNT; i++) { + fprintf(file, "%s %lu%s", op_names[i], + (ulong) ops[i], (i < (IBUF_OP_COUNT - 1)) ? ", " : ""); + } + + putc('\n', file); +} + /********************************************************************//** Creates a dummy index for inserting a record to a non-clustered index. - @return dummy index */ static dict_index_t* @@ -1246,8 +1495,16 @@ ibuf_build_entry_pre_4_1_x( } /*********************************************************************//** -Builds the entry to insert into a non-clustered index when we have the -corresponding record in an ibuf index. +Builds the entry used to + +1) IBUF_OP_INSERT: insert into a non-clustered index + +2) IBUF_OP_DELETE_MARK: find the record whose delete-mark flag we need to + activate + +3) IBUF_OP_DELETE: find the record we need to delete + +when we have the corresponding record in an ibuf index. NOTE that as we copy pointers to fields in ibuf_rec, the caller must hold a latch to the ibuf_rec page as long as the entry is used! @@ -1268,7 +1525,9 @@ ibuf_build_entry_from_ibuf_rec( const byte* types; const byte* data; ulint len; + ulint info_len; ulint i; + ulint comp; dict_index_t* index; data = rec_get_nth_field_old(ibuf_rec, 1, &len); @@ -1291,16 +1550,12 @@ ibuf_build_entry_from_ibuf_rec( types = rec_get_nth_field_old(ibuf_rec, 3, &len); - ut_a(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE <= 1); - index = ibuf_dummy_index_create( - n_fields, len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); + ibuf_rec_get_info(ibuf_rec, NULL, &comp, &info_len, NULL); - if (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) { - /* compact record format */ - len--; - ut_a(*types == 0); - types++; - } + index = ibuf_dummy_index_create(n_fields, comp); + + len -= info_len; + types += info_len; ut_a(len == n_fields * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); @@ -1330,6 +1585,58 @@ ibuf_build_entry_from_ibuf_rec( return(tuple); } +/******************************************************************//** +Get the data size. +@return size of fields */ +UNIV_INLINE +ulint +ibuf_rec_get_size( +/*==============*/ + const rec_t* rec, /*!< in: ibuf record */ + const byte* types, /*!< in: fields */ + ulint n_fields, /*!< in: number of fields */ + ibool pre_4_1, /*!< in: TRUE=pre-4.1 format, + FALSE=newer */ + ulint comp) /*!< in: 0=ROW_FORMAT=REDUNDANT, + nonzero=ROW_FORMAT=COMPACT */ +{ + ulint i; + ulint field_offset; + ulint types_offset; + ulint size = 0; + + if (pre_4_1) { + field_offset = 2; + types_offset = DATA_ORDER_NULL_TYPE_BUF_SIZE; + } else { + field_offset = 4; + types_offset = DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE; + } + + for (i = 0; i < n_fields; i++) { + ulint len; + dtype_t dtype; + + rec_get_nth_field_offs_old(rec, i + field_offset, &len); + + if (len != UNIV_SQL_NULL) { + size += len; + } else if (pre_4_1) { + dtype_read_for_order_and_null_size(&dtype, types); + + size += dtype_get_sql_null_size(&dtype, comp); + } else { + dtype_new_read_for_order_and_null_size(&dtype, types); + + size += dtype_get_sql_null_size(&dtype, comp); + } + + types += types_offset; + } + + return(size); +} + /********************************************************************//** Returns the space taken by a stored non-clustered index entry if converted to an index record. @@ -1341,22 +1648,21 @@ ibuf_rec_get_volume( /*================*/ const rec_t* ibuf_rec)/*!< in: ibuf record */ { - dtype_t dtype; - ibool new_format = FALSE; - ulint data_size = 0; - ulint n_fields; - const byte* types; - const byte* data; ulint len; - ulint i; + const byte* data; + const byte* types; + ulint n_fields; + ulint data_size; + ibool pre_4_1; ulint comp; ut_ad(ibuf_inside()); ut_ad(rec_get_n_fields_old(ibuf_rec) > 2); data = rec_get_nth_field_old(ibuf_rec, 1, &len); + pre_4_1 = (len > 1); - if (len > 1) { + if (pre_4_1) { /* < 4.1.x format record */ ut_a(trx_doublewrite_must_reset_space_ids); @@ -1370,54 +1676,46 @@ ibuf_rec_get_volume( comp = 0; } else { /* >= 4.1.x format record */ + ibuf_op_t op; + ulint info_len; ut_a(trx_sys_multiple_tablespace_format); ut_a(*data == 0); types = rec_get_nth_field_old(ibuf_rec, 3, &len); - comp = len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE; + ibuf_rec_get_info(ibuf_rec, &op, &comp, &info_len, NULL); + + if (op == IBUF_OP_DELETE_MARK || op == IBUF_OP_DELETE) { + /* Delete-marking a record doesn't take any + additional space, and while deleting a record + actually frees up space, we have to play it safe and + pretend it takes no additional space (the record + might not exist, etc.). */ - ut_a(comp <= 1); - if (comp) { - /* compact record format */ + return(0); + } else if (comp) { + dtuple_t* entry; ulint volume; dict_index_t* dummy_index; mem_heap_t* heap = mem_heap_create(500); - dtuple_t* entry = ibuf_build_entry_from_ibuf_rec( + + entry = ibuf_build_entry_from_ibuf_rec( ibuf_rec, heap, &dummy_index); + volume = rec_get_converted_size(dummy_index, entry, 0); + ibuf_dummy_index_free(dummy_index); mem_heap_free(heap); + return(volume + page_dir_calc_reserved_space(1)); } + types += info_len; n_fields = rec_get_n_fields_old(ibuf_rec) - 4; - - new_format = TRUE; } - for (i = 0; i < n_fields; i++) { - if (new_format) { - data = rec_get_nth_field_old(ibuf_rec, i + 4, &len); - - dtype_new_read_for_order_and_null_size( - &dtype, types + i - * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); - } else { - data = rec_get_nth_field_old(ibuf_rec, i + 2, &len); - - dtype_read_for_order_and_null_size( - &dtype, types + i - * DATA_ORDER_NULL_TYPE_BUF_SIZE); - } - - if (len == UNIV_SQL_NULL) { - data_size += dtype_get_sql_null_size(&dtype, comp); - } else { - data_size += len; - } - } + data_size = ibuf_rec_get_size(ibuf_rec, types, n_fields, pre_4_1, comp); return(data_size + rec_get_converted_extra_size(data_size, n_fields, 0) + page_dir_calc_reserved_space(1)); @@ -1435,11 +1733,14 @@ static dtuple_t* ibuf_entry_build( /*=============*/ + ibuf_op_t op, /*!< in: operation type */ dict_index_t* index, /*!< in: non-clustered index */ const dtuple_t* entry, /*!< in: entry for a non-clustered index */ ulint space, /*!< in: space id */ ulint page_no,/*!< in: index page number where entry should be inserted */ + ulint counter,/*!< in: counter value; + ULINT_UNDEFINED=not used */ mem_heap_t* heap) /*!< in: heap into which to build */ { dtuple_t* tuple; @@ -1447,28 +1748,28 @@ ibuf_entry_build( const dfield_t* entry_field; ulint n_fields; byte* buf; - byte* buf2; + byte* ti; + byte* type_info; ulint i; - /* Starting from 4.1.x, we have to build a tuple whose - (1) first field is the space id, - (2) the second field a single marker byte (0) to tell that this - is a new format record, - (3) the third contains the page number, and - (4) the fourth contains the relevent type information of each data - field; the length of this field % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE is - (a) 0 for b-trees in the old format, and - (b) 1 for b-trees in the compact format, the first byte of the field - being the marker (0); - (5) and the rest of the fields are copied from entry. All fields - in the tuple are ordered like the type binary in our insert buffer - tree. */ + ut_ad(counter != ULINT_UNDEFINED || op == IBUF_OP_INSERT); + ut_ad(counter == ULINT_UNDEFINED || counter <= 0xFFFF); + ut_ad(op < IBUF_OP_COUNT); + + /* We have to build a tuple with the following fields: + + 1-4) These are described at the top of this file. + + 5) The rest of the fields are copied from the entry. + + All fields in the tuple are ordered like the type binary in our + insert buffer tree. */ n_fields = dtuple_get_n_fields(entry); tuple = dtuple_create(heap, n_fields + 4); - /* Store the space id in tuple */ + /* 1) Space Id */ field = dtuple_get_nth_field(tuple, 0); @@ -1478,7 +1779,7 @@ ibuf_entry_build( dfield_set_data(field, buf, 4); - /* Store the marker byte field in tuple */ + /* 2) Marker byte */ field = dtuple_get_nth_field(tuple, 1); @@ -1490,7 +1791,7 @@ ibuf_entry_build( dfield_set_data(field, buf, 1); - /* Store the page number in tuple */ + /* 3) Page number */ field = dtuple_get_nth_field(tuple, 2); @@ -1500,14 +1801,42 @@ ibuf_entry_build( dfield_set_data(field, buf, 4); - /* Store the type info in buf2, and add the fields from entry to - tuple */ - buf2 = mem_heap_alloc(heap, n_fields - * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE - + dict_table_is_comp(index->table)); - if (dict_table_is_comp(index->table)) { - *buf2++ = 0; /* write the compact format indicator */ + /* 4) Type info, part #1 */ + + if (counter == ULINT_UNDEFINED) { + i = dict_table_is_comp(index->table) ? 1 : 0; + } else { + ut_ad(counter <= 0xFFFF); + i = IBUF_REC_INFO_SIZE; + } + + ti = type_info = mem_heap_alloc(heap, i + n_fields + * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE); + + switch (i) { + default: + ut_error; + break; + case 1: + /* set the flag for ROW_FORMAT=COMPACT */ + *ti++ = 0; + /* fall through */ + case 0: + /* the old format does not allow delete buffering */ + ut_ad(op == IBUF_OP_INSERT); + break; + case IBUF_REC_INFO_SIZE: + mach_write_to_2(ti + IBUF_REC_OFFSET_COUNTER, counter); + + ti[IBUF_REC_OFFSET_TYPE] = (byte) op; + ti[IBUF_REC_OFFSET_FLAGS] = dict_table_is_comp(index->table) + ? IBUF_REC_COMPACT : 0; + ti += IBUF_REC_INFO_SIZE; + break; } + + /* 5+) Fields from the entry */ + for (i = 0; i < n_fields; i++) { ulint fixed_len; const dict_field_t* ifield; @@ -1542,21 +1871,16 @@ ibuf_entry_build( #endif /* UNIV_DEBUG */ dtype_new_store_for_order_and_null_size( - buf2 + i * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE, - dfield_get_type(entry_field), fixed_len); + ti, dfield_get_type(entry_field), fixed_len); + ti += DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE; } - /* Store the type info in buf2 to field 3 of tuple */ + /* 4) Type info, part #2 */ field = dtuple_get_nth_field(tuple, 3); - if (dict_table_is_comp(index->table)) { - buf2--; - } + dfield_set_data(field, type_info, ti - type_info); - dfield_set_data(field, buf2, n_fields - * DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE - + dict_table_is_comp(index->table)); /* Set all the types in the new tuple binary */ dtuple_set_types_binary(tuple, n_fields + 4); @@ -1999,7 +2323,7 @@ ibuf_get_merge_page_nos( *n_stored = 0; - limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool->curr_size / 4); + limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool_get_curr_size() / 4); if (page_rec_is_supremum(rec)) { @@ -2165,6 +2489,21 @@ ibuf_contract_ext( ibuf_is_empty: mutex_exit(&ibuf_mutex); +#if 0 /* TODO */ + if (srv_shutdown_state) { + /* If the insert buffer becomes empty during + shutdown, note it in the system tablespace. */ + + trx_sys_set_ibuf_format(TRX_SYS_IBUF_EMPTY); + } + + /* TO DO: call trx_sys_set_ibuf_format() at startup + and whenever ibuf_use is changed to allow buffered + delete-marking or deleting. Never downgrade the + stamped format except when the insert buffer becomes + empty. */ +#endif + return(0); } @@ -2177,6 +2516,8 @@ ibuf_is_empty: btr_pcur_open_at_rnd_pos(ibuf->index, BTR_SEARCH_LEAF, &pcur, &mtr); + ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index)); + if (page_get_n_recs(btr_pcur_get_page(&pcur)) == 0) { /* When the ibuf tree is emptied completely, the last record is removed using an optimistic delete and ibuf_size_update @@ -2310,6 +2651,160 @@ ibuf_contract_after_insert( } /*********************************************************************//** +Determine if an insert buffer record has been encountered already. +@return TRUE if a new record, FALSE if possible duplicate */ +static +ibool +ibuf_get_volume_buffered_hash( +/*==========================*/ + const rec_t* rec, /*!< in: ibuf record in post-4.1 format */ + const byte* types, /*!< in: fields */ + const byte* data, /*!< in: start of user record data */ + ulint comp, /*!< in: 0=ROW_FORMAT=REDUNDANT, + nonzero=ROW_FORMAT=COMPACT */ + ulint* hash, /*!< in/out: hash array */ + ulint size) /*!< in: number of elements in hash array */ +{ + ulint len; + ulint fold; + ulint bitmask; + + len = ibuf_rec_get_size(rec, types, rec_get_n_fields_old(rec) - 4, + FALSE, comp); + fold = ut_fold_binary(data, len); + + hash += (fold / (CHAR_BIT * sizeof *hash)) % size; + bitmask = 1 << (fold % (CHAR_BIT * sizeof *hash)); + + if (*hash & bitmask) { + + return(FALSE); + } + + /* We have not seen this record yet. Insert it. */ + *hash |= bitmask; + + return(TRUE); +} + +/*********************************************************************//** +Update the estimate of the number of records on a page, and +get the space taken by merging the buffered record to the index page. +@return size of index record in bytes + an upper limit of the space +taken in the page directory */ +static +ulint +ibuf_get_volume_buffered_count( +/*===========================*/ + const rec_t* rec, /*!< in: insert buffer record */ + ulint* hash, /*!< in/out: hash array */ + ulint size, /*!< in: number of elements in hash array */ + lint* n_recs) /*!< in/out: estimated number of records + on the page that rec points to */ +{ + ulint len; + ibuf_op_t ibuf_op; + const byte* types; + ulint n_fields = rec_get_n_fields_old(rec); + + ut_ad(ibuf_inside()); + ut_ad(n_fields > 4); + n_fields -= 4; + + rec_get_nth_field_offs_old(rec, 1, &len); + /* This function is only invoked when buffering new + operations. All pre-4.1 records should have been merged + when the database was started up. */ + ut_a(len == 1); + ut_ad(trx_sys_multiple_tablespace_format); + + types = rec_get_nth_field_old(rec, 3, &len); + + switch (UNIV_EXPECT(len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE, + IBUF_REC_INFO_SIZE)) { + default: + ut_error; + case 0: + /* This ROW_TYPE=REDUNDANT record does not include an + operation counter. Exclude it from the *n_recs, + because deletes cannot be buffered if there are + old-style inserts buffered for the page. */ + + len = ibuf_rec_get_size(rec, types, n_fields, FALSE, 0); + + return(len + + rec_get_converted_extra_size(len, n_fields, 0) + + page_dir_calc_reserved_space(1)); + case 1: + /* This ROW_TYPE=COMPACT record does not include an + operation counter. Exclude it from the *n_recs, + because deletes cannot be buffered if there are + old-style inserts buffered for the page. */ + goto get_volume_comp; + + case IBUF_REC_INFO_SIZE: + ibuf_op = (ibuf_op_t) types[IBUF_REC_OFFSET_TYPE]; + break; + } + + switch (ibuf_op) { + case IBUF_OP_INSERT: + /* Inserts can be done by + btr_cur_set_deleted_flag_for_ibuf(). Because + delete-mark and insert operations can be pointing to + the same records, we must not count duplicates. */ + case IBUF_OP_DELETE_MARK: + /* There must be a record to delete-mark. + See if this record has been already buffered. */ + if (n_recs && ibuf_get_volume_buffered_hash( + rec, types + IBUF_REC_INFO_SIZE, + types + len, + types[IBUF_REC_OFFSET_FLAGS] & IBUF_REC_COMPACT, + hash, size)) { + (*n_recs)++; + } + + if (ibuf_op == IBUF_OP_DELETE_MARK) { + /* Setting the delete-mark flag does not + affect the available space on the page. */ + return(0); + } + break; + case IBUF_OP_DELETE: + /* A record will be removed from the page. */ + if (n_recs) { + (*n_recs)--; + } + /* While deleting a record actually frees up space, + we have to play it safe and pretend that it takes no + additional space (the record might not exist, etc.). */ + return(0); + default: + ut_error; + } + + ut_ad(ibuf_op == IBUF_OP_INSERT); + +get_volume_comp: + { + dtuple_t* entry; + ulint volume; + dict_index_t* dummy_index; + mem_heap_t* heap = mem_heap_create(500); + + entry = ibuf_build_entry_from_ibuf_rec( + rec, heap, &dummy_index); + + volume = rec_get_converted_size(dummy_index, entry, 0); + + ibuf_dummy_index_free(dummy_index); + mem_heap_free(heap); + + return(volume + page_dir_calc_reserved_space(1)); + } +} + +/*********************************************************************//** Gets an upper limit for the combined size of entries buffered in the insert buffer for a given page. @return upper limit for the volume of buffered inserts for the index @@ -2326,6 +2821,9 @@ ibuf_get_volume_buffered( or BTR_MODIFY_TREE */ ulint space, /*!< in: space id */ ulint page_no,/*!< in: page number of an index page */ + lint* n_recs, /*!< in/out: minimum number of records on the + page after the buffered changes have been + applied, or NULL to disable the counting */ mtr_t* mtr) /*!< in: mtr */ { ulint volume; @@ -2335,19 +2833,25 @@ ibuf_get_volume_buffered( page_t* prev_page; ulint next_page_no; page_t* next_page; + ulint hash_bitmap[128 / sizeof(ulint)]; /* bitmap of buffered recs */ ut_a(trx_sys_multiple_tablespace_format); ut_ad((pcur->latch_mode == BTR_MODIFY_PREV) || (pcur->latch_mode == BTR_MODIFY_TREE)); - /* Count the volume of records earlier in the alphabetical order than + /* Count the volume of inserts earlier in the alphabetical order than pcur */ volume = 0; + if (n_recs) { + memset(hash_bitmap, 0, sizeof hash_bitmap); + } + rec = btr_pcur_get_rec(pcur); page = page_align(rec); + ut_ad(page_validate(page, ibuf->index)); if (page_rec_is_supremum(rec)) { rec = page_rec_get_prev(rec); @@ -2365,9 +2869,11 @@ ibuf_get_volume_buffered( goto count_later; } - volume += ibuf_rec_get_volume(rec); + volume += ibuf_get_volume_buffered_count( + rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); rec = page_rec_get_prev(rec); + ut_ad(page_align(rec) == page); } /* Look at the previous page */ @@ -2389,6 +2895,7 @@ ibuf_get_volume_buffered( prev_page = buf_block_get_frame(block); + ut_ad(page_validate(prev_page, ibuf->index)); } #ifdef UNIV_BTR_DEBUG @@ -2415,9 +2922,11 @@ ibuf_get_volume_buffered( goto count_later; } - volume += ibuf_rec_get_volume(rec); + volume += ibuf_get_volume_buffered_count( + rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); rec = page_rec_get_prev(rec); + ut_ad(page_align(rec) == prev_page); } count_later: @@ -2439,7 +2948,8 @@ count_later: return(volume); } - volume += ibuf_rec_get_volume(rec); + volume += ibuf_get_volume_buffered_count( + rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); rec = page_rec_get_next(rec); } @@ -2463,6 +2973,7 @@ count_later: next_page = buf_block_get_frame(block); + ut_ad(page_validate(next_page, ibuf->index)); } #ifdef UNIV_BTR_DEBUG @@ -2486,9 +2997,11 @@ count_later: return(volume); } - volume += ibuf_rec_get_volume(rec); + volume += ibuf_get_volume_buffered_count( + rec, hash_bitmap, UT_ARR_SIZE(hash_bitmap), n_recs); rec = page_rec_get_next(rec); + ut_ad(page_align(rec) == next_page); } } @@ -2516,6 +3029,8 @@ ibuf_update_max_tablespace_id(void) btr_pcur_open_at_index_side( FALSE, ibuf->index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr); + ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index)); + btr_pcur_move_to_prev(&pcur, &mtr); if (btr_pcur_is_before_first_on_page(&pcur)) { @@ -2540,15 +3055,226 @@ ibuf_update_max_tablespace_id(void) fil_set_max_space_id_if_bigger(max_space_id); } +/****************************************************************//** +Helper function for ibuf_set_entry_counter. Checks if rec is for (space, +page_no), and if so, reads counter value from it and returns that + 1. +Otherwise, returns 0. +@return new counter value, or 0 */ +static +ulint +ibuf_get_entry_counter_low( +/*=======================*/ + const rec_t* rec, /*!< in: insert buffer record */ + ulint space, /*!< in: space id */ + ulint page_no) /*!< in: page number */ +{ + ulint counter; + const byte* field; + ulint len; + + ut_ad(ibuf_inside()); + ut_ad(rec_get_n_fields_old(rec) > 2); + + field = rec_get_nth_field_old(rec, 1, &len); + + if (UNIV_UNLIKELY(len != 1)) { + /* pre-4.1 format */ + ut_a(trx_doublewrite_must_reset_space_ids); + ut_a(!trx_sys_multiple_tablespace_format); + + return(ULINT_UNDEFINED); + } + + ut_a(trx_sys_multiple_tablespace_format); + + /* Check the tablespace identifier. */ + field = rec_get_nth_field_old(rec, 0, &len); + ut_a(len == 4); + + if (mach_read_from_4(field) != space) { + + return(0); + } + + /* Check the page offset. */ + field = rec_get_nth_field_old(rec, 2, &len); + ut_a(len == 4); + + if (mach_read_from_4(field) != page_no) { + + return(0); + } + + /* Check if the record contains a counter field. */ + field = rec_get_nth_field_old(rec, 3, &len); + + switch (len % DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE) { + default: + ut_error; + case 0: /* ROW_FORMAT=REDUNDANT */ + case 1: /* ROW_FORMAT=COMPACT */ + return(ULINT_UNDEFINED); + + case IBUF_REC_INFO_SIZE: + counter = mach_read_from_2(field + IBUF_REC_OFFSET_COUNTER); + ut_a(counter < 0xFFFF); + return(counter + 1); + } +} + +/****************************************************************//** +Set the counter field in entry to the correct value based on the current +last record in ibuf for (space, page_no). +@return FALSE if we should abort this insertion to ibuf */ +static +ibool +ibuf_set_entry_counter( +/*===================*/ + dtuple_t* entry, /*!< in/out: entry to patch */ + ulint space, /*!< in: space id of entry */ + ulint page_no, /*!< in: page number of entry */ + btr_pcur_t* pcur, /*!< in: pcur positioned on the record + found by btr_pcur_open(.., entry, + PAGE_CUR_LE, ..., pcur, ...) */ + ibool is_optimistic, /*!< in: is this an optimistic insert */ + mtr_t* mtr) /*!< in: mtr */ +{ + dfield_t* field; + byte* data; + ulint counter = 0; + + /* pcur points to either a user rec or to a page's infimum record. */ + ut_ad(page_validate(btr_pcur_get_page(pcur), ibuf->index)); + + if (btr_pcur_is_on_user_rec(pcur)) { + + counter = ibuf_get_entry_counter_low( + btr_pcur_get_rec(pcur), space, page_no); + + if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) { + /* The record lacks a counter field. + Such old records must be merged before + new records can be buffered. */ + + return(FALSE); + } + } else if (btr_pcur_is_before_first_in_tree(pcur, mtr)) { + /* Ibuf tree is either completely empty, or the insert + position is at the very first record of a non-empty tree. In + either case we have no previous records for (space, + page_no). */ + + counter = 0; + } else if (btr_pcur_is_before_first_on_page(pcur)) { + btr_cur_t* cursor = btr_pcur_get_btr_cur(pcur); + + if (cursor->low_match < 3) { + /* If low_match < 3, we know that the father node + pointer did not contain the searched for (space, + page_no), which means that the search ended on the + right page regardless of the counter value, and + since we're at the infimum record, there are no + existing records. */ + + counter = 0; + } else { + rec_t* rec; + const page_t* page; + buf_block_t* block; + page_t* prev_page; + ulint prev_page_no; + + ut_a(cursor->ibuf_cnt != ULINT_UNDEFINED); + + page = btr_pcur_get_page(pcur); + prev_page_no = btr_page_get_prev(page, mtr); + + ut_a(prev_page_no != FIL_NULL); + + block = buf_page_get( + IBUF_SPACE_ID, 0, prev_page_no, + RW_X_LATCH, mtr); + + buf_block_dbg_add_level(block, SYNC_TREE_NODE); + + prev_page = buf_block_get_frame(block); + + rec = page_rec_get_prev( + page_get_supremum_rec(prev_page)); + + ut_ad(page_rec_is_user_rec(rec)); + + counter = ibuf_get_entry_counter_low( + rec, space, page_no); + + if (UNIV_UNLIKELY(counter == ULINT_UNDEFINED)) { + /* The record lacks a counter field. + Such old records must be merged before + new records can be buffered. */ + + return(FALSE); + } + + if (counter < cursor->ibuf_cnt) { + /* Search ended on the wrong page. */ + + if (is_optimistic) { + /* In an optimistic insert, we can + shift the insert position to the left + page, since it only needs an X-latch + on the page itself, which the + original search acquired for us. */ + + btr_cur_position( + ibuf->index, rec, block, + btr_pcur_get_btr_cur(pcur)); + } else { + /* We can't shift the insert + position to the left page in a + pessimistic insert since it would + require an X-latch on the left + page's left page, so we have to + abort. */ + + return(FALSE); + } + } else { + /* The counter field in the father node is + the same as we would insert; we don't know + whether the insert should go to this page or + the left page (the later fields can differ), + so refuse the insert. */ + + return(FALSE); + } + } + } else { + /* The cursor is not positioned at or before a user record. */ + return(FALSE); + } + + /* Patch counter value in already built entry. */ + field = dtuple_get_nth_field(entry, 3); + data = dfield_get_data(field); + + mach_write_to_2(data + IBUF_REC_OFFSET_COUNTER, counter); + + return(TRUE); +} + /*********************************************************************//** -Makes an index insert to the insert buffer, instead of directly to the disk -page, if this is possible. +Buffer an operation in the insert/delete buffer, instead of doing it +directly to the disk page, if this is possible. @return DB_SUCCESS, DB_FAIL, DB_STRONG_FAIL */ static ulint ibuf_insert_low( /*============*/ ulint mode, /*!< in: BTR_MODIFY_PREV or BTR_MODIFY_TREE */ + ibuf_op_t op, /*!< in: operation type */ + ibool no_counter, + /*!< in: TRUE=use 5.0.3 format; + FALSE=allow delete buffering */ const dtuple_t* entry, /*!< in: index entry to insert */ ulint entry_size, /*!< in: rec_get_converted_size(index, entry) */ @@ -2565,6 +3291,7 @@ ibuf_insert_low( dtuple_t* ibuf_entry; mem_heap_t* heap; ulint buffered; + lint min_n_recs; rec_t* ins_rec; ibool old_bit_value; page_t* bitmap_page; @@ -2575,13 +3302,14 @@ ibuf_insert_low( ib_int64_t space_versions[IBUF_MAX_N_PAGES_MERGED]; ulint page_nos[IBUF_MAX_N_PAGES_MERGED]; ulint n_stored; - ulint bits; mtr_t mtr; mtr_t bitmap_mtr; ut_a(!dict_index_is_clust(index)); ut_ad(dtuple_check_typed(entry)); ut_ad(ut_is_2pow(zip_size)); + ut_ad(!no_counter || op == IBUF_OP_INSERT); + ut_a(op < IBUF_OP_COUNT); ut_a(trx_sys_multiple_tablespace_format); @@ -2640,11 +3368,17 @@ ibuf_insert_low( heap = mem_heap_create(512); - /* Build the entry which contains the space id and the page number as - the first fields and the type information for other fields, and which - will be inserted to the insert buffer. */ + /* Build the entry which contains the space id and the page number + as the first fields and the type information for other fields, and + which will be inserted to the insert buffer. Using a counter value + of 0xFFFF we find the last record for (space, page_no), from which + we can then read the counter value N and use N + 1 in the record we + insert. (We patch the ibuf_entry's counter field to the correct + value just before actually inserting the entry.) */ - ibuf_entry = ibuf_entry_build(index, entry, space, page_no, heap); + ibuf_entry = ibuf_entry_build( + op, index, entry, space, page_no, + no_counter ? ULINT_UNDEFINED : 0xFFFF, heap); /* Open a cursor to the insert buffer tree to calculate if we can add the new entry to it without exceeding the free space limit for the @@ -2653,10 +3387,49 @@ ibuf_insert_low( mtr_start(&mtr); btr_pcur_open(ibuf->index, ibuf_entry, PAGE_CUR_LE, mode, &pcur, &mtr); + ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index)); /* Find out the volume of already buffered inserts for the same index page */ - buffered = ibuf_get_volume_buffered(&pcur, space, page_no, &mtr); + min_n_recs = 0; + buffered = ibuf_get_volume_buffered(&pcur, space, page_no, + op == IBUF_OP_DELETE + ? &min_n_recs + : NULL, &mtr); + + if (op == IBUF_OP_DELETE + && (min_n_recs < 2 + || buf_pool_watch_occurred(space, page_no))) { + /* The page could become empty after the record is + deleted, or the page has been read in to the buffer + pool. Refuse to buffer the operation. */ + + /* The buffer pool watch is needed for IBUF_OP_DELETE + because of latching order considerations. We can + check buf_pool_watch_occurred() only after latching + the insert buffer B-tree pages that contain buffered + changes for the page. We never buffer IBUF_OP_DELETE, + unless some IBUF_OP_INSERT or IBUF_OP_DELETE_MARK have + been previously buffered for the page. Because there + are buffered operations for the page, the insert + buffer B-tree page latches held by mtr will guarantee + that no changes for the user page will be merged + before mtr_commit(&mtr). We must not mtr_commit(&mtr) + until after the IBUF_OP_DELETE has been buffered. */ + + err = DB_STRONG_FAIL; + + goto function_exit; + } + + /* After this point, the page could still be loaded to the + buffer pool, but we do not have to care about it, since we are + holding a latch on the insert buffer leaf page that contains + buffered changes for (space, page_no). If the page enters the + buffer pool, buf_page_io_complete() for (space, page_no) will + have to acquire a latch on the same insert buffer leaf page, + which it cannot do until we have buffered the IBUF_OP_DELETE + and done mtr_commit(&mtr) to release the latch. */ #ifdef UNIV_IBUF_COUNT_DEBUG ut_a((buffered == 0) || ibuf_count_get(space, page_no)); @@ -2670,28 +3443,45 @@ ibuf_insert_low( if (buf_page_peek(space, page_no) || lock_rec_expl_exist_on_page(space, page_no)) { - err = DB_STRONG_FAIL; - - mtr_commit(&bitmap_mtr); - goto function_exit; + goto bitmap_fail; } - bits = ibuf_bitmap_page_get_bits(bitmap_page, page_no, zip_size, - IBUF_BITMAP_FREE, &bitmap_mtr); + if (op == IBUF_OP_INSERT) { + ulint bits = ibuf_bitmap_page_get_bits( + bitmap_page, page_no, zip_size, IBUF_BITMAP_FREE, + &bitmap_mtr); - if (buffered + entry_size + page_dir_calc_reserved_space(1) - > ibuf_index_page_calc_free_from_bits(zip_size, bits)) { - mtr_commit(&bitmap_mtr); + if (buffered + entry_size + page_dir_calc_reserved_space(1) + > ibuf_index_page_calc_free_from_bits(zip_size, bits)) { + /* Release the bitmap page latch early. */ + mtr_commit(&bitmap_mtr); + + /* It may not fit */ + do_merge = TRUE; + + ibuf_get_merge_page_nos( + FALSE, btr_pcur_get_rec(&pcur), + space_ids, space_versions, + page_nos, &n_stored); - /* It may not fit */ + err = DB_STRONG_FAIL; + + goto function_exit; + } + } + + /* Patch correct counter value to the entry to insert. This can + change the insert position, which can result in the need to abort in + some cases. */ + if (!no_counter + && !ibuf_set_entry_counter(ibuf_entry, space, page_no, &pcur, + mode == BTR_MODIFY_PREV, &mtr)) { +bitmap_fail: err = DB_STRONG_FAIL; - do_merge = TRUE; + mtr_commit(&bitmap_mtr); - ibuf_get_merge_page_nos(FALSE, btr_pcur_get_rec(&pcur), - space_ids, space_versions, - page_nos, &n_stored); goto function_exit; } @@ -2716,7 +3506,7 @@ ibuf_insert_low( err = btr_cur_optimistic_insert(BTR_NO_LOCKING_FLAG, cursor, ibuf_entry, &ins_rec, &dummy_big_rec, 0, thr, &mtr); - if (err == DB_SUCCESS) { + if (err == DB_SUCCESS && op != IBUF_OP_DELETE) { /* Update the page max trx id field */ page_update_max_trx_id(btr_cur_get_block(cursor), NULL, thr_get_trx(thr)->id, &mtr); @@ -2736,7 +3526,7 @@ ibuf_insert_low( cursor, ibuf_entry, &ins_rec, &dummy_big_rec, 0, thr, &mtr); - if (err == DB_SUCCESS) { + if (err == DB_SUCCESS && op != IBUF_OP_DELETE) { /* Update the page max trx id field */ page_update_max_trx_id(btr_cur_get_block(cursor), NULL, thr_get_trx(thr)->id, &mtr); @@ -2773,7 +3563,6 @@ function_exit: mutex_enter(&ibuf_mutex); ibuf->empty = FALSE; - ibuf->n_inserts++; mutex_exit(&ibuf_mutex); @@ -2794,14 +3583,15 @@ function_exit: } /*********************************************************************//** -Makes an index insert to the insert buffer, instead of directly to the disk -page, if this is possible. Does not do insert if the index is clustered -or unique. +Buffer an operation in the insert/delete buffer, instead of doing it +directly to the disk page, if this is possible. Does not do it if the index +is clustered or unique. @return TRUE if success */ UNIV_INTERN ibool ibuf_insert( /*========*/ + ibuf_op_t op, /*!< in: operation type */ const dtuple_t* entry, /*!< in: index entry to insert */ dict_index_t* index, /*!< in: index where to insert */ ulint space, /*!< in: space id where to insert */ @@ -2809,8 +3599,12 @@ ibuf_insert( ulint page_no,/*!< in: page number where to insert */ que_thr_t* thr) /*!< in: query thread */ { - ulint err; - ulint entry_size; + ulint err; + ulint entry_size; + ibool no_counter; + /* Read the settable global variable ibuf_use only once in + this function, so that we will have a consistent view of it. */ + ibuf_use_t use = ibuf_use; ut_a(trx_sys_multiple_tablespace_format); ut_ad(dtuple_check_typed(entry)); @@ -2818,30 +3612,109 @@ ibuf_insert( ut_a(!dict_index_is_clust(index)); - switch (UNIV_EXPECT(ibuf_use, IBUF_USE_INSERT)) { - case IBUF_USE_NONE: - return(FALSE); - case IBUF_USE_INSERT: - goto do_insert; - case IBUF_USE_COUNT: + no_counter = use <= IBUF_USE_INSERT; + + switch (op) { + case IBUF_OP_INSERT: + switch (use) { + case IBUF_USE_NONE: + case IBUF_USE_DELETE: + case IBUF_USE_DELETE_MARK: + return(FALSE); + case IBUF_USE_INSERT: + case IBUF_USE_INSERT_DELETE_MARK: + case IBUF_USE_ALL: + goto check_watch; + case IBUF_USE_COUNT: + break; + } + break; + case IBUF_OP_DELETE_MARK: + switch (use) { + case IBUF_USE_NONE: + case IBUF_USE_INSERT: + return(FALSE); + case IBUF_USE_DELETE_MARK: + case IBUF_USE_DELETE: + case IBUF_USE_INSERT_DELETE_MARK: + case IBUF_USE_ALL: + ut_ad(!no_counter); + goto check_watch; + case IBUF_USE_COUNT: + break; + } + break; + case IBUF_OP_DELETE: + switch (use) { + case IBUF_USE_NONE: + case IBUF_USE_INSERT: + case IBUF_USE_INSERT_DELETE_MARK: + return(FALSE); + case IBUF_USE_DELETE_MARK: + case IBUF_USE_DELETE: + case IBUF_USE_ALL: + ut_ad(!no_counter); + goto skip_watch; + case IBUF_USE_COUNT: + break; + } + break; + case IBUF_OP_COUNT: break; } - ut_error; /* unknown value of ibuf_use */ + /* unknown op or use */ + ut_error; + +check_watch: + /* If a thread attempts to buffer an insert on a page while a + purge is in progress on the same page, the purge must not be + buffered, because it could remove a record that was + re-inserted later. For simplicity, we block the buffering of + all operations on a page that has a purge pending. + + We do not check this in the IBUF_OP_DELETE case, because that + would always trigger the buffer pool watch during purge and + thus prevent the buffering of delete operations. We assume + that the issuer of IBUF_OP_DELETE has called + buf_pool_watch_set(space, page_no). */ + + { + buf_page_t* bpage; + ulint fold = buf_page_address_fold(space, page_no); + buf_pool_t* buf_pool = buf_pool_get(space, page_no); + + buf_pool_mutex_enter(buf_pool); + bpage = buf_page_hash_get_low(buf_pool, space, page_no, fold); + buf_pool_mutex_exit(buf_pool); + + if (UNIV_LIKELY_NULL(bpage)) { + /* A buffer pool watch has been set or the + page has been read into the buffer pool. + Do not buffer the request. If a purge operation + is being buffered, have this request executed + directly on the page in the buffer pool after the + buffered entries for this page have been merged. */ + return(FALSE); + } + } -do_insert: +skip_watch: entry_size = rec_get_converted_size(index, entry, 0); if (entry_size - >= (page_get_free_space_of_empty(dict_table_is_comp(index->table)) - / 2)) { + >= page_get_free_space_of_empty(dict_table_is_comp(index->table)) + / 2) { + return(FALSE); } - err = ibuf_insert_low(BTR_MODIFY_PREV, entry, entry_size, + err = ibuf_insert_low(BTR_MODIFY_PREV, op, no_counter, + entry, entry_size, index, space, zip_size, page_no, thr); if (err == DB_FAIL) { - err = ibuf_insert_low(BTR_MODIFY_TREE, entry, entry_size, + err = ibuf_insert_low(BTR_MODIFY_TREE, op, no_counter, + entry, entry_size, index, space, zip_size, page_no, thr); } @@ -2893,6 +3766,20 @@ ibuf_insert_to_index_page( rec = page_rec_get_next(page_get_infimum_rec(page)); + if (page_rec_is_supremum(rec)) { + /* Empty pages can result from buffered delete operations. + The first record from the free list can be used to find the + father node. */ + rec = page_header_get_ptr(page, PAGE_FREE); + if (UNIV_UNLIKELY(rec == NULL)) { + fputs("InnoDB: Trying to insert a record from" + " the insert buffer to an index page\n" + "InnoDB: but the index page is empty!\n", + stderr); + goto dump; + } + } + if (UNIV_UNLIKELY(rec_get_n_fields(rec, index) != dtuple_get_n_fields(entry))) { fputs("InnoDB: Trying to insert a record from" @@ -2924,7 +3811,7 @@ dump: rec = page_cur_get_rec(&page_cur); page_zip = buf_block_get_page_zip(block); - btr_cur_del_unmark_for_ibuf(rec, page_zip, mtr); + btr_cur_set_deleted_flag_for_ibuf(rec, page_zip, FALSE, mtr); } else { rec = page_cur_tuple_insert(&page_cur, entry, index, 0, mtr); @@ -2986,6 +3873,178 @@ dump: } } +/****************************************************************//** +During merge, sets the delete mark on a record for a secondary index +entry. */ +static +void +ibuf_set_del_mark( +/*==============*/ + const dtuple_t* entry, /*!< in: entry */ + buf_block_t* block, /*!< in/out: block */ + const dict_index_t* index, /*!< in: record descriptor */ + mtr_t* mtr) /*!< in: mtr */ +{ + page_cur_t page_cur; + ulint low_match; + + ut_ad(ibuf_inside()); + ut_ad(dtuple_check_typed(entry)); + + low_match = page_cur_search( + block, index, entry, PAGE_CUR_LE, &page_cur); + + if (low_match == dtuple_get_n_fields(entry)) { + rec_t* rec; + page_zip_des_t* page_zip; + + rec = page_cur_get_rec(&page_cur); + page_zip = page_cur_get_page_zip(&page_cur); + + btr_cur_set_deleted_flag_for_ibuf(rec, page_zip, TRUE, mtr); + } else { + /* This can happen benignly in some situations. */ + } +} + +/****************************************************************//** +During merge, delete a record for a secondary index entry. */ +static +void +ibuf_delete( +/*========*/ + const dtuple_t* entry, /*!< in: entry */ + buf_block_t* block, /*!< in/out: block */ + dict_index_t* index, /*!< in: record descriptor */ + mtr_t* mtr) /*!< in/out: mtr; must be committed + before latching any further pages */ +{ + page_cur_t page_cur; + ulint low_match; + + ut_ad(ibuf_inside()); + ut_ad(dtuple_check_typed(entry)); + + low_match = page_cur_search( + block, index, entry, PAGE_CUR_LE, &page_cur); + + if (low_match == dtuple_get_n_fields(entry)) { + page_zip_des_t* page_zip= buf_block_get_page_zip(block); + page_t* page = buf_block_get_frame(block); + rec_t* rec = page_cur_get_rec(&page_cur); + + /* TODO: the below should probably be a separate function, + it's a bastardized version of btr_cur_optimistic_delete. */ + + ulint offsets_[REC_OFFS_NORMAL_SIZE]; + ulint* offsets = offsets_; + mem_heap_t* heap = NULL; + ulint max_ins_size; + + rec_offs_init(offsets_); + + offsets = rec_get_offsets( + rec, index, offsets, ULINT_UNDEFINED, &heap); + + /* Refuse to delete the last record. */ + ut_a(page_get_n_recs(page) > 1); + + /* The record should have been marked for deletion. */ + ut_ad(REC_INFO_DELETED_FLAG + & rec_get_info_bits(rec, page_is_comp(page))); + + lock_update_delete(block, rec); + + if (!page_zip) { + max_ins_size + = page_get_max_insert_size_after_reorganize( + page, 1); + } +#ifdef UNIV_ZIP_DEBUG + ut_a(!page_zip || page_zip_validate(page_zip, page)); +#endif /* UNIV_ZIP_DEBUG */ + page_cur_delete_rec(&page_cur, index, offsets, mtr); +#ifdef UNIV_ZIP_DEBUG + ut_a(!page_zip || page_zip_validate(page_zip, page)); +#endif /* UNIV_ZIP_DEBUG */ + + if (page_zip) { + ibuf_update_free_bits_zip(block, mtr); + } else { + ibuf_update_free_bits_low(block, max_ins_size, mtr); + } + + if (UNIV_LIKELY_NULL(heap)) { + mem_heap_free(heap); + } + } else { + /* This can happen benignly in some situations: either when + we crashed at just the right time, or on database startup + when we redo some old log entries (due to worse stored + position granularity on disk than in memory). */ + } +} + +/*********************************************************************//** +Restores insert buffer tree cursor position +@return TRUE if the position was restored; FALSE if not */ +static __attribute__((nonnull)) +ibool +ibuf_restore_pos( +/*=============*/ + ulint space, /*!< in: space id */ + ulint page_no,/*!< in: index page number where the record + should belong */ + const dtuple_t* search_tuple, + /*!< in: search tuple for entries of page_no */ + ulint mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */ + btr_pcur_t* pcur, /*!< in/out: persistent cursor whose + position is to be restored */ + mtr_t* mtr) /*!< in/out: mini-transaction */ +{ + ut_ad(mode == BTR_MODIFY_LEAF || mode == BTR_MODIFY_TREE); + + if (btr_pcur_restore_position(mode, pcur, mtr)) { + + return(TRUE); + } + + if (fil_space_get_flags(space) == ULINT_UNDEFINED) { + /* The tablespace has been dropped. It is possible + that another thread has deleted the insert buffer + entry. Do not complain. */ + btr_pcur_commit_specify_mtr(pcur, mtr); + } else { + fprintf(stderr, + "InnoDB: ERROR: Submit the output to" + " http://bugs.mysql.com\n" + "InnoDB: ibuf cursor restoration fails!\n" + "InnoDB: ibuf record inserted to page %lu:%lu\n", + (ulong) space, (ulong) page_no); + fflush(stderr); + + rec_print_old(stderr, btr_pcur_get_rec(pcur)); + rec_print_old(stderr, pcur->old_rec); + dtuple_print(stderr, search_tuple); + + rec_print_old(stderr, + page_rec_get_next(btr_pcur_get_rec(pcur))); + fflush(stderr); + + btr_pcur_commit_specify_mtr(pcur, mtr); + + fputs("InnoDB: Validating insert buffer tree:\n", stderr); + if (!btr_validate_index(ibuf->index, NULL)) { + ut_error; + } + + fprintf(stderr, "InnoDB: ibuf tree ok\n"); + fflush(stderr); + } + + return(FALSE); +} + /*********************************************************************//** Deletes from ibuf the record on which pcur is positioned. If we have to resort to a pessimistic delete, this function commits mtr and closes @@ -3040,41 +4099,8 @@ ibuf_delete_rec( mtr_start(mtr); - success = btr_pcur_restore_position(BTR_MODIFY_TREE, pcur, mtr); - - if (!success) { - if (fil_space_get_flags(space) == ULINT_UNDEFINED) { - /* The tablespace has been dropped. It is possible - that another thread has deleted the insert buffer - entry. Do not complain. */ - goto commit_and_exit; - } - - fprintf(stderr, - "InnoDB: ERROR: Submit the output to" - " http://bugs.mysql.com\n" - "InnoDB: ibuf cursor restoration fails!\n" - "InnoDB: ibuf record inserted to page %lu\n", - (ulong) page_no); - fflush(stderr); - - rec_print_old(stderr, btr_pcur_get_rec(pcur)); - rec_print_old(stderr, pcur->old_rec); - dtuple_print(stderr, search_tuple); - - rec_print_old(stderr, - page_rec_get_next(btr_pcur_get_rec(pcur))); - fflush(stderr); - - btr_pcur_commit_specify_mtr(pcur, mtr); - - fputs("InnoDB: Validating insert buffer tree:\n", stderr); - if (!btr_validate_index(ibuf->index, NULL)) { - ut_error; - } - - fprintf(stderr, "InnoDB: ibuf tree ok\n"); - fflush(stderr); + if (!ibuf_restore_pos(space, page_no, search_tuple, + BTR_MODIFY_TREE, pcur, mtr)) { goto func_exit; } @@ -3089,8 +4115,6 @@ ibuf_delete_rec( ibuf_count_set(space, page_no, ibuf_count_get(space, page_no) - 1); #endif ibuf_size_update(root, mtr); - -commit_and_exit: btr_pcur_commit_specify_mtr(pcur, mtr); func_exit: @@ -3103,11 +4127,11 @@ func_exit: /*********************************************************************//** When an index page is read from a disk to the buffer pool, this function -inserts to the page the possible index entries buffered in the insert buffer. -The entries are deleted from the insert buffer. If the page is not read, but -created in the buffer pool, this function deletes its buffered entries from -the insert buffer; there can exist entries for such a page if the page -belonged to an index which subsequently was dropped. */ +applies any buffered operations to the page and deletes the entries from the +insert buffer. If the page is not read, but created in the buffer pool, this +function deletes its buffered entries from the insert buffer; there can +exist entries for such a page if the page belonged to an index which +subsequently was dropped. */ UNIV_INTERN void ibuf_merge_or_delete_for_page( @@ -3128,15 +4152,18 @@ ibuf_merge_or_delete_for_page( mem_heap_t* heap; btr_pcur_t pcur; dtuple_t* search_tuple; - ulint n_inserts; #ifdef UNIV_IBUF_DEBUG - ulint volume; + ulint volume = 0; #endif page_zip_des_t* page_zip = NULL; ibool tablespace_being_deleted = FALSE; ibool corruption_noticed = FALSE; mtr_t mtr; + /* Counts for merged & discarded operations. */ + ulint mops[IBUF_OP_COUNT]; + ulint dops[IBUF_OP_COUNT]; + ut_ad(!block || buf_block_get_space(block) == space); ut_ad(!block || buf_block_get_page_no(block) == page_no); ut_ad(!block || buf_block_get_zip_size(block) == zip_size); @@ -3279,10 +4306,9 @@ ibuf_merge_or_delete_for_page( } } - n_inserts = 0; -#ifdef UNIV_IBUF_DEBUG - volume = 0; -#endif + memset(mops, 0, sizeof(mops)); + memset(dops, 0, sizeof(dops)); + loop: mtr_start(&mtr); @@ -3335,33 +4361,94 @@ loop: fputs("\nInnoDB: from the insert buffer!\n\n", stderr); } else if (block) { /* Now we have at pcur a record which should be - inserted to the index page; NOTE that the call below + applied on the index page; NOTE that the call below copies pointers to fields in rec, and we must keep the latch to the rec page until the insertion is finished! */ dtuple_t* entry; trx_id_t max_trx_id; dict_index_t* dummy_index; + ibuf_op_t op = ibuf_rec_get_op_type(rec); max_trx_id = page_get_max_trx_id(page_align(rec)); page_update_max_trx_id(block, page_zip, max_trx_id, &mtr); + ut_ad(page_validate(page_align(rec), ibuf->index)); + entry = ibuf_build_entry_from_ibuf_rec( rec, heap, &dummy_index); + + ut_ad(page_validate(block->frame, dummy_index)); + + switch (op) { + ibool success; + case IBUF_OP_INSERT: #ifdef UNIV_IBUF_DEBUG - volume += rec_get_converted_size(dummy_index, entry, 0) - + page_dir_calc_reserved_space(1); - ut_a(volume <= 4 * UNIV_PAGE_SIZE - / IBUF_PAGE_SIZE_PER_FREE_SPACE); + volume += rec_get_converted_size( + dummy_index, entry, 0); + + volume += page_dir_calc_reserved_space(1); + + ut_a(volume <= 4 * UNIV_PAGE_SIZE + / IBUF_PAGE_SIZE_PER_FREE_SPACE); #endif - ibuf_insert_to_index_page(entry, block, - dummy_index, &mtr); + ibuf_insert_to_index_page( + entry, block, dummy_index, &mtr); + break; + + case IBUF_OP_DELETE_MARK: + ibuf_set_del_mark( + entry, block, dummy_index, &mtr); + break; + + case IBUF_OP_DELETE: + ibuf_delete(entry, block, dummy_index, &mtr); + /* Because ibuf_delete() will latch an + insert buffer bitmap page, commit mtr + before latching any further pages. + Store and restore the cursor position. */ + ut_ad(rec == btr_pcur_get_rec(&pcur)); + ut_ad(page_rec_is_user_rec(rec)); + ut_ad(ibuf_rec_get_page_no(rec) == page_no); + ut_ad(ibuf_rec_get_space(rec) == space); + + btr_pcur_store_position(&pcur, &mtr); + btr_pcur_commit_specify_mtr(&pcur, &mtr); + + mtr_start(&mtr); + + success = buf_page_get_known_nowait( + RW_X_LATCH, block, + BUF_KEEP_OLD, + __FILE__, __LINE__, &mtr); + ut_a(success); + + buf_block_dbg_add_level(block, SYNC_TREE_NODE); + + if (!ibuf_restore_pos(space, page_no, + search_tuple, + BTR_MODIFY_LEAF, + &pcur, &mtr)) { + + mtr_commit(&mtr); + mops[op]++; + ibuf_dummy_index_free(dummy_index); + goto loop; + } + + break; + default: + ut_error; + } + + mops[op]++; + ibuf_dummy_index_free(dummy_index); + } else { + dops[ibuf_rec_get_op_type(rec)]++; } - n_inserts++; - /* Delete the record from ibuf */ if (ibuf_delete_rec(space, page_no, &pcur, search_tuple, &mtr)) { @@ -3378,12 +4465,6 @@ loop: } reset_bit: -#ifdef UNIV_IBUF_COUNT_DEBUG - if (ibuf_count_get(space, page_no) > 0) { - /* btr_print_tree(ibuf_data->index->tree, 100); - ibuf_print(); */ - } -#endif if (UNIV_LIKELY(update_ibuf_bitmap)) { page_t* bitmap_page; @@ -3418,7 +4499,8 @@ reset_bit: mutex_enter(&ibuf_mutex); ibuf->n_merges++; - ibuf->n_merged_recs += n_inserts; + ibuf_add_ops(ibuf->n_merged_ops, mops); + ibuf_add_ops(ibuf->n_discarded_ops, dops); mutex_exit(&ibuf_mutex); @@ -3451,9 +4533,11 @@ ibuf_delete_for_discarded_space( rec_t* ibuf_rec; ulint page_no; ibool closed; - ulint n_inserts; mtr_t mtr; + /* Counts for discarded operations. */ + ulint dops[IBUF_OP_COUNT]; + heap = mem_heap_create(512); /* Use page number 0 to build the search tuple so that we get the @@ -3461,7 +4545,7 @@ ibuf_delete_for_discarded_space( search_tuple = ibuf_new_search_tuple_build(space, 0, heap); - n_inserts = 0; + memset(dops, 0, sizeof(dops)); loop: ibuf_enter(); @@ -3492,7 +4576,7 @@ loop: page_no = ibuf_rec_get_page_no(ibuf_rec); - n_inserts++; + dops[ibuf_rec_get_op_type(ibuf_rec)]++; /* Delete the record from ibuf */ closed = ibuf_delete_rec(space, page_no, &pcur, search_tuple, @@ -3522,10 +4606,7 @@ leave_loop: /* Protect our statistics keeping from race conditions */ mutex_enter(&ibuf_mutex); - - ibuf->n_merges++; - ibuf->n_merged_recs += n_inserts; - + ibuf_add_ops(ibuf->n_discarded_ops, dops); mutex_exit(&ibuf_mutex); ibuf_exit(); @@ -3596,14 +4677,19 @@ ibuf_print( mutex_enter(&ibuf_mutex); fprintf(file, - "Ibuf: size %lu, free list len %lu, seg size %lu,\n" - "%lu inserts, %lu merged recs, %lu merges\n", + "Ibuf: size %lu, free list len %lu," + " seg size %lu, %lu merges\n", (ulong) ibuf->size, (ulong) ibuf->free_list_len, (ulong) ibuf->seg_size, - (ulong) ibuf->n_inserts, - (ulong) ibuf->n_merged_recs, (ulong) ibuf->n_merges); + + fputs("merged operations:\n ", file); + ibuf_print_ops(ibuf->n_merged_ops, file); + + fputs("discarded operations:\n ", file); + ibuf_print_ops(ibuf->n_discarded_ops, file); + #ifdef UNIV_IBUF_COUNT_DEBUG for (i = 0; i < IBUF_COUNT_N_SPACES; i++) { for (j = 0; j < IBUF_COUNT_N_PAGES; j++) { diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index d5c8258513c..cc08cc620c5 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. 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 @@ -68,19 +68,30 @@ enum btr_latch_mode { BTR_MODIFY_PREV = 36 }; +/* BTR_INSERT, BTR_DELETE and BTR_DELETE_MARK are mutually exclusive. */ + /** If this is ORed to btr_latch_mode, it means that the search tuple -will be inserted to the index, at the searched position */ +will be inserted to the index, at the searched position. +When the record is not in the buffer pool, try to use the insert buffer. */ #define BTR_INSERT 512 /** This flag ORed to btr_latch_mode says that we do the search in query optimization */ #define BTR_ESTIMATE 1024 -/** This flag ORed to btr_latch_mode says that we can ignore possible +/** This flag ORed to BTR_INSERT says that we can ignore possible UNIQUE definition on secondary indexes when we decide if we can use the insert buffer to speed up inserts */ #define BTR_IGNORE_SEC_UNIQUE 2048 +/** Try to delete mark the record at the searched position using the +insert/delete buffer when the record is not in the buffer pool. */ +#define BTR_DELETE_MARK 4096 + +/** Try to purge the record at the searched position using the insert/delete +buffer when the record is not in the buffer pool. */ +#define BTR_DELETE 8192 + /**************************************************************//** Gets the root node of a tree and x-latches it. @return root page, x-latched */ @@ -193,6 +204,10 @@ btr_leaf_page_release( mtr_t* mtr); /*!< in: mtr */ /**************************************************************//** Gets the child node file address in a node pointer. +NOTE: the offsets array must contain all offsets for the record since +we read the last field according to offsets and assume that it contains +the child page number. In other words offsets must have been retrieved +with rec_get_offsets(n_fields=ULINT_UNDEFINED). @return child node address */ UNIV_INLINE ulint @@ -317,12 +332,16 @@ Inserts a data tuple to a tree on a non-leaf level. It is assumed that mtr holds an x-latch on the tree. */ UNIV_INTERN void -btr_insert_on_non_leaf_level( -/*=========================*/ +btr_insert_on_non_leaf_level_func( +/*==============================*/ dict_index_t* index, /*!< in: index */ ulint level, /*!< in: level, must be > 0 */ dtuple_t* tuple, /*!< in: the record to be inserted */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr); /*!< in: mtr */ +# define btr_insert_on_non_leaf_level(i,l,t,m) \ + btr_insert_on_non_leaf_level_func(i,l,t,__FILE__,__LINE__,m) #endif /* !UNIV_HOTBACKUP */ /****************************************************************//** Sets a record as the predefined minimum record. */ diff --git a/storage/innobase/include/btr0btr.ic b/storage/innobase/include/btr0btr.ic index 2259d22c9a6..97944cc2e26 100644 --- a/storage/innobase/include/btr0btr.ic +++ b/storage/innobase/include/btr0btr.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. 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 @@ -255,6 +255,10 @@ btr_page_set_prev( /**************************************************************//** Gets the child node file address in a node pointer. +NOTE: the offsets array must contain all offsets for the record since +we read the last field according to offsets and assume that it contains +the child page number. In other words offsets must have been retrieved +with rec_get_offsets(n_fields=ULINT_UNDEFINED). @return child node address */ UNIV_INLINE ulint diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index 480a3877e54..136d2d068a1 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. 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 @@ -138,7 +138,8 @@ btr_cur_search_to_nth_level( should always be made using PAGE_CUR_LE to search the position! */ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ..., ORed with - BTR_INSERT and BTR_ESTIMATE; + at most one of BTR_INSERT, BTR_DELETE_MARK, + BTR_DELETE, or BTR_ESTIMATE; cursor->left_block is used to store a pointer to the left neighbor page, in the cases BTR_SEARCH_PREV and BTR_MODIFY_PREV; @@ -152,29 +153,39 @@ btr_cur_search_to_nth_level( ulint has_search_latch,/*!< in: latch mode the caller currently has on btr_search_latch: RW_S_LATCH, or 0 */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr); /*!< in: mtr */ /*****************************************************************//** Opens a cursor at either end of an index. */ UNIV_INTERN void -btr_cur_open_at_index_side( -/*=======================*/ +btr_cur_open_at_index_side_func( +/*============================*/ ibool from_left, /*!< in: TRUE if open to the low end, FALSE if to the high end */ dict_index_t* index, /*!< in: index */ ulint latch_mode, /*!< in: latch mode */ btr_cur_t* cursor, /*!< in: cursor */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr); /*!< in: mtr */ +#define btr_cur_open_at_index_side(f,i,l,c,m) \ + btr_cur_open_at_index_side_func(f,i,l,c,__FILE__,__LINE__,m) /**********************************************************************//** Positions a cursor at a randomly chosen position within a B-tree. */ UNIV_INTERN void -btr_cur_open_at_rnd_pos( -/*====================*/ +btr_cur_open_at_rnd_pos_func( +/*=========================*/ dict_index_t* index, /*!< in: index */ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */ btr_cur_t* cursor, /*!< in/out: B-tree cursor */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr); /*!< in: mtr */ +#define btr_cur_open_at_rnd_pos(i,l,c,m) \ + btr_cur_open_at_rnd_pos_func(i,l,c,__FILE__,__LINE__,m) /*************************************************************//** Tries to perform an insert to a page in an index tree, next to cursor. It is assumed that mtr holds an x-latch on the page. The operation does @@ -322,19 +333,6 @@ btr_cur_del_mark_set_sec_rec( ibool val, /*!< in: value to set */ que_thr_t* thr, /*!< in: query thread */ mtr_t* mtr); /*!< in: mtr */ -/***********************************************************//** -Clear a secondary index record's delete mark. This function is only -used by the insert buffer insert merge mechanism. */ -UNIV_INTERN -void -btr_cur_del_unmark_for_ibuf( -/*========================*/ - rec_t* rec, /*!< in/out: record to delete unmark */ - page_zip_des_t* page_zip, /*!< in/out: compressed page - corresponding to rec, or NULL - when the tablespace is - uncompressed */ - mtr_t* mtr); /*!< in: mtr */ /*************************************************************//** Tries to compress a page of the tree if it seems useful. It is assumed that mtr holds an x-latch on the tree and on the cursor page. To avoid @@ -586,7 +584,20 @@ btr_push_update_extern_fields( const upd_t* update, /*!< in: update vector */ mem_heap_t* heap) /*!< in: memory heap */ __attribute__((nonnull)); - +/***********************************************************//** +Sets a secondary index record's delete mark to the given value. This +function is only used by the insert buffer merge mechanism. */ +UNIV_INTERN +void +btr_cur_set_deleted_flag_for_ibuf( +/*==============================*/ + rec_t* rec, /*!< in/out: record */ + page_zip_des_t* page_zip, /*!< in/out: compressed page + corresponding to rec, or NULL + when the tablespace is + uncompressed */ + ibool val, /*!< in: value to set */ + mtr_t* mtr); /*!< in: mtr */ /*######################################################################*/ /** In the pessimistic delete, if the page data size drops below this @@ -618,8 +629,13 @@ enum btr_cur_method { hash_node, and might be necessary to update */ BTR_CUR_BINARY, /*!< success using the binary search */ - BTR_CUR_INSERT_TO_IBUF /*!< performed the intended insert to + BTR_CUR_INSERT_TO_IBUF, /*!< performed the intended insert to the insert buffer */ + BTR_CUR_DEL_MARK_IBUF, /*!< performed the intended delete + mark in the insert/delete buffer */ + BTR_CUR_DELETE_IBUF, /*!< performed the intended delete in + the insert/delete buffer */ + BTR_CUR_DELETE_REF /*!< row_purge_poss_sec() failed */ }; /** The tree cursor: the definition appears here only for the compiler @@ -627,6 +643,7 @@ to know struct size! */ struct btr_cur_struct { dict_index_t* index; /*!< index where positioned */ page_cur_t page_cur; /*!< page cursor */ + purge_node_t* purge_node; /*!< purge node, for BTR_DELETE */ buf_block_t* left_block; /*!< this field is used to store a pointer to the left neighbor page, in the cases @@ -683,6 +700,23 @@ struct btr_cur_struct { NULL */ ulint fold; /*!< fold value used in the search if flag is BTR_CUR_HASH */ + /*----- Delete buffering -------*/ + ulint ibuf_cnt; /* in searches done on insert buffer + trees, this contains the "counter" + value (the first two bytes of the + fourth field) extracted from the + page above the leaf page, from the + father node pointer that pointed to + the leaf page. in other words, it + contains the minimum counter value + for records to be inserted on the + chosen leaf page. If for some reason + this can't be read, or if the search + ended on the leftmost leaf page in + the tree (in which case the father + node pointer had the 'minimum + record' flag set), this is + ULINT_UNDEFINED. */ /*------------------------------*/ /* @} */ btr_path_t* path_arr; /*!< in estimating the number of diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h index 12b1375d8b7..2334a266280 100644 --- a/storage/innobase/include/btr0pcur.h +++ b/storage/innobase/include/btr0pcur.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -82,8 +82,8 @@ Initializes and opens a persistent cursor to an index tree. It should be closed with btr_pcur_close. */ UNIV_INLINE void -btr_pcur_open( -/*==========*/ +btr_pcur_open_func( +/*===============*/ dict_index_t* index, /*!< in: index */ const dtuple_t* tuple, /*!< in: tuple on which search done */ ulint mode, /*!< in: PAGE_CUR_L, ...; @@ -94,14 +94,18 @@ btr_pcur_open( record! */ ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */ btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr); /*!< in: mtr */ +#define btr_pcur_open(i,t,md,l,c,m) \ + btr_pcur_open_func(i,t,md,l,c,__FILE__,__LINE__,m) /**************************************************************//** Opens an persistent cursor to an index tree without initializing the cursor. */ UNIV_INLINE void -btr_pcur_open_with_no_init( -/*=======================*/ +btr_pcur_open_with_no_init_func( +/*============================*/ dict_index_t* index, /*!< in: index */ const dtuple_t* tuple, /*!< in: tuple on which search done */ ulint mode, /*!< in: PAGE_CUR_L, ...; @@ -119,7 +123,12 @@ btr_pcur_open_with_no_init( ulint has_search_latch,/*!< in: latch mode the caller currently has on btr_search_latch: RW_S_LATCH, or 0 */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr); /*!< in: mtr */ +#define btr_pcur_open_with_no_init(ix,t,md,l,cur,has,m) \ + btr_pcur_open_with_no_init_func(ix,t,md,l,cur,has,__FILE__,__LINE__,m) + /*****************************************************************//** Opens a persistent cursor at either end of an index. */ UNIV_INLINE @@ -160,8 +169,8 @@ before first in tree. The latching mode must be BTR_SEARCH_LEAF or BTR_MODIFY_LEAF. */ UNIV_INTERN void -btr_pcur_open_on_user_rec( -/*======================*/ +btr_pcur_open_on_user_rec_func( +/*===========================*/ dict_index_t* index, /*!< in: index */ const dtuple_t* tuple, /*!< in: tuple on which search done */ ulint mode, /*!< in: PAGE_CUR_L, ... */ @@ -169,17 +178,25 @@ btr_pcur_open_on_user_rec( BTR_MODIFY_LEAF */ btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr); /*!< in: mtr */ +#define btr_pcur_open_on_user_rec(i,t,md,l,c,m) \ + btr_pcur_open_on_user_rec_func(i,t,md,l,c,__FILE__,__LINE__,m) /**********************************************************************//** Positions a cursor at a randomly chosen position within a B-tree. */ UNIV_INLINE void -btr_pcur_open_at_rnd_pos( -/*=====================*/ +btr_pcur_open_at_rnd_pos_func( +/*==========================*/ dict_index_t* index, /*!< in: index */ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */ btr_pcur_t* cursor, /*!< in/out: B-tree pcur */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr); /*!< in: mtr */ +#define btr_pcur_open_at_rnd_pos(i,l,c,m) \ + btr_pcur_open_at_rnd_pos_func(i,l,c,__FILE__,__LINE__,m) /**************************************************************//** Frees the possible old_rec_buf buffer of a persistent cursor and sets the latch mode of the persistent cursor to BTR_NO_LATCHES. */ @@ -218,11 +235,15 @@ record and it can be restored on a user record whose ordering fields are identical to the ones of the original user record */ UNIV_INTERN ibool -btr_pcur_restore_position( -/*======================*/ +btr_pcur_restore_position_func( +/*===========================*/ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */ btr_pcur_t* cursor, /*!< in: detached persistent cursor */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr); /*!< in: mtr */ +#define btr_pcur_restore_position(l,cur,mtr) \ + btr_pcur_restore_position_func(l,cur,__FILE__,__LINE__,mtr) /**************************************************************//** If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY, releases the page latch and bufferfix reserved by the cursor. @@ -260,20 +281,13 @@ btr_pcur_get_mtr( /*=============*/ btr_pcur_t* cursor); /*!< in: persistent cursor */ /**************************************************************//** -Commits the pcur mtr and sets the pcur latch mode to BTR_NO_LATCHES, +Commits the mtr and sets the pcur latch mode to BTR_NO_LATCHES, that is, the cursor becomes detached. If there have been modifications to the page where pcur is positioned, this can be used instead of btr_pcur_release_leaf. Function btr_pcur_store_position should be used before calling this, if restoration of cursor is wanted later. */ UNIV_INLINE void -btr_pcur_commit( -/*============*/ - btr_pcur_t* pcur); /*!< in: persistent cursor */ -/**************************************************************//** -Differs from btr_pcur_commit in that we can specify the mtr to commit. */ -UNIV_INLINE -void btr_pcur_commit_specify_mtr( /*========================*/ btr_pcur_t* pcur, /*!< in: persistent cursor */ diff --git a/storage/innobase/include/btr0pcur.ic b/storage/innobase/include/btr0pcur.ic index 0ca7223f861..0c38797e6c5 100644 --- a/storage/innobase/include/btr0pcur.ic +++ b/storage/innobase/include/btr0pcur.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -395,30 +395,13 @@ btr_pcur_move_to_next( } /**************************************************************//** -Commits the pcur mtr and sets the pcur latch mode to BTR_NO_LATCHES, +Commits the mtr and sets the pcur latch mode to BTR_NO_LATCHES, that is, the cursor becomes detached. If there have been modifications to the page where pcur is positioned, this can be used instead of btr_pcur_release_leaf. Function btr_pcur_store_position should be used before calling this, if restoration of cursor is wanted later. */ UNIV_INLINE void -btr_pcur_commit( -/*============*/ - btr_pcur_t* pcur) /*!< in: persistent cursor */ -{ - ut_a(pcur->pos_state == BTR_PCUR_IS_POSITIONED); - - pcur->latch_mode = BTR_NO_LATCHES; - - mtr_commit(pcur->mtr); - - pcur->pos_state = BTR_PCUR_WAS_POSITIONED; -} - -/**************************************************************//** -Differs from btr_pcur_commit in that we can specify the mtr to commit. */ -UNIV_INLINE -void btr_pcur_commit_specify_mtr( /*========================*/ btr_pcur_t* pcur, /*!< in: persistent cursor */ @@ -483,8 +466,8 @@ Initializes and opens a persistent cursor to an index tree. It should be closed with btr_pcur_close. */ UNIV_INLINE void -btr_pcur_open( -/*==========*/ +btr_pcur_open_func( +/*===============*/ dict_index_t* index, /*!< in: index */ const dtuple_t* tuple, /*!< in: tuple on which search done */ ulint mode, /*!< in: PAGE_CUR_L, ...; @@ -495,6 +478,8 @@ btr_pcur_open( record! */ ulint latch_mode,/*!< in: BTR_SEARCH_LEAF, ... */ btr_pcur_t* cursor, /*!< in: memory buffer for persistent cursor */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mtr */ { btr_cur_t* btr_cursor; @@ -511,7 +496,7 @@ btr_pcur_open( btr_cursor = btr_pcur_get_btr_cur(cursor); btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode, - btr_cursor, 0, mtr); + btr_cursor, 0, file, line, mtr); cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->trx_if_known = NULL; @@ -522,8 +507,8 @@ Opens an persistent cursor to an index tree without initializing the cursor. */ UNIV_INLINE void -btr_pcur_open_with_no_init( -/*=======================*/ +btr_pcur_open_with_no_init_func( +/*============================*/ dict_index_t* index, /*!< in: index */ const dtuple_t* tuple, /*!< in: tuple on which search done */ ulint mode, /*!< in: PAGE_CUR_L, ...; @@ -541,6 +526,8 @@ btr_pcur_open_with_no_init( ulint has_search_latch,/*!< in: latch mode the caller currently has on btr_search_latch: RW_S_LATCH, or 0 */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mtr */ { btr_cur_t* btr_cursor; @@ -553,7 +540,8 @@ btr_pcur_open_with_no_init( btr_cursor = btr_pcur_get_btr_cur(cursor); btr_cur_search_to_nth_level(index, 0, tuple, mode, latch_mode, - btr_cursor, has_search_latch, mtr); + btr_cursor, has_search_latch, + file, line, mtr); cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; @@ -600,11 +588,13 @@ btr_pcur_open_at_index_side( Positions a cursor at a randomly chosen position within a B-tree. */ UNIV_INLINE void -btr_pcur_open_at_rnd_pos( -/*=====================*/ +btr_pcur_open_at_rnd_pos_func( +/*==========================*/ dict_index_t* index, /*!< in: index */ ulint latch_mode, /*!< in: BTR_SEARCH_LEAF, ... */ btr_pcur_t* cursor, /*!< in/out: B-tree pcur */ + const char* file, /*!< in: file name */ + ulint line, /*!< in: line where called */ mtr_t* mtr) /*!< in: mtr */ { /* Initialize the cursor */ @@ -614,8 +604,9 @@ btr_pcur_open_at_rnd_pos( btr_pcur_init(cursor); - btr_cur_open_at_rnd_pos(index, latch_mode, - btr_pcur_get_btr_cur(cursor), mtr); + btr_cur_open_at_rnd_pos_func(index, latch_mode, + btr_pcur_get_btr_cur(cursor), + file, line, mtr); cursor->pos_state = BTR_PCUR_IS_POSITIONED; cursor->old_stored = BTR_PCUR_OLD_NOT_STORED; diff --git a/storage/innobase/include/buf0buddy.h b/storage/innobase/include/buf0buddy.h index 7648950d5d1..03588d18197 100644 --- a/storage/innobase/include/buf0buddy.h +++ b/storage/innobase/include/buf0buddy.h @@ -36,22 +36,24 @@ Created December 2006 by Marko Makela /**********************************************************************//** Allocate a block. The thread calling this function must hold -buf_pool_mutex and must not hold buf_pool_zip_mutex or any -block->mutex. The buf_pool_mutex may only be released and reacquired +buf_pool->mutex and must not hold buf_pool_zip_mutex or any +block->mutex. The buf_pool->mutex may only be released and reacquired if lru != NULL. This function should only be used for allocating compressed page frames or control blocks (buf_page_t). Allocated control blocks must be properly initialized immediately after buf_buddy_alloc() has returned the memory, before releasing -buf_pool_mutex. +buf_pool->mutex. @return allocated block, possibly NULL if lru == NULL */ UNIV_INLINE void* buf_buddy_alloc( /*============*/ + buf_pool_t* buf_pool, + /*!< buffer pool in which the block resides */ ulint size, /*!< in: block size, up to UNIV_PAGE_SIZE */ ibool* lru) /*!< in: pointer to a variable that will be assigned TRUE if storage was allocated from the LRU list - and buf_pool_mutex was temporarily released, + and buf_pool->mutex was temporarily released, or NULL if the LRU list should not be used */ __attribute__((malloc)); @@ -61,28 +63,13 @@ UNIV_INLINE void buf_buddy_free( /*===========*/ + buf_pool_t* buf_pool, + /*!< buffer pool in which the block resides */ void* buf, /*!< in: block to be freed, must not be pointed to by the buffer pool */ ulint size) /*!< in: block size, up to UNIV_PAGE_SIZE */ __attribute__((nonnull)); -/** Statistics of buddy blocks of a given size. */ -struct buf_buddy_stat_struct { - /** Number of blocks allocated from the buddy system. */ - ulint used; - /** Number of blocks relocated by the buddy system. */ - ib_uint64_t relocated; - /** Total duration of block relocations, in microseconds. */ - ib_uint64_t relocated_usec; -}; - -/** Statistics of buddy blocks of a given size. */ -typedef struct buf_buddy_stat_struct buf_buddy_stat_t; - -/** Statistics of the buddy system, indexed by block size. -Protected by buf_pool_mutex. */ -extern buf_buddy_stat_t buf_buddy_stat[BUF_BUDDY_SIZES + 1]; - #ifndef UNIV_NONINL # include "buf0buddy.ic" #endif diff --git a/storage/innobase/include/buf0buddy.ic b/storage/innobase/include/buf0buddy.ic index c419a2374d9..387eacc754a 100644 --- a/storage/innobase/include/buf0buddy.ic +++ b/storage/innobase/include/buf0buddy.ic @@ -35,18 +35,20 @@ Created December 2006 by Marko Makela /**********************************************************************//** Allocate a block. The thread calling this function must hold -buf_pool_mutex and must not hold buf_pool_zip_mutex or any block->mutex. -The buf_pool_mutex may only be released and reacquired if lru != NULL. +buf_pool->mutex and must not hold buf_pool_zip_mutex or any block->mutex. +The buf_pool->mutex may only be released and reacquired if lru != NULL. @return allocated block, possibly NULL if lru==NULL */ UNIV_INTERN void* buf_buddy_alloc_low( /*================*/ + buf_pool_t* buf_pool, + /*!< in: buffer pool in which the page resides */ ulint i, /*!< in: index of buf_pool->zip_free[], or BUF_BUDDY_SIZES */ ibool* lru) /*!< in: pointer to a variable that will be assigned TRUE if storage was allocated from the LRU list - and buf_pool_mutex was temporarily released, + and buf_pool->mutex was temporarily released, or NULL if the LRU list should not be used */ __attribute__((malloc)); @@ -56,10 +58,11 @@ UNIV_INTERN void buf_buddy_free_low( /*===============*/ - void* buf, /*!< in: block to be freed, must not be - pointed to by the buffer pool */ - ulint i) /*!< in: index of buf_pool->zip_free[], - or BUF_BUDDY_SIZES */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + void* buf, /*!< in: block to be freed, must not be + pointed to by the buffer pool */ + ulint i) /*!< in: index of buf_pool->zip_free[], + or BUF_BUDDY_SIZES */ __attribute__((nonnull)); /**********************************************************************//** @@ -83,27 +86,32 @@ buf_buddy_get_slot( /**********************************************************************//** Allocate a block. The thread calling this function must hold -buf_pool_mutex and must not hold buf_pool_zip_mutex or any -block->mutex. The buf_pool_mutex may only be released and reacquired +buf_pool->mutex and must not hold buf_pool_zip_mutex or any +block->mutex. The buf_pool->mutex may only be released and reacquired if lru != NULL. This function should only be used for allocating compressed page frames or control blocks (buf_page_t). Allocated control blocks must be properly initialized immediately after buf_buddy_alloc() has returned the memory, before releasing -buf_pool_mutex. +buf_pool->mutex. @return allocated block, possibly NULL if lru == NULL */ UNIV_INLINE void* buf_buddy_alloc( /*============*/ - ulint size, /*!< in: block size, up to UNIV_PAGE_SIZE */ - ibool* lru) /*!< in: pointer to a variable that will be assigned - TRUE if storage was allocated from the LRU list - and buf_pool_mutex was temporarily released, - or NULL if the LRU list should not be used */ + buf_pool_t* buf_pool, /*!< in: buffer pool in which + the page resides */ + ulint size, /*!< in: block size, up to + UNIV_PAGE_SIZE */ + ibool* lru) /*!< in: pointer to a variable + that will be assigned TRUE if + storage was allocated from the + LRU list and buf_pool->mutex was + temporarily released, or NULL if + the LRU list should not be used */ { - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); - return(buf_buddy_alloc_low(buf_buddy_get_slot(size), lru)); + return(buf_buddy_alloc_low(buf_pool, buf_buddy_get_slot(size), lru)); } /**********************************************************************//** @@ -112,13 +120,15 @@ UNIV_INLINE void buf_buddy_free( /*===========*/ - void* buf, /*!< in: block to be freed, must not be - pointed to by the buffer pool */ - ulint size) /*!< in: block size, up to UNIV_PAGE_SIZE */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + void* buf, /*!< in: block to be freed, must not be + pointed to by the buffer pool */ + ulint size) /*!< in: block size, up to + UNIV_PAGE_SIZE */ { - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); - buf_buddy_free_low(buf, buf_buddy_get_slot(size)); + buf_buddy_free_low(buf_pool, buf, buf_buddy_get_slot(size)); } #ifdef UNIV_MATERIALIZE diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 927ff893e39..5326ca9c14f 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. 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 @@ -34,6 +34,7 @@ Created 11/5/1995 Heikki Tuuri #include "ut0byte.h" #include "page0types.h" #ifndef UNIV_HOTBACKUP +#include "ut0rbt.h" #include "os0proc.h" /** @name Modes for buf_page_get_gen */ @@ -46,6 +47,10 @@ Created 11/5/1995 Heikki Tuuri it is error-prone programming not to set a latch, and it should be used with care */ +#define BUF_GET_IF_IN_POOL_OR_WATCH 15 + /*!< Get the page only if it's in the + buffer pool, if not then set a watch + on the page. */ /* @} */ /** @name Modes for buf_page_get_known_nowait */ /* @{ */ @@ -58,7 +63,14 @@ Created 11/5/1995 Heikki Tuuri position of the block. */ /* @} */ -extern buf_pool_t* buf_pool; /*!< The buffer pool of the database */ +#define MAX_BUFFER_POOLS 64 /*!< The maximum number of buffer + pools that can be defined */ + +#define BUF_POOL_WATCH_SIZE 1 /*!< Maximum number of concurrent + buffer pool watches */ + +extern buf_pool_t* buf_pool_ptr[MAX_BUFFER_POOLS]; /*!< The buffer pools + of the database */ #ifdef UNIV_DEBUG extern ibool buf_debug_prints;/*!< If this is set TRUE, the program prints info whenever read or flush @@ -66,6 +78,8 @@ extern ibool buf_debug_prints;/*!< If this is set TRUE, the program #endif /* UNIV_DEBUG */ extern ulint srv_buf_pool_write_requests; /*!< variable to count write request issued */ +extern ulint srv_buf_pool_instances; +extern ulint srv_buf_pool_curr_size; #else /* !UNIV_HOTBACKUP */ extern buf_block_t* back_block1; /*!< first block, for --apply-log */ extern buf_block_t* back_block2; /*!< second block, for page reorganize */ @@ -81,6 +95,8 @@ The enumeration values must be 0..7. */ enum buf_page_state { BUF_BLOCK_ZIP_FREE = 0, /*!< contains a free compressed page */ + BUF_BLOCK_POOL_WATCH = 0, /*!< a sentinel for the buffer pool + watch, element of buf_pool_watch[] */ BUF_BLOCK_ZIP_PAGE, /*!< contains a clean compressed page */ BUF_BLOCK_ZIP_DIRTY, /*!< contains a compressed @@ -102,19 +118,36 @@ enum buf_page_state { #ifndef UNIV_HOTBACKUP /********************************************************************//** +Acquire mutex on all buffer pool instances */ +UNIV_INLINE +void +buf_pool_mutex_enter_all(void); +/*===========================*/ + +/********************************************************************//** +Release mutex on all buffer pool instances */ +UNIV_INLINE +void +buf_pool_mutex_exit_all(void); +/*==========================*/ + +/********************************************************************//** Creates the buffer pool. @return own: buf_pool object, NULL if not enough memory or error */ UNIV_INTERN -buf_pool_t* -buf_pool_init(void); -/*===============*/ +ulint +buf_pool_init( +/*=========*/ + ulint size, /*!< in: Size of the total pool in bytes */ + ulint n_instances); /*!< in: Number of instances */ /********************************************************************//** Frees the buffer pool at shutdown. This must not be invoked before freeing all mutexes. */ UNIV_INTERN void -buf_pool_free(void); -/*===============*/ +buf_pool_free( +/*==========*/ + ulint n_instances); /*!< in: numbere of instances to free */ /********************************************************************//** Drops the adaptive hash index. To prevent a livelock, this function @@ -151,23 +184,31 @@ UNIV_INLINE ulint buf_pool_get_curr_size(void); /*========================*/ +/*********************************************************************//** +Gets the current size of buffer buf_pool in frames. +@return size in pages */ +UNIV_INLINE +ulint +buf_pool_get_n_pages(void); +/*=======================*/ /********************************************************************//** Gets the smallest oldest_modification lsn for any page in the pool. Returns zero if all modified pages have been flushed to disk. @return oldest modification in pool, zero if none */ -UNIV_INLINE +UNIV_INTERN ib_uint64_t buf_pool_get_oldest_modification(void); /*==================================*/ /********************************************************************//** Allocates a buffer block. @return own: the allocated block, in state BUF_BLOCK_MEMORY */ -UNIV_INLINE +UNIV_INTERN buf_block_t* buf_block_alloc( /*============*/ - ulint zip_size); /*!< in: compressed page size in bytes, - or 0 if uncompressed tablespace */ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + ulint zip_size); /*!< in: compressed page size in bytes, + or 0 if uncompressed tablespace */ /********************************************************************//** Frees a buffer block which does not contain a file page. */ UNIV_INLINE @@ -202,20 +243,14 @@ with care. */ #define buf_page_get_with_no_latch(SP, ZS, OF, MTR) buf_page_get_gen(\ SP, ZS, OF, RW_NO_LATCH, NULL,\ BUF_GET_NO_LATCH, __FILE__, __LINE__, MTR) -/**************************************************************//** -NOTE! The following macros should be used instead of -buf_page_optimistic_get_func, to improve debugging. Only values RW_S_LATCH and -RW_X_LATCH are allowed as LA! */ -#define buf_page_optimistic_get(LA, BL, MC, MTR) \ - buf_page_optimistic_get_func(LA, BL, MC, __FILE__, __LINE__, MTR) /********************************************************************//** This is the general function used to get optimistic access to a database page. @return TRUE if success */ UNIV_INTERN ibool -buf_page_optimistic_get_func( -/*=========================*/ +buf_page_optimistic_get( +/*====================*/ ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH */ buf_block_t* block, /*!< in: guessed block */ ib_uint64_t modify_clock,/*!< in: modify clock value if mode is @@ -291,7 +326,8 @@ buf_page_get_gen( ulint rw_latch,/*!< in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ buf_block_t* guess, /*!< in: guessed block or NULL */ ulint mode, /*!< in: BUF_GET, BUF_GET_IF_IN_POOL, - BUF_GET_NO_LATCH */ + BUF_GET_NO_LATCH or + BUF_GET_IF_IN_POOL_OR_WATCH */ const char* file, /*!< in: file name */ ulint line, /*!< in: line where called */ mtr_t* mtr); /*!< in: mini-transaction */ @@ -341,9 +377,8 @@ void buf_page_release( /*=============*/ buf_block_t* block, /*!< in: buffer block */ - ulint rw_latch, /*!< in: RW_S_LATCH, RW_X_LATCH, + ulint rw_latch); /*!< in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ - mtr_t* mtr); /*!< in: mtr */ /********************************************************************//** Moves a page to the start of the buffer pool LRU list. This high-level function can be used to prevent an important page from slipping out of @@ -453,7 +488,7 @@ buf_page_get_newest_modification( page frame */ /********************************************************************//** Increments the modify clock of a frame by 1. The caller must (1) own the -buf_pool mutex and block bufferfix count has to be zero, (2) or own an x-lock +buf_pool->mutex and block bufferfix count has to be zero, (2) or own an x-lock on the block. */ UNIV_INLINE void @@ -535,7 +570,8 @@ UNIV_INTERN buf_block_t* buf_pool_contains_zip( /*==================*/ - const void* data); /*!< in: pointer to compressed page */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + const void* data); /*!< in: pointer to compressed page */ #endif /* UNIV_DEBUG */ #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /*********************************************************************//** @@ -609,8 +645,15 @@ buf_get_modified_ratio_pct(void); Refreshes the statistics used to print per-second averages. */ UNIV_INTERN void -buf_refresh_io_stats(void); -/*======================*/ +buf_refresh_io_stats( +/*=================*/ + buf_pool_t* buf_pool); /*!< buffer pool instance */ +/**********************************************************************//** +Refreshes the statistics used to print per-second averages. */ +UNIV_INTERN +void +buf_refresh_io_stats_all(void); +/*=================*/ /*********************************************************************//** Asserts that all file pages in the buffer are in a replaceable state. @return TRUE */ @@ -991,14 +1034,62 @@ buf_page_address_fold( ulint offset) /*!< in: offset of the page within space */ __attribute__((const)); /******************************************************************//** +Returns the buffer pool instance given a page instance +@return buf_pool */ +UNIV_INLINE +buf_pool_t* +buf_pool_from_bpage( +/*================*/ + const buf_page_t* bpage); /*!< in: buffer pool page */ +/******************************************************************//** +Returns the buffer pool instance given a block instance +@return buf_pool */ +UNIV_INLINE +buf_pool_t* +buf_pool_from_block( +/*================*/ + const buf_block_t* block); /*!< in: block */ +/******************************************************************//** +Returns the buffer pool instance given space and offset of page +@return buffer pool */ +UNIV_INLINE +buf_pool_t* +buf_pool_get( +/*==========*/ + ulint space, /*!< in: space id */ + ulint offset);/*!< in: offset of the page within space */ +/******************************************************************//** +Returns the buffer pool instance given its array index +@return buffer pool */ +UNIV_INLINE +buf_pool_t* +buf_pool_from_array( +/*====================*/ + ulint index); /*!< in: array index to get buffer pool instance from */ +/******************************************************************//** Returns the control block of a file page, NULL if not found. @return block, NULL if not found */ UNIV_INLINE buf_page_t* +buf_page_hash_get_low( +/*==================*/ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + ulint space, /*!< in: space id */ + ulint offset, /*!< in: offset of the page + within space */ + ulint fold); /*!< in: buf_page_address_fold( + space, offset) */ +/******************************************************************//** +Returns the control block of a file page, NULL if not found. +@return block, NULL if not found or not a real control block */ +UNIV_INLINE +buf_page_t* buf_page_hash_get( /*==============*/ - ulint space, /*!< in: space id */ - ulint offset);/*!< in: offset of the page within space */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint space, /*!< in: space id */ + ulint offset); /*!< in: offset of the page + within space */ /******************************************************************//** Returns the control block of a file page, NULL if not found or an uncompressed page frame does not exist. @@ -1007,8 +1098,10 @@ UNIV_INLINE buf_block_t* buf_block_hash_get( /*===============*/ - ulint space, /*!< in: space id */ - ulint offset);/*!< in: offset of the page within space */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint space, /*!< in: space id */ + ulint offset); /*!< in: offset of the page + within space */ /*********************************************************************//** Gets the current length of the free list of buffer blocks. @return length of the free list */ @@ -1016,8 +1109,67 @@ UNIV_INTERN ulint buf_get_free_list_len(void); /*=======================*/ -#endif /* !UNIV_HOTBACKUP */ +/******************************************************************** +Determine if a block is a sentinel for a buffer pool watch. +@return TRUE if a sentinel for a buffer pool watch, FALSE if not */ +UNIV_INTERN +ibool +buf_pool_watch_is_sentinel( +/*=======================*/ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + const buf_page_t* bpage) /*!< in: block */ + __attribute__((nonnull, warn_unused_result)); +/****************************************************************//** +Add watch for the given page to be read in. Caller must have the buffer pool +@return NULL if watch set, block if the page is in the buffer pool */ +UNIV_INTERN +buf_page_t* +buf_pool_watch_set( +/*===============*/ + ulint space, /*!< in: space id */ + ulint offset, /*!< in: page number */ + ulint fold) /*!< in: buf_page_address_fold(space, offset) */ + __attribute__((warn_unused_result)); +/****************************************************************//** +Stop watching if the page has been read in. +buf_pool_watch_set(space,offset) must have returned NULL before. */ +UNIV_INTERN +void +buf_pool_watch_unset( +/*=================*/ + ulint space, /*!< in: space id */ + ulint offset);/*!< in: page number */ +/****************************************************************//** +Check if the page has been read in. +This may only be called after buf_pool_watch_set(space,offset) +has returned NULL and before invoking buf_pool_watch_unset(space,offset). +@return FALSE if the given page was not read in, TRUE if it was */ +UNIV_INTERN +ibool +buf_pool_watch_occurred( +/*====================*/ + ulint space, /*!< in: space id */ + ulint offset) /*!< in: page number */ + __attribute__((warn_unused_result)); +/********************************************************************//** +Get total buffer pool statistics. */ +UNIV_INTERN +void +buf_get_total_list_len( +/*===================*/ + ulint* LRU_len, /*!< out: length of all LRU lists */ + ulint* free_len, /*!< out: length of all free lists */ + ulint* flush_list_len);/*!< out: length of all flush lists */ +/********************************************************************//** +Get total buffer pool statistics. */ +UNIV_INTERN +void +buf_get_total_stat( +/*===============*/ + buf_pool_stat_t*tot_stat); /*!< out: buffer pool stats */ + +#endif /* !UNIV_HOTBACKUP */ /** The common buffer control block structure for compressed and uncompressed frames */ @@ -1026,18 +1178,18 @@ struct buf_page_struct{ /** @name General fields None of these bit-fields must be modified without holding buf_page_get_mutex() [buf_block_struct::mutex or - buf_pool_zip_mutex], since they can be stored in the same + buf_pool->zip_mutex], since they can be stored in the same machine word. Some of these fields are additionally protected - by buf_pool_mutex. */ + by buf_pool->mutex. */ /* @{ */ unsigned space:32; /*!< tablespace id; also protected - by buf_pool_mutex. */ + by buf_pool->mutex. */ unsigned offset:32; /*!< page number; also protected - by buf_pool_mutex. */ + by buf_pool->mutex. */ unsigned state:3; /*!< state of the control block; also - protected by buf_pool_mutex. + protected by buf_pool->mutex. State transitions from BUF_BLOCK_READY_FOR_USE to BUF_BLOCK_MEMORY need not be @@ -1049,7 +1201,7 @@ struct buf_page_struct{ flush_type. @see enum buf_flush */ unsigned io_fix:2; /*!< type of pending I/O operation; - also protected by buf_pool_mutex + also protected by buf_pool->mutex @see enum buf_io_fix */ unsigned buf_fix_count:25;/*!< count of how manyfold this block is currently bufferfixed */ @@ -1057,7 +1209,10 @@ struct buf_page_struct{ #endif /* !UNIV_HOTBACKUP */ page_zip_des_t zip; /*!< compressed page; zip.data (but not the data it points to) is - also protected by buf_pool_mutex */ + also protected by buf_pool_mutex; + state == BUF_BLOCK_ZIP_PAGE and + zip.data == NULL means an active + buf_pool_watch */ #ifndef UNIV_HOTBACKUP buf_page_t* hash; /*!< node used in chaining to buf_pool->page_hash or @@ -1073,8 +1228,9 @@ struct buf_page_struct{ UT_LIST_NODE_T(buf_page_t) list; /*!< based on state, this is a - list node, protected only by - buf_pool_mutex, in one of the + list node, protected either by + buf_pool_mutex or by + flush_list_mutex, in one of the following lists in buf_pool: - BUF_BLOCK_NOT_USED: free @@ -1083,6 +1239,12 @@ struct buf_page_struct{ - BUF_BLOCK_ZIP_PAGE: zip_clean - BUF_BLOCK_ZIP_FREE: zip_free[] + If bpage is part of flush_list + then the node pointers are + covered by flush_list_mutex. + Otherwise these pointers are + protected by buf_pool_mutex. + The contents of the list node is undefined if !in_flush_list && state == BUF_BLOCK_FILE_PAGE, @@ -1093,10 +1255,15 @@ struct buf_page_struct{ #ifdef UNIV_DEBUG ibool in_flush_list; /*!< TRUE if in buf_pool->flush_list; - when buf_pool_mutex is free, the + when flush_list_mutex is free, the following should hold: in_flush_list == (state == BUF_BLOCK_FILE_PAGE - || state == BUF_BLOCK_ZIP_DIRTY) */ + || state == BUF_BLOCK_ZIP_DIRTY) + Writes to this field must be + covered by both block->mutex + and flush_list_mutex. Hence + reads can happen while holding + any one of the two mutexes */ ibool in_free_list; /*!< TRUE if in buf_pool->free; when buf_pool_mutex is free, the following should hold: in_free_list @@ -1106,7 +1273,8 @@ struct buf_page_struct{ /*!< log sequence number of the youngest modification to this block, zero if not - modified */ + modified. Protected by block + mutex */ ib_uint64_t oldest_modification; /*!< log sequence number of the START of the log entry @@ -1114,11 +1282,16 @@ struct buf_page_struct{ modification to this block which has not yet been flushed on disk; zero if all - modifications are on disk */ + modifications are on disk. + Writes to this field must be + covered by both block->mutex + and flush_list_mutex. Hence + reads can happen while holding + any one of the two mutexes */ /* @} */ /** @name LRU replacement algorithm fields - These fields are protected by buf_pool_mutex only (not - buf_pool_zip_mutex or buf_block_struct::mutex). */ + These fields are protected by buf_pool->mutex only (not + buf_pool->zip_mutex or buf_block_struct::mutex). */ /* @{ */ UT_LIST_NODE_T(buf_page_t) LRU; @@ -1148,6 +1321,8 @@ struct buf_page_struct{ frees a page in buffer pool */ # endif /* UNIV_DEBUG_FILE_ACCESSES */ #endif /* !UNIV_HOTBACKUP */ + buf_pool_t* buf_pool; /*!< buffer pool instance this + page belongs to */ }; /** The buffer control block structure */ @@ -1185,15 +1360,21 @@ struct buf_block_struct{ rw_lock_t lock; /*!< read-write lock of the buffer frame */ unsigned lock_hash_val:32;/*!< hashed value of the page address - in the record lock hash table */ - unsigned check_index_page_at_flush:1; + in the record lock hash table; + protected by buf_block_t::lock + (or buf_block_t::mutex, buf_pool->mutex + in buf_page_get_gen(), + buf_page_init_for_read() + and buf_page_create()) */ + ibool check_index_page_at_flush; /*!< TRUE if we know that this is an index page, and want the database to check its consistency before flush; note that there may be pages in the buffer pool which are index pages, but this flag is not set because - we do not keep track of all pages */ + we do not keep track of all pages; + NOT protected by any mutex */ /* @} */ /** @name Optimistic search field */ /* @{ */ @@ -1310,6 +1491,16 @@ struct buf_pool_stat_struct{ buf_page_peek_if_too_old() */ }; +/** Statistics of buddy blocks of a given size. */ +struct buf_buddy_stat_struct { + /** Number of blocks allocated from the buddy system. */ + ulint used; + /** Number of blocks relocated by the buddy system. */ + ib_uint64_t relocated; + /** Total duration of block relocations, in microseconds. */ + ib_uint64_t relocated_usec; +}; + /** @brief The buffer pool structure. NOTE! The definition appears here only for other modules of this @@ -1319,7 +1510,25 @@ struct buf_pool_struct{ /** @name General fields */ /* @{ */ - + mutex_t mutex; /*!< Buffer pool mutex of this + instance */ + mutex_t zip_mutex; /*!< Zip mutex of this buffer + pool instance, protects compressed + only pages (of type buf_page_t, not + buf_block_t */ + ulint instance_no; /*!< Array index of this buffer + pool instance */ + ulint old_pool_size; /*!< Old pool size in bytes */ + ulint curr_pool_size; /*!< Current pool size in bytes */ + ulint LRU_old_ratio; /*!< Reserve this much of the buffer + pool for "old" blocks */ +#ifdef UNIV_DEBUG + ulint buddy_n_frames; /*!< Number of frames allocated from + the buffer pool to the buddy system */ +#endif +#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG + ulint mutex_exit_forbidden; /*!< Forbid release mutex */ +#endif ulint n_chunks; /*!< number of buffer pool chunks */ buf_chunk_t* chunks; /*!< buffer pool chunks */ ulint curr_size; /*!< current pool size in pages */ @@ -1331,12 +1540,16 @@ struct buf_pool_struct{ whose frames are allocated to the zip buddy system, indexed by block->frame */ - ulint n_pend_reads; /*!< number of pending read operations */ + ulint n_pend_reads; /*!< number of pending read + operations */ ulint n_pend_unzip; /*!< number of pending decompressions */ time_t last_printout_time; /*!< when buf_print_io was last time called */ + buf_buddy_stat_t buddy_stat[BUF_BUDDY_SIZES + 1]; + /*!< Statistics of buddy system, + indexed by block size */ buf_pool_stat_t stat; /*!< current statistics */ buf_pool_stat_t old_stat; /*!< old statistics */ @@ -1346,6 +1559,13 @@ struct buf_pool_struct{ /* @{ */ + mutex_t flush_list_mutex;/*!< mutex protecting the + flush list access. This mutex + protects flush_list, flush_rbt + and bpage::list pointers when + the bpage is on flush_list. It + also protects writes to + bpage::oldest_modification */ UT_LIST_BASE_NODE_T(buf_page_t) flush_list; /*!< base node of the modified block list */ @@ -1359,6 +1579,20 @@ struct buf_pool_struct{ /*!< this is in the set state when there is no flush batch of the given type running */ + ib_rbt_t* flush_rbt; /*!< a red-black tree is used + exclusively during recovery to + speed up insertions in the + flush_list. This tree contains + blocks in order of + oldest_modification LSN and is + kept in sync with the + flush_list. + Each member of the tree MUST + also be on the flush_list. + This tree is relevant only in + recovery and is set to NULL + once the recovery is over. + Protected by flush_list_mutex */ ulint freed_page_clock;/*!< a sequence number used to count the number of buffer blocks removed from the end of @@ -1372,8 +1606,8 @@ struct buf_pool_struct{ this is incremented by one; this is set to zero when a buffer block is allocated */ - /* @} */ + /** @name LRU replacement algorithm fields */ /* @{ */ @@ -1411,6 +1645,12 @@ struct buf_pool_struct{ /*!< unmodified compressed pages */ UT_LIST_BASE_NODE_T(buf_page_t) zip_free[BUF_BUDDY_SIZES]; /*!< buddy free lists */ + + buf_page_t watch[BUF_POOL_WATCH_SIZE]; + /*!< Sentinel records for buffer + pool watches. Protected by + buf_pool->mutex. */ + #if BUF_BUDDY_HIGH != UNIV_PAGE_SIZE # error "BUF_BUDDY_HIGH != UNIV_PAGE_SIZE" #endif @@ -1432,40 +1672,51 @@ Use these instead of accessing buf_pool_mutex directly. */ /* @{ */ /** Test if buf_pool_mutex is owned. */ -#define buf_pool_mutex_own() mutex_own(&buf_pool_mutex) +#define buf_pool_mutex_own(b) mutex_own(&b->mutex) /** Acquire the buffer pool mutex. */ -#define buf_pool_mutex_enter() do { \ - ut_ad(!mutex_own(&buf_pool_zip_mutex)); \ - mutex_enter(&buf_pool_mutex); \ +#define buf_pool_mutex_enter(b) do { \ + ut_ad(!mutex_own(&b->zip_mutex)); \ + mutex_enter(&b->mutex); \ } while (0) +/** Test if flush list mutex is owned. */ +#define buf_flush_list_mutex_own(b) mutex_own(&b->flush_list_mutex) + +/** Acquire the flush list mutex. */ +#define buf_flush_list_mutex_enter(b) do { \ + mutex_enter(&b->flush_list_mutex); \ +} while (0) +/** Release the flush list mutex. */ +# define buf_flush_list_mutex_exit(b) do { \ + mutex_exit(&b->flush_list_mutex); \ +} while (0) + + + #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG -/** Flag to forbid the release of the buffer pool mutex. -Protected by buf_pool_mutex. */ -extern ulint buf_pool_mutex_exit_forbidden; /** Forbid the release of the buffer pool mutex. */ -# define buf_pool_mutex_exit_forbid() do { \ - ut_ad(buf_pool_mutex_own()); \ - buf_pool_mutex_exit_forbidden++; \ +# define buf_pool_mutex_exit_forbid(b) do { \ + ut_ad(buf_pool_mutex_own(b)); \ + b->mutex_exit_forbidden++; \ } while (0) /** Allow the release of the buffer pool mutex. */ -# define buf_pool_mutex_exit_allow() do { \ - ut_ad(buf_pool_mutex_own()); \ - ut_a(buf_pool_mutex_exit_forbidden); \ - buf_pool_mutex_exit_forbidden--; \ +# define buf_pool_mutex_exit_allow(b) do { \ + ut_ad(buf_pool_mutex_own(b)); \ + ut_a(b->mutex_exit_forbidden); \ + b->mutex_exit_forbidden--; \ } while (0) /** Release the buffer pool mutex. */ -# define buf_pool_mutex_exit() do { \ - ut_a(!buf_pool_mutex_exit_forbidden); \ - mutex_exit(&buf_pool_mutex); \ +# define buf_pool_mutex_exit(b) do { \ + ut_a(!b->mutex_exit_forbidden); \ + mutex_exit(&b->mutex); \ } while (0) #else /** Forbid the release of the buffer pool mutex. */ -# define buf_pool_mutex_exit_forbid() ((void) 0) +# define buf_pool_mutex_exit_forbid(b) ((void) 0) /** Allow the release of the buffer pool mutex. */ -# define buf_pool_mutex_exit_allow() ((void) 0) +# define buf_pool_mutex_exit_allow(b) ((void) 0) /** Release the buffer pool mutex. */ -# define buf_pool_mutex_exit() mutex_exit(&buf_pool_mutex) +# define buf_pool_mutex_exit(b) mutex_exit(&b->mutex) #endif #endif /* !UNIV_HOTBACKUP */ /* @} */ diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic index 0f92a59a1c7..713b7cb990d 100644 --- a/storage/innobase/include/buf0buf.ic +++ b/storage/innobase/include/buf0buf.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -31,11 +31,32 @@ Created 11/5/1995 Heikki Tuuri *******************************************************/ #include "mtr0mtr.h" -#ifndef UNIV_HOTBACKUP #include "buf0flu.h" #include "buf0lru.h" #include "buf0rea.h" +/*********************************************************************//** +Gets the current size of buffer buf_pool in bytes. +@return size in bytes */ +UNIV_INLINE +ulint +buf_pool_get_curr_size(void) +/*========================*/ +{ + return(srv_buf_pool_curr_size); +} + +/*********************************************************************//** +Gets the current size of buffer buf_pool in pages. +@return size in pages*/ +UNIV_INLINE +ulint +buf_pool_get_n_pages(void) +/*======================*/ +{ + return(buf_pool_get_curr_size() / UNIV_PAGE_SIZE); +} + /********************************************************************//** Reads the freed_page_clock of a buffer block. @return freed_page_clock */ @@ -45,7 +66,7 @@ buf_page_get_freed_page_clock( /*==========================*/ const buf_page_t* bpage) /*!< in: block */ { - /* This is sometimes read without holding buf_pool_mutex. */ + /* This is sometimes read without holding buf_pool->mutex. */ return(bpage->freed_page_clock); } @@ -72,6 +93,8 @@ buf_page_peek_if_too_old( /*=====================*/ const buf_page_t* bpage) /*!< in: block to make younger */ { + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + if (UNIV_UNLIKELY(buf_pool->freed_page_clock == 0)) { /* If eviction has not started yet, do not update the statistics or move blocks in the LRU list. This is @@ -81,7 +104,7 @@ buf_page_peek_if_too_old( unsigned access_time = buf_page_is_accessed(bpage); if (access_time > 0 - && (ut_time_ms() - access_time) + && ((ib_uint32_t) (ut_time_ms() - access_time)) >= buf_LRU_old_threshold_ms) { return(TRUE); } @@ -93,55 +116,12 @@ buf_page_peek_if_too_old( return((buf_pool->freed_page_clock & ((1UL << 31) - 1)) > ((ulint) bpage->freed_page_clock + (buf_pool->curr_size - * (BUF_LRU_OLD_RATIO_DIV - buf_LRU_old_ratio) + * (BUF_LRU_OLD_RATIO_DIV - buf_pool->LRU_old_ratio) / (BUF_LRU_OLD_RATIO_DIV * 4)))); } } /*********************************************************************//** -Gets the current size of buffer buf_pool in bytes. -@return size in bytes */ -UNIV_INLINE -ulint -buf_pool_get_curr_size(void) -/*========================*/ -{ - return(buf_pool->curr_size * UNIV_PAGE_SIZE); -} - -/********************************************************************//** -Gets the smallest oldest_modification lsn for any page in the pool. Returns -zero if all modified pages have been flushed to disk. -@return oldest modification in pool, zero if none */ -UNIV_INLINE -ib_uint64_t -buf_pool_get_oldest_modification(void) -/*==================================*/ -{ - buf_page_t* bpage; - ib_uint64_t lsn; - - buf_pool_mutex_enter(); - - bpage = UT_LIST_GET_LAST(buf_pool->flush_list); - - if (bpage == NULL) { - lsn = 0; - } else { - ut_ad(bpage->in_flush_list); - lsn = bpage->oldest_modification; - } - - buf_pool_mutex_exit(); - - /* The returned answer may be out of date: the flush_list can - change after the mutex has been released. */ - - return(lsn); -} -#endif /* !UNIV_HOTBACKUP */ - -/*********************************************************************//** Gets the state of a block. @return state */ UNIV_INLINE @@ -293,13 +273,15 @@ buf_page_get_mutex( /*===============*/ const buf_page_t* bpage) /*!< in: pointer to control block */ { + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + switch (buf_page_get_state(bpage)) { case BUF_BLOCK_ZIP_FREE: ut_error; return(NULL); case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_DIRTY: - return(&buf_pool_zip_mutex); + return(&buf_pool->zip_mutex); default: return(&((buf_block_t*) bpage)->mutex); } @@ -385,7 +367,7 @@ Gets the io_fix state of a block. UNIV_INLINE enum buf_io_fix buf_block_get_io_fix( -/*================*/ +/*=================*/ const buf_block_t* block) /*!< in: pointer to the control block */ { return(buf_page_get_io_fix(&block->page)); @@ -400,7 +382,10 @@ buf_page_set_io_fix( buf_page_t* bpage, /*!< in/out: control block */ enum buf_io_fix io_fix) /*!< in: io_fix state */ { - ut_ad(buf_pool_mutex_own()); +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(buf_pool_mutex_own(buf_pool)); +#endif ut_ad(mutex_own(buf_page_get_mutex(bpage))); bpage->io_fix = io_fix; @@ -428,7 +413,10 @@ buf_page_can_relocate( /*==================*/ const buf_page_t* bpage) /*!< control block being relocated */ { - ut_ad(buf_pool_mutex_own()); +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(buf_pool_mutex_own(buf_pool)); +#endif ut_ad(mutex_own(buf_page_get_mutex(bpage))); ut_ad(buf_page_in_file(bpage)); ut_ad(bpage->in_LRU_list); @@ -446,8 +434,11 @@ buf_page_is_old( /*============*/ const buf_page_t* bpage) /*!< in: control block */ { +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(buf_pool_mutex_own(buf_pool)); +#endif ut_ad(buf_page_in_file(bpage)); - ut_ad(buf_pool_mutex_own()); return(bpage->old); } @@ -461,8 +452,11 @@ buf_page_set_old( buf_page_t* bpage, /*!< in/out: control block */ ibool old) /*!< in: old */ { +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); +#endif /* UNIV_DEBUG */ ut_a(buf_page_in_file(bpage)); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); ut_ad(bpage->in_LRU_list); #ifdef UNIV_LRU_DEBUG @@ -508,8 +502,11 @@ buf_page_set_accessed( buf_page_t* bpage, /*!< in/out: control block */ ulint time_ms) /*!< in: ut_time_ms() */ { +#ifdef UNIV_DEBUG + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); + ut_ad(buf_pool_mutex_own(buf_pool)); +#endif ut_a(buf_page_in_file(bpage)); - ut_ad(buf_pool_mutex_own()); if (!bpage->access_time) { /* Make this the time of the first access. */ @@ -705,29 +702,16 @@ buf_block_get_lock_hash_val( /*========================*/ const buf_block_t* block) /*!< in: block */ { + ut_ad(block); + ut_ad(buf_page_in_file(&block->page)); +#ifdef UNIV_SYNC_DEBUG + ut_ad(rw_lock_own(&(((buf_block_t*) block)->lock), RW_LOCK_EXCLUSIVE) + || rw_lock_own(&(((buf_block_t*) block)->lock), RW_LOCK_SHARED)); +#endif /* UNIV_SYNC_DEBUG */ return(block->lock_hash_val); } /********************************************************************//** -Allocates a buffer block. -@return own: the allocated block, in state BUF_BLOCK_MEMORY */ -UNIV_INLINE -buf_block_t* -buf_block_alloc( -/*============*/ - ulint zip_size) /*!< in: compressed page size in bytes, - or 0 if uncompressed tablespace */ -{ - buf_block_t* block; - - block = buf_LRU_get_free_block(zip_size); - - buf_block_set_state(block, BUF_BLOCK_MEMORY); - - return(block); -} - -/********************************************************************//** Frees a buffer block which does not contain a file page. */ UNIV_INLINE void @@ -735,7 +719,9 @@ buf_block_free( /*===========*/ buf_block_t* block) /*!< in, own: block to be freed */ { - buf_pool_mutex_enter(); + buf_pool_t* buf_pool = buf_pool_from_bpage((buf_page_t*)block); + + buf_pool_mutex_enter(buf_pool); mutex_enter(&block->mutex); @@ -745,7 +731,7 @@ buf_block_free( mutex_exit(&block->mutex); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); } #endif /* !UNIV_HOTBACKUP */ @@ -819,7 +805,9 @@ buf_block_modify_clock_inc( buf_block_t* block) /*!< in: block */ { #ifdef UNIV_SYNC_DEBUG - ut_ad((buf_pool_mutex_own() + buf_pool_t* buf_pool = buf_pool_from_bpage((buf_page_t*)block); + + ut_ad((buf_pool_mutex_own(buf_pool) && (block->page.buf_fix_count == 0)) || rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE)); #endif /* UNIV_SYNC_DEBUG */ @@ -898,25 +886,87 @@ buf_block_buf_fix_dec( } /******************************************************************//** +Returns the buffer pool instance given a page instance +@return buf_pool */ +UNIV_INLINE +buf_pool_t* +buf_pool_from_bpage( +/*================*/ + const buf_page_t* bpage) /*!< in: buffer pool page */ +{ + /* Every page must be in some buffer pool. */ + ut_ad(bpage->buf_pool != NULL); + + return(bpage->buf_pool); +} + +/******************************************************************//** +Returns the buffer pool instance given a block instance +@return buf_pool */ +UNIV_INLINE +buf_pool_t* +buf_pool_from_block( +/*================*/ + const buf_block_t* block) /*!< in: block */ +{ + return(buf_pool_from_bpage(&block->page)); +} + +/******************************************************************//** +Returns the buffer pool instance given space and offset of page +@return buffer pool */ +UNIV_INLINE +buf_pool_t* +buf_pool_get( +/*==========*/ + ulint space, /*!< in: space id */ + ulint offset) /*!< in: offset of the page within space */ +{ + ulint fold; + ulint index; + ulint ignored_offset; + + ignored_offset = offset >> 6; /* 2log of BUF_READ_AHEAD_AREA (64)*/ + fold = buf_page_address_fold(space, ignored_offset); + index = fold % srv_buf_pool_instances; + return buf_pool_ptr[index]; +} + +/******************************************************************//** +Returns the buffer pool instance given its array index +@return buffer pool */ +UNIV_INLINE +buf_pool_t* +buf_pool_from_array( +/*================*/ + ulint index) /*!< in: array index to get + buffer pool instance from */ +{ + return buf_pool_ptr[index]; +} + +/******************************************************************//** Returns the control block of a file page, NULL if not found. @return block, NULL if not found */ UNIV_INLINE buf_page_t* -buf_page_hash_get( -/*==============*/ - ulint space, /*!< in: space id */ - ulint offset) /*!< in: offset of the page within space */ +buf_page_hash_get_low( +/*==================*/ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + ulint space, /*!< in: space id */ + ulint offset, /*!< in: offset of the page + within space */ + ulint fold) /*!< in: buf_page_address_fold( + space, offset) */ { buf_page_t* bpage; - ulint fold; ut_ad(buf_pool); - ut_ad(buf_pool_mutex_own()); + ut_ad(buf_pool_mutex_own(buf_pool)); + ut_ad(fold == buf_page_address_fold(space, offset)); /* Look for the page in the hash table */ - fold = buf_page_address_fold(space, offset); - HASH_SEARCH(hash, buf_pool->page_hash, fold, buf_page_t*, bpage, ut_ad(bpage->in_page_hash && !bpage->in_zip_hash && buf_page_in_file(bpage)), @@ -925,7 +975,36 @@ buf_page_hash_get( ut_a(buf_page_in_file(bpage)); ut_ad(bpage->in_page_hash); ut_ad(!bpage->in_zip_hash); +#if UNIV_WORD_SIZE == 4 + /* On 32-bit systems, there is no padding in + buf_page_t. On other systems, Valgrind could complain + about uninitialized pad bytes. */ UNIV_MEM_ASSERT_RW(bpage, sizeof *bpage); +#endif + } + + return(bpage); +} + +/******************************************************************//** +Returns the control block of a file page, NULL if not found. +@return block, NULL if not found or not a real control block */ +UNIV_INLINE +buf_page_t* +buf_page_hash_get( +/*==============*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint space, /*!< in: space id */ + ulint offset) /*!< in: offset of the page + within space */ +{ + buf_page_t* bpage; + ulint fold = buf_page_address_fold(space, offset); + + bpage = buf_page_hash_get_low(buf_pool, space, offset, fold); + + if (bpage && buf_pool_watch_is_sentinel(buf_pool, bpage)) { + bpage = NULL; } return(bpage); @@ -939,10 +1018,16 @@ UNIV_INLINE buf_block_t* buf_block_hash_get( /*===============*/ - ulint space, /*!< in: space id */ - ulint offset) /*!< in: offset of the page within space */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint space, /*!< in: space id */ + ulint offset) /*!< in: offset of the page + within space */ { - return(buf_page_get_block(buf_page_hash_get(space, offset))); + buf_block_t* block; + + block = buf_page_get_block(buf_page_hash_get(buf_pool, space, offset)); + + return(block); } /********************************************************************//** @@ -960,12 +1045,13 @@ buf_page_peek( ulint offset) /*!< in: page number */ { const buf_page_t* bpage; + buf_pool_t* buf_pool = buf_pool_get(space, offset); - buf_pool_mutex_enter(); + buf_pool_mutex_enter(buf_pool); - bpage = buf_page_hash_get(space, offset); + bpage = buf_page_hash_get(buf_pool, space, offset); - buf_pool_mutex_exit(); + buf_pool_mutex_exit(buf_pool); return(bpage != NULL); } @@ -979,6 +1065,7 @@ buf_page_release_zip( buf_page_t* bpage) /*!< in: buffer block */ { buf_block_t* block; + buf_pool_t* buf_pool = buf_pool_from_bpage(bpage); ut_ad(bpage); ut_a(bpage->buf_fix_count > 0); @@ -986,9 +1073,9 @@ buf_page_release_zip( switch (buf_page_get_state(bpage)) { case BUF_BLOCK_ZIP_PAGE: case BUF_BLOCK_ZIP_DIRTY: - mutex_enter(&buf_pool_zip_mutex); + mutex_enter(&buf_pool->zip_mutex); bpage->buf_fix_count--; - mutex_exit(&buf_pool_zip_mutex); + mutex_exit(&buf_pool->zip_mutex); return; case BUF_BLOCK_FILE_PAGE: block = (buf_block_t*) bpage; @@ -1007,6 +1094,7 @@ buf_page_release_zip( break; } + ut_error; } @@ -1018,21 +1106,14 @@ void buf_page_release( /*=============*/ buf_block_t* block, /*!< in: buffer block */ - ulint rw_latch, /*!< in: RW_S_LATCH, RW_X_LATCH, + ulint rw_latch) /*!< in: RW_S_LATCH, RW_X_LATCH, RW_NO_LATCH */ - mtr_t* mtr) /*!< in: mtr */ { ut_ad(block); ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); ut_a(block->page.buf_fix_count > 0); - if (rw_latch == RW_X_LATCH && mtr->modifications) { - buf_pool_mutex_enter(); - buf_flush_note_modification(block, mtr); - buf_pool_mutex_exit(); - } - mutex_enter(&block->mutex); #ifdef UNIV_SYNC_DEBUG @@ -1065,4 +1146,37 @@ buf_block_dbg_add_level( sync_thread_add_level(&block->lock, level); } #endif /* UNIV_SYNC_DEBUG */ +/********************************************************************//** +Acquire mutex on all buffer pool instances. */ +UNIV_INLINE +void +buf_pool_mutex_enter_all(void) +/*==========================*/ +{ + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + buf_pool_mutex_enter(buf_pool); + } +} + +/********************************************************************//** +Release mutex on all buffer pool instances. */ +UNIV_INLINE +void +buf_pool_mutex_exit_all(void) +/*=========================*/ +{ + ulint i; + + for (i = 0; i < srv_buf_pool_instances; i++) { + buf_pool_t* buf_pool; + + buf_pool = buf_pool_from_array(i); + buf_pool_mutex_exit(buf_pool); + } +} #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/include/buf0flu.h b/storage/innobase/include/buf0flu.h index 6c751852f54..55814b6bf86 100644 --- a/storage/innobase/include/buf0flu.h +++ b/storage/innobase/include/buf0flu.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. 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 @@ -31,6 +31,7 @@ Created 11/5/1995 Heikki Tuuri #ifndef UNIV_HOTBACKUP #include "mtr0types.h" #include "buf0types.h" +#include "log0log.h" /********************************************************************//** Remove a block from the flush list of modified blocks. */ @@ -39,6 +40,16 @@ void buf_flush_remove( /*=============*/ buf_page_t* bpage); /*!< in: pointer to the block in question */ +/*******************************************************************//** +Relocates a buffer control block on the flush_list. +Note that it is assumed that the contents of bpage has already been +copied to dpage. */ +UNIV_INTERN +void +buf_flush_relocate_on_flush_list( +/*=============================*/ + buf_page_t* bpage, /*!< in/out: control block being moved */ + buf_page_t* dpage); /*!< in/out: destination block */ /********************************************************************//** Updates the flush system data structures when a write is completed. */ UNIV_INTERN @@ -48,11 +59,19 @@ buf_flush_write_complete( buf_page_t* bpage); /*!< in: pointer to the block in question */ /*********************************************************************//** Flushes pages from the end of the LRU list if there is too small -a margin of replaceable pages there. */ +a margin of replaceable pages there. If buffer pool is NULL it +means flush free margin on all buffer pool instances. */ UNIV_INTERN void -buf_flush_free_margin(void); -/*=======================*/ +buf_flush_free_margin( +/*==================*/ + buf_pool_t* buf_pool); +/*********************************************************************//** +Flushes pages from the end of all the LRU lists. */ +UNIV_INTERN +void +buf_flush_free_margins(void); +/*=========================*/ #endif /* !UNIV_HOTBACKUP */ /********************************************************************//** Initializes a page for writing to the tablespace. */ @@ -66,21 +85,30 @@ buf_flush_init_for_writing( to the page */ #ifndef UNIV_HOTBACKUP /*******************************************************************//** -This utility flushes dirty blocks from the end of the LRU list or flush_list. -NOTE 1: in the case of an LRU flush the calling thread may own latches to -pages: to avoid deadlocks, this function must be written so that it cannot -end up waiting for these latches! NOTE 2: in the case of a flush list flush, -the calling thread is not allowed to own any latches on pages! +This utility flushes dirty blocks from the end of the LRU list. +NOTE: The calling thread may own latches to pages: to avoid deadlocks, +this function must be written so that it cannot end up waiting for these +latches! @return number of blocks for which the write request was queued; ULINT_UNDEFINED if there was a flush of the same type already running */ UNIV_INTERN ulint -buf_flush_batch( +buf_flush_LRU( +/*==========*/ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint min_n); /*!< in: wished minimum mumber of blocks + flushed (it is not guaranteed that the + actual number is that big, though) */ +/*******************************************************************//** +This utility flushes dirty blocks from the end of the flush_list of +all buffer pool instances. +NOTE: The calling thread is not allowed to own any latches on pages! +@return number of blocks for which the write request was queued; +ULINT_UNDEFINED if there was a flush of the same type already running */ +UNIV_INTERN +ulint +buf_flush_list( /*============*/ - enum buf_flush flush_type, /*!< in: BUF_FLUSH_LRU or - BUF_FLUSH_LIST; if BUF_FLUSH_LIST, - then the caller must not own any - latches on pages */ ulint min_n, /*!< in: wished minimum mumber of blocks flushed (it is not guaranteed that the actual number is that big, though) */ @@ -95,7 +123,9 @@ UNIV_INTERN void buf_flush_wait_batch_end( /*=====================*/ - enum buf_flush type); /*!< in: BUF_FLUSH_LRU or BUF_FLUSH_LIST */ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + enum buf_flush type); /*!< in: BUF_FLUSH_LRU + or BUF_FLUSH_LIST */ /********************************************************************//** This function should be called at a mini-transaction commit, if a page was modified in it. Puts the block to the list of modified blocks, if it not @@ -171,17 +201,35 @@ Validates the flush list. @return TRUE if ok */ UNIV_INTERN ibool -buf_flush_validate(void); -/*====================*/ +buf_flush_validate( +/*===============*/ + buf_pool_t* buf_pool); #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ +/********************************************************************//** +Initialize the red-black tree to speed up insertions into the flush_list +during recovery process. Should be called at the start of recovery +process before any page has been read/written. */ +UNIV_INTERN +void +buf_flush_init_flush_rbt(void); +/*==========================*/ + +/********************************************************************//** +Frees up the red-black tree. */ +UNIV_INTERN +void +buf_flush_free_flush_rbt(void); +/*==========================*/ + /** When buf_flush_free_margin is called, it tries to make this many blocks available to replacement in the free list and at the end of the LRU list (to make sure that a read-ahead batch can be read efficiently in a single sweep). */ -#define BUF_FLUSH_FREE_BLOCK_MARGIN (5 + BUF_READ_AHEAD_AREA) +#define BUF_FLUSH_FREE_BLOCK_MARGIN(b) (5 + BUF_READ_AHEAD_AREA(b)) /** Extra margin to apply above BUF_FLUSH_FREE_BLOCK_MARGIN */ -#define BUF_FLUSH_EXTRA_MARGIN (BUF_FLUSH_FREE_BLOCK_MARGIN / 4 + 100) +#define BUF_FLUSH_EXTRA_MARGIN(b) (BUF_FLUSH_FREE_BLOCK_MARGIN(b) / 4 \ + + 100) #endif /* !UNIV_HOTBACKUP */ #ifndef UNIV_NONINL diff --git a/storage/innobase/include/buf0flu.ic b/storage/innobase/include/buf0flu.ic index c90cd59e4b6..30e2cc8efe8 100644 --- a/storage/innobase/include/buf0flu.ic +++ b/storage/innobase/include/buf0flu.ic @@ -33,7 +33,9 @@ UNIV_INTERN void buf_flush_insert_into_flush_list( /*=============================*/ - buf_block_t* block); /*!< in/out: block which is modified */ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + buf_block_t* block, /*!< in/out: block which is modified */ + ib_uint64_t lsn); /*!< in: oldest modification */ /********************************************************************//** Inserts a modified block into the flush list in the right sorted position. This function is used by recovery, because there the modifications do not @@ -42,7 +44,9 @@ UNIV_INTERN void buf_flush_insert_sorted_into_flush_list( /*====================================*/ - buf_block_t* block); /*!< in/out: block which is modified */ + buf_pool_t* buf_pool, /*!< buffer pool instance */ + buf_block_t* block, /*!< in/out: block which is modified */ + ib_uint64_t lsn); /*!< in: oldest modification */ /********************************************************************//** This function should be called at a mini-transaction commit, if a page was @@ -55,30 +59,36 @@ buf_flush_note_modification( buf_block_t* block, /*!< in: block which is modified */ mtr_t* mtr) /*!< in: mtr */ { + buf_pool_t* buf_pool = buf_pool_from_block(block); + ut_ad(block); ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); ut_ad(block->page.buf_fix_count > 0); #ifdef UNIV_SYNC_DEBUG ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - ut_ad(buf_pool_mutex_own()); + + ut_ad(!buf_pool_mutex_own(buf_pool)); + ut_ad(!buf_flush_list_mutex_own(buf_pool)); + ut_ad(log_flush_order_mutex_own()); ut_ad(mtr->start_lsn != 0); ut_ad(mtr->modifications); + + mutex_enter(&block->mutex); ut_ad(block->page.newest_modification <= mtr->end_lsn); block->page.newest_modification = mtr->end_lsn; if (!block->page.oldest_modification) { - - block->page.oldest_modification = mtr->start_lsn; - ut_ad(block->page.oldest_modification != 0); - - buf_flush_insert_into_flush_list(block); + buf_flush_insert_into_flush_list( + buf_pool, block, mtr->start_lsn); } else { ut_ad(block->page.oldest_modification <= mtr->start_lsn); } + mutex_exit(&block->mutex); + ++srv_buf_pool_write_requests; } @@ -94,6 +104,8 @@ buf_flush_recv_note_modification( ib_uint64_t end_lsn) /*!< in: end lsn of the last mtr in the set of mtr's */ { + buf_pool_t* buf_pool = buf_pool_from_block(block); + ut_ad(block); ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE); ut_ad(block->page.buf_fix_count > 0); @@ -101,23 +113,24 @@ buf_flush_recv_note_modification( ut_ad(rw_lock_own(&(block->lock), RW_LOCK_EX)); #endif /* UNIV_SYNC_DEBUG */ - buf_pool_mutex_enter(); + ut_ad(!buf_pool_mutex_own(buf_pool)); + ut_ad(!buf_flush_list_mutex_own(buf_pool)); + ut_ad(log_flush_order_mutex_own()); + ut_ad(start_lsn != 0); ut_ad(block->page.newest_modification <= end_lsn); + mutex_enter(&block->mutex); block->page.newest_modification = end_lsn; if (!block->page.oldest_modification) { - - block->page.oldest_modification = start_lsn; - - ut_ad(block->page.oldest_modification != 0); - - buf_flush_insert_sorted_into_flush_list(block); + buf_flush_insert_sorted_into_flush_list( + buf_pool, block, start_lsn); } else { ut_ad(block->page.oldest_modification <= start_lsn); } - buf_pool_mutex_exit(); + mutex_exit(&block->mutex); + } #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/include/buf0lru.h b/storage/innobase/include/buf0lru.h index 009430af35b..7bcec633d9c 100644 --- a/storage/innobase/include/buf0lru.h +++ b/storage/innobase/include/buf0lru.h @@ -52,8 +52,9 @@ operations need new buffer blocks, and the i/o work done in flushing would be wasted. */ UNIV_INTERN void -buf_LRU_try_free_flushed_blocks(void); -/*==================================*/ +buf_LRU_try_free_flushed_blocks( +/*============================*/ + buf_pool_t* buf_pool); /*!< in: buffer pool instance */ /******************************************************************//** Returns TRUE if less than 25 % of the buffer pool is available. This can be used in heuristics to prevent huge transactions eating up the whole buffer @@ -72,7 +73,7 @@ These are low-level functions #define BUF_LRU_OLD_MIN_LEN 512 /* 8 megabytes of 16k pages */ /** Maximum LRU list search length in buf_flush_LRU_recommendation() */ -#define BUF_LRU_FREE_SEARCH_LEN (5 + 2 * BUF_READ_AHEAD_AREA) +#define BUF_LRU_FREE_SEARCH_LEN(b) (5 + 2 * BUF_READ_AHEAD_AREA(b)) /******************************************************************//** Invalidates all pages belonging to a given tablespace when we are deleting @@ -96,11 +97,11 @@ buf_LRU_insert_zip_clean( Try to free a block. If bpage is a descriptor of a compressed-only page, the descriptor object will be freed as well. -NOTE: If this function returns BUF_LRU_FREED, it will not temporarily -release buf_pool_mutex. Furthermore, the page frame will no longer be +NOTE: If this function returns BUF_LRU_FREED, it will temporarily +release buf_pool->mutex. Furthermore, the page frame will no longer be accessible via bpage. -The caller must hold buf_pool_mutex and buf_page_get_mutex(bpage) and +The caller must hold buf_pool->mutex and buf_page_get_mutex(bpage) and release these two mutexes after the call. No other buf_page_get_mutex() may be held when calling this function. @return BUF_LRU_FREED if freed, BUF_LRU_CANNOT_RELOCATE or @@ -114,7 +115,7 @@ buf_LRU_free_block( compressed page of an uncompressed page */ ibool* buf_pool_mutex_released); /*!< in: pointer to a variable that will - be assigned TRUE if buf_pool_mutex + be assigned TRUE if buf_pool->mutex was temporarily released, or NULL */ /******************************************************************//** Try to free a replaceable block. @@ -123,22 +124,26 @@ UNIV_INTERN ibool buf_LRU_search_and_free_block( /*==========================*/ - ulint n_iterations); /*!< in: how many times this has been called - repeatedly without result: a high value means - that we should search farther; if - n_iterations < 10, then we search - n_iterations / 10 * buf_pool->curr_size - pages from the end of the LRU list; if - n_iterations < 5, then we will also search - n_iterations / 5 of the unzip_LRU list. */ + buf_pool_t* buf_pool, /*!< in: buffer pool instance */ + ulint n_iterations); /*!< in: how many times this has + been called repeatedly without + result: a high value means that + we should search farther; if + n_iterations < 10, then we search + n_iterations / 10 * buf_pool->curr_size + pages from the end of the LRU list; if + n_iterations < 5, then we will + also search n_iterations / 5 + of the unzip_LRU list. */ /******************************************************************//** Returns a free block from the buf_pool. The block is taken off the free list. If it is empty, returns NULL. @return a free control block, or NULL if the buf_block->free list is empty */ UNIV_INTERN buf_block_t* -buf_LRU_get_free_only(void); -/*=======================*/ +buf_LRU_get_free_only( +/*==================*/ + buf_pool_t* buf_pool); /*!< buffer pool instance */ /******************************************************************//** Returns a free block from the buf_pool. The block is taken off the free list. If it is empty, blocks are moved from the end of the @@ -148,8 +153,9 @@ UNIV_INTERN buf_block_t* buf_LRU_get_free_block( /*===================*/ - ulint zip_size); /*!< in: compressed page size in bytes, - or 0 if uncompressed tablespace */ + buf_pool_t* buf_pool, /*!< in: preferred buffer pool */ + ulint zip_size); /*!< in: compressed page size in bytes, + or 0 if uncompressed tablespace */ /******************************************************************//** Puts a block back to the free list. */ @@ -196,7 +202,7 @@ buf_LRU_make_block_old( Updates buf_LRU_old_ratio. @return updated old_pct */ UNIV_INTERN -uint +ulint buf_LRU_old_ratio_update( /*=====================*/ uint old_pct,/*!< in: Reserve this percentage of @@ -232,7 +238,7 @@ buf_LRU_print(void); /** @name Heuristics for detecting index scan @{ */ /** Reserve this much/BUF_LRU_OLD_RATIO_DIV of the buffer pool for -"old" blocks. Protected by buf_pool_mutex. */ +"old" blocks. Protected by buf_pool->mutex. */ extern uint buf_LRU_old_ratio; /** The denominator of buf_LRU_old_ratio. */ #define BUF_LRU_OLD_RATIO_DIV 1024 @@ -278,7 +284,7 @@ Cleared by buf_LRU_stat_update(). */ extern buf_LRU_stat_t buf_LRU_stat_cur; /** Running sum of past values of buf_LRU_stat_cur. -Updated by buf_LRU_stat_update(). Protected by buf_pool_mutex. */ +Updated by buf_LRU_stat_update(). Protected by buf_pool->mutex. */ extern buf_LRU_stat_t buf_LRU_stat_sum; /********************************************************************//** diff --git a/storage/innobase/include/buf0rea.h b/storage/innobase/include/buf0rea.h index 093750623d6..4a52f9dcd8d 100644 --- a/storage/innobase/include/buf0rea.h +++ b/storage/innobase/include/buf0rea.h @@ -124,8 +124,8 @@ buf_read_recv_pages( /** The size in pages of the area which the read-ahead algorithms read if invoked */ -#define BUF_READ_AHEAD_AREA \ - ut_min(64, ut_2_power_up(buf_pool->curr_size / 32)) +#define BUF_READ_AHEAD_AREA(b) \ + ut_min(64, ut_2_power_up((b)->curr_size / 32)) /** @name Modes used in read-ahead @{ */ /** read only pages belonging to the insert buffer tree */ diff --git a/storage/innobase/include/buf0types.h b/storage/innobase/include/buf0types.h index bfae6477135..a2175098704 100644 --- a/storage/innobase/include/buf0types.h +++ b/storage/innobase/include/buf0types.h @@ -36,6 +36,8 @@ typedef struct buf_chunk_struct buf_chunk_t; typedef struct buf_pool_struct buf_pool_t; /** Buffer pool statistics struct */ typedef struct buf_pool_stat_struct buf_pool_stat_t; +/** Buffer pool buddy statistics struct */ +typedef struct buf_buddy_stat_struct buf_buddy_stat_t; /** A buffer frame. @see page_t */ typedef byte buf_frame_t; diff --git a/storage/innobase/include/data0type.ic b/storage/innobase/include/data0type.ic index 240b4288f39..2bf67a941bd 100644 --- a/storage/innobase/include/data0type.ic +++ b/storage/innobase/include/data0type.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -285,6 +285,10 @@ dtype_new_store_for_order_and_null_size( #endif ulint len; + ut_ad(type); + ut_ad(type->mtype >= DATA_VARCHAR); + ut_ad(type->mtype <= DATA_MYSQL); + buf[0] = (byte)(type->mtype & 0xFFUL); if (type->prtype & DATA_BINARY_TYPE) { diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h index 747e9b5364e..f84ce2d15aa 100644 --- a/storage/innobase/include/db0err.h +++ b/storage/innobase/include/db0err.h @@ -28,6 +28,8 @@ Created 5/24/1996 Heikki Tuuri enum db_err { + DB_SUCCESS_LOCKED_REC = 9, /*!< like DB_SUCCESS, but a new + explicit record lock was created */ DB_SUCCESS = 10, /* The following are error codes */ @@ -93,6 +95,13 @@ enum db_err { DB_PRIMARY_KEY_IS_NULL, /* a column in the PRIMARY KEY was found to be NULL */ + DB_STATS_DO_NOT_EXIST, /* an operation that requires the + persistent storage, used for recording + table and index statistics, was + requested but this storage does not + exist itself or the stats for a given + table do not exist */ + /* The following are partial failure codes */ DB_FAIL = 1000, DB_OVERFLOW, diff --git a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict0boot.h index 51d37ee98d1..148b5cbe250 100644 --- a/storage/innobase/include/dict0boot.h +++ b/storage/innobase/include/dict0boot.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -46,13 +46,14 @@ dict_hdr_get( /*=========*/ mtr_t* mtr); /*!< in: mtr */ /**********************************************************************//** -Returns a new row, table, index, or tree id. -@return the new id */ +Returns a new table, index, or space id. */ UNIV_INTERN -dulint +void dict_hdr_get_new_id( /*================*/ - ulint type); /*!< in: DICT_HDR_ROW_ID, ... */ + dulint* table_id, /*!< out: table id (not assigned if NULL) */ + dulint* index_id, /*!< out: index id (not assigned if NULL) */ + ulint* space_id); /*!< out: space id (not assigned if NULL) */ /**********************************************************************//** Returns a new row id. @return the new id */ @@ -119,7 +120,8 @@ dict_create(void); #define DICT_HDR_ROW_ID 0 /* The latest assigned row id */ #define DICT_HDR_TABLE_ID 8 /* The latest assigned table id */ #define DICT_HDR_INDEX_ID 16 /* The latest assigned index id */ -#define DICT_HDR_MIX_ID 24 /* Obsolete, always 0. */ +#define DICT_HDR_MAX_SPACE_ID 24 /* The latest assigned space id, or 0*/ +#define DICT_HDR_MIX_ID_LOW 28 /* Obsolete,always DICT_HDR_FIRST_ID */ #define DICT_HDR_TABLES 32 /* Root of the table index tree */ #define DICT_HDR_TABLE_IDS 36 /* Root of the table index tree */ #define DICT_HDR_COLUMNS 40 /* Root of the column index tree */ @@ -137,6 +139,7 @@ clustered index */ #define DICT_SYS_INDEXES_PAGE_NO_FIELD 8 #define DICT_SYS_INDEXES_SPACE_NO_FIELD 7 #define DICT_SYS_INDEXES_TYPE_FIELD 6 +#define DICT_SYS_INDEXES_NAME_FIELD 4 /* When a row id which is zero modulo this number (which must be a power of two) is assigned, the field DICT_HDR_ROW_ID on the dictionary header page is diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 12396556c2d..3a1bee4cd89 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -352,6 +352,7 @@ dict_create_foreign_constraints( name before it: test.table2; the default database id the database of parameter name */ + size_t sql_length, /*!< in: length of sql_string */ const char* name, /*!< in: table full name in the normalized form database_name/table_name */ @@ -928,9 +929,10 @@ UNIV_INTERN void dict_table_check_for_dup_indexes( /*=============================*/ - const dict_table_t* table); /*!< in: Check for dup indexes + const dict_table_t* table, /*!< in: Check for dup indexes in this table */ - + ibool tmp_ok);/*!< in: TRUE=allow temporary + index names */ #endif /* UNIV_DEBUG */ /**********************************************************************//** Builds a node pointer out of a physical record and a page number. @@ -1060,6 +1062,22 @@ UNIV_INTERN void dict_mutex_exit_for_mysql(void); /*===========================*/ +/**********************************************************************//** +Lock the appropriate mutex to protect index->stat_n_diff_key_vals[]. +index->id is used to pick the right mutex and it should not change +before dict_index_stat_mutex_exit() is called on this index. */ +UNIV_INTERN +void +dict_index_stat_mutex_enter( +/*========================*/ + const dict_index_t* index); /*!< in: index */ +/**********************************************************************//** +Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */ +UNIV_INTERN +void +dict_index_stat_mutex_exit( +/*=======================*/ + const dict_index_t* index); /*!< in: index */ /********************************************************************//** Checks if the database name in two table names is the same. @return TRUE if same db name */ diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index 46e78df8272..93c3f8d4733 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -765,7 +765,7 @@ dict_table_get_low( table = dict_table_check_if_in_cache_low(table_name); if (table == NULL) { - table = dict_load_table(table_name); + table = dict_load_table(table_name, TRUE); } ut_ad(!table || table->cached); diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h index 60b8c1fb632..d85f8f7fc3e 100644 --- a/storage/innobase/include/dict0load.h +++ b/storage/innobase/include/dict0load.h @@ -31,6 +31,35 @@ Created 4/24/1996 Heikki Tuuri #include "dict0types.h" #include "ut0byte.h" #include "mem0mem.h" +#include "btr0types.h" + +/** enum that defines all 6 system table IDs */ +enum dict_system_table_id { + SYS_TABLES = 0, + SYS_INDEXES, + SYS_COLUMNS, + SYS_FIELDS, + SYS_FOREIGN, + SYS_FOREIGN_COLS, + + /* This must be last item. Defines the number of system tables. */ + SYS_NUM_SYSTEM_TABLES +}; + +typedef enum dict_system_table_id dict_system_id_t; + +/** Status bit for dict_process_sys_tables_rec() */ +enum dict_table_info { + DICT_TABLE_LOAD_FROM_RECORD = 0,/*!< Directly populate a dict_table_t + structure with information from + a SYS_TABLES record */ + DICT_TABLE_LOAD_FROM_CACHE = 1, /*!< Check first whether dict_table_t + is in the cache, if so, return it */ + DICT_TABLE_UPDATE_STATS = 2 /*!< whether to update statistics + when loading SYS_TABLES information. */ +}; + +typedef enum dict_table_info dict_table_info_t; /********************************************************************//** In a crash recovery we already have all the tablespace objects created. @@ -54,6 +83,74 @@ char* dict_get_first_table_name_in_db( /*============================*/ const char* name); /*!< in: database name which ends to '/' */ + +/********************************************************************//** +Loads a table definition from a SYS_TABLES record to dict_table_t. +Does not load any columns or indexes. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_load_table_low( +/*================*/ + const char* name, /*!< in: table name */ + const rec_t* rec, /*!< in: SYS_TABLES record */ + dict_table_t** table); /*!< out,own: table, or NULL */ +/********************************************************************//** +Loads a table column definition from a SYS_COLUMNS record to +dict_table_t. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_load_column_low( +/*=================*/ + dict_table_t* table, /*!< in/out: table, could be NULL + if we just populate a dict_column_t + struct with information from + a SYS_COLUMNS record */ + mem_heap_t* heap, /*!< in/out: memory heap + for temporary storage */ + dict_col_t* column, /*!< out: dict_column_t to fill */ + dulint* table_id, /*!< out: table id */ + const char** col_name, /*!< out: column name */ + const rec_t* rec); /*!< in: SYS_COLUMNS record */ +/********************************************************************//** +Loads an index definition from a SYS_INDEXES record to dict_index_t. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_load_index_low( +/*================*/ + byte* table_id, /*!< in/out: table id (8 bytes_, + an "in" value if cached=TRUE + and "out" when cached=FALSE */ + const char* table_name, /*!< in: table name */ + mem_heap_t* heap, /*!< in/out: temporary memory heap */ + const rec_t* rec, /*!< in: SYS_INDEXES record */ + ibool cached, /*!< in: TRUE = add to cache + FALSE = do not */ + dict_index_t** index); /*!< out,own: index, or NULL */ +/********************************************************************//** +Loads an index field definition from a SYS_FIELDS record to +dict_index_t. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_load_field_low( +/*================*/ + byte* index_id, /*!< in/out: index id (8 bytes) + an "in" value if index != NULL + and "out" if index == NULL */ + dict_index_t* index, /*!< in/out: index, could be NULL + if we just populate a dict_field_t + struct with information from + a SYS_FIELDS record */ + dict_field_t* sys_field, /*!< out: dict_field_t to be + filled */ + ulint* pos, /*!< out: Field position */ + byte* last_index_id, /*!< in: last index id */ + mem_heap_t* heap, /*!< in/out: memory heap + for temporary storage */ + const rec_t* rec); /*!< in: SYS_FIELDS record */ /********************************************************************//** Loads a table definition and also all its index definitions, and also the cluster definition if the table is a member in a cluster. Also loads @@ -66,8 +163,9 @@ UNIV_INTERN dict_table_t* dict_load_table( /*============*/ - const char* name); /*!< in: table name in the + const char* name, /*!< in: table name in the databasename/tablename format */ + ibool cached);/*!< in: TRUE=add to cache, FALSE=do not */ /***********************************************************************//** Loads a table object based on the table id. @return table; NULL if table does not exist */ @@ -107,7 +205,113 @@ void dict_print(void); /*============*/ - +/********************************************************************//** +This function opens a system table, and return the first record. +@return first record of the system table */ +UNIV_INTERN +const rec_t* +dict_startscan_system( +/*==================*/ + btr_pcur_t* pcur, /*!< out: persistent cursor to + the record */ + mtr_t* mtr, /*!< in: the mini-transaction */ + dict_system_id_t system_id); /*!< in: which system table to open */ +/********************************************************************//** +This function get the next system table record as we scan the table. +@return the record if found, NULL if end of scan. */ +UNIV_INTERN +const rec_t* +dict_getnext_system( +/*================*/ + btr_pcur_t* pcur, /*!< in/out: persistent cursor + to the record */ + mtr_t* mtr); /*!< in: the mini-transaction */ +/********************************************************************//** +This function processes one SYS_TABLES record and populate the dict_table_t +struct for the table. Extracted out of dict_print() to be used by +both monitor table output and information schema innodb_sys_tables output. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_tables_rec( +/*========================*/ + mem_heap_t* heap, /*!< in: temporary memory heap */ + const rec_t* rec, /*!< in: SYS_TABLES record */ + dict_table_t** table, /*!< out: dict_table_t to fill */ + dict_table_info_t status); /*!< in: status bit controls + options such as whether we shall + look for dict_table_t from cache + first */ +/********************************************************************//** +This function parses a SYS_INDEXES record and populate a dict_index_t +structure with the information from the record. For detail information +about SYS_INDEXES fields, please refer to dict_boot() function. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_indexes_rec( +/*=========================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_INDEXES rec */ + dict_index_t* index, /*!< out: dict_index_t to be + filled */ + dulint* table_id); /*!< out: table id */ +/********************************************************************//** +This function parses a SYS_COLUMNS record and populate a dict_column_t +structure with the information from the record. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_columns_rec( +/*=========================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_COLUMNS rec */ + dict_col_t* column, /*!< out: dict_col_t to be filled */ + dulint* table_id, /*!< out: table id */ + const char** col_name); /*!< out: column name */ +/********************************************************************//** +This function parses a SYS_FIELDS record and populate a dict_field_t +structure with the information from the record. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_fields_rec( +/*========================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_FIELDS rec */ + dict_field_t* sys_field, /*!< out: dict_field_t to be + filled */ + ulint* pos, /*!< out: Field position */ + dulint* index_id, /*!< out: current index id */ + dulint last_id); /*!< in: previous index id */ +/********************************************************************//** +This function parses a SYS_FOREIGN record and populate a dict_foreign_t +structure with the information from the record. For detail information +about SYS_FOREIGN fields, please refer to dict_load_foreign() function +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_foreign_rec( +/*=========================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_FOREIGN rec */ + dict_foreign_t* foreign); /*!< out: dict_foreign_t to be + filled */ +/********************************************************************//** +This function parses a SYS_FOREIGN_COLS record and extract necessary +information from the record and return to caller. +@return error message, or NULL on success */ +UNIV_INTERN +const char* +dict_process_sys_foreign_col_rec( +/*=============================*/ + mem_heap_t* heap, /*!< in/out: heap memory */ + const rec_t* rec, /*!< in: current SYS_FOREIGN_COLS rec */ + const char** name, /*!< out: foreign key constraint name */ + const char** for_col_name, /*!< out: referencing column name */ + const char** ref_col_name, /*!< out: referenced column name + in referenced table */ + ulint* pos); /*!< out: column position */ #ifndef UNIV_NONINL #include "dict0load.ic" #endif diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 2d001111938..f93b2f8c8a3 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -80,21 +80,39 @@ combination of types */ /** File format */ /* @{ */ #define DICT_TF_FORMAT_SHIFT 5 /* file format */ -#define DICT_TF_FORMAT_MASK (127 << DICT_TF_FORMAT_SHIFT) +#define DICT_TF_FORMAT_MASK \ +((~(~0 << (DICT_TF_BITS - DICT_TF_FORMAT_SHIFT))) << DICT_TF_FORMAT_SHIFT) #define DICT_TF_FORMAT_51 0 /*!< InnoDB/MySQL up to 5.1 */ #define DICT_TF_FORMAT_ZIP 1 /*!< InnoDB plugin for 5.1: compressed tables, new BLOB treatment */ /** Maximum supported file format */ #define DICT_TF_FORMAT_MAX DICT_TF_FORMAT_ZIP - +/* @} */ #define DICT_TF_BITS 6 /*!< number of flag bits */ #if (1 << (DICT_TF_BITS - DICT_TF_FORMAT_SHIFT)) <= DICT_TF_FORMAT_MAX # error "DICT_TF_BITS is insufficient for DICT_TF_FORMAT_MAX" #endif /* @} */ + +/** @brief Additional table flags. + +These flags will be stored in SYS_TABLES.MIX_LEN. All unused flags +will be written as 0. The column may contain garbage for tables +created with old versions of InnoDB that only implemented +ROW_FORMAT=REDUNDANT. */ +/* @{ */ +#define DICT_TF2_SHIFT DICT_TF_BITS + /*!< Shift value for + table->flags. */ +#define DICT_TF2_TEMPORARY 1 /*!< TRUE for tables from + CREATE TEMPORARY TABLE. */ +#define DICT_TF2_BITS (DICT_TF2_SHIFT + 1) + /*!< Total number of bits + in table->flags. */ /* @} */ + /**********************************************************************//** Creates a table memory object. @return own: table object */ @@ -129,6 +147,36 @@ dict_mem_table_add_col( ulint prtype, /*!< in: precise type */ ulint len); /*!< in: precision */ /**********************************************************************//** +This function poplulates a dict_col_t memory structure with +supplied information. */ +UNIV_INLINE +void +dict_mem_fill_column_struct( +/*========================*/ + dict_col_t* column, /*!< out: column struct to be + filled */ + ulint col_pos, /*!< in: column position */ + ulint mtype, /*!< in: main data type */ + ulint prtype, /*!< in: precise type */ + ulint col_len); /*!< in: column lenght */ +/**********************************************************************//** +This function poplulates a dict_index_t index memory structure with +supplied information. */ +UNIV_INLINE +void +dict_mem_fill_index_struct( +/*=======================*/ + dict_index_t* index, /*!< out: index to be filled */ + mem_heap_t* heap, /*!< in: memory heap */ + const char* table_name, /*!< in: table name */ + const char* index_name, /*!< in: index name */ + ulint space, /*!< in: space where the index tree is + placed, ignored if the index is of + the clustered type */ + ulint type, /*!< in: DICT_UNIQUE, + DICT_CLUSTERED, ... ORed */ + ulint n_fields); /*!< in: number of fields */ +/**********************************************************************//** Creates an index memory object. @return own: index object */ UNIV_INTERN @@ -374,7 +422,7 @@ struct dict_table_struct{ unsigned space:32; /*!< space where the clustered index of the table is placed */ - unsigned flags:DICT_TF_BITS;/*!< DICT_TF_COMPACT, ... */ + unsigned flags:DICT_TF2_BITS;/*!< DICT_TF_COMPACT, ... */ unsigned ibd_file_missing:1; /*!< TRUE if this is in a single-table tablespace and the .ibd file is missing; then diff --git a/storage/innobase/include/dict0mem.ic b/storage/innobase/include/dict0mem.ic index c36adb07a18..5a851da5640 100644 --- a/storage/innobase/include/dict0mem.ic +++ b/storage/innobase/include/dict0mem.ic @@ -23,4 +23,82 @@ Data dictionary memory object creation Created 1/8/1996 Heikki Tuuri ***********************************************************************/ +#include "data0type.h" +#include "dict0mem.h" +#include "fil0fil.h" +/**********************************************************************//** +This function poplulates a dict_index_t index memory structure with +supplied information. */ +UNIV_INLINE +void +dict_mem_fill_index_struct( +/*=======================*/ + dict_index_t* index, /*!< out: index to be filled */ + mem_heap_t* heap, /*!< in: memory heap */ + const char* table_name, /*!< in: table name */ + const char* index_name, /*!< in: index name */ + ulint space, /*!< in: space where the index tree is + placed, ignored if the index is of + the clustered type */ + ulint type, /*!< in: DICT_UNIQUE, + DICT_CLUSTERED, ... ORed */ + ulint n_fields) /*!< in: number of fields */ +{ + + if (heap) { + index->heap = heap; + index->name = mem_heap_strdup(heap, index_name); + index->fields = (dict_field_t*) mem_heap_alloc( + heap, 1 + n_fields * sizeof(dict_field_t)); + } else { + index->name = index_name; + index->heap = NULL; + index->fields = NULL; + } + + index->type = type; +#ifndef UNIV_HOTBACKUP + index->space = (unsigned int) space; + index->page = FIL_NULL; +#endif /* !UNIV_HOTBACKUP */ + index->table_name = table_name; + index->n_fields = (unsigned int) n_fields; + /* The '1 +' above prevents allocation + of an empty mem block */ +#ifdef UNIV_DEBUG + index->magic_n = DICT_INDEX_MAGIC_N; +#endif /* UNIV_DEBUG */ +} + +/**********************************************************************//** +This function poplulates a dict_col_t memory structure with +supplied information. */ +UNIV_INLINE +void +dict_mem_fill_column_struct( +/*========================*/ + dict_col_t* column, /*!< out: column struct to be + filled */ + ulint col_pos, /*!< in: column position */ + ulint mtype, /*!< in: main data type */ + ulint prtype, /*!< in: precise type */ + ulint col_len) /*!< in: column lenght */ +{ +#ifndef UNIV_HOTBACKUP + ulint mbminlen; + ulint mbmaxlen; +#endif /* !UNIV_HOTBACKUP */ + + column->ind = (unsigned int) col_pos; + column->ord_part = 0; + column->mtype = (unsigned int) mtype; + column->prtype = (unsigned int) prtype; + column->len = (unsigned int) col_len; +#ifndef UNIV_HOTBACKUP + dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen); + + column->mbminlen = (unsigned int) mbminlen; + column->mbmaxlen = (unsigned int) mbmaxlen; +#endif /* !UNIV_HOTBACKUP */ +} diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 74d0fbcdacd..c746915844b 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. 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 @@ -26,13 +26,13 @@ Created 10/25/1995 Heikki Tuuri #ifndef fil0fil_h #define fil0fil_h -#include "univ.i" -#ifndef UNIV_HOTBACKUP -#include "sync0rw.h" -#endif /* !UNIV_HOTBACKUP */ #include "dict0types.h" #include "ut0byte.h" #include "os0file.h" +#ifndef UNIV_HOTBACKUP +#include "sync0rw.h" +#include "ibuf0types.h" +#endif /* !UNIV_HOTBACKUP */ /** When mysqld is run, the default directory "." is the mysqld datadir, but in the MySQL Embedded Server Library and ibbackup it is not the default @@ -110,9 +110,10 @@ extern fil_addr_t fil_addr_null; contents of this field is valid for all uncompressed pages. */ #define FIL_PAGE_FILE_FLUSH_LSN 26 /*!< this is only defined for the - first page in a data file: the file - has been flushed to disk at least up - to this lsn */ + first page in a system tablespace + data file (ibdata*, not *.ibd): + the file has been flushed to disk + at least up to this lsn */ #define FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID 34 /*!< starting from 4.1.x this contains the space id of the page */ #define FIL_PAGE_DATA 38 /*!< start of the data on the page */ @@ -224,6 +225,16 @@ fil_space_create( 0 for uncompressed tablespaces */ ulint purpose);/*!< in: FIL_TABLESPACE, or FIL_LOG if log */ /*******************************************************************//** +Assigns a new space id for a new single-table tablespace. This works simply by +incrementing the global counter. If 4 billion id's is not enough, we may need +to recycle id's. +@return TRUE if assigned, FALSE if not */ +UNIV_INTERN +ibool +fil_assign_new_space_id( +/*====================*/ + ulint* space_id); /*!< in/out: space id */ +/*******************************************************************//** Returns the size of the space in pages. The tablespace must be cached in the memory cache. @return space size, 0 if space not found */ @@ -426,9 +437,7 @@ UNIV_INTERN ulint fil_create_new_single_table_tablespace( /*===================================*/ - ulint* space_id, /*!< in/out: space id; if this is != 0, - then this is an input parameter, - otherwise output */ + ulint space_id, /*!< in: space id */ const char* tablename, /*!< in: the table name in the usual databasename/tablename format of InnoDB, or a dir path to a temp @@ -497,16 +506,6 @@ UNIV_INTERN ulint fil_load_single_table_tablespaces(void); /*===================================*/ -/********************************************************************//** -If we need crash recovery, and we have called -fil_load_single_table_tablespaces() and dict_load_single_table_tablespaces(), -we can call this function to print an error message of orphaned .ibd files -for which there is not a data dictionary entry with a matching table name -and space id. */ -UNIV_INTERN -void -fil_print_orphaned_tablespaces(void); -/*================================*/ /*******************************************************************//** Returns TRUE if a single-table tablespace does not exist in the memory cache, or is being deleted there. diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index b737a00b3dc..a9ee1d66b99 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 2006, 2010, Innobase Oy. All Rights Reserved. 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 @@ -215,11 +215,21 @@ innobase_casedn_str( /**********************************************************************//** Determines the connection character set. @return connection character set */ +UNIV_INTERN struct charset_info_st* innobase_get_charset( /*=================*/ void* mysql_thd); /*!< in: MySQL thread handle */ - +/**********************************************************************//** +Determines the current SQL statement. +@return SQL statement string */ +UNIV_INTERN +const char* +innobase_get_stmt( +/*==============*/ + void* mysql_thd, /*!< in: MySQL thread handle */ + size_t* length) /*!< out: length of the SQL statement */ + __attribute__((nonnull)); /******************************************************************//** This function is used to find the storage length in bytes of the first n characters for prefix indexes using a multibyte character set. The function diff --git a/storage/innobase/include/handler0alter.h b/storage/innobase/include/handler0alter.h index 7f5af6d2e76..017fe88d533 100644 --- a/storage/innobase/include/handler0alter.h +++ b/storage/innobase/include/handler0alter.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 2005, 2010, Innobase Oy. All Rights Reserved. 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 diff --git a/storage/innobase/include/hash0hash.h b/storage/innobase/include/hash0hash.h index 977cb829f35..b17c21a45ef 100644 --- a/storage/innobase/include/hash0hash.h +++ b/storage/innobase/include/hash0hash.h @@ -434,11 +434,12 @@ struct hash_table_struct { these heaps */ #endif /* !UNIV_HOTBACKUP */ mem_heap_t* heap; +#ifdef UNIV_DEBUG ulint magic_n; +# define HASH_TABLE_MAGIC_N 76561114 +#endif /* UNIV_DEBUG */ }; -#define HASH_TABLE_MAGIC_N 76561114 - #ifndef UNIV_NONINL #include "hash0hash.ic" #endif diff --git a/storage/innobase/include/hash0hash.ic b/storage/innobase/include/hash0hash.ic index 19da2d50701..0b437894e2e 100644 --- a/storage/innobase/include/hash0hash.ic +++ b/storage/innobase/include/hash0hash.ic @@ -35,6 +35,8 @@ hash_get_nth_cell( hash_table_t* table, /*!< in: hash table */ ulint n) /*!< in: cell index */ { + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); ut_ad(n < table->n_cells); return(table->array + n); @@ -48,6 +50,8 @@ hash_table_clear( /*=============*/ hash_table_t* table) /*!< in/out: hash table */ { + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); memset(table->array, 0x0, table->n_cells * sizeof(*table->array)); } @@ -61,6 +65,8 @@ hash_get_n_cells( /*=============*/ hash_table_t* table) /*!< in: table */ { + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); return(table->n_cells); } @@ -74,6 +80,8 @@ hash_calc_hash( ulint fold, /*!< in: folded value */ hash_table_t* table) /*!< in: hash table */ { + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); return(ut_hash_ulint(fold, table->n_cells)); } @@ -88,6 +96,8 @@ hash_get_mutex_no( hash_table_t* table, /*!< in: hash table */ ulint fold) /*!< in: fold */ { + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); ut_ad(ut_is_2pow(table->n_mutexes)); return(ut_2pow_remainder(hash_calc_hash(fold, table), table->n_mutexes)); @@ -103,6 +113,8 @@ hash_get_nth_heap( hash_table_t* table, /*!< in: hash table */ ulint i) /*!< in: index of the heap */ { + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); ut_ad(i < table->n_mutexes); return(table->heaps[i]); @@ -120,6 +132,9 @@ hash_get_heap( { ulint i; + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); + if (table->heap) { return(table->heap); } @@ -139,6 +154,8 @@ hash_get_nth_mutex( hash_table_t* table, /*!< in: hash table */ ulint i) /*!< in: index of the mutex */ { + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); ut_ad(i < table->n_mutexes); return(table->mutexes + i); @@ -156,6 +173,9 @@ hash_get_mutex( { ulint i; + ut_ad(table); + ut_ad(table->magic_n == HASH_TABLE_MAGIC_N); + i = hash_get_mutex_no(table, fold); return(hash_get_nth_mutex(table, i)); diff --git a/storage/innobase/include/ibuf0ibuf.h b/storage/innobase/include/ibuf0ibuf.h index 8aa21fb9d95..0f1631fde77 100644 --- a/storage/innobase/include/ibuf0ibuf.h +++ b/storage/innobase/include/ibuf0ibuf.h @@ -35,12 +35,27 @@ Created 7/19/1997 Heikki Tuuri #ifndef UNIV_HOTBACKUP # include "ibuf0types.h" +/* Possible operations buffered in the insert/whatever buffer. See +ibuf_insert(). DO NOT CHANGE THE VALUES OF THESE, THEY ARE STORED ON DISK. */ +typedef enum { + IBUF_OP_INSERT = 0, + IBUF_OP_DELETE_MARK = 1, + IBUF_OP_DELETE = 2, + + /* Number of different operation types. */ + IBUF_OP_COUNT = 3, +} ibuf_op_t; + /** Combinations of operations that can be buffered. Because the enum values are used for indexing innobase_change_buffering_values[], they should start at 0 and there should not be any gaps. */ typedef enum { IBUF_USE_NONE = 0, IBUF_USE_INSERT, /* insert */ + IBUF_USE_DELETE_MARK, /* delete */ + IBUF_USE_INSERT_DELETE_MARK, /* insert+delete */ + IBUF_USE_DELETE, /* delete+purge */ + IBUF_USE_ALL, /* insert+delete+purge */ IBUF_USE_COUNT /* number of entries in ibuf_use_t */ } ibuf_use_t; @@ -72,8 +87,7 @@ separately committed mini-transaction, because in crash recovery, the free bits could momentarily be set too high. */ /******************************************************************//** -Creates the insert buffer data structure at a database startup and -initializes the data structures for the insert buffer of each tablespace. */ +Creates the insert buffer data structure at a database startup. */ UNIV_INTERN void ibuf_init_at_db_start(void); @@ -243,14 +257,15 @@ void ibuf_free_excess_pages(void); /*========================*/ /*********************************************************************//** -Makes an index insert to the insert buffer, instead of directly to the disk -page, if this is possible. Does not do insert if the index is clustered -or unique. +Buffer an operation in the insert/delete buffer, instead of doing it +directly to the disk page, if this is possible. Does not do it if the index +is clustered or unique. @return TRUE if success */ UNIV_INTERN ibool ibuf_insert( /*========*/ + ibuf_op_t op, /*!< in: operation type */ const dtuple_t* entry, /*!< in: index entry to insert */ dict_index_t* index, /*!< in: index where to insert */ ulint space, /*!< in: space id where to insert */ @@ -259,11 +274,11 @@ ibuf_insert( que_thr_t* thr); /*!< in: query thread */ /*********************************************************************//** When an index page is read from a disk to the buffer pool, this function -inserts to the page the possible index entries buffered in the insert buffer. -The entries are deleted from the insert buffer. If the page is not read, but -created in the buffer pool, this function deletes its buffered entries from -the insert buffer; there can exist entries for such a page if the page -belonged to an index which subsequently was dropped. */ +applies any buffered operations to the page and deletes the entries from the +insert buffer. If the page is not read, but created in the buffer pool, this +function deletes its buffered entries from the insert buffer; there can +exist entries for such a page if the page belonged to an index which +subsequently was dropped. */ UNIV_INTERN void ibuf_merge_or_delete_for_page( @@ -356,6 +371,15 @@ void ibuf_print( /*=======*/ FILE* file); /*!< in: file where to print */ +/******************************************************************** +Read the first two bytes from a record's fourth field (counter field in new +records; something else in older records). +@return "counter" field, or ULINT_UNDEFINED if for some reason it can't be read */ +UNIV_INTERN +ulint +ibuf_rec_get_counter( +/*=================*/ + const rec_t* rec); /*!< in: ibuf record */ /******************************************************************//** Closes insert buffer and frees the data structures. */ UNIV_INTERN diff --git a/storage/innobase/include/ibuf0ibuf.ic b/storage/innobase/include/ibuf0ibuf.ic index 15bbe61ab30..aee27cf9739 100644 --- a/storage/innobase/include/ibuf0ibuf.ic +++ b/storage/innobase/include/ibuf0ibuf.ic @@ -55,10 +55,15 @@ struct ibuf_struct{ ulint height; /*!< tree height */ dict_index_t* index; /*!< insert buffer index */ - ulint n_inserts; /*!< number of inserts made to - the insert buffer */ ulint n_merges; /*!< number of pages merged */ - ulint n_merged_recs; /*!< number of records merged */ + ulint n_merged_ops[IBUF_OP_COUNT]; + /*!< number of operations of each type + merged to index pages */ + ulint n_discarded_ops[IBUF_OP_COUNT]; + /*!< number of operations of each type + discarded without merging due to the + tablespace being deleted or the + index being dropped */ }; /************************************************************************//** @@ -105,7 +110,7 @@ ibuf_should_try( if (ibuf_flush_count % 4 == 0) { - buf_LRU_try_free_flushed_blocks(); + buf_LRU_try_free_flushed_blocks(NULL); } return(TRUE); diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index 82e4c9bd976..0319c0e9261 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -340,11 +340,12 @@ lock_sec_rec_modify_check_and_lock( que_thr_t* thr, /*!< in: query thread */ mtr_t* mtr); /*!< in/out: mini-transaction */ /*********************************************************************//** -Like the counterpart for a clustered index below, but now we read a +Like lock_clust_rec_read_check_and_lock(), but reads a secondary index record. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK, +or DB_QUE_THR_SUSPENDED */ UNIV_INTERN -ulint +enum db_err lock_sec_rec_read_check_and_lock( /*=============================*/ ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG @@ -371,9 +372,10 @@ if the query thread should anyway be suspended for some reason; if not, then puts the transaction and the query thread to the lock wait state and inserts a waiting request for a record lock to the lock queue. Sets the requested mode lock on the record. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK, +or DB_QUE_THR_SUSPENDED */ UNIV_INTERN -ulint +enum db_err lock_clust_rec_read_check_and_lock( /*===============================*/ ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG @@ -613,13 +615,16 @@ lock_rec_print( FILE* file, /*!< in: file where to print */ const lock_t* lock); /*!< in: record type lock */ /*********************************************************************//** -Prints info of locks for all transactions. */ +Prints info of locks for all transactions. +@return FALSE if not able to obtain kernel mutex +and exits without printing info */ UNIV_INTERN -void +ibool lock_print_info_summary( /*====================*/ - FILE* file); /*!< in: file where to print */ -/*********************************************************************//** + FILE* file, /*!< in: file where to print */ + ibool nowait);/*!< in: whether to wait for the kernel mutex */ +/************************************************************************* Prints info of locks for each transaction. */ UNIV_INTERN void @@ -634,7 +639,7 @@ UNIV_INTERN ulint lock_number_of_rows_locked( /*=======================*/ - trx_t* trx); /*!< in: transaction */ + const trx_t* trx); /*!< in: transaction */ /*******************************************************************//** Check if a transaction holds any autoinc locks. @return TRUE if the transaction holds any AUTOINC locks. */ diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index 135aeb69e2d..1ae94a332e5 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -1,23 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. - -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; 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, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ -/***************************************************************************** - -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2009, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -780,6 +763,15 @@ struct log_struct{ #ifndef UNIV_HOTBACKUP mutex_t mutex; /*!< mutex protecting the log */ #endif /* !UNIV_HOTBACKUP */ + + mutex_t log_flush_order_mutex;/*!< mutex to serialize access to + the flush list when we are putting + dirty blocks in the list. The idea + behind this mutex is to be able + to release log_sys->mutex during + mtr_commit and still ensure that + insertions in the flush_list happen + in the LSN order. */ byte* buf_ptr; /* unaligned log buffer */ byte* buf; /*!< log buffer */ ulint buf_size; /*!< log buffer size in bytes */ @@ -825,7 +817,17 @@ struct log_struct{ written to some log group; for this to be advanced, it is enough that the write i/o has been completed for all - log groups */ + log groups. + Note that since InnoDB currently + has only one log group therefore + this value is redundant. Also it + is possible that this value + falls behind the + flushed_to_disk_lsn transiently. + It is appropriate to use either + flushed_to_disk_lsn or + write_lsn which are always + up-to-date and accurate. */ ib_uint64_t write_lsn; /*!< end lsn for the current running write */ ulint write_end_offset;/*!< the data in buffer has @@ -959,6 +961,19 @@ struct log_struct{ #endif /* UNIV_LOG_ARCHIVE */ }; +/** Test if flush order mutex is owned. */ +#define log_flush_order_mutex_own() \ + mutex_own(&log_sys->log_flush_order_mutex) + +/** Acquire the flush order mutex. */ +#define log_flush_order_mutex_enter() do { \ + mutex_enter(&log_sys->log_flush_order_mutex); \ +} while (0) +/** Release the flush order mutex. */ +# define log_flush_order_mutex_exit() do { \ + mutex_exit(&log_sys->log_flush_order_mutex); \ +} while (0) + #ifdef UNIV_LOG_ARCHIVE /** Archiving state @{ */ #define LOG_ARCH_ON 71 diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic index 36d151a3064..139f4041a36 100644 --- a/storage/innobase/include/log0log.ic +++ b/storage/innobase/include/log0log.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. 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 @@ -314,12 +314,15 @@ log_reserve_and_write_fast( ulint data_len; #ifdef UNIV_LOG_LSN_DEBUG /* length of the LSN pseudo-record */ - ulint lsn_len = 1 - + mach_get_compressed_size(log_sys->lsn >> 32) - + mach_get_compressed_size(log_sys->lsn & 0xFFFFFFFFUL); + ulint lsn_len; #endif /* UNIV_LOG_LSN_DEBUG */ mutex_enter(&log_sys->mutex); +#ifdef UNIV_LOG_LSN_DEBUG + lsn_len = 1 + + mach_get_compressed_size(log_sys->lsn >> 32) + + mach_get_compressed_size(log_sys->lsn & 0xFFFFFFFFUL); +#endif /* UNIV_LOG_LSN_DEBUG */ data_len = len #ifdef UNIV_LOG_LSN_DEBUG diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h index a3d2bd050f5..9f334a34b44 100644 --- a/storage/innobase/include/log0recv.h +++ b/storage/innobase/include/log0recv.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved. 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 @@ -176,6 +176,12 @@ UNIV_INTERN void recv_recovery_from_checkpoint_finish(void); /*======================================*/ +/********************************************************//** +Initiates the rollback of active transactions. */ +UNIV_INTERN +void +recv_recovery_rollback_active(void); +/*===============================*/ /*******************************************************//** Scans log from a buffer and stores new log data to the parsing buffer. Parses and hashes the log records if new data found. Unless @@ -258,12 +264,14 @@ void recv_sys_init( /*==========*/ ulint available_memory); /*!< in: available memory in bytes */ +#ifndef UNIV_HOTBACKUP /********************************************************//** Reset the state of the recovery system variables. */ UNIV_INTERN void recv_sys_var_init(void); /*===================*/ +#endif /* !UNIV_HOTBACKUP */ /*******************************************************************//** Empties the hash table of stored log records, applying them to appropriate pages. */ @@ -360,8 +368,8 @@ typedef struct recv_addr_struct recv_addr_t; struct recv_addr_struct{ enum recv_addr_state state; /*!< recovery state of the page */ - ulint space; /*!< space id */ - ulint page_no;/*!< page number */ + unsigned space:32;/*!< space id */ + unsigned page_no:32;/*!< page number */ UT_LIST_BASE_NODE_T(recv_t) rec_list;/*!< list of log records for this page */ hash_node_t addr_hash;/*!< hash node in the hash bucket chain */ diff --git a/storage/innobase/include/mach0data.ic b/storage/innobase/include/mach0data.ic index ef20356bd31..96d2417ac81 100644 --- a/storage/innobase/include/mach0data.ic +++ b/storage/innobase/include/mach0data.ic @@ -36,7 +36,7 @@ mach_write_to_1( ulint n) /*!< in: ulint integer to be stored, >= 0, < 256 */ { ut_ad(b); - ut_ad(n <= 0xFFUL); + ut_ad((n | 0xFFUL) <= 0xFFUL); b[0] = (byte)n; } @@ -65,7 +65,7 @@ mach_write_to_2( ulint n) /*!< in: ulint integer to be stored */ { ut_ad(b); - ut_ad(n <= 0xFFFFUL); + ut_ad((n | 0xFFFFUL) <= 0xFFFFUL); b[0] = (byte)(n >> 8); b[1] = (byte)(n); @@ -81,10 +81,7 @@ mach_read_from_2( /*=============*/ const byte* b) /*!< in: pointer to 2 bytes */ { - ut_ad(b); - return( ((ulint)(b[0]) << 8) - + (ulint)(b[1]) - ); + return(((ulint)(b[0]) << 8) | (ulint)(b[1])); } /********************************************************//** @@ -129,7 +126,7 @@ mach_write_to_3( ulint n) /*!< in: ulint integer to be stored */ { ut_ad(b); - ut_ad(n <= 0xFFFFFFUL); + ut_ad((n | 0xFFFFFFUL) <= 0xFFFFFFUL); b[0] = (byte)(n >> 16); b[1] = (byte)(n >> 8); @@ -148,8 +145,8 @@ mach_read_from_3( { ut_ad(b); return( ((ulint)(b[0]) << 16) - + ((ulint)(b[1]) << 8) - + (ulint)(b[2]) + | ((ulint)(b[1]) << 8) + | (ulint)(b[2]) ); } @@ -183,9 +180,9 @@ mach_read_from_4( { ut_ad(b); return( ((ulint)(b[0]) << 24) - + ((ulint)(b[1]) << 16) - + ((ulint)(b[2]) << 8) - + (ulint)(b[3]) + | ((ulint)(b[1]) << 16) + | ((ulint)(b[2]) << 8) + | (ulint)(b[3]) ); } @@ -721,7 +718,7 @@ mach_read_from_2_little_endian( /*===========================*/ const byte* buf) /*!< in: from where to read */ { - return((ulint)(*buf) + ((ulint)(*(buf + 1))) * 256); + return((ulint)(buf[0]) | ((ulint)(buf[1]) << 8)); } /*********************************************************//** diff --git a/storage/innobase/include/mem0dbg.h b/storage/innobase/include/mem0dbg.h index a064af5c678..d81e1418b2b 100644 --- a/storage/innobase/include/mem0dbg.h +++ b/storage/innobase/include/mem0dbg.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. 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 @@ -28,6 +28,13 @@ Created 6/9/1994 Heikki Tuuri check fields whose sizes are given below */ #ifdef UNIV_MEM_DEBUG +# ifndef UNIV_HOTBACKUP +/* The mutex which protects in the debug version the hash table +containing the list of live memory heaps, and also the global +variables in mem0dbg.c. */ +extern mutex_t mem_hash_mutex; +# endif /* !UNIV_HOTBACKUP */ + #define MEM_FIELD_HEADER_SIZE ut_calc_align(2 * sizeof(ulint),\ UNIV_MEM_ALIGNMENT) #define MEM_FIELD_TRAILER_SIZE sizeof(ulint) diff --git a/storage/innobase/include/mem0dbg.ic b/storage/innobase/include/mem0dbg.ic index cb9245411dc..b0c8178a623 100644 --- a/storage/innobase/include/mem0dbg.ic +++ b/storage/innobase/include/mem0dbg.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. 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 @@ -25,9 +25,6 @@ Created 6/8/1994 Heikki Tuuri *************************************************************************/ #ifdef UNIV_MEM_DEBUG -# ifndef UNIV_HOTBACKUP -extern mutex_t mem_hash_mutex; -# endif /* !UNIV_HOTBACKUP */ extern ulint mem_current_allocated_memory; /******************************************************************//** diff --git a/storage/innobase/include/mem0mem.h b/storage/innobase/include/mem0mem.h index 98f8748e529..5181bb4c9f7 100644 --- a/storage/innobase/include/mem0mem.h +++ b/storage/innobase/include/mem0mem.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. 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 @@ -359,6 +359,9 @@ struct mem_block_info_struct { to the heap is also the first block in this list, though it also contains the base node of the list. */ ulint len; /*!< physical length of this block in bytes */ + ulint total_size; /*!< physical length in bytes of all blocks + in the heap. This is defined only in the base + node and is set to ULINT_UNDEFINED in others. */ ulint type; /*!< type of heap: MEM_HEAP_DYNAMIC, or MEM_HEAP_BUF possibly ORed to MEM_HEAP_BTR_SEARCH */ ulint free; /*!< offset in bytes of the first free position for diff --git a/storage/innobase/include/mem0mem.ic b/storage/innobase/include/mem0mem.ic index e7080d8c508..cbce2edc661 100644 --- a/storage/innobase/include/mem0mem.ic +++ b/storage/innobase/include/mem0mem.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. 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 @@ -579,18 +579,12 @@ mem_heap_get_size( /*==============*/ mem_heap_t* heap) /*!< in: heap */ { - mem_block_t* block; ulint size = 0; ut_ad(mem_heap_check(heap)); - block = heap; - - while (block != NULL) { + size = heap->total_size; - size += mem_block_get_len(block); - block = UT_LIST_GET_NEXT(list, block); - } #ifndef UNIV_HOTBACKUP if (heap->free_block) { size += UNIV_PAGE_SIZE; diff --git a/storage/innobase/include/mem0pool.h b/storage/innobase/include/mem0pool.h index 5e93bf88a47..fa8be296ec9 100644 --- a/storage/innobase/include/mem0pool.h +++ b/storage/innobase/include/mem0pool.h @@ -100,18 +100,6 @@ mem_pool_get_reserved( /*==================*/ mem_pool_t* pool); /*!< in: memory pool */ /********************************************************************//** -Reserves the mem pool mutex. */ -UNIV_INTERN -void -mem_pool_mutex_enter(void); -/*======================*/ -/********************************************************************//** -Releases the mem pool mutex. */ -UNIV_INTERN -void -mem_pool_mutex_exit(void); -/*=====================*/ -/********************************************************************//** Validates a memory pool. @return TRUE if ok */ UNIV_INTERN diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic index 310c7c4117f..18f8e87b3cf 100644 --- a/storage/innobase/include/mtr0mtr.ic +++ b/storage/innobase/include/mtr0mtr.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. 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 @@ -70,6 +70,7 @@ mtr_memo_push( ut_ad(type <= MTR_MEMO_X_LOCK); ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); memo = &(mtr->memo); @@ -92,6 +93,7 @@ mtr_set_savepoint( ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE); memo = &(mtr->memo); @@ -149,6 +151,7 @@ mtr_memo_contains( ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_ACTIVE || mtr->state == MTR_COMMITTING); memo = &(mtr->memo); diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index 16568579f31..a112cb06697 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -1,23 +1,6 @@ -/***************************************************************************** - -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. - -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; 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, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ /*********************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2009, Percona Inc. Portions of this file contain modifications contributed and copyrighted @@ -93,29 +76,23 @@ extern ulint os_n_pending_writes; #ifdef __WIN__ /** File handle */ -#define os_file_t HANDLE +# define os_file_t HANDLE /** Convert a C file descriptor to a native file handle @param fd file descriptor @return native file handle */ -#define OS_FILE_FROM_FD(fd) (HANDLE) _get_osfhandle(fd) +# define OS_FILE_FROM_FD(fd) (HANDLE) _get_osfhandle(fd) #else /** File handle */ typedef int os_file_t; /** Convert a C file descriptor to a native file handle @param fd file descriptor @return native file handle */ -#define OS_FILE_FROM_FD(fd) fd +# define OS_FILE_FROM_FD(fd) fd #endif /** Umask for creating files */ extern ulint os_innodb_umask; -/** If this flag is TRUE, then we will use the native aio of the -OS (provided we compiled Innobase with it in), otherwise we will -use simulated aio we build below with threads */ - -extern ibool os_aio_use_native_aio; - /** The next value should be smaller or equal to the smallest sector size used on any disk. A log block is required to be a portion of disk which is written so that if the start and the end of a block get written to disk, then the @@ -158,7 +135,8 @@ log. */ #define OS_FILE_SHARING_VIOLATION 76 #define OS_FILE_ERROR_NOT_SPECIFIED 77 #define OS_FILE_INSUFFICIENT_RESOURCE 78 -#define OS_FILE_OPERATION_ABORTED 79 +#define OS_FILE_AIO_INTERRUPTED 79 +#define OS_FILE_OPERATION_ABORTED 80 /* @} */ /** Types for aio operations @{ */ @@ -204,6 +182,157 @@ extern ulint os_n_file_reads; extern ulint os_n_file_writes; extern ulint os_n_fsyncs; +#ifdef UNIV_PFS_IO +/* Keys to register InnoDB I/O with performance schema */ +extern mysql_pfs_key_t innodb_file_data_key; +extern mysql_pfs_key_t innodb_file_log_key; +extern mysql_pfs_key_t innodb_file_temp_key; + +/* Following four macros are instumentations to register +various file I/O operations with performance schema. +1) register_pfs_file_open_begin() and register_pfs_file_open_end() are +used to register file creation, opening, closing and renaming. +2) register_pfs_file_io_begin() and register_pfs_file_io_end() are +used to register actual file read, write and flush */ +# define register_pfs_file_open_begin(locker, key, op, name, \ + src_file, src_line) \ +do { \ + if (PSI_server) { \ + locker = PSI_server->get_thread_file_name_locker( \ + key, op, name, &locker); \ + if (locker) { \ + PSI_server->start_file_open_wait( \ + locker, src_file, src_line); \ + } \ + } \ +} while (0) + +# define register_pfs_file_open_end(locker, file) \ +do { \ + if (locker) { \ + PSI_server->end_file_open_wait_and_bind_to_descriptor( \ + locker, file); \ + } \ +} while (0) + +# define register_pfs_file_io_begin(locker, file, count, op, \ + src_file, src_line) \ +do { \ + if (PSI_server) { \ + locker = PSI_server->get_thread_file_descriptor_locker( \ + file, op); \ + if (locker) { \ + PSI_server->start_file_wait( \ + locker, count, src_file, src_line); \ + } \ + } \ +} while (0) + +# define register_pfs_file_io_end(locker, count) \ +do { \ + if (locker) { \ + PSI_server->end_file_wait(locker, count); \ + } \ +} while (0) +#endif /* UNIV_PFS_IO */ + +/* Following macros/functions are file I/O APIs that would be performance +schema instrumented if "UNIV_PFS_IO" is defined. They would point to +wrapper functions with performance schema instrumentation in such case. + +os_file_create +os_file_create_simple +os_file_create_simple_no_error_handling +os_file_close +os_file_rename +os_aio +os_file_read +os_file_read_no_error_handling +os_file_write + +The wrapper functions have the prefix of "innodb_". */ + +#ifdef UNIV_PFS_IO +# define os_file_create(key, name, create, purpose, type, success) \ + pfs_os_file_create_func(key, name, create, purpose, type, \ + success, __FILE__, __LINE__) + +# define os_file_create_simple(key, name, create, access, success) \ + pfs_os_file_create_simple_func(key, name, create, access, \ + success, __FILE__, __LINE__) + +# define os_file_create_simple_no_error_handling( \ + key, name, create_mode, access, success) \ + pfs_os_file_create_simple_no_error_handling_func( \ + key, name, create_mode, access, success, __FILE__, __LINE__) + +# define os_file_close(file) \ + pfs_os_file_close_func(file, __FILE__, __LINE__) + +# define os_aio(type, mode, name, file, buf, offset, offset_high, \ + n, message1, message2) \ + pfs_os_aio_func(type, mode, name, file, buf, offset, \ + offset_high, n, message1, message2, \ + __FILE__, __LINE__) + +# define os_file_read(file, buf, offset, offset_high, n) \ + pfs_os_file_read_func(file, buf, offset, offset_high, n, \ + __FILE__, __LINE__) + +# define os_file_read_no_error_handling(file, buf, offset, \ + offset_high, n) \ + pfs_os_file_read_no_error_handling_func(file, buf, offset, \ + offset_high, n, \ + __FILE__, __LINE__) + +# define os_file_write(name, file, buf, offset, offset_high, n) \ + pfs_os_file_write_func(name, file, buf, offset, offset_high, \ + n, __FILE__, __LINE__) + +# define os_file_flush(file) \ + pfs_os_file_flush_func(file, __FILE__, __LINE__) + +# define os_file_rename(key, oldpath, newpath) \ + pfs_os_file_rename_func(key, oldpath, newpath, __FILE__, __LINE__) +#else /* UNIV_PFS_IO */ + +/* If UNIV_PFS_IO is not defined, these I/O APIs point +to original un-instrumented file I/O APIs */ +# define os_file_create(key, name, create, purpose, type, success) \ + os_file_create_func(name, create, purpose, type, success) + +# define os_file_create_simple(key, name, create, access, success) \ + os_file_create_simple_func(name, create_mode, access, success) + +# define os_file_create_simple_no_error_handling( \ + key, name, create_mode, access, success) \ + os_file_create_simple_no_error_handling_func( \ + name, create_mode, access, success) + +# define os_file_close(file) os_file_close_func(file) + +# define os_aio(type, mode, name, file, buf, offset, offset_high, \ + n, message1, message2) \ + os_aio_func(type, mode, name, file, buf, offset, offset_high, n,\ + message1, message2) + +# define os_file_read(file, buf, offset, offset_high, n) \ + os_file_read_func(file, buf, offset, offset_high, n) + +# define os_file_read_no_error_handling(file, buf, offset, \ + offset_high, n) \ + os_file_read_no_error_handling_func(file, buf, offset, offset_high, n) + +# define os_file_write(name, file, buf, offset, offset_high, n) \ + os_file_write_func(name, file, buf, offset, offset_high, n) + +# define os_file_flush(file) os_file_flush_func(file) + +# define os_file_rename(key, oldpath, newpath) \ + os_file_rename_func(oldpath, newpath) + +#endif /* UNIV_PFS_IO */ + /* File types for directory entry data type */ enum os_file_type_enum{ @@ -313,13 +442,15 @@ os_file_create_directory( ibool fail_if_exists);/*!< in: if TRUE, pre-existing directory is treated as an error. */ /****************************************************************//** +NOTE! Use the corresponding macro os_file_create_simple(), not directly +this function! A simple function to open or create a file. @return own: handle to the file, not defined if error, error number can be retrieved with os_file_get_last_error */ UNIV_INTERN os_file_t -os_file_create_simple( -/*==================*/ +os_file_create_simple_func( +/*=======================*/ const char* name, /*!< in: name of the file or path as a null-terminated string */ ulint create_mode,/*!< in: OS_FILE_OPEN if an existing file is @@ -333,13 +464,15 @@ os_file_create_simple( OS_FILE_READ_WRITE */ ibool* success);/*!< out: TRUE if succeed, FALSE if error */ /****************************************************************//** +NOTE! Use the corresponding macro +os_file_create_simple_no_error_handling(), not directly this function! A simple function to open or create a file. @return own: handle to the file, not defined if error, error number can be retrieved with os_file_get_last_error */ UNIV_INTERN os_file_t -os_file_create_simple_no_error_handling( -/*====================================*/ +os_file_create_simple_no_error_handling_func( +/*=========================================*/ const char* name, /*!< in: name of the file or path as a null-terminated string */ ulint create_mode,/*!< in: OS_FILE_OPEN if an existing file @@ -363,13 +496,15 @@ os_file_set_nocache( const char* operation_name);/*!< in: "open" or "create"; used in the diagnostic message */ /****************************************************************//** +NOTE! Use the corresponding macro os_file_create(), not directly +this function! Opens an existing file or creates a new. @return own: handle to the file, not defined if error, error number can be retrieved with os_file_get_last_error */ UNIV_INTERN os_file_t -os_file_create( -/*===========*/ +os_file_create_func( +/*================*/ const char* name, /*!< in: name of the file or path as a null-terminated string */ ulint create_mode,/*!< in: OS_FILE_OPEN if an existing file @@ -407,25 +542,258 @@ os_file_delete_if_exists( /*=====================*/ const char* name); /*!< in: file path as a null-terminated string */ /***********************************************************************//** +NOTE! Use the corresponding macro os_file_rename(), not directly +this function! Renames a file (can also move it to another directory). It is safest that the file is closed before calling this function. @return TRUE if success */ UNIV_INTERN ibool -os_file_rename( -/*===========*/ +os_file_rename_func( +/*================*/ const char* oldpath, /*!< in: old file path as a null-terminated string */ const char* newpath); /*!< in: new file path */ /***********************************************************************//** +NOTE! Use the corresponding macro os_file_close(), not directly this +function! Closes a file handle. In case of error, error number can be retrieved with os_file_get_last_error. @return TRUE if success */ UNIV_INTERN ibool -os_file_close( -/*==========*/ +os_file_close_func( +/*===============*/ os_file_t file); /*!< in, own: handle to a file */ + +#ifdef UNIV_PFS_IO +/****************************************************************//** +NOTE! Please use the corresponding macro os_file_create_simple(), +not directly this function! +A performance schema instrumented wrapper function for +os_file_create_simple() which opens or creates a file. +@return own: handle to the file, not defined if error, error number +can be retrieved with os_file_get_last_error */ +UNIV_INLINE +os_file_t +pfs_os_file_create_simple_func( +/*===========================*/ + mysql_pfs_key_t key, /*!< in: Performance Schema Key */ + const char* name, /*!< in: name of the file or path as a + null-terminated string */ + ulint create_mode,/*!< in: OS_FILE_OPEN if an existing file is + opened (if does not exist, error), or + OS_FILE_CREATE if a new file is created + (if exists, error), or + OS_FILE_CREATE_PATH if new file + (if exists, error) and subdirectories along + its path are created (if needed)*/ + ulint access_type,/*!< in: OS_FILE_READ_ONLY or + OS_FILE_READ_WRITE */ + ibool* success,/*!< out: TRUE if succeed, FALSE if error */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line);/*!< in: line where the func invoked */ + +/****************************************************************//** +NOTE! Please use the corresponding macro +os_file_create_simple_no_error_handling(), not directly this function! +A performance schema instrumented wrapper function for +os_file_create_simple_no_error_handling(). Add instrumentation to +monitor file creation/open. +@return own: handle to the file, not defined if error, error number +can be retrieved with os_file_get_last_error */ +UNIV_INLINE +os_file_t +pfs_os_file_create_simple_no_error_handling_func( +/*=============================================*/ + mysql_pfs_key_t key, /*!< in: Performance Schema Key */ + const char* name, /*!< in: name of the file or path as a + null-terminated string */ + ulint create_mode,/*!< in: OS_FILE_OPEN if an existing file + is opened (if does not exist, error), or + OS_FILE_CREATE if a new file is created + (if exists, error) */ + ulint access_type,/*!< in: OS_FILE_READ_ONLY, + OS_FILE_READ_WRITE, or + OS_FILE_READ_ALLOW_DELETE; the last option is + used by a backup program reading the file */ + ibool* success,/*!< out: TRUE if succeed, FALSE if error */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line);/*!< in: line where the func invoked */ + +/****************************************************************//** +NOTE! Please use the corresponding macro os_file_create(), not directly +this function! +A performance schema wrapper function for os_file_create(). +Add instrumentation to monitor file creation/open. +@return own: handle to the file, not defined if error, error number +can be retrieved with os_file_get_last_error */ +UNIV_INLINE +os_file_t +pfs_os_file_create_func( +/*====================*/ + mysql_pfs_key_t key, /*!< in: Performance Schema Key */ + const char* name, /*!< in: name of the file or path as a + null-terminated string */ + ulint create_mode,/*!< in: OS_FILE_OPEN if an existing file + is opened (if does not exist, error), or + OS_FILE_CREATE if a new file is created + (if exists, error), + OS_FILE_OVERWRITE if a new file is created + or an old overwritten; + OS_FILE_OPEN_RAW, if a raw device or disk + partition should be opened */ + ulint purpose,/*!< in: OS_FILE_AIO, if asynchronous, + non-buffered i/o is desired, + OS_FILE_NORMAL, if any normal file; + NOTE that it also depends on type, os_aio_.. + and srv_.. variables whether we really use + async i/o or unbuffered i/o: look in the + function source code for the exact rules */ + ulint type, /*!< in: OS_DATA_FILE or OS_LOG_FILE */ + ibool* success,/*!< out: TRUE if succeed, FALSE if error */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line);/*!< in: line where the func invoked */ + +/***********************************************************************//** +NOTE! Please use the corresponding macro os_file_close(), not directly +this function! +A performance schema instrumented wrapper function for os_file_close(). +@return TRUE if success */ +UNIV_INLINE +ibool +pfs_os_file_close_func( +/*===================*/ + os_file_t file, /*!< in, own: handle to a file */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line);/*!< in: line where the func invoked */ +/*******************************************************************//** +NOTE! Please use the corresponding macro os_file_read(), not directly +this function! +This is the performance schema instrumented wrapper function for +os_file_read() which requests a synchronous read operation. +@return TRUE if request was successful, FALSE if fail */ +UNIV_INLINE +ibool +pfs_os_file_read_func( +/*==================*/ + os_file_t file, /*!< in: handle to a file */ + void* buf, /*!< in: buffer where to read */ + ulint offset, /*!< in: least significant 32 bits of file + offset where to read */ + ulint offset_high,/*!< in: most significant 32 bits of + offset */ + ulint n, /*!< in: number of bytes to read */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line);/*!< in: line where the func invoked */ + +/*******************************************************************//** +NOTE! Please use the corresponding macro os_file_read_no_error_handling(), +not directly this function! +This is the performance schema instrumented wrapper function for +os_file_read_no_error_handling_func() which requests a synchronous +read operation. +@return TRUE if request was successful, FALSE if fail */ +UNIV_INLINE +ibool +pfs_os_file_read_no_error_handling_func( +/*====================================*/ + os_file_t file, /*!< in: handle to a file */ + void* buf, /*!< in: buffer where to read */ + ulint offset, /*!< in: least significant 32 bits of file + offset where to read */ + ulint offset_high,/*!< in: most significant 32 bits of + offset */ + ulint n, /*!< in: number of bytes to read */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line);/*!< in: line where the func invoked */ + +/*******************************************************************//** +NOTE! Please use the corresponding macro os_aio(), not directly this +function! +Performance schema wrapper function of os_aio() which requests +an asynchronous i/o operation. +@return TRUE if request was queued successfully, FALSE if fail */ +UNIV_INLINE +ibool +pfs_os_aio_func( +/*============*/ + ulint type, /*!< in: OS_FILE_READ or OS_FILE_WRITE */ + ulint mode, /*!< in: OS_AIO_NORMAL etc. I/O mode */ + const char* name, /*!< in: name of the file or path as a + null-terminated string */ + os_file_t file, /*!< in: handle to a file */ + void* buf, /*!< in: buffer where to read or from which + to write */ + ulint offset, /*!< in: least significant 32 bits of file + offset where to read or write */ + ulint offset_high,/*!< in: most significant 32 bits of + offset */ + ulint n, /*!< in: number of bytes to read or write */ + fil_node_t* message1,/*!< in: message for the aio handler + (can be used to identify a completed + aio operation); ignored if mode is + OS_AIO_SYNC */ + void* message2,/*!< in: message for the aio handler + (can be used to identify a completed + aio operation); ignored if mode is + OS_AIO_SYNC */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line);/*!< in: line where the func invoked */ +/*******************************************************************//** +NOTE! Please use the corresponding macro os_file_write(), not directly +this function! +This is the performance schema instrumented wrapper function for +os_file_write() which requests a synchronous write operation. +@return TRUE if request was successful, FALSE if fail */ +UNIV_INLINE +ibool +pfs_os_file_write_func( +/*===================*/ + const char* name, /*!< in: name of the file or path as a + null-terminated string */ + os_file_t file, /*!< in: handle to a file */ + const void* buf, /*!< in: buffer from which to write */ + ulint offset, /*!< in: least significant 32 bits of file + offset where to write */ + ulint offset_high,/*!< in: most significant 32 bits of + offset */ + ulint n, /*!< in: number of bytes to write */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line);/*!< in: line where the func invoked */ +/***********************************************************************//** +NOTE! Please use the corresponding macro os_file_flush(), not directly +this function! +This is the performance schema instrumented wrapper function for +os_file_flush() which flushes the write buffers of a given file to the disk. +Flushes the write buffers of a given file to the disk. +@return TRUE if success */ +UNIV_INLINE +ibool +pfs_os_file_flush_func( +/*===================*/ + os_file_t file, /*!< in, own: handle to a file */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line);/*!< in: line where the func invoked */ + +/***********************************************************************//** +NOTE! Please use the corresponding macro os_file_rename(), not directly +this function! +This is the performance schema instrumented wrapper function for +os_file_rename() +@return TRUE if success */ +UNIV_INLINE +ibool +pfs_os_file_rename_func( +/*====================*/ + mysql_pfs_key_t key, /*!< in: Performance Schema Key */ + const char* oldpath,/*!< in: old file path as a null-terminated + string */ + const char* newpath,/*!< in: new file path */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line);/*!< in: line where the func invoked */ +#endif /* UNIV_PFS_IO */ + #ifdef UNIV_HOTBACKUP /***********************************************************************//** Closes a file handle. @@ -477,12 +845,13 @@ os_file_set_eof( /*============*/ FILE* file); /*!< in: file to be truncated */ /***********************************************************************//** +NOTE! Use the corresponding macro os_file_flush(), not directly this function! Flushes the write buffers of a given file to the disk. @return TRUE if success */ UNIV_INTERN ibool -os_file_flush( -/*==========*/ +os_file_flush_func( +/*===============*/ os_file_t file); /*!< in, own: handle to a file */ /***********************************************************************//** Retrieves the last error number if an error occurs in a file io function. @@ -497,12 +866,13 @@ os_file_get_last_error( ibool report_all_errors); /*!< in: TRUE if we want an error message printed of all errors */ /*******************************************************************//** +NOTE! Use the corresponding macro os_file_read(), not directly this function! Requests a synchronous read operation. @return TRUE if request was successful, FALSE if fail */ UNIV_INTERN ibool -os_file_read( -/*=========*/ +os_file_read_func( +/*==============*/ os_file_t file, /*!< in: handle to a file */ void* buf, /*!< in: buffer where to read */ ulint offset, /*!< in: least significant 32 bits of file @@ -522,13 +892,15 @@ os_file_read_string( char* str, /*!< in: buffer where to read */ ulint size); /*!< in: size of buffer */ /*******************************************************************//** +NOTE! Use the corresponding macro os_file_read_no_error_handling(), +not directly this function! Requests a synchronous positioned read operation. This function does not do any error handling. In case of error it returns FALSE. @return TRUE if request was successful, FALSE if fail */ UNIV_INTERN ibool -os_file_read_no_error_handling( -/*===========================*/ +os_file_read_no_error_handling_func( +/*================================*/ os_file_t file, /*!< in: handle to a file */ void* buf, /*!< in: buffer where to read */ ulint offset, /*!< in: least significant 32 bits of file @@ -538,12 +910,14 @@ os_file_read_no_error_handling( ulint n); /*!< in: number of bytes to read */ /*******************************************************************//** +NOTE! Use the corresponding macro os_file_write(), not directly this +function! Requests a synchronous write operation. @return TRUE if request was successful, FALSE if fail */ UNIV_INTERN ibool -os_file_write( -/*==========*/ +os_file_write_func( +/*===============*/ const char* name, /*!< in: name of the file or path as a null-terminated string */ os_file_t file, /*!< in: handle to a file */ @@ -612,7 +986,7 @@ respectively. The caller must create an i/o handler thread for each segment in these arrays. This function also creates the sync array. No i/o handler thread needs to be created for that */ UNIV_INTERN -void +ibool os_aio_init( /*========*/ ulint n_per_seg, /*<! in: maximum number of pending aio @@ -629,12 +1003,13 @@ os_aio_free(void); /*=============*/ /*******************************************************************//** +NOTE! Use the corresponding macro os_aio(), not directly this function! Requests an asynchronous i/o operation. @return TRUE if request was queued successfully, FALSE if fail */ UNIV_INTERN ibool -os_aio( -/*===*/ +os_aio_func( +/*========*/ ulint type, /*!< in: OS_FILE_READ or OS_FILE_WRITE */ ulint mode, /*!< in: OS_AIO_NORMAL, ..., possibly ORed to OS_AIO_SIMULATED_WAKE_LATER: the @@ -802,4 +1177,36 @@ innobase_mysql_tmpfile(void); /*========================*/ #endif /* !UNIV_HOTBACKUP && !__NETWARE__ */ + +#if defined(LINUX_NATIVE_AIO) +/************************************************************************** +This function is only used in Linux native asynchronous i/o. +Waits for an aio operation to complete. This function is used to wait the +for completed requests. The aio array of pending requests is divided +into segments. The thread specifies which segment or slot it wants to wait +for. NOTE: this function will also take care of freeing the aio slot, +therefore no other thread is allowed to do the freeing! +@return TRUE if the IO was successful */ +UNIV_INTERN +ibool +os_aio_linux_handle( +/*================*/ + ulint global_seg, /*!< in: segment number in the aio array + to wait for; segment 0 is the ibuf + i/o thread, segment 1 is log i/o thread, + then follow the non-ibuf read threads, + and the last are the non-ibuf write + threads. */ + fil_node_t**message1, /*!< out: the messages passed with the */ + void** message2, /*!< aio request; note that in case the + aio operation failed, these output + parameters are valid and can be used to + restart the operation. */ + ulint* type); /*!< out: OS_FILE_WRITE or ..._READ */ +#endif /* LINUX_NATIVE_AIO */ + +#ifndef UNIV_NONINL +#include "os0file.ic" +#endif + #endif diff --git a/storage/innobase/include/os0file.ic b/storage/innobase/include/os0file.ic new file mode 100644 index 00000000000..32f0e7cf666 --- /dev/null +++ b/storage/innobase/include/os0file.ic @@ -0,0 +1,408 @@ +/***************************************************************************** + +Copyright (c) 2010, Oracle and/or its affiliates. All Rights Reserved. + +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; 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, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ + +/**************************************************//** +@file include/os0file.ic +The interface to the operating system file io + +Created 2/20/2010 Jimmy Yang +*******************************************************/ + +#include "univ.i" + +#ifdef UNIV_PFS_IO +/****************************************************************//** +NOTE! Please use the corresponding macro os_file_create_simple(), +not directly this function! +A performance schema instrumented wrapper function for +os_file_create_simple() which opens or creates a file. +@return own: handle to the file, not defined if error, error number +can be retrieved with os_file_get_last_error */ +UNIV_INLINE +os_file_t +pfs_os_file_create_simple_func( +/*===========================*/ + mysql_pfs_key_t key, /*!< in: Performance Schema Key */ + const char* name, /*!< in: name of the file or path as a + null-terminated string */ + ulint create_mode,/*!< in: OS_FILE_OPEN if an existing file is + opened (if does not exist, error), or + OS_FILE_CREATE if a new file is created + (if exists, error), or + OS_FILE_CREATE_PATH if new file + (if exists, error) and subdirectories along + its path are created (if needed)*/ + ulint access_type,/*!< in: OS_FILE_READ_ONLY or + OS_FILE_READ_WRITE */ + ibool* success,/*!< out: TRUE if succeed, FALSE if error */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line)/*!< in: line where the func invoked */ +{ + os_file_t file; + struct PSI_file_locker* locker = NULL; + + /* register a file open or creation depending on "create_mode" */ + register_pfs_file_open_begin(locker, key, + ((create_mode == OS_FILE_CREATE) + ? PSI_FILE_CREATE + : PSI_FILE_OPEN), + name, src_file, src_line); + + file = os_file_create_simple_func(name, create_mode, + access_type, success); + + /* Regsiter the returning "file" value with the system */ + register_pfs_file_open_end(locker, file); + + return(file); +} + +/****************************************************************//** +NOTE! Please use the corresponding macro +os_file_create_simple_no_error_handling(), not directly this function! +A performance schema instrumented wrapper function for +os_file_create_simple_no_error_handling(). Add instrumentation to +monitor file creation/open. +@return own: handle to the file, not defined if error, error number +can be retrieved with os_file_get_last_error */ +UNIV_INLINE +os_file_t +pfs_os_file_create_simple_no_error_handling_func( +/*=============================================*/ + mysql_pfs_key_t key, /*!< in: Performance Schema Key */ + const char* name, /*!< in: name of the file or path as a + null-terminated string */ + ulint create_mode,/*!< in: OS_FILE_OPEN if an existing file + is opened (if does not exist, error), or + OS_FILE_CREATE if a new file is created + (if exists, error) */ + ulint access_type,/*!< in: OS_FILE_READ_ONLY, + OS_FILE_READ_WRITE, or + OS_FILE_READ_ALLOW_DELETE; the last option is + used by a backup program reading the file */ + ibool* success,/*!< out: TRUE if succeed, FALSE if error */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line)/*!< in: line where the func invoked */ +{ + os_file_t file; + struct PSI_file_locker* locker = NULL; + + /* register a file open or creation depending on "create_mode" */ + register_pfs_file_open_begin(locker, key, + ((create_mode == OS_FILE_CREATE) + ? PSI_FILE_CREATE + : PSI_FILE_OPEN), + name, src_file, src_line); + + file = os_file_create_simple_no_error_handling_func( + name, create_mode, access_type, success); + + register_pfs_file_open_end(locker, file); + + return(file); +} + +/****************************************************************//** +NOTE! Please use the corresponding macro os_file_create(), not directly +this function! +A performance schema wrapper function for os_file_create(). +Add instrumentation to monitor file creation/open. +@return own: handle to the file, not defined if error, error number +can be retrieved with os_file_get_last_error */ +UNIV_INLINE +os_file_t +pfs_os_file_create_func( +/*====================*/ + mysql_pfs_key_t key, /*!< in: Performance Schema Key */ + const char* name, /*!< in: name of the file or path as a + null-terminated string */ + ulint create_mode,/*!< in: OS_FILE_OPEN if an existing file + is opened (if does not exist, error), or + OS_FILE_CREATE if a new file is created + (if exists, error), + OS_FILE_OVERWRITE if a new file is created + or an old overwritten; + OS_FILE_OPEN_RAW, if a raw device or disk + partition should be opened */ + ulint purpose,/*!< in: OS_FILE_AIO, if asynchronous, + non-buffered i/o is desired, + OS_FILE_NORMAL, if any normal file; + NOTE that it also depends on type, os_aio_.. + and srv_.. variables whether we really use + async i/o or unbuffered i/o: look in the + function source code for the exact rules */ + ulint type, /*!< in: OS_DATA_FILE or OS_LOG_FILE */ + ibool* success,/*!< out: TRUE if succeed, FALSE if error */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line)/*!< in: line where the func invoked */ +{ + os_file_t file; + struct PSI_file_locker* locker = NULL; + + /* register a file open or creation depending on "create_mode" */ + register_pfs_file_open_begin(locker, key, + ((create_mode == OS_FILE_CREATE) + ? PSI_FILE_CREATE + : PSI_FILE_OPEN), + name, src_file, src_line); + + file = os_file_create_func(name, create_mode, purpose, type, success); + + register_pfs_file_open_end(locker, file); + + return(file); +} + +/***********************************************************************//** +NOTE! Please use the corresponding macro os_file_close(), not directly +this function! +A performance schema instrumented wrapper function for os_file_close(). +@return TRUE if success */ +UNIV_INLINE +ibool +pfs_os_file_close_func( +/*===================*/ + os_file_t file, /*!< in, own: handle to a file */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line)/*!< in: line where the func invoked */ +{ + ibool result; + struct PSI_file_locker* locker = NULL; + + /* register the file close */ + register_pfs_file_io_begin(locker, file, 0, PSI_FILE_CLOSE, + src_file, src_line); + + result = os_file_close_func(file); + + register_pfs_file_io_end(locker, 0); + + return(result); +} + +/*******************************************************************//** +NOTE! Please use the corresponding macro os_aio(), not directly this +function! +Performance schema instrumented wrapper function of os_aio() which +requests an asynchronous i/o operation. +@return TRUE if request was queued successfully, FALSE if fail */ +UNIV_INLINE +ibool +pfs_os_aio_func( +/*============*/ + ulint type, /*!< in: OS_FILE_READ or OS_FILE_WRITE */ + ulint mode, /*!< in: OS_AIO_NORMAL etc. I/O mode */ + const char* name, /*!< in: name of the file or path as a + null-terminated string */ + os_file_t file, /*!< in: handle to a file */ + void* buf, /*!< in: buffer where to read or from which + to write */ + ulint offset, /*!< in: least significant 32 bits of file + offset where to read or write */ + ulint offset_high,/*!< in: most significant 32 bits of + offset */ + ulint n, /*!< in: number of bytes to read or write */ + fil_node_t* message1,/*!< in: message for the aio handler + (can be used to identify a completed + aio operation); ignored if mode is + OS_AIO_SYNC */ + void* message2,/*!< in: message for the aio handler + (can be used to identify a completed + aio operation); ignored if mode is + OS_AIO_SYNC */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line)/*!< in: line where the func invoked */ +{ + ibool result; + struct PSI_file_locker* locker = NULL; + + /* Register the read or write I/O depending on "type" */ + register_pfs_file_io_begin(locker, file, n, + (type == OS_FILE_WRITE) + ? PSI_FILE_WRITE + : PSI_FILE_READ, + src_file, src_line); + + result = os_aio_func(type, mode, name, file, buf, offset, offset_high, + n, message1, message2); + + register_pfs_file_io_end(locker, n); + + return(result); +} + +/*******************************************************************//** +NOTE! Please use the corresponding macro os_file_read(), not directly +this function! +This is the performance schema instrumented wrapper function for +os_file_read() which requests a synchronous read operation. +@return TRUE if request was successful, FALSE if fail */ +UNIV_INLINE +ibool +pfs_os_file_read_func( +/*==================*/ + os_file_t file, /*!< in: handle to a file */ + void* buf, /*!< in: buffer where to read */ + ulint offset, /*!< in: least significant 32 bits of file + offset where to read */ + ulint offset_high,/*!< in: most significant 32 bits of + offset */ + ulint n, /*!< in: number of bytes to read */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line)/*!< in: line where the func invoked */ +{ + ibool result; + struct PSI_file_locker* locker = NULL; + + register_pfs_file_io_begin(locker, file, n, PSI_FILE_READ, + src_file, src_line); + + result = os_file_read_func(file, buf, offset, offset_high, n); + + register_pfs_file_io_end(locker, n); + + return(result); +} + +/*******************************************************************//** +NOTE! Please use the corresponding macro +os_file_read_no_error_handling(), not directly this function! +This is the performance schema instrumented wrapper function for +os_file_read_no_error_handling() which requests a synchronous +positioned read operation. This function does not do any error +handling. In case of error it returns FALSE. +@return TRUE if request was successful, FALSE if fail */ +UNIV_INLINE +ibool +pfs_os_file_read_no_error_handling_func( +/*====================================*/ + os_file_t file, /*!< in: handle to a file */ + void* buf, /*!< in: buffer where to read */ + ulint offset, /*!< in: least significant 32 bits of file + offset where to read */ + ulint offset_high,/*!< in: most significant 32 bits of + offset */ + ulint n, /*!< in: number of bytes to read */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line)/*!< in: line where the func invoked */ +{ + ibool result; + struct PSI_file_locker* locker = NULL; + + register_pfs_file_io_begin(locker, file, n, PSI_FILE_READ, + src_file, src_line); + + result = os_file_read_no_error_handling_func(file, buf, offset, + offset_high, n); + + register_pfs_file_io_end(locker, n); + + return(result); +} + +/*******************************************************************//** +NOTE! Please use the corresponding macro os_file_write(), not directly +this function! +This is the performance schema instrumented wrapper function for +os_file_write() which requests a synchronous write operation. +@return TRUE if request was successful, FALSE if fail */ +UNIV_INLINE +ibool +pfs_os_file_write_func( +/*===================*/ + const char* name, /*!< in: name of the file or path as a + null-terminated string */ + os_file_t file, /*!< in: handle to a file */ + const void* buf, /*!< in: buffer from which to write */ + ulint offset, /*!< in: least significant 32 bits of file + offset where to write */ + ulint offset_high,/*!< in: most significant 32 bits of + offset */ + ulint n, /*!< in: number of bytes to write */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line)/*!< in: line where the func invoked */ +{ + ibool result; + struct PSI_file_locker* locker = NULL; + + register_pfs_file_io_begin(locker, file, n, PSI_FILE_WRITE, + src_file, src_line); + + result = os_file_write_func(name, file, buf, offset, offset_high, n); + + register_pfs_file_io_end(locker, n); + + return(result); +} + +/***********************************************************************//** +NOTE! Please use the corresponding macro os_file_flush(), not directly +this function! +This is the performance schema instrumented wrapper function for +os_file_flush() which flushes the write buffers of a given file to the disk. +@return TRUE if success */ +UNIV_INLINE +ibool +pfs_os_file_flush_func( +/*===================*/ + os_file_t file, /*!< in, own: handle to a file */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line)/*!< in: line where the func invoked */ +{ + ibool result; + struct PSI_file_locker* locker = NULL; + + register_pfs_file_io_begin(locker, file, 0, PSI_FILE_SYNC, + src_file, src_line); + result = os_file_flush_func(file); + + register_pfs_file_io_end(locker, 0); + + return(result); +} + +/***********************************************************************//** +NOTE! Please use the corresponding macro os_file_rename(), not directly +this function! +This is the performance schema instrumented wrapper function for +os_file_rename() +@return TRUE if success */ +UNIV_INLINE +ibool +pfs_os_file_rename_func( +/*====================*/ + mysql_pfs_key_t key, /*!< in: Performance Schema Key */ + const char* oldpath,/*!< in: old file path as a null-terminated + string */ + const char* newpath,/*!< in: new file path */ + const char* src_file,/*!< in: file name where func invoked */ + ulint src_line)/*!< in: line where the func invoked */ +{ + ibool result; + struct PSI_file_locker* locker = NULL; + + register_pfs_file_open_begin(locker, key, PSI_FILE_RENAME, newpath, + src_file, src_line); + + result = os_file_rename_func(oldpath, newpath); + + register_pfs_file_open_end(locker, 0); + + return(result); +} +#endif /* UNIV_PFS_IO */ diff --git a/storage/innobase/include/os0thread.h b/storage/innobase/include/os0thread.h index 6583de0005f..cc56e2158ee 100644 --- a/storage/innobase/include/os0thread.h +++ b/storage/innobase/include/os0thread.h @@ -56,6 +56,11 @@ typedef os_thread_t os_thread_id_t; /*!< In Unix we use the thread /* Define a function pointer type to use in a typecast */ typedef void* (*os_posix_f_t) (void*); +#ifdef HAVE_PSI_INTERFACE +/* Define for performance schema registration key */ +typedef unsigned int mysql_pfs_key_t; +#endif + /***************************************************************//** Compares two thread ids for equality. @return TRUE if equal */ @@ -86,7 +91,7 @@ os_thread_t os_thread_create( /*=============*/ #ifndef __WIN__ - os_posix_f_t start_f, + os_posix_f_t start_f, #else ulint (*start_f)(void*), /*!< in: pointer to function from which to start */ diff --git a/storage/innobase/include/pars0pars.h b/storage/innobase/include/pars0pars.h index fe5d76ebbb0..524fe4ac3e7 100644 --- a/storage/innobase/include/pars0pars.h +++ b/storage/innobase/include/pars0pars.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -520,6 +520,23 @@ pars_info_add_int4_literal( Equivalent to: char buf[8]; +mach_write_ull(buf, val); +pars_info_add_literal(info, name, buf, 8, DATA_INT, 0); + +except that the buffer is dynamically allocated from the info struct's +heap. */ +UNIV_INTERN +void +pars_info_add_uint64_literal( +/*=========================*/ + pars_info_t* info, /*!< in: info struct */ + const char* name, /*!< in: name */ + ib_uint64_t val); /*!< in: value */ + +/****************************************************************//** +Equivalent to: + +char buf[8]; mach_write_to_8(buf, val); pars_info_add_literal(info, name, buf, 8, DATA_BINARY, 0); diff --git a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h index 420f34550e2..39f8d07af89 100644 --- a/storage/innobase/include/que0que.h +++ b/storage/innobase/include/que0que.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -30,6 +30,7 @@ Created 5/27/1996 Heikki Tuuri #include "data0data.h" #include "dict0types.h" #include "trx0trx.h" +#include "trx0roll.h" #include "srv0srv.h" #include "usr0types.h" #include "que0types.h" @@ -215,6 +216,16 @@ trx_t* thr_get_trx( /*========*/ que_thr_t* thr); /*!< in: query thread */ +/*******************************************************************//** +Determines if this thread is rolling back an incomplete transaction +in crash recovery. +@return TRUE if thr is rolling back an incomplete transaction in crash +recovery */ +UNIV_INLINE +ibool +thr_is_recv( +/*========*/ + const que_thr_t* thr); /*!< in: query thread */ /***********************************************************************//** Gets the type of a graph node. */ UNIV_INLINE diff --git a/storage/innobase/include/que0que.ic b/storage/innobase/include/que0que.ic index a1c0dc1e77a..bd936670e1e 100644 --- a/storage/innobase/include/que0que.ic +++ b/storage/innobase/include/que0que.ic @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -38,6 +38,20 @@ thr_get_trx( return(thr->graph->trx); } +/*******************************************************************//** +Determines if this thread is rolling back an incomplete transaction +in crash recovery. +@return TRUE if thr is rolling back an incomplete transaction in crash +recovery */ +UNIV_INLINE +ibool +thr_is_recv( +/*========*/ + const que_thr_t* thr) /*!< in: query thread */ +{ + return(trx_is_recv(thr->graph->trx)); +} + /***********************************************************************//** Gets the first thr in a fork. */ UNIV_INLINE diff --git a/storage/innobase/include/rem0cmp.h b/storage/innobase/include/rem0cmp.h index 072f74267ea..2f751a38864 100644 --- a/storage/innobase/include/rem0cmp.h +++ b/storage/innobase/include/rem0cmp.h @@ -148,7 +148,9 @@ cmp_rec_rec_simple( const rec_t* rec2, /*!< in: physical record */ const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */ const ulint* offsets2,/*!< in: rec_get_offsets(rec2, ...) */ - const dict_index_t* index); /*!< in: data dictionary index */ + const dict_index_t* index, /*!< in: data dictionary index */ + ibool* null_eq);/*!< out: set to TRUE if + found matching null values */ /*************************************************************//** This function is used to compare two physical records. Only the common first fields are compared, and if an externally stored field is diff --git a/storage/innobase/include/row0merge.h b/storage/innobase/include/row0merge.h index fbeb125ce7b..be7c77e7724 100644 --- a/storage/innobase/include/row0merge.h +++ b/storage/innobase/include/row0merge.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 2005, 2010, Innobase Oy. All Rights Reserved. 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 diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index b05241f00f8..39ea240772c 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 2000, 2010, Innobase Oy. All Rights Reserved. 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 @@ -253,15 +253,6 @@ row_table_got_default_clust_index( /*==============================*/ const dict_table_t* table); /*!< in: table */ /*********************************************************************//** -Calculates the key number used inside MySQL for an Innobase index. We have -to take into account if we generated a default clustered index for the table -@return the key number used inside MySQL */ -UNIV_INTERN -ulint -row_get_mysql_key_number_for_index( -/*===============================*/ - const dict_index_t* index); /*!< in: index */ -/*********************************************************************//** Does an update or delete of a row for MySQL. @return error code or DB_SUCCESS */ UNIV_INTERN @@ -273,27 +264,26 @@ row_update_for_mysql( row_prebuilt_t* prebuilt); /*!< in: prebuilt struct in MySQL handle */ /*********************************************************************//** -This can only be used when srv_locks_unsafe_for_binlog is TRUE or -session is using a READ COMMITTED isolation level. Before -calling this function we must use trx_reset_new_rec_lock_info() and -trx_register_new_rec_lock() to store the information which new record locks -really were set. This function removes a newly set lock under prebuilt->pcur, -and also under prebuilt->clust_pcur. Currently, this is only used and tested -in the case of an UPDATE or a DELETE statement, where the row lock is of the -LOCK_X type. -Thus, this implements a 'mini-rollback' that releases the latest record -locks we set. -@return error code or DB_SUCCESS */ +This can only be used when srv_locks_unsafe_for_binlog is TRUE or this +session is using a READ COMMITTED or READ UNCOMMITTED isolation level. +Before calling this function row_search_for_mysql() must have +initialized prebuilt->new_rec_locks to store the information which new +record locks really were set. This function removes a newly set +clustered index record lock under prebuilt->pcur or +prebuilt->clust_pcur. Thus, this implements a 'mini-rollback' that +releases the latest clustered index record lock we set. +@return error code or DB_SUCCESS */ UNIV_INTERN int row_unlock_for_mysql( /*=================*/ - row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in MySQL + row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct in MySQL handle */ - ibool has_latches_on_recs);/*!< TRUE if called so that we have - the latches on the records under pcur - and clust_pcur, and we do not need to - reposition the cursors. */ + ibool has_latches_on_recs);/*!< in: TRUE if called + so that we have the latches on + the records under pcur and + clust_pcur, and we do not need + to reposition the cursors. */ /*********************************************************************//** Creates an query graph node of 'update' type to be used in the MySQL interface. @@ -403,6 +393,7 @@ row_table_add_foreign_constraints( FOREIGN KEY (a, b) REFERENCES table2(c, d), table2 can be written also with the database name before it: test.table2 */ + size_t sql_length, /*!< in: length of sql_string */ const char* name, /*!< in: table full name in the normalized form database_name/table_name */ @@ -451,6 +442,12 @@ row_drop_table_for_mysql( const char* name, /*!< in: table name */ trx_t* trx, /*!< in: transaction handle */ ibool drop_db);/*!< in: TRUE=dropping whole database */ +/*********************************************************************//** +Drop all temporary tables during crash recovery. */ +UNIV_INTERN +void +row_mysql_drop_temp_tables(void); +/*============================*/ /*********************************************************************//** Discards the tablespace of a table which stored in an .ibd file. Discarding @@ -494,14 +491,19 @@ row_rename_table_for_mysql( trx_t* trx, /*!< in: transaction handle */ ibool commit); /*!< in: if TRUE then commit trx */ /*********************************************************************//** -Checks a table for corruption. -@return DB_ERROR or DB_SUCCESS */ +Checks that the index contains entries in an ascending order, unique +constraint is not broken, and calculates the number of index entries +in the read view of the current transaction. +@return DB_SUCCESS if ok */ UNIV_INTERN ulint -row_check_table_for_mysql( +row_check_index_for_mysql( /*======================*/ - row_prebuilt_t* prebuilt); /*!< in: prebuilt struct in MySQL - handle */ + row_prebuilt_t* prebuilt, /*!< in: prebuilt struct + in MySQL handle */ + const dict_index_t* index, /*!< in: index */ + ulint* n_rows); /*!< out: number of entries + seen in the consistent read */ /*********************************************************************//** Determines if a table is a magic monitor table. @@ -699,18 +701,17 @@ struct row_prebuilt_struct { ulint new_rec_locks; /*!< normally 0; if srv_locks_unsafe_for_binlog is TRUE or session is using READ - COMMITTED isolation level, in a - cursor search, if we set a new - record lock on an index, this is - incremented; this is used in - releasing the locks under the - cursors if we are performing an - UPDATE and we determine after - retrieving the row that it does - not need to be locked; thus, - these can be used to implement a - 'mini-rollback' that releases - the latest record locks */ + COMMITTED or READ UNCOMMITTED + isolation level, set in + row_search_for_mysql() if we set a new + record lock on the secondary + or clustered index; this is + used in row_unlock_for_mysql() + when releasing the lock under + the cursor if we determine + after retrieving the row that + it does not need to be locked + ('mini-rollback') */ ulint mysql_prefix_len;/*!< byte offset of the end of the last requested column */ ulint mysql_row_len; /*!< length in bytes of a row in the diff --git a/storage/innobase/include/row0purge.h b/storage/innobase/include/row0purge.h index 89ec54fb54a..485d51dbc83 100644 --- a/storage/innobase/include/row0purge.h +++ b/storage/innobase/include/row0purge.h @@ -45,6 +45,28 @@ row_purge_node_create( que_thr_t* parent, /*!< in: parent node, i.e., a thr node */ mem_heap_t* heap); /*!< in: memory heap where created */ /***********************************************************//** +Determines if it is possible to remove a secondary index entry. +Removal is possible if the secondary index entry does not refer to any +not delete marked version of a clustered index record where DB_TRX_ID +is newer than the purge view. + +NOTE: This function should only be called by the purge thread, only +while holding a latch on the leaf page of the secondary index entry +(or keeping the buffer pool watch on the page). It is possible that +this function first returns TRUE and then FALSE, if a user transaction +inserts a record that the secondary index entry would refer to. +However, in that case, the user transaction would also re-insert the +secondary index entry after purge has removed it and released the leaf +page latch. +@return TRUE if the secondary index record can be purged */ +UNIV_INTERN +ibool +row_purge_poss_sec( +/*===============*/ + purge_node_t* node, /*!< in/out: row purge node */ + dict_index_t* index, /*!< in: secondary index */ + const dtuple_t* entry); /*!< in: secondary index entry */ +/*************************************************************** Does the purge operation for a single undo log record. This is a high-level function used in an SQL execution graph. @return query thread to run next or NULL */ diff --git a/storage/innobase/include/row0row.h b/storage/innobase/include/row0row.h index 723b7b53395..195691a420b 100644 --- a/storage/innobase/include/row0row.h +++ b/storage/innobase/include/row0row.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -257,11 +257,25 @@ row_get_clust_rec( dict_index_t* index, /*!< in: secondary index */ dict_index_t** clust_index,/*!< out: clustered index */ mtr_t* mtr); /*!< in: mtr */ + +/** Result of row_search_index_entry */ +enum row_search_result { + ROW_FOUND = 0, /*!< the record was found */ + ROW_NOT_FOUND, /*!< record not found */ + ROW_BUFFERED, /*!< one of BTR_INSERT, BTR_DELETE, or + BTR_DELETE_MARK was specified, the + secondary index leaf page was not in + the buffer pool, and the operation was + enqueued in the insert/delete buffer */ + ROW_NOT_DELETED_REF, /*!< BTR_DELETE was specified, and + row_purge_poss_sec() failed */ +}; + /***************************************************************//** Searches an index record. -@return TRUE if found */ +@return whether the record was found or buffered */ UNIV_INTERN -ibool +enum row_search_result row_search_index_entry( /*===================*/ dict_index_t* index, /*!< in: index */ diff --git a/storage/innobase/include/row0sel.h b/storage/innobase/include/row0sel.h index 01a5afaa23e..8544b9d08ba 100644 --- a/storage/innobase/include/row0sel.h +++ b/storage/innobase/include/row0sel.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved. 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 @@ -105,17 +105,6 @@ row_fetch_print( /*============*/ void* row, /*!< in: sel_node_t* */ void* user_arg); /*!< in: not used */ -/****************************************************************//** -Callback function for fetch that stores an unsigned 4 byte integer to the -location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length -= 4. -@return always returns NULL */ -UNIV_INTERN -void* -row_fetch_store_uint4( -/*==================*/ - void* row, /*!< in: sel_node_t* */ - void* user_arg); /*!< in: data pointer */ /***********************************************************//** Prints a row in a select result. @return query thread to run next or NULL */ diff --git a/storage/innobase/include/row0types.h b/storage/innobase/include/row0types.h index 1be729206ba..7d6a7c8e2b1 100644 --- a/storage/innobase/include/row0types.h +++ b/storage/innobase/include/row0types.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 diff --git a/storage/innobase/include/srv0que.h b/storage/innobase/include/srv0que.h deleted file mode 100644 index 82ee7739ef7..00000000000 --- a/storage/innobase/include/srv0que.h +++ /dev/null @@ -1,42 +0,0 @@ -/***************************************************************************** - -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. - -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; 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, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ - -/**************************************************//** -@file include/srv0que.h -Server query execution - -Created 6/5/1996 Heikki Tuuri -*******************************************************/ - -#ifndef srv0que_h -#define srv0que_h - -#include "univ.i" -#include "que0types.h" - -/**********************************************************************//** -Enqueues a task to server task queue and releases a worker thread, if there -is a suspended one. */ -UNIV_INTERN -void -srv_que_task_enqueue_low( -/*=====================*/ - que_thr_t* thr); /*!< in: query thread */ - -#endif - diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index ce7f6004813..98e127d41e2 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -1,7 +1,8 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, 2009, Google Inc. +Copyright (c) 2009, Percona Inc. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -9,6 +10,13 @@ briefly in the InnoDB documentation. The contributions by Google are incorporated with their permission, and subject to the conditions contained in the file COPYING.Google. +Portions of this file contain modifications contributed and copyrighted +by Percona Inc.. Those modifications are +gratefully acknowledged and are described briefly in the InnoDB +documentation. The contributions by Percona Inc. are incorporated with +their permission, and subject to the conditions contained in the file +COPYING.Percona. + 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; version 2 of the License. @@ -22,32 +30,6 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ -/*********************************************************************** - -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. -Copyright (c) 2009, Percona Inc. - -Portions of this file contain modifications contributed and copyrighted -by Percona Inc.. Those modifications are -gratefully acknowledged and are described briefly in the InnoDB -documentation. The contributions by Percona Inc. are incorporated with -their permission, and subject to the conditions contained in the file -COPYING.Percona. - -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; 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, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -***********************************************************************/ /**************************************************//** @file include/srv0srv.h @@ -125,6 +107,11 @@ on duplicate key checking and foreign key checking */ extern ibool srv_locks_unsafe_for_binlog; #endif /* !UNIV_HOTBACKUP */ +/* If this flag is TRUE, then we will use the native aio of the +OS (provided we compiled Innobase with it in), otherwise we will +use simulated aio we build below with threads. +Currently we support native aio on windows and linux */ +extern my_bool srv_use_native_aio; extern ulint srv_n_data_files; extern char** srv_data_file_names; extern ulint* srv_data_file_sizes; @@ -155,6 +142,7 @@ extern my_bool srv_use_sys_malloc; extern ibool srv_use_sys_malloc; #endif /* UNIV_HOTBACKUP */ extern ulint srv_buf_pool_size; /*!< requested size in bytes */ +extern ulint srv_buf_pool_instances; /*!< requested number of buffer pool instances */ extern ulint srv_buf_pool_old_size; /*!< previously requested size */ extern ulint srv_buf_pool_curr_size; /*!< current size in bytes */ extern ulint srv_mem_pool_size; @@ -224,7 +212,8 @@ extern ibool srv_print_innodb_tablespace_monitor; extern ibool srv_print_verbose_log; extern ibool srv_print_innodb_table_monitor; -extern ibool srv_lock_timeout_and_monitor_active; +extern ibool srv_lock_timeout_active; +extern ibool srv_monitor_active; extern ibool srv_error_monitor_active; extern ulong srv_n_spin_wait_rounds; @@ -283,6 +272,12 @@ extern ulint srv_os_log_pending_writes; log buffer and have to flush it */ extern ulint srv_log_waits; +/* the number of purge threads to use from the worker pool (currently 0 or 1) */ +extern ulong srv_n_purge_threads; + +/* the number of records to purge in one batch */ +extern ulong srv_purge_batch_size; + /* variable that counts amount of data read in total (in bytes) */ extern ulint srv_data_read; @@ -324,6 +319,38 @@ typedef struct srv_sys_struct srv_sys_t; /** The server system */ extern srv_sys_t* srv_sys; + +# ifdef UNIV_PFS_THREAD +/* Keys to register InnoDB threads with performance schema */ +extern mysql_pfs_key_t trx_rollback_clean_thread_key; +extern mysql_pfs_key_t io_handler_thread_key; +extern mysql_pfs_key_t srv_lock_timeout_thread_key; +extern mysql_pfs_key_t srv_error_monitor_thread_key; +extern mysql_pfs_key_t srv_monitor_thread_key; +extern mysql_pfs_key_t srv_master_thread_key; +extern mysql_pfs_key_t srv_purge_thread_key; + +/* This macro register the current thread and its key with performance +schema */ +# define pfs_register_thread(key) \ +do { \ + if (PSI_server) { \ + struct PSI_thread* psi = PSI_server->new_thread(key, NULL, 0);\ + if (psi) { \ + PSI_server->set_thread(psi); \ + } \ + } \ +} while (0) + +/* This macro delist the current thread from performance schema */ +# define pfs_delete_thread() \ +do { \ + if (PSI_server) { \ + PSI_server->delete_current_thread(); \ + } \ +} while (0) +# endif /* UNIV_PFS_THREAD */ + #endif /* !UNIV_HOTBACKUP */ /** Types of raw partitions in innodb_data_file_path */ @@ -464,6 +491,12 @@ srv_master_thread( void* arg); /*!< in: a dummy parameter required by os_thread_create */ /*******************************************************************//** +Wakes up the purge thread if it's not already awake. */ +UNIV_INTERN +void +srv_wake_purge_thread(void); +/*=======================*/ +/*******************************************************************//** Tells the Innobase server that there has been activity in the database and wakes up the master thread if it is suspended (not sleeping). Used in the MySQL interface. Note that there is a small chance that the master @@ -479,6 +512,16 @@ UNIV_INTERN void srv_wake_master_thread(void); /*========================*/ +/*******************************************************************//** +Tells the purge thread that there has been activity in the database +and wakes up the purge thread if it is suspended (not sleeping). Note +that there is a small chance that the purge thread stays suspended +(we do not protect our operation with the kernel mutex, for +performace reasons). */ +UNIV_INTERN +void +srv_wake_purge_thread_if_not_active(void); +/*=====================================*/ /*********************************************************************//** Puts an OS thread to wait if there are too many concurrent threads (>= srv_thread_concurrency) inside InnoDB. The threads wait in a FIFO queue. */ @@ -537,15 +580,23 @@ srv_release_mysql_thread_if_suspended( MySQL OS thread */ /*********************************************************************//** A thread which wakes up threads whose lock wait may have lasted too long. -This also prints the info output by various InnoDB monitors. @return a dummy parameter */ UNIV_INTERN os_thread_ret_t -srv_lock_timeout_and_monitor_thread( -/*================================*/ +srv_lock_timeout_thread( +/*====================*/ void* arg); /*!< in: a dummy parameter required by os_thread_create */ /*********************************************************************//** +A thread which prints the info output by various InnoDB monitors. +@return a dummy parameter */ +UNIV_INTERN +os_thread_ret_t +srv_monitor_thread( +/*===============*/ + void* arg); /*!< in: a dummy parameter required by + os_thread_create */ +/************************************************************************* A thread which prints warnings about semaphore waits which have lasted too long. These can be used to track bugs which cause hangs. @return a dummy parameter */ @@ -556,12 +607,15 @@ srv_error_monitor_thread( void* arg); /*!< in: a dummy parameter required by os_thread_create */ /******************************************************************//** -Outputs to a file the output of the InnoDB Monitor. */ +Outputs to a file the output of the InnoDB Monitor. +@return FALSE if not all information printed +due to failure to obtain necessary mutex */ UNIV_INTERN -void +ibool srv_printf_innodb_monitor( /*======================*/ FILE* file, /*!< in: output stream */ + ibool nowait, /*!< in: whether to wait for kernel mutex */ ulint* trx_start, /*!< out: file position of the start of the list of active transactions */ ulint* trx_end); /*!< out: file position of the end of @@ -574,11 +628,32 @@ void srv_export_innodb_status(void); /*==========================*/ -/** Thread slot in the thread table */ -typedef struct srv_slot_struct srv_slot_t; +/*********************************************************************//** +Asynchronous purge thread. +@return a dummy parameter */ +UNIV_INTERN +os_thread_ret_t +srv_purge_thread( +/*=============*/ + void* arg __attribute__((unused))); /*!< in: a dummy parameter + required by os_thread_create */ + +/**********************************************************************//** +Enqueues a task to server task queue and releases a worker thread, if there +is a suspended one. */ +UNIV_INTERN +void +srv_que_task_enqueue_low( +/*=====================*/ + que_thr_t* thr); /*!< in: query thread */ -/** Thread table is an array of slots */ -typedef srv_slot_t srv_table_t; +/**********************************************************************//** +Check whether any background thread is active. +@return FALSE if all are are suspended or have exited. */ +UNIV_INTERN +ibool +srv_is_any_background_thread_active(void); +/*======================================*/ /** Status variables to be passed to MySQL */ struct export_var_struct{ @@ -634,6 +709,12 @@ struct export_var_struct{ ulint innodb_rows_deleted; /*!< srv_n_rows_deleted */ }; +/** Thread slot in the thread table */ +typedef struct srv_slot_struct srv_slot_t; + +/** Thread table is an array of slots */ +typedef srv_slot_t srv_table_t; + /** The server system struct */ struct srv_sys_struct{ srv_table_t* threads; /*!< server thread table */ @@ -643,8 +724,9 @@ struct srv_sys_struct{ extern ulint srv_n_threads_active[]; #else /* !UNIV_HOTBACKUP */ -# define srv_use_checksums TRUE # define srv_use_adaptive_hash_indexes FALSE +# define srv_use_checksums TRUE +# define srv_use_native_aio FALSE # define srv_force_recovery 0UL # define srv_set_io_thread_op_info(t,info) ((void) 0) # define srv_is_being_started 0 diff --git a/storage/innobase/include/sync0rw.h b/storage/innobase/include/sync0rw.h index aedfd5f3f86..70471186f6d 100644 --- a/storage/innobase/include/sync0rw.h +++ b/storage/innobase/include/sync0rw.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -105,23 +105,140 @@ extern ib_int64_t rw_x_os_wait_count; set only when UNIV_SYNC_PERF_STAT is defined */ extern ib_int64_t rw_x_exit_count; +#ifdef UNIV_PFS_RWLOCK +/* Following are rwlock keys used to register with MySQL +performance schema */ +# ifdef UNIV_LOG_ARCHIVE +extern mysql_pfs_key_t archive_lock_key; +# endif /* UNIV_LOG_ARCHIVE */ +extern mysql_pfs_key_t btr_search_latch_key; +extern mysql_pfs_key_t buf_block_lock_key; +# ifdef UNIV_SYNC_DEBUG +extern mysql_pfs_key_t buf_block_debug_latch_key; +# endif /* UNIV_SYNC_DEBUG */ +extern mysql_pfs_key_t dict_operation_lock_key; +extern mysql_pfs_key_t fil_space_latch_key; +extern mysql_pfs_key_t checkpoint_lock_key; +extern mysql_pfs_key_t trx_i_s_cache_lock_key; +extern mysql_pfs_key_t trx_purge_latch_key; +extern mysql_pfs_key_t index_tree_rw_lock_key; +#endif /* UNIV_PFS_RWLOCK */ + + +#ifndef UNIV_PFS_RWLOCK /******************************************************************//** Creates, or rather, initializes an rw-lock object in a specified memory location (which must be appropriately aligned). The rw-lock is initialized to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free -is necessary only if the memory block containing it is freed. */ -#ifdef UNIV_DEBUG -# ifdef UNIV_SYNC_DEBUG -# define rw_lock_create(L, level) \ +is necessary only if the memory block containing it is freed. +if MySQL performance schema is enabled and "UNIV_PFS_RWLOCK" is +defined, the rwlock are instrumented with performance schema probes. */ +# ifdef UNIV_DEBUG +# ifdef UNIV_SYNC_DEBUG +# define rw_lock_create(K, L, level) \ rw_lock_create_func((L), (level), #L, __FILE__, __LINE__) -# else /* UNIV_SYNC_DEBUG */ -# define rw_lock_create(L, level) \ +# else /* UNIV_SYNC_DEBUG */ +# define rw_lock_create(K, L, level) \ rw_lock_create_func((L), #L, __FILE__, __LINE__) -# endif /* UNIV_SYNC_DEBUG */ -#else /* UNIV_DEBUG */ -# define rw_lock_create(L, level) \ +# endif/* UNIV_SYNC_DEBUG */ +# else /* UNIV_DEBUG */ +# define rw_lock_create(K, L, level) \ rw_lock_create_func((L), __FILE__, __LINE__) -#endif /* UNIV_DEBUG */ +# endif /* UNIV_DEBUG */ + +/**************************************************************//** +NOTE! The following macros should be used in rw locking and +unlocking, not the corresponding function. */ + +# define rw_lock_s_lock(M) \ + rw_lock_s_lock_func((M), 0, __FILE__, __LINE__) + +# define rw_lock_s_lock_gen(M, P) \ + rw_lock_s_lock_func((M), (P), __FILE__, __LINE__) + +# define rw_lock_s_lock_nowait(M, F, L) \ + rw_lock_s_lock_low((M), 0, (F), (L)) + +# ifdef UNIV_SYNC_DEBUG +# define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(P, L) +# else +# define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(L) +# endif + + +# define rw_lock_x_lock(M) \ + rw_lock_x_lock_func((M), 0, __FILE__, __LINE__) + +# define rw_lock_x_lock_gen(M, P) \ + rw_lock_x_lock_func((M), (P), __FILE__, __LINE__) + +# define rw_lock_x_lock_nowait(M) \ + rw_lock_x_lock_func_nowait((M), __FILE__, __LINE__) + +# ifdef UNIV_SYNC_DEBUG +# define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(P, L) +# else +# define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(L) +# endif + +# define rw_lock_free(M) rw_lock_free_func(M) + +#else /* !UNIV_PFS_RWLOCK */ + +/* Following macros point to Performance Schema instrumented functions. */ +# ifdef UNIV_DEBUG +# ifdef UNIV_SYNC_DEBUG +# define rw_lock_create(K, L, level) \ + pfs_rw_lock_create_func((K), (L), (level), #L, __FILE__, __LINE__) +# else /* UNIV_SYNC_DEBUG */ +# define rw_lock_create(K, L, level) \ + pfs_rw_lock_create_func((K), (L), #L, __FILE__, __LINE__) +# endif/* UNIV_SYNC_DEBUG */ +# else /* UNIV_DEBUG */ +# define rw_lock_create(K, L, level) \ + pfs_rw_lock_create_func((K), (L), __FILE__, __LINE__) +# endif /* UNIV_DEBUG */ + +/****************************************************************** +NOTE! The following macros should be used in rw locking and +unlocking, not the corresponding function. */ + +# define rw_lock_s_lock(M) \ + pfs_rw_lock_s_lock_func((M), 0, __FILE__, __LINE__) + +# define rw_lock_s_lock_gen(M, P) \ + pfs_rw_lock_s_lock_func((M), (P), __FILE__, __LINE__) + +# define rw_lock_s_lock_nowait(M, F, L) \ + pfs_rw_lock_s_lock_low((M), 0, (F), (L)) + +# ifdef UNIV_SYNC_DEBUG +# define rw_lock_s_unlock_gen(L, P) pfs_rw_lock_s_unlock_func(P, L) +# else +# define rw_lock_s_unlock_gen(L, P) pfs_rw_lock_s_unlock_func(L) +# endif + +# define rw_lock_x_lock(M) \ + pfs_rw_lock_x_lock_func((M), 0, __FILE__, __LINE__) + +# define rw_lock_x_lock_gen(M, P) \ + pfs_rw_lock_x_lock_func((M), (P), __FILE__, __LINE__) + +# define rw_lock_x_lock_nowait(M) \ + pfs_rw_lock_x_lock_func_nowait((M), __FILE__, __LINE__) + +# ifdef UNIV_SYNC_DEBUG +# define rw_lock_x_unlock_gen(L, P) pfs_rw_lock_x_unlock_func(P, L) +# else +# define rw_lock_x_unlock_gen(L, P) pfs_rw_lock_x_unlock_func(L) +# endif + +# define rw_lock_free(M) pfs_rw_lock_free_func(M) + +#endif /* UNIV_PFS_RWLOCK */ + +#define rw_lock_s_unlock(L) rw_lock_s_unlock_gen(L, 0) +#define rw_lock_x_unlock(L) rw_lock_x_unlock_gen(L, 0) /******************************************************************//** Creates, or rather, initializes an rw-lock object in a specified memory @@ -137,18 +254,18 @@ rw_lock_create_func( # ifdef UNIV_SYNC_DEBUG ulint level, /*!< in: level */ # endif /* UNIV_SYNC_DEBUG */ - const char* cmutex_name, /*!< in: mutex name */ + const char* cmutex_name, /*!< in: mutex name */ #endif /* UNIV_DEBUG */ const char* cfile_name, /*!< in: file name where created */ - ulint cline); /*!< in: file line where created */ + ulint cline); /*!< in: file line where created */ /******************************************************************//** Calling this function is obligatory only if the memory buffer containing the rw-lock is freed. Removes an rw-lock object from the global list. The rw-lock is checked to be in the non-locked state. */ UNIV_INTERN void -rw_lock_free( -/*=========*/ +rw_lock_free_func( +/*==============*/ rw_lock_t* lock); /*!< in: rw-lock */ #ifdef UNIV_DEBUG /******************************************************************//** @@ -161,24 +278,6 @@ rw_lock_validate( /*=============*/ rw_lock_t* lock); /*!< in: rw-lock */ #endif /* UNIV_DEBUG */ -/**************************************************************//** -NOTE! The following macros should be used in rw s-locking, not the -corresponding function. */ - -#define rw_lock_s_lock(M) rw_lock_s_lock_func(\ - (M), 0, __FILE__, __LINE__) -/**************************************************************//** -NOTE! The following macros should be used in rw s-locking, not the -corresponding function. */ - -#define rw_lock_s_lock_gen(M, P) rw_lock_s_lock_func(\ - (M), (P), __FILE__, __LINE__) -/**************************************************************//** -NOTE! The following macros should be used in rw s-locking, not the -corresponding function. */ - -#define rw_lock_s_lock_nowait(M, F, L) rw_lock_s_lock_low(\ - (M), 0, (F), (L)) /******************************************************************//** Low-level function which tries to lock an rw-lock in s-mode. Performs no spinning. @@ -233,33 +332,6 @@ rw_lock_s_unlock_func( #endif rw_lock_t* lock); /*!< in/out: rw-lock */ -#ifdef UNIV_SYNC_DEBUG -# define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(P, L) -#else -# define rw_lock_s_unlock_gen(L, P) rw_lock_s_unlock_func(L) -#endif -/*******************************************************************//** -Releases a shared mode lock. */ -#define rw_lock_s_unlock(L) rw_lock_s_unlock_gen(L, 0) - -/**************************************************************//** -NOTE! The following macro should be used in rw x-locking, not the -corresponding function. */ - -#define rw_lock_x_lock(M) rw_lock_x_lock_func(\ - (M), 0, __FILE__, __LINE__) -/**************************************************************//** -NOTE! The following macro should be used in rw x-locking, not the -corresponding function. */ - -#define rw_lock_x_lock_gen(M, P) rw_lock_x_lock_func(\ - (M), (P), __FILE__, __LINE__) -/**************************************************************//** -NOTE! The following macros should be used in rw x-locking, not the -corresponding function. */ - -#define rw_lock_x_lock_nowait(M) rw_lock_x_lock_func_nowait(\ - (M), __FILE__, __LINE__) /******************************************************************//** NOTE! Use the corresponding macro, not directly this function! Lock an rw-lock in exclusive mode for the current thread. If the rw-lock is locked @@ -290,14 +362,6 @@ rw_lock_x_unlock_func( #endif rw_lock_t* lock); /*!< in/out: rw-lock */ -#ifdef UNIV_SYNC_DEBUG -# define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(P, L) -#else -# define rw_lock_x_unlock_gen(L, P) rw_lock_x_unlock_func(L) -#endif -/*******************************************************************//** -Releases an exclusive mode lock. */ -#define rw_lock_x_unlock(L) rw_lock_x_unlock_gen(L, 0) /******************************************************************//** Low-level function which locks an rw-lock in s-mode when we know that it @@ -429,8 +493,9 @@ ibool rw_lock_own( /*========*/ rw_lock_t* lock, /*!< in: rw-lock */ - ulint lock_type); /*!< in: lock type: RW_LOCK_SHARED, + ulint lock_type) /*!< in: lock type: RW_LOCK_SHARED, RW_LOCK_EX */ + __attribute__((warn_unused_result)); #endif /* UNIV_SYNC_DEBUG */ /******************************************************************//** Checks if somebody has locked the rw-lock in the specified mode. */ @@ -539,6 +604,9 @@ struct rw_lock_struct { info list of the lock */ ulint level; /*!< Level in the global latching order. */ #endif /* UNIV_SYNC_DEBUG */ +#ifdef UNIV_PFS_RWLOCK + struct PSI_rwlock *pfs_psi;/*!< The instrumentation hook */ +#endif ulint count_os_wait; /*!< Count of os_waits. May not be accurate */ const char* cfile_name;/*!< File name where lock created */ /* last s-lock file/line is not guaranteed to be correct */ @@ -554,11 +622,12 @@ struct rw_lock_struct { unsigned cline:14; /*!< Line where created */ unsigned last_s_line:14; /*!< Line number where last time s-locked */ unsigned last_x_line:14; /*!< Line number where last time x-locked */ +#ifdef UNIV_DEBUG ulint magic_n; /*!< RW_LOCK_MAGIC_N */ -}; - /** Value of rw_lock_struct::magic_n */ #define RW_LOCK_MAGIC_N 22643 +#endif /* UNIV_DEBUG */ +}; #ifdef UNIV_SYNC_DEBUG /** The structure for storing debug info of an rw-lock */ @@ -577,6 +646,160 @@ struct rw_lock_debug_struct { }; #endif /* UNIV_SYNC_DEBUG */ +/* For performance schema instrumentation, a new set of rwlock +wrap functions are created if "UNIV_PFS_RWLOCK" is defined. +The instrumentations are not planted directly into original +functions, so that we keep the underlying function as they +are. And in case, user wants to "take out" some rwlock from +instrumentation even if performance schema (UNIV_PFS_RWLOCK) +is defined, they can do so by reinstating APIs directly link to +original underlying functions. +The instrumented function names have prefix of "pfs_rw_lock_" vs. +original name prefix of "rw_lock_". Following are list of functions +that have been instrumented: + +rw_lock_create() +rw_lock_x_lock() +rw_lock_x_lock_gen() +rw_lock_x_lock_nowait() +rw_lock_x_unlock_gen() +rw_lock_s_lock() +rw_lock_s_lock_gen() +rw_lock_s_lock_nowait() +rw_lock_s_unlock_gen() +rw_lock_free() + +Two function APIs rw_lock_x_unlock_direct() and rw_lock_s_unlock_direct() +do not have any caller/user, they are not instrumented. +*/ + +#ifdef UNIV_PFS_RWLOCK +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_create_func() +NOTE! Please use the corresponding macro rw_lock_create(), not +directly this function! */ +UNIV_INLINE +void +pfs_rw_lock_create_func( +/*====================*/ + PSI_rwlock_key key, /*!< in: key registered with + performance schema */ + rw_lock_t* lock, /*!< in: rw lock */ +#ifdef UNIV_DEBUG +# ifdef UNIV_SYNC_DEBUG + ulint level, /*!< in: level */ +# endif /* UNIV_SYNC_DEBUG */ + const char* cmutex_name, /*!< in: mutex name */ +#endif /* UNIV_DEBUG */ + const char* cfile_name, /*!< in: file name where created */ + ulint cline); /*!< in: file line where created */ + +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_x_lock_func() +NOTE! Please use the corresponding macro rw_lock_x_lock(), not +directly this function! */ +UNIV_INLINE +void +pfs_rw_lock_x_lock_func( +/*====================*/ + rw_lock_t* lock, /*!< in: pointer to rw-lock */ + ulint pass, /*!< in: pass value; != 0, if the lock will + be passed to another thread to unlock */ + const char* file_name,/*!< in: file name where lock requested */ + ulint line); /*!< in: line where requested */ +/******************************************************************//** +Performance schema instrumented wrap function for +rw_lock_x_lock_func_nowait() +NOTE! Please use the corresponding macro, not directly this function! +@return TRUE if success */ +UNIV_INLINE +ibool +pfs_rw_lock_x_lock_func_nowait( +/*===========================*/ + rw_lock_t* lock, /*!< in: pointer to rw-lock */ + const char* file_name,/*!< in: file name where lock requested */ + ulint line); /*!< in: line where requested */ +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_s_lock_func() +NOTE! Please use the corresponding macro rw_lock_s_lock(), not directly +this function! */ +UNIV_INLINE +void +pfs_rw_lock_s_lock_func( +/*====================*/ + rw_lock_t* lock, /*!< in: pointer to rw-lock */ + ulint pass, /*!< in: pass value; != 0, if the lock will + be passed to another thread to unlock */ + const char* file_name,/*!< in: file name where lock requested */ + ulint line); /*!< in: line where requested */ +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_s_lock_func() +NOTE! Please use the corresponding macro rw_lock_s_lock(), not directly +this function! +@return TRUE if success */ +UNIV_INLINE +ibool +pfs_rw_lock_s_lock_low( +/*===================*/ + rw_lock_t* lock, /*!< in: pointer to rw-lock */ + ulint pass, /*!< in: pass value; != 0, if the + lock will be passed to another + thread to unlock */ + const char* file_name, /*!< in: file name where lock requested */ + ulint line); /*!< in: line where requested */ +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_x_lock_func() +NOTE! Please use the corresponding macro rw_lock_x_lock(), not directly +this function! */ +UNIV_INLINE +void +pfs_rw_lock_x_lock_func( +/*====================*/ + rw_lock_t* lock, /*!< in: pointer to rw-lock */ + ulint pass, /*!< in: pass value; != 0, if the lock will + be passed to another thread to unlock */ + const char* file_name,/*!< in: file name where lock requested */ + ulint line); /*!< in: line where requested */ +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_s_unlock_func() +NOTE! Please use the corresponding macro rw_lock_s_unlock(), not directly +this function! */ +UNIV_INLINE +void +pfs_rw_lock_s_unlock_func( +/*======================*/ +#ifdef UNIV_SYNC_DEBUG + ulint pass, /*!< in: pass value; != 0, if the + lock may have been passed to another + thread to unlock */ +#endif + rw_lock_t* lock); /*!< in/out: rw-lock */ +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_s_unlock_func() +NOTE! Please use the corresponding macro rw_lock_x_unlock(), not directly +this function! */ +UNIV_INLINE +void +pfs_rw_lock_x_unlock_func( +/*======================*/ +#ifdef UNIV_SYNC_DEBUG + ulint pass, /*!< in: pass value; != 0, if the + lock may have been passed to another + thread to unlock */ +#endif + rw_lock_t* lock); /*!< in/out: rw-lock */ +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_free_func() +NOTE! Please use the corresponding macro rw_lock_free(), not directly +this function! */ +UNIV_INLINE +void +pfs_rw_lock_free_func( +/*==================*/ + rw_lock_t* lock); /*!< in: rw-lock */ +#endif /* UNIV_PFS_RWLOCK */ + + #ifndef UNIV_NONINL #include "sync0rw.ic" #endif diff --git a/storage/innobase/include/sync0rw.ic b/storage/innobase/include/sync0rw.ic index 7116f1b7c9b..73405759bce 100644 --- a/storage/innobase/include/sync0rw.ic +++ b/storage/innobase/include/sync0rw.ic @@ -622,3 +622,265 @@ rw_lock_x_unlock_direct( rw_x_exit_count++; #endif } + +#ifdef UNIV_PFS_RWLOCK + +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_create_func(). +NOTE! Please use the corresponding macro rw_lock_create(), not directly +this function! */ +UNIV_INLINE +void +pfs_rw_lock_create_func( +/*====================*/ + mysql_pfs_key_t key, /*!< in: key registered with + performance schema */ + rw_lock_t* lock, /*!< in: pointer to memory */ +# ifdef UNIV_DEBUG +# ifdef UNIV_SYNC_DEBUG + ulint level, /*!< in: level */ +# endif /* UNIV_SYNC_DEBUG */ + const char* cmutex_name, /*!< in: mutex name */ +# endif /* UNIV_DEBUG */ + const char* cfile_name, /*!< in: file name where created */ + ulint cline) /*!< in: file line where created */ +{ + /* Initialize the rwlock for performance schema */ + lock->pfs_psi = (PSI_server && PFS_IS_INSTRUMENTED(key)) + ? PSI_server->init_rwlock(key, lock) + : NULL; + + /* The actual function to initialize an rwlock */ + rw_lock_create_func(lock, +# ifdef UNIV_DEBUG +# ifdef UNIV_SYNC_DEBUG + level, +# endif /* UNIV_SYNC_DEBUG */ + cmutex_name, +# endif /* UNIV_DEBUG */ + cfile_name, + cline); +} +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_x_lock_func() +NOTE! Please use the corresponding macro rw_lock_x_lock(), not directly +this function! */ +UNIV_INLINE +void +pfs_rw_lock_x_lock_func( +/*====================*/ + rw_lock_t* lock, /*!< in: pointer to rw-lock */ + ulint pass, /*!< in: pass value; != 0, if the lock will + be passed to another thread to unlock */ + const char* file_name,/*!< in: file name where lock requested */ + ulint line) /*!< in: line where requested */ +{ + struct PSI_rwlock_locker* locker = NULL; + + /* Record the entry of rw x lock request in performance schema */ + if (UNIV_LIKELY(PSI_server && lock->pfs_psi)) { + locker = PSI_server->get_thread_rwlock_locker( + lock->pfs_psi, PSI_RWLOCK_WRITELOCK); + + if (locker) { + PSI_server->start_rwlock_wrwait(locker, + file_name, line); + } + } + + rw_lock_x_lock_func(lock, pass, file_name, line); + + if (locker) { + PSI_server->end_rwlock_wrwait(locker, 0); + } +} +/******************************************************************//** +Performance schema instrumented wrap function for +rw_lock_x_lock_func_nowait() +NOTE! Please use the corresponding macro rw_lock_x_lock_func(), +not directly this function! +@return TRUE if success */ +UNIV_INLINE +ibool +pfs_rw_lock_x_lock_func_nowait( +/*===========================*/ + rw_lock_t* lock, /*!< in: pointer to rw-lock */ + const char* file_name,/*!< in: file name where lock + requested */ + ulint line) /*!< in: line where requested */ +{ + struct PSI_rwlock_locker* locker = NULL; + ibool ret; + + /* Record the entry of rw x lock request in performance schema */ + if (UNIV_LIKELY(PSI_server && lock->pfs_psi)) { + locker = PSI_server->get_thread_rwlock_locker( + lock->pfs_psi, PSI_RWLOCK_WRITELOCK); + + if (locker) { + PSI_server->start_rwlock_wrwait(locker, + file_name, line); + } + } + + ret = rw_lock_x_lock_func_nowait(lock, file_name, line); + + if (locker) { + PSI_server->end_rwlock_wrwait(locker, 0); + } + + return(ret); +} +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_free_func() +NOTE! Please use the corresponding macro rw_lock_free(), not directly +this function! */ +UNIV_INLINE +void +pfs_rw_lock_free_func( +/*==================*/ + rw_lock_t* lock) /*!< in: pointer to rw-lock */ +{ + if (UNIV_LIKELY(PSI_server && lock->pfs_psi)) { + PSI_server->destroy_rwlock(lock->pfs_psi); + lock->pfs_psi = NULL; + } + + rw_lock_free_func(lock); +} +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_s_lock_func() +NOTE! Please use the corresponding macro rw_lock_s_lock(), not +directly this function! */ +UNIV_INLINE +void +pfs_rw_lock_s_lock_func( +/*====================*/ + rw_lock_t* lock, /*!< in: pointer to rw-lock */ + ulint pass, /*!< in: pass value; != 0, if the + lock will be passed to another + thread to unlock */ + const char* file_name,/*!< in: file name where lock + requested */ + ulint line) /*!< in: line where requested */ +{ + struct PSI_rwlock_locker* locker = NULL; + + /* Instrumented to inform we are aquiring a shared rwlock */ + if (UNIV_LIKELY(PSI_server && lock->pfs_psi)) { + locker = PSI_server->get_thread_rwlock_locker( + lock->pfs_psi, PSI_RWLOCK_READLOCK); + if (locker) { + PSI_server->start_rwlock_rdwait(locker, + file_name, line); + } + } + + rw_lock_s_lock_func(lock, pass, file_name, line); + + if (locker) { + PSI_server->end_rwlock_rdwait(locker, 0); + } +} +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_s_lock_func() +NOTE! Please use the corresponding macro rw_lock_s_lock(), not +directly this function! +@return TRUE if success */ +UNIV_INLINE +ibool +pfs_rw_lock_s_lock_low( +/*===================*/ + rw_lock_t* lock, /*!< in: pointer to rw-lock */ + ulint pass, /*!< in: pass value; != 0, if the + lock will be passed to another + thread to unlock */ + const char* file_name, /*!< in: file name where lock requested */ + ulint line) /*!< in: line where requested */ +{ + + struct PSI_rwlock_locker* locker = NULL; + ibool ret; + + /* Instrumented to inform we are aquiring a shared rwlock */ + if (UNIV_LIKELY(PSI_server && lock->pfs_psi)) { + locker = PSI_server->get_thread_rwlock_locker( + lock->pfs_psi, PSI_RWLOCK_READLOCK); + if (locker) { + PSI_server->start_rwlock_rdwait(locker, + file_name, line); + } + } + + ret = rw_lock_s_lock_low(lock, pass, file_name, line); + + if (locker) { + PSI_server->end_rwlock_rdwait(locker, 0); + } + + return(ret); +} + +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_x_unlock_func() +NOTE! Please use the corresponding macro rw_lock_x_unlock(), not directly +this function! */ +UNIV_INLINE +void +pfs_rw_lock_x_unlock_func( +/*======================*/ +#ifdef UNIV_SYNC_DEBUG + ulint pass, /*!< in: pass value; != 0, if the + lock may have been passed to another + thread to unlock */ +#endif + rw_lock_t* lock) /*!< in/out: rw-lock */ +{ + /* Inform performance schema we are unlocking the lock */ + if (UNIV_LIKELY(PSI_server && lock->pfs_psi)) { + struct PSI_thread* thread; + thread = PSI_server->get_thread(); + if (thread) { + PSI_server->unlock_rwlock(thread, lock->pfs_psi); + } + } + + rw_lock_x_unlock_func( +#ifdef UNIV_SYNC_DEBUG + pass, +#endif + lock); +} + +/******************************************************************//** +Performance schema instrumented wrap function for rw_lock_s_unlock_func() +NOTE! Please use the corresponding macro pfs_rw_lock_s_unlock(), not +directly this function! */ +UNIV_INLINE +void +pfs_rw_lock_s_unlock_func( +/*======================*/ +#ifdef UNIV_SYNC_DEBUG + ulint pass, /*!< in: pass value; != 0, if the + lock may have been passed to another + thread to unlock */ +#endif + rw_lock_t* lock) /*!< in/out: rw-lock */ +{ + /* Inform performance schema we are unlocking the lock */ + if (UNIV_LIKELY(PSI_server && lock->pfs_psi)) { + struct PSI_thread* thread; + thread = PSI_server->get_thread(); + if (thread) { + PSI_server->unlock_rwlock(thread, lock->pfs_psi); + } + } + + rw_lock_s_unlock_func( +#ifdef UNIV_SYNC_DEBUG + pass, +#endif + lock); + +} +#endif /* UNIV_PFS_RWLOCK */ diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index df990823cc4..4e73bee9108 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -52,6 +52,69 @@ typedef LONG lock_word_t; /*!< On Windows, InterlockedExchange operates typedef byte lock_word_t; #endif +#if defined UNIV_PFS_MUTEX || defined UNIV_PFS_RWLOCK +/* There are mutexes/rwlocks that we want to exclude from +instrumentation even if their corresponding performance schema +define is set. And this PFS_NOT_INSTRUMENTED is used +as the key value to dentify those objects that would +be excluded from instrumentation. */ +# define PFS_NOT_INSTRUMENTED ULINT32_UNDEFINED + +# define PFS_IS_INSTRUMENTED(key) ((key) != PFS_NOT_INSTRUMENTED) + +/* By default, buffer mutexes and rwlocks will be excluded from +instrumentation due to their large number of instances. */ +# define PFS_SKIP_BUFFER_MUTEX_RWLOCK + +#endif /* UNIV_PFS_MUTEX || UNIV_PFS_RWLOCK */ + +#ifdef UNIV_PFS_MUTEX +/* Key defines to register InnoDB mutexes with performance schema */ +extern mysql_pfs_key_t autoinc_mutex_key; +extern mysql_pfs_key_t btr_search_enabled_mutex_key; +extern mysql_pfs_key_t buffer_block_mutex_key; +extern mysql_pfs_key_t buf_pool_mutex_key; +extern mysql_pfs_key_t buf_pool_zip_mutex_key; +extern mysql_pfs_key_t cache_last_read_mutex_key; +extern mysql_pfs_key_t dict_foreign_err_mutex_key; +extern mysql_pfs_key_t dict_sys_mutex_key; +extern mysql_pfs_key_t file_format_max_mutex_key; +extern mysql_pfs_key_t fil_system_mutex_key; +extern mysql_pfs_key_t flush_list_mutex_key; +extern mysql_pfs_key_t hash_table_mutex_key; +extern mysql_pfs_key_t ibuf_bitmap_mutex_key; +extern mysql_pfs_key_t ibuf_mutex_key; +extern mysql_pfs_key_t ibuf_pessimistic_insert_mutex_key; +extern mysql_pfs_key_t ios_mutex_key; +extern mysql_pfs_key_t log_sys_mutex_key; +extern mysql_pfs_key_t log_flush_order_mutex_key; +extern mysql_pfs_key_t kernel_mutex_key; +# ifdef UNIV_MEM_DEBUG +extern mysql_pfs_key_t mem_hash_mutex_key; +# endif /* UNIV_MEM_DEBUG */ +extern mysql_pfs_key_t mem_pool_mutex_key; +extern mysql_pfs_key_t mutex_list_mutex_key; +extern mysql_pfs_key_t purge_sys_mutex_key; +extern mysql_pfs_key_t recv_sys_mutex_key; +extern mysql_pfs_key_t rseg_mutex_key; +# ifdef UNIV_SYNC_DEBUG +extern mysql_pfs_key_t rw_lock_debug_mutex_key; +# endif /* UNIV_SYNC_DEBUG */ +extern mysql_pfs_key_t rw_lock_list_mutex_key; +extern mysql_pfs_key_t rw_lock_mutex_key; +extern mysql_pfs_key_t srv_dict_tmpfile_mutex_key; +extern mysql_pfs_key_t srv_innodb_monitor_mutex_key; +extern mysql_pfs_key_t srv_misc_tmpfile_mutex_key; +extern mysql_pfs_key_t srv_monitor_file_mutex_key; +extern mysql_pfs_key_t syn_arr_mutex_key; +# ifdef UNIV_SYNC_DEBUG +extern mysql_pfs_key_t sync_thread_mutex_key; +# endif /* UNIV_SYNC_DEBUG */ +extern mysql_pfs_key_t trx_doublewrite_mutex_key; +extern mysql_pfs_key_t thr_local_mutex_key; +extern mysql_pfs_key_t trx_undo_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + /******************************************************************//** Initializes the synchronization data structures. */ UNIV_INTERN @@ -64,24 +127,82 @@ UNIV_INTERN void sync_close(void); /*===========*/ + +#undef mutex_free /* Fix for MacOS X */ + +#ifdef UNIV_PFS_MUTEX +/********************************************************************** +Following mutex APIs would be performance schema instrumented +if "UNIV_PFS_MUTEX" is defined: + +mutex_create +mutex_enter +mutex_exit +mutex_enter_nowait +mutex_free + +These mutex APIs will point to corresponding wrapper functions that contain +the performance schema instrumentation if "UNIV_PFS_MUTEX" is defined. +The instrumented wrapper functions have the prefix of "innodb_". + +NOTE! The following macro should be used in mutex operation, not the +corresponding function. */ + /******************************************************************//** Creates, or rather, initializes a mutex object to a specified memory location (which must be appropriately aligned). The mutex is initialized in the reset state. Explicit freeing of the mutex with mutex_free is necessary only if the memory block containing it is freed. */ +# ifdef UNIV_DEBUG +# ifdef UNIV_SYNC_DEBUG +# define mutex_create(K, M, level) \ + pfs_mutex_create_func((K), (M), #M, (level), __FILE__, __LINE__) +# else +# define mutex_create(K, M, level) \ + pfs_mutex_create_func((K), (M), #M, __FILE__, __LINE__) +# endif/* UNIV_SYNC_DEBUG */ +# else +# define mutex_create(K, M, level) \ + pfs_mutex_create_func((K), (M), __FILE__, __LINE__) +# endif /* UNIV_DEBUG */ -#ifdef UNIV_DEBUG -# ifdef UNIV_SYNC_DEBUG -# define mutex_create(M, level) \ +# define mutex_enter(M) \ + pfs_mutex_enter_func((M), __FILE__, __LINE__) + +# define mutex_enter_nowait(M) \ + pfs_mutex_enter_nowait_func((M), __FILE__, __LINE__) + +# define mutex_exit(M) pfs_mutex_exit_func(M) + +# define mutex_free(M) pfs_mutex_free_func(M) + +#else /* UNIV_PFS_MUTEX */ + +/* If "UNIV_PFS_MUTEX" is not defined, the mutex APIs point to +original non-instrumented functions */ +# ifdef UNIV_DEBUG +# ifdef UNIV_SYNC_DEBUG +# define mutex_create(K, M, level) \ mutex_create_func((M), #M, (level), __FILE__, __LINE__) -# else -# define mutex_create(M, level) \ +# else /* UNIV_SYNC_DEBUG */ +# define mutex_create(K, M, level) \ mutex_create_func((M), #M, __FILE__, __LINE__) -# endif -#else -# define mutex_create(M, level) \ +# endif /* UNIV_SYNC_DEBUG */ +# else /* UNIV_DEBUG */ +# define mutex_create(K, M, level) \ mutex_create_func((M), __FILE__, __LINE__) -#endif +# endif /* UNIV_DEBUG */ + +# define mutex_enter(M) mutex_enter_func((M), __FILE__, __LINE__) + +# define mutex_enter_nowait(M) \ + mutex_enter_nowait_func((M), __FILE__, __LINE__) + +# define mutex_exit(M) mutex_exit_func(M) + +# define mutex_free(M) mutex_free_func(M) + +#endif /* UNIV_PFS_MUTEX */ /******************************************************************//** Creates, or rather, initializes a mutex object in a specified memory @@ -102,26 +223,20 @@ mutex_create_func( const char* cfile_name, /*!< in: file name where created */ ulint cline); /*!< in: file line where created */ -#undef mutex_free /* Fix for MacOS X */ - /******************************************************************//** +NOTE! Use the corresponding macro mutex_free(), not directly this function! Calling this function is obligatory only if the memory buffer containing the mutex is freed. Removes a mutex object from the mutex list. The mutex is checked to be in the reset state. */ UNIV_INTERN void -mutex_free( -/*=======*/ +mutex_free_func( +/*============*/ mutex_t* mutex); /*!< in: mutex */ /**************************************************************//** NOTE! The following macro should be used in mutex locking, not the corresponding function. */ -#define mutex_enter(M) mutex_enter_func((M), __FILE__, __LINE__) -/**************************************************************//** -NOTE! The following macro should be used in mutex locking, not the -corresponding function. */ - /* NOTE! currently same as mutex_enter! */ #define mutex_enter_fast(M) mutex_enter_func((M), __FILE__, __LINE__) @@ -137,12 +252,6 @@ mutex_enter_func( mutex_t* mutex, /*!< in: pointer to mutex */ const char* file_name, /*!< in: file name where locked */ ulint line); /*!< in: line where locked */ -/**************************************************************//** -NOTE! The following macro should be used in mutex locking, not the -corresponding function. */ - -#define mutex_enter_nowait(M) \ - mutex_enter_nowait_func((M), __FILE__, __LINE__) /********************************************************************//** NOTE! Use the corresponding macro in the header file, not this function directly. Tries to lock the mutex for the current thread. If the lock is not @@ -157,12 +266,86 @@ mutex_enter_nowait_func( requested */ ulint line); /*!< in: line where requested */ /******************************************************************//** +NOTE! Use the corresponding macro mutex_exit(), not directly this function! Unlocks a mutex owned by the current thread. */ UNIV_INLINE void -mutex_exit( -/*=======*/ +mutex_exit_func( +/*============*/ mutex_t* mutex); /*!< in: pointer to mutex */ + + +#ifdef UNIV_PFS_MUTEX +/******************************************************************//** +NOTE! Please use the corresponding macro mutex_create(), not directly +this function! +A wrapper function for mutex_create_func(), registers the mutex +with peformance schema if "UNIV_PFS_MUTEX" is defined when +creating the mutex */ +UNIV_INLINE +void +pfs_mutex_create_func( +/*==================*/ + PSI_mutex_key key, /*!< in: Performance Schema key */ + mutex_t* mutex, /*!< in: pointer to memory */ +# ifdef UNIV_DEBUG + const char* cmutex_name, /*!< in: mutex name */ +# ifdef UNIV_SYNC_DEBUG + ulint level, /*!< in: level */ +# endif /* UNIV_SYNC_DEBUG */ +# endif /* UNIV_DEBUG */ + const char* cfile_name, /*!< in: file name where created */ + ulint cline); /*!< in: file line where created */ +/******************************************************************//** +NOTE! Please use the corresponding macro mutex_enter(), not directly +this function! +This is a performance schema instrumented wrapper function for +mutex_enter_func(). */ +UNIV_INLINE +void +pfs_mutex_enter_func( +/*=================*/ + mutex_t* mutex, /*!< in: pointer to mutex */ + const char* file_name, /*!< in: file name where locked */ + ulint line); /*!< in: line where locked */ +/********************************************************************//** +NOTE! Please use the corresponding macro mutex_enter_nowait(), not directly +this function! +This is a performance schema instrumented wrapper function for +mutex_enter_nowait_func. +@return 0 if succeed, 1 if not */ +UNIV_INLINE +ulint +pfs_mutex_enter_nowait_func( +/*========================*/ + mutex_t* mutex, /*!< in: pointer to mutex */ + const char* file_name, /*!< in: file name where mutex + requested */ + ulint line); /*!< in: line where requested */ +/******************************************************************//** +NOTE! Please use the corresponding macro mutex_exit(), not directly +this function! +A wrap function of mutex_exit_func() with peformance schema instrumentation. +Unlocks a mutex owned by the current thread. */ +UNIV_INLINE +void +pfs_mutex_exit_func( +/*================*/ + mutex_t* mutex); /*!< in: pointer to mutex */ + +/******************************************************************//** +NOTE! Please use the corresponding macro mutex_free(), not directly +this function! +Wrapper function for mutex_free_func(). Also destroys the performance +schema probes when freeing the mutex */ +UNIV_INLINE +void +pfs_mutex_free_func( +/*================*/ + mutex_t* mutex); /*!< in: mutex */ + +#endif /* UNIV_PFS_MUTEX */ + #ifdef UNIV_SYNC_DEBUG /******************************************************************//** Returns TRUE if no mutex or rw-lock is currently locked. @@ -206,7 +389,8 @@ UNIV_INTERN ibool mutex_own( /*======*/ - const mutex_t* mutex); /*!< in: mutex */ + const mutex_t* mutex) /*!< in: mutex */ + __attribute__((warn_unused_result)); #endif /* UNIV_DEBUG */ #ifdef UNIV_SYNC_DEBUG /******************************************************************//** @@ -238,16 +422,27 @@ ibool sync_thread_levels_empty(void); /*==========================*/ /******************************************************************//** -Checks that the level array for the current thread is empty. -@return TRUE if empty except the exceptions specified below */ +Checks if the level array for the current thread contains a +mutex or rw-latch at the specified level. +@return a matching latch, or NULL if not found */ UNIV_INTERN -ibool -sync_thread_levels_empty_gen( -/*=========================*/ +void* +sync_thread_levels_contains( +/*========================*/ + ulint level); /*!< in: latching order level + (SYNC_DICT, ...)*/ +/******************************************************************//** +Checks if the level array for the current thread is empty. +@return a latch, or NULL if empty except the exceptions specified below */ +UNIV_INTERN +void* +sync_thread_levels_nonempty_gen( +/*============================*/ ibool dict_mutex_allowed); /*!< in: TRUE if dictionary mutex is allowed to be owned by the thread, also purge_is_running mutex is allowed */ +#define sync_thread_levels_empty_gen(d) (!sync_thread_levels_nonempty_gen(d)) /******************************************************************//** Gets the debug information for a reserved mutex. */ UNIV_INTERN @@ -466,6 +661,7 @@ or row lock! */ #define SYNC_TRX_LOCK_HEAP 298 #define SYNC_TRX_SYS_HEADER 290 #define SYNC_LOG 170 +#define SYNC_LOG_FLUSH_ORDER 147 #define SYNC_RECV 168 #define SYNC_WORK_QUEUE 162 #define SYNC_SEARCH_SYS_CONF 161 /* for assigning btr_search_enabled */ @@ -475,8 +671,9 @@ or row lock! */ SYNC_SEARCH_SYS, as memory allocation can call routines there! Otherwise the level is SYNC_MEM_HASH. */ -#define SYNC_BUF_POOL 150 -#define SYNC_BUF_BLOCK 149 +#define SYNC_BUF_POOL 150 /* Buffer pool mutex */ +#define SYNC_BUF_BLOCK 146 /* Block mutex */ +#define SYNC_BUF_FLUSH_LIST 145 /* Buffer flush list mutex */ #define SYNC_DOUBLEWRITE 140 #define SYNC_ANY_LATCH 135 #define SYNC_THR_LOCAL 133 @@ -538,6 +735,10 @@ struct mutex_struct { const char* cmutex_name; /*!< mutex name */ ulint mutex_type; /*!< 0=usual mutex, 1=rw_lock mutex */ #endif /* UNIV_DEBUG */ +#ifdef UNIV_PFS_MUTEX + struct PSI_mutex* pfs_psi; /*!< The performance schema + instrumentation hook */ +#endif }; /** The global array of wait cells for implementation of the databases own diff --git a/storage/innobase/include/sync0sync.ic b/storage/innobase/include/sync0sync.ic index b05020b5660..cf080e2e3ce 100644 --- a/storage/innobase/include/sync0sync.ic +++ b/storage/innobase/include/sync0sync.ic @@ -152,11 +152,12 @@ mutex_get_waiters( } /******************************************************************//** +NOTE! Use the corresponding macro mutex_exit(), not directly this function! Unlocks a mutex owned by the current thread. */ UNIV_INLINE void -mutex_exit( -/*=======*/ +mutex_exit_func( +/*============*/ mutex_t* mutex) /*!< in: pointer to mutex */ { ut_ad(mutex_own(mutex)); @@ -220,3 +221,148 @@ mutex_enter_func( mutex_spin_wait(mutex, file_name, line); } + +#ifdef UNIV_PFS_MUTEX +/******************************************************************//** +NOTE! Please use the corresponding macro mutex_enter(), not directly +this function! +This is a performance schema instrumented wrapper function for +mutex_enter_func(). */ +UNIV_INLINE +void +pfs_mutex_enter_func( +/*=================*/ + mutex_t* mutex, /*!< in: pointer to mutex */ + const char* file_name, /*!< in: file name where locked */ + ulint line) /*!< in: line where locked */ +{ + struct PSI_mutex_locker* locker = NULL; + int result = 0; + + if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) { + locker = PSI_server->get_thread_mutex_locker( + mutex->pfs_psi, PSI_MUTEX_LOCK); + if (locker) { + PSI_server->start_mutex_wait(locker, file_name, line); + } + } + + mutex_enter_func(mutex, file_name, line); + + if (locker) { + PSI_server->end_mutex_wait(locker, result); + } +} +/********************************************************************//** +NOTE! Please use the corresponding macro mutex_enter_nowait(), not directly +this function! +This is a performance schema instrumented wrapper function for +mutex_enter_nowait_func. +@return 0 if succeed, 1 if not */ +UNIV_INLINE +ulint +pfs_mutex_enter_nowait_func( +/*========================*/ + mutex_t* mutex, /*!< in: pointer to mutex */ + const char* file_name, /*!< in: file name where mutex + requested */ + ulint line) /*!< in: line where requested */ +{ + ulint ret; + struct PSI_mutex_locker* locker = NULL; + int result = 0; + + if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) { + locker = PSI_server->get_thread_mutex_locker( + mutex->pfs_psi, PSI_MUTEX_LOCK); + if (locker) { + PSI_server->start_mutex_wait(locker, file_name, line); + } + } + + ret = mutex_enter_nowait_func(mutex, file_name, line); + + if (locker) { + PSI_server->end_mutex_wait(locker, result); + } + + return(ret); +} +/******************************************************************//** +NOTE! Please use the corresponding macro mutex_exit(), not directly +this function! +A wrap function of mutex_exit_func() with performance schema instrumentation. +Unlocks a mutex owned by the current thread. */ +UNIV_INLINE +void +pfs_mutex_exit_func( +/*================*/ + mutex_t* mutex) /*!< in: pointer to mutex */ +{ + if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) { + struct PSI_thread* thread; + thread = PSI_server->get_thread(); + + if (thread) { + PSI_server->unlock_mutex(thread, mutex->pfs_psi); + } + } + + mutex_exit_func(mutex); +} + +/******************************************************************//** +NOTE! Please use the corresponding macro mutex_create(), not directly +this function! +A wrapper function for mutex_create_func(), registers the mutex +with performance schema if "UNIV_PFS_MUTEX" is defined when +creating the mutex */ +UNIV_INLINE +void +pfs_mutex_create_func( +/*==================*/ + mysql_pfs_key_t key, /*!< in: Performance Schema key */ + mutex_t* mutex, /*!< in: pointer to memory */ +# ifdef UNIV_DEBUG + const char* cmutex_name, /*!< in: mutex name */ +# ifdef UNIV_SYNC_DEBUG + ulint level, /*!< in: level */ +# endif /* UNIV_SYNC_DEBUG */ +# endif /* UNIV_DEBUG */ + const char* cfile_name, /*!< in: file name where created */ + ulint cline) /*!< in: file line where created */ +{ + mutex->pfs_psi = (PSI_server && PFS_IS_INSTRUMENTED(key)) + ? PSI_server->init_mutex(key, mutex) + : NULL; + + mutex_create_func(mutex, +# ifdef UNIV_DEBUG + cmutex_name, +# ifdef UNIV_SYNC_DEBUG + level, +# endif /* UNIV_SYNC_DEBUG */ +# endif /* UNIV_DEBUG */ + cfile_name, + cline); +} +/******************************************************************//** +NOTE! Please use the corresponding macro mutex_free(), not directly +this function! +Wrapper function for mutex_free_func(). Also destroys the performance +schema probes when freeing the mutex */ +UNIV_INLINE +void +pfs_mutex_free_func( +/*================*/ + mutex_t* mutex) /*!< in: mutex */ +{ + if (UNIV_LIKELY(PSI_server && mutex->pfs_psi)) { + PSI_server->destroy_mutex(mutex->pfs_psi); + mutex->pfs_psi = NULL; + } + + mutex_free_func(mutex); +} + +#endif /* UNIV_PFS_MUTEX */ diff --git a/storage/innobase/include/trx0i_s.h b/storage/innobase/include/trx0i_s.h index 7bd4e1b88c8..c610782c229 100644 --- a/storage/innobase/include/trx0i_s.h +++ b/storage/innobase/include/trx0i_s.h @@ -44,6 +44,37 @@ i_s_locks_row_t::lock_data */ i_s_trx_row_t::trx_query */ #define TRX_I_S_TRX_QUERY_MAX_LEN 1024 +/** The maximum length of a string that can be stored in +i_s_trx_row_t::trx_operation_state */ +#define TRX_I_S_TRX_OP_STATE_MAX_LEN 64 + +/** The maximum length of a string that can be stored in +i_s_trx_row_t::trx_foreign_key_error */ +#define TRX_I_S_TRX_FK_ERROR_MAX_LEN 256 + +/** The maximum length of a string that can be stored in +i_s_trx_row_t::trx_isolation_level */ +#define TRX_I_S_TRX_ISOLATION_LEVEL_MAX_LEN 16 + +/** Safely copy strings in to the INNODB_TRX table's +string based columns */ +#define TRX_I_S_STRING_COPY(data, field, constraint, tcache) \ +do { \ + if (strlen(data) > constraint) { \ + char buff[constraint + 1]; \ + strncpy(buff, data, constraint); \ + buff[constraint] = '\0'; \ + \ + field = ha_storage_put_memlim( \ + (tcache)->storage, buff, constraint + 1,\ + MAX_ALLOWED_FOR_STORAGE(tcache)); \ + } else { \ + field = ha_storage_put_str_memlim( \ + (tcache)->storage, data, \ + MAX_ALLOWED_FOR_STORAGE(tcache)); \ + } \ +} while (0) + /** A row of INFORMATION_SCHEMA.innodb_locks */ typedef struct i_s_locks_row_struct i_s_locks_row_t; /** A row of INFORMATION_SCHEMA.innodb_trx */ @@ -95,21 +126,49 @@ struct i_s_locks_row_struct { /** This structure represents INFORMATION_SCHEMA.innodb_trx row */ struct i_s_trx_row_struct { - ullint trx_id; /*!< transaction identifier */ - const char* trx_state; /*!< transaction state from - trx_get_que_state_str() */ - ib_time_t trx_started; /*!< trx_struct::start_time */ + ullint trx_id; /*!< transaction identifier */ + const char* trx_state; /*!< transaction state from + trx_get_que_state_str() */ + ib_time_t trx_started; /*!< trx_struct::start_time */ const i_s_locks_row_t* requested_lock_row; - /*!< pointer to a row - in innodb_locks if trx - is waiting, or NULL */ - ib_time_t trx_wait_started; - /*!< trx_struct::wait_started */ - ullint trx_weight; /*!< TRX_WEIGHT() */ - ulint trx_mysql_thread_id; - /*!< thd_get_thread_id() */ - const char* trx_query; /*!< MySQL statement being - executed in the transaction */ + /*!< pointer to a row + in innodb_locks if trx + is waiting, or NULL */ + ib_time_t trx_wait_started; /*!< trx_struct::wait_started */ + ullint trx_weight; /*!< TRX_WEIGHT() */ + ulint trx_mysql_thread_id; /*!< thd_get_thread_id() */ + const char* trx_query; /*!< MySQL statement being + executed in the transaction */ + const char* trx_operation_state; /*!< trx_struct::op_info */ + ulint trx_tables_in_use;/*!< n_mysql_tables_in_use in + trx_struct */ + ulint trx_tables_locked; + /*!< mysql_n_tables_locked in + trx_struct */ + ulint trx_lock_structs;/*!< list len of trx_locks in + trx_struct */ + ulint trx_lock_memory_bytes; + /*!< mem_heap_get_size( + trx->lock_heap) */ + ulint trx_rows_locked;/*!< lock_number_of_rows_locked() */ + ullint trx_rows_modified;/*!< trx_struct::undo_no */ + ulint trx_concurrency_tickets; + /*!< n_tickets_to_enter_innodb in + trx_struct */ + const char* trx_isolation_level; + /*!< isolation_level in trx_struct*/ + ibool trx_unique_checks; + /*!< check_unique_secondary in + trx_struct*/ + ibool trx_foreign_key_checks; + /*!< check_foreigns in trx_struct */ + const char* trx_foreign_key_error; + /*!< detailed_error in trx_struct */ + ibool trx_has_search_latch; + /*!< has_search_latch in trx_struct */ + ulint trx_search_latch_timeout; + /*!< search_latch_timeout in + trx_struct */ }; /** This structure represents INFORMATION_SCHEMA.innodb_lock_waits row */ diff --git a/storage/innobase/include/trx0purge.h b/storage/innobase/include/trx0purge.h index 908760580f6..d2730a68a78 100644 --- a/storage/innobase/include/trx0purge.h +++ b/storage/innobase/include/trx0purge.h @@ -112,8 +112,10 @@ This function runs a purge batch. @return number of undo log pages handled in the batch */ UNIV_INTERN ulint -trx_purge(void); -/*===========*/ +trx_purge( +/*======*/ + ulint limit); /*!< in: the maximum number of records to + purge in one batch */ /******************************************************************//** Prints information of the purge system to stderr. */ UNIV_INTERN diff --git a/storage/innobase/include/trx0rseg.h b/storage/innobase/include/trx0rseg.h index ba1fc88b6c4..78a7a8c4bb0 100644 --- a/storage/innobase/include/trx0rseg.h +++ b/storage/innobase/include/trx0rseg.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -103,7 +103,7 @@ trx_rseg_header_create( ulint zip_size, /*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint max_size, /*!< in: max size in pages */ - ulint* slot_no, /*!< out: rseg id == slot number in trx sys */ + ulint rseg_slot_no, /*!< in: rseg id == slot number in trx sys */ mtr_t* mtr); /*!< in: mtr */ /*********************************************************************//** Creates the memory copies for rollback segments and initializes the @@ -114,17 +114,6 @@ trx_rseg_list_and_array_init( /*=========================*/ trx_sysf_t* sys_header, /*!< in: trx system header */ mtr_t* mtr); /*!< in: mtr */ -/****************************************************************//** -Creates a new rollback segment to the database. -@return the created segment object, NULL if fail */ -UNIV_INTERN -trx_rseg_t* -trx_rseg_create( -/*============*/ - ulint space, /*!< in: space id */ - ulint max_size, /*!< in: max size in pages */ - ulint* id, /*!< out: rseg id */ - mtr_t* mtr); /*!< in: mtr */ /*************************************************************************** Free's an instance of the rollback segment in memory. */ UNIV_INTERN @@ -133,6 +122,12 @@ trx_rseg_mem_free( /*==============*/ trx_rseg_t* rseg); /* in, own: instance to free */ +/********************************************************************* +Creates a rollback segment. */ +UNIV_INTERN +trx_rseg_t* +trx_rseg_create(void); +/*==================*/ /* Number of undo log slots in a rollback segment file copy */ #define TRX_RSEG_N_SLOTS (UNIV_PAGE_SIZE / 16) diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index a53296a06d9..fc92b4317d5 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -333,12 +333,14 @@ UNIV_INTERN void trx_sys_file_format_tag_init(void); /*==============================*/ +#ifndef UNIV_HOTBACKUP /*****************************************************************//** Shutdown/Close the transaction system. */ UNIV_INTERN void trx_sys_close(void); /*===============*/ +#endif /* !UNIV_HOTBACKUP */ /*****************************************************************//** Get the name representation of the file format from its id. @return pointer to the name */ @@ -429,6 +431,14 @@ trx_sys_file_format_id_to_name( const ulint id); /*!< in: id of the file format */ #endif /* !UNIV_HOTBACKUP */ +/********************************************************************* +Creates the rollback segments */ +UNIV_INTERN +void +trx_sys_create_rsegs( +/*=================*/ + ulint n_rsegs); /*!< number of rollback segments to create */ + /* The automatically created system rollback segment has this id */ #define TRX_SYS_SYSTEM_RSEG_ID 0 @@ -463,11 +473,16 @@ trx_sys_file_format_id_to_name( slots */ /*------------------------------------------------------------- @} */ -/** Maximum number of rollback segments: the number of segment -specification slots in the transaction system array; rollback segment -id must fit in one byte, therefore 256; each slot is currently 8 bytes -in size */ -#define TRX_SYS_N_RSEGS 256 +/* Max number of rollback segments: the number of segment specification slots +in the transaction system array; rollback segment id must fit in one (signed) +byte, therefore 128; each slot is currently 8 bytes in size. If you want +to raise the level to 256 then you will need to fix some assertions that +impose the 7 bit restriction. e.g., mach_write_to_3() */ +#define TRX_SYS_N_RSEGS 128 +/* Originally, InnoDB defined TRX_SYS_N_RSEGS as 256 but created only one +rollback segment. It initialized some arrays with this number of entries. +We must remember this limit in order to keep file compatibility. */ +#define TRX_SYS_OLD_N_RSEGS 256 /** Maximum length of MySQL binlog file name, in bytes. @see trx_sys_mysql_master_log_name @@ -495,7 +510,6 @@ this contains the same fields as TRX_SYS_MYSQL_LOG_INFO below */ within that file */ #define TRX_SYS_MYSQL_LOG_NAME 12 /*!< MySQL log file name */ -#ifndef UNIV_HOTBACKUP /** Doublewrite buffer */ /* @{ */ /** The offset of the doublewrite buffer header on the trx system header page */ @@ -547,6 +561,7 @@ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_NO. */ #define TRX_SYS_DOUBLEWRITE_BLOCK_SIZE FSP_EXTENT_SIZE /* @} */ +#ifndef UNIV_HOTBACKUP /** File format tag */ /* @{ */ /** The offset of the file format tag on the trx system header page diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 5f2c1246f37..abd175d365b 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -349,7 +349,7 @@ trx_print( use the default max length */ /** Type of data dictionary operation */ -enum trx_dict_op { +typedef enum trx_dict_op { /** The transaction is not modifying the data dictionary. */ TRX_DICT_OP_NONE = 0, /** The transaction is creating a table or an index, or @@ -361,7 +361,7 @@ enum trx_dict_op { existing table. In crash recovery, the data dictionary must be locked, but the table must not be dropped. */ TRX_DICT_OP_INDEX = 2 -}; +} trx_dict_op_t; /**********************************************************************//** Determine if a transaction is a dictionary operation. @@ -391,6 +391,14 @@ ibool trx_is_interrupted( /*===============*/ trx_t* trx); /*!< in: transaction */ +/**********************************************************************//** +Determines if the currently running transaction is in strict mode. +@return TRUE if strict */ +UNIV_INTERN +ibool +trx_is_strict( +/*==========*/ + trx_t* trx); /*!< in: transaction */ #else /* !UNIV_HOTBACKUP */ #define trx_is_interrupted(trx) FALSE #endif /* !UNIV_HOTBACKUP */ @@ -463,69 +471,79 @@ rolling back after a database recovery */ struct trx_struct{ ulint magic_n; - /* All the next fields are protected by the kernel mutex, except the - undo logs which are protected by undo_mutex */ + + /* These fields are not protected by any mutex. */ const char* op_info; /*!< English text describing the current operation, or an empty string */ - unsigned is_purge:1; /*!< 0=user transaction, 1=purge */ - unsigned is_recovered:1; /*!< 0=normal transaction, - 1=recovered, must be rolled back */ - unsigned conc_state:2; /*!< state of the trx from the point + ulint conc_state; /*!< state of the trx from the point of view of concurrency control: TRX_ACTIVE, TRX_COMMITTED_IN_MEMORY, ... */ - unsigned que_state:2; /*!< valid when conc_state == TRX_ACTIVE: - TRX_QUE_RUNNING, TRX_QUE_LOCK_WAIT, - ... */ - unsigned isolation_level:2;/* TRX_ISO_REPEATABLE_READ, ... */ - unsigned check_foreigns:1;/* normally TRUE, but if the user + ulint isolation_level;/* TRX_ISO_REPEATABLE_READ, ... */ + ulint check_foreigns; /* normally TRUE, but if the user wants to suppress foreign key checks, (in table imports, for example) we set this FALSE */ - unsigned check_unique_secondary:1; + ulint check_unique_secondary; /* normally TRUE, but if the user wants to speed up inserts by suppressing unique key checks for secondary indexes when we decide if we can use the insert buffer for them, we set this FALSE */ - unsigned support_xa:1; /*!< normally we do the XA two-phase + ulint support_xa; /*!< normally we do the XA two-phase commit steps, but by setting this to FALSE, one can save CPU time and about 150 bytes in the undo log size as then we skip XA steps */ - unsigned flush_log_later:1;/* In 2PC, we hold the + ulint flush_log_later;/* In 2PC, we hold the prepare_commit mutex across both phases. In that case, we defer flush of the logs to disk until after we release the mutex. */ - unsigned must_flush_log_later:1;/* this flag is set to TRUE in + ulint must_flush_log_later;/* this flag is set to TRUE in trx_commit_off_kernel() if flush_log_later was TRUE, and there were modifications by the transaction; in that case we must flush the log in trx_commit_complete_for_mysql() */ - unsigned dict_operation:2;/**< @see enum trx_dict_op */ - unsigned duplicates:2; /*!< TRX_DUP_IGNORE | TRX_DUP_REPLACE */ - unsigned active_trans:2; /*!< 1 - if a transaction in MySQL + ulint duplicates; /*!< TRX_DUP_IGNORE | TRX_DUP_REPLACE */ + ulint active_trans; /*!< 1 - if a transaction in MySQL is active. 2 - if prepare_commit_mutex was taken */ - unsigned has_search_latch:1; + ulint has_search_latch; /* TRUE if this trx has latched the search system latch in S-mode */ - unsigned declared_to_be_inside_innodb:1; + ulint deadlock_mark; /*!< a mark field used in deadlock + checking algorithm. */ + trx_dict_op_t dict_operation; /**< @see enum trx_dict_op */ + + /* Fields protected by the srv_conc_mutex. */ + ulint declared_to_be_inside_innodb; /* this is TRUE if we have declared this transaction in srv_conc_enter_innodb to be inside the InnoDB engine */ - unsigned handling_signals:1;/* this is TRUE as long as the trx - is handling signals */ - unsigned dict_operation_lock_mode:2; - /* 0, RW_S_LATCH, or RW_X_LATCH: + + /* Fields protected by dict_operation_lock. The very latch + it is used to track. */ + ulint dict_operation_lock_mode; + /*!< 0, RW_S_LATCH, or RW_X_LATCH: the latch mode trx currently holds on dict_operation_lock */ + + /* All the next fields are protected by the kernel mutex, except the + undo logs which are protected by undo_mutex */ + ulint is_purge; /*!< 0=user transaction, 1=purge */ + ulint is_recovered; /*!< 0=normal transaction, + 1=recovered, must be rolled back */ + ulint que_state; /*!< valid when conc_state + == TRX_ACTIVE: TRX_QUE_RUNNING, + TRX_QUE_LOCK_WAIT, ... */ + ulint handling_signals;/* this is TRUE as long as the trx + is handling signals */ time_t start_time; /*!< time the trx object was created or the state last time became TRX_ACTIVE */ @@ -542,9 +560,6 @@ struct trx_struct{ /*------------------------------*/ void* mysql_thd; /*!< MySQL thread handle corresponding to this trx, or NULL */ - char** mysql_query_str;/* pointer to the field in mysqld_thd - which contains the pointer to the - current SQL query string */ const char* mysql_log_file_name; /* if MySQL binlog is used, this field contains a pointer to the latest file @@ -640,11 +655,6 @@ struct trx_struct{ wait_thrs; /*!< query threads belonging to this trx that are in the QUE_THR_LOCK_WAIT state */ - ulint deadlock_mark; /*!< a mark field used in deadlock - checking algorithm. This must be - in its own machine word, because - it can be changed by other - threads while holding kernel_mutex. */ /*------------------------------*/ mem_heap_t* lock_heap; /*!< memory heap for the locks of the transaction */ diff --git a/storage/innobase/include/trx0types.h b/storage/innobase/include/trx0types.h index 24cf57d53d5..40a7256cbfd 100644 --- a/storage/innobase/include/trx0types.h +++ b/storage/innobase/include/trx0types.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -70,6 +70,13 @@ typedef struct trx_named_savept_struct trx_named_savept_t; enum trx_rb_ctx { RB_NONE = 0, /*!< no rollback */ RB_NORMAL, /*!< normal rollback */ + RB_RECOVERY_PURGE_REC, + /*!< rolling back an incomplete transaction, + in crash recovery, rolling back an + INSERT that was performed by updating a + delete-marked record; if the delete-marked record + no longer exists in an active read view, it will + be purged */ RB_RECOVERY /*!< rolling back an incomplete transaction, in crash recovery */ }; diff --git a/storage/innobase/include/trx0undo.ic b/storage/innobase/include/trx0undo.ic index 2d289b34ef1..6502ee826e5 100644 --- a/storage/innobase/include/trx0undo.ic +++ b/storage/innobase/include/trx0undo.ic @@ -42,7 +42,7 @@ trx_undo_build_roll_ptr( #if DATA_ROLL_PTR_LEN != 7 # error "DATA_ROLL_PTR_LEN != 7" #endif - ut_ad(rseg_id < 128); + ut_ad(rseg_id < TRX_SYS_N_RSEGS); return(ut_dulint_create(is_insert * 128 * 256 * 256 + rseg_id * 256 * 256 diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index 2081e136590..11cec113fc8 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Copyright (c) 2009, Sun Microsystems, Inc. @@ -45,8 +45,8 @@ Created 1/20/1994 Heikki Tuuri #endif /* UNIV_HOTBACKUP */ #define INNODB_VERSION_MAJOR 1 -#define INNODB_VERSION_MINOR 0 -#define INNODB_VERSION_BUGFIX 6 +#define INNODB_VERSION_MINOR 1 +#define INNODB_VERSION_BUGFIX 1 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; @@ -115,7 +115,7 @@ if we are compiling on Windows. */ /* Include <sys/stat.h> to get S_I... macros defined for os0file.c */ # include <sys/stat.h> -# if !defined(__NETWARE__) && !defined(__WIN__) +# if !defined(__NETWARE__) && !defined(__WIN__) # include <sys/mman.h> /* mmap() for os0proc.c */ # endif @@ -144,6 +144,23 @@ Sun Studio */ #endif /* #if (defined(WIN32) || ... */ +/* Following defines are to enable performance schema +instrumentation in each of four InnoDB modules if +HAVE_PSI_INTERFACE is defined. */ +#ifdef HAVE_PSI_INTERFACE +# define UNIV_PFS_MUTEX +# define UNIV_PFS_RWLOCK +/* For I/O instrumentation, performance schema rely +on a native descriptor to identify the file, this +descriptor could conflict with our OS level descriptor. +Disable IO instrumentation on Windows until this is +resolved */ +# ifndef __WIN__ +# define UNIV_PFS_IO +# endif +# define UNIV_PFS_THREAD +#endif /* HAVE_PSI_INTERFACE */ + /* DEBUG VERSION CONTROL ===================== */ @@ -165,6 +182,9 @@ command. Not tested on Windows. */ #define UNIV_COMPILE_TEST_FUNCS */ +#if defined HAVE_VALGRIND +# define UNIV_DEBUG_VALGRIND +#endif /* HAVE_VALGRIND */ #if 0 #define UNIV_DEBUG_VALGRIND /* Enable extra Valgrind instrumentation */ @@ -208,6 +228,9 @@ operations (very slow); also UNIV_DEBUG must be defined */ for compressed pages */ #define UNIV_ZIP_COPY /* call page_zip_copy_recs() more often */ +#define UNIV_AIO_DEBUG /* prints info about + submitted and reaped AIO + requests to the log. */ #endif #define UNIV_BTR_DEBUG /* check B-tree links */ @@ -229,11 +252,6 @@ by one. */ /* the above option prevents forcing of log to disk at a buffer page write: it should be tested with this option off; also some ibuf tests are suppressed */ -/* -#define UNIV_BASIC_LOG_DEBUG -*/ - /* the above option enables basic recovery debugging: - new allocated file pages are reset */ /* Linkage specifier for non-static InnoDB symbols (variables and functions) that are only referenced from within InnoDB, not from MySQL */ diff --git a/storage/innobase/include/ut0lst.h b/storage/innobase/include/ut0lst.h index 261d33963dc..bb295ea1b22 100644 --- a/storage/innobase/include/ut0lst.h +++ b/storage/innobase/include/ut0lst.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. 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 @@ -110,7 +110,7 @@ Adds the node as the last element in a two-way linked list. */ #define UT_LIST_ADD_LAST(NAME, BASE, N)\ {\ - ut_ad(N);\ + ut_ad(N != NULL);\ ((BASE).count)++;\ ((N)->NAME).prev = (BASE).end;\ ((N)->NAME).next = NULL;\ diff --git a/storage/innobase/include/ut0mem.h b/storage/innobase/include/ut0mem.h index cf41cba4643..57dfb08f41c 100644 --- a/storage/innobase/include/ut0mem.h +++ b/storage/innobase/include/ut0mem.h @@ -113,12 +113,13 @@ ut_test_malloc( ulint n); /*!< in: try to allocate this many bytes */ #endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** -Frees a memory block allocated with ut_malloc. */ +Frees a memory block allocated with ut_malloc. Freeing a NULL pointer is +a nop. */ UNIV_INTERN void ut_free( /*====*/ - void* ptr); /*!< in, own: memory block */ + void* ptr); /*!< in, own: memory block, can be NULL */ #ifndef UNIV_HOTBACKUP /**********************************************************************//** Implements realloc. This is needed by /pars/lexyy.c. Otherwise, you should not diff --git a/storage/innobase/include/ut0rbt.h b/storage/innobase/include/ut0rbt.h new file mode 100644 index 00000000000..7902dc91f09 --- /dev/null +++ b/storage/innobase/include/ut0rbt.h @@ -0,0 +1,316 @@ +/***************************************************************************//** + +Copyright (c) 2007, 2010, Innobase Oy. All Rights Reserved. + +Portions of this file contain modifications contributed and copyrighted by +Sun Microsystems, Inc. Those modifications are gratefully acknowledged and +are described briefly in the InnoDB documentation. The contributions by +Sun Microsystems are incorporated with their permission, and subject to the +conditions contained in the file COPYING.Sun_Microsystems. + +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; 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, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ +/******************************************************************//** +@file include/ut0rbt.h +Various utilities + +Created 2007-03-20 Sunny Bains +*******************************************************/ + +#ifndef INNOBASE_UT0RBT_H +#define INNOBASE_UT0RBT_H + +#if !defined(IB_RBT_TESTING) +#include "univ.i" +#include "ut0mem.h" +#else +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#define ut_malloc malloc +#define ut_free free +#define ulint unsigned long +#define ut_a(c) assert(c) +#define ut_error assert(0) +#define ibool unsigned int +#define TRUE 1 +#define FALSE 0 +#endif + +/* Red black tree typedefs */ +typedef struct ib_rbt_struct ib_rbt_t; +typedef struct ib_rbt_node_struct ib_rbt_node_t; +// FIXME: Iterator is a better name than _bound_ +typedef struct ib_rbt_bound_struct ib_rbt_bound_t; +typedef void (*ib_rbt_print_node)(const ib_rbt_node_t* node); +typedef int (*ib_rbt_compare)(const void* p1, const void* p2); + +/** Red black tree color types */ +enum ib_rbt_color_enum { + IB_RBT_RED, + IB_RBT_BLACK +}; + +typedef enum ib_rbt_color_enum ib_rbt_color_t; + +/** Red black tree node */ +struct ib_rbt_node_struct { + ib_rbt_color_t color; /* color of this node */ + + ib_rbt_node_t* left; /* points left child */ + ib_rbt_node_t* right; /* points right child */ + ib_rbt_node_t* parent; /* points parent node */ + + char value[1]; /* Data value */ +}; + +/** Red black tree instance.*/ +struct ib_rbt_struct { + ib_rbt_node_t* nil; /* Black colored node that is + used as a sentinel. This is + pre-allocated too.*/ + + ib_rbt_node_t* root; /* Root of the tree, this is + pre-allocated and the first + data node is the left child.*/ + + ulint n_nodes; /* Total number of data nodes */ + + ib_rbt_compare compare; /* Fn. to use for comparison */ + ulint sizeof_value; /* Sizeof the item in bytes */ +}; + +/** The result of searching for a key in the tree, this is useful for +a speedy lookup and insert if key doesn't exist.*/ +struct ib_rbt_bound_struct { + const ib_rbt_node_t* + last; /* Last node visited */ + + int result; /* Result of comparing with + the last non-nil node that + was visited */ +}; + +/* Size in elements (t is an rb tree instance) */ +#define rbt_size(t) (t->n_nodes) + +/* Check whether the rb tree is empty (t is an rb tree instance) */ +#define rbt_empty(t) (rbt_size(t) == 0) + +/* Get data value (t is the data type, n is an rb tree node instance) */ +#define rbt_value(t, n) ((t*) &n->value[0]) + +/* Compare a key with the node value (t is tree, k is key, n is node)*/ +#define rbt_compare(t, k, n) (t->compare(k, n->value)) + +/**********************************************************************//** +Free an instance of a red black tree */ +UNIV_INTERN +void +rbt_free( +/*=====*/ + ib_rbt_t* tree); /*!< in: rb tree to free */ +/**********************************************************************//** +Create an instance of a red black tree +@return rb tree instance */ +UNIV_INTERN +ib_rbt_t* +rbt_create( +/*=======*/ + size_t sizeof_value, /*!< in: size in bytes */ + ib_rbt_compare compare); /*!< in: comparator */ +/**********************************************************************//** +Delete a node from the red black tree, identified by key */ +UNIV_INTERN +ibool +rbt_delete( +/*=======*/ + /* in: TRUE on success */ + ib_rbt_t* tree, /* in: rb tree */ + const void* key); /* in: key to delete */ +/**********************************************************************//** +Remove a node from the red black tree, NOTE: This function will not delete +the node instance, THAT IS THE CALLERS RESPONSIBILITY. +@return the deleted node with the const. */ +UNIV_INTERN +ib_rbt_node_t* +rbt_remove_node( +/*============*/ + ib_rbt_t* tree, /*!< in: rb tree */ + const ib_rbt_node_t* + node); /*!< in: node to delete, this + is a fudge and declared const + because the caller has access + only to const nodes.*/ +/**********************************************************************//** +Return a node from the red black tree, identified by +key, NULL if not found +@return node if found else return NULL */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_lookup( +/*=======*/ + const ib_rbt_t* tree, /*!< in: rb tree to search */ + const void* key); /*!< in: key to lookup */ +/**********************************************************************//** +Add data to the red black tree, identified by key (no dups yet!) +@return inserted node */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_insert( +/*=======*/ + ib_rbt_t* tree, /*!< in: rb tree */ + const void* key, /*!< in: key for ordering */ + const void* value); /*!< in: data that will be + copied to the node.*/ +/**********************************************************************//** +Add a new node to the tree, useful for data that is pre-sorted. +@return appended node */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_add_node( +/*=========*/ + ib_rbt_t* tree, /*!< in: rb tree */ + ib_rbt_bound_t* parent, /*!< in: parent */ + const void* value); /*!< in: this value is copied + to the node */ +/**********************************************************************//** +Return the left most data node in the tree +@return left most node */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_first( +/*======*/ + const ib_rbt_t* tree); /*!< in: rb tree */ +/**********************************************************************//** +Return the right most data node in the tree +@return right most node */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_last( +/*=====*/ + const ib_rbt_t* tree); /*!< in: rb tree */ +/**********************************************************************//** +Return the next node from current. +@return successor node to current that is passed in. */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_next( +/*=====*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + const ib_rbt_node_t* /* in: current node */ + current); +/**********************************************************************//** +Return the prev node from current. +@return precedessor node to current that is passed in */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_prev( +/*=====*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + const ib_rbt_node_t* /* in: current node */ + current); +/**********************************************************************//** +Find the node that has the lowest key that is >= key. +@return node that satisfies the lower bound constraint or NULL */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_lower_bound( +/*============*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + const void* key); /*!< in: key to search */ +/**********************************************************************//** +Find the node that has the greatest key that is <= key. +@return node that satisifies the upper bound constraint or NULL */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_upper_bound( +/*============*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + const void* key); /*!< in: key to search */ +/**********************************************************************//** +Search for the key, a node will be retuned in parent.last, whether it +was found or not. If not found then parent.last will contain the +parent node for the possibly new key otherwise the matching node. +@return result of last comparison */ +UNIV_INTERN +int +rbt_search( +/*=======*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + ib_rbt_bound_t* parent, /*!< in: search bounds */ + const void* key); /*!< in: key to search */ +/**********************************************************************//** +Search for the key, a node will be retuned in parent.last, whether it +was found or not. If not found then parent.last will contain the +parent node for the possibly new key otherwise the matching node. +@return result of last comparison */ +UNIV_INTERN +int +rbt_search_cmp( +/*===========*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + ib_rbt_bound_t* parent, /*!< in: search bounds */ + const void* key, /*!< in: key to search */ + ib_rbt_compare compare); /*!< in: comparator */ +/**********************************************************************//** +Clear the tree, deletes (and free's) all the nodes. */ +UNIV_INTERN +void +rbt_clear( +/*======*/ + ib_rbt_t* tree); /*!< in: rb tree */ +/**********************************************************************//** +Merge the node from dst into src. Return the number of nodes merged. +@return no. of recs merged */ +UNIV_INTERN +ulint +rbt_merge_uniq( +/*===========*/ + ib_rbt_t* dst, /*!< in: dst rb tree */ + const ib_rbt_t* src); /*!< in: src rb tree */ +/**********************************************************************//** +Merge the node from dst into src. Return the number of nodes merged. +Delete the nodes from src after copying node to dst. As a side effect +the duplicates will be left untouched in the src, since we don't support +duplicates (yet). NOTE: src and dst must be similar, the function doesn't +check for this condition (yet). +@return no. of recs merged */ +UNIV_INTERN +ulint +rbt_merge_uniq_destructive( +/*=======================*/ + ib_rbt_t* dst, /*!< in: dst rb tree */ + ib_rbt_t* src); /*!< in: src rb tree */ +/**********************************************************************//** +Verify the integrity of the RB tree. For debugging. 0 failure else height +of tree (in count of black nodes). +@return TRUE if OK FALSE if tree invalid. */ +UNIV_INTERN +ibool +rbt_validate( +/*=========*/ + const ib_rbt_t* tree); /*!< in: tree to validate */ +/**********************************************************************//** +Iterate over the tree in depth first order. */ +UNIV_INTERN +void +rbt_print( +/*======*/ + const ib_rbt_t* tree, /*!< in: tree to traverse */ + ib_rbt_print_node print); /*!< in: print function */ + +#endif /* INNOBASE_UT0RBT_H */ diff --git a/storage/innobase/include/ut0rnd.ic b/storage/innobase/include/ut0rnd.ic index 763469142ec..c3dbd86923c 100644 --- a/storage/innobase/include/ut0rnd.ic +++ b/storage/innobase/include/ut0rnd.ic @@ -152,6 +152,7 @@ ut_hash_ulint( ulint key, /*!< in: value to be hashed */ ulint table_size) /*!< in: hash table size */ { + ut_ad(table_size); key = key ^ UT_HASH_RANDOM_MASK2; return(key % table_size); diff --git a/storage/innobase/include/ut0ut.h b/storage/innobase/include/ut0ut.h index 197b8401428..dd59b3eba46 100644 --- a/storage/innobase/include/ut0ut.h +++ b/storage/innobase/include/ut0ut.h @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2009, Sun Microsystems, Inc. Portions of this file contain modifications contributed and copyrighted by @@ -35,6 +35,8 @@ Created 1/20/1994 Heikki Tuuri #include "univ.i" +#include "db0err.h" + #ifndef UNIV_HOTBACKUP # include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ #endif /* UNIV_HOTBACKUP */ @@ -395,6 +397,16 @@ a limited buffer. */ # define ut_snprintf snprintf #endif /* __WIN__ */ +/*************************************************************//** +Convert an error number to a human readable text message. The +returned string is static and should not be freed or modified. +@return string, describing the error */ +UNIV_INTERN +const char* +ut_strerr( +/*======*/ + enum db_err num); /*!< in: error number */ + #ifndef UNIV_NONINL #include "ut0ut.ic" #endif diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c index 1fce8002bdf..0e57a52666e 100644 --- a/storage/innobase/lock/lock0lock.c +++ b/storage/innobase/lock/lock0lock.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -376,6 +376,7 @@ UNIV_INTERN FILE* lock_latest_err_file; /* Flags for recursive deadlock search */ #define LOCK_VICTIM_IS_START 1 #define LOCK_VICTIM_IS_OTHER 2 +#define LOCK_EXCEED_MAX_DEPTH 3 /********************************************************************//** Checks if a lock request results in a deadlock. @@ -394,24 +395,25 @@ Looks recursively for a deadlock. deadlock and we chose 'start' as the victim, LOCK_VICTIM_IS_OTHER if a deadlock was found and we chose some other trx as a victim: we must do the search again in this last case because there may be another -deadlock! */ +deadlock! +LOCK_EXCEED_MAX_DEPTH if the lock search exceeds max steps or max depth. */ static ulint lock_deadlock_recursive( /*====================*/ trx_t* start, /*!< in: recursion starting point */ trx_t* trx, /*!< in: a transaction waiting for a lock */ - lock_t* wait_lock, /*!< in: the lock trx is waiting to be granted */ + lock_t* wait_lock, /*!< in: lock that is waiting to be granted */ ulint* cost, /*!< in/out: number of calculation steps thus far: if this exceeds LOCK_MAX_N_STEPS_... - we return LOCK_VICTIM_IS_START */ + we return LOCK_EXCEED_MAX_DEPTH */ ulint depth); /*!< in: recursion depth: if this exceeds LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK, we - return LOCK_VICTIM_IS_START */ + return LOCK_EXCEED_MAX_DEPTH */ /*********************************************************************//** Gets the nth bit of a record lock. -@return TRUE if bit set */ +@return TRUE if bit set also if i == ULINT_UNDEFINED return FALSE*/ UNIV_INLINE ibool lock_rec_get_nth_bit( @@ -1222,7 +1224,7 @@ lock_rec_get_first_on_page( /*********************************************************************//** Gets the next explicit lock request on a record. -@return next lock, NULL if none exists */ +@return next lock, NULL if none exists or if heap_no == ULINT_UNDEFINED */ UNIV_INLINE lock_t* lock_rec_get_next( @@ -1622,7 +1624,7 @@ UNIV_INTERN ulint lock_number_of_rows_locked( /*=======================*/ - trx_t* trx) /*!< in: transaction */ + const trx_t* trx) /*!< in: transaction */ { lock_t* lock; ulint n_records = 0; @@ -1731,11 +1733,11 @@ lock_rec_create( Enqueues a waiting request for a lock which cannot be granted immediately. Checks for deadlocks. @return DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED, or -DB_SUCCESS; DB_SUCCESS means that there was a deadlock, but another -transaction was chosen as a victim, and we got the lock immediately: -no need to wait then */ +DB_SUCCESS_LOCKED_REC; DB_SUCCESS_LOCKED_REC means that +there was a deadlock, but another transaction was chosen as a victim, +and we got the lock immediately: no need to wait then */ static -ulint +enum db_err lock_rec_enqueue_waiting( /*=====================*/ ulint type_mode,/*!< in: lock mode this @@ -1807,7 +1809,7 @@ lock_rec_enqueue_waiting( if (trx->wait_lock == NULL) { - return(DB_SUCCESS); + return(DB_SUCCESS_LOCKED_REC); } trx->que_state = TRX_QUE_LOCK_WAIT; @@ -1923,6 +1925,16 @@ somebody_waits: return(lock_rec_create(type_mode, block, heap_no, index, trx)); } +/** Record locking request status */ +enum lock_rec_req_status { + /** Failed to acquire a lock */ + LOCK_REC_FAIL, + /** Succeeded in acquiring a lock (implicit or already acquired) */ + LOCK_REC_SUCCESS, + /** Explicitly created a new lock */ + LOCK_REC_SUCCESS_CREATED +}; + /*********************************************************************//** This is a fast routine for locking a record in the most common cases: there are no explicit locks on the page, or there is just one lock, owned @@ -1930,9 +1942,9 @@ by this transaction, and of the right type_mode. This is a low-level function which does NOT look at implicit locks! Checks lock compatibility within explicit locks. This function sets a normal next-key lock, or in the case of a page supremum record, a gap type lock. -@return TRUE if locking succeeded */ +@return whether the locking succeeded */ UNIV_INLINE -ibool +enum lock_rec_req_status lock_rec_lock_fast( /*===============*/ ibool impl, /*!< in: if TRUE, no lock is set @@ -1971,19 +1983,19 @@ lock_rec_lock_fast( lock_rec_create(mode, block, heap_no, index, trx); } - return(TRUE); + return(LOCK_REC_SUCCESS_CREATED); } if (lock_rec_get_next_on_page(lock)) { - return(FALSE); + return(LOCK_REC_FAIL); } if (lock->trx != trx || lock->type_mode != (mode | LOCK_REC) || lock_rec_get_n_bits(lock) <= heap_no) { - return(FALSE); + return(LOCK_REC_FAIL); } if (!impl) { @@ -1992,10 +2004,11 @@ lock_rec_lock_fast( if (!lock_rec_get_nth_bit(lock, heap_no)) { lock_rec_set_nth_bit(lock, heap_no); + return(LOCK_REC_SUCCESS_CREATED); } } - return(TRUE); + return(LOCK_REC_SUCCESS); } /*********************************************************************//** @@ -2003,9 +2016,10 @@ This is the general, and slower, routine for locking a record. This is a low-level function which does NOT look at implicit locks! Checks lock compatibility within explicit locks. This function sets a normal next-key lock, or in the case of a page supremum record, a gap type lock. -@return DB_SUCCESS, DB_LOCK_WAIT, or error code */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK, +or DB_QUE_THR_SUSPENDED */ static -ulint +enum db_err lock_rec_lock_slow( /*===============*/ ibool impl, /*!< in: if TRUE, no lock is set @@ -2022,7 +2036,6 @@ lock_rec_lock_slow( que_thr_t* thr) /*!< in: query thread */ { trx_t* trx; - ulint err; ut_ad(mutex_own(&kernel_mutex)); ut_ad((LOCK_MODE_MASK & mode) != LOCK_S @@ -2041,27 +2054,23 @@ lock_rec_lock_slow( /* The trx already has a strong enough lock on rec: do nothing */ - err = DB_SUCCESS; } else if (lock_rec_other_has_conflicting(mode, block, heap_no, trx)) { /* If another transaction has a non-gap conflicting request in the queue, as this transaction does not have a lock strong enough already granted on the record, we have to wait. */ - err = lock_rec_enqueue_waiting(mode, block, heap_no, - index, thr); - } else { - if (!impl) { - /* Set the requested lock on the record */ + return(lock_rec_enqueue_waiting(mode, block, heap_no, + index, thr)); + } else if (!impl) { + /* Set the requested lock on the record */ - lock_rec_add_to_queue(LOCK_REC | mode, block, - heap_no, index, trx); - } - - err = DB_SUCCESS; + lock_rec_add_to_queue(LOCK_REC | mode, block, + heap_no, index, trx); + return(DB_SUCCESS_LOCKED_REC); } - return(err); + return(DB_SUCCESS); } /*********************************************************************//** @@ -2070,9 +2079,10 @@ possible, enqueues a waiting lock request. This is a low-level function which does NOT look at implicit locks! Checks lock compatibility within explicit locks. This function sets a normal next-key lock, or in the case of a page supremum record, a gap type lock. -@return DB_SUCCESS, DB_LOCK_WAIT, or error code */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK, +or DB_QUE_THR_SUSPENDED */ static -ulint +enum db_err lock_rec_lock( /*==========*/ ibool impl, /*!< in: if TRUE, no lock is set @@ -2088,8 +2098,6 @@ lock_rec_lock( dict_index_t* index, /*!< in: index of record */ que_thr_t* thr) /*!< in: query thread */ { - ulint err; - ut_ad(mutex_own(&kernel_mutex)); ut_ad((LOCK_MODE_MASK & mode) != LOCK_S || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS)); @@ -2101,18 +2109,20 @@ lock_rec_lock( || mode - (LOCK_MODE_MASK & mode) == LOCK_REC_NOT_GAP || mode - (LOCK_MODE_MASK & mode) == 0); - if (lock_rec_lock_fast(impl, mode, block, heap_no, index, thr)) { - - /* We try a simplified and faster subroutine for the most - common cases */ - - err = DB_SUCCESS; - } else { - err = lock_rec_lock_slow(impl, mode, block, - heap_no, index, thr); + /* We try a simplified and faster subroutine for the most + common cases */ + switch (lock_rec_lock_fast(impl, mode, block, heap_no, index, thr)) { + case LOCK_REC_SUCCESS: + return(DB_SUCCESS); + case LOCK_REC_SUCCESS_CREATED: + return(DB_SUCCESS_LOCKED_REC); + case LOCK_REC_FAIL: + return(lock_rec_lock_slow(impl, mode, block, + heap_no, index, thr)); } - return(err); + ut_error; + return(DB_ERROR); } /*********************************************************************//** @@ -2398,7 +2408,7 @@ lock_rec_inherit_to_gap( if (!lock_rec_get_insert_intention(lock) && !((srv_locks_unsafe_for_binlog || lock->trx->isolation_level - == TRX_ISO_READ_COMMITTED) + <= TRX_ISO_READ_COMMITTED) && lock_get_mode(lock) == LOCK_X)) { lock_rec_add_to_queue(LOCK_REC | LOCK_GAP @@ -3261,8 +3271,6 @@ lock_deadlock_occurs( lock_t* lock, /*!< in: lock the transaction is requesting */ trx_t* trx) /*!< in: transaction */ { - dict_table_t* table; - dict_index_t* index; trx_t* mark_trx; ulint ret; ulint cost = 0; @@ -3284,31 +3292,50 @@ retry: ret = lock_deadlock_recursive(trx, trx, lock, &cost, 0); - if (ret == LOCK_VICTIM_IS_OTHER) { + switch (ret) { + case LOCK_VICTIM_IS_OTHER: /* We chose some other trx as a victim: retry if there still is a deadlock */ - goto retry; - } - if (UNIV_UNLIKELY(ret == LOCK_VICTIM_IS_START)) { - if (lock_get_type_low(lock) & LOCK_TABLE) { - table = lock->un_member.tab_lock.table; - index = NULL; + case LOCK_EXCEED_MAX_DEPTH: + /* If the lock search exceeds the max step + or the max depth, the current trx will be + the victim. Print its information. */ + rewind(lock_latest_err_file); + ut_print_timestamp(lock_latest_err_file); + + fputs("TOO DEEP OR LONG SEARCH IN THE LOCK TABLE" + " WAITS-FOR GRAPH, WE WILL ROLL BACK" + " FOLLOWING TRANSACTION \n", + lock_latest_err_file); + + fputs("\n*** TRANSACTION:\n", lock_latest_err_file); + trx_print(lock_latest_err_file, trx, 3000); + + fputs("*** WAITING FOR THIS LOCK TO BE GRANTED:\n", + lock_latest_err_file); + + if (lock_get_type(lock) == LOCK_REC) { + lock_rec_print(lock_latest_err_file, lock); } else { - index = lock->index; - table = index->table; + lock_table_print(lock_latest_err_file, lock); } + break; - lock_deadlock_found = TRUE; - + case LOCK_VICTIM_IS_START: fputs("*** WE ROLL BACK TRANSACTION (2)\n", lock_latest_err_file); + break; - return(TRUE); + default: + /* No deadlock detected*/ + return(FALSE); } - return(FALSE); + lock_deadlock_found = TRUE; + + return(TRUE); } /********************************************************************//** @@ -3317,25 +3344,26 @@ Looks recursively for a deadlock. deadlock and we chose 'start' as the victim, LOCK_VICTIM_IS_OTHER if a deadlock was found and we chose some other trx as a victim: we must do the search again in this last case because there may be another -deadlock! */ +deadlock! +LOCK_EXCEED_MAX_DEPTH if the lock search exceeds max steps or max depth. */ static ulint lock_deadlock_recursive( /*====================*/ trx_t* start, /*!< in: recursion starting point */ trx_t* trx, /*!< in: a transaction waiting for a lock */ - lock_t* wait_lock, /*!< in: the lock trx is waiting to be granted */ + lock_t* wait_lock, /*!< in: lock that is waiting to be granted */ ulint* cost, /*!< in/out: number of calculation steps thus far: if this exceeds LOCK_MAX_N_STEPS_... - we return LOCK_VICTIM_IS_START */ + we return LOCK_EXCEED_MAX_DEPTH */ ulint depth) /*!< in: recursion depth: if this exceeds LOCK_MAX_DEPTH_IN_DEADLOCK_CHECK, we - return LOCK_VICTIM_IS_START */ + return LOCK_EXCEED_MAX_DEPTH */ { + ulint ret; lock_t* lock; - ulint bit_no = ULINT_UNDEFINED; trx_t* lock_trx; - ulint ret; + ulint heap_no = ULINT_UNDEFINED; ut_a(trx); ut_a(start); @@ -3351,27 +3379,44 @@ lock_deadlock_recursive( *cost = *cost + 1; - lock = wait_lock; - if (lock_get_type_low(wait_lock) == LOCK_REC) { + ulint space; + ulint page_no; + + heap_no = lock_rec_find_set_bit(wait_lock); + ut_a(heap_no != ULINT_UNDEFINED); + + space = wait_lock->un_member.rec_lock.space; + page_no = wait_lock->un_member.rec_lock.page_no; - bit_no = lock_rec_find_set_bit(wait_lock); + lock = lock_rec_get_first_on_page_addr(space, page_no); - ut_a(bit_no != ULINT_UNDEFINED); + /* Position the iterator on the first matching record lock. */ + while (lock != NULL + && lock != wait_lock + && !lock_rec_get_nth_bit(lock, heap_no)) { + + lock = lock_rec_get_next_on_page(lock); + } + + if (lock == wait_lock) { + lock = NULL; + } + + ut_ad(lock == NULL || lock_rec_get_nth_bit(lock, heap_no)); + + } else { + lock = wait_lock; } /* Look at the locks ahead of wait_lock in the lock queue */ for (;;) { - if (lock_get_type_low(lock) & LOCK_TABLE) { + /* Get previous table lock. */ + if (heap_no == ULINT_UNDEFINED) { - lock = UT_LIST_GET_PREV(un_member.tab_lock.locks, - lock); - } else { - ut_ad(lock_get_type_low(lock) == LOCK_REC); - ut_a(bit_no != ULINT_UNDEFINED); - - lock = (lock_t*) lock_rec_get_prev(lock, bit_no); + lock = UT_LIST_GET_PREV( + un_member.tab_lock.locks, lock); } if (lock == NULL) { @@ -3389,7 +3434,7 @@ lock_deadlock_recursive( lock_trx = lock->trx; - if (lock_trx == start || too_far) { + if (lock_trx == start) { /* We came back to the recursion starting point: a deadlock detected; or we have @@ -3436,19 +3481,10 @@ lock_deadlock_recursive( } #ifdef UNIV_DEBUG if (lock_print_waits) { - fputs("Deadlock detected" - " or too long search\n", + fputs("Deadlock detected\n", stderr); } #endif /* UNIV_DEBUG */ - if (too_far) { - - fputs("TOO DEEP OR LONG SEARCH" - " IN THE LOCK TABLE" - " WAITS-FOR GRAPH\n", ef); - - return(LOCK_VICTIM_IS_START); - } if (trx_weight_cmp(wait_lock->trx, start) >= 0) { @@ -3484,6 +3520,21 @@ lock_deadlock_recursive( return(LOCK_VICTIM_IS_OTHER); } + if (too_far) { + +#ifdef UNIV_DEBUG + if (lock_print_waits) { + fputs("Deadlock search exceeds" + " max steps or depth.\n", + stderr); + } +#endif /* UNIV_DEBUG */ + /* The information about transaction/lock + to be rolled back is available in the top + level. Do not print anything here. */ + return(LOCK_EXCEED_MAX_DEPTH); + } + if (lock_trx->que_state == TRX_QUE_LOCK_WAIT) { /* Another trx ahead has requested lock in an @@ -3493,12 +3544,28 @@ lock_deadlock_recursive( ret = lock_deadlock_recursive( start, lock_trx, lock_trx->wait_lock, cost, depth + 1); + if (ret != 0) { return(ret); } } } + /* Get the next record lock to check. */ + if (heap_no != ULINT_UNDEFINED) { + + ut_a(lock != NULL); + + do { + lock = lock_rec_get_next_on_page(lock); + } while (lock != NULL + && lock != wait_lock + && !lock_rec_get_nth_bit(lock, heap_no)); + + if (lock == wait_lock) { + lock = NULL; + } + } }/* end of the 'for (;;)'-loop */ } @@ -3694,9 +3761,10 @@ lock_table_enqueue_waiting( /*********************************************************************//** Checks if other transactions have an incompatible mode lock request in -the lock queue. */ +the lock queue. +@return lock or NULL */ UNIV_INLINE -ibool +lock_t* lock_table_other_has_incompatible( /*==============================*/ trx_t* trx, /*!< in: transaction, or NULL if all @@ -3718,13 +3786,13 @@ lock_table_other_has_incompatible( && (!lock_mode_compatible(lock_get_mode(lock), mode)) && (wait || !(lock_get_wait(lock)))) { - return(TRUE); + return(lock); } lock = UT_LIST_GET_PREV(un_member.tab_lock.locks, lock); } - return(FALSE); + return(NULL); } /*********************************************************************//** @@ -3875,8 +3943,8 @@ lock_rec_unlock( const rec_t* rec, /*!< in: record */ enum lock_mode lock_mode)/*!< in: LOCK_S or LOCK_X */ { + lock_t* first_lock; lock_t* lock; - lock_t* release_lock = NULL; ulint heap_no; ut_ad(trx && rec); @@ -3886,48 +3954,40 @@ lock_rec_unlock( mutex_enter(&kernel_mutex); - lock = lock_rec_get_first(block, heap_no); + first_lock = lock_rec_get_first(block, heap_no); /* Find the last lock with the same lock_mode and transaction from the record. */ - while (lock != NULL) { + for (lock = first_lock; lock != NULL; + lock = lock_rec_get_next(heap_no, lock)) { if (lock->trx == trx && lock_get_mode(lock) == lock_mode) { - release_lock = lock; ut_a(!lock_get_wait(lock)); + lock_rec_reset_nth_bit(lock, heap_no); + goto released; } - - lock = lock_rec_get_next(heap_no, lock); } - /* If a record lock is found, release the record lock */ - - if (UNIV_LIKELY(release_lock != NULL)) { - lock_rec_reset_nth_bit(release_lock, heap_no); - } else { - mutex_exit(&kernel_mutex); - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Error: unlock row could not" - " find a %lu mode lock on the record\n", - (ulong) lock_mode); + mutex_exit(&kernel_mutex); + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Error: unlock row could not" + " find a %lu mode lock on the record\n", + (ulong) lock_mode); - return; - } + return; +released: /* Check if we can now grant waiting lock requests */ - lock = lock_rec_get_first(block, heap_no); - - while (lock != NULL) { + for (lock = first_lock; lock != NULL; + lock = lock_rec_get_next(heap_no, lock)) { if (lock_get_wait(lock) && !lock_rec_has_to_wait_in_queue(lock)) { /* Grant the lock */ lock_grant(lock); } - - lock = lock_rec_get_next(heap_no, lock); } mutex_exit(&kernel_mutex); @@ -4249,28 +4309,29 @@ lock_rec_print( block = buf_page_try_get(space, page_no, &mtr); - if (block) { - for (i = 0; i < lock_rec_get_n_bits(lock); i++) { + for (i = 0; i < lock_rec_get_n_bits(lock); ++i) { - if (lock_rec_get_nth_bit(lock, i)) { + if (!lock_rec_get_nth_bit(lock, i)) { + continue; + } - const rec_t* rec - = page_find_rec_with_heap_no( - buf_block_get_frame(block), i); - offsets = rec_get_offsets( - rec, lock->index, offsets, - ULINT_UNDEFINED, &heap); + fprintf(file, "Record lock, heap no %lu", (ulong) i); - fprintf(file, "Record lock, heap no %lu ", - (ulong) i); - rec_print_new(file, rec, offsets); - putc('\n', file); - } - } - } else { - for (i = 0; i < lock_rec_get_n_bits(lock); i++) { - fprintf(file, "Record lock, heap no %lu\n", (ulong) i); + if (block) { + const rec_t* rec; + + rec = page_find_rec_with_heap_no( + buf_block_get_frame(block), i); + + offsets = rec_get_offsets( + rec, lock->index, offsets, + ULINT_UNDEFINED, &heap); + + putc(' ', file); + rec_print_new(file, rec, offsets); } + + putc('\n', file); } mtr_commit(&mtr); @@ -4317,14 +4378,26 @@ lock_get_n_rec_locks(void) #endif /* PRINT_NUM_OF_LOCK_STRUCTS */ /*********************************************************************//** -Prints info of locks for all transactions. */ +Prints info of locks for all transactions. +@return FALSE if not able to obtain kernel mutex +and exits without printing info */ UNIV_INTERN -void +ibool lock_print_info_summary( /*====================*/ - FILE* file) /*!< in: file where to print */ + FILE* file, /*!< in: file where to print */ + ibool nowait) /*!< in: whether to wait for the kernel mutex */ { - lock_mutex_enter_kernel(); + /* if nowait is FALSE, wait on the kernel mutex, + otherwise return immediately if fail to obtain the + mutex. */ + if (!nowait) { + lock_mutex_enter_kernel(); + } else if (mutex_enter_nowait(&kernel_mutex)) { + fputs("FAIL TO OBTAIN KERNEL MUTEX, " + "SKIP LOCK INFO PRINTING\n", file); + return(FALSE); + } if (lock_deadlock_found) { fputs("------------------------\n" @@ -4356,6 +4429,7 @@ lock_print_info_summary( "Total number of lock structs in row lock hash table %lu\n", (ulong) lock_get_n_rec_locks()); #endif /* PRINT_NUM_OF_LOCK_STRUCTS */ + return(TRUE); } /*********************************************************************//** @@ -4636,6 +4710,7 @@ lock_rec_queue_validate( ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, block, heap_no, impl_trx)); } +#if 0 } else { /* The kernel mutex may get released temporarily in the @@ -4646,6 +4721,27 @@ lock_rec_queue_validate( (fil_space_t::latch), the following check WILL break latching order and may cause a deadlock of threads. */ + /* NOTE: This is a bogus check that would fail in the + following case: Our transaction is updating a + row. After it has updated the clustered index record, + it goes to a secondary index record and finds someone + else holding an explicit S- or X-lock on that + secondary index record, presumably from a locking + read. Our transaction cannot update the secondary + index immediately, but places a waiting X-lock request + on the secondary index record. There is nothing + illegal in this. The assertion is simply too strong. */ + + /* From the locking point of view, each secondary + index is a separate table. A lock that is held on + secondary index rec does not give any rights to modify + or read the clustered index rec. Therefore, we can + think of the sec index as a separate 'table' from the + clust index 'table'. Conversely, a transaction that + has acquired a lock on and modified a clustered index + record may need to wait for a lock on the + corresponding record in a secondary index. */ + impl_trx = lock_sec_rec_some_has_impl_off_kernel( rec, index, offsets); @@ -4656,6 +4752,7 @@ lock_rec_queue_validate( ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, block, heap_no, impl_trx)); } +#endif } lock = lock_rec_get_first(block, heap_no); @@ -4753,6 +4850,13 @@ loop: || lock->trx->conc_state == TRX_PREPARED || lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY); +# ifdef UNIV_SYNC_DEBUG + /* Only validate the record queues when this thread is not + holding a space->latch. Deadlocks are possible due to + latching order violation when UNIV_DEBUG is defined while + UNIV_SYNC_DEBUG is not. */ + if (!sync_thread_levels_contains(SYNC_FSP)) +# endif /* UNIV_SYNC_DEBUG */ for (i = nth_bit; i < lock_rec_get_n_bits(lock); i++) { if (i == 1 || lock_rec_get_nth_bit(lock, i)) { @@ -4918,7 +5022,7 @@ lock_rec_insert_check_and_lock( } trx = thr_get_trx(thr); - next_rec = page_rec_get_next((rec_t*) rec); + next_rec = page_rec_get_next_const(rec); next_rec_heap_no = page_rec_get_heap_no(next_rec); lock_mutex_enter_kernel(); @@ -4976,7 +5080,14 @@ lock_rec_insert_check_and_lock( lock_mutex_exit_kernel(); - if ((err == DB_SUCCESS) && !dict_index_is_clust(index)) { + switch (err) { + case DB_SUCCESS_LOCKED_REC: + err = DB_SUCCESS; + /* fall through */ + case DB_SUCCESS: + if (dict_index_is_clust(index)) { + break; + } /* Update the page max trx id field */ page_update_max_trx_id(block, buf_block_get_page_zip(block), @@ -5099,6 +5210,10 @@ lock_clust_rec_modify_check_and_lock( ut_ad(lock_rec_queue_validate(block, rec, index, offsets)); + if (UNIV_UNLIKELY(err == DB_SUCCESS_LOCKED_REC)) { + err = DB_SUCCESS; + } + return(err); } @@ -5165,22 +5280,27 @@ lock_sec_rec_modify_check_and_lock( } #endif /* UNIV_DEBUG */ - if (err == DB_SUCCESS) { + if (err == DB_SUCCESS || err == DB_SUCCESS_LOCKED_REC) { /* Update the page max trx id field */ + /* It might not be necessary to do this if + err == DB_SUCCESS (no new lock created), + but it should not cost too much performance. */ page_update_max_trx_id(block, buf_block_get_page_zip(block), thr_get_trx(thr)->id, mtr); + err = DB_SUCCESS; } return(err); } /*********************************************************************//** -Like the counterpart for a clustered index below, but now we read a +Like lock_clust_rec_read_check_and_lock(), but reads a secondary index record. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK, +or DB_QUE_THR_SUSPENDED */ UNIV_INTERN -ulint +enum db_err lock_sec_rec_read_check_and_lock( /*=============================*/ ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG @@ -5201,8 +5321,8 @@ lock_sec_rec_read_check_and_lock( LOCK_REC_NOT_GAP */ que_thr_t* thr) /*!< in: query thread */ { - ulint err; - ulint heap_no; + enum db_err err; + ulint heap_no; ut_ad(!dict_index_is_clust(index)); ut_ad(block->frame == page_align(rec)); @@ -5253,9 +5373,10 @@ if the query thread should anyway be suspended for some reason; if not, then puts the transaction and the query thread to the lock wait state and inserts a waiting request for a record lock to the lock queue. Sets the requested mode lock on the record. -@return DB_SUCCESS, DB_LOCK_WAIT, DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, DB_LOCK_WAIT, DB_DEADLOCK, +or DB_QUE_THR_SUSPENDED */ UNIV_INTERN -ulint +enum db_err lock_clust_rec_read_check_and_lock( /*===============================*/ ulint flags, /*!< in: if BTR_NO_LOCKING_FLAG @@ -5276,8 +5397,8 @@ lock_clust_rec_read_check_and_lock( LOCK_REC_NOT_GAP */ que_thr_t* thr) /*!< in: query thread */ { - ulint err; - ulint heap_no; + enum db_err err; + ulint heap_no; ut_ad(dict_index_is_clust(index)); ut_ad(block->frame == page_align(rec)); @@ -5348,17 +5469,22 @@ lock_clust_rec_read_check_and_lock_alt( mem_heap_t* tmp_heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; - ulint ret; + ulint err; rec_offs_init(offsets_); offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &tmp_heap); - ret = lock_clust_rec_read_check_and_lock(flags, block, rec, index, + err = lock_clust_rec_read_check_and_lock(flags, block, rec, index, offsets, mode, gap_mode, thr); if (tmp_heap) { mem_heap_free(tmp_heap); } - return(ret); + + if (UNIV_UNLIKELY(err == DB_SUCCESS_LOCKED_REC)) { + err = DB_SUCCESS; + } + + return(err); } /*******************************************************************//** diff --git a/storage/innobase/log/log0log.c b/storage/innobase/log/log0log.c index d5b696074b3..386f9630baa 100644 --- a/storage/innobase/log/log0log.c +++ b/storage/innobase/log/log0log.c @@ -1,23 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. - -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; 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, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ -/***************************************************************************** - -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2009, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -99,6 +82,18 @@ UNIV_INTERN ulint log_fsp_current_free_limit = 0; /* Global log system variable */ UNIV_INTERN log_t* log_sys = NULL; +#ifdef UNIV_PFS_RWLOCK +UNIV_INTERN mysql_pfs_key_t checkpoint_lock_key; +# ifdef UNIV_LOG_ARCHIVE +UNIV_INTERN mysql_pfs_key_t archive_lock_key; +# endif +#endif /* UNIV_PFS_RWLOCK */ + +#ifdef UNIV_PFS_MUTEX +UNIV_INTERN mysql_pfs_key_t log_sys_mutex_key; +UNIV_INTERN mysql_pfs_key_t log_flush_order_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + #ifdef UNIV_DEBUG UNIV_INTERN ibool log_do_write = TRUE; #endif /* UNIV_DEBUG */ @@ -773,7 +768,11 @@ log_init(void) { log_sys = mem_alloc(sizeof(log_t)); - mutex_create(&log_sys->mutex, SYNC_LOG); + mutex_create(log_sys_mutex_key, &log_sys->mutex, SYNC_LOG); + + mutex_create(log_flush_order_mutex_key, + &log_sys->log_flush_order_mutex, + SYNC_LOG_FLUSH_ORDER); mutex_enter(&(log_sys->mutex)); @@ -829,7 +828,8 @@ log_init(void) log_sys->last_checkpoint_lsn = log_sys->lsn; log_sys->n_pending_checkpoint_writes = 0; - rw_lock_create(&log_sys->checkpoint_lock, SYNC_NO_ORDER_CHECK); + rw_lock_create(checkpoint_lock_key, &log_sys->checkpoint_lock, + SYNC_NO_ORDER_CHECK); log_sys->checkpoint_buf_ptr = mem_alloc(2 * OS_FILE_LOG_BLOCK_SIZE); log_sys->checkpoint_buf = ut_align(log_sys->checkpoint_buf_ptr, @@ -845,7 +845,8 @@ log_init(void) log_sys->n_pending_archive_ios = 0; - rw_lock_create(&log_sys->archive_lock, SYNC_NO_ORDER_CHECK); + rw_lock_create(archive_lock_key, &log_sys->archive_lock, + SYNC_NO_ORDER_CHECK); log_sys->archive_buf = NULL; @@ -1654,10 +1655,10 @@ log_preflush_pool_modified_pages( recv_apply_hashed_log_recs(TRUE); } - n_pages = buf_flush_batch(BUF_FLUSH_LIST, ULINT_MAX, new_oldest); + n_pages = buf_flush_list(ULINT_MAX, new_oldest); if (sync) { - buf_flush_wait_batch_end(BUF_FLUSH_LIST); + buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); } if (n_pages == ULINT_UNDEFINED) { @@ -2013,7 +2014,7 @@ log_checkpoint( return(TRUE); } - ut_ad(log_sys->written_to_all_lsn >= oldest_lsn); + ut_ad(log_sys->flushed_to_disk_lsn >= oldest_lsn); if (log_sys->n_pending_checkpoint_writes > 0) { /* A checkpoint write is running */ @@ -2371,13 +2372,15 @@ loop: log_archived_file_name_gen(name, group->id, group->archived_file_no + n_files); - file_handle = os_file_create(name, open_mode, OS_FILE_AIO, + file_handle = os_file_create(innodb_file_log_key, + name, open_mode, + OS_FILE_AIO, OS_DATA_FILE, &ret); if (!ret && (open_mode == OS_FILE_CREATE)) { file_handle = os_file_create( - name, OS_FILE_OPEN, OS_FILE_AIO, - OS_DATA_FILE, &ret); + innodb_file_log_key, name, OS_FILE_OPEN, + OS_FILE_AIO, OS_DATA_FILE, &ret); } if (!ret) { @@ -3095,7 +3098,7 @@ loop: if (srv_fast_shutdown < 2 && (srv_error_monitor_active - || srv_lock_timeout_and_monitor_active)) { + || srv_lock_timeout_active || srv_monitor_active)) { mutex_exit(&kernel_mutex); @@ -3128,17 +3131,14 @@ loop: return; /* We SKIP ALL THE REST !! */ } - /* Check that the master thread is suspended */ - - if (srv_n_threads_active[SRV_MASTER] != 0) { + mutex_exit(&kernel_mutex); - mutex_exit(&kernel_mutex); + /* Check that the background threads are suspended */ + if (srv_is_any_background_thread_active()) { goto loop; } - mutex_exit(&kernel_mutex); - mutex_enter(&(log_sys->mutex)); if (log_sys->n_pending_checkpoint_writes @@ -3196,18 +3196,14 @@ loop: mutex_exit(&(log_sys->mutex)); - mutex_enter(&kernel_mutex); - /* Check that the master thread has stayed suspended */ - if (srv_n_threads_active[SRV_MASTER] != 0) { + /* Check that the background threads stay suspended */ + if (srv_is_any_background_thread_active()) { fprintf(stderr, - "InnoDB: Warning: the master thread woke up" + "InnoDB: Warning: some background thread woke up" " during shutdown\n"); - mutex_exit(&kernel_mutex); - goto loop; } - mutex_exit(&kernel_mutex); fil_flush_file_spaces(FIL_TABLESPACE); fil_flush_file_spaces(FIL_LOG); @@ -3225,7 +3221,8 @@ loop: srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE; /* Make some checks that the server really is quiet */ - ut_a(srv_n_threads_active[SRV_MASTER] == 0); + ut_a(!srv_is_any_background_thread_active()); + ut_a(buf_all_freed()); ut_a(lsn == log_sys->lsn); @@ -3246,7 +3243,8 @@ loop: fil_close_all_files(); /* Make some checks that the server really is quiet */ - ut_a(srv_n_threads_active[SRV_MASTER] == 0); + ut_a(!srv_is_any_background_thread_active()); + ut_a(buf_all_freed()); ut_a(lsn == log_sys->lsn); } @@ -3287,9 +3285,9 @@ log_check_log_recs( ut_memcpy(scan_buf, start, end - start); - recv_scan_log_recs((buf_pool->curr_size - - recv_n_pool_free_frames) * UNIV_PAGE_SIZE, - FALSE, scan_buf, end - start, + recv_scan_log_recs((buf_pool_get_n_pages() + - (recv_n_pool_free_frames * srv_buf_pool_instances)) + * UNIV_PAGE_SIZE, FALSE, scan_buf, end - start, ut_uint64_align_down(buf_start_lsn, OS_FILE_LOG_BLOCK_SIZE), &contiguous_lsn, &scanned_lsn); diff --git a/storage/innobase/log/log0recv.c b/storage/innobase/log/log0recv.c index ddbc71d4b71..f47f47e6a68 100644 --- a/storage/innobase/log/log0recv.c +++ b/storage/innobase/log/log0recv.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved. 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 @@ -138,7 +138,9 @@ UNIV_INTERN ulint recv_max_parsed_page_no; /** This many frames must be left free in the buffer pool when we scan the log and store the scanned log records in the buffer pool: we will use these free frames to read in pages when we start applying the -log records to the database. */ +log records to the database. +This is the default value. If the actual size of the buffer pool is +larger than 10 MB we'll set this value to 512. */ UNIV_INTERN ulint recv_n_pool_free_frames; /** The maximum lsn we see for a page during the recovery process. If this @@ -146,6 +148,14 @@ is bigger than the lsn we are able to scan up to, that is an indication that the recovery failed and the database may be corrupt. */ UNIV_INTERN ib_uint64_t recv_max_page_lsn; +#ifdef UNIV_PFS_THREAD +UNIV_INTERN mysql_pfs_key_t trx_rollback_clean_thread_key; +#endif /* UNIV_PFS_THREAD */ + +#ifdef UNIV_PFS_MUTEX +UNIV_INTERN mysql_pfs_key_t recv_sys_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + /* prototypes */ #ifndef UNIV_HOTBACKUP @@ -173,7 +183,7 @@ recv_sys_create(void) recv_sys = mem_alloc(sizeof(*recv_sys)); memset(recv_sys, 0x0, sizeof(*recv_sys)); - mutex_create(&recv_sys->mutex, SYNC_RECV); + mutex_create(recv_sys_mutex_key, &recv_sys->mutex, SYNC_RECV); recv_sys->heap = NULL; recv_sys->addr_hash = NULL; @@ -239,6 +249,7 @@ recv_sys_mem_free(void) } } +#ifndef UNIV_HOTBACKUP /************************************************************ Reset the state of the recovery system variables. */ UNIV_INTERN @@ -278,6 +289,7 @@ recv_sys_var_init(void) recv_max_page_lsn = 0; } +#endif /* !UNIV_HOTBACKUP */ /************************************************************ Inits the recovery system for a recovery operation. */ @@ -292,20 +304,34 @@ recv_sys_init( return; } +#ifndef UNIV_HOTBACKUP + /* Initialize red-black tree for fast insertions into the + flush_list during recovery process. + As this initialization is done while holding the buffer pool + mutex we perform it before acquiring recv_sys->mutex. */ +#ifndef UNIV_HOTBACKUP + buf_flush_init_flush_rbt(); +#endif /* !UNIV_HOTBACKUP */ + mutex_enter(&(recv_sys->mutex)); -#ifndef UNIV_HOTBACKUP recv_sys->heap = mem_heap_create_in_buffer(256); #else /* !UNIV_HOTBACKUP */ recv_sys->heap = mem_heap_create(256); recv_is_from_backup = TRUE; #endif /* !UNIV_HOTBACKUP */ + /* Set appropriate value of recv_n_pool_free_frames. */ + if (buf_pool_get_curr_size() >= (10 * 1024 * 1024)) { + /* Buffer pool of size greater than 10 MB. */ + recv_n_pool_free_frames = 512; + } + recv_sys->buf = ut_malloc(RECV_PARSING_BUF_SIZE); recv_sys->len = 0; recv_sys->recovered_offset = 0; - recv_sys->addr_hash = hash_create(available_memory / 64); + recv_sys->addr_hash = hash_create(available_memory / 512); recv_sys->n_addrs = 0; recv_sys->apply_log_recs = FALSE; @@ -345,7 +371,7 @@ recv_sys_empty_hash(void) hash_table_free(recv_sys->addr_hash); mem_heap_empty(recv_sys->heap); - recv_sys->addr_hash = hash_create(buf_pool_get_curr_size() / 256); + recv_sys->addr_hash = hash_create(buf_pool_get_curr_size() / 512); } #ifndef UNIV_HOTBACKUP @@ -370,6 +396,9 @@ recv_sys_debug_free(void) recv_sys->last_block_buf_start = NULL; mutex_exit(&(recv_sys->mutex)); + + /* Free up the flush_rbt. */ + buf_flush_free_flush_rbt(); } # endif /* UNIV_LOG_DEBUG */ @@ -1630,9 +1659,15 @@ recv_recover_page_func( #ifndef UNIV_HOTBACKUP if (modification_to_page) { + buf_pool_t* buf_pool; + ut_a(block); + buf_pool = buf_pool_from_block(block); + + log_flush_order_mutex_enter(); buf_flush_recv_note_modification(block, start_lsn, end_lsn); + log_flush_order_mutex_exit(); } #endif /* !UNIV_HOTBACKUP */ @@ -1817,11 +1852,10 @@ loop: mutex_exit(&(recv_sys->mutex)); mutex_exit(&(log_sys->mutex)); - n_pages = buf_flush_batch(BUF_FLUSH_LIST, ULINT_MAX, - IB_ULONGLONG_MAX); - ut_a(n_pages != ULINT_UNDEFINED); - - buf_flush_wait_batch_end(BUF_FLUSH_LIST); + n_pages = buf_flush_list(ULINT_MAX, IB_ULONGLONG_MAX); + ut_a(n_pages != ULINT_UNDEFINED); + + buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); buf_pool_invalidate(); @@ -2050,15 +2084,6 @@ recv_parse_log_rec( } #endif /* UNIV_LOG_LSN_DEBUG */ - /* Check that page_no is sensible */ - - if (UNIV_UNLIKELY(*page_no > 0x8FFFFFFFUL)) { - - recv_sys->found_corrupt_log = TRUE; - - return(0); - } - new_ptr = recv_parse_or_apply_log_rec_body(*type, new_ptr, end_ptr, NULL, NULL); if (UNIV_UNLIKELY(new_ptr == NULL)) { @@ -2167,6 +2192,14 @@ recv_report_corrupt_log( putc('\n', stderr); } +#ifndef UNIV_HOTBACKUP + if (!srv_force_recovery) { + fputs("InnoDB: Set innodb_force_recovery" + " to ignore this error.\n", stderr); + ut_error; + } +#endif /* !UNIV_HOTBACKUP */ + fputs("InnoDB: WARNING: the log file may have been corrupt and it\n" "InnoDB: is possible that the log scan did not proceed\n" "InnoDB: far enough in recovery! Please run CHECK TABLE\n" @@ -2556,7 +2589,7 @@ recv_scan_log_recs( ut_ad(start_lsn % OS_FILE_LOG_BLOCK_SIZE == 0); ut_ad(len % OS_FILE_LOG_BLOCK_SIZE == 0); - ut_ad(len > 0); + ut_ad(len >= OS_FILE_LOG_BLOCK_SIZE); ut_a(store_to_hash <= TRUE); finished = FALSE; @@ -2681,6 +2714,16 @@ recv_scan_log_recs( recv_sys->found_corrupt_log = TRUE; +#ifndef UNIV_HOTBACKUP + if (!srv_force_recovery) { + fputs("InnoDB: Set" + " innodb_force_recovery" + " to ignore this error.\n", + stderr); + ut_error; + } +#endif /* !UNIV_HOTBACKUP */ + } else if (!recv_sys->found_corrupt_log) { more_data = recv_sys_add_to_parsing_buf( log_block, scanned_lsn); @@ -2722,8 +2765,8 @@ recv_scan_log_recs( recv_parse_log_recs(store_to_hash); #ifndef UNIV_HOTBACKUP - if (store_to_hash && mem_heap_get_size(recv_sys->heap) - > available_memory) { + if (store_to_hash + && mem_heap_get_size(recv_sys->heap) > available_memory) { /* Hash table of log records has grown too big: empty it; FALSE means no ibuf operations @@ -2775,8 +2818,10 @@ recv_group_scan_log_recs( group, start_lsn, end_lsn); finished = recv_scan_log_recs( - (buf_pool->curr_size - recv_n_pool_free_frames) - * UNIV_PAGE_SIZE, TRUE, log_sys->buf, RECV_SCAN_SIZE, + (buf_pool_get_n_pages() + - (recv_n_pool_free_frames * srv_buf_pool_instances)) + * UNIV_PAGE_SIZE, + TRUE, log_sys->buf, RECV_SCAN_SIZE, start_lsn, contiguous_lsn, group_scanned_lsn); start_lsn = end_lsn; } @@ -3210,8 +3255,6 @@ void recv_recovery_from_checkpoint_finish(void) /*======================================*/ { - int i; - /* Apply the hashed log records to the respective file pages */ if (srv_force_recovery < SRV_FORCE_NO_LOG_REDO) { @@ -3259,9 +3302,16 @@ recv_recovery_from_checkpoint_finish(void) The data dictionary latch should guarantee that there is at most one data dictionary transaction active at a time. */ trx_rollback_or_clean_recovered(FALSE); +} - /* Drop partially created indexes. */ - row_merge_drop_temp_indexes(); +/********************************************************//** +Initiates the rollback of active transactions. */ +UNIV_INTERN +void +recv_recovery_rollback_active(void) +/*===============================*/ +{ + int i; #ifdef UNIV_SYNC_DEBUG /* Wait for a while so that created threads have time to suspend @@ -3271,6 +3321,11 @@ recv_recovery_from_checkpoint_finish(void) /* Switch latching order checks on in sync0sync.c */ sync_order_checks_on = TRUE; #endif + /* Drop partially created indexes. */ + row_merge_drop_temp_indexes(); + /* Drop temporary tables. */ + row_mysql_drop_temp_tables(); + if (srv_force_recovery < SRV_FORCE_NO_TRX_UNDO) { /* Rollback the uncommitted transactions which have no user session */ @@ -3386,8 +3441,10 @@ recv_reset_log_files_for_backup( sprintf(name, "%s%s%lu", log_dir, ib_logfile_basename, (ulong)i); - log_file = os_file_create_simple(name, OS_FILE_CREATE, - OS_FILE_READ_WRITE, &success); + log_file = os_file_create_simple(innodb_file_log_key, + name, OS_FILE_CREATE, + OS_FILE_READ_WRITE, + &success); if (!success) { fprintf(stderr, "InnoDB: Cannot create %s. Check that" @@ -3426,7 +3483,8 @@ recv_reset_log_files_for_backup( LOG_BLOCK_HDR_SIZE); sprintf(name, "%s%s%lu", log_dir, ib_logfile_basename, (ulong)0); - log_file = os_file_create_simple(name, OS_FILE_OPEN, + log_file = os_file_create_simple(innodb_file_log_key, + name, OS_FILE_OPEN, OS_FILE_READ_WRITE, &success); if (!success) { fprintf(stderr, "InnoDB: Cannot open %s.\n", name); @@ -3444,6 +3502,7 @@ recv_reset_log_files_for_backup( #endif /* UNIV_HOTBACKUP */ #ifdef UNIV_LOG_ARCHIVE +/* Dead code */ /******************************************************//** Reads from the archive of a log group and performs recovery. @return TRUE if no more complete consistent archive files */ @@ -3476,7 +3535,8 @@ try_open_again: log_archived_file_name_gen(name, group->id, group->archived_file_no); - file_handle = os_file_create(name, OS_FILE_OPEN, + file_handle = os_file_create(innodb_file_log_key, + name, OS_FILE_OPEN, OS_FILE_LOG, OS_FILE_AIO, &ret); if (ret == FALSE) { @@ -3608,7 +3668,8 @@ ask_again: read_offset % UNIV_PAGE_SIZE, len, buf, NULL); ret = recv_scan_log_recs( - (buf_pool->n_frames - recv_n_pool_free_frames) + (buf_pool_get_n_pages() + - (recv_n_pool_free_frames * srv_buf_pool_instances)) * UNIV_PAGE_SIZE, TRUE, buf, len, start_lsn, &dummy_lsn, &scanned_lsn); diff --git a/storage/innobase/mem/mem0dbg.c b/storage/innobase/mem/mem0dbg.c index 01eda20ec45..d91e610a08a 100644 --- a/storage/innobase/mem/mem0dbg.c +++ b/storage/innobase/mem/mem0dbg.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. 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 @@ -29,7 +29,13 @@ Created 6/9/1994 Heikki Tuuri /* The mutex which protects in the debug version the hash table containing the list of live memory heaps, and also the global variables below. */ -UNIV_INTERN mutex_t mem_hash_mutex; +UNIV_INTERN mutex_t mem_hash_mutex; + +#ifdef UNIV_PFS_MUTEX +/* Key to register mem_hash_mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t mem_hash_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + # endif /* !UNIV_HOTBACKUP */ /* The following variables contain information about the @@ -149,7 +155,7 @@ mem_init( /* Initialize the hash table */ ut_a(FALSE == mem_hash_initialized); - mutex_create(&mem_hash_mutex, SYNC_MEM_HASH); + mutex_create(mem_hash_mutex_key, &mem_hash_mutex, SYNC_MEM_HASH); for (i = 0; i < MEM_HASH_SIZE; i++) { UT_LIST_INIT(*mem_hash_get_nth_cell(i)); @@ -180,6 +186,10 @@ mem_close(void) { mem_pool_free(mem_comm_pool); mem_comm_pool = NULL; +#ifdef UNIV_MEM_DEBUG + mutex_free(&mem_hash_mutex); + mem_hash_initialized = FALSE; +#endif /* UNIV_MEM_DEBUG */ } #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/mem/mem0mem.c b/storage/innobase/mem/mem0mem.c index ccb2fd8a7b4..b5a7ddbd7b2 100644 --- a/storage/innobase/mem/mem0mem.c +++ b/storage/innobase/mem/mem0mem.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. 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 @@ -347,7 +347,7 @@ mem_heap_create_block( return(NULL); } } else { - buf_block = buf_block_alloc(0); + buf_block = buf_block_alloc(NULL, 0); } block = (mem_block_t*) buf_block->frame; @@ -367,7 +367,7 @@ mem_heap_create_block( block->line = line; #ifdef MEM_PERIODIC_CHECK - mem_pool_mutex_enter(); + mutex_enter(&(mem_comm_pool->mutex)); if (!mem_block_list_inited) { mem_block_list_inited = TRUE; @@ -376,13 +376,27 @@ mem_heap_create_block( UT_LIST_ADD_LAST(mem_block_list, mem_block_list, block); - mem_pool_mutex_exit(); + mutex_exit(&(mem_comm_pool->mutex)); #endif mem_block_set_len(block, len); mem_block_set_type(block, type); mem_block_set_free(block, MEM_BLOCK_HEADER_SIZE); mem_block_set_start(block, MEM_BLOCK_HEADER_SIZE); + if (UNIV_UNLIKELY(heap == NULL)) { + /* This is the first block of the heap. The field + total_size should be initialized here */ + block->total_size = len; + } else { + /* Not the first allocation for the heap. This block's + total_length field should be set to undefined. */ + ut_d(block->total_size = ULINT_UNDEFINED); + UNIV_MEM_INVALID(&block->total_size, + sizeof block->total_size); + + heap->total_size += len; + } + ut_ad((ulint)MEM_BLOCK_HEADER_SIZE < len); return(block); @@ -465,12 +479,16 @@ mem_heap_block_free( UT_LIST_REMOVE(list, heap->base, block); #ifdef MEM_PERIODIC_CHECK - mem_pool_mutex_enter(); + mutex_enter(&(mem_comm_pool->mutex)); UT_LIST_REMOVE(mem_block_list, mem_block_list, block); - mem_pool_mutex_exit(); + mutex_exit(&(mem_comm_pool->mutex)); #endif + + ut_ad(heap->total_size >= block->len); + heap->total_size -= block->len; + type = heap->type; len = block->len; block->magic_n = MEM_FREED_BLOCK_MAGIC_N; @@ -538,7 +556,7 @@ mem_validate_all_blocks(void) { mem_block_t* block; - mem_pool_mutex_enter(); + mutex_enter(&(mem_comm_pool->mutex)); block = UT_LIST_GET_FIRST(mem_block_list); @@ -550,6 +568,6 @@ mem_validate_all_blocks(void) block = UT_LIST_GET_NEXT(mem_block_list, block); } - mem_pool_mutex_exit(); + mutex_exit(&(mem_comm_pool->mutex)); } #endif diff --git a/storage/innobase/mem/mem0pool.c b/storage/innobase/mem/mem0pool.c index c4f8af607e0..dc68cf8eb24 100644 --- a/storage/innobase/mem/mem0pool.c +++ b/storage/innobase/mem/mem0pool.c @@ -34,6 +34,7 @@ Created 5/12/1997 Heikki Tuuri #include "ut0lst.h" #include "ut0byte.h" #include "mem0mem.h" +#include "srv0start.h" /* We would like to use also the buffer frames to allocate memory. This would be desirable, because then the memory consumption of the database @@ -114,6 +115,11 @@ struct mem_pool_struct{ /** The common memory pool */ UNIV_INTERN mem_pool_t* mem_comm_pool = NULL; +#ifdef UNIV_PFS_MUTEX +/* Key to register mutex in mem_pool_struct with performance schema */ +UNIV_INTERN mysql_pfs_key_t mem_pool_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + /* We use this counter to check that the mem pool mutex does not leak; this is to track a strange assertion failure reported at mysql@lists.mysql.com */ @@ -121,23 +127,33 @@ mysql@lists.mysql.com */ UNIV_INTERN ulint mem_n_threads_inside = 0; /********************************************************************//** -Reserves the mem pool mutex. */ -UNIV_INTERN +Reserves the mem pool mutex if we are not in server shutdown. Use +this function only in memory free functions, since only memory +free functions are used during server shutdown. */ +UNIV_INLINE void -mem_pool_mutex_enter(void) -/*======================*/ +mem_pool_mutex_enter( +/*=================*/ + mem_pool_t* pool) /*!< in: memory pool */ { - mutex_enter(&(mem_comm_pool->mutex)); + if (srv_shutdown_state < SRV_SHUTDOWN_EXIT_THREADS) { + mutex_enter(&(pool->mutex)); + } } /********************************************************************//** -Releases the mem pool mutex. */ -UNIV_INTERN +Releases the mem pool mutex if we are not in server shutdown. As +its corresponding mem_pool_mutex_enter() function, use it only +in memory free functions */ +UNIV_INLINE void -mem_pool_mutex_exit(void) -/*=====================*/ +mem_pool_mutex_exit( +/*================*/ + mem_pool_t* pool) /*!< in: memory pool */ { - mutex_exit(&(mem_comm_pool->mutex)); + if (srv_shutdown_state < SRV_SHUTDOWN_EXIT_THREADS) { + mutex_exit(&(pool->mutex)); + } } /********************************************************************//** @@ -219,7 +235,7 @@ mem_pool_create( pool->buf = ut_malloc_low(size, FALSE, TRUE); pool->size = size; - mutex_create(&pool->mutex, SYNC_MEM_POOL); + mutex_create(mem_pool_mutex_key, &pool->mutex, SYNC_MEM_POOL); /* Initialize the free lists */ @@ -567,7 +583,7 @@ mem_area_free( n = ut_2_log(size); - mutex_enter(&(pool->mutex)); + mem_pool_mutex_enter(pool); mem_n_threads_inside++; ut_a(mem_n_threads_inside == 1); @@ -595,7 +611,7 @@ mem_area_free( pool->reserved += ut_2_exp(n); mem_n_threads_inside--; - mutex_exit(&(pool->mutex)); + mem_pool_mutex_exit(pool); mem_area_free(new_ptr, pool); @@ -611,7 +627,7 @@ mem_area_free( } mem_n_threads_inside--; - mutex_exit(&(pool->mutex)); + mem_pool_mutex_exit(pool); ut_ad(mem_pool_validate(pool)); } @@ -630,7 +646,7 @@ mem_pool_validate( ulint free; ulint i; - mutex_enter(&(pool->mutex)); + mem_pool_mutex_enter(pool); free = 0; @@ -658,7 +674,7 @@ mem_pool_validate( ut_a(free + pool->reserved == pool->size); - mutex_exit(&(pool->mutex)); + mem_pool_mutex_exit(pool); return(TRUE); } diff --git a/storage/innobase/mtr/mtr0mtr.c b/storage/innobase/mtr/mtr0mtr.c index 417e97732bb..b01462f6b9b 100644 --- a/storage/innobase/mtr/mtr0mtr.c +++ b/storage/innobase/mtr/mtr0mtr.c @@ -30,6 +30,7 @@ Created 11/26/1995 Heikki Tuuri #endif #include "buf0buf.h" +#include "buf0flu.h" #include "page0types.h" #include "mtr0log.h" #include "log0log.h" @@ -38,7 +39,7 @@ Created 11/26/1995 Heikki Tuuri # include "log0recv.h" /*****************************************************************//** Releases the item in the slot given. */ -UNIV_INLINE +static void mtr_memo_slot_release( /*==================*/ @@ -48,14 +49,19 @@ mtr_memo_slot_release( void* object; ulint type; - ut_ad(mtr && slot); + ut_ad(mtr); + ut_ad(slot); + +#ifndef UNIV_DEBUG + UT_NOT_USED(mtr); +#endif /* UNIV_DEBUG */ object = slot->object; type = slot->type; if (UNIV_LIKELY(object != NULL)) { if (type <= MTR_MEMO_BUF_FIX) { - buf_page_release((buf_block_t*)object, type, mtr); + buf_page_release((buf_block_t*)object, type); } else if (type == MTR_MEMO_S_LOCK) { rw_lock_s_unlock((rw_lock_t*)object); #ifdef UNIV_DEBUG @@ -73,13 +79,10 @@ mtr_memo_slot_release( } /**********************************************************//** -Releases the mlocks and other objects stored in an mtr memo. They are released -in the order opposite to which they were pushed to the memo. NOTE! It is -essential that the x-rw-lock on a modified buffer page is not released before -buf_page_note_modification is called for that page! Otherwise, some thread -might race to modify it, and the flush list sort order on lsn would be -destroyed. */ -UNIV_INLINE +Releases the mlocks and other objects stored in an mtr memo. +They are released in the order opposite to which they were pushed +to the memo. */ +static void mtr_memo_pop_all( /*=============*/ @@ -105,6 +108,63 @@ mtr_memo_pop_all( } } +/*****************************************************************//** +Releases the item in the slot given. */ +static +void +mtr_memo_slot_note_modification( +/*============================*/ + mtr_t* mtr, /*!< in: mtr */ + mtr_memo_slot_t* slot) /*!< in: memo slot */ +{ + ut_ad(mtr); + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->modifications); + + if (slot->object != NULL && slot->type == MTR_MEMO_PAGE_X_FIX) { + buf_block_t* block = (buf_block_t*) slot->object; + +#ifdef UNIV_DEBUG + ut_ad(log_flush_order_mutex_own()); +#endif /* UNIV_DEBUG */ + buf_flush_note_modification(block, mtr); + } +} + +/**********************************************************//** +Add the modified pages to the buffer flush list. They are released +in the order opposite to which they were pushed to the memo. NOTE! It is +essential that the x-rw-lock on a modified buffer page is not released +before buf_page_note_modification is called for that page! Otherwise, +some thread might race to modify it, and the flush list sort order on +lsn would be destroyed. */ +static +void +mtr_memo_note_modifications( +/*========================*/ + mtr_t* mtr) /*!< in: mtr */ +{ + dyn_array_t* memo; + ulint offset; + + ut_ad(mtr); + ut_ad(mtr->magic_n == MTR_MAGIC_N); + ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in + commit */ + memo = &mtr->memo; + + offset = dyn_array_get_data_size(memo); + + while (offset > 0) { + mtr_memo_slot_t* slot; + + offset -= sizeof(mtr_memo_slot_t); + slot = dyn_array_get_element(memo, offset); + + mtr_memo_slot_note_modification(mtr, slot); + } +} + /************************************************************//** Writes the contents of a mini-transaction log, if any, to the database log. */ static @@ -137,7 +197,9 @@ mtr_log_reserve_and_write( &mtr->start_lsn); if (mtr->end_lsn) { - return; + /* Success. We have the log mutex. + Add pages to flush list and exit */ + goto func_exit; } } @@ -161,6 +223,20 @@ mtr_log_reserve_and_write( } mtr->end_lsn = log_close(); + +func_exit: + log_flush_order_mutex_enter(); + + /* It is now safe to release the log mutex because the + flush_order mutex will ensure that we are the first one + to insert into the flush list. */ + log_release(); + + if (mtr->modifications) { + mtr_memo_note_modifications(mtr); + } + + log_flush_order_mutex_exit(); } #endif /* !UNIV_HOTBACKUP */ @@ -172,10 +248,6 @@ mtr_commit( /*=======*/ mtr_t* mtr) /*!< in: mini-transaction */ { -#ifndef UNIV_HOTBACKUP - ibool write_log; -#endif /* !UNIV_HOTBACKUP */ - ut_ad(mtr); ut_ad(mtr->magic_n == MTR_MAGIC_N); ut_ad(mtr->state == MTR_ACTIVE); @@ -184,25 +256,12 @@ mtr_commit( #ifndef UNIV_HOTBACKUP /* This is a dirty read, for debugging. */ ut_ad(!recv_no_log_write); - write_log = mtr->modifications && mtr->n_log_recs; - if (write_log) { + if (mtr->modifications && mtr->n_log_recs) { mtr_log_reserve_and_write(mtr); } - /* We first update the modification info to buffer pages, and only - after that release the log mutex: this guarantees that when the log - mutex is free, all buffer pages contain an up-to-date info of their - modifications. This fact is used in making a checkpoint when we look - at the oldest modification of any page in the buffer pool. It is also - required when we insert modified buffer pages in to the flush list - which must be sorted on oldest_modification. */ - mtr_memo_pop_all(mtr); - - if (write_log) { - log_release(); - } #endif /* !UNIV_HOTBACKUP */ ut_d(mtr->state = MTR_COMMITTED); @@ -241,6 +300,10 @@ mtr_rollback_to_savepoint( slot = dyn_array_get_element(memo, offset); ut_ad(slot->type != MTR_MEMO_MODIFY); + + /* We do not call mtr_memo_slot_note_modification() + because there MUST be no changes made to the buffer + pages after the savepoint */ mtr_memo_slot_release(mtr, slot); } } @@ -267,18 +330,23 @@ mtr_memo_release( offset = dyn_array_get_data_size(memo); + log_flush_order_mutex_enter(); while (offset > 0) { offset -= sizeof(mtr_memo_slot_t); slot = dyn_array_get_element(memo, offset); - if ((object == slot->object) && (type == slot->type)) { + if (object == slot->object && type == slot->type) { + if (mtr->modifications) { + mtr_memo_slot_note_modification(mtr, slot); + } mtr_memo_slot_release(mtr, slot); break; } } + log_flush_order_mutex_exit(); } #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/mysql-test/ctype_innodb_like.inc b/storage/innobase/mysql-test/ctype_innodb_like.inc deleted file mode 100644 index ae43342885a..00000000000 --- a/storage/innobase/mysql-test/ctype_innodb_like.inc +++ /dev/null @@ -1,21 +0,0 @@ -# -# Bug#11650: LIKE pattern matching using prefix index -# doesn't return correct result -# ---disable_warnings -# -# This query creates a column using -# character_set_connection and -# collation_connection. -# -create table t1 engine=innodb select repeat('a',50) as c1; ---enable_warnings -alter table t1 add index(c1(5)); - -insert into t1 values ('abcdefg'),('abcde100'),('abcde110'),('abcde111'); -select collation(c1) from t1 limit 1; -select c1 from t1 where c1 like 'abcdef%' order by c1; -select c1 from t1 where c1 like 'abcde1%' order by c1; -select c1 from t1 where c1 like 'abcde11%' order by c1; -select c1 from t1 where c1 like 'abcde111%' order by c1; -drop table t1; diff --git a/storage/innobase/mysql-test/have_innodb.inc b/storage/innobase/mysql-test/have_innodb.inc deleted file mode 100644 index 8944cc46f3e..00000000000 --- a/storage/innobase/mysql-test/have_innodb.inc +++ /dev/null @@ -1,4 +0,0 @@ -disable_query_log; ---require r/true.require -select (support = 'YES' or support = 'DEFAULT' or support = 'ENABLED') as `TRUE` from information_schema.engines where engine = 'innodb'; -enable_query_log; diff --git a/storage/innobase/mysql-test/innodb-analyze.result b/storage/innobase/mysql-test/innodb-analyze.result deleted file mode 100644 index 2aee004a2d6..00000000000 --- a/storage/innobase/mysql-test/innodb-analyze.result +++ /dev/null @@ -1,2 +0,0 @@ -Variable_name Value -innodb_stats_sample_pages 1 diff --git a/storage/innobase/mysql-test/innodb-analyze.test b/storage/innobase/mysql-test/innodb-analyze.test deleted file mode 100644 index 9bdb9db697c..00000000000 --- a/storage/innobase/mysql-test/innodb-analyze.test +++ /dev/null @@ -1,65 +0,0 @@ -# -# Test that mysqld does not crash when running ANALYZE TABLE with -# different values of the parameter innodb_stats_sample_pages. -# - --- source include/have_innodb.inc - -# we care only that the following SQL commands do not produce errors -# and do not crash the server --- disable_query_log --- disable_result_log --- enable_warnings - -let $sample_pages=`select @@innodb_stats_sample_pages`; -SET GLOBAL innodb_stats_sample_pages=0; - -# check that the value has been adjusted to 1 --- enable_result_log -SHOW VARIABLES LIKE 'innodb_stats_sample_pages'; --- disable_result_log - -CREATE TABLE innodb_analyze ( - a INT, - b INT, - KEY(a), - KEY(b,a) -) ENGINE=InnoDB; - -# test with empty table - -ANALYZE TABLE innodb_analyze; - -SET GLOBAL innodb_stats_sample_pages=2; -ANALYZE TABLE innodb_analyze; - -SET GLOBAL innodb_stats_sample_pages=4; -ANALYZE TABLE innodb_analyze; - -SET GLOBAL innodb_stats_sample_pages=8; -ANALYZE TABLE innodb_analyze; - -SET GLOBAL innodb_stats_sample_pages=16; -ANALYZE TABLE innodb_analyze; - -INSERT INTO innodb_analyze VALUES -(1,1), (1,1), (1,2), (1,3), (1,4), (1,5), -(8,1), (8,8), (8,2), (7,1), (1,4), (3,5); - -SET GLOBAL innodb_stats_sample_pages=1; -ANALYZE TABLE innodb_analyze; - -SET GLOBAL innodb_stats_sample_pages=2; -ANALYZE TABLE innodb_analyze; - -SET GLOBAL innodb_stats_sample_pages=4; -ANALYZE TABLE innodb_analyze; - -SET GLOBAL innodb_stats_sample_pages=8; -ANALYZE TABLE innodb_analyze; - -SET GLOBAL innodb_stats_sample_pages=16; -ANALYZE TABLE innodb_analyze; - -DROP TABLE innodb_analyze; -EVAL SET GLOBAL innodb_stats_sample_pages=$sample_pages; diff --git a/storage/innobase/mysql-test/innodb-autoinc.result b/storage/innobase/mysql-test/innodb-autoinc.result deleted file mode 100644 index d2e8eb19e0c..00000000000 --- a/storage/innobase/mysql-test/innodb-autoinc.result +++ /dev/null @@ -1,891 +0,0 @@ -drop table if exists t1; -CREATE TABLE t1 (c1 BIGINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (9223372036854775807, null); -INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors -SELECT * FROM t1; -c1 c2 -9223372036854775807 NULL -DROP TABLE t1; -CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (127, null); -INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors -SELECT * FROM t1; -c1 c2 -127 NULL -DROP TABLE t1; -CREATE TABLE t1 (c1 TINYINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (255, null); -INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors -SELECT * FROM t1; -c1 c2 -255 NULL -DROP TABLE t1; -CREATE TABLE t1 (c1 SMALLINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (32767, null); -INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors -SELECT * FROM t1; -c1 c2 -32767 NULL -DROP TABLE t1; -CREATE TABLE t1 (c1 SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (65535, null); -INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors -SELECT * FROM t1; -c1 c2 -65535 NULL -DROP TABLE t1; -CREATE TABLE t1 (c1 MEDIUMINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (8388607, null); -INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors -SELECT * FROM t1; -c1 c2 -8388607 NULL -DROP TABLE t1; -CREATE TABLE t1 (c1 MEDIUMINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (16777215, null); -INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors -SELECT * FROM t1; -c1 c2 -16777215 NULL -DROP TABLE t1; -CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (2147483647, null); -INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors -SELECT * FROM t1; -c1 c2 -2147483647 NULL -DROP TABLE t1; -CREATE TABLE t1 (c1 INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (4294967295, null); -INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors -SELECT * FROM t1; -c1 c2 -4294967295 NULL -DROP TABLE t1; -CREATE TABLE t1 (c1 BIGINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (9223372036854775807, null); -INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors -SELECT * FROM t1; -c1 c2 -9223372036854775807 NULL -DROP TABLE t1; -CREATE TABLE t1 (c1 BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (18446744073709551615, null); -INSERT INTO t1 (c2) VALUES ('innodb'); -Got one of the listed errors -SELECT * FROM t1; -c1 c2 -18446744073709551615 NULL -DROP TABLE t1; -CREATE TABLE t1(c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; -INSERT INTO t1 VALUES (1), (2), (3); -INSERT INTO t1 VALUES (NULL), (NULL), (NULL); -SELECT c1 FROM t1; -c1 -1 -2 -3 -4 -5 -6 -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`c1`) -) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 -TRUNCATE TABLE t1; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`c1`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -INSERT INTO t1 VALUES (1), (2), (3); -INSERT INTO t1 VALUES (NULL), (NULL), (NULL); -SELECT c1 FROM t1; -c1 -1 -2 -3 -4 -5 -6 -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`c1`) -) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 -DROP TABLE t1; -CREATE TABLE t1(c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; -INSERT INTO t1 VALUES (1), (2), (3); -INSERT INTO t1 VALUES (NULL), (NULL), (NULL); -SELECT c1 FROM t1; -c1 -1 -2 -3 -4 -5 -6 -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`c1`) -) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 -DELETE FROM t1; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`c1`) -) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1 -INSERT INTO t1 VALUES (1), (2), (3); -INSERT INTO t1 VALUES (NULL), (NULL), (NULL); -SELECT c1 FROM t1; -c1 -1 -2 -3 -7 -8 -9 -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`c1`) -) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1 -DROP TABLE t1; -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (NULL, 1); -DELETE FROM t1 WHERE c1 = 1; -INSERT INTO t1 VALUES (2,1); -INSERT INTO t1 VALUES (NULL,8); -SELECT * FROM t1; -c1 c2 -2 1 -3 8 -DROP TABLE t1; -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (NULL, 1); -DELETE FROM t1 WHERE c1 = 1; -INSERT INTO t1 VALUES (2,1), (NULL, 8); -INSERT INTO t1 VALUES (NULL,9); -SELECT * FROM t1; -c1 c2 -2 1 -3 8 -5 9 -DROP TABLE t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 100 -auto_increment_offset 10 -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (NULL),(5),(NULL); -INSERT INTO t1 VALUES (250),(NULL); -SELECT * FROM t1; -c1 -5 -10 -110 -250 -310 -INSERT INTO t1 VALUES (1000); -SET @@INSERT_ID=400; -INSERT INTO t1 VALUES(NULL),(NULL); -SELECT * FROM t1; -c1 -5 -10 -110 -250 -310 -400 -410 -1000 -DROP TABLE t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 1 -auto_increment_offset 1 -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(0); -SELECT * FROM t1; -c1 -1 -SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -INSERT INTO t1 VALUES (-1), (NULL),(2),(NULL); -INSERT INTO t1 VALUES (250),(NULL); -SELECT * FROM t1; -c1 --1 -1 -2 -10 -110 -250 -410 -SET @@INSERT_ID=400; -INSERT INTO t1 VALUES(NULL),(NULL); -Got one of the listed errors -SELECT * FROM t1; -c1 --1 -1 -2 -10 -110 -250 -410 -DROP TABLE t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 1 -auto_increment_offset 1 -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(-1); -SELECT * FROM t1; -c1 --1 -SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 100 -auto_increment_offset 10 -INSERT INTO t1 VALUES (-2), (NULL),(2),(NULL); -INSERT INTO t1 VALUES (250),(NULL); -SELECT * FROM t1; -c1 --2 --1 -1 -2 -10 -250 -310 -INSERT INTO t1 VALUES (1000); -SET @@INSERT_ID=400; -INSERT INTO t1 VALUES(NULL),(NULL); -SELECT * FROM t1; -c1 --2 --1 -1 -2 -10 -250 -310 -400 -410 -1000 -DROP TABLE t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 1 -auto_increment_offset 1 -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(-1); -Warnings: -Warning 1264 Out of range value for column 'c1' at row 1 -SELECT * FROM t1; -c1 -1 -SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 100 -auto_increment_offset 10 -INSERT INTO t1 VALUES (-2); -Warnings: -Warning 1264 Out of range value for column 'c1' at row 1 -INSERT INTO t1 VALUES (NULL); -INSERT INTO t1 VALUES (2); -INSERT INTO t1 VALUES (NULL); -INSERT INTO t1 VALUES (250); -INSERT INTO t1 VALUES (NULL); -SELECT * FROM t1; -c1 -1 -2 -10 -110 -210 -250 -310 -INSERT INTO t1 VALUES (1000); -SET @@INSERT_ID=400; -INSERT INTO t1 VALUES(NULL); -INSERT INTO t1 VALUES(NULL); -SELECT * FROM t1; -c1 -1 -2 -10 -110 -210 -250 -310 -400 -1000 -1010 -DROP TABLE t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 1 -auto_increment_offset 1 -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(-1); -Warnings: -Warning 1264 Out of range value for column 'c1' at row 1 -SELECT * FROM t1; -c1 -1 -SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 100 -auto_increment_offset 10 -INSERT INTO t1 VALUES (-2),(NULL),(2),(NULL); -Warnings: -Warning 1264 Out of range value for column 'c1' at row 1 -INSERT INTO t1 VALUES (250),(NULL); -SELECT * FROM t1; -c1 -1 -2 -10 -110 -210 -250 -410 -INSERT INTO t1 VALUES (1000); -SET @@INSERT_ID=400; -INSERT INTO t1 VALUES(NULL),(NULL); -Got one of the listed errors -SELECT * FROM t1; -c1 -1 -2 -10 -110 -210 -250 -410 -1000 -DROP TABLE t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 1 -auto_increment_offset 1 -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(NULL); -INSERT INTO t1 VALUES (9223372036854775794); -SELECT * FROM t1; -c1 -1 -9223372036854775794 -SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 2 -auto_increment_offset 10 -INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); -SELECT * FROM t1; -c1 -1 -9223372036854775794 -9223372036854775796 -9223372036854775798 -9223372036854775800 -9223372036854775802 -9223372036854775804 -9223372036854775806 -DROP TABLE t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 1 -auto_increment_offset 1 -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(NULL); -INSERT INTO t1 VALUES (18446744073709551603); -SELECT * FROM t1; -c1 -1 -18446744073709551603 -SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 2 -auto_increment_offset 10 -INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); -SELECT * FROM t1; -c1 -1 -18446744073709551603 -18446744073709551604 -18446744073709551606 -18446744073709551608 -18446744073709551610 -18446744073709551612 -18446744073709551614 -DROP TABLE t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 1 -auto_increment_offset 1 -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(NULL); -INSERT INTO t1 VALUES (18446744073709551603); -SELECT * FROM t1; -c1 -1 -18446744073709551603 -SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 5 -auto_increment_offset 7 -INSERT INTO t1 VALUES (NULL),(NULL); -SELECT * FROM t1; -c1 -1 -18446744073709551603 -18446744073709551607 -18446744073709551612 -DROP TABLE t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 1 -auto_increment_offset 1 -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(NULL); -INSERT INTO t1 VALUES(-9223372036854775806); -INSERT INTO t1 VALUES(-9223372036854775807); -INSERT INTO t1 VALUES(-9223372036854775808); -SELECT * FROM t1; -c1 --9223372036854775808 --9223372036854775807 --9223372036854775806 -1 -SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 3 -auto_increment_offset 3 -INSERT INTO t1 VALUES (NULL),(NULL), (NULL); -SELECT * FROM t1; -c1 --9223372036854775808 --9223372036854775807 --9223372036854775806 -1 -3 -6 -9 -DROP TABLE t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 1 -auto_increment_offset 1 -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(NULL); -INSERT INTO t1 VALUES (18446744073709551610); -SELECT * FROM t1; -c1 -1 -18446744073709551610 -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976; -Warnings: -Warning 1292 Truncated incorrect auto_increment_increment value: '1152921504606846976' -Warning 1292 Truncated incorrect auto_increment_offset value: '1152921504606846976' -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 65535 -auto_increment_offset 65535 -INSERT INTO t1 VALUES (NULL); -SELECT * FROM t1; -c1 -1 -18446744073709551610 -18446744073709551615 -DROP TABLE t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -Variable_name Value -auto_increment_increment 1 -auto_increment_offset 1 -CREATE TABLE t1 (c1 DOUBLE NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(NULL, 1); -INSERT INTO t1 VALUES(NULL, 2); -SELECT * FROM t1; -c1 c2 -1 1 -2 2 -ALTER TABLE t1 CHANGE c1 c1 SERIAL; -SELECT * FROM t1; -c1 c2 -1 1 -2 2 -INSERT INTO t1 VALUES(NULL, 3); -INSERT INTO t1 VALUES(NULL, 4); -SELECT * FROM t1; -c1 c2 -1 1 -2 2 -3 3 -4 4 -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 FLOAT NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(NULL, 1); -INSERT INTO t1 VALUES(NULL, 2); -SELECT * FROM t1; -c1 c2 -1 1 -2 2 -ALTER TABLE t1 CHANGE c1 c1 SERIAL; -SELECT * FROM t1; -c1 c2 -1 1 -2 2 -INSERT INTO t1 VALUES(NULL, 3); -INSERT INTO t1 VALUES(NULL, 4); -SELECT * FROM t1; -c1 c2 -1 1 -2 2 -3 3 -4 4 -DROP TABLE t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=5; -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -DROP TABLE IF EXISTS t2; -Warnings: -Note 1051 Unknown table 't2' -CREATE TABLE t1 ( -a INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, -b INT(10) UNSIGNED NOT NULL, -c ENUM('FALSE','TRUE') DEFAULT NULL, -PRIMARY KEY (a)) ENGINE = InnoDB; -CREATE TABLE t2 ( -m INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, -n INT(10) UNSIGNED NOT NULL, -o enum('FALSE','TRUE') DEFAULT NULL, -PRIMARY KEY (m)) ENGINE = InnoDB; -INSERT INTO t2 (n,o) VALUES -(1 , 'true'), (1 , 'false'), (2 , 'true'), (2 , 'false'), (3 , 'true'), -(3 , 'false'), (4 , 'true'), (4 , 'false'), (5 , 'true'), (5 , 'false'); -SHOW CREATE TABLE t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `m` int(11) unsigned NOT NULL AUTO_INCREMENT, - `n` int(10) unsigned NOT NULL, - `o` enum('FALSE','TRUE') DEFAULT NULL, - PRIMARY KEY (`m`) -) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=latin1 -INSERT INTO t1 (b,c) SELECT n,o FROM t2 ; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) unsigned NOT NULL AUTO_INCREMENT, - `b` int(10) unsigned NOT NULL, - `c` enum('FALSE','TRUE') DEFAULT NULL, - PRIMARY KEY (`a`) -) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=latin1 -INSERT INTO t1 (b,c) SELECT n,o FROM t2 ; -SELECT * FROM t1; -a b c -1 1 TRUE -2 1 FALSE -3 2 TRUE -4 2 FALSE -5 3 TRUE -6 3 FALSE -7 4 TRUE -8 4 FALSE -9 5 TRUE -10 5 FALSE -13 1 TRUE -14 1 FALSE -15 2 TRUE -16 2 FALSE -17 3 TRUE -18 3 FALSE -19 4 TRUE -20 4 FALSE -21 5 TRUE -22 5 FALSE -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) unsigned NOT NULL AUTO_INCREMENT, - `b` int(10) unsigned NOT NULL, - `c` enum('FALSE','TRUE') DEFAULT NULL, - PRIMARY KEY (`a`) -) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=latin1 -INSERT INTO t1 (b,c) SELECT n,o FROM t2 WHERE o = 'false'; -SELECT * FROM t1; -a b c -1 1 TRUE -2 1 FALSE -3 2 TRUE -4 2 FALSE -5 3 TRUE -6 3 FALSE -7 4 TRUE -8 4 FALSE -9 5 TRUE -10 5 FALSE -13 1 TRUE -14 1 FALSE -15 2 TRUE -16 2 FALSE -17 3 TRUE -18 3 FALSE -19 4 TRUE -20 4 FALSE -21 5 TRUE -22 5 FALSE -23 1 FALSE -24 2 FALSE -25 3 FALSE -26 4 FALSE -27 5 FALSE -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) unsigned NOT NULL AUTO_INCREMENT, - `b` int(10) unsigned NOT NULL, - `c` enum('FALSE','TRUE') DEFAULT NULL, - PRIMARY KEY (`a`) -) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=latin1 -INSERT INTO t1 (b,c) SELECT n,o FROM t2 WHERE o = 'false'; -SELECT * FROM t1; -a b c -1 1 TRUE -2 1 FALSE -3 2 TRUE -4 2 FALSE -5 3 TRUE -6 3 FALSE -7 4 TRUE -8 4 FALSE -9 5 TRUE -10 5 FALSE -13 1 TRUE -14 1 FALSE -15 2 TRUE -16 2 FALSE -17 3 TRUE -18 3 FALSE -19 4 TRUE -20 4 FALSE -21 5 TRUE -22 5 FALSE -23 1 FALSE -24 2 FALSE -25 3 FALSE -26 4 FALSE -27 5 FALSE -30 1 FALSE -31 2 FALSE -32 3 FALSE -33 4 FALSE -34 5 FALSE -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) unsigned NOT NULL AUTO_INCREMENT, - `b` int(10) unsigned NOT NULL, - `c` enum('FALSE','TRUE') DEFAULT NULL, - PRIMARY KEY (`a`) -) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=latin1 -INSERT INTO t1 (b,c) SELECT n,o FROM t2 WHERE o = 'false'; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) unsigned NOT NULL AUTO_INCREMENT, - `b` int(10) unsigned NOT NULL, - `c` enum('FALSE','TRUE') DEFAULT NULL, - PRIMARY KEY (`a`) -) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=latin1 -INSERT INTO t1 (b,c) SELECT n,o FROM t2 WHERE o = 'false'; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) unsigned NOT NULL AUTO_INCREMENT, - `b` int(10) unsigned NOT NULL, - `c` enum('FALSE','TRUE') DEFAULT NULL, - PRIMARY KEY (`a`) -) ENGINE=InnoDB AUTO_INCREMENT=51 DEFAULT CHARSET=latin1 -INSERT INTO t1 (b,c) SELECT n,o FROM t2 WHERE o = 'false'; -SELECT * FROM t1; -a b c -1 1 TRUE -2 1 FALSE -3 2 TRUE -4 2 FALSE -5 3 TRUE -6 3 FALSE -7 4 TRUE -8 4 FALSE -9 5 TRUE -10 5 FALSE -13 1 TRUE -14 1 FALSE -15 2 TRUE -16 2 FALSE -17 3 TRUE -18 3 FALSE -19 4 TRUE -20 4 FALSE -21 5 TRUE -22 5 FALSE -23 1 FALSE -24 2 FALSE -25 3 FALSE -26 4 FALSE -27 5 FALSE -30 1 FALSE -31 2 FALSE -32 3 FALSE -33 4 FALSE -34 5 FALSE -37 1 FALSE -38 2 FALSE -39 3 FALSE -40 4 FALSE -41 5 FALSE -44 1 FALSE -45 2 FALSE -46 3 FALSE -47 4 FALSE -48 5 FALSE -51 1 FALSE -52 2 FALSE -53 3 FALSE -54 4 FALSE -55 5 FALSE -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) unsigned NOT NULL AUTO_INCREMENT, - `b` int(10) unsigned NOT NULL, - `c` enum('FALSE','TRUE') DEFAULT NULL, - PRIMARY KEY (`a`) -) ENGINE=InnoDB AUTO_INCREMENT=58 DEFAULT CHARSET=latin1 -DROP TABLE t1; -DROP TABLE t2; -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -DROP TABLE IF EXISTS t2; -Warnings: -Note 1051 Unknown table 't2' -CREATE TABLE t1( -c1 INT(10) UNSIGNED NOT NULL AUTO_INCREMENT -PRIMARY KEY) ENGINE=InnoDB; -INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL); -CREATE TABLE t2( -c1 TINYINT(3) UNSIGNED NOT NULL AUTO_INCREMENT -PRIMARY KEY) ENGINE=InnoDB; -INSERT INTO t2 SELECT c1 FROM t1; -Got one of the listed errors -INSERT INTO t2 SELECT NULL FROM t1; -Got one of the listed errors -DROP TABLE t1; -DROP TABLE t2; -CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; -INSERT INTO t1 VALUES (null); -INSERT INTO t1 VALUES (null); -ALTER TABLE t1 CHANGE c1 d1 INT NOT NULL AUTO_INCREMENT; -SELECT * FROM t1; -d1 -1 -3 -SELECT * FROM t1; -d1 -1 -3 -INSERT INTO t1 VALUES(null); -Got one of the listed errors -ALTER TABLE t1 AUTO_INCREMENT = 3; -INSERT INTO t1 VALUES(null); -SELECT * FROM t1; -d1 -1 -3 -4 -DROP TABLE t1; diff --git a/storage/innobase/mysql-test/innodb-autoinc.test b/storage/innobase/mysql-test/innodb-autoinc.test deleted file mode 100644 index 61c42f45733..00000000000 --- a/storage/innobase/mysql-test/innodb-autoinc.test +++ /dev/null @@ -1,500 +0,0 @@ --- source include/have_innodb.inc -# embedded server ignores 'delayed', so skip this --- source include/not_embedded.inc - ---disable_warnings -drop table if exists t1; ---enable_warnings - -# -# Bug #34335 -# -CREATE TABLE t1 (c1 BIGINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (9223372036854775807, null); --- error ER_DUP_ENTRY,1062 -INSERT INTO t1 (c2) VALUES ('innodb'); -SELECT * FROM t1; -DROP TABLE t1; -# -## Test AUTOINC overflow -## - -# TINYINT -CREATE TABLE t1 (c1 TINYINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (127, null); --- error ER_DUP_ENTRY,1062 -INSERT INTO t1 (c2) VALUES ('innodb'); -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 (c1 TINYINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (255, null); --- error ER_DUP_ENTRY,1062 -INSERT INTO t1 (c2) VALUES ('innodb'); -SELECT * FROM t1; -DROP TABLE t1; -# -# SMALLINT -# -CREATE TABLE t1 (c1 SMALLINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (32767, null); --- error ER_DUP_ENTRY,1062 -INSERT INTO t1 (c2) VALUES ('innodb'); -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 (c1 SMALLINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (65535, null); --- error ER_DUP_ENTRY,1062 -INSERT INTO t1 (c2) VALUES ('innodb'); -SELECT * FROM t1; -DROP TABLE t1; -# -# MEDIUMINT -# -CREATE TABLE t1 (c1 MEDIUMINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (8388607, null); --- error ER_DUP_ENTRY,1062 -INSERT INTO t1 (c2) VALUES ('innodb'); -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 (c1 MEDIUMINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (16777215, null); --- error ER_DUP_ENTRY,1062 -INSERT INTO t1 (c2) VALUES ('innodb'); -SELECT * FROM t1; -DROP TABLE t1; -# -# INT -# -CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (2147483647, null); --- error ER_DUP_ENTRY,1062 -INSERT INTO t1 (c2) VALUES ('innodb'); -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 (c1 INT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (4294967295, null); --- error ER_DUP_ENTRY,1062 -INSERT INTO t1 (c2) VALUES ('innodb'); -SELECT * FROM t1; -DROP TABLE t1; -# -# BIGINT -# -CREATE TABLE t1 (c1 BIGINT PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (9223372036854775807, null); --- error ER_DUP_ENTRY,1062 -INSERT INTO t1 (c2) VALUES ('innodb'); -SELECT * FROM t1; -DROP TABLE t1; - -CREATE TABLE t1 (c1 BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT, c2 VARCHAR(10)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (18446744073709551615, null); --- error ER_AUTOINC_READ_FAILED,1467 -INSERT INTO t1 (c2) VALUES ('innodb'); -SELECT * FROM t1; -DROP TABLE t1; - -# -# Bug 37531 -# After truncate, auto_increment behaves incorrectly for InnoDB -# -CREATE TABLE t1(c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; -INSERT INTO t1 VALUES (1), (2), (3); -INSERT INTO t1 VALUES (NULL), (NULL), (NULL); -SELECT c1 FROM t1; -SHOW CREATE TABLE t1; -TRUNCATE TABLE t1; -SHOW CREATE TABLE t1; -INSERT INTO t1 VALUES (1), (2), (3); -INSERT INTO t1 VALUES (NULL), (NULL), (NULL); -SELECT c1 FROM t1; -SHOW CREATE TABLE t1; -DROP TABLE t1; - -# -# Deleting all records should not reset the AUTOINC counter. -# -CREATE TABLE t1(c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; -INSERT INTO t1 VALUES (1), (2), (3); -INSERT INTO t1 VALUES (NULL), (NULL), (NULL); -SELECT c1 FROM t1; -SHOW CREATE TABLE t1; -DELETE FROM t1; -SHOW CREATE TABLE t1; -INSERT INTO t1 VALUES (1), (2), (3); -INSERT INTO t1 VALUES (NULL), (NULL), (NULL); -SELECT c1 FROM t1; -SHOW CREATE TABLE t1; -DROP TABLE t1; - -# -# Bug 38839 -# Reset the last value generated at end of statement -# -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (NULL, 1); -DELETE FROM t1 WHERE c1 = 1; -INSERT INTO t1 VALUES (2,1); -INSERT INTO t1 VALUES (NULL,8); -SELECT * FROM t1; -DROP TABLE t1; -# Bug 38839 -- same as above but for multi value insert -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 INT AUTO_INCREMENT, c2 INT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (NULL, 1); -DELETE FROM t1 WHERE c1 = 1; -INSERT INTO t1 VALUES (2,1), (NULL, 8); -INSERT INTO t1 VALUES (NULL,9); -SELECT * FROM t1; -DROP TABLE t1; - -# -# Test changes to AUTOINC next value calculation -SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (NULL),(5),(NULL); -INSERT INTO t1 VALUES (250),(NULL); -SELECT * FROM t1; -INSERT INTO t1 VALUES (1000); -SET @@INSERT_ID=400; -INSERT INTO t1 VALUES(NULL),(NULL); -SELECT * FROM t1; -DROP TABLE t1; - -# Test with SIGNED INT column, by inserting a 0 for the first column value -# 0 is treated in the same was NULL. -# Reset the AUTOINC session variables -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(0); -SELECT * FROM t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -INSERT INTO t1 VALUES (-1), (NULL),(2),(NULL); -INSERT INTO t1 VALUES (250),(NULL); -SELECT * FROM t1; -SET @@INSERT_ID=400; -# Duplicate error expected here for autoinc_lock_mode != TRADITIONAL --- error ER_DUP_ENTRY,1062 -INSERT INTO t1 VALUES(NULL),(NULL); -SELECT * FROM t1; -DROP TABLE t1; - -# Test with SIGNED INT column -# Reset the AUTOINC session variables -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 INT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(-1); -SELECT * FROM t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; -INSERT INTO t1 VALUES (-2), (NULL),(2),(NULL); -INSERT INTO t1 VALUES (250),(NULL); -SELECT * FROM t1; -INSERT INTO t1 VALUES (1000); -SET @@INSERT_ID=400; -INSERT INTO t1 VALUES(NULL),(NULL); -SELECT * FROM t1; -DROP TABLE t1; - -# Test with UNSIGNED INT column, single insert -# The sign in the value is ignored and a new column value is generated -# Reset the AUTOINC session variables -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(-1); -SELECT * FROM t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; -INSERT INTO t1 VALUES (-2); -INSERT INTO t1 VALUES (NULL); -INSERT INTO t1 VALUES (2); -INSERT INTO t1 VALUES (NULL); -INSERT INTO t1 VALUES (250); -INSERT INTO t1 VALUES (NULL); -SELECT * FROM t1; -INSERT INTO t1 VALUES (1000); -SET @@INSERT_ID=400; -INSERT INTO t1 VALUES(NULL); -INSERT INTO t1 VALUES(NULL); -SELECT * FROM t1; -DROP TABLE t1; - -# Test with UNSIGNED INT column, multi-value inserts -# The sign in the value is ignored and a new column value is generated -# Reset the AUTOINC session variables -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 INT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(-1); -SELECT * FROM t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=100, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; -INSERT INTO t1 VALUES (-2),(NULL),(2),(NULL); -INSERT INTO t1 VALUES (250),(NULL); -SELECT * FROM t1; -INSERT INTO t1 VALUES (1000); -SET @@INSERT_ID=400; -# Duplicate error expected here for autoinc_lock_mode != TRADITIONAL --- error ER_DUP_ENTRY,1062 -INSERT INTO t1 VALUES(NULL),(NULL); -SELECT * FROM t1; -DROP TABLE t1; - -# -# Check for overflow handling when increment is > 1 -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -# TODO: Fix the autoinc init code -# We have to do this because of a bug in the AUTOINC init code. -INSERT INTO t1 VALUES(NULL); -INSERT INTO t1 VALUES (9223372036854775794); #-- 2^63 - 14 -SELECT * FROM t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; -# This should just fit -INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); -SELECT * FROM t1; -DROP TABLE t1; - -# -# Check for overflow handling when increment and offser are > 1 -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -# TODO: Fix the autoinc init code -# We have to do this because of a bug in the AUTOINC init code. -INSERT INTO t1 VALUES(NULL); -INSERT INTO t1 VALUES (18446744073709551603); #-- 2^64 - 13 -SELECT * FROM t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=2, @@SESSION.AUTO_INCREMENT_OFFSET=10; -SHOW VARIABLES LIKE "%auto_inc%"; -# This should fail because of overflow but it doesn't, it seems to be -# a MySQL server bug. It wraps around to 0 for the last value. -# See MySQL Bug# 39828 -# -# Instead of wrapping around, it asserts when MySQL is compiled --with-debug -# (see sql/handler.cc:handler::update_auto_increment()). Don't test for -# overflow until Bug #39828 is fixed. -# -# Since this asserts when compiled --with-debug, we can't properly test this -# until Bug #39828 is fixed. For now, this test is meaningless. -#if Bug #39828 is fixed -#INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL); -#else -INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL); -#endif -SELECT * FROM t1; -DROP TABLE t1; - -# -# Check for overflow handling when increment and offset are odd numbers -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -# TODO: Fix the autoinc init code -# We have to do this because of a bug in the AUTOINC init code. -INSERT INTO t1 VALUES(NULL); -INSERT INTO t1 VALUES (18446744073709551603); #-- 2^64 - 13 -SELECT * FROM t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=5, @@SESSION.AUTO_INCREMENT_OFFSET=7; -SHOW VARIABLES LIKE "%auto_inc%"; -# This should fail because of overflow but it doesn't. It fails with -# a duplicate entry message because of a MySQL server bug, it wraps -# around. See MySQL Bug# 39828, once MySQL fix the bug we can replace -# the ER_DUP_ENTRY, 1062 below with the appropriate error message -# -# Since this asserts when compiled --with-debug, we can't properly test this -# until Bug #39828 is fixed. For now, this test is meaningless. -#if Bug #39828 is fixed -# Still need to fix this error code, error should mention overflow -#-- error ER_DUP_ENTRY,1062 -#INSERT INTO t1 VALUES (NULL),(NULL), (NULL); -#else -INSERT INTO t1 VALUES (NULL),(NULL); -#endif -SELECT * FROM t1; -DROP TABLE t1; - -# Check for overflow handling when increment and offset are odd numbers -# and check for large -ve numbers -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 BIGINT AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -# TODO: Fix the autoinc init code -# We have to do this because of a bug in the AUTOINC init code. -INSERT INTO t1 VALUES(NULL); -INSERT INTO t1 VALUES(-9223372036854775806); #-- -2^63 + 2 -INSERT INTO t1 VALUES(-9223372036854775807); #-- -2^63 + 1 -INSERT INTO t1 VALUES(-9223372036854775808); #-- -2^63 -SELECT * FROM t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=3, @@SESSION.AUTO_INCREMENT_OFFSET=3; -SHOW VARIABLES LIKE "%auto_inc%"; -INSERT INTO t1 VALUES (NULL),(NULL), (NULL); -SELECT * FROM t1; -DROP TABLE t1; -# -# Check for overflow handling when increment and offset are very -# large numbers 2^60 -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 BIGINT UNSIGNED AUTO_INCREMENT, PRIMARY KEY(c1)) ENGINE=InnoDB; -# TODO: Fix the autoinc init code -# We have to do this because of a bug in the AUTOINC init code. -INSERT INTO t1 VALUES(NULL); -INSERT INTO t1 VALUES (18446744073709551610); #-- 2^64 - 2 -SELECT * FROM t1; -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1152921504606846976, @@SESSION.AUTO_INCREMENT_OFFSET=1152921504606846976; -SHOW VARIABLES LIKE "%auto_inc%"; -# This should fail because of overflow but it doesn't. It wraps around -# and the autoinc values look bogus too. -# See MySQL Bug# 39828, once MySQL fix the bug we can enable the error -# code expected test. -# -- error ER_AUTOINC_READ_FAILED,1467 -# -# Since this asserts when compiled --with-debug, we can't properly test this -# until Bug #39828 is fixed. For now, this test is meaningless. -#if Bug #39828 is fixed -#-- error ER_AUTOINC_READ_FAILED,1467 -#INSERT INTO t1 VALUES (NULL),(NULL); -#else -INSERT INTO t1 VALUES (NULL); -#endif -SELECT * FROM t1; -DROP TABLE t1; - -# -# Check for floating point autoinc column handling -# -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1; -SET @@INSERT_ID=1; -SHOW VARIABLES LIKE "%auto_inc%"; -CREATE TABLE t1 (c1 DOUBLE NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(NULL, 1); -INSERT INTO t1 VALUES(NULL, 2); -SELECT * FROM t1; -ALTER TABLE t1 CHANGE c1 c1 SERIAL; -SELECT * FROM t1; -INSERT INTO t1 VALUES(NULL, 3); -INSERT INTO t1 VALUES(NULL, 4); -SELECT * FROM t1; -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 FLOAT NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES(NULL, 1); -INSERT INTO t1 VALUES(NULL, 2); -SELECT * FROM t1; -ALTER TABLE t1 CHANGE c1 c1 SERIAL; -SELECT * FROM t1; -INSERT INTO t1 VALUES(NULL, 3); -INSERT INTO t1 VALUES(NULL, 4); -SELECT * FROM t1; -DROP TABLE t1; - -# -# Bug# 42714: AUTOINC column calculated next value not greater than highest -# value stored in table. -# -SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=5; -DROP TABLE IF EXISTS t1; -DROP TABLE IF EXISTS t2; -CREATE TABLE t1 ( - a INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, - b INT(10) UNSIGNED NOT NULL, - c ENUM('FALSE','TRUE') DEFAULT NULL, - PRIMARY KEY (a)) ENGINE = InnoDB; -CREATE TABLE t2 ( - m INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, - n INT(10) UNSIGNED NOT NULL, - o enum('FALSE','TRUE') DEFAULT NULL, - PRIMARY KEY (m)) ENGINE = InnoDB; -INSERT INTO t2 (n,o) VALUES - (1 , 'true'), (1 , 'false'), (2 , 'true'), (2 , 'false'), (3 , 'true'), - (3 , 'false'), (4 , 'true'), (4 , 'false'), (5 , 'true'), (5 , 'false'); -SHOW CREATE TABLE t2; -INSERT INTO t1 (b,c) SELECT n,o FROM t2 ; -SHOW CREATE TABLE t1; -INSERT INTO t1 (b,c) SELECT n,o FROM t2 ; -SELECT * FROM t1; -SHOW CREATE TABLE t1; -INSERT INTO t1 (b,c) SELECT n,o FROM t2 WHERE o = 'false'; -SELECT * FROM t1; -SHOW CREATE TABLE t1; -INSERT INTO t1 (b,c) SELECT n,o FROM t2 WHERE o = 'false'; -SELECT * FROM t1; -SHOW CREATE TABLE t1; -INSERT INTO t1 (b,c) SELECT n,o FROM t2 WHERE o = 'false'; -SHOW CREATE TABLE t1; -INSERT INTO t1 (b,c) SELECT n,o FROM t2 WHERE o = 'false'; -SHOW CREATE TABLE t1; -INSERT INTO t1 (b,c) SELECT n,o FROM t2 WHERE o = 'false'; -SELECT * FROM t1; -SHOW CREATE TABLE t1; -DROP TABLE t1; -DROP TABLE t2; -# -# 43203: Overflow from auto incrementing causes server segv -# - -DROP TABLE IF EXISTS t1; -DROP TABLE IF EXISTS t2; -CREATE TABLE t1( - c1 INT(10) UNSIGNED NOT NULL AUTO_INCREMENT - PRIMARY KEY) ENGINE=InnoDB; -INSERT INTO t1 VALUES (NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL); -CREATE TABLE t2( - c1 TINYINT(3) UNSIGNED NOT NULL AUTO_INCREMENT - PRIMARY KEY) ENGINE=InnoDB; --- error ER_DUP_ENTRY,1062 -INSERT INTO t2 SELECT c1 FROM t1; --- error ER_DUP_ENTRY,1467 -INSERT INTO t2 SELECT NULL FROM t1; -DROP TABLE t1; -DROP TABLE t2; -# -# 44030: Error: (1500) Couldn't read the MAX(ID) autoinc value from -# the index (PRIMARY) -# This test requires a restart of the server -CREATE TABLE t1 (c1 INT PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; -INSERT INTO t1 VALUES (null); -INSERT INTO t1 VALUES (null); -ALTER TABLE t1 CHANGE c1 d1 INT NOT NULL AUTO_INCREMENT; -SELECT * FROM t1; -# Restart the server --- source include/restart_mysqld.inc -# The MySQL and InnoDB data dictionaries should now be out of sync. -# The select should print message to the error log -SELECT * FROM t1; --- error ER_AUTOINC_READ_FAILED,1467 -INSERT INTO t1 VALUES(null); -ALTER TABLE t1 AUTO_INCREMENT = 3; -INSERT INTO t1 VALUES(null); -SELECT * FROM t1; -DROP TABLE t1; diff --git a/storage/innobase/mysql-test/innodb-consistent-master.opt b/storage/innobase/mysql-test/innodb-consistent-master.opt deleted file mode 100644 index 8cca44767da..00000000000 --- a/storage/innobase/mysql-test/innodb-consistent-master.opt +++ /dev/null @@ -1 +0,0 @@ ---innodb_lock_wait_timeout=2
diff --git a/storage/innobase/mysql-test/innodb-consistent.result b/storage/innobase/mysql-test/innodb-consistent.result deleted file mode 100644 index 9115791b99c..00000000000 --- a/storage/innobase/mysql-test/innodb-consistent.result +++ /dev/null @@ -1,35 +0,0 @@ -drop table if exists t1; -set session transaction isolation level read committed; -create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; -create table t2 like t1; -insert into t2 values (1),(2),(3),(4),(5),(6),(7); -set autocommit=0; -begin; -replace into t1 select * from t2; -set session transaction isolation level read committed; -set autocommit=0; -delete from t2 where a=5; -commit; -delete from t2; -commit; -commit; -begin; -insert into t1 select * from t2; -set session transaction isolation level read committed; -set autocommit=0; -delete from t2 where a=5; -commit; -delete from t2; -commit; -commit; -select * from t1; -a -1 -2 -3 -4 -5 -6 -7 -drop table t1; -drop table t2; diff --git a/storage/innobase/mysql-test/innodb-consistent.test b/storage/innobase/mysql-test/innodb-consistent.test deleted file mode 100644 index 791600fc8a7..00000000000 --- a/storage/innobase/mysql-test/innodb-consistent.test +++ /dev/null @@ -1,58 +0,0 @@ --- source include/not_embedded.inc
--- source include/have_innodb.inc
-
---disable_warnings
-drop table if exists t1;
---enable_warnings
-
-# REPLACE INTO ... SELECT and INSERT INTO ... SELECT should do
-# a consistent read of the source table.
-
-connect (a,localhost,root,,);
-connect (b,localhost,root,,);
-connection a;
-set session transaction isolation level read committed;
-create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
-create table t2 like t1;
-insert into t2 values (1),(2),(3),(4),(5),(6),(7);
-set autocommit=0;
-
-# REPLACE INTO ... SELECT case
-begin;
-# this should not result in any locks on t2.
-replace into t1 select * from t2;
-
-connection b;
-set session transaction isolation level read committed;
-set autocommit=0;
-# should not cuase a lock wait.
-delete from t2 where a=5;
-commit;
-delete from t2;
-commit;
-connection a;
-commit;
-
-# INSERT INTO ... SELECT case
-begin;
-# this should not result in any locks on t2.
-insert into t1 select * from t2;
-
-connection b;
-set session transaction isolation level read committed;
-set autocommit=0;
-# should not cuase a lock wait.
-delete from t2 where a=5;
-commit;
-delete from t2;
-commit;
-connection a;
-commit;
-
-select * from t1;
-drop table t1;
-drop table t2;
-
-connection default;
-disconnect a;
-disconnect b;
diff --git a/storage/innobase/mysql-test/innodb-index.result b/storage/innobase/mysql-test/innodb-index.result deleted file mode 100644 index a7d66b15300..00000000000 --- a/storage/innobase/mysql-test/innodb-index.result +++ /dev/null @@ -1,1170 +0,0 @@ -create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb; -insert into t1 values (5,5,'oo','oo'),(4,4,'tr','tr'),(3,4,'ad','ad'),(2,3,'ak','ak'); -commit; -alter table t1 add index b (b), add index b (b); -ERROR 42000: Duplicate key name 'b' -alter table t1 add index (b,b); -ERROR 42S21: Duplicate column name 'b' -alter table t1 add index d2 (d); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) NOT NULL, - `d` varchar(20) DEFAULT NULL, - KEY `d2` (`d`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -explain select * from t1 force index(d2) order by d; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL d2 23 NULL 4 -select * from t1 force index (d2) order by d; -a b c d -3 4 ad ad -2 3 ak ak -5 5 oo oo -4 4 tr tr -alter table t1 add unique index (b); -ERROR 23000: Duplicate entry '4' for key 'b' -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) NOT NULL, - `d` varchar(20) DEFAULT NULL, - KEY `d2` (`d`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -alter table t1 add index (b); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) NOT NULL, - `d` varchar(20) DEFAULT NULL, - KEY `d2` (`d`), - KEY `b` (`b`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -CREATE TABLE `t1#1`(a INT PRIMARY KEY) ENGINE=InnoDB; -alter table t1 add unique index (c), add index (d); -ERROR HY000: Table 'test.t1#1' already exists -rename table `t1#1` to `t1#2`; -alter table t1 add unique index (c), add index (d); -ERROR HY000: Table 'test.t1#2' already exists -drop table `t1#2`; -alter table t1 add unique index (c), add index (d); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) NOT NULL, - `d` varchar(20) DEFAULT NULL, - UNIQUE KEY `c` (`c`), - KEY `d2` (`d`), - KEY `b` (`b`), - KEY `d` (`d`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -explain select * from t1 force index(c) order by c; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL c 10 NULL 4 -alter table t1 add primary key (a), drop index c; -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) NOT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - KEY `d2` (`d`), - KEY `b` (`b`), - KEY `d` (`d`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -alter table t1 add primary key (c); -ERROR 42000: Multiple primary key defined -alter table t1 drop primary key, add primary key (b); -ERROR 23000: Duplicate entry '4' for key 'PRIMARY' -create unique index c on t1 (c); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) NOT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `c` (`c`), - KEY `d2` (`d`), - KEY `b` (`b`), - KEY `d` (`d`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -explain select * from t1 force index(c) order by c; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL c 10 NULL 4 -select * from t1 force index(c) order by c; -a b c d -3 4 ad ad -2 3 ak ak -5 5 oo oo -4 4 tr tr -alter table t1 drop index b, add index (b); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) NOT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `c` (`c`), - KEY `d2` (`d`), - KEY `d` (`d`), - KEY `b` (`b`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -insert into t1 values(6,1,'ggg','ggg'); -select * from t1; -a b c d -2 3 ak ak -3 4 ad ad -4 4 tr tr -5 5 oo oo -6 1 ggg ggg -select * from t1 force index(b) order by b; -a b c d -6 1 ggg ggg -2 3 ak ak -3 4 ad ad -4 4 tr tr -5 5 oo oo -select * from t1 force index(c) order by c; -a b c d -3 4 ad ad -2 3 ak ak -6 1 ggg ggg -5 5 oo oo -4 4 tr tr -select * from t1 force index(d) order by d; -a b c d -3 4 ad ad -2 3 ak ak -6 1 ggg ggg -5 5 oo oo -4 4 tr tr -explain select * from t1 force index(b) order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 5 NULL 5 -explain select * from t1 force index(c) order by c; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL c 10 NULL 5 -explain select * from t1 force index(d) order by d; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL d 23 NULL 5 -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) NOT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `c` (`c`), - KEY `d2` (`d`), - KEY `d` (`d`), - KEY `b` (`b`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1; -create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb; -insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ad','ad'),(4,4,'afe','afe'); -commit; -alter table t1 add index (c(2)); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - KEY `c` (`c`(2)) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -alter table t1 add unique index (d(10)); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `d` (`d`(10)), - KEY `c` (`c`(2)) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -insert into t1 values(5,1,'ggg','ggg'); -select * from t1; -a b c d -1 1 ab ab -2 2 ac ac -3 3 ad ad -4 4 afe afe -5 1 ggg ggg -select * from t1 force index(c) order by c; -a b c d -1 1 ab ab -2 2 ac ac -3 3 ad ad -4 4 afe afe -5 1 ggg ggg -select * from t1 force index(d) order by d; -a b c d -1 1 ab ab -2 2 ac ac -3 3 ad ad -4 4 afe afe -5 1 ggg ggg -explain select * from t1 order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort -explain select * from t1 force index(c) order by c; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort -explain select * from t1 force index(d) order by d; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 5 Using filesort -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `d` (`d`(10)), - KEY `c` (`c`(2)) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -alter table t1 drop index d; -insert into t1 values(8,9,'fff','fff'); -select * from t1; -a b c d -1 1 ab ab -2 2 ac ac -3 3 ad ad -4 4 afe afe -5 1 ggg ggg -8 9 fff fff -select * from t1 force index(c) order by c; -a b c d -1 1 ab ab -2 2 ac ac -3 3 ad ad -4 4 afe afe -8 9 fff fff -5 1 ggg ggg -explain select * from t1 order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort -explain select * from t1 force index(c) order by c; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort -explain select * from t1 order by d; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 6 Using filesort -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - KEY `c` (`c`(2)) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1; -create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb; -insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe'); -commit; -alter table t1 add unique index (b,c); -insert into t1 values(8,9,'fff','fff'); -select * from t1; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -select * from t1 force index(b) order by b; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -explain select * from t1 force index(b) order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 16 NULL 5 -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `b` (`b`,`c`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -alter table t1 add index (b,c); -insert into t1 values(11,11,'kkk','kkk'); -select * from t1; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -11 11 kkk kkk -select * from t1 force index(b) order by b; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -11 11 kkk kkk -explain select * from t1 force index(b) order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 16 NULL 6 -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `b` (`b`,`c`), - KEY `b_2` (`b`,`c`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -alter table t1 add unique index (c,d); -insert into t1 values(13,13,'yyy','aaa'); -select * from t1; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -11 11 kkk kkk -13 13 yyy aaa -select * from t1 force index(b) order by b; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -11 11 kkk kkk -13 13 yyy aaa -select * from t1 force index(c) order by c; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -11 11 kkk kkk -13 13 yyy aaa -explain select * from t1 force index(b) order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 16 NULL 7 -explain select * from t1 force index(c) order by c; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL c 34 NULL 7 -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `b` (`b`,`c`), - UNIQUE KEY `c` (`c`,`d`), - KEY `b_2` (`b`,`c`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1; -create table t1(a int not null, b int not null, c int, primary key (a), key (b)) engine = innodb; -create table t3(a int not null, c int not null, d int, primary key (a), key (c)) engine = innodb; -create table t4(a int not null, d int not null, e int, primary key (a), key (d)) engine = innodb; -create table t2(a int not null, b int not null, c int not null, d int not null, e int, -foreign key (b) references t1(b) on delete cascade, -foreign key (c) references t3(c), foreign key (d) references t4(d)) -engine = innodb; -alter table t1 drop index b; -ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint -alter table t3 drop index c; -ERROR HY000: Cannot drop index 'c': needed in a foreign key constraint -alter table t4 drop index d; -ERROR HY000: Cannot drop index 'd': needed in a foreign key constraint -alter table t2 drop index b; -ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint -alter table t2 drop index b, drop index c, drop index d; -ERROR HY000: Cannot drop index 'b': needed in a foreign key constraint -create unique index dc on t2 (d,c); -create index dc on t1 (b,c); -alter table t2 add primary key (a); -insert into t1 values (1,1,1); -insert into t3 values (1,1,1); -insert into t4 values (1,1,1); -insert into t2 values (1,1,1,1,1); -commit; -alter table t4 add constraint dc foreign key (a) references t1(a); -show create table t4; -Table Create Table -t4 CREATE TABLE `t4` ( - `a` int(11) NOT NULL, - `d` int(11) NOT NULL, - `e` int(11) DEFAULT NULL, - PRIMARY KEY (`a`), - KEY `d` (`d`), - CONSTRAINT `dc` FOREIGN KEY (`a`) REFERENCES `t1` (`a`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -alter table t3 add constraint dc foreign key (a) references t1(a); -ERROR HY000: Can't create table '#sql-temporary' (errno: 121) -show create table t3; -Table Create Table -t3 CREATE TABLE `t3` ( - `a` int(11) NOT NULL, - `c` int(11) NOT NULL, - `d` int(11) DEFAULT NULL, - PRIMARY KEY (`a`), - KEY `c` (`c`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -alter table t2 drop index b, add index (b); -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `a` int(11) NOT NULL, - `b` int(11) NOT NULL, - `c` int(11) NOT NULL, - `d` int(11) NOT NULL, - `e` int(11) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `dc` (`d`,`c`), - KEY `c` (`c`), - KEY `b` (`b`), - CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`b`) ON DELETE CASCADE, - CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`c`) REFERENCES `t3` (`c`), - CONSTRAINT `t2_ibfk_3` FOREIGN KEY (`d`) REFERENCES `t4` (`d`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -delete from t1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `dc` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) -drop index dc on t4; -ERROR 42000: Can't DROP 'dc'; check that column/key exists -alter table t3 drop foreign key dc; -ERROR HY000: Error on rename of './test/t3' to '#sql2-temporary' (errno: 152) -alter table t4 drop foreign key dc; -select * from t2; -a b c d e -1 1 1 1 1 -delete from t1; -select * from t2; -a b c d e -drop table t2,t4,t3,t1; -create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb default charset=utf8; -insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe'); -commit; -alter table t1 add unique index (b); -ERROR 23000: Duplicate entry '2' for key 'b' -insert into t1 values(8,9,'fff','fff'); -select * from t1; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 -alter table t1 add index (b); -insert into t1 values(10,10,'kkk','iii'); -select * from t1; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -10 10 kkk iii -select * from t1 force index(b) order by b; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -10 10 kkk iii -explain select * from t1 force index(b) order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 5 NULL 6 -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - KEY `b` (`b`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 -alter table t1 add unique index (c), add index (d); -insert into t1 values(11,11,'aaa','mmm'); -select * from t1; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -10 10 kkk iii -11 11 aaa mmm -select * from t1 force index(b) order by b; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -10 10 kkk iii -11 11 aaa mmm -select * from t1 force index(c) order by c; -a b c d -11 11 aaa mmm -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -10 10 kkk iii -select * from t1 force index(d) order by d; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -10 10 kkk iii -11 11 aaa mmm -explain select * from t1 force index(b) order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 5 NULL 7 -explain select * from t1 force index(c) order by c; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL c 31 NULL 7 -explain select * from t1 force index(d) order by d; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL d 63 NULL 7 -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `c` (`c`), - KEY `b` (`b`), - KEY `d` (`d`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 -check table t1; -Table Op Msg_type Msg_text -test.t1 check status OK -drop table t1; -create table t1(a int not null, b int) engine = innodb; -insert into t1 values (1,1),(1,1),(1,1),(1,1); -alter table t1 add unique index (a); -ERROR 23000: Duplicate entry '1' for key 'a' -alter table t1 add unique index (b); -ERROR 23000: Duplicate entry '1' for key 'b' -alter table t1 add unique index (a), add unique index(b); -ERROR 23000: Duplicate entry '1' for key 'a' -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1; -create table t1(a int not null, c int not null,b int, primary key(a), unique key(c), key(b)) engine = innodb; -alter table t1 drop index c, drop index b; -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `c` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - PRIMARY KEY (`a`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1; -create table t1(a int not null, b int, primary key(a)) engine = innodb; -alter table t1 add index (b); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - PRIMARY KEY (`a`), - KEY `b` (`b`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1; -create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb; -insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ac','ac'),(4,4,'afe','afe'),(5,4,'affe','affe'); -alter table t1 add unique index (b), add unique index (c), add unique index (d); -ERROR 23000: Duplicate entry '4' for key 'b' -alter table t1 add unique index (c), add unique index (b), add index (d); -ERROR 23000: Duplicate entry 'ac' for key 'c' -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1; -create table t1(a int not null, b int not null, c int, primary key (a), key(c)) engine=innodb; -insert into t1 values (5,1,5),(4,2,4),(3,3,3),(2,4,2),(1,5,1); -alter table t1 add unique index (b); -insert into t1 values (10,20,20),(11,19,19),(12,18,18),(13,17,17); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) NOT NULL, - `c` int(11) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `b` (`b`), - KEY `c` (`c`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -check table t1; -Table Op Msg_type Msg_text -test.t1 check status OK -explain select * from t1 force index(c) order by c; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL c 5 NULL 9 -explain select * from t1 order by a; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 4 NULL 9 -explain select * from t1 force index(b) order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 4 NULL 9 -select * from t1 order by a; -a b c -1 5 1 -2 4 2 -3 3 3 -4 2 4 -5 1 5 -10 20 20 -11 19 19 -12 18 18 -13 17 17 -select * from t1 force index(b) order by b; -a b c -5 1 5 -4 2 4 -3 3 3 -2 4 2 -1 5 1 -13 17 17 -12 18 18 -11 19 19 -10 20 20 -select * from t1 force index(c) order by c; -a b c -1 5 1 -2 4 2 -3 3 3 -4 2 4 -5 1 5 -13 17 17 -12 18 18 -11 19 19 -10 20 20 -drop table t1; -create table t1(a int not null, b int not null) engine=innodb; -insert into t1 values (1,1); -alter table t1 add primary key(b); -insert into t1 values (2,2); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) NOT NULL, - PRIMARY KEY (`b`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -check table t1; -Table Op Msg_type Msg_text -test.t1 check status OK -select * from t1; -a b -1 1 -2 2 -explain select * from t1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 2 -explain select * from t1 order by a; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 2 Using filesort -explain select * from t1 order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 -checksum table t1; -Table Checksum -test.t1 582702641 -drop table t1; -create table t1(a int not null) engine=innodb; -insert into t1 values (1); -alter table t1 add primary key(a); -insert into t1 values (2); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - PRIMARY KEY (`a`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -check table t1; -Table Op Msg_type Msg_text -test.t1 check status OK -commit; -select * from t1; -a -1 -2 -explain select * from t1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index -explain select * from t1 order by a; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 4 NULL 2 Using index -drop table t1; -create table t2(d varchar(17) primary key) engine=innodb default charset=utf8; -create table t3(a int primary key) engine=innodb; -insert into t3 values(22),(44),(33),(55),(66); -insert into t2 values ('jejdkrun87'),('adfd72nh9k'), -('adfdpplkeock'),('adfdijnmnb78k'),('adfdijn0loKNHJik'); -create table t1(a int, b blob, c text, d text not null) -engine=innodb default charset = utf8; -insert into t1 -select a,left(repeat(d,100*a),65535),repeat(d,20*a),d from t2,t3; -drop table t2, t3; -select count(*) from t1 where a=44; -count(*) -5 -select a, -length(b),b=left(repeat(d,100*a),65535),length(c),c=repeat(d,20*a),d from t1; -a length(b) b=left(repeat(d,100*a),65535) length(c) c=repeat(d,20*a) d -22 22000 1 4400 1 adfd72nh9k -22 35200 1 7040 1 adfdijn0loKNHJik -22 28600 1 5720 1 adfdijnmnb78k -22 26400 1 5280 1 adfdpplkeock -22 22000 1 4400 1 jejdkrun87 -33 33000 1 6600 1 adfd72nh9k -33 52800 1 10560 1 adfdijn0loKNHJik -33 42900 1 8580 1 adfdijnmnb78k -33 39600 1 7920 1 adfdpplkeock -33 33000 1 6600 1 jejdkrun87 -44 44000 1 8800 1 adfd72nh9k -44 65535 1 14080 1 adfdijn0loKNHJik -44 57200 1 11440 1 adfdijnmnb78k -44 52800 1 10560 1 adfdpplkeock -44 44000 1 8800 1 jejdkrun87 -55 55000 1 11000 1 adfd72nh9k -55 65535 1 17600 1 adfdijn0loKNHJik -55 65535 1 14300 1 adfdijnmnb78k -55 65535 1 13200 1 adfdpplkeock -55 55000 1 11000 1 jejdkrun87 -66 65535 1 13200 1 adfd72nh9k -66 65535 1 21120 1 adfdijn0loKNHJik -66 65535 1 17160 1 adfdijnmnb78k -66 65535 1 15840 1 adfdpplkeock -66 65535 1 13200 1 jejdkrun87 -alter table t1 add primary key (a), add key (b(20)); -ERROR 23000: Duplicate entry '22' for key 'PRIMARY' -delete from t1 where a%2; -check table t1; -Table Op Msg_type Msg_text -test.t1 check status OK -alter table t1 add primary key (a,b(255),c(255)), add key (b(767)); -select count(*) from t1 where a=44; -count(*) -5 -select a, -length(b),b=left(repeat(d,100*a),65535),length(c),c=repeat(d,20*a),d from t1; -a length(b) b=left(repeat(d,100*a),65535) length(c) c=repeat(d,20*a) d -22 22000 1 4400 1 adfd72nh9k -22 35200 1 7040 1 adfdijn0loKNHJik -22 28600 1 5720 1 adfdijnmnb78k -22 26400 1 5280 1 adfdpplkeock -22 22000 1 4400 1 jejdkrun87 -44 44000 1 8800 1 adfd72nh9k -44 65535 1 14080 1 adfdijn0loKNHJik -44 57200 1 11440 1 adfdijnmnb78k -44 52800 1 10560 1 adfdpplkeock -44 44000 1 8800 1 jejdkrun87 -66 65535 1 13200 1 adfd72nh9k -66 65535 1 21120 1 adfdijn0loKNHJik -66 65535 1 17160 1 adfdijnmnb78k -66 65535 1 15840 1 adfdpplkeock -66 65535 1 13200 1 jejdkrun87 -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL DEFAULT '0', - `b` blob NOT NULL, - `c` text NOT NULL, - `d` text NOT NULL, - PRIMARY KEY (`a`,`b`(255),`c`(255)), - KEY `b` (`b`(767)) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 -check table t1; -Table Op Msg_type Msg_text -test.t1 check status OK -explain select * from t1 where b like 'adfd%'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL b NULL NULL NULL 15 Using where -create table t2(a int, b varchar(255), primary key(a,b)) engine=innodb; -insert into t2 select a,left(b,255) from t1; -drop table t1; -rename table t2 to t1; -set innodb_lock_wait_timeout=1; -begin; -select a from t1 limit 1 for update; -a -22 -set innodb_lock_wait_timeout=1; -create index t1ba on t1 (b,a); -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -commit; -begin; -select a from t1 limit 1 lock in share mode; -a -22 -create index t1ba on t1 (b,a); -drop index t1ba on t1; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -commit; -explain select a from t1 order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL t1ba 261 NULL 15 Using index -select a,sleep(2+a/100) from t1 order by b limit 3; -select sleep(1); -sleep(1) -0 -drop index t1ba on t1; -a sleep(2+a/100) -22 0 -44 0 -66 0 -explain select a from t1 order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 261 NULL 15 Using index; Using filesort -select a from t1 order by b limit 3; -a -22 -66 -44 -commit; -drop table t1; -set global innodb_file_per_table=on; -set global innodb_file_format='Barracuda'; -create table t1(a blob,b blob,c blob,d blob,e blob,f blob,g blob,h blob, -i blob,j blob,k blob,l blob,m blob,n blob,o blob,p blob, -q blob,r blob,s blob,t blob,u blob) -engine=innodb row_format=dynamic; -create index t1a on t1 (a(1)); -create index t1b on t1 (b(1)); -create index t1c on t1 (c(1)); -create index t1d on t1 (d(1)); -create index t1e on t1 (e(1)); -create index t1f on t1 (f(1)); -create index t1g on t1 (g(1)); -create index t1h on t1 (h(1)); -create index t1i on t1 (i(1)); -create index t1j on t1 (j(1)); -create index t1k on t1 (k(1)); -create index t1l on t1 (l(1)); -create index t1m on t1 (m(1)); -create index t1n on t1 (n(1)); -create index t1o on t1 (o(1)); -create index t1p on t1 (p(1)); -create index t1q on t1 (q(1)); -create index t1r on t1 (r(1)); -create index t1s on t1 (s(1)); -create index t1t on t1 (t(1)); -create index t1u on t1 (u(1)); -ERROR HY000: Too big row -create index t1ut on t1 (u(1), t(1)); -ERROR HY000: Too big row -create index t1st on t1 (s(1), t(1)); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` blob, - `b` blob, - `c` blob, - `d` blob, - `e` blob, - `f` blob, - `g` blob, - `h` blob, - `i` blob, - `j` blob, - `k` blob, - `l` blob, - `m` blob, - `n` blob, - `o` blob, - `p` blob, - `q` blob, - `r` blob, - `s` blob, - `t` blob, - `u` blob, - KEY `t1a` (`a`(1)), - KEY `t1b` (`b`(1)), - KEY `t1c` (`c`(1)), - KEY `t1d` (`d`(1)), - KEY `t1e` (`e`(1)), - KEY `t1f` (`f`(1)), - KEY `t1g` (`g`(1)), - KEY `t1h` (`h`(1)), - KEY `t1i` (`i`(1)), - KEY `t1j` (`j`(1)), - KEY `t1k` (`k`(1)), - KEY `t1l` (`l`(1)), - KEY `t1m` (`m`(1)), - KEY `t1n` (`n`(1)), - KEY `t1o` (`o`(1)), - KEY `t1p` (`p`(1)), - KEY `t1q` (`q`(1)), - KEY `t1r` (`r`(1)), - KEY `t1s` (`s`(1)), - KEY `t1t` (`t`(1)), - KEY `t1st` (`s`(1),`t`(1)) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC -create index t1u on t1 (u(1)); -ERROR HY000: Too big row -alter table t1 row_format=compact; -create index t1u on t1 (u(1)); -drop table t1; -set global innodb_file_per_table=0; -set global innodb_file_format=Antelope; -SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0; -SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; -CREATE TABLE t1( -c1 BIGINT(12) NOT NULL, -PRIMARY KEY (c1) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; -CREATE TABLE t2( -c1 BIGINT(16) NOT NULL, -c2 BIGINT(12) NOT NULL, -c3 BIGINT(12) NOT NULL, -PRIMARY KEY (c1) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca -FOREIGN KEY (c3) REFERENCES t1(c1); -SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; -SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS; -SHOW CREATE TABLE t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `c1` bigint(16) NOT NULL, - `c2` bigint(12) NOT NULL, - `c3` bigint(12) NOT NULL, - PRIMARY KEY (`c1`), - KEY `fk_t2_ca` (`c3`), - CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -CREATE INDEX i_t2_c3_c2 ON t2(c3, c2); -SHOW CREATE TABLE t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `c1` bigint(16) NOT NULL, - `c2` bigint(12) NOT NULL, - `c3` bigint(12) NOT NULL, - PRIMARY KEY (`c1`), - KEY `i_t2_c3_c2` (`c3`,`c2`), - CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; -SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS; -INSERT INTO t2 VALUES(0,0,0); -ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`)) -INSERT INTO t1 VALUES(0); -INSERT INTO t2 VALUES(0,0,0); -DROP TABLE t2; -CREATE TABLE t2( -c1 BIGINT(16) NOT NULL, -c2 BIGINT(12) NOT NULL, -c3 BIGINT(12) NOT NULL, -PRIMARY KEY (c1,c2,c3) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca -FOREIGN KEY (c3) REFERENCES t1(c1); -SHOW CREATE TABLE t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `c1` bigint(16) NOT NULL, - `c2` bigint(12) NOT NULL, - `c3` bigint(12) NOT NULL, - PRIMARY KEY (`c1`,`c2`,`c3`), - KEY `fk_t2_ca` (`c3`), - CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -CREATE INDEX i_t2_c3_c2 ON t2(c3, c2); -SHOW CREATE TABLE t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `c1` bigint(16) NOT NULL, - `c2` bigint(12) NOT NULL, - `c3` bigint(12) NOT NULL, - PRIMARY KEY (`c1`,`c2`,`c3`), - KEY `i_t2_c3_c2` (`c3`,`c2`), - CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -INSERT INTO t2 VALUES(0,0,1); -ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`)) -INSERT INTO t2 VALUES(0,0,0); -DELETE FROM t1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`) REFERENCES `t1` (`c1`)) -DELETE FROM t2; -DROP TABLE t2; -DROP TABLE t1; -CREATE TABLE t1( -c1 BIGINT(12) NOT NULL, -c2 INT(4) NOT NULL, -PRIMARY KEY (c2,c1) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; -CREATE TABLE t2( -c1 BIGINT(16) NOT NULL, -c2 BIGINT(12) NOT NULL, -c3 BIGINT(12) NOT NULL, -PRIMARY KEY (c1) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca -FOREIGN KEY (c3,c2) REFERENCES t1(c1,c1); -ERROR HY000: Can't create table '#sql-temporary' (errno: 150) -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca -FOREIGN KEY (c3,c2) REFERENCES t1(c1,c2); -ERROR HY000: Can't create table '#sql-temporary' (errno: 150) -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca -FOREIGN KEY (c3,c2) REFERENCES t1(c2,c1); -ERROR HY000: Can't create table '#sql-temporary' (errno: 150) -ALTER TABLE t1 MODIFY COLUMN c2 BIGINT(12) NOT NULL; -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca -FOREIGN KEY (c3,c2) REFERENCES t1(c1,c2); -ERROR HY000: Can't create table '#sql-temporary' (errno: 150) -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca -FOREIGN KEY (c3,c2) REFERENCES t1(c2,c1); -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` bigint(12) NOT NULL, - `c2` bigint(12) NOT NULL, - PRIMARY KEY (`c2`,`c1`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -SHOW CREATE TABLE t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `c1` bigint(16) NOT NULL, - `c2` bigint(12) NOT NULL, - `c3` bigint(12) NOT NULL, - PRIMARY KEY (`c1`), - KEY `fk_t2_ca` (`c3`,`c2`), - CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`, `c2`) REFERENCES `t1` (`c2`, `c1`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -CREATE INDEX i_t2_c2_c1 ON t2(c2, c1); -SHOW CREATE TABLE t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `c1` bigint(16) NOT NULL, - `c2` bigint(12) NOT NULL, - `c3` bigint(12) NOT NULL, - PRIMARY KEY (`c1`), - KEY `fk_t2_ca` (`c3`,`c2`), - KEY `i_t2_c2_c1` (`c2`,`c1`), - CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`, `c2`) REFERENCES `t1` (`c2`, `c1`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -CREATE INDEX i_t2_c3_c1_c2 ON t2(c3, c1, c2); -SHOW CREATE TABLE t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `c1` bigint(16) NOT NULL, - `c2` bigint(12) NOT NULL, - `c3` bigint(12) NOT NULL, - PRIMARY KEY (`c1`), - KEY `fk_t2_ca` (`c3`,`c2`), - KEY `i_t2_c2_c1` (`c2`,`c1`), - KEY `i_t2_c3_c1_c2` (`c3`,`c1`,`c2`), - CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`, `c2`) REFERENCES `t1` (`c2`, `c1`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -CREATE INDEX i_t2_c3_c2 ON t2(c3, c2); -SHOW CREATE TABLE t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `c1` bigint(16) NOT NULL, - `c2` bigint(12) NOT NULL, - `c3` bigint(12) NOT NULL, - PRIMARY KEY (`c1`), - KEY `i_t2_c2_c1` (`c2`,`c1`), - KEY `i_t2_c3_c1_c2` (`c3`,`c1`,`c2`), - KEY `i_t2_c3_c2` (`c3`,`c2`), - CONSTRAINT `fk_t2_ca` FOREIGN KEY (`c3`, `c2`) REFERENCES `t1` (`c2`, `c1`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -DROP TABLE t2; -DROP TABLE t1; -CREATE TABLE t1 (a INT, b CHAR(1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (3,'a'),(3,'b'),(1,'c'),(0,'d'),(1,'e'); -BEGIN; -SELECT * FROM t1; -a b -3 a -3 b -1 c -0 d -1 e -CREATE INDEX t1a ON t1(a); -SELECT * FROM t1; -a b -3 a -3 b -1 c -0 d -1 e -SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a; -ERROR HY000: Table definition has changed, please retry transaction -SELECT * FROM t1; -a b -3 a -3 b -1 c -0 d -1 e -COMMIT; -SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a; -a b -0 d -1 c -1 e -3 a -3 b -DROP TABLE t1; diff --git a/storage/innobase/mysql-test/innodb-index.test b/storage/innobase/mysql-test/innodb-index.test deleted file mode 100644 index 42888ff3686..00000000000 --- a/storage/innobase/mysql-test/innodb-index.test +++ /dev/null @@ -1,534 +0,0 @@ --- source include/have_innodb.inc - -create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb; -insert into t1 values (5,5,'oo','oo'),(4,4,'tr','tr'),(3,4,'ad','ad'),(2,3,'ak','ak'); -commit; ---error ER_DUP_KEYNAME -alter table t1 add index b (b), add index b (b); ---error ER_DUP_FIELDNAME -alter table t1 add index (b,b); -alter table t1 add index d2 (d); -show create table t1; -explain select * from t1 force index(d2) order by d; -select * from t1 force index (d2) order by d; ---error ER_DUP_ENTRY -alter table t1 add unique index (b); -show create table t1; -alter table t1 add index (b); -show create table t1; - -# Check how existing tables interfere with temporary tables. -CREATE TABLE `t1#1`(a INT PRIMARY KEY) ENGINE=InnoDB; - ---error 156 -alter table t1 add unique index (c), add index (d); -rename table `t1#1` to `t1#2`; ---error 156 -alter table t1 add unique index (c), add index (d); -drop table `t1#2`; - -alter table t1 add unique index (c), add index (d); -show create table t1; -explain select * from t1 force index(c) order by c; -alter table t1 add primary key (a), drop index c; -show create table t1; ---error ER_MULTIPLE_PRI_KEY -alter table t1 add primary key (c); ---error ER_DUP_ENTRY -alter table t1 drop primary key, add primary key (b); -create unique index c on t1 (c); -show create table t1; -explain select * from t1 force index(c) order by c; -select * from t1 force index(c) order by c; -alter table t1 drop index b, add index (b); -show create table t1; -insert into t1 values(6,1,'ggg','ggg'); -select * from t1; -select * from t1 force index(b) order by b; -select * from t1 force index(c) order by c; -select * from t1 force index(d) order by d; -explain select * from t1 force index(b) order by b; -explain select * from t1 force index(c) order by c; -explain select * from t1 force index(d) order by d; -show create table t1; -drop table t1; - -create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb; -insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ad','ad'),(4,4,'afe','afe'); -commit; -alter table t1 add index (c(2)); -show create table t1; -alter table t1 add unique index (d(10)); -show create table t1; -insert into t1 values(5,1,'ggg','ggg'); -select * from t1; -select * from t1 force index(c) order by c; -select * from t1 force index(d) order by d; -explain select * from t1 order by b; -explain select * from t1 force index(c) order by c; -explain select * from t1 force index(d) order by d; -show create table t1; -alter table t1 drop index d; -insert into t1 values(8,9,'fff','fff'); -select * from t1; -select * from t1 force index(c) order by c; -explain select * from t1 order by b; -explain select * from t1 force index(c) order by c; -explain select * from t1 order by d; -show create table t1; -drop table t1; - -create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb; -insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe'); -commit; -alter table t1 add unique index (b,c); -insert into t1 values(8,9,'fff','fff'); -select * from t1; -select * from t1 force index(b) order by b; -explain select * from t1 force index(b) order by b; -show create table t1; -alter table t1 add index (b,c); -insert into t1 values(11,11,'kkk','kkk'); -select * from t1; -select * from t1 force index(b) order by b; -explain select * from t1 force index(b) order by b; -show create table t1; -alter table t1 add unique index (c,d); -insert into t1 values(13,13,'yyy','aaa'); -select * from t1; -select * from t1 force index(b) order by b; -select * from t1 force index(c) order by c; -explain select * from t1 force index(b) order by b; -explain select * from t1 force index(c) order by c; -show create table t1; -drop table t1; - -create table t1(a int not null, b int not null, c int, primary key (a), key (b)) engine = innodb; -create table t3(a int not null, c int not null, d int, primary key (a), key (c)) engine = innodb; -create table t4(a int not null, d int not null, e int, primary key (a), key (d)) engine = innodb; -create table t2(a int not null, b int not null, c int not null, d int not null, e int, -foreign key (b) references t1(b) on delete cascade, -foreign key (c) references t3(c), foreign key (d) references t4(d)) -engine = innodb; ---error ER_DROP_INDEX_FK -alter table t1 drop index b; ---error ER_DROP_INDEX_FK -alter table t3 drop index c; ---error ER_DROP_INDEX_FK -alter table t4 drop index d; ---error ER_DROP_INDEX_FK -alter table t2 drop index b; ---error ER_DROP_INDEX_FK -alter table t2 drop index b, drop index c, drop index d; -# Apparently, the following makes mysql_alter_table() drop index d. -create unique index dc on t2 (d,c); -create index dc on t1 (b,c); -# This should preserve the foreign key constraints. -alter table t2 add primary key (a); -insert into t1 values (1,1,1); -insert into t3 values (1,1,1); -insert into t4 values (1,1,1); -insert into t2 values (1,1,1,1,1); -commit; -alter table t4 add constraint dc foreign key (a) references t1(a); -show create table t4; ---replace_regex /'test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ -# a foreign key 'test/dc' already exists ---error ER_CANT_CREATE_TABLE -alter table t3 add constraint dc foreign key (a) references t1(a); -show create table t3; -alter table t2 drop index b, add index (b); -show create table t2; ---error ER_ROW_IS_REFERENCED_2 -delete from t1; ---error ER_CANT_DROP_FIELD_OR_KEY -drop index dc on t4; -# there is no foreign key dc on t3 ---replace_regex /'\.\/test\/#sql2-[0-9a-f-]*'/'#sql2-temporary'/ ---error ER_ERROR_ON_RENAME -alter table t3 drop foreign key dc; -alter table t4 drop foreign key dc; -select * from t2; -delete from t1; -select * from t2; - -drop table t2,t4,t3,t1; - --- let charset = utf8 --- source include/innodb-index.inc - -create table t1(a int not null, b int) engine = innodb; -insert into t1 values (1,1),(1,1),(1,1),(1,1); ---error ER_DUP_ENTRY -alter table t1 add unique index (a); ---error ER_DUP_ENTRY -alter table t1 add unique index (b); ---error ER_DUP_ENTRY -alter table t1 add unique index (a), add unique index(b); -show create table t1; -drop table t1; - -create table t1(a int not null, c int not null,b int, primary key(a), unique key(c), key(b)) engine = innodb; -alter table t1 drop index c, drop index b; -show create table t1; -drop table t1; - -create table t1(a int not null, b int, primary key(a)) engine = innodb; -alter table t1 add index (b); -show create table t1; -drop table t1; - -create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb; -insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ac','ac'),(4,4,'afe','afe'),(5,4,'affe','affe'); ---error ER_DUP_ENTRY -alter table t1 add unique index (b), add unique index (c), add unique index (d); ---error ER_DUP_ENTRY -alter table t1 add unique index (c), add unique index (b), add index (d); -show create table t1; -drop table t1; - -create table t1(a int not null, b int not null, c int, primary key (a), key(c)) engine=innodb; -insert into t1 values (5,1,5),(4,2,4),(3,3,3),(2,4,2),(1,5,1); -alter table t1 add unique index (b); -insert into t1 values (10,20,20),(11,19,19),(12,18,18),(13,17,17); -show create table t1; -check table t1; -explain select * from t1 force index(c) order by c; -explain select * from t1 order by a; -explain select * from t1 force index(b) order by b; -select * from t1 order by a; -select * from t1 force index(b) order by b; -select * from t1 force index(c) order by c; -drop table t1; - -create table t1(a int not null, b int not null) engine=innodb; -insert into t1 values (1,1); -alter table t1 add primary key(b); -insert into t1 values (2,2); -show create table t1; -check table t1; -select * from t1; -explain select * from t1; -explain select * from t1 order by a; -explain select * from t1 order by b; -checksum table t1; -drop table t1; - -create table t1(a int not null) engine=innodb; -insert into t1 values (1); -alter table t1 add primary key(a); -insert into t1 values (2); -show create table t1; -check table t1; -commit; -select * from t1; -explain select * from t1; -explain select * from t1 order by a; -drop table t1; - -create table t2(d varchar(17) primary key) engine=innodb default charset=utf8; -create table t3(a int primary key) engine=innodb; - -insert into t3 values(22),(44),(33),(55),(66); - -insert into t2 values ('jejdkrun87'),('adfd72nh9k'), -('adfdpplkeock'),('adfdijnmnb78k'),('adfdijn0loKNHJik'); - -create table t1(a int, b blob, c text, d text not null) -engine=innodb default charset = utf8; - -# r2667 The following test is disabled because MySQL behavior changed. -# r2667 The test was added with this comment: -# r2667 -# r2667 ------------------------------------------------------------------------ -# r2667 r1699 | marko | 2007-08-10 19:53:19 +0300 (Fri, 10 Aug 2007) | 5 lines -# r2667 -# r2667 branches/zip: Add changes that accidentally omitted from r1698: -# r2667 -# r2667 innodb-index.test, innodb-index.result: Add a test for creating -# r2667 a PRIMARY KEY on a column that contains a NULL value. -# r2667 ------------------------------------------------------------------------ -# r2667 -# r2667 but in BZR-r2667: -# r2667 http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/davi%40mysql.com-20080617141221-8yre8ys9j4uw3xx5?start_revid=joerg%40mysql.com-20080630105418-7qoe5ehomgrcdb89 -# r2667 MySQL changed the behavior to do full table copy when creating PRIMARY INDEX -# r2667 on a non-NULL column instead of calling ::add_index() which would fail (and -# r2667 this is what we were testing here). Before r2667 the code execution path was -# r2667 like this (when adding PRIMARY INDEX on a non-NULL column with ALTER TABLE): -# r2667 -# r2667 mysql_alter_table() -# r2667 compare_tables() // would return ALTER_TABLE_INDEX_CHANGED -# r2667 ::add_index() // would fail with "primary index cannot contain NULL" -# r2667 -# r2667 after r2667 the code execution path is the following: -# r2667 -# r2667 mysql_alter_table() -# r2667 compare_tables() // returns ALTER_TABLE_DATA_CHANGED -# r2667 full copy is done, without calling ::add_index() -# r2667 -# r2667 To enable, remove "# r2667: " below. -# r2667 -# r2667: insert into t1 values (null,null,null,'null'); -insert into t1 -select a,left(repeat(d,100*a),65535),repeat(d,20*a),d from t2,t3; -drop table t2, t3; -select count(*) from t1 where a=44; -select a, -length(b),b=left(repeat(d,100*a),65535),length(c),c=repeat(d,20*a),d from t1; -# r2667: --error ER_PRIMARY_CANT_HAVE_NULL -# r2667: alter table t1 add primary key (a), add key (b(20)); -# r2667: delete from t1 where d='null'; ---error ER_DUP_ENTRY -alter table t1 add primary key (a), add key (b(20)); -delete from t1 where a%2; -check table t1; -alter table t1 add primary key (a,b(255),c(255)), add key (b(767)); -select count(*) from t1 where a=44; -select a, -length(b),b=left(repeat(d,100*a),65535),length(c),c=repeat(d,20*a),d from t1; -show create table t1; -check table t1; -explain select * from t1 where b like 'adfd%'; - -# -# Test locking -# - -create table t2(a int, b varchar(255), primary key(a,b)) engine=innodb; -insert into t2 select a,left(b,255) from t1; -drop table t1; -rename table t2 to t1; - -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connection a; -set innodb_lock_wait_timeout=1; -begin; -# Obtain an IX lock on the table -select a from t1 limit 1 for update; -connection b; -set innodb_lock_wait_timeout=1; -# This would require an S lock on the table, conflicting with the IX lock. ---error ER_LOCK_WAIT_TIMEOUT -create index t1ba on t1 (b,a); -connection a; -commit; -begin; -# Obtain an IS lock on the table -select a from t1 limit 1 lock in share mode; -connection b; -# This will require an S lock on the table. No conflict with the IS lock. -create index t1ba on t1 (b,a); -# This would require an X lock on the table, conflicting with the IS lock. ---error ER_LOCK_WAIT_TIMEOUT -drop index t1ba on t1; -connection a; -commit; -explain select a from t1 order by b; ---send -select a,sleep(2+a/100) from t1 order by b limit 3; - -# The following DROP INDEX will succeed, altough the SELECT above has -# opened a read view. However, during the execution of the SELECT, -# MySQL should hold a table lock that should block the execution -# of the DROP INDEX below. - -connection b; -select sleep(1); -drop index t1ba on t1; - -# After the index was dropped, subsequent SELECTs will use the same -# read view, but they should not be accessing the dropped index any more. - -connection a; -reap; -explain select a from t1 order by b; -select a from t1 order by b limit 3; -commit; - -connection default; -disconnect a; -disconnect b; - -drop table t1; - -let $per_table=`select @@innodb_file_per_table`; -let $format=`select @@innodb_file_format`; -set global innodb_file_per_table=on; -set global innodb_file_format='Barracuda'; -# Test creating a table that could lead to undo log overflow. -# In the undo log, we write a 768-byte prefix (REC_MAX_INDEX_COL_LEN) -# of each externally stored column that appears as a column prefix in an index. -# For this test case, it would suffice to write 1 byte, though. -create table t1(a blob,b blob,c blob,d blob,e blob,f blob,g blob,h blob, - i blob,j blob,k blob,l blob,m blob,n blob,o blob,p blob, - q blob,r blob,s blob,t blob,u blob) - engine=innodb row_format=dynamic; -create index t1a on t1 (a(1)); -create index t1b on t1 (b(1)); -create index t1c on t1 (c(1)); -create index t1d on t1 (d(1)); -create index t1e on t1 (e(1)); -create index t1f on t1 (f(1)); -create index t1g on t1 (g(1)); -create index t1h on t1 (h(1)); -create index t1i on t1 (i(1)); -create index t1j on t1 (j(1)); -create index t1k on t1 (k(1)); -create index t1l on t1 (l(1)); -create index t1m on t1 (m(1)); -create index t1n on t1 (n(1)); -create index t1o on t1 (o(1)); -create index t1p on t1 (p(1)); -create index t1q on t1 (q(1)); -create index t1r on t1 (r(1)); -create index t1s on t1 (s(1)); -create index t1t on t1 (t(1)); ---error 139 -create index t1u on t1 (u(1)); ---error 139 -create index t1ut on t1 (u(1), t(1)); -create index t1st on t1 (s(1), t(1)); -show create table t1; ---error 139 -create index t1u on t1 (u(1)); -alter table t1 row_format=compact; -create index t1u on t1 (u(1)); - -drop table t1; -eval set global innodb_file_per_table=$per_table; -eval set global innodb_file_format=$format; - -# -# Test to check whether CREATE INDEX handles implicit foreign key -# constraint modifications (Issue #70, Bug #38786) -# -SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0; -SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0; - -CREATE TABLE t1( - c1 BIGINT(12) NOT NULL, - PRIMARY KEY (c1) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - -CREATE TABLE t2( - c1 BIGINT(16) NOT NULL, - c2 BIGINT(12) NOT NULL, - c3 BIGINT(12) NOT NULL, - PRIMARY KEY (c1) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca - FOREIGN KEY (c3) REFERENCES t1(c1); - -SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; -SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS; - -SHOW CREATE TABLE t2; - -CREATE INDEX i_t2_c3_c2 ON t2(c3, c2); - -SHOW CREATE TABLE t2; - -SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS; -SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS; - ---error ER_NO_REFERENCED_ROW_2 -INSERT INTO t2 VALUES(0,0,0); -INSERT INTO t1 VALUES(0); -INSERT INTO t2 VALUES(0,0,0); - -DROP TABLE t2; - -CREATE TABLE t2( - c1 BIGINT(16) NOT NULL, - c2 BIGINT(12) NOT NULL, - c3 BIGINT(12) NOT NULL, - PRIMARY KEY (c1,c2,c3) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca - FOREIGN KEY (c3) REFERENCES t1(c1); - -SHOW CREATE TABLE t2; - -CREATE INDEX i_t2_c3_c2 ON t2(c3, c2); - -SHOW CREATE TABLE t2; ---error ER_NO_REFERENCED_ROW_2 -INSERT INTO t2 VALUES(0,0,1); -INSERT INTO t2 VALUES(0,0,0); ---error ER_ROW_IS_REFERENCED_2 -DELETE FROM t1; -DELETE FROM t2; - -DROP TABLE t2; -DROP TABLE t1; - -CREATE TABLE t1( - c1 BIGINT(12) NOT NULL, - c2 INT(4) NOT NULL, - PRIMARY KEY (c2,c1) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - -CREATE TABLE t2( - c1 BIGINT(16) NOT NULL, - c2 BIGINT(12) NOT NULL, - c3 BIGINT(12) NOT NULL, - PRIMARY KEY (c1) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - ---replace_regex /'test\.#sql-[0-9_a-f-]*'/'#sql-temporary'/ ---error ER_CANT_CREATE_TABLE -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca - FOREIGN KEY (c3,c2) REFERENCES t1(c1,c1); ---replace_regex /'test\.#sql-[0-9_a-f-]*'/'#sql-temporary'/ ---error ER_CANT_CREATE_TABLE -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca - FOREIGN KEY (c3,c2) REFERENCES t1(c1,c2); ---replace_regex /'test\.#sql-[0-9_a-f-]*'/'#sql-temporary'/ ---error ER_CANT_CREATE_TABLE -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca - FOREIGN KEY (c3,c2) REFERENCES t1(c2,c1); -ALTER TABLE t1 MODIFY COLUMN c2 BIGINT(12) NOT NULL; ---replace_regex /'test\.#sql-[0-9_a-f-]*'/'#sql-temporary'/ ---error ER_CANT_CREATE_TABLE -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca - FOREIGN KEY (c3,c2) REFERENCES t1(c1,c2); - -ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca - FOREIGN KEY (c3,c2) REFERENCES t1(c2,c1); -SHOW CREATE TABLE t1; -SHOW CREATE TABLE t2; -CREATE INDEX i_t2_c2_c1 ON t2(c2, c1); -SHOW CREATE TABLE t2; -CREATE INDEX i_t2_c3_c1_c2 ON t2(c3, c1, c2); -SHOW CREATE TABLE t2; -CREATE INDEX i_t2_c3_c2 ON t2(c3, c2); -SHOW CREATE TABLE t2; - -DROP TABLE t2; -DROP TABLE t1; - -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connection a; -CREATE TABLE t1 (a INT, b CHAR(1)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (3,'a'),(3,'b'),(1,'c'),(0,'d'),(1,'e'); -connection b; -BEGIN; -SELECT * FROM t1; -connection a; -CREATE INDEX t1a ON t1(a); -connection b; -SELECT * FROM t1; ---error ER_TABLE_DEF_CHANGED -SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a; -SELECT * FROM t1; -COMMIT; -SELECT * FROM t1 FORCE INDEX(t1a) ORDER BY a; -connection default; -disconnect a; -disconnect b; - -DROP TABLE t1; diff --git a/storage/innobase/mysql-test/innodb-index_ucs2.result b/storage/innobase/mysql-test/innodb-index_ucs2.result deleted file mode 100644 index c8a1e8c7da1..00000000000 --- a/storage/innobase/mysql-test/innodb-index_ucs2.result +++ /dev/null @@ -1,116 +0,0 @@ -create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb default charset=ucs2; -insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe'); -commit; -alter table t1 add unique index (b); -ERROR 23000: Duplicate entry '2' for key 'b' -insert into t1 values(8,9,'fff','fff'); -select * from t1; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`) -) ENGINE=InnoDB DEFAULT CHARSET=ucs2 -alter table t1 add index (b); -insert into t1 values(10,10,'kkk','iii'); -select * from t1; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -10 10 kkk iii -select * from t1 force index(b) order by b; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -10 10 kkk iii -explain select * from t1 force index(b) order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 5 NULL 6 -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - KEY `b` (`b`) -) ENGINE=InnoDB DEFAULT CHARSET=ucs2 -alter table t1 add unique index (c), add index (d); -insert into t1 values(11,11,'aaa','mmm'); -select * from t1; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -10 10 kkk iii -11 11 aaa mmm -select * from t1 force index(b) order by b; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -10 10 kkk iii -11 11 aaa mmm -select * from t1 force index(c) order by c; -a b c d -11 11 aaa mmm -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -10 10 kkk iii -select * from t1 force index(d) order by d; -a b c d -1 1 ab ab -2 2 ac ac -3 2 ad ad -4 4 afe afe -8 9 fff fff -10 10 kkk iii -11 11 aaa mmm -explain select * from t1 force index(b) order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 5 NULL 7 -explain select * from t1 force index(c) order by c; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL c 21 NULL 7 -explain select * from t1 force index(d) order by d; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL d 43 NULL 7 -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `d` varchar(20) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `c` (`c`), - KEY `b` (`b`), - KEY `d` (`d`) -) ENGINE=InnoDB DEFAULT CHARSET=ucs2 -check table t1; -Table Op Msg_type Msg_text -test.t1 check status OK -drop table t1; diff --git a/storage/innobase/mysql-test/innodb-index_ucs2.test b/storage/innobase/mysql-test/innodb-index_ucs2.test deleted file mode 100644 index fff9a4da1a8..00000000000 --- a/storage/innobase/mysql-test/innodb-index_ucs2.test +++ /dev/null @@ -1,5 +0,0 @@ --- source include/have_innodb.inc --- source include/have_ucs2.inc - --- let charset = ucs2 --- source include/innodb-index.inc diff --git a/storage/innobase/mysql-test/innodb-lock.result b/storage/innobase/mysql-test/innodb-lock.result deleted file mode 100644 index 4ace4065c34..00000000000 --- a/storage/innobase/mysql-test/innodb-lock.result +++ /dev/null @@ -1,57 +0,0 @@ -set global innodb_table_locks=1; -select @@innodb_table_locks; -@@innodb_table_locks -1 -drop table if exists t1; -set @@innodb_table_locks=1; -create table t1 (id integer, x integer) engine=INNODB; -insert into t1 values(0, 0); -set autocommit=0; -SELECT * from t1 where id = 0 FOR UPDATE; -id x -0 0 -set autocommit=0; -lock table t1 write; -update t1 set x=1 where id = 0; -select * from t1; -id x -0 1 -commit; -update t1 set x=2 where id = 0; -commit; -unlock tables; -select * from t1; -id x -0 2 -commit; -drop table t1; -set @@innodb_table_locks=0; -create table t1 (id integer primary key, x integer) engine=INNODB; -insert into t1 values(0, 0),(1,1),(2,2); -commit; -SELECT * from t1 where id = 0 FOR UPDATE; -id x -0 0 -set autocommit=0; -set @@innodb_table_locks=0; -lock table t1 write; -update t1 set x=10 where id = 2; -SELECT * from t1 where id = 2; -id x -2 2 -UPDATE t1 set x=3 where id = 2; -commit; -SELECT * from t1; -id x -0 0 -1 1 -2 3 -commit; -unlock tables; -commit; -select * from t1; -id x -0 0 -1 1 -2 10 -drop table t1; diff --git a/storage/innobase/mysql-test/innodb-lock.test b/storage/innobase/mysql-test/innodb-lock.test deleted file mode 100644 index eacf7e562be..00000000000 --- a/storage/innobase/mysql-test/innodb-lock.test +++ /dev/null @@ -1,102 +0,0 @@ --- source include/have_innodb.inc - -# -# Check and select innodb lock type -# - -set global innodb_table_locks=1; - -select @@innodb_table_locks; - -# -# Testing of explicit table locks with enforced table locks -# - -connect (con1,localhost,root,,); -connect (con2,localhost,root,,); - ---disable_warnings -drop table if exists t1; ---enable_warnings - -# -# Testing of explicit table locks with enforced table locks -# - -set @@innodb_table_locks=1; - -connection con1; -create table t1 (id integer, x integer) engine=INNODB; -insert into t1 values(0, 0); -set autocommit=0; -SELECT * from t1 where id = 0 FOR UPDATE; - -connection con2; -set autocommit=0; - -# The following statement should hang because con1 is locking the page ---send -lock table t1 write; ---sleep 2 - -connection con1; -update t1 set x=1 where id = 0; -select * from t1; -commit; - -connection con2; -reap; -update t1 set x=2 where id = 0; -commit; -unlock tables; - -connection con1; -select * from t1; -commit; - -drop table t1; - -# -# Try with old lock method (where LOCK TABLE is ignored by InnoDB) -# - -set @@innodb_table_locks=0; - -create table t1 (id integer primary key, x integer) engine=INNODB; -insert into t1 values(0, 0),(1,1),(2,2); -commit; -SELECT * from t1 where id = 0 FOR UPDATE; - -connection con2; -set autocommit=0; -set @@innodb_table_locks=0; - -# The following statement should work becase innodb doesn't check table locks -lock table t1 write; - -connection con1; - -# This will be locked by MySQL ---send -update t1 set x=10 where id = 2; ---sleep 2 - -connection con2; - -# Note that we will get a deadlock if we try to select any rows marked -# for update by con1 ! - -SELECT * from t1 where id = 2; -UPDATE t1 set x=3 where id = 2; -commit; -SELECT * from t1; -commit; -unlock tables; - -connection con1; -reap; -commit; -select * from t1; -drop table t1; - -# End of 4.1 tests diff --git a/storage/innobase/mysql-test/innodb-replace.result b/storage/innobase/mysql-test/innodb-replace.result deleted file mode 100644 index c926bb89a2e..00000000000 --- a/storage/innobase/mysql-test/innodb-replace.result +++ /dev/null @@ -1,13 +0,0 @@ -drop table if exists t1; -create table t1 (c1 char(5) unique not null, c2 int, stamp timestamp) engine=innodb; -select * from t1; -c1 c2 stamp -replace delayed into t1 (c1, c2) values ( "text1","11"); -ERROR HY000: DELAYED option not supported for table 't1' -select * from t1; -c1 c2 stamp -replace delayed into t1 (c1, c2) values ( "text1","12"); -ERROR HY000: DELAYED option not supported for table 't1' -select * from t1; -c1 c2 stamp -drop table t1; diff --git a/storage/innobase/mysql-test/innodb-replace.test b/storage/innobase/mysql-test/innodb-replace.test deleted file mode 100644 index 8c3aacde5e8..00000000000 --- a/storage/innobase/mysql-test/innodb-replace.test +++ /dev/null @@ -1,22 +0,0 @@ --- source include/have_innodb.inc -# embedded server ignores 'delayed', so skip this --- source include/not_embedded.inc - ---disable_warnings -drop table if exists t1; ---enable_warnings - -# -# Bug #1078 -# -create table t1 (c1 char(5) unique not null, c2 int, stamp timestamp) engine=innodb; -select * from t1; ---error ER_DELAYED_NOT_SUPPORTED -replace delayed into t1 (c1, c2) values ( "text1","11"); -select * from t1; ---error ER_DELAYED_NOT_SUPPORTED -replace delayed into t1 (c1, c2) values ( "text1","12"); -select * from t1; -drop table t1; - -# End of 4.1 tests diff --git a/storage/innobase/mysql-test/innodb-semi-consistent.result b/storage/innobase/mysql-test/innodb-semi-consistent.result deleted file mode 100644 index ca0e362ef80..00000000000 --- a/storage/innobase/mysql-test/innodb-semi-consistent.result +++ /dev/null @@ -1,47 +0,0 @@ -drop table if exists t1; -set binlog_format=mixed; -set session transaction isolation level repeatable read; -create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; -insert into t1 values (1),(2),(3),(4),(5),(6),(7); -set autocommit=0; -select * from t1 where a=3 lock in share mode; -a -3 -set binlog_format=mixed; -set session transaction isolation level repeatable read; -set autocommit=0; -update t1 set a=10 where a=5; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -commit; -set session transaction isolation level read committed; -update t1 set a=10 where a=5; -select * from t1 where a=2 for update; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -select * from t1 where a=2 limit 1 for update; -a -2 -update t1 set a=11 where a=6; -update t1 set a=12 where a=2; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -update t1 set a=13 where a=1; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -commit; -update t1 set a=14 where a=1; -commit; -select * from t1; -a -14 -2 -3 -4 -10 -11 -7 -drop table t1; -create table t1 (a int, b int) engine=myisam; -create table t2 (c int, d int, key (c)) engine=innodb; -insert into t1 values (1,1); -insert into t2 values (1,2); -set session transaction isolation level read committed; -delete from t1 using t1 join t2 on t1.a = t2.c where t2.d in (1); -drop table t1, t2; diff --git a/storage/innobase/mysql-test/innodb-semi-consistent.test b/storage/innobase/mysql-test/innodb-semi-consistent.test deleted file mode 100644 index 61ad7815ca9..00000000000 --- a/storage/innobase/mysql-test/innodb-semi-consistent.test +++ /dev/null @@ -1,68 +0,0 @@ --- source include/not_embedded.inc --- source include/have_innodb.inc - ---disable_warnings -drop table if exists t1; ---enable_warnings - -# basic tests of semi-consistent reads - -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connection a; -set binlog_format=mixed; -set session transaction isolation level repeatable read; -create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; -insert into t1 values (1),(2),(3),(4),(5),(6),(7); -set autocommit=0; -# this should lock the entire table -select * from t1 where a=3 lock in share mode; -connection b; -set binlog_format=mixed; -set session transaction isolation level repeatable read; -set autocommit=0; --- error ER_LOCK_WAIT_TIMEOUT -update t1 set a=10 where a=5; -connection a; -commit; -connection b; -# perform a semi-consisent read (and unlock non-matching rows) -set session transaction isolation level read committed; -update t1 set a=10 where a=5; -connection a; --- error ER_LOCK_WAIT_TIMEOUT -select * from t1 where a=2 for update; -# this should lock the records (1),(2) -select * from t1 where a=2 limit 1 for update; -connection b; -# semi-consistent read will skip non-matching locked rows a=1, a=2 -update t1 set a=11 where a=6; --- error ER_LOCK_WAIT_TIMEOUT -update t1 set a=12 where a=2; --- error ER_LOCK_WAIT_TIMEOUT -update t1 set a=13 where a=1; -connection a; -commit; -connection b; -update t1 set a=14 where a=1; -commit; -connection a; -select * from t1; -drop table t1; - -connection default; -disconnect a; -disconnect b; - -# Bug 39320 -create table t1 (a int, b int) engine=myisam; -create table t2 (c int, d int, key (c)) engine=innodb; -insert into t1 values (1,1); -insert into t2 values (1,2); -connect (a,localhost,root,,); -connection a; -set session transaction isolation level read committed; -delete from t1 using t1 join t2 on t1.a = t2.c where t2.d in (1); -connection default; -disconnect a; -drop table t1, t2; diff --git a/storage/innobase/mysql-test/innodb-timeout.result b/storage/innobase/mysql-test/innodb-timeout.result deleted file mode 100644 index be9a688cd72..00000000000 --- a/storage/innobase/mysql-test/innodb-timeout.result +++ /dev/null @@ -1,38 +0,0 @@ -set global innodb_lock_wait_timeout=42; -select @@innodb_lock_wait_timeout; -@@innodb_lock_wait_timeout -42 -set innodb_lock_wait_timeout=1; -select @@innodb_lock_wait_timeout; -@@innodb_lock_wait_timeout -1 -select @@innodb_lock_wait_timeout; -@@innodb_lock_wait_timeout -42 -set global innodb_lock_wait_timeout=347; -select @@innodb_lock_wait_timeout; -@@innodb_lock_wait_timeout -42 -set innodb_lock_wait_timeout=1; -select @@innodb_lock_wait_timeout; -@@innodb_lock_wait_timeout -1 -select @@innodb_lock_wait_timeout; -@@innodb_lock_wait_timeout -347 -create table t1(a int primary key)engine=innodb; -begin; -insert into t1 values(1),(2),(3); -select * from t1 for update; -commit; -a -1 -2 -3 -begin; -insert into t1 values(4); -select * from t1 for update; -commit; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -drop table t1; -set global innodb_lock_wait_timeout=50; diff --git a/storage/innobase/mysql-test/innodb-timeout.test b/storage/innobase/mysql-test/innodb-timeout.test deleted file mode 100644 index f23fe3cff2d..00000000000 --- a/storage/innobase/mysql-test/innodb-timeout.test +++ /dev/null @@ -1,64 +0,0 @@ --- source include/have_innodb.inc - -let $timeout=`select @@innodb_lock_wait_timeout`; -set global innodb_lock_wait_timeout=42; - -connect (a,localhost,root,,); -connect (b,localhost,root,,); - -connection a; -select @@innodb_lock_wait_timeout; -set innodb_lock_wait_timeout=1; -select @@innodb_lock_wait_timeout; - -connection b; -select @@innodb_lock_wait_timeout; -set global innodb_lock_wait_timeout=347; -select @@innodb_lock_wait_timeout; -set innodb_lock_wait_timeout=1; -select @@innodb_lock_wait_timeout; - -connect (c,localhost,root,,); -connection c; -select @@innodb_lock_wait_timeout; -connection default; -disconnect c; - -connection a; -create table t1(a int primary key)engine=innodb; -begin; -insert into t1 values(1),(2),(3); - -connection b; ---send -select * from t1 for update; - -connection a; -commit; - -connection b; -reap; - -connection a; -begin; -insert into t1 values(4); - -connection b; ---send -select * from t1 for update; - -connection a; -sleep 2; -commit; - -connection b; ---error ER_LOCK_WAIT_TIMEOUT -reap; -drop table t1; - -connection default; - -disconnect a; -disconnect b; - -eval set global innodb_lock_wait_timeout=$timeout; diff --git a/storage/innobase/mysql-test/innodb-use-sys-malloc-master.opt b/storage/innobase/mysql-test/innodb-use-sys-malloc-master.opt deleted file mode 100644 index 889834add01..00000000000 --- a/storage/innobase/mysql-test/innodb-use-sys-malloc-master.opt +++ /dev/null @@ -1,2 +0,0 @@ ---innodb-use-sys-malloc=true ---innodb-use-sys-malloc=true diff --git a/storage/innobase/mysql-test/innodb-use-sys-malloc.result b/storage/innobase/mysql-test/innodb-use-sys-malloc.result deleted file mode 100644 index 2ec4c7c8130..00000000000 --- a/storage/innobase/mysql-test/innodb-use-sys-malloc.result +++ /dev/null @@ -1,48 +0,0 @@ -SELECT @@GLOBAL.innodb_use_sys_malloc; -@@GLOBAL.innodb_use_sys_malloc -1 -1 Expected -SET @@GLOBAL.innodb_use_sys_malloc=0; -ERROR HY000: Variable 'innodb_use_sys_malloc' is a read only variable -Expected error 'Read only variable' -SELECT @@GLOBAL.innodb_use_sys_malloc; -@@GLOBAL.innodb_use_sys_malloc -1 -1 Expected -drop table if exists t1; -create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; -insert into t1 values (1),(2),(3),(4),(5),(6),(7); -select * from t1; -a -1 -2 -3 -4 -5 -6 -7 -drop table t1; -SELECT @@GLOBAL.innodb_use_sys_malloc; -@@GLOBAL.innodb_use_sys_malloc -1 -1 Expected -SET @@GLOBAL.innodb_use_sys_malloc=0; -ERROR HY000: Variable 'innodb_use_sys_malloc' is a read only variable -Expected error 'Read only variable' -SELECT @@GLOBAL.innodb_use_sys_malloc; -@@GLOBAL.innodb_use_sys_malloc -1 -1 Expected -drop table if exists t1; -create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; -insert into t1 values (1),(2),(3),(4),(5),(6),(7); -select * from t1; -a -1 -2 -3 -4 -5 -6 -7 -drop table t1; diff --git a/storage/innobase/mysql-test/innodb-use-sys-malloc.test b/storage/innobase/mysql-test/innodb-use-sys-malloc.test deleted file mode 100644 index 325dd19d086..00000000000 --- a/storage/innobase/mysql-test/innodb-use-sys-malloc.test +++ /dev/null @@ -1,48 +0,0 @@ ---source include/have_innodb.inc - -#display current value of innodb_use_sys_malloc -SELECT @@GLOBAL.innodb_use_sys_malloc; ---echo 1 Expected - -#try changing it. Should fail. ---error ER_INCORRECT_GLOBAL_LOCAL_VAR -SET @@GLOBAL.innodb_use_sys_malloc=0; ---echo Expected error 'Read only variable' - -SELECT @@GLOBAL.innodb_use_sys_malloc; ---echo 1 Expected - - -#do some stuff to see if it works. ---disable_warnings -drop table if exists t1; ---enable_warnings - -create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; -insert into t1 values (1),(2),(3),(4),(5),(6),(7); -select * from t1; -drop table t1; ---source include/have_innodb.inc - -#display current value of innodb_use_sys_malloc -SELECT @@GLOBAL.innodb_use_sys_malloc; ---echo 1 Expected - -#try changing it. Should fail. ---error ER_INCORRECT_GLOBAL_LOCAL_VAR -SET @@GLOBAL.innodb_use_sys_malloc=0; ---echo Expected error 'Read only variable' - -SELECT @@GLOBAL.innodb_use_sys_malloc; ---echo 1 Expected - - -#do some stuff to see if it works. ---disable_warnings -drop table if exists t1; ---enable_warnings - -create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; -insert into t1 values (1),(2),(3),(4),(5),(6),(7); -select * from t1; -drop table t1; diff --git a/storage/innobase/mysql-test/innodb-zip.result b/storage/innobase/mysql-test/innodb-zip.result deleted file mode 100644 index b26c4112826..00000000000 --- a/storage/innobase/mysql-test/innodb-zip.result +++ /dev/null @@ -1,421 +0,0 @@ -set global innodb_file_per_table=off; -set global innodb_file_format=`0`; -create table t0(a int primary key) engine=innodb row_format=compressed; -Warnings: -Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table. -Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. -create table t00(a int primary key) engine=innodb -key_block_size=4 row_format=compressed; -Warnings: -Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. -Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=4. -Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table. -Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. -create table t1(a int primary key) engine=innodb row_format=dynamic; -Warnings: -Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table. -Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. -create table t2(a int primary key) engine=innodb row_format=redundant; -create table t3(a int primary key) engine=innodb row_format=compact; -create table t4(a int primary key) engine=innodb key_block_size=9; -Warnings: -Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. -Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=9. -create table t5(a int primary key) engine=innodb -key_block_size=1 row_format=redundant; -Warnings: -Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. -Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1. -set global innodb_file_per_table=on; -create table t6(a int primary key) engine=innodb -key_block_size=1 row_format=redundant; -Warnings: -Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1. -set global innodb_file_format=`1`; -create table t7(a int primary key) engine=innodb -key_block_size=1 row_format=redundant; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. -create table t8(a int primary key) engine=innodb -key_block_size=1 row_format=fixed; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. -Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. -create table t9(a int primary key) engine=innodb -key_block_size=1 row_format=compact; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. -create table t10(a int primary key) engine=innodb -key_block_size=1 row_format=dynamic; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED. -create table t11(a int primary key) engine=innodb -key_block_size=1 row_format=compressed; -create table t12(a int primary key) engine=innodb -key_block_size=1; -create table t13(a int primary key) engine=innodb -row_format=compressed; -create table t14(a int primary key) engine=innodb key_block_size=9; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=9. -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -table_schema table_name row_format -test t0 Compact -test t00 Compact -test t1 Compact -test t10 Dynamic -test t11 Compressed -test t12 Compressed -test t13 Compressed -test t14 Compact -test t2 Redundant -test t3 Compact -test t4 Compact -test t5 Redundant -test t6 Redundant -test t7 Redundant -test t8 Compact -test t9 Compact -drop table t0,t00,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14; -alter table t1 key_block_size=0; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=0. -alter table t1 row_format=dynamic; -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -table_schema table_name row_format -test t1 Dynamic -alter table t1 row_format=compact; -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -table_schema table_name row_format -test t1 Compact -alter table t1 row_format=redundant; -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -table_schema table_name row_format -test t1 Redundant -drop table t1; -create table t1(a int not null, b text, index(b(10))) engine=innodb -key_block_size=1; -create table t2(b text)engine=innodb; -insert into t2 values(concat('1abcdefghijklmnopqrstuvwxyz', repeat('A',5000))); -insert into t1 select 1, b from t2; -commit; -begin; -update t1 set b=repeat('B',100); -select a,left(b,40) from t1 natural join t2; -a left(b,40) -1 1abcdefghijklmnopqrstuvwxyzAAAAAAAAAAAAA -rollback; -select a,left(b,40) from t1 natural join t2; -a left(b,40) -1 1abcdefghijklmnopqrstuvwxyzAAAAAAAAAAAAA -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -table_schema table_name row_format -test t1 Compressed -test t2 Compact -drop table t1,t2; -SET SESSION innodb_strict_mode = off; -CREATE TABLE t1( -c TEXT NOT NULL, d TEXT NOT NULL, -PRIMARY KEY (c(767),d(767))) -ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; -ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs -CREATE TABLE t1( -c TEXT NOT NULL, d TEXT NOT NULL, -PRIMARY KEY (c(767),d(767))) -ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2 CHARSET=ASCII; -ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs -CREATE TABLE t1( -c TEXT NOT NULL, d TEXT NOT NULL, -PRIMARY KEY (c(767),d(767))) -ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4 CHARSET=ASCII; -drop table t1; -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) -ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; -ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) -ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; -INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); -DROP TABLE t1; -create table t1( c1 int not null, c2 blob, c3 blob, c4 blob, -primary key(c1, c2(22), c3(22))) -engine = innodb row_format = dynamic; -begin; -insert into t1 values(1, repeat('A', 20000), repeat('B', 20000), -repeat('C', 20000)); -update t1 set c3 = repeat('D', 20000) where c1 = 1; -commit; -select count(*) from t1 where c2 = repeat('A', 20000); -count(*) -1 -select count(*) from t1 where c3 = repeat('D', 20000); -count(*) -1 -select count(*) from t1 where c4 = repeat('C', 20000); -count(*) -1 -update t1 set c3 = repeat('E', 20000) where c1 = 1; -drop table t1; -set global innodb_file_format=`0`; -select @@innodb_file_format; -@@innodb_file_format -Antelope -set global innodb_file_format=`1`; -select @@innodb_file_format; -@@innodb_file_format -Barracuda -set global innodb_file_format=`2`; -ERROR HY000: Incorrect arguments to SET -set global innodb_file_format=`-1`; -ERROR HY000: Incorrect arguments to SET -set global innodb_file_format=`Antelope`; -set global innodb_file_format=`Barracuda`; -set global innodb_file_format=`Cheetah`; -ERROR HY000: Incorrect arguments to SET -set global innodb_file_format=`abc`; -ERROR HY000: Incorrect arguments to SET -set global innodb_file_format=`1a`; -ERROR HY000: Incorrect arguments to SET -set global innodb_file_format=``; -ERROR HY000: Incorrect arguments to SET -set global innodb_file_per_table = on; -set global innodb_file_format = `1`; -set innodb_strict_mode = off; -create table t1 (id int primary key) engine = innodb key_block_size = 0; -Warnings: -Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=0. -drop table t1; -set innodb_strict_mode = on; -create table t1 (id int primary key) engine = innodb key_block_size = 0; -ERROR HY000: Can't create table 'test.t1' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 0. Valid values are [1, 2, 4, 8, 16] -Error 1005 Can't create table 'test.t1' (errno: 1478) -create table t2 (id int primary key) engine = innodb key_block_size = 9; -ERROR HY000: Can't create table 'test.t2' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] -Error 1005 Can't create table 'test.t2' (errno: 1478) -create table t3 (id int primary key) engine = innodb key_block_size = 1; -create table t4 (id int primary key) engine = innodb key_block_size = 2; -create table t5 (id int primary key) engine = innodb key_block_size = 4; -create table t6 (id int primary key) engine = innodb key_block_size = 8; -create table t7 (id int primary key) engine = innodb key_block_size = 16; -create table t8 (id int primary key) engine = innodb row_format = compressed; -create table t9 (id int primary key) engine = innodb row_format = dynamic; -create table t10(id int primary key) engine = innodb row_format = compact; -create table t11(id int primary key) engine = innodb row_format = redundant; -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -table_schema table_name row_format -test t10 Compact -test t11 Redundant -test t3 Compressed -test t4 Compressed -test t5 Compressed -test t6 Compressed -test t7 Compressed -test t8 Compressed -test t9 Dynamic -drop table t3, t4, t5, t6, t7, t8, t9, t10, t11; -create table t1 (id int primary key) engine = innodb -key_block_size = 8 row_format = compressed; -create table t2 (id int primary key) engine = innodb -key_block_size = 8 row_format = redundant; -ERROR HY000: Can't create table 'test.t2' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. -Error 1005 Can't create table 'test.t2' (errno: 1478) -create table t3 (id int primary key) engine = innodb -key_block_size = 8 row_format = compact; -ERROR HY000: Can't create table 'test.t3' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. -Error 1005 Can't create table 'test.t3' (errno: 1478) -create table t4 (id int primary key) engine = innodb -key_block_size = 8 row_format = dynamic; -ERROR HY000: Can't create table 'test.t4' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. -Error 1005 Can't create table 'test.t4' (errno: 1478) -create table t5 (id int primary key) engine = innodb -key_block_size = 8 row_format = default; -ERROR HY000: Can't create table 'test.t5' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. -Error 1005 Can't create table 'test.t5' (errno: 1478) -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -table_schema table_name row_format -test t1 Compressed -drop table t1; -create table t1 (id int primary key) engine = innodb -key_block_size = 9 row_format = redundant; -ERROR HY000: Can't create table 'test.t1' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] -Error 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. -Error 1005 Can't create table 'test.t1' (errno: 1478) -create table t2 (id int primary key) engine = innodb -key_block_size = 9 row_format = compact; -ERROR HY000: Can't create table 'test.t2' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] -Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE. -Error 1005 Can't create table 'test.t2' (errno: 1478) -create table t2 (id int primary key) engine = innodb -key_block_size = 9 row_format = dynamic; -ERROR HY000: Can't create table 'test.t2' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16] -Error 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. -Error 1005 Can't create table 'test.t2' (errno: 1478) -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -table_schema table_name row_format -set global innodb_file_per_table = off; -create table t1 (id int primary key) engine = innodb key_block_size = 1; -ERROR HY000: Can't create table 'test.t1' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. -Error 1005 Can't create table 'test.t1' (errno: 1478) -create table t2 (id int primary key) engine = innodb key_block_size = 2; -ERROR HY000: Can't create table 'test.t2' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. -Error 1005 Can't create table 'test.t2' (errno: 1478) -create table t3 (id int primary key) engine = innodb key_block_size = 4; -ERROR HY000: Can't create table 'test.t3' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. -Error 1005 Can't create table 'test.t3' (errno: 1478) -create table t4 (id int primary key) engine = innodb key_block_size = 8; -ERROR HY000: Can't create table 'test.t4' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. -Error 1005 Can't create table 'test.t4' (errno: 1478) -create table t5 (id int primary key) engine = innodb key_block_size = 16; -ERROR HY000: Can't create table 'test.t5' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. -Error 1005 Can't create table 'test.t5' (errno: 1478) -create table t6 (id int primary key) engine = innodb row_format = compressed; -ERROR HY000: Can't create table 'test.t6' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table. -Error 1005 Can't create table 'test.t6' (errno: 1478) -create table t7 (id int primary key) engine = innodb row_format = dynamic; -ERROR HY000: Can't create table 'test.t7' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table. -Error 1005 Can't create table 'test.t7' (errno: 1478) -create table t8 (id int primary key) engine = innodb row_format = compact; -create table t9 (id int primary key) engine = innodb row_format = redundant; -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -table_schema table_name row_format -test t8 Compact -test t9 Redundant -drop table t8, t9; -set global innodb_file_per_table = on; -set global innodb_file_format = `0`; -create table t1 (id int primary key) engine = innodb key_block_size = 1; -ERROR HY000: Can't create table 'test.t1' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. -Error 1005 Can't create table 'test.t1' (errno: 1478) -create table t2 (id int primary key) engine = innodb key_block_size = 2; -ERROR HY000: Can't create table 'test.t2' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. -Error 1005 Can't create table 'test.t2' (errno: 1478) -create table t3 (id int primary key) engine = innodb key_block_size = 4; -ERROR HY000: Can't create table 'test.t3' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. -Error 1005 Can't create table 'test.t3' (errno: 1478) -create table t4 (id int primary key) engine = innodb key_block_size = 8; -ERROR HY000: Can't create table 'test.t4' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. -Error 1005 Can't create table 'test.t4' (errno: 1478) -create table t5 (id int primary key) engine = innodb key_block_size = 16; -ERROR HY000: Can't create table 'test.t5' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. -Error 1005 Can't create table 'test.t5' (errno: 1478) -create table t6 (id int primary key) engine = innodb row_format = compressed; -ERROR HY000: Can't create table 'test.t6' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope. -Error 1005 Can't create table 'test.t6' (errno: 1478) -create table t7 (id int primary key) engine = innodb row_format = dynamic; -ERROR HY000: Can't create table 'test.t7' (errno: 1478) -show errors; -Level Code Message -Error 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. -Error 1005 Can't create table 'test.t7' (errno: 1478) -create table t8 (id int primary key) engine = innodb row_format = compact; -create table t9 (id int primary key) engine = innodb row_format = redundant; -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -table_schema table_name row_format -test t8 Compact -test t9 Redundant -drop table t8, t9; -set global innodb_file_per_table=0; -set global innodb_file_format=Antelope; -set global innodb_file_per_table=on; -set global innodb_file_format=`Barracuda`; -set global innodb_file_format_check=`Antelope`; -create table normal_table ( -c1 int -) engine = innodb; -select @@innodb_file_format_check; -@@innodb_file_format_check -Antelope -create table zip_table ( -c1 int -) engine = innodb key_block_size = 8; -select @@innodb_file_format_check; -@@innodb_file_format_check -Barracuda -set global innodb_file_format_check=`Antelope`; -select @@innodb_file_format_check; -@@innodb_file_format_check -Antelope -show table status; -select @@innodb_file_format_check; -@@innodb_file_format_check -Barracuda -drop table normal_table, zip_table; diff --git a/storage/innobase/mysql-test/innodb-zip.test b/storage/innobase/mysql-test/innodb-zip.test deleted file mode 100644 index 5bcd0e3c824..00000000000 --- a/storage/innobase/mysql-test/innodb-zip.test +++ /dev/null @@ -1,343 +0,0 @@ --- source include/have_innodb.inc - -let $per_table=`select @@innodb_file_per_table`; -let $format=`select @@innodb_file_format`; -let $innodb_file_format_check_orig=`select @@innodb_file_format_check`; -set global innodb_file_per_table=off; -set global innodb_file_format=`0`; - -create table t0(a int primary key) engine=innodb row_format=compressed; -create table t00(a int primary key) engine=innodb -key_block_size=4 row_format=compressed; -create table t1(a int primary key) engine=innodb row_format=dynamic; -create table t2(a int primary key) engine=innodb row_format=redundant; -create table t3(a int primary key) engine=innodb row_format=compact; -create table t4(a int primary key) engine=innodb key_block_size=9; -create table t5(a int primary key) engine=innodb -key_block_size=1 row_format=redundant; - -set global innodb_file_per_table=on; -create table t6(a int primary key) engine=innodb -key_block_size=1 row_format=redundant; -set global innodb_file_format=`1`; -create table t7(a int primary key) engine=innodb -key_block_size=1 row_format=redundant; -create table t8(a int primary key) engine=innodb -key_block_size=1 row_format=fixed; -create table t9(a int primary key) engine=innodb -key_block_size=1 row_format=compact; -create table t10(a int primary key) engine=innodb -key_block_size=1 row_format=dynamic; -create table t11(a int primary key) engine=innodb -key_block_size=1 row_format=compressed; -create table t12(a int primary key) engine=innodb -key_block_size=1; -create table t13(a int primary key) engine=innodb -row_format=compressed; -create table t14(a int primary key) engine=innodb key_block_size=9; - -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; - -drop table t0,t00,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14; -alter table t1 key_block_size=0; -alter table t1 row_format=dynamic; -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -alter table t1 row_format=compact; -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -alter table t1 row_format=redundant; -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -drop table t1; - -create table t1(a int not null, b text, index(b(10))) engine=innodb -key_block_size=1; - -create table t2(b text)engine=innodb; -insert into t2 values(concat('1abcdefghijklmnopqrstuvwxyz', repeat('A',5000))); - -insert into t1 select 1, b from t2; -commit; - -connect (a,localhost,root,,); -connect (b,localhost,root,,); - -connection a; -begin; -update t1 set b=repeat('B',100); - -connection b; -select a,left(b,40) from t1 natural join t2; - -connection a; -rollback; - -connection b; -select a,left(b,40) from t1 natural join t2; - -connection default; -disconnect a; -disconnect b; - -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -drop table t1,t2; - -# The following should fail even in non-strict mode. -SET SESSION innodb_strict_mode = off; ---error ER_TOO_BIG_ROWSIZE -CREATE TABLE t1( - c TEXT NOT NULL, d TEXT NOT NULL, - PRIMARY KEY (c(767),d(767))) -ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; ---error ER_TOO_BIG_ROWSIZE -CREATE TABLE t1( - c TEXT NOT NULL, d TEXT NOT NULL, - PRIMARY KEY (c(767),d(767))) -ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2 CHARSET=ASCII; -CREATE TABLE t1( - c TEXT NOT NULL, d TEXT NOT NULL, - PRIMARY KEY (c(767),d(767))) -ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4 CHARSET=ASCII; -drop table t1; ---error ER_TOO_BIG_ROWSIZE -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440))) -ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; -CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438))) -ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII; -INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512)); -DROP TABLE t1; - -# -# Test blob column inheritance (mantis issue#36) -# - -create table t1( c1 int not null, c2 blob, c3 blob, c4 blob, - primary key(c1, c2(22), c3(22))) - engine = innodb row_format = dynamic; -begin; -insert into t1 values(1, repeat('A', 20000), repeat('B', 20000), - repeat('C', 20000)); - -update t1 set c3 = repeat('D', 20000) where c1 = 1; -commit; - -# one blob column which is unchanged in update and part of PK -# one blob column which is changed and part of of PK -# one blob column which is not part of PK and is unchanged -select count(*) from t1 where c2 = repeat('A', 20000); -select count(*) from t1 where c3 = repeat('D', 20000); -select count(*) from t1 where c4 = repeat('C', 20000); - -update t1 set c3 = repeat('E', 20000) where c1 = 1; -drop table t1; - -# -# -# Test innodb_file_format -# -set global innodb_file_format=`0`; -select @@innodb_file_format; -set global innodb_file_format=`1`; -select @@innodb_file_format; --- error ER_WRONG_ARGUMENTS -set global innodb_file_format=`2`; --- error ER_WRONG_ARGUMENTS -set global innodb_file_format=`-1`; -set global innodb_file_format=`Antelope`; -set global innodb_file_format=`Barracuda`; --- error ER_WRONG_ARGUMENTS -set global innodb_file_format=`Cheetah`; --- error ER_WRONG_ARGUMENTS -set global innodb_file_format=`abc`; --- error ER_WRONG_ARGUMENTS -set global innodb_file_format=`1a`; --- error ER_WRONG_ARGUMENTS -set global innodb_file_format=``; - -#test strict mode. -# this does not work anymore, has been removed from mysqltest -# -- enable_errors -set global innodb_file_per_table = on; -set global innodb_file_format = `1`; - -set innodb_strict_mode = off; -create table t1 (id int primary key) engine = innodb key_block_size = 0; -drop table t1; - -#set strict_mode -set innodb_strict_mode = on; - -#Test different values of KEY_BLOCK_SIZE - ---error ER_CANT_CREATE_TABLE -create table t1 (id int primary key) engine = innodb key_block_size = 0; -show errors; - ---error ER_CANT_CREATE_TABLE -create table t2 (id int primary key) engine = innodb key_block_size = 9; -show errors; - - -create table t3 (id int primary key) engine = innodb key_block_size = 1; -create table t4 (id int primary key) engine = innodb key_block_size = 2; -create table t5 (id int primary key) engine = innodb key_block_size = 4; -create table t6 (id int primary key) engine = innodb key_block_size = 8; -create table t7 (id int primary key) engine = innodb key_block_size = 16; - -#check various ROW_FORMAT values. -create table t8 (id int primary key) engine = innodb row_format = compressed; -create table t9 (id int primary key) engine = innodb row_format = dynamic; -create table t10(id int primary key) engine = innodb row_format = compact; -create table t11(id int primary key) engine = innodb row_format = redundant; - -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -drop table t3, t4, t5, t6, t7, t8, t9, t10, t11; - -#test different values of ROW_FORMAT with KEY_BLOCK_SIZE -create table t1 (id int primary key) engine = innodb -key_block_size = 8 row_format = compressed; - ---error ER_CANT_CREATE_TABLE -create table t2 (id int primary key) engine = innodb -key_block_size = 8 row_format = redundant; -show errors; - ---error ER_CANT_CREATE_TABLE -create table t3 (id int primary key) engine = innodb -key_block_size = 8 row_format = compact; -show errors; - ---error ER_CANT_CREATE_TABLE -create table t4 (id int primary key) engine = innodb -key_block_size = 8 row_format = dynamic; -show errors; - ---error ER_CANT_CREATE_TABLE -create table t5 (id int primary key) engine = innodb -key_block_size = 8 row_format = default; -show errors; - -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -drop table t1; - -#test multiple errors ---error ER_CANT_CREATE_TABLE -create table t1 (id int primary key) engine = innodb -key_block_size = 9 row_format = redundant; -show errors; - ---error ER_CANT_CREATE_TABLE -create table t2 (id int primary key) engine = innodb -key_block_size = 9 row_format = compact; -show errors; - ---error ER_CANT_CREATE_TABLE -create table t2 (id int primary key) engine = innodb -key_block_size = 9 row_format = dynamic; -show errors; - -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; - -#test valid values with innodb_file_per_table unset -set global innodb_file_per_table = off; - ---error ER_CANT_CREATE_TABLE -create table t1 (id int primary key) engine = innodb key_block_size = 1; -show errors; ---error ER_CANT_CREATE_TABLE -create table t2 (id int primary key) engine = innodb key_block_size = 2; -show errors; ---error ER_CANT_CREATE_TABLE -create table t3 (id int primary key) engine = innodb key_block_size = 4; -show errors; ---error ER_CANT_CREATE_TABLE -create table t4 (id int primary key) engine = innodb key_block_size = 8; -show errors; ---error ER_CANT_CREATE_TABLE -create table t5 (id int primary key) engine = innodb key_block_size = 16; -show errors; ---error ER_CANT_CREATE_TABLE -create table t6 (id int primary key) engine = innodb row_format = compressed; -show errors; ---error ER_CANT_CREATE_TABLE -create table t7 (id int primary key) engine = innodb row_format = dynamic; -show errors; -create table t8 (id int primary key) engine = innodb row_format = compact; -create table t9 (id int primary key) engine = innodb row_format = redundant; - -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -drop table t8, t9; - -#test valid values with innodb_file_format unset -set global innodb_file_per_table = on; -set global innodb_file_format = `0`; - ---error ER_CANT_CREATE_TABLE -create table t1 (id int primary key) engine = innodb key_block_size = 1; -show errors; ---error ER_CANT_CREATE_TABLE -create table t2 (id int primary key) engine = innodb key_block_size = 2; -show errors; ---error ER_CANT_CREATE_TABLE -create table t3 (id int primary key) engine = innodb key_block_size = 4; -show errors; ---error ER_CANT_CREATE_TABLE -create table t4 (id int primary key) engine = innodb key_block_size = 8; -show errors; ---error ER_CANT_CREATE_TABLE -create table t5 (id int primary key) engine = innodb key_block_size = 16; -show errors; ---error ER_CANT_CREATE_TABLE -create table t6 (id int primary key) engine = innodb row_format = compressed; -show errors; ---error ER_CANT_CREATE_TABLE -create table t7 (id int primary key) engine = innodb row_format = dynamic; -show errors; -create table t8 (id int primary key) engine = innodb row_format = compact; -create table t9 (id int primary key) engine = innodb row_format = redundant; - -SELECT table_schema, table_name, row_format -FROM information_schema.tables WHERE engine='innodb'; -drop table t8, t9; - -eval set global innodb_file_per_table=$per_table; -eval set global innodb_file_format=$format; -# -# Testing of tablespace tagging -# --- disable_info -set global innodb_file_per_table=on; -set global innodb_file_format=`Barracuda`; -set global innodb_file_format_check=`Antelope`; -create table normal_table ( - c1 int -) engine = innodb; -select @@innodb_file_format_check; -create table zip_table ( - c1 int -) engine = innodb key_block_size = 8; -select @@innodb_file_format_check; -set global innodb_file_format_check=`Antelope`; -select @@innodb_file_format_check; --- disable_result_log -show table status; --- enable_result_log -select @@innodb_file_format_check; -drop table normal_table, zip_table; --- disable_result_log - -# -# restore environment to the state it was before this test execution -# - --- disable_query_log -eval set global innodb_file_format=$format; -eval set global innodb_file_per_table=$per_table; -eval set global innodb_file_format_check=$innodb_file_format_check_orig; diff --git a/storage/innobase/mysql-test/innodb.result b/storage/innobase/mysql-test/innodb.result deleted file mode 100644 index bdae7633fd1..00000000000 --- a/storage/innobase/mysql-test/innodb.result +++ /dev/null @@ -1,3310 +0,0 @@ -drop table if exists t1,t2,t3,t4; -drop database if exists mysqltest; -create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) engine=innodb; -insert into t1 (code, name) values (1, 'Tim'), (1, 'Monty'), (2, 'David'), (2, 'Erik'), (3, 'Sasha'), (3, 'Jeremy'), (4, 'Matt'); -select id, code, name from t1 order by id; -id code name -1 1 Tim -2 1 Monty -3 2 David -4 2 Erik -5 3 Sasha -6 3 Jeremy -7 4 Matt -update ignore t1 set id = 8, name = 'Sinisa' where id < 3; -select id, code, name from t1 order by id; -id code name -2 1 Monty -3 2 David -4 2 Erik -5 3 Sasha -6 3 Jeremy -7 4 Matt -8 1 Sinisa -update ignore t1 set id = id + 10, name = 'Ralph' where id < 4; -select id, code, name from t1 order by id; -id code name -3 2 David -4 2 Erik -5 3 Sasha -6 3 Jeremy -7 4 Matt -8 1 Sinisa -12 1 Ralph -drop table t1; -CREATE TABLE t1 ( -id int(11) NOT NULL auto_increment, -parent_id int(11) DEFAULT '0' NOT NULL, -level tinyint(4) DEFAULT '0' NOT NULL, -PRIMARY KEY (id), -KEY parent_id (parent_id), -KEY level (level) -) engine=innodb; -INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),(24,4,2),(28,5,2),(29,5,2),(30,5,2),(31,6,2),(32,6,2),(33,6,2),(203,7,2),(202,7,2),(20,3,2),(157,0,0),(193,5,2),(40,7,2),(2,1,1),(15,2,2),(6,1,1),(34,6,2),(35,6,2),(16,3,2),(7,1,1),(36,7,2),(18,3,2),(26,5,2),(27,5,2),(183,4,2),(38,7,2),(25,5,2),(37,7,2),(21,4,2),(19,3,2),(5,1,1),(179,5,2); -update t1 set parent_id=parent_id+100; -select * from t1 where parent_id=102; -id parent_id level -8 102 2 -9 102 2 -15 102 2 -update t1 set id=id+1000; -update t1 set id=1024 where id=1009; -Got one of the listed errors -select * from t1; -id parent_id level -1001 100 0 -1002 101 1 -1003 101 1 -1004 101 1 -1005 101 1 -1006 101 1 -1007 101 1 -1008 102 2 -1009 102 2 -1015 102 2 -1016 103 2 -1017 103 2 -1018 103 2 -1019 103 2 -1020 103 2 -1021 104 2 -1022 104 2 -1024 104 2 -1025 105 2 -1026 105 2 -1027 105 2 -1028 105 2 -1029 105 2 -1030 105 2 -1031 106 2 -1032 106 2 -1033 106 2 -1034 106 2 -1035 106 2 -1036 107 2 -1037 107 2 -1038 107 2 -1040 107 2 -1157 100 0 -1179 105 2 -1183 104 2 -1193 105 2 -1202 107 2 -1203 107 2 -update ignore t1 set id=id+1; -select * from t1; -id parent_id level -1001 100 0 -1002 101 1 -1003 101 1 -1004 101 1 -1005 101 1 -1006 101 1 -1007 101 1 -1008 102 2 -1010 102 2 -1015 102 2 -1016 103 2 -1017 103 2 -1018 103 2 -1019 103 2 -1020 103 2 -1021 104 2 -1023 104 2 -1024 104 2 -1025 105 2 -1026 105 2 -1027 105 2 -1028 105 2 -1029 105 2 -1030 105 2 -1031 106 2 -1032 106 2 -1033 106 2 -1034 106 2 -1035 106 2 -1036 107 2 -1037 107 2 -1039 107 2 -1041 107 2 -1158 100 0 -1180 105 2 -1184 104 2 -1194 105 2 -1202 107 2 -1204 107 2 -update ignore t1 set id=1023 where id=1010; -select * from t1 where parent_id=102; -id parent_id level -1008 102 2 -1010 102 2 -1015 102 2 -explain select level from t1 where level=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref level level 1 const # Using index -explain select level,id from t1 where level=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref level level 1 const # Using index -explain select level,id,parent_id from t1 where level=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref level level 1 const # -select level,id from t1 where level=1; -level id -1 1002 -1 1003 -1 1004 -1 1005 -1 1006 -1 1007 -select level,id,parent_id from t1 where level=1; -level id parent_id -1 1002 101 -1 1003 101 -1 1004 101 -1 1005 101 -1 1006 101 -1 1007 101 -optimize table t1; -Table Op Msg_type Msg_text -test.t1 optimize note Table does not support optimize, doing recreate + analyze instead -test.t1 optimize status OK -show keys from t1; -Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment -t1 0 PRIMARY 1 id A # NULL NULL BTREE -t1 1 parent_id 1 parent_id A # NULL NULL BTREE -t1 1 level 1 level A # NULL NULL BTREE -drop table t1; -CREATE TABLE t1 ( -gesuchnr int(11) DEFAULT '0' NOT NULL, -benutzer_id int(11) DEFAULT '0' NOT NULL, -PRIMARY KEY (gesuchnr,benutzer_id) -) engine=innodb; -replace into t1 (gesuchnr,benutzer_id) values (2,1); -replace into t1 (gesuchnr,benutzer_id) values (1,1); -replace into t1 (gesuchnr,benutzer_id) values (1,1); -select * from t1; -gesuchnr benutzer_id -1 1 -2 1 -drop table t1; -create table t1 (a int) engine=innodb; -insert into t1 values (1), (2); -optimize table t1; -Table Op Msg_type Msg_text -test.t1 optimize note Table does not support optimize, doing recreate + analyze instead -test.t1 optimize status OK -delete from t1 where a = 1; -select * from t1; -a -2 -check table t1; -Table Op Msg_type Msg_text -test.t1 check status OK -drop table t1; -create table t1 (a int,b varchar(20)) engine=innodb; -insert into t1 values (1,""), (2,"testing"); -delete from t1 where a = 1; -select * from t1; -a b -2 testing -create index skr on t1 (a); -insert into t1 values (3,""), (4,"testing"); -analyze table t1; -Table Op Msg_type Msg_text -test.t1 analyze status OK -show keys from t1; -Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment -t1 1 skr 1 a A # NULL NULL YES BTREE -drop table t1; -create table t1 (a int,b varchar(20),key(a)) engine=innodb; -insert into t1 values (1,""), (2,"testing"); -select * from t1 where a = 1; -a b -1 -drop table t1; -create table t1 (n int not null primary key) engine=innodb; -set autocommit=0; -insert into t1 values (4); -rollback; -select n, "after rollback" from t1; -n after rollback -insert into t1 values (4); -commit; -select n, "after commit" from t1; -n after commit -4 after commit -commit; -insert into t1 values (5); -insert into t1 values (4); -ERROR 23000: Duplicate entry '4' for key 'PRIMARY' -commit; -select n, "after commit" from t1; -n after commit -4 after commit -5 after commit -set autocommit=1; -insert into t1 values (6); -insert into t1 values (4); -ERROR 23000: Duplicate entry '4' for key 'PRIMARY' -select n from t1; -n -4 -5 -6 -set autocommit=0; -begin; -savepoint `my_savepoint`; -insert into t1 values (7); -savepoint `savept2`; -insert into t1 values (3); -select n from t1; -n -3 -4 -5 -6 -7 -savepoint savept3; -rollback to savepoint savept2; -rollback to savepoint savept3; -ERROR 42000: SAVEPOINT savept3 does not exist -rollback to savepoint savept2; -release savepoint `my_savepoint`; -select n from t1; -n -4 -5 -6 -7 -rollback to savepoint `my_savepoint`; -ERROR 42000: SAVEPOINT my_savepoint does not exist -rollback to savepoint savept2; -ERROR 42000: SAVEPOINT savept2 does not exist -insert into t1 values (8); -savepoint sv; -commit; -savepoint sv; -set autocommit=1; -rollback; -drop table t1; -create table t1 (n int not null primary key) engine=innodb; -start transaction; -insert into t1 values (4); -flush tables with read lock; -commit; -unlock tables; -commit; -select * from t1; -n -4 -drop table t1; -create table t1 ( id int NOT NULL PRIMARY KEY, nom varchar(64)) engine=innodb; -begin; -insert into t1 values(1,'hamdouni'); -select id as afterbegin_id,nom as afterbegin_nom from t1; -afterbegin_id afterbegin_nom -1 hamdouni -rollback; -select id as afterrollback_id,nom as afterrollback_nom from t1; -afterrollback_id afterrollback_nom -set autocommit=0; -insert into t1 values(2,'mysql'); -select id as afterautocommit0_id,nom as afterautocommit0_nom from t1; -afterautocommit0_id afterautocommit0_nom -2 mysql -rollback; -select id as afterrollback_id,nom as afterrollback_nom from t1; -afterrollback_id afterrollback_nom -set autocommit=1; -drop table t1; -CREATE TABLE t1 (id char(8) not null primary key, val int not null) engine=innodb; -insert into t1 values ('pippo', 12); -insert into t1 values ('pippo', 12); -ERROR 23000: Duplicate entry 'pippo' for key 'PRIMARY' -delete from t1; -delete from t1 where id = 'pippo'; -select * from t1; -id val -insert into t1 values ('pippo', 12); -set autocommit=0; -delete from t1; -rollback; -select * from t1; -id val -pippo 12 -delete from t1; -commit; -select * from t1; -id val -drop table t1; -create table t1 (a integer) engine=innodb; -start transaction; -rename table t1 to t2; -create table t1 (b integer) engine=innodb; -insert into t1 values (1); -rollback; -drop table t1; -rename table t2 to t1; -drop table t1; -set autocommit=1; -CREATE TABLE t1 (ID INTEGER NOT NULL PRIMARY KEY, NAME VARCHAR(64)) ENGINE=innodb; -INSERT INTO t1 VALUES (1, 'Jochen'); -select * from t1; -ID NAME -1 Jochen -drop table t1; -CREATE TABLE t1 ( _userid VARCHAR(60) NOT NULL PRIMARY KEY) ENGINE=innodb; -set autocommit=0; -INSERT INTO t1 SET _userid='marc@anyware.co.uk'; -COMMIT; -SELECT * FROM t1; -_userid -marc@anyware.co.uk -SELECT _userid FROM t1 WHERE _userid='marc@anyware.co.uk'; -_userid -marc@anyware.co.uk -drop table t1; -set autocommit=1; -CREATE TABLE t1 ( -user_id int(10) DEFAULT '0' NOT NULL, -name varchar(100), -phone varchar(100), -ref_email varchar(100) DEFAULT '' NOT NULL, -detail varchar(200), -PRIMARY KEY (user_id,ref_email) -)engine=innodb; -INSERT INTO t1 VALUES (10292,'sanjeev','29153373','sansh777@hotmail.com','xxx'),(10292,'shirish','2333604','shirish@yahoo.com','ddsds'),(10292,'sonali','323232','sonali@bolly.com','filmstar'); -select * from t1 where user_id=10292; -user_id name phone ref_email detail -10292 sanjeev 29153373 sansh777@hotmail.com xxx -10292 shirish 2333604 shirish@yahoo.com ddsds -10292 sonali 323232 sonali@bolly.com filmstar -INSERT INTO t1 VALUES (10291,'sanjeev','29153373','sansh777@hotmail.com','xxx'),(10293,'shirish','2333604','shirish@yahoo.com','ddsds'); -select * from t1 where user_id=10292; -user_id name phone ref_email detail -10292 sanjeev 29153373 sansh777@hotmail.com xxx -10292 shirish 2333604 shirish@yahoo.com ddsds -10292 sonali 323232 sonali@bolly.com filmstar -select * from t1 where user_id>=10292; -user_id name phone ref_email detail -10292 sanjeev 29153373 sansh777@hotmail.com xxx -10292 shirish 2333604 shirish@yahoo.com ddsds -10292 sonali 323232 sonali@bolly.com filmstar -10293 shirish 2333604 shirish@yahoo.com ddsds -select * from t1 where user_id>10292; -user_id name phone ref_email detail -10293 shirish 2333604 shirish@yahoo.com ddsds -select * from t1 where user_id<10292; -user_id name phone ref_email detail -10291 sanjeev 29153373 sansh777@hotmail.com xxx -drop table t1; -CREATE TABLE t1 (a int not null, b int not null,c int not null, -key(a),primary key(a,b), unique(c),key(a),unique(b)); -show index from t1; -Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment -t1 0 PRIMARY 1 a A # NULL NULL BTREE -t1 0 PRIMARY 2 b A # NULL NULL BTREE -t1 0 c 1 c A # NULL NULL BTREE -t1 0 b 1 b A # NULL NULL BTREE -t1 1 a 1 a A # NULL NULL BTREE -t1 1 a_2 1 a A # NULL NULL BTREE -drop table t1; -create table t1 (col1 int not null, col2 char(4) not null, primary key(col1)); -alter table t1 engine=innodb; -insert into t1 values ('1','1'),('5','2'),('2','3'),('3','4'),('4','4'); -select * from t1; -col1 col2 -1 1 -2 3 -3 4 -4 4 -5 2 -update t1 set col2='7' where col1='4'; -select * from t1; -col1 col2 -1 1 -2 3 -3 4 -4 7 -5 2 -alter table t1 add co3 int not null; -select * from t1; -col1 col2 co3 -1 1 0 -2 3 0 -3 4 0 -4 7 0 -5 2 0 -update t1 set col2='9' where col1='2'; -select * from t1; -col1 col2 co3 -1 1 0 -2 9 0 -3 4 0 -4 7 0 -5 2 0 -drop table t1; -create table t1 (a int not null , b int, primary key (a)) engine = innodb; -create table t2 (a int not null , b int, primary key (a)) engine = myisam; -insert into t1 VALUES (1,3) , (2,3), (3,3); -select * from t1; -a b -1 3 -2 3 -3 3 -insert into t2 select * from t1; -select * from t2; -a b -1 3 -2 3 -3 3 -delete from t1 where b = 3; -select * from t1; -a b -insert into t1 select * from t2; -select * from t1; -a b -1 3 -2 3 -3 3 -select * from t2; -a b -1 3 -2 3 -3 3 -drop table t1,t2; -CREATE TABLE t1 ( -user_name varchar(12), -password text, -subscribed char(1), -user_id int(11) DEFAULT '0' NOT NULL, -quota bigint(20), -weight double, -access_date date, -access_time time, -approved datetime, -dummy_primary_key int(11) NOT NULL auto_increment, -PRIMARY KEY (dummy_primary_key) -) ENGINE=innodb; -INSERT INTO t1 VALUES ('user_0','somepassword','N',0,0,0,'2000-09-07','23:06:59','2000-09-07 23:06:59',1); -INSERT INTO t1 VALUES ('user_1','somepassword','Y',1,1,1,'2000-09-07','23:06:59','2000-09-07 23:06:59',2); -INSERT INTO t1 VALUES ('user_2','somepassword','N',2,2,1.4142135623731,'2000-09-07','23:06:59','2000-09-07 23:06:59',3); -INSERT INTO t1 VALUES ('user_3','somepassword','Y',3,3,1.7320508075689,'2000-09-07','23:06:59','2000-09-07 23:06:59',4); -INSERT INTO t1 VALUES ('user_4','somepassword','N',4,4,2,'2000-09-07','23:06:59','2000-09-07 23:06:59',5); -select user_name, password , subscribed, user_id, quota, weight, access_date, access_time, approved, dummy_primary_key from t1 order by user_name; -user_name password subscribed user_id quota weight access_date access_time approved dummy_primary_key -user_0 somepassword N 0 0 0 2000-09-07 23:06:59 2000-09-07 23:06:59 1 -user_1 somepassword Y 1 1 1 2000-09-07 23:06:59 2000-09-07 23:06:59 2 -user_2 somepassword N 2 2 1.4142135623731 2000-09-07 23:06:59 2000-09-07 23:06:59 3 -user_3 somepassword Y 3 3 1.7320508075689 2000-09-07 23:06:59 2000-09-07 23:06:59 4 -user_4 somepassword N 4 4 2 2000-09-07 23:06:59 2000-09-07 23:06:59 5 -drop table t1; -CREATE TABLE t1 ( -id int(11) NOT NULL auto_increment, -parent_id int(11) DEFAULT '0' NOT NULL, -level tinyint(4) DEFAULT '0' NOT NULL, -KEY (id), -KEY parent_id (parent_id), -KEY level (level) -) engine=innodb; -INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),(24,4,2),(28,5,2),(29,5,2),(30,5,2),(31,6,2),(32,6,2),(33,6,2),(203,7,2),(202,7,2),(20,3,2),(157,0,0),(193,5,2),(40,7,2),(2,1,1),(15,2,2),(6,1,1),(34,6,2),(35,6,2),(16,3,2),(7,1,1),(36,7,2),(18,3,2),(26,5,2),(27,5,2),(183,4,2),(38,7,2),(25,5,2),(37,7,2),(21,4,2),(19,3,2),(5,1,1); -INSERT INTO t1 values (179,5,2); -update t1 set parent_id=parent_id+100; -select * from t1 where parent_id=102; -id parent_id level -8 102 2 -9 102 2 -15 102 2 -update t1 set id=id+1000; -update t1 set id=1024 where id=1009; -select * from t1; -id parent_id level -1001 100 0 -1003 101 1 -1004 101 1 -1008 102 2 -1024 102 2 -1017 103 2 -1022 104 2 -1024 104 2 -1028 105 2 -1029 105 2 -1030 105 2 -1031 106 2 -1032 106 2 -1033 106 2 -1203 107 2 -1202 107 2 -1020 103 2 -1157 100 0 -1193 105 2 -1040 107 2 -1002 101 1 -1015 102 2 -1006 101 1 -1034 106 2 -1035 106 2 -1016 103 2 -1007 101 1 -1036 107 2 -1018 103 2 -1026 105 2 -1027 105 2 -1183 104 2 -1038 107 2 -1025 105 2 -1037 107 2 -1021 104 2 -1019 103 2 -1005 101 1 -1179 105 2 -update ignore t1 set id=id+1; -select * from t1; -id parent_id level -1002 100 0 -1004 101 1 -1005 101 1 -1009 102 2 -1025 102 2 -1018 103 2 -1023 104 2 -1025 104 2 -1029 105 2 -1030 105 2 -1031 105 2 -1032 106 2 -1033 106 2 -1034 106 2 -1204 107 2 -1203 107 2 -1021 103 2 -1158 100 0 -1194 105 2 -1041 107 2 -1003 101 1 -1016 102 2 -1007 101 1 -1035 106 2 -1036 106 2 -1017 103 2 -1008 101 1 -1037 107 2 -1019 103 2 -1027 105 2 -1028 105 2 -1184 104 2 -1039 107 2 -1026 105 2 -1038 107 2 -1022 104 2 -1020 103 2 -1006 101 1 -1180 105 2 -update ignore t1 set id=1023 where id=1010; -select * from t1 where parent_id=102; -id parent_id level -1009 102 2 -1025 102 2 -1016 102 2 -explain select level from t1 where level=1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref level level 1 const # Using index -select level,id from t1 where level=1; -level id -1 1004 -1 1005 -1 1003 -1 1007 -1 1008 -1 1006 -select level,id,parent_id from t1 where level=1; -level id parent_id -1 1004 101 -1 1005 101 -1 1003 101 -1 1007 101 -1 1008 101 -1 1006 101 -select level,id from t1 where level=1 order by id; -level id -1 1003 -1 1004 -1 1005 -1 1006 -1 1007 -1 1008 -delete from t1 where level=1; -select * from t1; -id parent_id level -1002 100 0 -1009 102 2 -1025 102 2 -1018 103 2 -1023 104 2 -1025 104 2 -1029 105 2 -1030 105 2 -1031 105 2 -1032 106 2 -1033 106 2 -1034 106 2 -1204 107 2 -1203 107 2 -1021 103 2 -1158 100 0 -1194 105 2 -1041 107 2 -1016 102 2 -1035 106 2 -1036 106 2 -1017 103 2 -1037 107 2 -1019 103 2 -1027 105 2 -1028 105 2 -1184 104 2 -1039 107 2 -1026 105 2 -1038 107 2 -1022 104 2 -1020 103 2 -1180 105 2 -drop table t1; -CREATE TABLE t1 ( -sca_code char(6) NOT NULL, -cat_code char(6) NOT NULL, -sca_desc varchar(50), -lan_code char(2) NOT NULL, -sca_pic varchar(100), -sca_sdesc varchar(50), -sca_sch_desc varchar(16), -PRIMARY KEY (sca_code, cat_code, lan_code), -INDEX sca_pic (sca_pic) -) engine = innodb ; -INSERT INTO t1 ( sca_code, cat_code, sca_desc, lan_code, sca_pic, sca_sdesc, sca_sch_desc) VALUES ( 'PD', 'J', 'PENDANT', 'EN', NULL, NULL, 'PENDANT'),( 'RI', 'J', 'RING', 'EN', NULL, NULL, 'RING'),( 'QQ', 'N', 'RING', 'EN', 'not null', NULL, 'RING'); -select count(*) from t1 where sca_code = 'PD'; -count(*) -1 -select count(*) from t1 where sca_code <= 'PD'; -count(*) -1 -select count(*) from t1 where sca_pic is null; -count(*) -2 -alter table t1 drop index sca_pic, add index sca_pic (cat_code, sca_pic); -select count(*) from t1 where sca_code='PD' and sca_pic is null; -count(*) -1 -select count(*) from t1 where cat_code='E'; -count(*) -0 -alter table t1 drop index sca_pic, add index (sca_pic, cat_code); -select count(*) from t1 where sca_code='PD' and sca_pic is null; -count(*) -1 -select count(*) from t1 where sca_pic >= 'n'; -count(*) -1 -select sca_pic from t1 where sca_pic is null; -sca_pic -NULL -NULL -update t1 set sca_pic="test" where sca_pic is null; -delete from t1 where sca_code='pd'; -drop table t1; -set @a:=now(); -CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) engine=innodb; -insert into t1 (a) values(1),(2),(3); -select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a; -a -1 -2 -3 -select a from t1 natural join t1 as t2 where b >= @a order by a; -a -1 -2 -3 -update t1 set a=5 where a=1; -select a from t1; -a -2 -3 -5 -drop table t1; -create table t1 (a varchar(100) not null, primary key(a), b int not null) engine=innodb; -insert into t1 values("hello",1),("world",2); -select * from t1 order by b desc; -a b -world 2 -hello 1 -optimize table t1; -Table Op Msg_type Msg_text -test.t1 optimize note Table does not support optimize, doing recreate + analyze instead -test.t1 optimize status OK -show keys from t1; -Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment -t1 0 PRIMARY 1 a A # NULL NULL BTREE -drop table t1; -create table t1 (i int, j int ) ENGINE=innodb; -insert into t1 values (1,2); -select * from t1 where i=1 and j=2; -i j -1 2 -create index ax1 on t1 (i,j); -select * from t1 where i=1 and j=2; -i j -1 2 -drop table t1; -CREATE TABLE t1 ( -a int3 unsigned NOT NULL, -b int1 unsigned NOT NULL, -UNIQUE (a, b) -) ENGINE = innodb; -INSERT INTO t1 VALUES (1, 1); -SELECT MIN(B),MAX(b) FROM t1 WHERE t1.a = 1; -MIN(B) MAX(b) -1 1 -drop table t1; -CREATE TABLE t1 (a int unsigned NOT NULL) engine=innodb; -INSERT INTO t1 VALUES (1); -SELECT * FROM t1; -a -1 -DROP TABLE t1; -create table t1 (a int primary key,b int, c int, d int, e int, f int, g int, h int, i int, j int, k int, l int, m int, n int, o int, p int, q int, r int, s int, t int, u int, v int, w int, x int, y int, z int, a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, b1 int, b2 int, b3 int, b4 int, b5 int, b6 int) engine = innodb; -insert into t1 values (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1); -explain select * from t1 where a > 0 and a < 50; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL # Using where -drop table t1; -create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) engine=innodb; -insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL'); -LOCK TABLES t1 WRITE; -insert into t1 values (99,1,2,'D'),(1,1,2,'D'); -ERROR 23000: Duplicate entry '1-1' for key 'PRIMARY' -select id from t1; -id -0 -1 -2 -select id from t1; -id -0 -1 -2 -UNLOCK TABLES; -DROP TABLE t1; -create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) engine=innodb; -insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL'); -LOCK TABLES t1 WRITE; -begin; -insert into t1 values (99,1,2,'D'),(1,1,2,'D'); -ERROR 23000: Duplicate entry '1-1' for key 'PRIMARY' -select id from t1; -id -0 -1 -2 -insert ignore into t1 values (100,1,2,'D'),(1,1,99,'D'); -commit; -select id,id3 from t1; -id id3 -0 0 -1 1 -2 2 -100 2 -UNLOCK TABLES; -DROP TABLE t1; -create table t1 (a char(20), unique (a(5))) engine=innodb; -drop table t1; -create table t1 (a char(20), index (a(5))) engine=innodb; -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` char(20) DEFAULT NULL, - KEY `a` (`a`(5)) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1; -create temporary table t1 (a int not null auto_increment, primary key(a)) engine=innodb; -insert into t1 values (NULL),(NULL),(NULL); -delete from t1 where a=3; -insert into t1 values (NULL); -select * from t1; -a -1 -2 -4 -alter table t1 add b int; -select * from t1; -a b -1 NULL -2 NULL -4 NULL -drop table t1; -create table t1 -( -id int auto_increment primary key, -name varchar(32) not null, -value text not null, -uid int not null, -unique key(name,uid) -) engine=innodb; -insert into t1 values (1,'one','one value',101), -(2,'two','two value',102),(3,'three','three value',103); -set insert_id=5; -replace into t1 (value,name,uid) values ('other value','two',102); -delete from t1 where uid=102; -set insert_id=5; -replace into t1 (value,name,uid) values ('other value','two',102); -set insert_id=6; -replace into t1 (value,name,uid) values ('other value','two',102); -select * from t1; -id name value uid -1 one one value 101 -3 three three value 103 -6 two other value 102 -drop table t1; -create database mysqltest; -create table mysqltest.t1 (a int not null) engine= innodb; -insert into mysqltest.t1 values(1); -create table mysqltest.t2 (a int not null) engine= myisam; -insert into mysqltest.t2 values(1); -create table mysqltest.t3 (a int not null) engine= heap; -insert into mysqltest.t3 values(1); -commit; -drop database mysqltest; -show tables from mysqltest; -ERROR 42000: Unknown database 'mysqltest' -set autocommit=0; -create table t1 (a int not null) engine= innodb; -insert into t1 values(1),(2); -truncate table t1; -commit; -truncate table t1; -truncate table t1; -select * from t1; -a -insert into t1 values(1),(2); -delete from t1; -select * from t1; -a -commit; -drop table t1; -set autocommit=1; -create table t1 (a int not null) engine= innodb; -insert into t1 values(1),(2); -truncate table t1; -insert into t1 values(1),(2); -select * from t1; -a -1 -2 -truncate table t1; -insert into t1 values(1),(2); -delete from t1; -select * from t1; -a -drop table t1; -create table t1 (a int not null, b int not null, c int not null, primary key (a),key(b)) engine=innodb; -insert into t1 values (3,3,3),(1,1,1),(2,2,2),(4,4,4); -explain select * from t1 order by a; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 4 NULL # -explain select * from t1 order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL # Using filesort -explain select * from t1 order by c; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL # Using filesort -explain select a from t1 order by a; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL PRIMARY 4 NULL # Using index -explain select b from t1 order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 4 NULL # Using index -explain select a,b from t1 order by b; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 4 NULL # Using index -explain select a,b from t1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL b 4 NULL # Using index -explain select a,b,c from t1; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL # -drop table t1; -create table t1 (t int not null default 1, key (t)) engine=innodb; -desc t1; -Field Type Null Key Default Extra -t int(11) NO MUL 1 -drop table t1; -CREATE TABLE t1 ( -number bigint(20) NOT NULL default '0', -cname char(15) NOT NULL default '', -carrier_id smallint(6) NOT NULL default '0', -privacy tinyint(4) NOT NULL default '0', -last_mod_date timestamp NOT NULL, -last_mod_id smallint(6) NOT NULL default '0', -last_app_date timestamp NOT NULL, -last_app_id smallint(6) default '-1', -version smallint(6) NOT NULL default '0', -assigned_scps int(11) default '0', -status tinyint(4) default '0' -) ENGINE=InnoDB; -INSERT INTO t1 VALUES (4077711111,'SeanWheeler',90,2,20020111112846,500,00000000000000,-1,2,3,1); -INSERT INTO t1 VALUES (9197722223,'berry',90,3,20020111112809,500,20020102114532,501,4,10,0); -INSERT INTO t1 VALUES (650,'San Francisco',0,0,20011227111336,342,00000000000000,-1,1,24,1); -INSERT INTO t1 VALUES (302467,'Sue\'s Subshop',90,3,20020109113241,500,20020102115111,501,7,24,0); -INSERT INTO t1 VALUES (6014911113,'SudzCarwash',520,1,20020102115234,500,20020102115259,501,33,32768,0); -INSERT INTO t1 VALUES (333,'tubs',99,2,20020109113440,501,20020109113440,500,3,10,0); -CREATE TABLE t2 ( -number bigint(20) NOT NULL default '0', -cname char(15) NOT NULL default '', -carrier_id smallint(6) NOT NULL default '0', -privacy tinyint(4) NOT NULL default '0', -last_mod_date timestamp NOT NULL, -last_mod_id smallint(6) NOT NULL default '0', -last_app_date timestamp NOT NULL, -last_app_id smallint(6) default '-1', -version smallint(6) NOT NULL default '0', -assigned_scps int(11) default '0', -status tinyint(4) default '0' -) ENGINE=InnoDB; -INSERT INTO t2 VALUES (4077711111,'SeanWheeler',0,2,20020111112853,500,00000000000000,-1,2,3,1); -INSERT INTO t2 VALUES (9197722223,'berry',90,3,20020111112818,500,20020102114532,501,4,10,0); -INSERT INTO t2 VALUES (650,'San Francisco',90,0,20020109113158,342,00000000000000,-1,1,24,1); -INSERT INTO t2 VALUES (333,'tubs',99,2,20020109113453,501,20020109113453,500,3,10,0); -select * from t1; -number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status -4077711111 SeanWheeler 90 2 2002-01-11 11:28:46 500 0000-00-00 00:00:00 -1 2 3 1 -9197722223 berry 90 3 2002-01-11 11:28:09 500 2002-01-02 11:45:32 501 4 10 0 -650 San Francisco 0 0 2001-12-27 11:13:36 342 0000-00-00 00:00:00 -1 1 24 1 -302467 Sue's Subshop 90 3 2002-01-09 11:32:41 500 2002-01-02 11:51:11 501 7 24 0 -6014911113 SudzCarwash 520 1 2002-01-02 11:52:34 500 2002-01-02 11:52:59 501 33 32768 0 -333 tubs 99 2 2002-01-09 11:34:40 501 2002-01-09 11:34:40 500 3 10 0 -select * from t2; -number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status -4077711111 SeanWheeler 0 2 2002-01-11 11:28:53 500 0000-00-00 00:00:00 -1 2 3 1 -9197722223 berry 90 3 2002-01-11 11:28:18 500 2002-01-02 11:45:32 501 4 10 0 -650 San Francisco 90 0 2002-01-09 11:31:58 342 0000-00-00 00:00:00 -1 1 24 1 -333 tubs 99 2 2002-01-09 11:34:53 501 2002-01-09 11:34:53 500 3 10 0 -delete t1, t2 from t1 left join t2 on t1.number=t2.number where (t1.carrier_id=90 and t1.number=t2.number) or (t2.carrier_id=90 and t1.number=t2.number) or (t1.carrier_id=90 and t2.number is null); -select * from t1; -number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status -6014911113 SudzCarwash 520 1 2002-01-02 11:52:34 500 2002-01-02 11:52:59 501 33 32768 0 -333 tubs 99 2 2002-01-09 11:34:40 501 2002-01-09 11:34:40 500 3 10 0 -select * from t2; -number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status -333 tubs 99 2 2002-01-09 11:34:53 501 2002-01-09 11:34:53 500 3 10 0 -select * from t2; -number cname carrier_id privacy last_mod_date last_mod_id last_app_date last_app_id version assigned_scps status -333 tubs 99 2 2002-01-09 11:34:53 501 2002-01-09 11:34:53 500 3 10 0 -drop table t1,t2; -create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) engine=innodb; -BEGIN; -SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; -SELECT @@tx_isolation,@@global.tx_isolation; -@@tx_isolation @@global.tx_isolation -SERIALIZABLE REPEATABLE-READ -insert into t1 (code, name) values (1, 'Tim'), (1, 'Monty'), (2, 'David'); -select id, code, name from t1 order by id; -id code name -1 1 Tim -2 1 Monty -3 2 David -COMMIT; -BEGIN; -SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; -insert into t1 (code, name) values (2, 'Erik'), (3, 'Sasha'); -select id, code, name from t1 order by id; -id code name -1 1 Tim -2 1 Monty -3 2 David -4 2 Erik -5 3 Sasha -COMMIT; -SET binlog_format='MIXED'; -BEGIN; -SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -insert into t1 (code, name) values (3, 'Jeremy'), (4, 'Matt'); -select id, code, name from t1 order by id; -id code name -1 1 Tim -2 1 Monty -3 2 David -4 2 Erik -5 3 Sasha -6 3 Jeremy -7 4 Matt -COMMIT; -DROP TABLE t1; -create table t1 (n int(10), d int(10)) engine=innodb; -create table t2 (n int(10), d int(10)) engine=innodb; -insert into t1 values(1,1),(1,2); -insert into t2 values(1,10),(2,20); -UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; -select * from t1; -n d -1 10 -1 10 -select * from t2; -n d -1 30 -2 20 -drop table t1,t2; -drop table if exists t1, t2; -CREATE TABLE t1 (a int, PRIMARY KEY (a)); -CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -create trigger trg_del_t2 after delete on t2 for each row -insert into t1 values (1); -insert into t1 values (1); -insert into t2 values (1),(2); -delete t2 from t2; -ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -select count(*) from t2 /* must be 2 as restored after rollback caused by the error */; -count(*) -2 -drop table t1, t2; -drop table if exists t1, t2; -CREATE TABLE t1 (a int, PRIMARY KEY (a)); -CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -create trigger trg_del_t2 after delete on t2 for each row -insert into t1 values (1); -insert into t1 values (1); -insert into t2 values (1),(2); -delete t2 from t2; -ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -select count(*) from t2 /* must be 2 as restored after rollback caused by the error */; -count(*) -2 -drop table t1, t2; -create table t1 (a int, b int) engine=innodb; -insert into t1 values(20,null); -select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on -t2.b=t3.a; -b ifnull(t2.b,"this is null") -NULL this is null -select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on -t2.b=t3.a order by 1; -b ifnull(t2.b,"this is null") -NULL this is null -insert into t1 values(10,null); -select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on -t2.b=t3.a order by 1; -b ifnull(t2.b,"this is null") -NULL this is null -NULL this is null -drop table t1; -create table t1 (a varchar(10) not null) engine=myisam; -create table t2 (b varchar(10) not null unique) engine=innodb; -select t1.a from t1,t2 where t1.a=t2.b; -a -drop table t1,t2; -create table t1 (a int not null, b int, primary key (a)) engine = innodb; -create table t2 (a int not null, b int, primary key (a)) engine = innodb; -insert into t1 values (10, 20); -insert into t2 values (10, 20); -update t1, t2 set t1.b = 150, t2.b = t1.b where t2.a = t1.a and t1.a = 10; -drop table t1,t2; -CREATE TABLE t1 (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB; -CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), FOREIGN KEY (t1_id) REFERENCES t1(id) ON DELETE CASCADE ) ENGINE=INNODB; -insert into t1 set id=1; -insert into t2 set id=1, t1_id=1; -delete t1,t2 from t1,t2 where t1.id=t2.t1_id; -select * from t1; -id -select * from t2; -id t1_id -drop table t2,t1; -CREATE TABLE t1(id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB; -CREATE TABLE t2(id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id) ) ENGINE=INNODB; -INSERT INTO t1 VALUES(1); -INSERT INTO t2 VALUES(1, 1); -SELECT * from t1; -id -1 -UPDATE t1,t2 SET t1.id=t1.id+1, t2.t1_id=t1.id+1; -SELECT * from t1; -id -2 -UPDATE t1,t2 SET t1.id=t1.id+1 where t1.id!=t2.id; -SELECT * from t1; -id -3 -DROP TABLE t1,t2; -set autocommit=0; -CREATE TABLE t1 (id CHAR(15) NOT NULL, value CHAR(40) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB; -CREATE TABLE t2 (id CHAR(15) NOT NULL, value CHAR(40) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB; -CREATE TABLE t3 (id1 CHAR(15) NOT NULL, id2 CHAR(15) NOT NULL, PRIMARY KEY(id1, id2)) ENGINE=InnoDB; -INSERT INTO t3 VALUES("my-test-1", "my-test-2"); -COMMIT; -INSERT INTO t1 VALUES("this-key", "will disappear"); -INSERT INTO t2 VALUES("this-key", "will also disappear"); -DELETE FROM t3 WHERE id1="my-test-1"; -SELECT * FROM t1; -id value -this-key will disappear -SELECT * FROM t2; -id value -this-key will also disappear -SELECT * FROM t3; -id1 id2 -ROLLBACK; -SELECT * FROM t1; -id value -SELECT * FROM t2; -id value -SELECT * FROM t3; -id1 id2 -my-test-1 my-test-2 -SELECT * FROM t3 WHERE id1="my-test-1" LOCK IN SHARE MODE; -id1 id2 -my-test-1 my-test-2 -COMMIT; -set autocommit=1; -DROP TABLE t1,t2,t3; -CREATE TABLE t1 (a int not null primary key, b int not null, unique (b)) engine=innodb; -INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); -UPDATE t1 set a=a+100 where b between 2 and 3 and a < 1000; -SELECT * from t1; -a b -1 1 -102 2 -103 3 -4 4 -5 5 -6 6 -7 7 -8 8 -9 9 -drop table t1; -CREATE TABLE t1 (a int not null primary key, b int not null, key (b)) engine=innodb; -CREATE TABLE t2 (a int not null primary key, b int not null, key (b)) engine=innodb; -INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12); -INSERT INTO t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); -update t1,t2 set t1.a=t1.a+100; -select * from t1; -a b -101 1 -102 2 -103 3 -104 4 -105 5 -106 6 -107 7 -108 8 -109 9 -110 10 -111 11 -112 12 -update t1,t2 set t1.a=t1.a+100 where t1.a=101; -select * from t1; -a b -201 1 -102 2 -103 3 -104 4 -105 5 -106 6 -107 7 -108 8 -109 9 -110 10 -111 11 -112 12 -update t1,t2 set t1.b=t1.b+10 where t1.b=2; -select * from t1; -a b -201 1 -103 3 -104 4 -105 5 -106 6 -107 7 -108 8 -109 9 -110 10 -111 11 -102 12 -112 12 -update t1,t2 set t1.b=t1.b+2,t2.b=t1.b+10 where t1.b between 3 and 5 and t1.a=t2.a+100; -select * from t1; -a b -201 1 -103 5 -104 6 -106 6 -105 7 -107 7 -108 8 -109 9 -110 10 -111 11 -102 12 -112 12 -select * from t2; -a b -1 1 -2 2 -6 6 -7 7 -8 8 -9 9 -3 13 -4 14 -5 15 -drop table t1,t2; -CREATE TABLE t2 ( NEXT_T BIGINT NOT NULL PRIMARY KEY) ENGINE=MyISAM; -CREATE TABLE t1 ( B_ID INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; -SET AUTOCOMMIT=0; -INSERT INTO t1 ( B_ID ) VALUES ( 1 ); -INSERT INTO t2 ( NEXT_T ) VALUES ( 1 ); -ROLLBACK; -Warnings: -Warning 1196 Some non-transactional changed tables couldn't be rolled back -SELECT * FROM t1; -B_ID -drop table t1,t2; -create table t1 ( pk int primary key, parent int not null, child int not null, index (parent) ) engine = innodb; -insert into t1 values (1,0,4), (2,1,3), (3,2,1), (4,1,2); -select distinct parent,child from t1 order by parent; -parent child -0 4 -1 2 -1 3 -2 1 -drop table t1; -create table t1 (a int not null auto_increment primary key, b int, c int, key(c)) engine=innodb; -create table t2 (a int not null auto_increment primary key, b int); -insert into t1 (b) values (null),(null),(null),(null),(null),(null),(null); -insert into t2 (a) select b from t1; -insert into t1 (b) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -select count(*) from t1; -count(*) -623 -explain select * from t1 where c between 1 and 2500; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range c c 5 NULL # Using where -update t1 set c=a; -explain select * from t1 where c between 1 and 2500; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL c NULL NULL NULL # Using where -drop table t1,t2; -create table t1 (id int primary key auto_increment, fk int, index index_fk (fk)) engine=innodb; -insert into t1 (id) values (null),(null),(null),(null),(null); -update t1 set fk=69 where fk is null order by id limit 1; -SELECT * from t1; -id fk -2 NULL -3 NULL -4 NULL -5 NULL -1 69 -drop table t1; -create table t1 (a int not null, b int not null, key (a)); -insert into t1 values (1,1),(1,2),(1,3),(3,1),(3,2),(3,3),(3,1),(3,2),(3,3),(2,1),(2,2),(2,3); -SET @tmp=0; -update t1 set b=(@tmp:=@tmp+1) order by a; -update t1 set b=99 where a=1 order by b asc limit 1; -update t1 set b=100 where a=1 order by b desc limit 2; -update t1 set a=a+10+b where a=1 order by b; -select * from t1 order by a,b; -a b -2 4 -2 5 -2 6 -3 7 -3 8 -3 9 -3 10 -3 11 -3 12 -13 2 -111 100 -111 100 -drop table t1; -create table t1 ( c char(8) not null ) engine=innodb; -insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'); -insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F'); -alter table t1 add b char(8) not null; -alter table t1 add a char(8) not null; -alter table t1 add primary key (a,b,c); -update t1 set a=c, b=c; -create table t2 (c char(8) not null, b char(8) not null, a char(8) not null, primary key(a,b,c)) engine=innodb; -insert into t2 select * from t1; -delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b; -drop table t1,t2; -SET AUTOCOMMIT=1; -create table t1 (a integer auto_increment primary key) engine=innodb; -insert into t1 (a) values (NULL),(NULL); -truncate table t1; -insert into t1 (a) values (NULL),(NULL); -SELECT * from t1; -a -1 -2 -drop table t1; -CREATE TABLE t1 (`id 1` INT NOT NULL, PRIMARY KEY (`id 1`)) ENGINE=INNODB; -CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), FOREIGN KEY (`t1_id`) REFERENCES `t1`(`id 1`) ON DELETE CASCADE ) ENGINE=INNODB; -drop table t2,t1; -create table `t1` (`id` int( 11 ) not null ,primary key ( `id` )) engine = innodb; -insert into `t1`values ( 1 ) ; -create table `t2` (`id` int( 11 ) not null default '0',unique key `id` ( `id` ) ,constraint `t1_id_fk` foreign key ( `id` ) references `t1` (`id` )) engine = innodb; -insert into `t2`values ( 1 ) ; -create table `t3` (`id` int( 11 ) not null default '0',key `id` ( `id` ) ,constraint `t2_id_fk` foreign key ( `id` ) references `t2` (`id` )) engine = innodb; -insert into `t3`values ( 1 ) ; -delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)) -update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`)) -update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; -ERROR 42S22: Unknown column 't1.id' in 'where clause' -drop table t3,t2,t1; -create table t1( -id int primary key, -pid int, -index(pid), -foreign key(pid) references t1(id) on delete cascade) engine=innodb; -insert into t1 values(0,0),(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6), -(8,7),(9,8),(10,9),(11,10),(12,11),(13,12),(14,13),(15,14); -delete from t1 where id=0; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`pid`) REFERENCES `t1` (`id`) ON DELETE CASCADE) -delete from t1 where id=15; -delete from t1 where id=0; -drop table t1; -CREATE TABLE t1 (col1 int(1))ENGINE=InnoDB; -CREATE TABLE t2 (col1 int(1),stamp TIMESTAMP,INDEX stamp_idx -(stamp))ENGINE=InnoDB; -insert into t1 values (1),(2),(3); -insert into t2 values (1, 20020204130000),(2, 20020204130000),(4,20020204310000 ),(5,20020204230000); -Warnings: -Warning 1265 Data truncated for column 'stamp' at row 3 -SELECT col1 FROM t1 UNION SELECT col1 FROM t2 WHERE stamp < -'20020204120000' GROUP BY col1; -col1 -1 -2 -3 -4 -drop table t1,t2; -CREATE TABLE t1 ( -`id` int(10) unsigned NOT NULL auto_increment, -`id_object` int(10) unsigned default '0', -`id_version` int(10) unsigned NOT NULL default '1', -`label` varchar(100) NOT NULL default '', -`description` text, -PRIMARY KEY (`id`), -KEY `id_object` (`id_object`), -KEY `id_version` (`id_version`) -) ENGINE=InnoDB; -INSERT INTO t1 VALUES("6", "3382", "9", "Test", NULL), ("7", "102", "5", "Le Pekin (Test)", NULL),("584", "1794", "4", "Test de resto", NULL),("837", "1822", "6", "Test 3", NULL),("1119", "3524", "1", "Societe Test", NULL),("1122", "3525", "1", "Fournisseur Test", NULL); -CREATE TABLE t2 ( -`id` int(10) unsigned NOT NULL auto_increment, -`id_version` int(10) unsigned NOT NULL default '1', -PRIMARY KEY (`id`), -KEY `id_version` (`id_version`) -) ENGINE=InnoDB; -INSERT INTO t2 VALUES("3524", "1"),("3525", "1"),("1794", "4"),("102", "5"),("1822", "6"),("3382", "9"); -SELECT t2.id, t1.`label` FROM t2 INNER JOIN -(SELECT t1.id_object as id_object FROM t1 WHERE t1.`label` LIKE '%test%') AS lbl -ON (t2.id = lbl.id_object) INNER JOIN t1 ON (t2.id = t1.id_object); -id label -3382 Test -102 Le Pekin (Test) -1794 Test de resto -1822 Test 3 -3524 Societe Test -3525 Fournisseur Test -drop table t1,t2; -create table t1 (a int, b varchar(200), c text not null) checksum=1 engine=myisam; -create table t2 (a int, b varchar(200), c text not null) checksum=0 engine=innodb; -create table t3 (a int, b varchar(200), c text not null) checksum=1 engine=innodb; -insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, ""); -insert t2 select * from t1; -insert t3 select * from t1; -checksum table t1, t2, t3, t4 quick; -Table Checksum -test.t1 2948697075 -test.t2 NULL -test.t3 NULL -test.t4 NULL -Warnings: -Error 1146 Table 'test.t4' doesn't exist -checksum table t1, t2, t3, t4; -Table Checksum -test.t1 2948697075 -test.t2 2948697075 -test.t3 2948697075 -test.t4 NULL -Warnings: -Error 1146 Table 'test.t4' doesn't exist -checksum table t1, t2, t3, t4 extended; -Table Checksum -test.t1 2948697075 -test.t2 2948697075 -test.t3 2948697075 -test.t4 NULL -Warnings: -Error 1146 Table 'test.t4' doesn't exist -drop table t1,t2,t3; -create table t1 (id int, name char(10) not null, name2 char(10) not null) engine=innodb; -insert into t1 values(1,'first','fff'),(2,'second','sss'),(3,'third','ttt'); -select trim(name2) from t1 union all select trim(name) from t1 union all select trim(id) from t1; -trim(name2) -fff -sss -ttt -first -second -third -1 -2 -3 -drop table t1; -create table t1 (a int) engine=innodb; -create table t2 like t1; -drop table t1,t2; -create table t1 (id int(11) not null, id2 int(11) not null, unique (id,id2)) engine=innodb; -create table t2 (id int(11) not null, constraint t1_id_fk foreign key ( id ) references t1 (id)) engine = innodb; -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `id` int(11) NOT NULL, - `id2` int(11) NOT NULL, - UNIQUE KEY `id` (`id`,`id2`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `id` int(11) NOT NULL, - KEY `t1_id_fk` (`id`), - CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -create index id on t2 (id); -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `id` int(11) NOT NULL, - KEY `id` (`id`), - CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -create index id2 on t2 (id); -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `id` int(11) NOT NULL, - KEY `id` (`id`), - KEY `id2` (`id`), - CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop index id2 on t2; -drop index id on t2; -ERROR HY000: Cannot drop index 'id': needed in a foreign key constraint -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `id` int(11) NOT NULL, - KEY `id` (`id`), - CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t2; -create table t2 (id int(11) not null, id2 int(11) not null, constraint t1_id_fk foreign key (id,id2) references t1 (id,id2)) engine = innodb; -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `id` int(11) NOT NULL, - `id2` int(11) NOT NULL, - KEY `t1_id_fk` (`id`,`id2`), - CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`, `id2`) REFERENCES `t1` (`id`, `id2`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -create unique index id on t2 (id,id2); -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `id` int(11) NOT NULL, - `id2` int(11) NOT NULL, - UNIQUE KEY `id` (`id`,`id2`), - CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`, `id2`) REFERENCES `t1` (`id`, `id2`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t2; -create table t2 (id int(11) not null, id2 int(11) not null, unique (id,id2),constraint t1_id_fk foreign key (id2,id) references t1 (id,id2)) engine = innodb; -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `id` int(11) NOT NULL, - `id2` int(11) NOT NULL, - UNIQUE KEY `id` (`id`,`id2`), - KEY `t1_id_fk` (`id2`,`id`), - CONSTRAINT `t1_id_fk` FOREIGN KEY (`id2`, `id`) REFERENCES `t1` (`id`, `id2`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t2; -create table t2 (id int(11) not null, id2 int(11) not null, unique (id,id2), constraint t1_id_fk foreign key (id) references t1 (id)) engine = innodb; -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `id` int(11) NOT NULL, - `id2` int(11) NOT NULL, - UNIQUE KEY `id` (`id`,`id2`), - CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t2; -create table t2 (id int(11) not null, id2 int(11) not null, unique (id,id2),constraint t1_id_fk foreign key (id2,id) references t1 (id,id2)) engine = innodb; -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `id` int(11) NOT NULL, - `id2` int(11) NOT NULL, - UNIQUE KEY `id` (`id`,`id2`), - KEY `t1_id_fk` (`id2`,`id`), - CONSTRAINT `t1_id_fk` FOREIGN KEY (`id2`, `id`) REFERENCES `t1` (`id`, `id2`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t2; -create table t2 (id int(11) not null auto_increment, id2 int(11) not null, constraint t1_id_fk foreign key (id) references t1 (id), primary key (id), index (id,id2)) engine = innodb; -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `id2` int(11) NOT NULL, - PRIMARY KEY (`id`), - KEY `id` (`id`,`id2`), - CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t2; -create table t2 (id int(11) not null auto_increment, id2 int(11) not null, constraint t1_id_fk foreign key (id) references t1 (id)) engine= innodb; -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `id2` int(11) NOT NULL, - KEY `t1_id_fk` (`id`), - CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -alter table t2 add index id_test (id), add index id_test2 (id,id2); -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `id2` int(11) NOT NULL, - KEY `id_test` (`id`), - KEY `id_test2` (`id`,`id2`), - CONSTRAINT `t1_id_fk` FOREIGN KEY (`id`) REFERENCES `t1` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t2; -create table t2 (id int(11) not null, id2 int(11) not null, constraint t1_id_fk foreign key (id2,id) references t1 (id)) engine = innodb; -ERROR 42000: Incorrect foreign key definition for 't1_id_fk': Key reference and table reference don't match -create table t2 (a int auto_increment primary key, b int, index(b), foreign key (b) references t1(id), unique(b)) engine=innodb; -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `a` int(11) NOT NULL AUTO_INCREMENT, - `b` int(11) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `b_2` (`b`), - KEY `b` (`b`), - CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t2; -create table t2 (a int auto_increment primary key, b int, foreign key (b) references t1(id), foreign key (b) references t1(id), unique(b)) engine=innodb; -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `a` int(11) NOT NULL AUTO_INCREMENT, - `b` int(11) DEFAULT NULL, - PRIMARY KEY (`a`), - UNIQUE KEY `b` (`b`), - CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`id`), - CONSTRAINT `t2_ibfk_2` FOREIGN KEY (`b`) REFERENCES `t1` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t2, t1; -create table t1 (c char(10), index (c,c)) engine=innodb; -ERROR 42S21: Duplicate column name 'c' -create table t1 (c1 char(10), c2 char(10), index (c1,c2,c1)) engine=innodb; -ERROR 42S21: Duplicate column name 'c1' -create table t1 (c1 char(10), c2 char(10), index (c1,c1,c2)) engine=innodb; -ERROR 42S21: Duplicate column name 'c1' -create table t1 (c1 char(10), c2 char(10), index (c2,c1,c1)) engine=innodb; -ERROR 42S21: Duplicate column name 'c1' -create table t1 (c1 char(10), c2 char(10)) engine=innodb; -alter table t1 add key (c1,c1); -ERROR 42S21: Duplicate column name 'c1' -alter table t1 add key (c2,c1,c1); -ERROR 42S21: Duplicate column name 'c1' -alter table t1 add key (c1,c2,c1); -ERROR 42S21: Duplicate column name 'c1' -alter table t1 add key (c1,c1,c2); -ERROR 42S21: Duplicate column name 'c1' -drop table t1; -create table t1(a int(1) , b int(1)) engine=innodb; -insert into t1 values ('1111', '3333'); -select distinct concat(a, b) from t1; -concat(a, b) -11113333 -drop table t1; -CREATE TABLE t1 ( a char(10) ) ENGINE=InnoDB; -SELECT a FROM t1 WHERE MATCH (a) AGAINST ('test' IN BOOLEAN MODE); -ERROR HY000: The used table type doesn't support FULLTEXT indexes -DROP TABLE t1; -CREATE TABLE t1 (a_id tinyint(4) NOT NULL default '0', PRIMARY KEY (a_id)) ENGINE=InnoDB DEFAULT CHARSET=latin1; -INSERT INTO t1 VALUES (1),(2),(3); -CREATE TABLE t2 (b_id tinyint(4) NOT NULL default '0',b_a tinyint(4) NOT NULL default '0', PRIMARY KEY (b_id), KEY (b_a), -CONSTRAINT fk_b_a FOREIGN KEY (b_a) REFERENCES t1 (a_id) ON DELETE CASCADE ON UPDATE NO ACTION) ENGINE=InnoDB DEFAULT CHARSET=latin1; -INSERT INTO t2 VALUES (1,1),(2,1),(3,1),(4,2),(5,2); -SELECT * FROM (SELECT t1.*,GROUP_CONCAT(t2.b_id SEPARATOR ',') as b_list FROM (t1 LEFT JOIN (t2) on t1.a_id = t2.b_a) GROUP BY t1.a_id ) AS xyz; -a_id b_list -1 1,2,3 -2 4,5 -3 NULL -DROP TABLE t2; -DROP TABLE t1; -create temporary table t1 (a int) engine=innodb; -insert into t1 values (4711); -truncate t1; -insert into t1 values (42); -select * from t1; -a -42 -drop table t1; -create table t1 (a int) engine=innodb; -insert into t1 values (4711); -truncate t1; -insert into t1 values (42); -select * from t1; -a -42 -drop table t1; -create table t1 (a int not null, b int not null, c blob not null, d int not null, e int, primary key (a,b,c(255),d)) engine=innodb; -insert into t1 values (2,2,"b",2,2),(1,1,"a",1,1),(3,3,"ab",3,3); -select * from t1 order by a,b,c,d; -a b c d e -1 1 a 1 1 -2 2 b 2 2 -3 3 ab 3 3 -explain select * from t1 order by a,b,c,d; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort -drop table t1; -create table t1 (a char(1), b char(1), key(a, b)) engine=innodb; -insert into t1 values ('8', '6'), ('4', '7'); -select min(a) from t1; -min(a) -4 -select min(b) from t1 where a='8'; -min(b) -6 -drop table t1; -create table t1 (x bigint unsigned not null primary key) engine=innodb; -insert into t1(x) values (0xfffffffffffffff0),(0xfffffffffffffff1); -select * from t1; -x -18446744073709551600 -18446744073709551601 -select count(*) from t1 where x>0; -count(*) -2 -select count(*) from t1 where x=0; -count(*) -0 -select count(*) from t1 where x<0; -count(*) -0 -select count(*) from t1 where x < -16; -count(*) -0 -select count(*) from t1 where x = -16; -count(*) -0 -explain select count(*) from t1 where x > -16; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index PRIMARY PRIMARY 8 NULL 2 Using where; Using index -select count(*) from t1 where x > -16; -count(*) -2 -select * from t1 where x > -16; -x -18446744073709551600 -18446744073709551601 -select count(*) from t1 where x = 18446744073709551601; -count(*) -1 -drop table t1; -SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_buffer_pool_pages_total'; -variable_value -8191 -SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_page_size'; -variable_value -16384 -SELECT variable_value - @innodb_rows_deleted_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_deleted'; -variable_value - @innodb_rows_deleted_orig -71 -SELECT variable_value - @innodb_rows_inserted_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_inserted'; -variable_value - @innodb_rows_inserted_orig -1084 -SELECT variable_value - @innodb_rows_updated_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_updated'; -variable_value - @innodb_rows_updated_orig -885 -SELECT variable_value - @innodb_row_lock_waits_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_waits'; -variable_value - @innodb_row_lock_waits_orig -0 -SELECT variable_value - @innodb_row_lock_current_waits_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_current_waits'; -variable_value - @innodb_row_lock_current_waits_orig -0 -SELECT variable_value - @innodb_row_lock_time_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_time'; -variable_value - @innodb_row_lock_time_orig -0 -SELECT variable_value - @innodb_row_lock_time_max_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_time_max'; -variable_value - @innodb_row_lock_time_max_orig -0 -SELECT variable_value - @innodb_row_lock_time_avg_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_time_avg'; -variable_value - @innodb_row_lock_time_avg_orig -0 -SET @innodb_sync_spin_loops_orig = @@innodb_sync_spin_loops; -show variables like "innodb_sync_spin_loops"; -Variable_name Value -innodb_sync_spin_loops 30 -set global innodb_sync_spin_loops=1000; -show variables like "innodb_sync_spin_loops"; -Variable_name Value -innodb_sync_spin_loops 1000 -set global innodb_sync_spin_loops=0; -show variables like "innodb_sync_spin_loops"; -Variable_name Value -innodb_sync_spin_loops 0 -set global innodb_sync_spin_loops=20; -show variables like "innodb_sync_spin_loops"; -Variable_name Value -innodb_sync_spin_loops 20 -set global innodb_sync_spin_loops=@innodb_sync_spin_loops_orig; -show variables like "innodb_thread_concurrency"; -Variable_name Value -innodb_thread_concurrency 0 -set global innodb_thread_concurrency=1001; -Warnings: -Warning 1292 Truncated incorrect thread_concurrency value: '1001' -show variables like "innodb_thread_concurrency"; -Variable_name Value -innodb_thread_concurrency 1000 -set global innodb_thread_concurrency=0; -show variables like "innodb_thread_concurrency"; -Variable_name Value -innodb_thread_concurrency 0 -set global innodb_thread_concurrency=16; -show variables like "innodb_thread_concurrency"; -Variable_name Value -innodb_thread_concurrency 16 -show variables like "innodb_concurrency_tickets"; -Variable_name Value -innodb_concurrency_tickets 500 -set global innodb_concurrency_tickets=1000; -show variables like "innodb_concurrency_tickets"; -Variable_name Value -innodb_concurrency_tickets 1000 -set global innodb_concurrency_tickets=0; -Warnings: -Warning 1292 Truncated incorrect concurrency_tickets value: '0' -show variables like "innodb_concurrency_tickets"; -Variable_name Value -innodb_concurrency_tickets 1 -set global innodb_concurrency_tickets=500; -show variables like "innodb_concurrency_tickets"; -Variable_name Value -innodb_concurrency_tickets 500 -show variables like "innodb_thread_sleep_delay"; -Variable_name Value -innodb_thread_sleep_delay 10000 -set global innodb_thread_sleep_delay=100000; -show variables like "innodb_thread_sleep_delay"; -Variable_name Value -innodb_thread_sleep_delay 100000 -set global innodb_thread_sleep_delay=0; -show variables like "innodb_thread_sleep_delay"; -Variable_name Value -innodb_thread_sleep_delay 0 -set global innodb_thread_sleep_delay=10000; -show variables like "innodb_thread_sleep_delay"; -Variable_name Value -innodb_thread_sleep_delay 10000 -set storage_engine=INNODB; -drop table if exists t1,t2,t3; ---- Testing varchar --- ---- Testing varchar --- -create table t1 (v varchar(10), c char(10), t text); -insert into t1 values('+ ', '+ ', '+ '); -set @a=repeat(' ',20); -insert into t1 values (concat('+',@a),concat('+',@a),concat('+',@a)); -Warnings: -Note 1265 Data truncated for column 'v' at row 1 -select concat('*',v,'*',c,'*',t,'*') from t1; -concat('*',v,'*',c,'*',t,'*') -*+ *+*+ * -*+ *+*+ * -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(10) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` text -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -create table t2 like t1; -show create table t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `v` varchar(10) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` text -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -create table t3 select * from t1; -show create table t3; -Table Create Table -t3 CREATE TABLE `t3` ( - `v` varchar(10) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` text -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -alter table t1 modify c varchar(10); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(10) DEFAULT NULL, - `c` varchar(10) DEFAULT NULL, - `t` text -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -alter table t1 modify v char(10); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` char(10) DEFAULT NULL, - `c` varchar(10) DEFAULT NULL, - `t` text -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -alter table t1 modify t varchar(10); -Warnings: -Note 1265 Data truncated for column 't' at row 2 -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` char(10) DEFAULT NULL, - `c` varchar(10) DEFAULT NULL, - `t` varchar(10) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -select concat('*',v,'*',c,'*',t,'*') from t1; -concat('*',v,'*',c,'*',t,'*') -*+*+*+ * -*+*+*+ * -drop table t1,t2,t3; -create table t1 (v varchar(10), c char(10), t text, key(v), key(c), key(t(10))); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(10) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` text, - KEY `v` (`v`), - KEY `c` (`c`), - KEY `t` (`t`(10)) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -select count(*) from t1; -count(*) -270 -insert into t1 values(concat('a',char(1)),concat('a',char(1)),concat('a',char(1))); -select count(*) from t1 where v='a'; -count(*) -10 -select count(*) from t1 where c='a'; -count(*) -10 -select count(*) from t1 where t='a'; -count(*) -10 -select count(*) from t1 where v='a '; -count(*) -10 -select count(*) from t1 where c='a '; -count(*) -10 -select count(*) from t1 where t='a '; -count(*) -10 -select count(*) from t1 where v between 'a' and 'a '; -count(*) -10 -select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; -count(*) -10 -select count(*) from t1 where v like 'a%'; -count(*) -11 -select count(*) from t1 where c like 'a%'; -count(*) -11 -select count(*) from t1 where t like 'a%'; -count(*) -11 -select count(*) from t1 where v like 'a %'; -count(*) -9 -explain select count(*) from t1 where v='a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 13 const # Using where; Using index -explain select count(*) from t1 where c='a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref c c 11 const # Using where; Using index -explain select count(*) from t1 where t='a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref t t 13 const # Using where -explain select count(*) from t1 where v like 'a%'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 13 NULL # Using where; Using index -explain select count(*) from t1 where v between 'a' and 'a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 13 const # Using where; Using index -explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 13 const # Using where; Using index -alter table t1 add unique(v); -ERROR 23000: Duplicate entry 'v' for key 'v_2' -alter table t1 add key(v); -select concat('*',v,'*',c,'*',t,'*') as qq from t1 where v='a'; -qq -*a*a*a* -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -*a *a*a * -explain select * from t1 where v='a'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v,v_2 # 13 const # Using where -select v,count(*) from t1 group by v limit 10; -v count(*) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select v,count(t) from t1 group by v limit 10; -v count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select v,count(c) from t1 group by v limit 10; -v count(c) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select sql_big_result v,count(t) from t1 group by v limit 10; -v count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select sql_big_result v,count(c) from t1 group by v limit 10; -v count(c) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select c,count(*) from t1 group by c limit 10; -c count(*) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select c,count(t) from t1 group by c limit 10; -c count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select sql_big_result c,count(t) from t1 group by c limit 10; -c count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select t,count(*) from t1 group by t limit 10; -t count(*) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select t,count(t) from t1 group by t limit 10; -t count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select sql_big_result t,count(t) from t1 group by t limit 10; -t count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -alter table t1 modify v varchar(300), drop key v, drop key v_2, add key v (v); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(300) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` text, - KEY `c` (`c`), - KEY `t` (`t`(10)), - KEY `v` (`v`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -select count(*) from t1 where v='a'; -count(*) -10 -select count(*) from t1 where v='a '; -count(*) -10 -select count(*) from t1 where v between 'a' and 'a '; -count(*) -10 -select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; -count(*) -10 -select count(*) from t1 where v like 'a%'; -count(*) -11 -select count(*) from t1 where v like 'a %'; -count(*) -9 -explain select count(*) from t1 where v='a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 303 const # Using where; Using index -explain select count(*) from t1 where v like 'a%'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 303 NULL # Using where; Using index -explain select count(*) from t1 where v between 'a' and 'a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 303 const # Using where; Using index -explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 303 const # Using where; Using index -explain select * from t1 where v='a'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 303 const # Using where -select v,count(*) from t1 group by v limit 10; -v count(*) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select v,count(t) from t1 group by v limit 10; -v count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select sql_big_result v,count(t) from t1 group by v limit 10; -v count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -alter table t1 drop key v, add key v (v(30)); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(300) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` text, - KEY `c` (`c`), - KEY `t` (`t`(10)), - KEY `v` (`v`(30)) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -select count(*) from t1 where v='a'; -count(*) -10 -select count(*) from t1 where v='a '; -count(*) -10 -select count(*) from t1 where v between 'a' and 'a '; -count(*) -10 -select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; -count(*) -10 -select count(*) from t1 where v like 'a%'; -count(*) -11 -select count(*) from t1 where v like 'a %'; -count(*) -9 -explain select count(*) from t1 where v='a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 33 const # Using where -explain select count(*) from t1 where v like 'a%'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range v v 33 NULL # Using where -explain select count(*) from t1 where v between 'a' and 'a '; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 33 const # Using where -explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 33 const # Using where -explain select * from t1 where v='a'; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref v v 33 const # Using where -select v,count(*) from t1 group by v limit 10; -v count(*) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select v,count(t) from t1 group by v limit 10; -v count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select sql_big_result v,count(t) from t1 group by v limit 10; -v count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -alter table t1 modify v varchar(600), drop key v, add key v (v); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(600) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` text, - KEY `c` (`c`), - KEY `t` (`t`(10)), - KEY `v` (`v`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -select v,count(*) from t1 group by v limit 10; -v count(*) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select v,count(t) from t1 group by v limit 10; -v count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -select sql_big_result v,count(t) from t1 group by v limit 10; -v count(t) -a 1 -a 10 -b 10 -c 10 -d 10 -e 10 -f 10 -g 10 -h 10 -i 10 -drop table t1; -create table t1 (a char(10), unique (a)); -insert into t1 values ('a '); -insert into t1 values ('a '); -ERROR 23000: Duplicate entry 'a' for key 'a' -alter table t1 modify a varchar(10); -insert into t1 values ('a '),('a '),('a '),('a '); -ERROR 23000: Duplicate entry 'a ' for key 'a' -insert into t1 values ('a '); -ERROR 23000: Duplicate entry 'a ' for key 'a' -insert into t1 values ('a '); -ERROR 23000: Duplicate entry 'a ' for key 'a' -insert into t1 values ('a '); -ERROR 23000: Duplicate entry 'a ' for key 'a' -update t1 set a='a ' where a like 'a%'; -select concat(a,'.') from t1; -concat(a,'.') -a . -update t1 set a='abc ' where a like 'a '; -select concat(a,'.') from t1; -concat(a,'.') -a . -update t1 set a='a ' where a like 'a %'; -select concat(a,'.') from t1; -concat(a,'.') -a . -update t1 set a='a ' where a like 'a '; -select concat(a,'.') from t1; -concat(a,'.') -a . -drop table t1; -create table t1 (v varchar(10), c char(10), t text, key(v(5)), key(c(5)), key(t(5))); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(10) DEFAULT NULL, - `c` char(10) DEFAULT NULL, - `t` text, - KEY `v` (`v`(5)), - KEY `c` (`c`(5)), - KEY `t` (`t`(5)) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1; -create table t1 (v char(10) character set utf8); -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` char(10) CHARACTER SET utf8 DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1; -create table t1 (v varchar(10), c char(10)) row_format=fixed; -Warnings: -Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT. -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` varchar(10) DEFAULT NULL, - `c` char(10) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=FIXED -insert into t1 values('a','a'),('a ','a '); -select concat('*',v,'*',c,'*') from t1; -concat('*',v,'*',c,'*') -*a*a* -*a *a* -drop table t1; -create table t1 (v varchar(65530), key(v(10))); -insert into t1 values(repeat('a',65530)); -select length(v) from t1 where v=repeat('a',65530); -length(v) -65530 -drop table t1; -create table t1(a int, b varchar(12), key ba(b, a)); -insert into t1 values (1, 'A'), (20, NULL); -explain select * from t1 where a=20 and b is null; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 ref ba ba 20 const,const 1 Using where; Using index -select * from t1 where a=20 and b is null; -a b -20 NULL -drop table t1; -create table t1 (v varchar(65530), key(v)); -Warnings: -Warning 1071 Specified key was too long; max key length is 767 bytes -drop table t1; -create table t1 (v varchar(65536)); -Warnings: -Note 1246 Converting column 'v' from VARCHAR to TEXT -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` mediumtext -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1; -create table t1 (v varchar(65530) character set utf8); -Warnings: -Note 1246 Converting column 'v' from VARCHAR to TEXT -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `v` mediumtext CHARACTER SET utf8 -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1; -set storage_engine=MyISAM; -create table t1 (v varchar(16384)) engine=innodb; -drop table t1; -create table t1 (a char(1), b char(1), key(a, b)) engine=innodb; -insert into t1 values ('8', '6'), ('4', '7'); -select min(a) from t1; -min(a) -4 -select min(b) from t1 where a='8'; -min(b) -6 -drop table t1; -CREATE TABLE t1 ( `a` int(11) NOT NULL auto_increment, `b` int(11) default NULL,PRIMARY KEY (`a`),UNIQUE KEY `b` (`b`)) ENGINE=innodb; -insert into t1 (b) values (1); -replace into t1 (b) values (2), (1), (3); -select * from t1; -a b -3 1 -2 2 -4 3 -truncate table t1; -insert into t1 (b) values (1); -replace into t1 (b) values (2); -replace into t1 (b) values (1); -replace into t1 (b) values (3); -select * from t1; -a b -3 1 -2 2 -4 3 -drop table t1; -create table t1 (rowid int not null auto_increment, val int not null,primary -key (rowid), unique(val)) engine=innodb; -replace into t1 (val) values ('1'),('2'); -replace into t1 (val) values ('1'),('2'); -insert into t1 (val) values ('1'),('2'); -ERROR 23000: Duplicate entry '1' for key 'val' -select * from t1; -rowid val -3 1 -4 2 -drop table t1; -create table t1 (a int not null auto_increment primary key, val int) engine=InnoDB; -insert into t1 (val) values (1); -update t1 set a=2 where a=1; -insert into t1 (val) values (1); -ERROR 23000: Duplicate entry '2' for key 'PRIMARY' -select * from t1; -a val -2 1 -drop table t1; -CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB; -INSERT INTO t1 (GRADE) VALUES (151),(252),(343); -SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300; -GRADE -252 -SELECT GRADE FROM t1 WHERE GRADE= 151; -GRADE -151 -DROP TABLE t1; -create table t1 (f1 varchar(10), f2 varchar(10), primary key (f1,f2)) engine=innodb; -create table t2 (f3 varchar(10), f4 varchar(10), key (f4)) engine=innodb; -insert into t2 values ('aa','cc'); -insert into t1 values ('aa','bb'),('aa','cc'); -delete t1 from t1,t2 where f1=f3 and f4='cc'; -select * from t1; -f1 f2 -drop table t1,t2; -CREATE TABLE t1 ( -id INTEGER NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) -) ENGINE=InnoDB; -CREATE TABLE t2 ( -id INTEGER NOT NULL, -FOREIGN KEY (id) REFERENCES t1 (id) -) ENGINE=InnoDB; -INSERT INTO t1 (id) VALUES (NULL); -SELECT * FROM t1; -id -1 -TRUNCATE t1; -INSERT INTO t1 (id) VALUES (NULL); -SELECT * FROM t1; -id -1 -DELETE FROM t1; -TRUNCATE t1; -INSERT INTO t1 (id) VALUES (NULL); -SELECT * FROM t1; -id -1 -DROP TABLE t2, t1; -CREATE TABLE t1 -( -id INT PRIMARY KEY -) ENGINE=InnoDB; -CREATE TEMPORARY TABLE t2 -( -id INT NOT NULL PRIMARY KEY, -b INT, -FOREIGN KEY (b) REFERENCES test.t1(id) -) ENGINE=InnoDB; -Got one of the listed errors -DROP TABLE t1; -create table t1 (col1 varchar(2000), index (col1(767))) -character set = latin1 engine = innodb; -create table t2 (col1 char(255), index (col1)) -character set = latin1 engine = innodb; -create table t3 (col1 binary(255), index (col1)) -character set = latin1 engine = innodb; -create table t4 (col1 varchar(767), index (col1)) -character set = latin1 engine = innodb; -create table t5 (col1 varchar(767) primary key) -character set = latin1 engine = innodb; -create table t6 (col1 varbinary(767) primary key) -character set = latin1 engine = innodb; -create table t7 (col1 text, index(col1(767))) -character set = latin1 engine = innodb; -create table t8 (col1 blob, index(col1(767))) -character set = latin1 engine = innodb; -create table t9 (col1 varchar(512), col2 varchar(512), index(col1, col2)) -character set = latin1 engine = innodb; -show create table t9; -Table Create Table -t9 CREATE TABLE `t9` ( - `col1` varchar(512) DEFAULT NULL, - `col2` varchar(512) DEFAULT NULL, - KEY `col1` (`col1`,`col2`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1, t2, t3, t4, t5, t6, t7, t8, t9; -create table t1 (col1 varchar(768), index(col1)) -character set = latin1 engine = innodb; -Warnings: -Warning 1071 Specified key was too long; max key length is 767 bytes -create table t2 (col1 varbinary(768), index(col1)) -character set = latin1 engine = innodb; -Warnings: -Warning 1071 Specified key was too long; max key length is 767 bytes -create table t3 (col1 text, index(col1(768))) -character set = latin1 engine = innodb; -Warnings: -Warning 1071 Specified key was too long; max key length is 767 bytes -create table t4 (col1 blob, index(col1(768))) -character set = latin1 engine = innodb; -Warnings: -Warning 1071 Specified key was too long; max key length is 767 bytes -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `col1` varchar(768) DEFAULT NULL, - KEY `col1` (`col1`(767)) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1, t2, t3, t4; -create table t1 (col1 varchar(768) primary key) -character set = latin1 engine = innodb; -ERROR 42000: Specified key was too long; max key length is 767 bytes -create table t2 (col1 varbinary(768) primary key) -character set = latin1 engine = innodb; -ERROR 42000: Specified key was too long; max key length is 767 bytes -create table t3 (col1 text, primary key(col1(768))) -character set = latin1 engine = innodb; -ERROR 42000: Specified key was too long; max key length is 767 bytes -create table t4 (col1 blob, primary key(col1(768))) -character set = latin1 engine = innodb; -ERROR 42000: Specified key was too long; max key length is 767 bytes -CREATE TABLE t1 -( -id INT PRIMARY KEY -) ENGINE=InnoDB; -CREATE TABLE t2 -( -v INT, -CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id) -) ENGINE=InnoDB; -INSERT INTO t2 VALUES(2); -ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`)) -INSERT INTO t1 VALUES(1); -INSERT INTO t2 VALUES(1); -DELETE FROM t1 WHERE id = 1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`)) -DROP TABLE t1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails -SET FOREIGN_KEY_CHECKS=0; -DROP TABLE t1; -SET FOREIGN_KEY_CHECKS=1; -INSERT INTO t2 VALUES(3); -ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c1` FOREIGN KEY (`v`) REFERENCES `t1` (`id`)) -DROP TABLE t2; -create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; -insert into t1 values (1),(2); -set autocommit=0; -checksum table t1; -Table Checksum -test.t1 1531596814 -insert into t1 values(3); -checksum table t1; -Table Checksum -test.t1 1531596814 -commit; -checksum table t1; -Table Checksum -test.t1 2050879373 -commit; -drop table t1; -create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; -insert into t1 values (1),(2); -set autocommit=1; -checksum table t1; -Table Checksum -test.t1 1531596814 -set autocommit=1; -insert into t1 values(3); -checksum table t1; -Table Checksum -test.t1 2050879373 -drop table t1; -set foreign_key_checks=0; -create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb; -create table t1(a char(10) primary key, b varchar(20)) engine = innodb; -ERROR HY000: Can't create table 'test.t1' (errno: 150) -set foreign_key_checks=1; -drop table t2; -set foreign_key_checks=0; -create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; -create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=utf8; -ERROR HY000: Can't create table 'test.t2' (errno: 150) -set foreign_key_checks=1; -drop table t1; -set foreign_key_checks=0; -create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb; -create table t1(a varchar(10) primary key) engine = innodb; -alter table t1 modify column a int; -Got one of the listed errors -set foreign_key_checks=1; -drop table t2,t1; -set foreign_key_checks=0; -create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; -create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; -alter table t1 convert to character set utf8; -set foreign_key_checks=1; -drop table t2,t1; -set foreign_key_checks=0; -create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; -create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8; -rename table t3 to t1; -ERROR HY000: Error on rename of './test/t3' to './test/t1' (errno: 150) -set foreign_key_checks=1; -drop table t2,t3; -create table t1(a int primary key) row_format=redundant engine=innodb; -create table t2(a int primary key,constraint foreign key(a)references t1(a)) row_format=compact engine=innodb; -create table t3(a int primary key) row_format=compact engine=innodb; -create table t4(a int primary key,constraint foreign key(a)references t3(a)) row_format=redundant engine=innodb; -insert into t1 values(1); -insert into t3 values(1); -insert into t2 values(2); -ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) -insert into t4 values(2); -ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`)) -insert into t2 values(1); -insert into t4 values(1); -update t1 set a=2; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) -update t2 set a=2; -ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) -update t3 set a=2; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`)) -update t4 set a=2; -ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`)) -truncate t1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) -truncate t3; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t4`, CONSTRAINT `t4_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t3` (`a`)) -truncate t2; -truncate t4; -truncate t1; -truncate t3; -drop table t4,t3,t2,t1; -create table t1 (a varchar(255) character set utf8, -b varchar(255) character set utf8, -c varchar(255) character set utf8, -d varchar(255) character set utf8, -key (a,b,c,d)) engine=innodb; -drop table t1; -create table t1 (a varchar(255) character set utf8, -b varchar(255) character set utf8, -c varchar(255) character set utf8, -d varchar(255) character set utf8, -e varchar(255) character set utf8, -key (a,b,c,d,e)) engine=innodb; -ERROR 42000: Specified key was too long; max key length is 3072 bytes -create table t1 (s1 varbinary(2),primary key (s1)) engine=innodb; -create table t2 (s1 binary(2),primary key (s1)) engine=innodb; -create table t3 (s1 varchar(2) binary,primary key (s1)) engine=innodb; -create table t4 (s1 char(2) binary,primary key (s1)) engine=innodb; -insert into t1 values (0x41),(0x4120),(0x4100); -insert into t2 values (0x41),(0x4120),(0x4100); -ERROR 23000: Duplicate entry 'A' for key 'PRIMARY' -insert into t2 values (0x41),(0x4120); -insert into t3 values (0x41),(0x4120),(0x4100); -ERROR 23000: Duplicate entry 'A ' for key 'PRIMARY' -insert into t3 values (0x41),(0x4100); -insert into t4 values (0x41),(0x4120),(0x4100); -ERROR 23000: Duplicate entry 'A' for key 'PRIMARY' -insert into t4 values (0x41),(0x4100); -select hex(s1) from t1; -hex(s1) -41 -4100 -4120 -select hex(s1) from t2; -hex(s1) -4100 -4120 -select hex(s1) from t3; -hex(s1) -4100 -41 -select hex(s1) from t4; -hex(s1) -4100 -41 -drop table t1,t2,t3,t4; -create table t1 (a int primary key,s1 varbinary(3) not null unique) engine=innodb; -create table t2 (s1 binary(2) not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; -insert into t1 values(1,0x4100),(2,0x41),(3,0x4120),(4,0x42); -insert into t2 values(0x42); -ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) -insert into t2 values(0x41); -select hex(s1) from t2; -hex(s1) -4100 -update t1 set s1=0x123456 where a=2; -select hex(s1) from t2; -hex(s1) -4100 -update t1 set s1=0x12 where a=1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) -update t1 set s1=0x12345678 where a=1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) -update t1 set s1=0x123457 where a=1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) -update t1 set s1=0x1220 where a=1; -select hex(s1) from t2; -hex(s1) -1220 -update t1 set s1=0x1200 where a=1; -select hex(s1) from t2; -hex(s1) -1200 -update t1 set s1=0x4200 where a=1; -select hex(s1) from t2; -hex(s1) -4200 -delete from t1 where a=1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) -delete from t1 where a=2; -update t2 set s1=0x4120; -delete from t1; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) -delete from t1 where a!=3; -select a,hex(s1) from t1; -a hex(s1) -3 4120 -select hex(s1) from t2; -hex(s1) -4120 -drop table t2,t1; -create table t1 (a int primary key,s1 varchar(2) binary not null unique) engine=innodb; -create table t2 (s1 char(2) binary not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; -insert into t1 values(1,0x4100),(2,0x41); -insert into t2 values(0x41); -select hex(s1) from t2; -hex(s1) -41 -update t1 set s1=0x1234 where a=1; -select hex(s1) from t2; -hex(s1) -41 -update t1 set s1=0x12 where a=2; -select hex(s1) from t2; -hex(s1) -12 -delete from t1 where a=1; -delete from t1 where a=2; -ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `c` FOREIGN KEY (`s1`) REFERENCES `t1` (`s1`) ON UPDATE CASCADE) -select a,hex(s1) from t1; -a hex(s1) -2 12 -select hex(s1) from t2; -hex(s1) -12 -drop table t2,t1; -CREATE TABLE t1(a INT, PRIMARY KEY(a)) ENGINE=InnoDB; -CREATE TABLE t2(a INT) ENGINE=InnoDB; -ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1(a); -ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_1; -ALTER TABLE t2 ADD CONSTRAINT t2_ibfk_0 FOREIGN KEY (a) REFERENCES t1(a); -ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_0; -SHOW CREATE TABLE t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `a` int(11) DEFAULT NULL, - KEY `t2_ibfk_0` (`a`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -DROP TABLE t2,t1; -create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -insert into t1(a) values (1),(2),(3); -commit; -set autocommit = 0; -update t1 set b = 5 where a = 2; -create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end | -set autocommit = 0; -insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100), -(11),(21),(31),(41),(51),(61),(71),(81),(91),(101), -(12),(22),(32),(42),(52),(62),(72),(82),(92),(102), -(13),(23),(33),(43),(53),(63),(73),(83),(93),(103), -(14),(24),(34),(44),(54),(64),(74),(84),(94),(104); -commit; -commit; -drop trigger t1t; -drop table t1; -create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t2(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t3(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t4(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t5(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -insert into t1(a) values (1),(2),(3); -insert into t2(a) values (1),(2),(3); -insert into t3(a) values (1),(2),(3); -insert into t4(a) values (1),(2),(3); -insert into t3(a) values (5),(7),(8); -insert into t4(a) values (5),(7),(8); -insert into t5(a) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12); -create trigger t1t before insert on t1 for each row begin -INSERT INTO t2 SET a = NEW.a; -end | -create trigger t2t before insert on t2 for each row begin -DELETE FROM t3 WHERE a = NEW.a; -end | -create trigger t3t before delete on t3 for each row begin -UPDATE t4 SET b = b + 1 WHERE a = OLD.a; -end | -create trigger t4t before update on t4 for each row begin -UPDATE t5 SET b = b + 1 where a = NEW.a; -end | -commit; -set autocommit = 0; -update t1 set b = b + 5 where a = 1; -update t2 set b = b + 5 where a = 1; -update t3 set b = b + 5 where a = 1; -update t4 set b = b + 5 where a = 1; -insert into t5(a) values(20); -set autocommit = 0; -insert into t1(a) values(7); -insert into t2(a) values(8); -delete from t2 where a = 3; -update t4 set b = b + 1 where a = 3; -commit; -drop trigger t1t; -drop trigger t2t; -drop trigger t3t; -drop trigger t4t; -drop table t1, t2, t3, t4, t5; -CREATE TABLE t1 ( -field1 varchar(8) NOT NULL DEFAULT '', -field2 varchar(8) NOT NULL DEFAULT '', -PRIMARY KEY (field1, field2) -) ENGINE=InnoDB; -CREATE TABLE t2 ( -field1 varchar(8) NOT NULL DEFAULT '' PRIMARY KEY, -FOREIGN KEY (field1) REFERENCES t1 (field1) -ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB; -INSERT INTO t1 VALUES ('old', 'somevalu'); -INSERT INTO t1 VALUES ('other', 'anyvalue'); -INSERT INTO t2 VALUES ('old'); -INSERT INTO t2 VALUES ('other'); -UPDATE t1 SET field1 = 'other' WHERE field2 = 'somevalu'; -ERROR 23000: Upholding foreign key constraints for table 't1', entry 'other-somevalu', key 1 would lead to a duplicate entry -DROP TABLE t2; -DROP TABLE t1; -create table t1 ( -c1 bigint not null, -c2 bigint not null, -primary key (c1), -unique key (c2) -) engine=innodb; -create table t2 ( -c1 bigint not null, -primary key (c1) -) engine=innodb; -alter table t1 add constraint c2_fk foreign key (c2) -references t2(c1) on delete cascade; -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` bigint(20) NOT NULL, - `c2` bigint(20) NOT NULL, - PRIMARY KEY (`c1`), - UNIQUE KEY `c2` (`c2`), - CONSTRAINT `c2_fk` FOREIGN KEY (`c2`) REFERENCES `t2` (`c1`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -alter table t1 drop foreign key c2_fk; -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `c1` bigint(20) NOT NULL, - `c2` bigint(20) NOT NULL, - PRIMARY KEY (`c1`), - UNIQUE KEY `c2` (`c2`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -drop table t1, t2; -create table t1(a date) engine=innodb; -create table t2(a date, key(a)) engine=innodb; -insert into t1 values('2005-10-01'); -insert into t2 values('2005-10-01'); -select * from t1, t2 -where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; -a a -2005-10-01 2005-10-01 -drop table t1, t2; -create table t1 (id int not null, f_id int not null, f int not null, -primary key(f_id, id)) engine=innodb; -create table t2 (id int not null,s_id int not null,s varchar(200), -primary key(id)) engine=innodb; -INSERT INTO t1 VALUES (8, 1, 3); -INSERT INTO t1 VALUES (1, 2, 1); -INSERT INTO t2 VALUES (1, 0, ''); -INSERT INTO t2 VALUES (8, 1, ''); -commit; -DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id) -WHERE mm.id IS NULL; -select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id) -where mm.id is null lock in share mode; -id f_id f -drop table t1,t2; -create table t1(a int not null, b int, primary key(a)) engine=innodb; -insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); -commit; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -update t1 set b = 5 where b = 1; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -select * from t1 where a = 7 and b = 3 for update; -a b -7 3 -commit; -commit; -drop table t1; -create table t1(a int not null, b int, primary key(a)) engine=innodb; -insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); -commit; -set autocommit = 0; -select * from t1 lock in share mode; -a b -1 1 -2 2 -3 1 -4 2 -5 1 -6 2 -update t1 set b = 5 where b = 1; -set autocommit = 0; -select * from t1 where a = 2 and b = 2 for update; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -commit; -commit; -drop table t1; -create table t1(a int not null, b int, primary key(a)) engine=innodb; -insert into t1 values (1,2),(5,3),(4,2); -create table t2(d int not null, e int, primary key(d)) engine=innodb; -insert into t2 values (8,6),(12,1),(3,1); -commit; -set autocommit = 0; -select * from t2 for update; -d e -3 1 -8 6 -12 1 -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -insert into t1 select * from t2; -update t1 set b = (select e from t2 where a = d); -create table t3(d int not null, e int, primary key(d)) engine=innodb -select * from t2; -commit; -commit; -drop table t1, t2, t3; -create table t1(a int not null, b int, primary key(a)) engine=innodb; -insert into t1 values (1,2),(5,3),(4,2); -create table t2(a int not null, b int, primary key(a)) engine=innodb; -insert into t2 values (8,6),(12,1),(3,1); -create table t3(d int not null, b int, primary key(d)) engine=innodb; -insert into t3 values (8,6),(12,1),(3,1); -create table t5(a int not null, b int, primary key(a)) engine=innodb; -insert into t5 values (1,2),(5,3),(4,2); -create table t6(d int not null, e int, primary key(d)) engine=innodb; -insert into t6 values (8,6),(12,1),(3,1); -create table t8(a int not null, b int, primary key(a)) engine=innodb; -insert into t8 values (1,2),(5,3),(4,2); -create table t9(d int not null, e int, primary key(d)) engine=innodb; -insert into t9 values (8,6),(12,1),(3,1); -commit; -set autocommit = 0; -select * from t2 for update; -a b -3 1 -8 6 -12 1 -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; -insert into t1 select * from t2; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; -update t3 set b = (select b from t2 where a = d); -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; -create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -insert into t5 (select * from t2 lock in share mode); -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -update t6 set e = (select b from t2 where a = d lock in share mode); -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -insert into t8 (select * from t2 for update); -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -update t9 set e = (select b from t2 where a = d for update); -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update; -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -ERROR HY000: Lock wait timeout exceeded; try restarting transaction -commit; -drop table t1, t2, t3, t5, t6, t8, t9; -CREATE TABLE t1 (DB_ROW_ID int) engine=innodb; -ERROR HY000: Can't create table 'test.t1' (errno: -1) -CREATE TABLE t1 ( -a BIGINT(20) NOT NULL, -PRIMARY KEY (a) -) ENGINE=INNODB DEFAULT CHARSET=UTF8; -CREATE TABLE t2 ( -a BIGINT(20) NOT NULL, -b VARCHAR(128) NOT NULL, -c TEXT NOT NULL, -PRIMARY KEY (a,b), -KEY idx_t2_b_c (b,c(200)), -CONSTRAINT t_fk FOREIGN KEY (a) REFERENCES t1 (a) -ON DELETE CASCADE -) ENGINE=INNODB DEFAULT CHARSET=UTF8; -INSERT INTO t1 VALUES (1); -INSERT INTO t2 VALUES (1, 'bar', 'vbar'); -INSERT INTO t2 VALUES (1, 'BAR2', 'VBAR'); -INSERT INTO t2 VALUES (1, 'bar_bar', 'bibi'); -INSERT INTO t2 VALUES (1, 'customer_over', '1'); -SELECT * FROM t2 WHERE b = 'customer_over'; -a b c -1 customer_over 1 -SELECT * FROM t2 WHERE BINARY b = 'customer_over'; -a b c -1 customer_over 1 -SELECT DISTINCT p0.a FROM t2 p0 WHERE p0.b = 'customer_over'; -a -1 -/* Bang: Empty result set, above was expected: */ -SELECT DISTINCT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; -a -1 -SELECT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; -a -1 -drop table t2, t1; -CREATE TABLE t1 ( a int ) ENGINE=innodb; -BEGIN; -INSERT INTO t1 VALUES (1); -OPTIMIZE TABLE t1; -Table Op Msg_type Msg_text -test.t1 optimize note Table does not support optimize, doing recreate + analyze instead -test.t1 optimize status OK -DROP TABLE t1; -CREATE TABLE t1 (id int PRIMARY KEY, f int NOT NULL, INDEX(f)) ENGINE=InnoDB; -CREATE TABLE t2 (id int PRIMARY KEY, f INT NOT NULL, -CONSTRAINT t2_t1 FOREIGN KEY (id) REFERENCES t1 (id) -ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB; -ALTER TABLE t2 ADD FOREIGN KEY (f) REFERENCES t1 (f) ON -DELETE CASCADE ON UPDATE CASCADE; -SHOW CREATE TABLE t2; -Table Create Table -t2 CREATE TABLE `t2` ( - `id` int(11) NOT NULL, - `f` int(11) NOT NULL, - PRIMARY KEY (`id`), - KEY `f` (`f`), - CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`f`) REFERENCES `t1` (`f`) ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT `t2_t1` FOREIGN KEY (`id`) REFERENCES `t1` (`id`) ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -DROP TABLE t2, t1; -CREATE TABLE t1 (a INT, INDEX(a)) ENGINE=InnoDB; -CREATE TABLE t2 (a INT, INDEX(a)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (1); -INSERT INTO t2 VALUES (1); -ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1 (a) ON DELETE SET NULL; -ALTER TABLE t2 MODIFY a INT NOT NULL; -ERROR HY000: Error on rename of '#sql-temporary' to './test/t2' (errno: 150) -DELETE FROM t1; -DROP TABLE t2,t1; -CREATE TABLE t1 (a VARCHAR(5) COLLATE utf8_unicode_ci PRIMARY KEY) -ENGINE=InnoDB; -INSERT INTO t1 VALUES (0xEFBCA4EFBCA4EFBCA4); -DELETE FROM t1; -INSERT INTO t1 VALUES ('DDD'); -SELECT * FROM t1; -a -DDD -DROP TABLE t1; -CREATE TABLE t1 (id int PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB -AUTO_INCREMENT=42; -INSERT INTO t1 VALUES (0),(347),(0); -SELECT * FROM t1; -id -42 -347 -348 -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=349 DEFAULT CHARSET=latin1 -CREATE TABLE t2 (id int PRIMARY KEY) ENGINE=InnoDB; -INSERT INTO t2 VALUES(42),(347),(348); -ALTER TABLE t1 ADD CONSTRAINT t1_t2 FOREIGN KEY (id) REFERENCES t2(id); -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - PRIMARY KEY (`id`), - CONSTRAINT `t1_t2` FOREIGN KEY (`id`) REFERENCES `t2` (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=349 DEFAULT CHARSET=latin1 -DROP TABLE t1,t2; -set innodb_strict_mode=on; -CREATE TABLE t1 ( -c01 CHAR(255), c02 CHAR(255), c03 CHAR(255), c04 CHAR(255), -c05 CHAR(255), c06 CHAR(255), c07 CHAR(255), c08 CHAR(255), -c09 CHAR(255), c10 CHAR(255), c11 CHAR(255), c12 CHAR(255), -c13 CHAR(255), c14 CHAR(255), c15 CHAR(255), c16 CHAR(255), -c17 CHAR(255), c18 CHAR(255), c19 CHAR(255), c20 CHAR(255), -c21 CHAR(255), c22 CHAR(255), c23 CHAR(255), c24 CHAR(255), -c25 CHAR(255), c26 CHAR(255), c27 CHAR(255), c28 CHAR(255), -c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255) -) ENGINE = InnoDB; -ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs -DROP TABLE IF EXISTS t1; -Warnings: -Note 1051 Unknown table 't1' -CREATE TABLE t1( -id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY -) ENGINE=InnoDB; -INSERT INTO t1 VALUES(-10); -SELECT * FROM t1; -id --10 -INSERT INTO t1 VALUES(NULL); -SELECT * FROM t1; -id --10 -1 -DROP TABLE t1; -SET binlog_format='MIXED'; -SET TX_ISOLATION='read-committed'; -SET AUTOCOMMIT=0; -DROP TABLE IF EXISTS t1, t2; -Warnings: -Note 1051 Unknown table 't1' -Note 1051 Unknown table 't2' -CREATE TABLE t1 ( a int ) ENGINE=InnoDB; -CREATE TABLE t2 LIKE t1; -SELECT * FROM t2; -a -SET binlog_format='MIXED'; -SET TX_ISOLATION='read-committed'; -SET AUTOCOMMIT=0; -INSERT INTO t1 VALUES (1); -COMMIT; -SELECT * FROM t1 WHERE a=1; -a -1 -SET binlog_format='MIXED'; -SET TX_ISOLATION='read-committed'; -SET AUTOCOMMIT=0; -SELECT * FROM t2; -a -SET binlog_format='MIXED'; -SET TX_ISOLATION='read-committed'; -SET AUTOCOMMIT=0; -INSERT INTO t1 VALUES (2); -COMMIT; -SELECT * FROM t1 WHERE a=2; -a -2 -SELECT * FROM t1 WHERE a=2; -a -2 -DROP TABLE t1; -DROP TABLE t2; -create table t1 (i int, j int) engine=innodb; -insert into t1 (i, j) values (1, 1), (2, 2); -update t1 set j = 2; -affected rows: 1 -info: Rows matched: 2 Changed: 1 Warnings: 0 -drop table t1; -create table t1 (id int) comment='this is a comment' engine=innodb; -select table_comment, data_free > 0 as data_free_is_set -from information_schema.tables -where table_schema='test' and table_name = 't1'; -table_comment data_free_is_set -this is a comment 1 -drop table t1; -CREATE TABLE t1 ( -c1 INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, -c2 VARCHAR(128) NOT NULL, -PRIMARY KEY(c1) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=100; -CREATE TABLE t2 ( -c1 INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, -c2 INT(10) UNSIGNED DEFAULT NULL, -PRIMARY KEY(c1) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=200; -SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE table_name = 't2'; -AUTO_INCREMENT -200 -ALTER TABLE t2 ADD CONSTRAINT t1_t2_1 FOREIGN KEY(c1) REFERENCES t1(c1); -SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE table_name = 't2'; -AUTO_INCREMENT -200 -DROP TABLE t2; -DROP TABLE t1; -CREATE TABLE t1 (c1 int default NULL, -c2 int default NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; -TRUNCATE TABLE t1; -affected rows: 0 -INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5); -affected rows: 5 -info: Records: 5 Duplicates: 0 Warnings: 0 -TRUNCATE TABLE t1; -affected rows: 0 -DROP TABLE t1; -Variable_name Value -Handler_update 0 -Variable_name Value -Handler_delete 0 -Variable_name Value -Handler_update 1 -Variable_name Value -Handler_delete 1 diff --git a/storage/innobase/mysql-test/innodb.test b/storage/innobase/mysql-test/innodb.test deleted file mode 100644 index f46a3a70b56..00000000000 --- a/storage/innobase/mysql-test/innodb.test +++ /dev/null @@ -1,2569 +0,0 @@ -####################################################################### -# # -# Please, DO NOT TOUCH this file as well as the innodb.result file. # -# These files are to be modified ONLY BY INNOBASE guys. # -# # -# Use innodb_mysql.[test|result] files instead. # -# # -# If nevertheless you need to make some changes here, please, forward # -# your commit message # -# To: innodb_dev_ww@oracle.com # -# Cc: dev-innodb@mysql.com # -# (otherwise your changes may be erased). # -# # -####################################################################### - --- source include/have_innodb.inc - -# Save the original values of some variables in order to be able to -# estimate how much they have changed during the tests. Previously this -# test assumed that e.g. rows_deleted is 0 here and after deleting 23 -# rows it expected that rows_deleted will be 23. Now we do not make -# assumptions about the values of the variables at the beginning, e.g. -# rows_deleted should be 23 + "rows_deleted before the test". This allows -# the test to be run multiple times without restarting the mysqld server. -# See Bug#43309 Test main.innodb can't be run twice --- disable_query_log -SET @innodb_thread_concurrency_orig = @@innodb_thread_concurrency; - -SET @innodb_rows_deleted_orig = (SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_deleted'); -SET @innodb_rows_inserted_orig = (SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_inserted'); -SET @innodb_rows_updated_orig = (SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_updated'); -SET @innodb_row_lock_waits_orig = (SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_waits'); -SET @innodb_row_lock_current_waits_orig = (SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_current_waits'); -SET @innodb_row_lock_time_orig = (SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_time'); -SET @innodb_row_lock_time_max_orig = (SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_time_max'); -SET @innodb_row_lock_time_avg_orig = (SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_time_avg'); --- enable_query_log - ---disable_warnings -drop table if exists t1,t2,t3,t4; -drop database if exists mysqltest; ---enable_warnings - -# -# Small basic test with ignore -# - -create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) engine=innodb; - -insert into t1 (code, name) values (1, 'Tim'), (1, 'Monty'), (2, 'David'), (2, 'Erik'), (3, 'Sasha'), (3, 'Jeremy'), (4, 'Matt'); -select id, code, name from t1 order by id; - -update ignore t1 set id = 8, name = 'Sinisa' where id < 3; -select id, code, name from t1 order by id; -update ignore t1 set id = id + 10, name = 'Ralph' where id < 4; -select id, code, name from t1 order by id; - -drop table t1; - -# -# A bit bigger test -# The 'replace_column' statements are needed because the cardinality calculated -# by innodb is not always the same between runs -# - -CREATE TABLE t1 ( - id int(11) NOT NULL auto_increment, - parent_id int(11) DEFAULT '0' NOT NULL, - level tinyint(4) DEFAULT '0' NOT NULL, - PRIMARY KEY (id), - KEY parent_id (parent_id), - KEY level (level) -) engine=innodb; -INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),(24,4,2),(28,5,2),(29,5,2),(30,5,2),(31,6,2),(32,6,2),(33,6,2),(203,7,2),(202,7,2),(20,3,2),(157,0,0),(193,5,2),(40,7,2),(2,1,1),(15,2,2),(6,1,1),(34,6,2),(35,6,2),(16,3,2),(7,1,1),(36,7,2),(18,3,2),(26,5,2),(27,5,2),(183,4,2),(38,7,2),(25,5,2),(37,7,2),(21,4,2),(19,3,2),(5,1,1),(179,5,2); -update t1 set parent_id=parent_id+100; -select * from t1 where parent_id=102; -update t1 set id=id+1000; --- error ER_DUP_ENTRY,1022 -update t1 set id=1024 where id=1009; -select * from t1; -update ignore t1 set id=id+1; # This will change all rows -select * from t1; -update ignore t1 set id=1023 where id=1010; -select * from t1 where parent_id=102; ---replace_column 9 # -explain select level from t1 where level=1; ---replace_column 9 # -explain select level,id from t1 where level=1; ---replace_column 9 # -explain select level,id,parent_id from t1 where level=1; -select level,id from t1 where level=1; -select level,id,parent_id from t1 where level=1; -optimize table t1; ---replace_column 7 # -show keys from t1; -drop table t1; - -# -# Test replace -# - -CREATE TABLE t1 ( - gesuchnr int(11) DEFAULT '0' NOT NULL, - benutzer_id int(11) DEFAULT '0' NOT NULL, - PRIMARY KEY (gesuchnr,benutzer_id) -) engine=innodb; - -replace into t1 (gesuchnr,benutzer_id) values (2,1); -replace into t1 (gesuchnr,benutzer_id) values (1,1); -replace into t1 (gesuchnr,benutzer_id) values (1,1); -select * from t1; -drop table t1; - -# -# test delete using hidden_primary_key -# - -create table t1 (a int) engine=innodb; -insert into t1 values (1), (2); -optimize table t1; -delete from t1 where a = 1; -select * from t1; -check table t1; -drop table t1; - -create table t1 (a int,b varchar(20)) engine=innodb; -insert into t1 values (1,""), (2,"testing"); -delete from t1 where a = 1; -select * from t1; -create index skr on t1 (a); -insert into t1 values (3,""), (4,"testing"); -analyze table t1; ---replace_column 7 # -show keys from t1; -drop table t1; - - -# Test of reading on secondary key with may be null - -create table t1 (a int,b varchar(20),key(a)) engine=innodb; -insert into t1 values (1,""), (2,"testing"); -select * from t1 where a = 1; -drop table t1; - -# -# Test rollback -# - -create table t1 (n int not null primary key) engine=innodb; -set autocommit=0; -insert into t1 values (4); -rollback; -select n, "after rollback" from t1; -insert into t1 values (4); -commit; -select n, "after commit" from t1; -commit; -insert into t1 values (5); --- error ER_DUP_ENTRY -insert into t1 values (4); -commit; -select n, "after commit" from t1; -set autocommit=1; -insert into t1 values (6); --- error ER_DUP_ENTRY -insert into t1 values (4); -select n from t1; -set autocommit=0; -# -# savepoints -# -begin; -savepoint `my_savepoint`; -insert into t1 values (7); -savepoint `savept2`; -insert into t1 values (3); -select n from t1; -savepoint savept3; -rollback to savepoint savept2; ---error 1305 -rollback to savepoint savept3; -rollback to savepoint savept2; -release savepoint `my_savepoint`; -select n from t1; --- error 1305 -rollback to savepoint `my_savepoint`; ---error 1305 -rollback to savepoint savept2; -insert into t1 values (8); -savepoint sv; -commit; -savepoint sv; -set autocommit=1; -# nop -rollback; -drop table t1; - -# -# Test for commit and FLUSH TABLES WITH READ LOCK -# - -create table t1 (n int not null primary key) engine=innodb; -start transaction; -insert into t1 values (4); -flush tables with read lock; -# -# Current code can't handle a read lock in middle of transaction -#--error 1223; -commit; -unlock tables; -commit; -select * from t1; -drop table t1; - -# -# Testing transactions -# - -create table t1 ( id int NOT NULL PRIMARY KEY, nom varchar(64)) engine=innodb; -begin; -insert into t1 values(1,'hamdouni'); -select id as afterbegin_id,nom as afterbegin_nom from t1; -rollback; -select id as afterrollback_id,nom as afterrollback_nom from t1; -set autocommit=0; -insert into t1 values(2,'mysql'); -select id as afterautocommit0_id,nom as afterautocommit0_nom from t1; -rollback; -select id as afterrollback_id,nom as afterrollback_nom from t1; -set autocommit=1; -drop table t1; - -# -# Simple not autocommit test -# - -CREATE TABLE t1 (id char(8) not null primary key, val int not null) engine=innodb; -insert into t1 values ('pippo', 12); --- error ER_DUP_ENTRY -insert into t1 values ('pippo', 12); # Gives error -delete from t1; -delete from t1 where id = 'pippo'; -select * from t1; - -insert into t1 values ('pippo', 12); -set autocommit=0; -delete from t1; -rollback; -select * from t1; -delete from t1; -commit; -select * from t1; -drop table t1; - -# -# Test of active transactions -# - -create table t1 (a integer) engine=innodb; -start transaction; -rename table t1 to t2; -create table t1 (b integer) engine=innodb; -insert into t1 values (1); -rollback; -drop table t1; -rename table t2 to t1; -drop table t1; -set autocommit=1; - -# -# The following simple tests failed at some point -# - -CREATE TABLE t1 (ID INTEGER NOT NULL PRIMARY KEY, NAME VARCHAR(64)) ENGINE=innodb; -INSERT INTO t1 VALUES (1, 'Jochen'); -select * from t1; -drop table t1; - -CREATE TABLE t1 ( _userid VARCHAR(60) NOT NULL PRIMARY KEY) ENGINE=innodb; -set autocommit=0; -INSERT INTO t1 SET _userid='marc@anyware.co.uk'; -COMMIT; -SELECT * FROM t1; -SELECT _userid FROM t1 WHERE _userid='marc@anyware.co.uk'; -drop table t1; -set autocommit=1; - -# -# Test when reading on part of unique key -# -CREATE TABLE t1 ( - user_id int(10) DEFAULT '0' NOT NULL, - name varchar(100), - phone varchar(100), - ref_email varchar(100) DEFAULT '' NOT NULL, - detail varchar(200), - PRIMARY KEY (user_id,ref_email) -)engine=innodb; - -INSERT INTO t1 VALUES (10292,'sanjeev','29153373','sansh777@hotmail.com','xxx'),(10292,'shirish','2333604','shirish@yahoo.com','ddsds'),(10292,'sonali','323232','sonali@bolly.com','filmstar'); -select * from t1 where user_id=10292; -INSERT INTO t1 VALUES (10291,'sanjeev','29153373','sansh777@hotmail.com','xxx'),(10293,'shirish','2333604','shirish@yahoo.com','ddsds'); -select * from t1 where user_id=10292; -select * from t1 where user_id>=10292; -select * from t1 where user_id>10292; -select * from t1 where user_id<10292; -drop table t1; - -# -# Test that keys are created in right order -# - -CREATE TABLE t1 (a int not null, b int not null,c int not null, -key(a),primary key(a,b), unique(c),key(a),unique(b)); ---replace_column 7 # -show index from t1; -drop table t1; - -# -# Test of ALTER TABLE and innodb tables -# - -create table t1 (col1 int not null, col2 char(4) not null, primary key(col1)); -alter table t1 engine=innodb; -insert into t1 values ('1','1'),('5','2'),('2','3'),('3','4'),('4','4'); -select * from t1; -update t1 set col2='7' where col1='4'; -select * from t1; -alter table t1 add co3 int not null; -select * from t1; -update t1 set col2='9' where col1='2'; -select * from t1; -drop table t1; - -# -# INSERT INTO innodb tables -# - -create table t1 (a int not null , b int, primary key (a)) engine = innodb; -create table t2 (a int not null , b int, primary key (a)) engine = myisam; -insert into t1 VALUES (1,3) , (2,3), (3,3); -select * from t1; -insert into t2 select * from t1; -select * from t2; -delete from t1 where b = 3; -select * from t1; -insert into t1 select * from t2; -select * from t1; -select * from t2; -drop table t1,t2; - -# -# ORDER BY on not primary key -# - -CREATE TABLE t1 ( - user_name varchar(12), - password text, - subscribed char(1), - user_id int(11) DEFAULT '0' NOT NULL, - quota bigint(20), - weight double, - access_date date, - access_time time, - approved datetime, - dummy_primary_key int(11) NOT NULL auto_increment, - PRIMARY KEY (dummy_primary_key) -) ENGINE=innodb; -INSERT INTO t1 VALUES ('user_0','somepassword','N',0,0,0,'2000-09-07','23:06:59','2000-09-07 23:06:59',1); -INSERT INTO t1 VALUES ('user_1','somepassword','Y',1,1,1,'2000-09-07','23:06:59','2000-09-07 23:06:59',2); -INSERT INTO t1 VALUES ('user_2','somepassword','N',2,2,1.4142135623731,'2000-09-07','23:06:59','2000-09-07 23:06:59',3); -INSERT INTO t1 VALUES ('user_3','somepassword','Y',3,3,1.7320508075689,'2000-09-07','23:06:59','2000-09-07 23:06:59',4); -INSERT INTO t1 VALUES ('user_4','somepassword','N',4,4,2,'2000-09-07','23:06:59','2000-09-07 23:06:59',5); -select user_name, password , subscribed, user_id, quota, weight, access_date, access_time, approved, dummy_primary_key from t1 order by user_name; -drop table t1; - -# -# Testing of tables without primary keys -# - -CREATE TABLE t1 ( - id int(11) NOT NULL auto_increment, - parent_id int(11) DEFAULT '0' NOT NULL, - level tinyint(4) DEFAULT '0' NOT NULL, - KEY (id), - KEY parent_id (parent_id), - KEY level (level) -) engine=innodb; -INSERT INTO t1 VALUES (1,0,0),(3,1,1),(4,1,1),(8,2,2),(9,2,2),(17,3,2),(22,4,2),(24,4,2),(28,5,2),(29,5,2),(30,5,2),(31,6,2),(32,6,2),(33,6,2),(203,7,2),(202,7,2),(20,3,2),(157,0,0),(193,5,2),(40,7,2),(2,1,1),(15,2,2),(6,1,1),(34,6,2),(35,6,2),(16,3,2),(7,1,1),(36,7,2),(18,3,2),(26,5,2),(27,5,2),(183,4,2),(38,7,2),(25,5,2),(37,7,2),(21,4,2),(19,3,2),(5,1,1); -INSERT INTO t1 values (179,5,2); -update t1 set parent_id=parent_id+100; -select * from t1 where parent_id=102; -update t1 set id=id+1000; -update t1 set id=1024 where id=1009; -select * from t1; -update ignore t1 set id=id+1; # This will change all rows -select * from t1; -update ignore t1 set id=1023 where id=1010; -select * from t1 where parent_id=102; ---replace_column 9 # -explain select level from t1 where level=1; -select level,id from t1 where level=1; -select level,id,parent_id from t1 where level=1; -select level,id from t1 where level=1 order by id; -delete from t1 where level=1; -select * from t1; -drop table t1; - -# -# Test of index only reads -# -CREATE TABLE t1 ( - sca_code char(6) NOT NULL, - cat_code char(6) NOT NULL, - sca_desc varchar(50), - lan_code char(2) NOT NULL, - sca_pic varchar(100), - sca_sdesc varchar(50), - sca_sch_desc varchar(16), - PRIMARY KEY (sca_code, cat_code, lan_code), - INDEX sca_pic (sca_pic) -) engine = innodb ; - -INSERT INTO t1 ( sca_code, cat_code, sca_desc, lan_code, sca_pic, sca_sdesc, sca_sch_desc) VALUES ( 'PD', 'J', 'PENDANT', 'EN', NULL, NULL, 'PENDANT'),( 'RI', 'J', 'RING', 'EN', NULL, NULL, 'RING'),( 'QQ', 'N', 'RING', 'EN', 'not null', NULL, 'RING'); -select count(*) from t1 where sca_code = 'PD'; -select count(*) from t1 where sca_code <= 'PD'; -select count(*) from t1 where sca_pic is null; -alter table t1 drop index sca_pic, add index sca_pic (cat_code, sca_pic); -select count(*) from t1 where sca_code='PD' and sca_pic is null; -select count(*) from t1 where cat_code='E'; - -alter table t1 drop index sca_pic, add index (sca_pic, cat_code); -select count(*) from t1 where sca_code='PD' and sca_pic is null; -select count(*) from t1 where sca_pic >= 'n'; -select sca_pic from t1 where sca_pic is null; -update t1 set sca_pic="test" where sca_pic is null; -delete from t1 where sca_code='pd'; -drop table t1; - -# -# Test of opening table twice and timestamps -# -set @a:=now(); -CREATE TABLE t1 (a int not null, b timestamp not null, primary key (a)) engine=innodb; -insert into t1 (a) values(1),(2),(3); -select t1.a from t1 natural join t1 as t2 where t1.b >= @a order by t1.a; -select a from t1 natural join t1 as t2 where b >= @a order by a; -update t1 set a=5 where a=1; -select a from t1; -drop table t1; - -# -# Test with variable length primary key -# -create table t1 (a varchar(100) not null, primary key(a), b int not null) engine=innodb; -insert into t1 values("hello",1),("world",2); -select * from t1 order by b desc; -optimize table t1; ---replace_column 7 # -show keys from t1; -drop table t1; - -# -# Test of create index with NULL columns -# -create table t1 (i int, j int ) ENGINE=innodb; -insert into t1 values (1,2); -select * from t1 where i=1 and j=2; -create index ax1 on t1 (i,j); -select * from t1 where i=1 and j=2; -drop table t1; - -# -# Test min-max optimization -# - -CREATE TABLE t1 ( - a int3 unsigned NOT NULL, - b int1 unsigned NOT NULL, - UNIQUE (a, b) -) ENGINE = innodb; - -INSERT INTO t1 VALUES (1, 1); -SELECT MIN(B),MAX(b) FROM t1 WHERE t1.a = 1; -drop table t1; - -# -# Test INSERT DELAYED -# - -CREATE TABLE t1 (a int unsigned NOT NULL) engine=innodb; -# Can't test this in 3.23 -# INSERT DELAYED INTO t1 VALUES (1); -INSERT INTO t1 VALUES (1); -SELECT * FROM t1; -DROP TABLE t1; - - -# -# Crash when using many tables (Test case by Jeremy D Zawodny) -# - -create table t1 (a int primary key,b int, c int, d int, e int, f int, g int, h int, i int, j int, k int, l int, m int, n int, o int, p int, q int, r int, s int, t int, u int, v int, w int, x int, y int, z int, a1 int, a2 int, a3 int, a4 int, a5 int, a6 int, a7 int, a8 int, a9 int, b1 int, b2 int, b3 int, b4 int, b5 int, b6 int) engine = innodb; -insert into t1 values (1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1); ---replace_column 9 # -explain select * from t1 where a > 0 and a < 50; -drop table t1; - -# -# Test lock tables -# - -create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) engine=innodb; -insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL'); -LOCK TABLES t1 WRITE; ---error ER_DUP_ENTRY -insert into t1 values (99,1,2,'D'),(1,1,2,'D'); -select id from t1; -select id from t1; -UNLOCK TABLES; -DROP TABLE t1; - -create table t1 (id int NOT NULL,id2 int NOT NULL,id3 int NOT NULL,dummy1 char(30),primary key (id,id2),index index_id3 (id3)) engine=innodb; -insert into t1 values (0,0,0,'ABCDEFGHIJ'),(2,2,2,'BCDEFGHIJK'),(1,1,1,'CDEFGHIJKL'); -LOCK TABLES t1 WRITE; -begin; ---error ER_DUP_ENTRY -insert into t1 values (99,1,2,'D'),(1,1,2,'D'); -select id from t1; -insert ignore into t1 values (100,1,2,'D'),(1,1,99,'D'); -commit; -select id,id3 from t1; -UNLOCK TABLES; -DROP TABLE t1; - -# -# Test prefix key -# -create table t1 (a char(20), unique (a(5))) engine=innodb; -drop table t1; -create table t1 (a char(20), index (a(5))) engine=innodb; -show create table t1; -drop table t1; - -# -# Test using temporary table and auto_increment -# - -create temporary table t1 (a int not null auto_increment, primary key(a)) engine=innodb; -insert into t1 values (NULL),(NULL),(NULL); -delete from t1 where a=3; -insert into t1 values (NULL); -select * from t1; -alter table t1 add b int; -select * from t1; -drop table t1; - -#Slashdot bug -create table t1 - ( - id int auto_increment primary key, - name varchar(32) not null, - value text not null, - uid int not null, - unique key(name,uid) - ) engine=innodb; -insert into t1 values (1,'one','one value',101), - (2,'two','two value',102),(3,'three','three value',103); -set insert_id=5; -replace into t1 (value,name,uid) values ('other value','two',102); -delete from t1 where uid=102; -set insert_id=5; -replace into t1 (value,name,uid) values ('other value','two',102); -set insert_id=6; -replace into t1 (value,name,uid) values ('other value','two',102); -select * from t1; -drop table t1; - -# -# Test DROP DATABASE -# - -create database mysqltest; -create table mysqltest.t1 (a int not null) engine= innodb; -insert into mysqltest.t1 values(1); -create table mysqltest.t2 (a int not null) engine= myisam; -insert into mysqltest.t2 values(1); -create table mysqltest.t3 (a int not null) engine= heap; -insert into mysqltest.t3 values(1); -commit; -drop database mysqltest; -# Don't check error message ---error 1049 -show tables from mysqltest; - -# -# Test truncate table with and without auto_commit -# - -set autocommit=0; -create table t1 (a int not null) engine= innodb; -insert into t1 values(1),(2); -truncate table t1; -commit; -truncate table t1; -truncate table t1; -select * from t1; -insert into t1 values(1),(2); -delete from t1; -select * from t1; -commit; -drop table t1; -set autocommit=1; - -create table t1 (a int not null) engine= innodb; -insert into t1 values(1),(2); -truncate table t1; -insert into t1 values(1),(2); -select * from t1; -truncate table t1; -insert into t1 values(1),(2); -delete from t1; -select * from t1; -drop table t1; - -# -# Test of how ORDER BY works when doing it on the whole table -# - -create table t1 (a int not null, b int not null, c int not null, primary key (a),key(b)) engine=innodb; -insert into t1 values (3,3,3),(1,1,1),(2,2,2),(4,4,4); ---replace_column 9 # -explain select * from t1 order by a; ---replace_column 9 # -explain select * from t1 order by b; ---replace_column 9 # -explain select * from t1 order by c; ---replace_column 9 # -explain select a from t1 order by a; ---replace_column 9 # -explain select b from t1 order by b; ---replace_column 9 # -explain select a,b from t1 order by b; ---replace_column 9 # -explain select a,b from t1; ---replace_column 9 # -explain select a,b,c from t1; -drop table t1; - -# -# Check describe -# - -create table t1 (t int not null default 1, key (t)) engine=innodb; -desc t1; -drop table t1; - -# -# Test of multi-table-delete -# - -CREATE TABLE t1 ( - number bigint(20) NOT NULL default '0', - cname char(15) NOT NULL default '', - carrier_id smallint(6) NOT NULL default '0', - privacy tinyint(4) NOT NULL default '0', - last_mod_date timestamp NOT NULL, - last_mod_id smallint(6) NOT NULL default '0', - last_app_date timestamp NOT NULL, - last_app_id smallint(6) default '-1', - version smallint(6) NOT NULL default '0', - assigned_scps int(11) default '0', - status tinyint(4) default '0' -) ENGINE=InnoDB; -INSERT INTO t1 VALUES (4077711111,'SeanWheeler',90,2,20020111112846,500,00000000000000,-1,2,3,1); -INSERT INTO t1 VALUES (9197722223,'berry',90,3,20020111112809,500,20020102114532,501,4,10,0); -INSERT INTO t1 VALUES (650,'San Francisco',0,0,20011227111336,342,00000000000000,-1,1,24,1); -INSERT INTO t1 VALUES (302467,'Sue\'s Subshop',90,3,20020109113241,500,20020102115111,501,7,24,0); -INSERT INTO t1 VALUES (6014911113,'SudzCarwash',520,1,20020102115234,500,20020102115259,501,33,32768,0); -INSERT INTO t1 VALUES (333,'tubs',99,2,20020109113440,501,20020109113440,500,3,10,0); -CREATE TABLE t2 ( - number bigint(20) NOT NULL default '0', - cname char(15) NOT NULL default '', - carrier_id smallint(6) NOT NULL default '0', - privacy tinyint(4) NOT NULL default '0', - last_mod_date timestamp NOT NULL, - last_mod_id smallint(6) NOT NULL default '0', - last_app_date timestamp NOT NULL, - last_app_id smallint(6) default '-1', - version smallint(6) NOT NULL default '0', - assigned_scps int(11) default '0', - status tinyint(4) default '0' -) ENGINE=InnoDB; -INSERT INTO t2 VALUES (4077711111,'SeanWheeler',0,2,20020111112853,500,00000000000000,-1,2,3,1); -INSERT INTO t2 VALUES (9197722223,'berry',90,3,20020111112818,500,20020102114532,501,4,10,0); -INSERT INTO t2 VALUES (650,'San Francisco',90,0,20020109113158,342,00000000000000,-1,1,24,1); -INSERT INTO t2 VALUES (333,'tubs',99,2,20020109113453,501,20020109113453,500,3,10,0); -select * from t1; -select * from t2; -delete t1, t2 from t1 left join t2 on t1.number=t2.number where (t1.carrier_id=90 and t1.number=t2.number) or (t2.carrier_id=90 and t1.number=t2.number) or (t1.carrier_id=90 and t2.number is null); -select * from t1; -select * from t2; -select * from t2; -drop table t1,t2; - -# -# A simple test with some isolation levels -# TODO: Make this into a test using replication to really test how -# this works. -# - -create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) engine=innodb; - -BEGIN; -SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; -SELECT @@tx_isolation,@@global.tx_isolation; -insert into t1 (code, name) values (1, 'Tim'), (1, 'Monty'), (2, 'David'); -select id, code, name from t1 order by id; -COMMIT; - -BEGIN; -SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ; -insert into t1 (code, name) values (2, 'Erik'), (3, 'Sasha'); -select id, code, name from t1 order by id; -COMMIT; - -SET binlog_format='MIXED'; -BEGIN; -SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -insert into t1 (code, name) values (3, 'Jeremy'), (4, 'Matt'); -select id, code, name from t1 order by id; -COMMIT; -DROP TABLE t1; - -# -# Test of multi-table-update -# -create table t1 (n int(10), d int(10)) engine=innodb; -create table t2 (n int(10), d int(10)) engine=innodb; -insert into t1 values(1,1),(1,2); -insert into t2 values(1,10),(2,20); -UPDATE t1,t2 SET t1.d=t2.d,t2.d=30 WHERE t1.n=t2.n; -select * from t1; -select * from t2; -drop table t1,t2; - -# -# Bug #29136 erred multi-delete on trans table does not rollback -# - -# prepare ---disable_warnings -drop table if exists t1, t2; ---enable_warnings -CREATE TABLE t1 (a int, PRIMARY KEY (a)); -CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -create trigger trg_del_t2 after delete on t2 for each row - insert into t1 values (1); -insert into t1 values (1); -insert into t2 values (1),(2); - - -# exec cases A, B - see multi_update.test - -# A. send_error() w/o send_eof() branch - ---error ER_DUP_ENTRY -delete t2 from t2; - -# check - -select count(*) from t2 /* must be 2 as restored after rollback caused by the error */; - -# cleanup bug#29136 - -drop table t1, t2; - - -# -# Bug #29136 erred multi-delete on trans table does not rollback -# - -# prepare ---disable_warnings -drop table if exists t1, t2; ---enable_warnings -CREATE TABLE t1 (a int, PRIMARY KEY (a)); -CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB; -create trigger trg_del_t2 after delete on t2 for each row - insert into t1 values (1); -insert into t1 values (1); -insert into t2 values (1),(2); - - -# exec cases A, B - see multi_update.test - -# A. send_error() w/o send_eof() branch - ---error ER_DUP_ENTRY -delete t2 from t2; - -# check - -select count(*) from t2 /* must be 2 as restored after rollback caused by the error */; - -# cleanup bug#29136 - -drop table t1, t2; - - -# -# Testing of IFNULL -# -create table t1 (a int, b int) engine=innodb; -insert into t1 values(20,null); -select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on -t2.b=t3.a; -select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on -t2.b=t3.a order by 1; -insert into t1 values(10,null); -select t2.b, ifnull(t2.b,"this is null") from t1 as t2 left join t1 as t3 on -t2.b=t3.a order by 1; -drop table t1; - -# -# Test of read_through not existing const_table -# - -create table t1 (a varchar(10) not null) engine=myisam; -create table t2 (b varchar(10) not null unique) engine=innodb; -select t1.a from t1,t2 where t1.a=t2.b; -drop table t1,t2; -create table t1 (a int not null, b int, primary key (a)) engine = innodb; -create table t2 (a int not null, b int, primary key (a)) engine = innodb; -insert into t1 values (10, 20); -insert into t2 values (10, 20); -update t1, t2 set t1.b = 150, t2.b = t1.b where t2.a = t1.a and t1.a = 10; -drop table t1,t2; - -# -# Test of multi-table-delete with foreign key constraints -# - -CREATE TABLE t1 (id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB; -CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), FOREIGN KEY (t1_id) REFERENCES t1(id) ON DELETE CASCADE ) ENGINE=INNODB; -insert into t1 set id=1; -insert into t2 set id=1, t1_id=1; -delete t1,t2 from t1,t2 where t1.id=t2.t1_id; -select * from t1; -select * from t2; -drop table t2,t1; -CREATE TABLE t1(id INT NOT NULL, PRIMARY KEY (id)) ENGINE=INNODB; -CREATE TABLE t2(id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id) ) ENGINE=INNODB; -INSERT INTO t1 VALUES(1); -INSERT INTO t2 VALUES(1, 1); -SELECT * from t1; -UPDATE t1,t2 SET t1.id=t1.id+1, t2.t1_id=t1.id+1; -SELECT * from t1; -UPDATE t1,t2 SET t1.id=t1.id+1 where t1.id!=t2.id; -SELECT * from t1; -DROP TABLE t1,t2; - -# -# Test of range_optimizer -# - -set autocommit=0; - -CREATE TABLE t1 (id CHAR(15) NOT NULL, value CHAR(40) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB; - -CREATE TABLE t2 (id CHAR(15) NOT NULL, value CHAR(40) NOT NULL, PRIMARY KEY(id)) ENGINE=InnoDB; - -CREATE TABLE t3 (id1 CHAR(15) NOT NULL, id2 CHAR(15) NOT NULL, PRIMARY KEY(id1, id2)) ENGINE=InnoDB; - -INSERT INTO t3 VALUES("my-test-1", "my-test-2"); -COMMIT; - -INSERT INTO t1 VALUES("this-key", "will disappear"); -INSERT INTO t2 VALUES("this-key", "will also disappear"); -DELETE FROM t3 WHERE id1="my-test-1"; - -SELECT * FROM t1; -SELECT * FROM t2; -SELECT * FROM t3; -ROLLBACK; - -SELECT * FROM t1; -SELECT * FROM t2; -SELECT * FROM t3; -SELECT * FROM t3 WHERE id1="my-test-1" LOCK IN SHARE MODE; -COMMIT; -set autocommit=1; -DROP TABLE t1,t2,t3; - -# -# Check update with conflicting key -# - -CREATE TABLE t1 (a int not null primary key, b int not null, unique (b)) engine=innodb; -INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); -# We need the a < 1000 test here to quard against the halloween problems -UPDATE t1 set a=a+100 where b between 2 and 3 and a < 1000; -SELECT * from t1; -drop table t1; - -# -# Test multi update with different join methods -# - -CREATE TABLE t1 (a int not null primary key, b int not null, key (b)) engine=innodb; -CREATE TABLE t2 (a int not null primary key, b int not null, key (b)) engine=innodb; -INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10),(11,11),(12,12); -INSERT INTO t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9); - -# Full join, without key -update t1,t2 set t1.a=t1.a+100; -select * from t1; - -# unique key -update t1,t2 set t1.a=t1.a+100 where t1.a=101; -select * from t1; - -# ref key -update t1,t2 set t1.b=t1.b+10 where t1.b=2; -select * from t1; - -# Range key (in t1) -update t1,t2 set t1.b=t1.b+2,t2.b=t1.b+10 where t1.b between 3 and 5 and t1.a=t2.a+100; -select * from t1; -select * from t2; - -drop table t1,t2; -CREATE TABLE t2 ( NEXT_T BIGINT NOT NULL PRIMARY KEY) ENGINE=MyISAM; -CREATE TABLE t1 ( B_ID INTEGER NOT NULL PRIMARY KEY) ENGINE=InnoDB; -SET AUTOCOMMIT=0; -INSERT INTO t1 ( B_ID ) VALUES ( 1 ); -INSERT INTO t2 ( NEXT_T ) VALUES ( 1 ); -ROLLBACK; -SELECT * FROM t1; -drop table t1,t2; -create table t1 ( pk int primary key, parent int not null, child int not null, index (parent) ) engine = innodb; -insert into t1 values (1,0,4), (2,1,3), (3,2,1), (4,1,2); -select distinct parent,child from t1 order by parent; -drop table t1; - -# -# Test that MySQL priorities clustered indexes -# -create table t1 (a int not null auto_increment primary key, b int, c int, key(c)) engine=innodb; -create table t2 (a int not null auto_increment primary key, b int); -insert into t1 (b) values (null),(null),(null),(null),(null),(null),(null); -insert into t2 (a) select b from t1; -insert into t1 (b) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -insert into t2 (a) select b from t1; -insert into t1 (a) select b from t2; -select count(*) from t1; ---replace_column 9 # -explain select * from t1 where c between 1 and 2500; -update t1 set c=a; ---replace_column 9 # -explain select * from t1 where c between 1 and 2500; -drop table t1,t2; - -# -# Test of UPDATE ... ORDER BY -# - -create table t1 (id int primary key auto_increment, fk int, index index_fk (fk)) engine=innodb; - -insert into t1 (id) values (null),(null),(null),(null),(null); -update t1 set fk=69 where fk is null order by id limit 1; -SELECT * from t1; -drop table t1; - -create table t1 (a int not null, b int not null, key (a)); -insert into t1 values (1,1),(1,2),(1,3),(3,1),(3,2),(3,3),(3,1),(3,2),(3,3),(2,1),(2,2),(2,3); -SET @tmp=0; -update t1 set b=(@tmp:=@tmp+1) order by a; -update t1 set b=99 where a=1 order by b asc limit 1; -update t1 set b=100 where a=1 order by b desc limit 2; -update t1 set a=a+10+b where a=1 order by b; -select * from t1 order by a,b; -drop table t1; - -# -# Test of multi-table-updates (bug #1980). -# - -create table t1 ( c char(8) not null ) engine=innodb; -insert into t1 values ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7'),('8'),('9'); -insert into t1 values ('A'),('B'),('C'),('D'),('E'),('F'); - -alter table t1 add b char(8) not null; -alter table t1 add a char(8) not null; -alter table t1 add primary key (a,b,c); -update t1 set a=c, b=c; - -create table t2 (c char(8) not null, b char(8) not null, a char(8) not null, primary key(a,b,c)) engine=innodb; -insert into t2 select * from t1; - -delete t1,t2 from t2,t1 where t1.a<'B' and t2.b=t1.b; -drop table t1,t2; - -# -# test autoincrement with TRUNCATE -# - -SET AUTOCOMMIT=1; -create table t1 (a integer auto_increment primary key) engine=innodb; -insert into t1 (a) values (NULL),(NULL); -truncate table t1; -insert into t1 (a) values (NULL),(NULL); -SELECT * from t1; -drop table t1; - -# -# Test dictionary handling with spaceand quoting -# - -CREATE TABLE t1 (`id 1` INT NOT NULL, PRIMARY KEY (`id 1`)) ENGINE=INNODB; -CREATE TABLE t2 (id INT PRIMARY KEY, t1_id INT, INDEX par_ind (t1_id), FOREIGN KEY (`t1_id`) REFERENCES `t1`(`id 1`) ON DELETE CASCADE ) ENGINE=INNODB; -#show create table t2; -drop table t2,t1; - -# -# Test of multi updated and foreign keys -# - -create table `t1` (`id` int( 11 ) not null ,primary key ( `id` )) engine = innodb; -insert into `t1`values ( 1 ) ; -create table `t2` (`id` int( 11 ) not null default '0',unique key `id` ( `id` ) ,constraint `t1_id_fk` foreign key ( `id` ) references `t1` (`id` )) engine = innodb; -insert into `t2`values ( 1 ) ; -create table `t3` (`id` int( 11 ) not null default '0',key `id` ( `id` ) ,constraint `t2_id_fk` foreign key ( `id` ) references `t2` (`id` )) engine = innodb; -insert into `t3`values ( 1 ) ; ---error 1451 -delete t3,t2,t1 from t1,t2,t3 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; ---error 1451 -update t1,t2,t3 set t3.id=5, t2.id=6, t1.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; ---error 1054 -update t3 set t3.id=7 where t1.id =1 and t2.id = t1.id and t3.id = t2.id; -drop table t3,t2,t1; - -# -# test for recursion depth limit -# -create table t1( - id int primary key, - pid int, - index(pid), - foreign key(pid) references t1(id) on delete cascade) engine=innodb; -insert into t1 values(0,0),(1,0),(2,1),(3,2),(4,3),(5,4),(6,5),(7,6), - (8,7),(9,8),(10,9),(11,10),(12,11),(13,12),(14,13),(15,14); --- error 1451 -delete from t1 where id=0; -delete from t1 where id=15; -delete from t1 where id=0; - -drop table t1; - -# -# Test timestamps -# - -CREATE TABLE t1 (col1 int(1))ENGINE=InnoDB; -CREATE TABLE t2 (col1 int(1),stamp TIMESTAMP,INDEX stamp_idx -(stamp))ENGINE=InnoDB; -insert into t1 values (1),(2),(3); -# Note that timestamp 3 is wrong -insert into t2 values (1, 20020204130000),(2, 20020204130000),(4,20020204310000 ),(5,20020204230000); -SELECT col1 FROM t1 UNION SELECT col1 FROM t2 WHERE stamp < -'20020204120000' GROUP BY col1; -drop table t1,t2; - -# -# Test by Francois MASUREL -# - -CREATE TABLE t1 ( - `id` int(10) unsigned NOT NULL auto_increment, - `id_object` int(10) unsigned default '0', - `id_version` int(10) unsigned NOT NULL default '1', - `label` varchar(100) NOT NULL default '', - `description` text, - PRIMARY KEY (`id`), - KEY `id_object` (`id_object`), - KEY `id_version` (`id_version`) -) ENGINE=InnoDB; - -INSERT INTO t1 VALUES("6", "3382", "9", "Test", NULL), ("7", "102", "5", "Le Pekin (Test)", NULL),("584", "1794", "4", "Test de resto", NULL),("837", "1822", "6", "Test 3", NULL),("1119", "3524", "1", "Societe Test", NULL),("1122", "3525", "1", "Fournisseur Test", NULL); - -CREATE TABLE t2 ( - `id` int(10) unsigned NOT NULL auto_increment, - `id_version` int(10) unsigned NOT NULL default '1', - PRIMARY KEY (`id`), - KEY `id_version` (`id_version`) -) ENGINE=InnoDB; - -INSERT INTO t2 VALUES("3524", "1"),("3525", "1"),("1794", "4"),("102", "5"),("1822", "6"),("3382", "9"); - -SELECT t2.id, t1.`label` FROM t2 INNER JOIN -(SELECT t1.id_object as id_object FROM t1 WHERE t1.`label` LIKE '%test%') AS lbl -ON (t2.id = lbl.id_object) INNER JOIN t1 ON (t2.id = t1.id_object); -drop table t1,t2; - -create table t1 (a int, b varchar(200), c text not null) checksum=1 engine=myisam; -create table t2 (a int, b varchar(200), c text not null) checksum=0 engine=innodb; -create table t3 (a int, b varchar(200), c text not null) checksum=1 engine=innodb; -insert t1 values (1, "aaa", "bbb"), (NULL, "", "ccccc"), (0, NULL, ""); -insert t2 select * from t1; -insert t3 select * from t1; -checksum table t1, t2, t3, t4 quick; -checksum table t1, t2, t3, t4; -checksum table t1, t2, t3, t4 extended; -#show table status; -drop table t1,t2,t3; - -# -# Test problem with refering to different fields in same table in UNION -# (Bug #2552) -# -create table t1 (id int, name char(10) not null, name2 char(10) not null) engine=innodb; -insert into t1 values(1,'first','fff'),(2,'second','sss'),(3,'third','ttt'); -select trim(name2) from t1 union all select trim(name) from t1 union all select trim(id) from t1; -drop table t1; - -# -# Bug2160 -# -create table t1 (a int) engine=innodb; -create table t2 like t1; -drop table t1,t2; - -# -# Test of automaticly created foreign keys -# - -create table t1 (id int(11) not null, id2 int(11) not null, unique (id,id2)) engine=innodb; -create table t2 (id int(11) not null, constraint t1_id_fk foreign key ( id ) references t1 (id)) engine = innodb; -show create table t1; -show create table t2; -create index id on t2 (id); -show create table t2; -create index id2 on t2 (id); -show create table t2; -drop index id2 on t2; ---error ER_DROP_INDEX_FK -drop index id on t2; -show create table t2; -drop table t2; - -create table t2 (id int(11) not null, id2 int(11) not null, constraint t1_id_fk foreign key (id,id2) references t1 (id,id2)) engine = innodb; -show create table t2; -create unique index id on t2 (id,id2); -show create table t2; -drop table t2; - -# Check foreign key columns created in different order than key columns -create table t2 (id int(11) not null, id2 int(11) not null, unique (id,id2),constraint t1_id_fk foreign key (id2,id) references t1 (id,id2)) engine = innodb; -show create table t2; -drop table t2; - -create table t2 (id int(11) not null, id2 int(11) not null, unique (id,id2), constraint t1_id_fk foreign key (id) references t1 (id)) engine = innodb; -show create table t2; -drop table t2; - -create table t2 (id int(11) not null, id2 int(11) not null, unique (id,id2),constraint t1_id_fk foreign key (id2,id) references t1 (id,id2)) engine = innodb; -show create table t2; -drop table t2; - -create table t2 (id int(11) not null auto_increment, id2 int(11) not null, constraint t1_id_fk foreign key (id) references t1 (id), primary key (id), index (id,id2)) engine = innodb; -show create table t2; -drop table t2; - -create table t2 (id int(11) not null auto_increment, id2 int(11) not null, constraint t1_id_fk foreign key (id) references t1 (id)) engine= innodb; -show create table t2; -alter table t2 add index id_test (id), add index id_test2 (id,id2); -show create table t2; -drop table t2; - -# Test error handling - -# Embedded server doesn't chdir to data directory ---replace_result $MYSQLTEST_VARDIR . master-data/ '' ---error ER_WRONG_FK_DEF -create table t2 (id int(11) not null, id2 int(11) not null, constraint t1_id_fk foreign key (id2,id) references t1 (id)) engine = innodb; - -# bug#3749 - -create table t2 (a int auto_increment primary key, b int, index(b), foreign key (b) references t1(id), unique(b)) engine=innodb; -show create table t2; -drop table t2; -create table t2 (a int auto_increment primary key, b int, foreign key (b) references t1(id), foreign key (b) references t1(id), unique(b)) engine=innodb; -show create table t2; -drop table t2, t1; - - -# -# Bug #6126: Duplicate columns in keys gives misleading error message -# ---error 1060 -create table t1 (c char(10), index (c,c)) engine=innodb; ---error 1060 -create table t1 (c1 char(10), c2 char(10), index (c1,c2,c1)) engine=innodb; ---error 1060 -create table t1 (c1 char(10), c2 char(10), index (c1,c1,c2)) engine=innodb; ---error 1060 -create table t1 (c1 char(10), c2 char(10), index (c2,c1,c1)) engine=innodb; -create table t1 (c1 char(10), c2 char(10)) engine=innodb; ---error 1060 -alter table t1 add key (c1,c1); ---error 1060 -alter table t1 add key (c2,c1,c1); ---error 1060 -alter table t1 add key (c1,c2,c1); ---error 1060 -alter table t1 add key (c1,c1,c2); -drop table t1; - -# -# Bug #4082: integer truncation -# - -create table t1(a int(1) , b int(1)) engine=innodb; -insert into t1 values ('1111', '3333'); -select distinct concat(a, b) from t1; -drop table t1; - -# -# BUG#7709 test case - Boolean fulltext query against unsupported -# engines does not fail -# - -CREATE TABLE t1 ( a char(10) ) ENGINE=InnoDB; ---error 1214 -SELECT a FROM t1 WHERE MATCH (a) AGAINST ('test' IN BOOLEAN MODE); -DROP TABLE t1; - -# -# check null values #1 -# - ---disable_warnings -CREATE TABLE t1 (a_id tinyint(4) NOT NULL default '0', PRIMARY KEY (a_id)) ENGINE=InnoDB DEFAULT CHARSET=latin1; -INSERT INTO t1 VALUES (1),(2),(3); -CREATE TABLE t2 (b_id tinyint(4) NOT NULL default '0',b_a tinyint(4) NOT NULL default '0', PRIMARY KEY (b_id), KEY (b_a), - CONSTRAINT fk_b_a FOREIGN KEY (b_a) REFERENCES t1 (a_id) ON DELETE CASCADE ON UPDATE NO ACTION) ENGINE=InnoDB DEFAULT CHARSET=latin1; ---enable_warnings -INSERT INTO t2 VALUES (1,1),(2,1),(3,1),(4,2),(5,2); -SELECT * FROM (SELECT t1.*,GROUP_CONCAT(t2.b_id SEPARATOR ',') as b_list FROM (t1 LEFT JOIN (t2) on t1.a_id = t2.b_a) GROUP BY t1.a_id ) AS xyz; -DROP TABLE t2; -DROP TABLE t1; - -# -# Bug#11816 - Truncate table doesn't work with temporary innodb tables -# This is not an innodb bug, but we test it using innodb. -# -create temporary table t1 (a int) engine=innodb; -insert into t1 values (4711); -truncate t1; -insert into t1 values (42); -select * from t1; -drop table t1; -# Show that it works with permanent tables too. -create table t1 (a int) engine=innodb; -insert into t1 values (4711); -truncate t1; -insert into t1 values (42); -select * from t1; -drop table t1; - -# -# Bug #13025 Server crash during filesort -# - -create table t1 (a int not null, b int not null, c blob not null, d int not null, e int, primary key (a,b,c(255),d)) engine=innodb; -insert into t1 values (2,2,"b",2,2),(1,1,"a",1,1),(3,3,"ab",3,3); -select * from t1 order by a,b,c,d; -explain select * from t1 order by a,b,c,d; -drop table t1; - -# -# BUG#11039,#13218 Wrong key length in min() -# - -create table t1 (a char(1), b char(1), key(a, b)) engine=innodb; -insert into t1 values ('8', '6'), ('4', '7'); -select min(a) from t1; -select min(b) from t1 where a='8'; -drop table t1; - -# End of 4.1 tests - -# -# range optimizer problem -# - -create table t1 (x bigint unsigned not null primary key) engine=innodb; -insert into t1(x) values (0xfffffffffffffff0),(0xfffffffffffffff1); -select * from t1; -select count(*) from t1 where x>0; -select count(*) from t1 where x=0; -select count(*) from t1 where x<0; -select count(*) from t1 where x < -16; -select count(*) from t1 where x = -16; -explain select count(*) from t1 where x > -16; -select count(*) from t1 where x > -16; -select * from t1 where x > -16; -select count(*) from t1 where x = 18446744073709551601; -drop table t1; - - -# Test for testable InnoDB status variables. This test -# uses previous ones(pages_created, rows_deleted, ...). ---replace_result 8192 8191 -SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_buffer_pool_pages_total'; -SELECT variable_value FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_page_size'; -SELECT variable_value - @innodb_rows_deleted_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_deleted'; -SELECT variable_value - @innodb_rows_inserted_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_inserted'; -SELECT variable_value - @innodb_rows_updated_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_rows_updated'; - -# Test for row locks InnoDB status variables. -SELECT variable_value - @innodb_row_lock_waits_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_waits'; -SELECT variable_value - @innodb_row_lock_current_waits_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_current_waits'; -SELECT variable_value - @innodb_row_lock_time_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_time'; -SELECT variable_value - @innodb_row_lock_time_max_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_time_max'; -SELECT variable_value - @innodb_row_lock_time_avg_orig FROM information_schema.global_status WHERE LOWER(variable_name) = 'innodb_row_lock_time_avg'; - -# Test for innodb_sync_spin_loops variable -SET @innodb_sync_spin_loops_orig = @@innodb_sync_spin_loops; -show variables like "innodb_sync_spin_loops"; -set global innodb_sync_spin_loops=1000; -show variables like "innodb_sync_spin_loops"; -set global innodb_sync_spin_loops=0; -show variables like "innodb_sync_spin_loops"; -set global innodb_sync_spin_loops=20; -show variables like "innodb_sync_spin_loops"; -set global innodb_sync_spin_loops=@innodb_sync_spin_loops_orig; - -# Test for innodb_thread_concurrency variable -show variables like "innodb_thread_concurrency"; -set global innodb_thread_concurrency=1001; -show variables like "innodb_thread_concurrency"; -set global innodb_thread_concurrency=0; -show variables like "innodb_thread_concurrency"; -set global innodb_thread_concurrency=16; -show variables like "innodb_thread_concurrency"; - -# Test for innodb_concurrency_tickets variable -show variables like "innodb_concurrency_tickets"; -set global innodb_concurrency_tickets=1000; -show variables like "innodb_concurrency_tickets"; -set global innodb_concurrency_tickets=0; -show variables like "innodb_concurrency_tickets"; -set global innodb_concurrency_tickets=500; -show variables like "innodb_concurrency_tickets"; - -# Test for innodb_thread_sleep_delay variable -show variables like "innodb_thread_sleep_delay"; -set global innodb_thread_sleep_delay=100000; -show variables like "innodb_thread_sleep_delay"; -set global innodb_thread_sleep_delay=0; -show variables like "innodb_thread_sleep_delay"; -set global innodb_thread_sleep_delay=10000; -show variables like "innodb_thread_sleep_delay"; - -# -# Test varchar -# - -let $default=`select @@storage_engine`; -set storage_engine=INNODB; -source include/varchar.inc; - -# -# Some errors/warnings on create -# - -# Embedded server doesn't chdir to data directory ---replace_result $MYSQLTEST_VARDIR . master-data/ '' -create table t1 (v varchar(65530), key(v)); -drop table t1; -create table t1 (v varchar(65536)); -show create table t1; -drop table t1; -create table t1 (v varchar(65530) character set utf8); -show create table t1; -drop table t1; - -eval set storage_engine=$default; - -# InnoDB specific varchar tests -create table t1 (v varchar(16384)) engine=innodb; -drop table t1; - -# -# BUG#11039 Wrong key length in min() -# - -create table t1 (a char(1), b char(1), key(a, b)) engine=innodb; -insert into t1 values ('8', '6'), ('4', '7'); -select min(a) from t1; -select min(b) from t1 where a='8'; -drop table t1; - -# -# Bug #11080 & #11005 Multi-row REPLACE fails on a duplicate key error -# - -CREATE TABLE t1 ( `a` int(11) NOT NULL auto_increment, `b` int(11) default NULL,PRIMARY KEY (`a`),UNIQUE KEY `b` (`b`)) ENGINE=innodb; -insert into t1 (b) values (1); -replace into t1 (b) values (2), (1), (3); -select * from t1; -truncate table t1; -insert into t1 (b) values (1); -replace into t1 (b) values (2); -replace into t1 (b) values (1); -replace into t1 (b) values (3); -select * from t1; -drop table t1; - -create table t1 (rowid int not null auto_increment, val int not null,primary -key (rowid), unique(val)) engine=innodb; -replace into t1 (val) values ('1'),('2'); -replace into t1 (val) values ('1'),('2'); ---error ER_DUP_ENTRY -insert into t1 (val) values ('1'),('2'); -select * from t1; -drop table t1; - -# -# Test that update does not change internal auto-increment value -# - -create table t1 (a int not null auto_increment primary key, val int) engine=InnoDB; -insert into t1 (val) values (1); -update t1 set a=2 where a=1; -# We should get the following error because InnoDB does not update the counter ---error ER_DUP_ENTRY -insert into t1 (val) values (1); -select * from t1; -drop table t1; -# -# Bug #10465 -# - ---disable_warnings -CREATE TABLE t1 (GRADE DECIMAL(4) NOT NULL, PRIMARY KEY (GRADE)) ENGINE=INNODB; ---enable_warnings -INSERT INTO t1 (GRADE) VALUES (151),(252),(343); -SELECT GRADE FROM t1 WHERE GRADE > 160 AND GRADE < 300; -SELECT GRADE FROM t1 WHERE GRADE= 151; -DROP TABLE t1; - -# -# Bug #12340 multitable delete deletes only one record -# -create table t1 (f1 varchar(10), f2 varchar(10), primary key (f1,f2)) engine=innodb; -create table t2 (f3 varchar(10), f4 varchar(10), key (f4)) engine=innodb; -insert into t2 values ('aa','cc'); -insert into t1 values ('aa','bb'),('aa','cc'); -delete t1 from t1,t2 where f1=f3 and f4='cc'; -select * from t1; -drop table t1,t2; - -# -# Test that the slow TRUNCATE implementation resets autoincrement columns -# (bug #11946) -# - -CREATE TABLE t1 ( -id INTEGER NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) -) ENGINE=InnoDB; - -CREATE TABLE t2 ( -id INTEGER NOT NULL, -FOREIGN KEY (id) REFERENCES t1 (id) -) ENGINE=InnoDB; - -INSERT INTO t1 (id) VALUES (NULL); -SELECT * FROM t1; -TRUNCATE t1; -INSERT INTO t1 (id) VALUES (NULL); -SELECT * FROM t1; - -# continued from above; test that doing a slow TRUNCATE on a table with 0 -# rows resets autoincrement columns -DELETE FROM t1; -TRUNCATE t1; -INSERT INTO t1 (id) VALUES (NULL); -SELECT * FROM t1; -DROP TABLE t2, t1; - -# Test that foreign keys in temporary tables are not accepted (bug #12084) -CREATE TABLE t1 -( - id INT PRIMARY KEY -) ENGINE=InnoDB; - ---error 1005,1005 -CREATE TEMPORARY TABLE t2 -( - id INT NOT NULL PRIMARY KEY, - b INT, - FOREIGN KEY (b) REFERENCES test.t1(id) -) ENGINE=InnoDB; -DROP TABLE t1; - -# -# Test that index column max sizes are honored (bug #13315) -# - -# prefix index -create table t1 (col1 varchar(2000), index (col1(767))) - character set = latin1 engine = innodb; - -# normal indexes -create table t2 (col1 char(255), index (col1)) - character set = latin1 engine = innodb; -create table t3 (col1 binary(255), index (col1)) - character set = latin1 engine = innodb; -create table t4 (col1 varchar(767), index (col1)) - character set = latin1 engine = innodb; -create table t5 (col1 varchar(767) primary key) - character set = latin1 engine = innodb; -create table t6 (col1 varbinary(767) primary key) - character set = latin1 engine = innodb; -create table t7 (col1 text, index(col1(767))) - character set = latin1 engine = innodb; -create table t8 (col1 blob, index(col1(767))) - character set = latin1 engine = innodb; - -# multi-column indexes are allowed to be longer -create table t9 (col1 varchar(512), col2 varchar(512), index(col1, col2)) - character set = latin1 engine = innodb; - -show create table t9; - -drop table t1, t2, t3, t4, t5, t6, t7, t8, t9; - -# these should have their index length trimmed -create table t1 (col1 varchar(768), index(col1)) - character set = latin1 engine = innodb; -create table t2 (col1 varbinary(768), index(col1)) - character set = latin1 engine = innodb; -create table t3 (col1 text, index(col1(768))) - character set = latin1 engine = innodb; -create table t4 (col1 blob, index(col1(768))) - character set = latin1 engine = innodb; - -show create table t1; - -drop table t1, t2, t3, t4; - -# these should be refused ---error 1071 -create table t1 (col1 varchar(768) primary key) - character set = latin1 engine = innodb; ---error 1071 -create table t2 (col1 varbinary(768) primary key) - character set = latin1 engine = innodb; ---error 1071 -create table t3 (col1 text, primary key(col1(768))) - character set = latin1 engine = innodb; ---error 1071 -create table t4 (col1 blob, primary key(col1(768))) - character set = latin1 engine = innodb; - -# -# Test improved foreign key error messages (bug #3443) -# - -CREATE TABLE t1 -( - id INT PRIMARY KEY -) ENGINE=InnoDB; - -CREATE TABLE t2 -( - v INT, - CONSTRAINT c1 FOREIGN KEY (v) REFERENCES t1(id) -) ENGINE=InnoDB; - ---error 1452 -INSERT INTO t2 VALUES(2); - -INSERT INTO t1 VALUES(1); -INSERT INTO t2 VALUES(1); - ---error 1451 -DELETE FROM t1 WHERE id = 1; - ---error 1217 -DROP TABLE t1; - -SET FOREIGN_KEY_CHECKS=0; -DROP TABLE t1; -SET FOREIGN_KEY_CHECKS=1; - ---error 1452 -INSERT INTO t2 VALUES(3); - -DROP TABLE t2; -# -# Test that checksum table uses a consistent read Bug #12669 -# -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connection a; -create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; -insert into t1 values (1),(2); -set autocommit=0; -checksum table t1; -connection b; -insert into t1 values(3); -connection a; -# -# Here checksum should not see insert -# -checksum table t1; -connection a; -commit; -checksum table t1; -commit; -drop table t1; -# -# autocommit = 1 -# -connection a; -create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1; -insert into t1 values (1),(2); -set autocommit=1; -checksum table t1; -connection b; -set autocommit=1; -insert into t1 values(3); -connection a; -# -# Here checksum sees insert -# -checksum table t1; -drop table t1; - -connection default; -disconnect a; -disconnect b; - -# tests for bugs #9802 and #13778 - -# test that FKs between invalid types are not accepted - -set foreign_key_checks=0; -create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb; -# Embedded server doesn't chdir to data directory ---replace_result $MYSQLTEST_VARDIR . master-data/ '' --- error 1005 -create table t1(a char(10) primary key, b varchar(20)) engine = innodb; -set foreign_key_checks=1; -drop table t2; - -# test that FKs between different charsets are not accepted in CREATE even -# when f_k_c is 0 - -set foreign_key_checks=0; -create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; -# Embedded server doesn't chdir to data directory ---replace_result $MYSQLTEST_VARDIR . master-data/ '' --- error 1005 -create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=utf8; -set foreign_key_checks=1; -drop table t1; - -# test that invalid datatype conversions with ALTER are not allowed - -set foreign_key_checks=0; -create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb; -create table t1(a varchar(10) primary key) engine = innodb; --- error 1025,1025 -alter table t1 modify column a int; -set foreign_key_checks=1; -drop table t2,t1; - -# test that charset conversions with ALTER are allowed when f_k_c is 0 - -set foreign_key_checks=0; -create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; -create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; -alter table t1 convert to character set utf8; -set foreign_key_checks=1; -drop table t2,t1; - -# test that RENAME does not allow invalid charsets when f_k_c is 0 - -set foreign_key_checks=0; -create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; -create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8; -# Embedded server doesn't chdir to data directory ---replace_result $MYSQLTEST_VARDIR . master-data/ '' --- error 1025 -rename table t3 to t1; -set foreign_key_checks=1; -drop table t2,t3; - -# test that foreign key errors are reported correctly (Bug #15550) - -create table t1(a int primary key) row_format=redundant engine=innodb; -create table t2(a int primary key,constraint foreign key(a)references t1(a)) row_format=compact engine=innodb; -create table t3(a int primary key) row_format=compact engine=innodb; -create table t4(a int primary key,constraint foreign key(a)references t3(a)) row_format=redundant engine=innodb; - -insert into t1 values(1); -insert into t3 values(1); --- error 1452 -insert into t2 values(2); --- error 1452 -insert into t4 values(2); -insert into t2 values(1); -insert into t4 values(1); --- error 1451 -update t1 set a=2; --- error 1452 -update t2 set a=2; --- error 1451 -update t3 set a=2; --- error 1452 -update t4 set a=2; --- error 1451 -truncate t1; --- error 1451 -truncate t3; -truncate t2; -truncate t4; -truncate t1; -truncate t3; - -drop table t4,t3,t2,t1; - - -# -# Test that we can create a large (>1K) key -# -create table t1 (a varchar(255) character set utf8, - b varchar(255) character set utf8, - c varchar(255) character set utf8, - d varchar(255) character set utf8, - key (a,b,c,d)) engine=innodb; -drop table t1; ---error ER_TOO_LONG_KEY -create table t1 (a varchar(255) character set utf8, - b varchar(255) character set utf8, - c varchar(255) character set utf8, - d varchar(255) character set utf8, - e varchar(255) character set utf8, - key (a,b,c,d,e)) engine=innodb; - - -# test the padding of BINARY types and collations (Bug #14189) - -create table t1 (s1 varbinary(2),primary key (s1)) engine=innodb; -create table t2 (s1 binary(2),primary key (s1)) engine=innodb; -create table t3 (s1 varchar(2) binary,primary key (s1)) engine=innodb; -create table t4 (s1 char(2) binary,primary key (s1)) engine=innodb; - -insert into t1 values (0x41),(0x4120),(0x4100); --- error ER_DUP_ENTRY -insert into t2 values (0x41),(0x4120),(0x4100); -insert into t2 values (0x41),(0x4120); --- error ER_DUP_ENTRY -insert into t3 values (0x41),(0x4120),(0x4100); -insert into t3 values (0x41),(0x4100); --- error ER_DUP_ENTRY -insert into t4 values (0x41),(0x4120),(0x4100); -insert into t4 values (0x41),(0x4100); -select hex(s1) from t1; -select hex(s1) from t2; -select hex(s1) from t3; -select hex(s1) from t4; -drop table t1,t2,t3,t4; - -create table t1 (a int primary key,s1 varbinary(3) not null unique) engine=innodb; -create table t2 (s1 binary(2) not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; - -insert into t1 values(1,0x4100),(2,0x41),(3,0x4120),(4,0x42); --- error 1452 -insert into t2 values(0x42); -insert into t2 values(0x41); -select hex(s1) from t2; -update t1 set s1=0x123456 where a=2; -select hex(s1) from t2; --- error 1451 -update t1 set s1=0x12 where a=1; --- error 1451 -update t1 set s1=0x12345678 where a=1; --- error 1451 -update t1 set s1=0x123457 where a=1; -update t1 set s1=0x1220 where a=1; -select hex(s1) from t2; -update t1 set s1=0x1200 where a=1; -select hex(s1) from t2; -update t1 set s1=0x4200 where a=1; -select hex(s1) from t2; --- error 1451 -delete from t1 where a=1; -delete from t1 where a=2; -update t2 set s1=0x4120; --- error 1451 -delete from t1; -delete from t1 where a!=3; -select a,hex(s1) from t1; -select hex(s1) from t2; - -drop table t2,t1; - -create table t1 (a int primary key,s1 varchar(2) binary not null unique) engine=innodb; -create table t2 (s1 char(2) binary not null, constraint c foreign key(s1) references t1(s1) on update cascade) engine=innodb; - -insert into t1 values(1,0x4100),(2,0x41); -insert into t2 values(0x41); -select hex(s1) from t2; -update t1 set s1=0x1234 where a=1; -select hex(s1) from t2; -update t1 set s1=0x12 where a=2; -select hex(s1) from t2; -delete from t1 where a=1; --- error 1451 -delete from t1 where a=2; -select a,hex(s1) from t1; -select hex(s1) from t2; - -drop table t2,t1; -# Ensure that <tablename>_ibfk_0 is not mistreated as a -# generated foreign key identifier. (Bug #16387) - -CREATE TABLE t1(a INT, PRIMARY KEY(a)) ENGINE=InnoDB; -CREATE TABLE t2(a INT) ENGINE=InnoDB; -ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1(a); -ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_1; -ALTER TABLE t2 ADD CONSTRAINT t2_ibfk_0 FOREIGN KEY (a) REFERENCES t1(a); -ALTER TABLE t2 DROP FOREIGN KEY t2_ibfk_0; -SHOW CREATE TABLE t2; -DROP TABLE t2,t1; - -# -# Test case for bug #16229: MySQL/InnoDB uses full explicit table locks in trigger processing -# - -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connection a; -create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -insert into t1(a) values (1),(2),(3); -commit; -connection b; -set autocommit = 0; -update t1 set b = 5 where a = 2; -connection a; -delimiter |; -create trigger t1t before insert on t1 for each row begin set NEW.b = NEW.a * 10 + 5, NEW.c = NEW.a / 10; end | -delimiter ;| -set autocommit = 0; -connection a; -insert into t1(a) values (10),(20),(30),(40),(50),(60),(70),(80),(90),(100), -(11),(21),(31),(41),(51),(61),(71),(81),(91),(101), -(12),(22),(32),(42),(52),(62),(72),(82),(92),(102), -(13),(23),(33),(43),(53),(63),(73),(83),(93),(103), -(14),(24),(34),(44),(54),(64),(74),(84),(94),(104); -connection b; -commit; -connection a; -commit; -drop trigger t1t; -drop table t1; -disconnect a; -disconnect b; -# -# Another trigger test -# -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connection a; -create table t1(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t2(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t3(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t4(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -create table t5(a int not null, b int, c int, d int, primary key(a)) engine=innodb; -insert into t1(a) values (1),(2),(3); -insert into t2(a) values (1),(2),(3); -insert into t3(a) values (1),(2),(3); -insert into t4(a) values (1),(2),(3); -insert into t3(a) values (5),(7),(8); -insert into t4(a) values (5),(7),(8); -insert into t5(a) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12); - -delimiter |; -create trigger t1t before insert on t1 for each row begin - INSERT INTO t2 SET a = NEW.a; -end | - -create trigger t2t before insert on t2 for each row begin - DELETE FROM t3 WHERE a = NEW.a; -end | - -create trigger t3t before delete on t3 for each row begin - UPDATE t4 SET b = b + 1 WHERE a = OLD.a; -end | - -create trigger t4t before update on t4 for each row begin - UPDATE t5 SET b = b + 1 where a = NEW.a; -end | -delimiter ;| -commit; -set autocommit = 0; -update t1 set b = b + 5 where a = 1; -update t2 set b = b + 5 where a = 1; -update t3 set b = b + 5 where a = 1; -update t4 set b = b + 5 where a = 1; -insert into t5(a) values(20); -connection b; -set autocommit = 0; -insert into t1(a) values(7); -insert into t2(a) values(8); -delete from t2 where a = 3; -update t4 set b = b + 1 where a = 3; -commit; -drop trigger t1t; -drop trigger t2t; -drop trigger t3t; -drop trigger t4t; -drop table t1, t2, t3, t4, t5; -connection default; -disconnect a; -disconnect b; - -# -# Test that cascading updates leading to duplicate keys give the correct -# error message (bug #9680) -# - -CREATE TABLE t1 ( - field1 varchar(8) NOT NULL DEFAULT '', - field2 varchar(8) NOT NULL DEFAULT '', - PRIMARY KEY (field1, field2) -) ENGINE=InnoDB; - -CREATE TABLE t2 ( - field1 varchar(8) NOT NULL DEFAULT '' PRIMARY KEY, - FOREIGN KEY (field1) REFERENCES t1 (field1) - ON DELETE CASCADE ON UPDATE CASCADE -) ENGINE=InnoDB; - -INSERT INTO t1 VALUES ('old', 'somevalu'); -INSERT INTO t1 VALUES ('other', 'anyvalue'); - -INSERT INTO t2 VALUES ('old'); -INSERT INTO t2 VALUES ('other'); - ---error ER_FOREIGN_DUPLICATE_KEY -UPDATE t1 SET field1 = 'other' WHERE field2 = 'somevalu'; - -DROP TABLE t2; -DROP TABLE t1; - -# -# Bug#18477 - MySQL/InnoDB Ignoring Foreign Keys in ALTER TABLE -# -create table t1 ( - c1 bigint not null, - c2 bigint not null, - primary key (c1), - unique key (c2) -) engine=innodb; -# -create table t2 ( - c1 bigint not null, - primary key (c1) -) engine=innodb; -# -alter table t1 add constraint c2_fk foreign key (c2) - references t2(c1) on delete cascade; -show create table t1; -# -alter table t1 drop foreign key c2_fk; -show create table t1; -# -drop table t1, t2; - -# -# Bug #14360: problem with intervals -# - -create table t1(a date) engine=innodb; -create table t2(a date, key(a)) engine=innodb; -insert into t1 values('2005-10-01'); -insert into t2 values('2005-10-01'); -select * from t1, t2 - where t2.a between t1.a - interval 2 day and t1.a + interval 2 day; -drop table t1, t2; - -create table t1 (id int not null, f_id int not null, f int not null, -primary key(f_id, id)) engine=innodb; -create table t2 (id int not null,s_id int not null,s varchar(200), -primary key(id)) engine=innodb; -INSERT INTO t1 VALUES (8, 1, 3); -INSERT INTO t1 VALUES (1, 2, 1); -INSERT INTO t2 VALUES (1, 0, ''); -INSERT INTO t2 VALUES (8, 1, ''); -commit; -DELETE ml.* FROM t1 AS ml LEFT JOIN t2 AS mm ON (mm.id=ml.id) -WHERE mm.id IS NULL; -select ml.* from t1 as ml left join t2 as mm on (mm.id=ml.id) -where mm.id is null lock in share mode; -drop table t1,t2; - -# -# Test case where X-locks on unused rows should be released in a -# update (because READ COMMITTED isolation level) -# - -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connection a; -create table t1(a int not null, b int, primary key(a)) engine=innodb; -insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2),(7,3); -commit; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -update t1 set b = 5 where b = 1; -connection b; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -# -# X-lock to record (7,3) should be released in a update -# -select * from t1 where a = 7 and b = 3 for update; -connection a; -commit; -connection b; -commit; -drop table t1; -connection default; -disconnect a; -disconnect b; - -# -# Test case where no locks should be released (because we are not -# using READ COMMITTED isolation level) -# - -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connection a; -create table t1(a int not null, b int, primary key(a)) engine=innodb; -insert into t1 values(1,1),(2,2),(3,1),(4,2),(5,1),(6,2); -commit; -set autocommit = 0; -select * from t1 lock in share mode; -update t1 set b = 5 where b = 1; -connection b; -set autocommit = 0; -# -# S-lock to records (2,2),(4,2), and (6,2) should not be released in a update -# ---error 1205 -select * from t1 where a = 2 and b = 2 for update; -# -# X-lock to record (1,1),(3,1),(5,1) should not be released in a update -# ---error 1205 -connection a; -commit; -connection b; -commit; -connection default; -disconnect a; -disconnect b; -drop table t1; - -# -# Consistent read should be used in following selects -# -# 1) INSERT INTO ... SELECT -# 2) UPDATE ... = ( SELECT ...) -# 3) CREATE ... SELECT - -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connection a; -create table t1(a int not null, b int, primary key(a)) engine=innodb; -insert into t1 values (1,2),(5,3),(4,2); -create table t2(d int not null, e int, primary key(d)) engine=innodb; -insert into t2 values (8,6),(12,1),(3,1); -commit; -set autocommit = 0; -select * from t2 for update; -connection b; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -insert into t1 select * from t2; -update t1 set b = (select e from t2 where a = d); -create table t3(d int not null, e int, primary key(d)) engine=innodb -select * from t2; -commit; -connection a; -commit; -connection default; -disconnect a; -disconnect b; -drop table t1, t2, t3; - -# -# Consistent read should not be used if -# -# (a) isolation level is serializable OR -# (b) select ... lock in share mode OR -# (c) select ... for update -# -# in following queries: -# -# 1) INSERT INTO ... SELECT -# 2) UPDATE ... = ( SELECT ...) -# 3) CREATE ... SELECT - -connect (a,localhost,root,,); -connect (b,localhost,root,,); -connect (c,localhost,root,,); -connect (d,localhost,root,,); -connect (e,localhost,root,,); -connect (f,localhost,root,,); -connect (g,localhost,root,,); -connect (h,localhost,root,,); -connect (i,localhost,root,,); -connect (j,localhost,root,,); -connection a; -create table t1(a int not null, b int, primary key(a)) engine=innodb; -insert into t1 values (1,2),(5,3),(4,2); -create table t2(a int not null, b int, primary key(a)) engine=innodb; -insert into t2 values (8,6),(12,1),(3,1); -create table t3(d int not null, b int, primary key(d)) engine=innodb; -insert into t3 values (8,6),(12,1),(3,1); -create table t5(a int not null, b int, primary key(a)) engine=innodb; -insert into t5 values (1,2),(5,3),(4,2); -create table t6(d int not null, e int, primary key(d)) engine=innodb; -insert into t6 values (8,6),(12,1),(3,1); -create table t8(a int not null, b int, primary key(a)) engine=innodb; -insert into t8 values (1,2),(5,3),(4,2); -create table t9(d int not null, e int, primary key(d)) engine=innodb; -insert into t9 values (8,6),(12,1),(3,1); -commit; -set autocommit = 0; -select * from t2 for update; -connection b; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; ---send -insert into t1 select * from t2; -connection c; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; ---send -update t3 set b = (select b from t2 where a = d); -connection d; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE; ---send -create table t4(a int not null, b int, primary key(a)) engine=innodb select * from t2; -connection e; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; ---send -insert into t5 (select * from t2 lock in share mode); -connection f; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; ---send -update t6 set e = (select b from t2 where a = d lock in share mode); -connection g; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; ---send -create table t7(a int not null, b int, primary key(a)) engine=innodb select * from t2 lock in share mode; -connection h; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; ---send -insert into t8 (select * from t2 for update); -connection i; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; ---send -update t9 set e = (select b from t2 where a = d for update); -connection j; -SET binlog_format='MIXED'; -set autocommit = 0; -SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; ---send -create table t10(a int not null, b int, primary key(a)) engine=innodb select * from t2 for update; - -connection b; ---error 1205 -reap; - -connection c; ---error 1205 -reap; - -connection d; ---error 1205 -reap; - -connection e; ---error 1205 -reap; - -connection f; ---error 1205 -reap; - -connection g; ---error 1205 -reap; - -connection h; ---error 1205 -reap; - -connection i; ---error 1205 -reap; - -connection j; ---error 1205 -reap; - -connection a; -commit; - -connection default; -disconnect a; -disconnect b; -disconnect c; -disconnect d; -disconnect e; -disconnect f; -disconnect g; -disconnect h; -disconnect i; -disconnect j; -drop table t1, t2, t3, t5, t6, t8, t9; - -# bug 18934, "InnoDB crashes when table uses column names like DB_ROW_ID" ---error 1005 -CREATE TABLE t1 (DB_ROW_ID int) engine=innodb; - -# -# Bug #17152: Wrong result with BINARY comparison on aliased column -# - -CREATE TABLE t1 ( - a BIGINT(20) NOT NULL, - PRIMARY KEY (a) - ) ENGINE=INNODB DEFAULT CHARSET=UTF8; - -CREATE TABLE t2 ( - a BIGINT(20) NOT NULL, - b VARCHAR(128) NOT NULL, - c TEXT NOT NULL, - PRIMARY KEY (a,b), - KEY idx_t2_b_c (b,c(200)), - CONSTRAINT t_fk FOREIGN KEY (a) REFERENCES t1 (a) - ON DELETE CASCADE - ) ENGINE=INNODB DEFAULT CHARSET=UTF8; - -INSERT INTO t1 VALUES (1); -INSERT INTO t2 VALUES (1, 'bar', 'vbar'); -INSERT INTO t2 VALUES (1, 'BAR2', 'VBAR'); -INSERT INTO t2 VALUES (1, 'bar_bar', 'bibi'); -INSERT INTO t2 VALUES (1, 'customer_over', '1'); - -SELECT * FROM t2 WHERE b = 'customer_over'; -SELECT * FROM t2 WHERE BINARY b = 'customer_over'; -SELECT DISTINCT p0.a FROM t2 p0 WHERE p0.b = 'customer_over'; -/* Bang: Empty result set, above was expected: */ -SELECT DISTINCT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; -SELECT p0.a FROM t2 p0 WHERE BINARY p0.b = 'customer_over'; - -drop table t2, t1; - -# -# Test optimize on table with open transaction -# - -CREATE TABLE t1 ( a int ) ENGINE=innodb; -BEGIN; -INSERT INTO t1 VALUES (1); -OPTIMIZE TABLE t1; -DROP TABLE t1; - -# -# Bug #24741 (existing cascade clauses disappear when adding foreign keys) -# - -CREATE TABLE t1 (id int PRIMARY KEY, f int NOT NULL, INDEX(f)) ENGINE=InnoDB; - -CREATE TABLE t2 (id int PRIMARY KEY, f INT NOT NULL, - CONSTRAINT t2_t1 FOREIGN KEY (id) REFERENCES t1 (id) - ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB; - -ALTER TABLE t2 ADD FOREIGN KEY (f) REFERENCES t1 (f) ON -DELETE CASCADE ON UPDATE CASCADE; - -SHOW CREATE TABLE t2; -DROP TABLE t2, t1; - -# -# Bug #25927: Prevent ALTER TABLE ... MODIFY ... NOT NULL on columns -# for which there is a foreign key constraint ON ... SET NULL. -# - -CREATE TABLE t1 (a INT, INDEX(a)) ENGINE=InnoDB; -CREATE TABLE t2 (a INT, INDEX(a)) ENGINE=InnoDB; -INSERT INTO t1 VALUES (1); -INSERT INTO t2 VALUES (1); -ALTER TABLE t2 ADD FOREIGN KEY (a) REFERENCES t1 (a) ON DELETE SET NULL; -# mysqltest first does replace_regex, then replace_result ---replace_regex /'[^']*test\/#sql-[0-9a-f_]*'/'#sql-temporary'/ -# Embedded server doesn't chdir to data directory ---replace_result $MYSQLTEST_VARDIR . master-data/ '' ---error 1025 -ALTER TABLE t2 MODIFY a INT NOT NULL; -DELETE FROM t1; -DROP TABLE t2,t1; - -# -# Bug #26835: table corruption after delete+insert -# - -CREATE TABLE t1 (a VARCHAR(5) COLLATE utf8_unicode_ci PRIMARY KEY) -ENGINE=InnoDB; -INSERT INTO t1 VALUES (0xEFBCA4EFBCA4EFBCA4); -DELETE FROM t1; -INSERT INTO t1 VALUES ('DDD'); -SELECT * FROM t1; -DROP TABLE t1; - -# -# Bug #23313 (AUTO_INCREMENT=# not reported back for InnoDB tables) -# Bug #21404 (AUTO_INCREMENT value reset when Adding FKEY (or ALTER?)) -# - -CREATE TABLE t1 (id int PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB -AUTO_INCREMENT=42; - -INSERT INTO t1 VALUES (0),(347),(0); -SELECT * FROM t1; - -SHOW CREATE TABLE t1; - -CREATE TABLE t2 (id int PRIMARY KEY) ENGINE=InnoDB; -INSERT INTO t2 VALUES(42),(347),(348); -ALTER TABLE t1 ADD CONSTRAINT t1_t2 FOREIGN KEY (id) REFERENCES t2(id); -SHOW CREATE TABLE t1; - -DROP TABLE t1,t2; - -# -# Bug #21101 (Prints wrong error message if max row size is too large) -# -set innodb_strict_mode=on; ---error 1118 -CREATE TABLE t1 ( - c01 CHAR(255), c02 CHAR(255), c03 CHAR(255), c04 CHAR(255), - c05 CHAR(255), c06 CHAR(255), c07 CHAR(255), c08 CHAR(255), - c09 CHAR(255), c10 CHAR(255), c11 CHAR(255), c12 CHAR(255), - c13 CHAR(255), c14 CHAR(255), c15 CHAR(255), c16 CHAR(255), - c17 CHAR(255), c18 CHAR(255), c19 CHAR(255), c20 CHAR(255), - c21 CHAR(255), c22 CHAR(255), c23 CHAR(255), c24 CHAR(255), - c25 CHAR(255), c26 CHAR(255), c27 CHAR(255), c28 CHAR(255), - c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255) - ) ENGINE = InnoDB; - -# -# Bug #31860 InnoDB assumes AUTOINC values can only be positive. -# -DROP TABLE IF EXISTS t1; -CREATE TABLE t1( - id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY - ) ENGINE=InnoDB; -INSERT INTO t1 VALUES(-10); -SELECT * FROM t1; -# -# NOTE: The server really needs to be restarted at this point -# for the test to be useful. -# -# Without the fix InnoDB would trip over an assertion here. -INSERT INTO t1 VALUES(NULL); -# The next value should be 1 and not -9 or a -ve number -SELECT * FROM t1; -DROP TABLE t1; - -# -# Bug #21409 Incorrect result returned when in READ-COMMITTED with -# query_cache ON -# -CONNECT (c1,localhost,root,,); -CONNECT (c2,localhost,root,,); -CONNECTION c1; -SET binlog_format='MIXED'; -SET TX_ISOLATION='read-committed'; -SET AUTOCOMMIT=0; -DROP TABLE IF EXISTS t1, t2; -CREATE TABLE t1 ( a int ) ENGINE=InnoDB; -CREATE TABLE t2 LIKE t1; -SELECT * FROM t2; -CONNECTION c2; -SET binlog_format='MIXED'; -SET TX_ISOLATION='read-committed'; -SET AUTOCOMMIT=0; -INSERT INTO t1 VALUES (1); -COMMIT; -CONNECTION c1; -SELECT * FROM t1 WHERE a=1; -DISCONNECT c1; -DISCONNECT c2; -CONNECT (c1,localhost,root,,); -CONNECT (c2,localhost,root,,); -CONNECTION c1; -SET binlog_format='MIXED'; -SET TX_ISOLATION='read-committed'; -SET AUTOCOMMIT=0; -SELECT * FROM t2; -CONNECTION c2; -SET binlog_format='MIXED'; -SET TX_ISOLATION='read-committed'; -SET AUTOCOMMIT=0; -INSERT INTO t1 VALUES (2); -COMMIT; -CONNECTION c1; -# The result set below should be the same for both selects -SELECT * FROM t1 WHERE a=2; -SELECT * FROM t1 WHERE a=2; -DROP TABLE t1; -DROP TABLE t2; -DISCONNECT c1; -DISCONNECT c2; -CONNECTION default; - -# -# Bug #29157 UPDATE, changed rows incorrect -# -create table t1 (i int, j int) engine=innodb; -insert into t1 (i, j) values (1, 1), (2, 2); ---enable_info -update t1 set j = 2; ---disable_info -drop table t1; - -# -# Bug #32440 InnoDB free space info does not appear in SHOW TABLE STATUS or -# I_S -# -create table t1 (id int) comment='this is a comment' engine=innodb; -select table_comment, data_free > 0 as data_free_is_set - from information_schema.tables - where table_schema='test' and table_name = 't1'; -drop table t1; - -# -# Bug 34920 test -# -CONNECTION default; -CREATE TABLE t1 ( - c1 INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, - c2 VARCHAR(128) NOT NULL, - PRIMARY KEY(c1) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=100; - -CREATE TABLE t2 ( - c1 INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, - c2 INT(10) UNSIGNED DEFAULT NULL, - PRIMARY KEY(c1) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=200; - -SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE table_name = 't2'; -ALTER TABLE t2 ADD CONSTRAINT t1_t2_1 FOREIGN KEY(c1) REFERENCES t1(c1); -SELECT AUTO_INCREMENT FROM INFORMATION_SCHEMA.TABLES WHERE table_name = 't2'; -DROP TABLE t2; -DROP TABLE t1; -# End 34920 test -# -# Bug #29507 TRUNCATE shows to many rows effected -# -CONNECTION default; -CREATE TABLE t1 (c1 int default NULL, - c2 int default NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1; - ---enable_info -TRUNCATE TABLE t1; - -INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5); -TRUNCATE TABLE t1; - ---disable_info -DROP TABLE t1; -# -# Bug#35537 Innodb doesn't increment handler_update and handler_delete. -# --- disable_query_log --- disable_result_log - -CONNECT (c1,localhost,root,,); - -DROP TABLE IF EXISTS bug35537; -CREATE TABLE bug35537 ( - c1 int -) ENGINE=InnoDB; - -INSERT INTO bug35537 VALUES (1); - --- enable_result_log - -SHOW SESSION STATUS LIKE 'Handler_update%'; -SHOW SESSION STATUS LIKE 'Handler_delete%'; - -UPDATE bug35537 SET c1 = 2 WHERE c1 = 1; -DELETE FROM bug35537 WHERE c1 = 2; - -SHOW SESSION STATUS LIKE 'Handler_update%'; -SHOW SESSION STATUS LIKE 'Handler_delete%'; - -DROP TABLE bug35537; - -DISCONNECT c1; -CONNECTION default; - -SET GLOBAL innodb_thread_concurrency = @innodb_thread_concurrency_orig; - --- enable_query_log - -####################################################################### -# # -# Please, DO NOT TOUCH this file as well as the innodb.result file. # -# These files are to be modified ONLY BY INNOBASE guys. # -# # -# Use innodb_mysql.[test|result] files instead. # -# # -# If nevertheless you need to make some changes here, please, forward # -# your commit message # -# To: innodb_dev_ww@oracle.com # -# Cc: dev-innodb@mysql.com # -# (otherwise your changes may be erased). # -# # -####################################################################### diff --git a/storage/innobase/mysql-test/innodb_bug21704.test b/storage/innobase/mysql-test/innodb_bug21704.test deleted file mode 100644 index c649b61034c..00000000000 --- a/storage/innobase/mysql-test/innodb_bug21704.test +++ /dev/null @@ -1,96 +0,0 @@ --- source include/have_innodb.inc - ---echo # ---echo # Bug#21704: Renaming column does not update FK definition. ---echo # - ---echo ---echo # Test that it's not possible to rename columns participating in a ---echo # foreign key (either in the referencing or referenced table). ---echo - ---disable_warnings -DROP TABLE IF EXISTS t1; -DROP TABLE IF EXISTS t2; -DROP TABLE IF EXISTS t3; ---enable_warnings - -CREATE TABLE t1 (a INT PRIMARY KEY, b INT) ROW_FORMAT=COMPACT ENGINE=INNODB; - -CREATE TABLE t2 (a INT PRIMARY KEY, b INT, - CONSTRAINT fk1 FOREIGN KEY (a) REFERENCES t1(a)) -ROW_FORMAT=COMPACT ENGINE=INNODB; - -CREATE TABLE t3 (a INT PRIMARY KEY, b INT, KEY(b), C INT, - CONSTRAINT fk2 FOREIGN KEY (b) REFERENCES t3 (a)) -ROW_FORMAT=COMPACT ENGINE=INNODB; - -INSERT INTO t1 VALUES (1,1),(2,2),(3,3); -INSERT INTO t2 VALUES (1,1),(2,2),(3,3); -INSERT INTO t3 VALUES (1,1,1),(2,2,2),(3,3,3); - ---echo ---echo # Test renaming the column in the referenced table. ---echo - -# mysqltest first does replace_regex, then replace_result ---replace_regex /'[^']*test\/#sql-[0-9a-f_]*'/'#sql-temporary'/ -# Embedded server doesn't chdir to data directory ---replace_result $MYSQLTEST_VARDIR . mysqld.1/data/ '' ---error ER_ERROR_ON_RENAME -ALTER TABLE t1 CHANGE a c INT; - ---echo # Ensure that online column rename works. - ---enable_info -ALTER TABLE t1 CHANGE b c INT; ---disable_info - ---echo ---echo # Test renaming the column in the referencing table ---echo - -# mysqltest first does replace_regex, then replace_result ---replace_regex /'[^']*test\/#sql-[0-9a-f_]*'/'#sql-temporary'/ -# Embedded server doesn't chdir to data directory ---replace_result $MYSQLTEST_VARDIR . mysqld.1/data/ '' ---error ER_ERROR_ON_RENAME -ALTER TABLE t2 CHANGE a c INT; - ---echo # Ensure that online column rename works. - ---enable_info -ALTER TABLE t2 CHANGE b c INT; ---disable_info - ---echo ---echo # Test with self-referential constraints ---echo - -# mysqltest first does replace_regex, then replace_result ---replace_regex /'[^']*test\/#sql-[0-9a-f_]*'/'#sql-temporary'/ -# Embedded server doesn't chdir to data directory ---replace_result $MYSQLTEST_VARDIR . mysqld.1/data/ '' ---error ER_ERROR_ON_RENAME -ALTER TABLE t3 CHANGE a d INT; - -# mysqltest first does replace_regex, then replace_result ---replace_regex /'[^']*test\/#sql-[0-9a-f_]*'/'#sql-temporary'/ -# Embedded server doesn't chdir to data directory ---replace_result $MYSQLTEST_VARDIR . mysqld.1/data/ '' ---error ER_ERROR_ON_RENAME -ALTER TABLE t3 CHANGE b d INT; - ---echo # Ensure that online column rename works. - ---enable_info -ALTER TABLE t3 CHANGE c d INT; ---disable_info - ---echo ---echo # Cleanup. ---echo - -DROP TABLE t3; -DROP TABLE t2; -DROP TABLE t1; diff --git a/storage/innobase/mysql-test/innodb_bug34053.result b/storage/innobase/mysql-test/innodb_bug34053.result deleted file mode 100644 index 195775f74c8..00000000000 --- a/storage/innobase/mysql-test/innodb_bug34053.result +++ /dev/null @@ -1 +0,0 @@ -SET storage_engine=InnoDB; diff --git a/storage/innobase/mysql-test/innodb_bug34053.test b/storage/innobase/mysql-test/innodb_bug34053.test deleted file mode 100644 index b935e45c06d..00000000000 --- a/storage/innobase/mysql-test/innodb_bug34053.test +++ /dev/null @@ -1,50 +0,0 @@ -# -# Make sure http://bugs.mysql.com/34053 remains fixed. -# - --- source include/not_embedded.inc --- source include/have_innodb.inc - -SET storage_engine=InnoDB; - -# we do not really care about what gets printed, we are only -# interested in getting success or failure according to our -# expectations --- disable_query_log --- disable_result_log - -GRANT USAGE ON *.* TO 'shane'@'localhost' IDENTIFIED BY '12345'; -FLUSH PRIVILEGES; - --- connect (con1,localhost,shane,12345,) - --- connection con1 --- error ER_SPECIFIC_ACCESS_DENIED_ERROR -CREATE TABLE innodb_monitor (a INT) ENGINE=INNODB; --- error ER_SPECIFIC_ACCESS_DENIED_ERROR -CREATE TABLE innodb_mem_validate (a INT) ENGINE=INNODB; -CREATE TABLE innodb_monitorx (a INT) ENGINE=INNODB; -DROP TABLE innodb_monitorx; -CREATE TABLE innodb_monito (a INT) ENGINE=INNODB; -DROP TABLE innodb_monito; -CREATE TABLE xinnodb_monitor (a INT) ENGINE=INNODB; -DROP TABLE xinnodb_monitor; -CREATE TABLE nnodb_monitor (a INT) ENGINE=INNODB; -DROP TABLE nnodb_monitor; - --- connection default -CREATE TABLE innodb_monitor (a INT) ENGINE=INNODB; -CREATE TABLE innodb_mem_validate (a INT) ENGINE=INNODB; - --- connection con1 --- error ER_SPECIFIC_ACCESS_DENIED_ERROR -DROP TABLE innodb_monitor; --- error ER_SPECIFIC_ACCESS_DENIED_ERROR -DROP TABLE innodb_mem_validate; - --- connection default -DROP TABLE innodb_monitor; -DROP TABLE innodb_mem_validate; -DROP USER 'shane'@'localhost'; - --- disconnect con1 diff --git a/storage/innobase/mysql-test/innodb_bug34300.result b/storage/innobase/mysql-test/innodb_bug34300.result deleted file mode 100644 index ae9fee81ad7..00000000000 --- a/storage/innobase/mysql-test/innodb_bug34300.result +++ /dev/null @@ -1,4 +0,0 @@ -f4 f8 -xxx zzz -f4 f8 -xxx zzz diff --git a/storage/innobase/mysql-test/innodb_bug34300.test b/storage/innobase/mysql-test/innodb_bug34300.test deleted file mode 100644 index 68c385fd72a..00000000000 --- a/storage/innobase/mysql-test/innodb_bug34300.test +++ /dev/null @@ -1,34 +0,0 @@ -# -# Bug#34300 Tinyblob & tinytext fields currupted after export/import and alter in 5.1 -# http://bugs.mysql.com/34300 -# - --- source include/have_innodb.inc - --- disable_query_log --- disable_result_log - -# set packet size and reconnect -let $max_packet=`select @@global.max_allowed_packet`; -SET @@global.max_allowed_packet=16777216; ---connect (newconn, localhost, root,,) - -DROP TABLE IF EXISTS bug34300; -CREATE TABLE bug34300 ( - f4 TINYTEXT, - f6 MEDIUMTEXT, - f8 TINYBLOB -) ENGINE=InnoDB; - -INSERT INTO bug34300 VALUES ('xxx', repeat('a', 8459264), 'zzz'); - --- enable_result_log - -SELECT f4, f8 FROM bug34300; - -ALTER TABLE bug34300 ADD COLUMN (f10 INT); - -SELECT f4, f8 FROM bug34300; - -DROP TABLE bug34300; -EVAL SET @@global.max_allowed_packet=$max_packet; diff --git a/storage/innobase/mysql-test/innodb_bug35220.result b/storage/innobase/mysql-test/innodb_bug35220.result deleted file mode 100644 index 195775f74c8..00000000000 --- a/storage/innobase/mysql-test/innodb_bug35220.result +++ /dev/null @@ -1 +0,0 @@ -SET storage_engine=InnoDB; diff --git a/storage/innobase/mysql-test/innodb_bug35220.test b/storage/innobase/mysql-test/innodb_bug35220.test deleted file mode 100644 index 26f7d6b1ddd..00000000000 --- a/storage/innobase/mysql-test/innodb_bug35220.test +++ /dev/null @@ -1,16 +0,0 @@ -# -# Bug#35220 ALTER TABLE too picky on reserved word "foreign" -# http://bugs.mysql.com/35220 -# - --- source include/have_innodb.inc - -SET storage_engine=InnoDB; - -# we care only that the following SQL commands do not produce errors --- disable_query_log --- disable_result_log - -CREATE TABLE bug35220 (foreign_col INT, dummy_cant_delete_all_columns INT); -ALTER TABLE bug35220 DROP foreign_col; -DROP TABLE bug35220; diff --git a/storage/innobase/mysql-test/innodb_bug36169.result b/storage/innobase/mysql-test/innodb_bug36169.result deleted file mode 100644 index aa80e4d7aa4..00000000000 --- a/storage/innobase/mysql-test/innodb_bug36169.result +++ /dev/null @@ -1,2 +0,0 @@ -SET GLOBAL innodb_file_format='Barracuda'; -SET GLOBAL innodb_file_per_table=ON; diff --git a/storage/innobase/mysql-test/innodb_bug36169.test b/storage/innobase/mysql-test/innodb_bug36169.test deleted file mode 100644 index 5bf55193b5c..00000000000 --- a/storage/innobase/mysql-test/innodb_bug36169.test +++ /dev/null @@ -1,1159 +0,0 @@ -# -# Bug#36169 create innodb compressed table with too large row size crashed -# http://bugs.mysql.com/36169 -# - --- source include/have_innodb.inc - -let $file_format=`select @@innodb_file_format`; -let $file_per_table=`select @@innodb_file_per_table`; -SET GLOBAL innodb_file_format='Barracuda'; -SET GLOBAL innodb_file_per_table=ON; - -# -# The following is copied from http://bugs.mysql.com/36169 -# (http://bugs.mysql.com/file.php?id=9121) -# Probably it can be simplified but that is not obvious. -# - -# we care only that the following SQL commands do produce errors -# as expected and do not crash the server --- disable_query_log --- disable_result_log - -# Generating 10 tables -# Creating a table with 94 columns and 24 indexes -DROP TABLE IF EXISTS `table0`; ---error ER_TOO_BIG_ROWSIZE -CREATE TABLE IF NOT EXISTS `table0` -(`col0` BOOL, -`col1` BOOL, -`col2` TINYINT, -`col3` DATE, -`col4` TIME, -`col5` SET ('test1','test2','test3'), -`col6` TIME, -`col7` TEXT, -`col8` DECIMAL, -`col9` SET ('test1','test2','test3'), -`col10` FLOAT, -`col11` DOUBLE PRECISION, -`col12` ENUM ('test1','test2','test3'), -`col13` TINYBLOB, -`col14` YEAR, -`col15` SET ('test1','test2','test3'), -`col16` NUMERIC, -`col17` NUMERIC, -`col18` BLOB, -`col19` DATETIME, -`col20` DOUBLE PRECISION, -`col21` DECIMAL, -`col22` DATETIME, -`col23` NUMERIC, -`col24` NUMERIC, -`col25` LONGTEXT, -`col26` TINYBLOB, -`col27` TIME, -`col28` TINYBLOB, -`col29` ENUM ('test1','test2','test3'), -`col30` SMALLINT, -`col31` REAL, -`col32` FLOAT, -`col33` CHAR (175), -`col34` TINYTEXT, -`col35` TINYTEXT, -`col36` TINYBLOB, -`col37` TINYBLOB, -`col38` TINYTEXT, -`col39` MEDIUMBLOB, -`col40` TIMESTAMP, -`col41` DOUBLE, -`col42` SMALLINT, -`col43` LONGBLOB, -`col44` VARCHAR (80), -`col45` MEDIUMTEXT, -`col46` NUMERIC, -`col47` BIGINT, -`col48` DATE, -`col49` TINYBLOB, -`col50` DATE, -`col51` BOOL, -`col52` MEDIUMINT, -`col53` FLOAT, -`col54` TINYBLOB, -`col55` LONGTEXT, -`col56` SMALLINT, -`col57` ENUM ('test1','test2','test3'), -`col58` DATETIME, -`col59` MEDIUMTEXT, -`col60` VARCHAR (232), -`col61` NUMERIC, -`col62` YEAR, -`col63` SMALLINT, -`col64` TIMESTAMP, -`col65` BLOB, -`col66` LONGBLOB, -`col67` INT, -`col68` LONGTEXT, -`col69` ENUM ('test1','test2','test3'), -`col70` INT, -`col71` TIME, -`col72` TIMESTAMP, -`col73` TIMESTAMP, -`col74` VARCHAR (170), -`col75` SET ('test1','test2','test3'), -`col76` TINYBLOB, -`col77` BIGINT, -`col78` NUMERIC, -`col79` DATETIME, -`col80` YEAR, -`col81` NUMERIC, -`col82` LONGBLOB, -`col83` TEXT, -`col84` CHAR (83), -`col85` DECIMAL, -`col86` FLOAT, -`col87` INT, -`col88` VARCHAR (145), -`col89` DATE, -`col90` DECIMAL, -`col91` DECIMAL, -`col92` MEDIUMBLOB, -`col93` TIME, -KEY `idx0` (`col69`,`col90`,`col8`), -KEY `idx1` (`col60`), -KEY `idx2` (`col60`,`col70`,`col74`), -KEY `idx3` (`col22`,`col32`,`col72`,`col30`), -KEY `idx4` (`col29`), -KEY `idx5` (`col19`,`col45`(143)), -KEY `idx6` (`col46`,`col48`,`col5`,`col39`(118)), -KEY `idx7` (`col48`,`col61`), -KEY `idx8` (`col93`), -KEY `idx9` (`col31`), -KEY `idx10` (`col30`,`col21`), -KEY `idx11` (`col67`), -KEY `idx12` (`col44`,`col6`,`col8`,`col38`(226)), -KEY `idx13` (`col71`,`col41`,`col15`,`col49`(88)), -KEY `idx14` (`col78`), -KEY `idx15` (`col63`,`col67`,`col64`), -KEY `idx16` (`col17`,`col86`), -KEY `idx17` (`col77`,`col56`,`col10`,`col55`(24)), -KEY `idx18` (`col62`), -KEY `idx19` (`col31`,`col57`,`col56`,`col53`), -KEY `idx20` (`col46`), -KEY `idx21` (`col83`(54)), -KEY `idx22` (`col51`,`col7`(120)), -KEY `idx23` (`col7`(163),`col31`,`col71`,`col14`) -)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; - -# Creating a table with 10 columns and 32 indexes -DROP TABLE IF EXISTS `table1`; ---error ER_TOO_BIG_ROWSIZE -CREATE TABLE IF NOT EXISTS `table1` -(`col0` CHAR (113), -`col1` FLOAT, -`col2` BIGINT, -`col3` DECIMAL, -`col4` BLOB, -`col5` LONGTEXT, -`col6` SET ('test1','test2','test3'), -`col7` BIGINT, -`col8` BIGINT, -`col9` TINYBLOB, -KEY `idx0` (`col5`(101),`col7`,`col8`), -KEY `idx1` (`col8`), -KEY `idx2` (`col4`(177),`col9`(126),`col6`,`col3`), -KEY `idx3` (`col5`(160)), -KEY `idx4` (`col9`(242)), -KEY `idx5` (`col4`(139),`col2`,`col3`), -KEY `idx6` (`col7`), -KEY `idx7` (`col6`,`col2`,`col0`,`col3`), -KEY `idx8` (`col9`(66)), -KEY `idx9` (`col5`(253)), -KEY `idx10` (`col1`,`col7`,`col2`), -KEY `idx11` (`col9`(242),`col0`,`col8`,`col5`(163)), -KEY `idx12` (`col8`), -KEY `idx13` (`col0`,`col9`(37)), -KEY `idx14` (`col0`), -KEY `idx15` (`col5`(111)), -KEY `idx16` (`col8`,`col0`,`col5`(13)), -KEY `idx17` (`col4`(139)), -KEY `idx18` (`col5`(189),`col2`,`col3`,`col9`(136)), -KEY `idx19` (`col0`,`col3`,`col1`,`col8`), -KEY `idx20` (`col8`), -KEY `idx21` (`col0`,`col7`,`col9`(227),`col3`), -KEY `idx22` (`col0`), -KEY `idx23` (`col2`), -KEY `idx24` (`col3`), -KEY `idx25` (`col2`,`col3`), -KEY `idx26` (`col0`), -KEY `idx27` (`col5`(254)), -KEY `idx28` (`col3`), -KEY `idx29` (`col3`), -KEY `idx30` (`col7`,`col3`,`col0`,`col4`(220)), -KEY `idx31` (`col4`(1),`col0`) -)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; - -# Creating a table with 141 columns and 18 indexes -DROP TABLE IF EXISTS `table2`; ---error ER_TOO_BIG_ROWSIZE -CREATE TABLE IF NOT EXISTS `table2` -(`col0` BOOL, -`col1` MEDIUMINT, -`col2` VARCHAR (209), -`col3` MEDIUMBLOB, -`col4` CHAR (13), -`col5` DOUBLE, -`col6` TINYTEXT, -`col7` REAL, -`col8` SMALLINT, -`col9` BLOB, -`col10` TINYINT, -`col11` DECIMAL, -`col12` BLOB, -`col13` DECIMAL, -`col14` LONGBLOB, -`col15` SMALLINT, -`col16` LONGBLOB, -`col17` TINYTEXT, -`col18` FLOAT, -`col19` CHAR (78), -`col20` MEDIUMTEXT, -`col21` SET ('test1','test2','test3'), -`col22` MEDIUMINT, -`col23` INT, -`col24` MEDIUMBLOB, -`col25` ENUM ('test1','test2','test3'), -`col26` TINYBLOB, -`col27` VARCHAR (116), -`col28` TIMESTAMP, -`col29` BLOB, -`col30` SMALLINT, -`col31` DOUBLE PRECISION, -`col32` DECIMAL, -`col33` DECIMAL, -`col34` TEXT, -`col35` MEDIUMINT, -`col36` MEDIUMINT, -`col37` BIGINT, -`col38` VARCHAR (253), -`col39` TINYBLOB, -`col40` MEDIUMBLOB, -`col41` BIGINT, -`col42` DOUBLE, -`col43` TEXT, -`col44` BLOB, -`col45` TIME, -`col46` MEDIUMINT, -`col47` DOUBLE PRECISION, -`col48` SET ('test1','test2','test3'), -`col49` DOUBLE PRECISION, -`col50` VARCHAR (97), -`col51` TEXT, -`col52` NUMERIC, -`col53` ENUM ('test1','test2','test3'), -`col54` MEDIUMTEXT, -`col55` MEDIUMINT, -`col56` DATETIME, -`col57` DATETIME, -`col58` MEDIUMTEXT, -`col59` CHAR (244), -`col60` LONGBLOB, -`col61` MEDIUMBLOB, -`col62` DOUBLE, -`col63` SMALLINT, -`col64` BOOL, -`col65` SMALLINT, -`col66` VARCHAR (212), -`col67` TIME, -`col68` REAL, -`col69` BOOL, -`col70` BIGINT, -`col71` DATE, -`col72` TINYINT, -`col73` ENUM ('test1','test2','test3'), -`col74` DATE, -`col75` TIME, -`col76` DATETIME, -`col77` BOOL, -`col78` TINYTEXT, -`col79` MEDIUMINT, -`col80` NUMERIC, -`col81` LONGTEXT, -`col82` SET ('test1','test2','test3'), -`col83` DOUBLE PRECISION, -`col84` NUMERIC, -`col85` VARCHAR (184), -`col86` DOUBLE PRECISION, -`col87` MEDIUMTEXT, -`col88` MEDIUMBLOB, -`col89` BOOL, -`col90` SMALLINT, -`col91` TINYINT, -`col92` ENUM ('test1','test2','test3'), -`col93` BOOL, -`col94` TIMESTAMP, -`col95` BOOL, -`col96` MEDIUMTEXT, -`col97` DECIMAL, -`col98` BOOL, -`col99` DECIMAL, -`col100` MEDIUMINT, -`col101` DOUBLE PRECISION, -`col102` TINYINT, -`col103` BOOL, -`col104` MEDIUMINT, -`col105` DECIMAL, -`col106` NUMERIC, -`col107` TIMESTAMP, -`col108` MEDIUMBLOB, -`col109` TINYBLOB, -`col110` SET ('test1','test2','test3'), -`col111` YEAR, -`col112` TIMESTAMP, -`col113` CHAR (201), -`col114` BOOL, -`col115` TINYINT, -`col116` DOUBLE, -`col117` TINYINT, -`col118` TIMESTAMP, -`col119` SET ('test1','test2','test3'), -`col120` SMALLINT, -`col121` TINYBLOB, -`col122` TIMESTAMP, -`col123` BLOB, -`col124` DATE, -`col125` SMALLINT, -`col126` ENUM ('test1','test2','test3'), -`col127` MEDIUMBLOB, -`col128` DOUBLE PRECISION, -`col129` REAL, -`col130` VARCHAR (159), -`col131` MEDIUMBLOB, -`col132` BIGINT, -`col133` INT, -`col134` SET ('test1','test2','test3'), -`col135` CHAR (198), -`col136` SET ('test1','test2','test3'), -`col137` MEDIUMTEXT, -`col138` SMALLINT, -`col139` BLOB, -`col140` LONGBLOB, -KEY `idx0` (`col14`(139),`col24`(208),`col38`,`col35`), -KEY `idx1` (`col48`,`col118`,`col29`(131),`col100`), -KEY `idx2` (`col86`,`col67`,`col43`(175)), -KEY `idx3` (`col19`), -KEY `idx4` (`col40`(220),`col67`), -KEY `idx5` (`col99`,`col56`), -KEY `idx6` (`col68`,`col28`,`col137`(157)), -KEY `idx7` (`col51`(160),`col99`,`col45`,`col39`(9)), -KEY `idx8` (`col15`,`col52`,`col90`,`col94`), -KEY `idx9` (`col24`(3),`col139`(248),`col108`(118),`col41`), -KEY `idx10` (`col36`,`col92`,`col114`), -KEY `idx11` (`col115`,`col9`(116)), -KEY `idx12` (`col130`,`col93`,`col134`), -KEY `idx13` (`col123`(65)), -KEY `idx14` (`col44`(90),`col86`,`col119`), -KEY `idx15` (`col69`), -KEY `idx16` (`col132`,`col81`(118),`col18`), -KEY `idx17` (`col24`(250),`col7`,`col92`,`col45`) -)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; - -# Creating a table with 199 columns and 1 indexes -DROP TABLE IF EXISTS `table3`; ---error ER_TOO_BIG_ROWSIZE -CREATE TABLE IF NOT EXISTS `table3` -(`col0` SMALLINT, -`col1` SET ('test1','test2','test3'), -`col2` TINYTEXT, -`col3` DOUBLE, -`col4` NUMERIC, -`col5` DATE, -`col6` BIGINT, -`col7` DOUBLE, -`col8` TEXT, -`col9` INT, -`col10` REAL, -`col11` TINYINT, -`col12` NUMERIC, -`col13` NUMERIC, -`col14` TIME, -`col15` DOUBLE, -`col16` REAL, -`col17` MEDIUMBLOB, -`col18` YEAR, -`col19` TINYTEXT, -`col20` YEAR, -`col21` CHAR (250), -`col22` TINYINT, -`col23` TINYINT, -`col24` SMALLINT, -`col25` DATETIME, -`col26` MEDIUMINT, -`col27` LONGBLOB, -`col28` VARCHAR (106), -`col29` FLOAT, -`col30` MEDIUMTEXT, -`col31` TINYBLOB, -`col32` BIGINT, -`col33` YEAR, -`col34` REAL, -`col35` MEDIUMBLOB, -`col36` LONGTEXT, -`col37` LONGBLOB, -`col38` BIGINT, -`col39` FLOAT, -`col40` TIME, -`col41` DATETIME, -`col42` BOOL, -`col43` BIGINT, -`col44` SMALLINT, -`col45` TIME, -`col46` DOUBLE PRECISION, -`col47` TIME, -`col48` TINYTEXT, -`col49` DOUBLE PRECISION, -`col50` BIGINT, -`col51` NUMERIC, -`col52` TINYBLOB, -`col53` DATE, -`col54` DECIMAL, -`col55` SMALLINT, -`col56` TINYTEXT, -`col57` ENUM ('test1','test2','test3'), -`col58` YEAR, -`col59` TIME, -`col60` TINYINT, -`col61` DECIMAL, -`col62` DOUBLE, -`col63` DATE, -`col64` LONGTEXT, -`col65` DOUBLE, -`col66` VARCHAR (88), -`col67` MEDIUMTEXT, -`col68` DATE, -`col69` MEDIUMINT, -`col70` DECIMAL, -`col71` MEDIUMTEXT, -`col72` LONGTEXT, -`col73` REAL, -`col74` DOUBLE, -`col75` TIME, -`col76` DATE, -`col77` DECIMAL, -`col78` MEDIUMBLOB, -`col79` NUMERIC, -`col80` BIGINT, -`col81` YEAR, -`col82` SMALLINT, -`col83` MEDIUMINT, -`col84` TINYINT, -`col85` MEDIUMBLOB, -`col86` TIME, -`col87` MEDIUMBLOB, -`col88` LONGTEXT, -`col89` BOOL, -`col90` BLOB, -`col91` LONGBLOB, -`col92` YEAR, -`col93` BLOB, -`col94` INT, -`col95` TINYTEXT, -`col96` TINYINT, -`col97` DECIMAL, -`col98` ENUM ('test1','test2','test3'), -`col99` MEDIUMINT, -`col100` TINYINT, -`col101` MEDIUMBLOB, -`col102` TINYINT, -`col103` SET ('test1','test2','test3'), -`col104` TIMESTAMP, -`col105` TEXT, -`col106` DATETIME, -`col107` MEDIUMTEXT, -`col108` CHAR (220), -`col109` TIME, -`col110` VARCHAR (131), -`col111` DECIMAL, -`col112` FLOAT, -`col113` SMALLINT, -`col114` BIGINT, -`col115` LONGBLOB, -`col116` SET ('test1','test2','test3'), -`col117` ENUM ('test1','test2','test3'), -`col118` BLOB, -`col119` MEDIUMTEXT, -`col120` SET ('test1','test2','test3'), -`col121` DATETIME, -`col122` FLOAT, -`col123` VARCHAR (242), -`col124` YEAR, -`col125` MEDIUMBLOB, -`col126` TIME, -`col127` BOOL, -`col128` TINYBLOB, -`col129` DOUBLE, -`col130` TINYINT, -`col131` BIGINT, -`col132` SMALLINT, -`col133` INT, -`col134` DOUBLE PRECISION, -`col135` MEDIUMBLOB, -`col136` SET ('test1','test2','test3'), -`col137` TINYTEXT, -`col138` DOUBLE PRECISION, -`col139` NUMERIC, -`col140` BLOB, -`col141` SET ('test1','test2','test3'), -`col142` INT, -`col143` VARCHAR (26), -`col144` BLOB, -`col145` REAL, -`col146` SET ('test1','test2','test3'), -`col147` LONGBLOB, -`col148` TEXT, -`col149` BLOB, -`col150` CHAR (189), -`col151` LONGTEXT, -`col152` INT, -`col153` FLOAT, -`col154` LONGTEXT, -`col155` DATE, -`col156` LONGBLOB, -`col157` TINYBLOB, -`col158` REAL, -`col159` DATE, -`col160` TIME, -`col161` YEAR, -`col162` DOUBLE, -`col163` VARCHAR (90), -`col164` FLOAT, -`col165` NUMERIC, -`col166` ENUM ('test1','test2','test3'), -`col167` DOUBLE PRECISION, -`col168` DOUBLE PRECISION, -`col169` TINYBLOB, -`col170` TIME, -`col171` SMALLINT, -`col172` TINYTEXT, -`col173` SMALLINT, -`col174` DOUBLE, -`col175` VARCHAR (14), -`col176` VARCHAR (90), -`col177` REAL, -`col178` MEDIUMINT, -`col179` TINYBLOB, -`col180` FLOAT, -`col181` TIMESTAMP, -`col182` REAL, -`col183` DOUBLE PRECISION, -`col184` BIGINT, -`col185` INT, -`col186` MEDIUMTEXT, -`col187` TIME, -`col188` FLOAT, -`col189` TIME, -`col190` INT, -`col191` FLOAT, -`col192` MEDIUMINT, -`col193` TINYINT, -`col194` MEDIUMTEXT, -`col195` DATE, -`col196` TIME, -`col197` YEAR, -`col198` CHAR (206), -KEY `idx0` (`col39`,`col23`) -)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; - -# Creating a table with 133 columns and 16 indexes -DROP TABLE IF EXISTS `table4`; ---error ER_TOO_BIG_ROWSIZE -CREATE TABLE IF NOT EXISTS `table4` -(`col0` VARCHAR (60), -`col1` NUMERIC, -`col2` LONGTEXT, -`col3` MEDIUMTEXT, -`col4` LONGTEXT, -`col5` LONGBLOB, -`col6` LONGBLOB, -`col7` DATETIME, -`col8` TINYTEXT, -`col9` BLOB, -`col10` BOOL, -`col11` BIGINT, -`col12` TEXT, -`col13` VARCHAR (213), -`col14` TINYBLOB, -`col15` BOOL, -`col16` MEDIUMTEXT, -`col17` DOUBLE, -`col18` TEXT, -`col19` BLOB, -`col20` SET ('test1','test2','test3'), -`col21` TINYINT, -`col22` DATETIME, -`col23` TINYINT, -`col24` ENUM ('test1','test2','test3'), -`col25` REAL, -`col26` BOOL, -`col27` FLOAT, -`col28` LONGBLOB, -`col29` DATETIME, -`col30` FLOAT, -`col31` SET ('test1','test2','test3'), -`col32` LONGBLOB, -`col33` NUMERIC, -`col34` YEAR, -`col35` VARCHAR (146), -`col36` BIGINT, -`col37` DATETIME, -`col38` DATE, -`col39` SET ('test1','test2','test3'), -`col40` CHAR (112), -`col41` FLOAT, -`col42` YEAR, -`col43` TIME, -`col44` DOUBLE, -`col45` NUMERIC, -`col46` FLOAT, -`col47` DECIMAL, -`col48` BIGINT, -`col49` DECIMAL, -`col50` YEAR, -`col51` MEDIUMTEXT, -`col52` LONGBLOB, -`col53` SET ('test1','test2','test3'), -`col54` BLOB, -`col55` FLOAT, -`col56` REAL, -`col57` REAL, -`col58` TEXT, -`col59` MEDIUMBLOB, -`col60` INT, -`col61` INT, -`col62` DATE, -`col63` TEXT, -`col64` DATE, -`col65` ENUM ('test1','test2','test3'), -`col66` DOUBLE PRECISION, -`col67` TINYTEXT, -`col68` TINYBLOB, -`col69` FLOAT, -`col70` BLOB, -`col71` DATETIME, -`col72` DOUBLE, -`col73` LONGTEXT, -`col74` TIME, -`col75` DATETIME, -`col76` VARCHAR (122), -`col77` MEDIUMTEXT, -`col78` MEDIUMTEXT, -`col79` BOOL, -`col80` LONGTEXT, -`col81` TINYTEXT, -`col82` NUMERIC, -`col83` DOUBLE PRECISION, -`col84` DATE, -`col85` YEAR, -`col86` BLOB, -`col87` TINYTEXT, -`col88` DOUBLE PRECISION, -`col89` MEDIUMINT, -`col90` MEDIUMTEXT, -`col91` NUMERIC, -`col92` DATETIME, -`col93` NUMERIC, -`col94` SET ('test1','test2','test3'), -`col95` TINYTEXT, -`col96` SET ('test1','test2','test3'), -`col97` YEAR, -`col98` MEDIUMINT, -`col99` TEXT, -`col100` TEXT, -`col101` TIME, -`col102` VARCHAR (225), -`col103` TINYTEXT, -`col104` TEXT, -`col105` MEDIUMTEXT, -`col106` TINYINT, -`col107` TEXT, -`col108` LONGBLOB, -`col109` LONGTEXT, -`col110` TINYTEXT, -`col111` CHAR (56), -`col112` YEAR, -`col113` ENUM ('test1','test2','test3'), -`col114` TINYBLOB, -`col115` DATETIME, -`col116` DATE, -`col117` TIME, -`col118` MEDIUMTEXT, -`col119` DOUBLE PRECISION, -`col120` FLOAT, -`col121` TIMESTAMP, -`col122` MEDIUMINT, -`col123` YEAR, -`col124` DATE, -`col125` TEXT, -`col126` FLOAT, -`col127` TINYTEXT, -`col128` BOOL, -`col129` NUMERIC, -`col130` TIMESTAMP, -`col131` INT, -`col132` MEDIUMBLOB, -KEY `idx0` (`col130`), -KEY `idx1` (`col30`,`col55`,`col19`(31)), -KEY `idx2` (`col104`(186)), -KEY `idx3` (`col131`), -KEY `idx4` (`col64`,`col93`,`col2`(11)), -KEY `idx5` (`col34`,`col121`,`col22`), -KEY `idx6` (`col33`,`col55`,`col83`), -KEY `idx7` (`col17`,`col87`(245),`col99`(17)), -KEY `idx8` (`col65`,`col120`), -KEY `idx9` (`col82`), -KEY `idx10` (`col9`(72)), -KEY `idx11` (`col88`), -KEY `idx12` (`col128`,`col9`(200),`col71`,`col66`), -KEY `idx13` (`col77`(126)), -KEY `idx14` (`col105`(26),`col13`,`col117`), -KEY `idx15` (`col4`(246),`col130`,`col115`,`col3`(141)) -)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; - -# Creating a table with 176 columns and 13 indexes -DROP TABLE IF EXISTS `table5`; ---error ER_TOO_BIG_ROWSIZE -CREATE TABLE IF NOT EXISTS `table5` -(`col0` MEDIUMTEXT, -`col1` VARCHAR (90), -`col2` TINYTEXT, -`col3` TIME, -`col4` BOOL, -`col5` TINYTEXT, -`col6` BOOL, -`col7` TIMESTAMP, -`col8` TINYBLOB, -`col9` TINYINT, -`col10` YEAR, -`col11` SET ('test1','test2','test3'), -`col12` TEXT, -`col13` CHAR (248), -`col14` BIGINT, -`col15` TEXT, -`col16` TINYINT, -`col17` NUMERIC, -`col18` SET ('test1','test2','test3'), -`col19` LONGBLOB, -`col20` FLOAT, -`col21` INT, -`col22` TEXT, -`col23` BOOL, -`col24` DECIMAL, -`col25` DOUBLE PRECISION, -`col26` FLOAT, -`col27` TINYBLOB, -`col28` NUMERIC, -`col29` MEDIUMBLOB, -`col30` DATE, -`col31` LONGTEXT, -`col32` DATE, -`col33` FLOAT, -`col34` BIGINT, -`col35` TINYTEXT, -`col36` MEDIUMTEXT, -`col37` TIME, -`col38` INT, -`col39` TINYINT, -`col40` SET ('test1','test2','test3'), -`col41` CHAR (130), -`col42` SMALLINT, -`col43` INT, -`col44` MEDIUMTEXT, -`col45` VARCHAR (126), -`col46` INT, -`col47` DOUBLE PRECISION, -`col48` BIGINT, -`col49` MEDIUMTEXT, -`col50` TINYBLOB, -`col51` MEDIUMINT, -`col52` TEXT, -`col53` VARCHAR (208), -`col54` VARCHAR (207), -`col55` NUMERIC, -`col56` DATETIME, -`col57` ENUM ('test1','test2','test3'), -`col58` NUMERIC, -`col59` TINYBLOB, -`col60` VARCHAR (73), -`col61` MEDIUMTEXT, -`col62` TINYBLOB, -`col63` DATETIME, -`col64` NUMERIC, -`col65` MEDIUMINT, -`col66` DATETIME, -`col67` NUMERIC, -`col68` TINYINT, -`col69` VARCHAR (58), -`col70` DECIMAL, -`col71` MEDIUMTEXT, -`col72` DATE, -`col73` TIME, -`col74` DOUBLE PRECISION, -`col75` DECIMAL, -`col76` MEDIUMBLOB, -`col77` REAL, -`col78` YEAR, -`col79` YEAR, -`col80` LONGBLOB, -`col81` BLOB, -`col82` BIGINT, -`col83` ENUM ('test1','test2','test3'), -`col84` NUMERIC, -`col85` SET ('test1','test2','test3'), -`col86` MEDIUMTEXT, -`col87` LONGBLOB, -`col88` TIME, -`col89` ENUM ('test1','test2','test3'), -`col90` DECIMAL, -`col91` FLOAT, -`col92` DATETIME, -`col93` TINYTEXT, -`col94` TIMESTAMP, -`col95` TIMESTAMP, -`col96` TEXT, -`col97` REAL, -`col98` VARCHAR (198), -`col99` TIME, -`col100` TINYINT, -`col101` BIGINT, -`col102` LONGBLOB, -`col103` LONGBLOB, -`col104` MEDIUMINT, -`col105` MEDIUMTEXT, -`col106` TIMESTAMP, -`col107` SMALLINT, -`col108` NUMERIC, -`col109` DECIMAL, -`col110` FLOAT, -`col111` DECIMAL, -`col112` REAL, -`col113` TINYTEXT, -`col114` FLOAT, -`col115` VARCHAR (7), -`col116` LONGTEXT, -`col117` DATE, -`col118` BIGINT, -`col119` TEXT, -`col120` BIGINT, -`col121` BLOB, -`col122` CHAR (110), -`col123` NUMERIC, -`col124` MEDIUMBLOB, -`col125` NUMERIC, -`col126` NUMERIC, -`col127` BOOL, -`col128` TIME, -`col129` TINYBLOB, -`col130` TINYBLOB, -`col131` DATE, -`col132` INT, -`col133` VARCHAR (123), -`col134` CHAR (238), -`col135` VARCHAR (225), -`col136` LONGTEXT, -`col137` LONGBLOB, -`col138` REAL, -`col139` TINYBLOB, -`col140` DATETIME, -`col141` TINYTEXT, -`col142` LONGBLOB, -`col143` BIGINT, -`col144` VARCHAR (236), -`col145` TEXT, -`col146` YEAR, -`col147` DECIMAL, -`col148` TEXT, -`col149` MEDIUMBLOB, -`col150` TINYINT, -`col151` BOOL, -`col152` VARCHAR (72), -`col153` INT, -`col154` VARCHAR (165), -`col155` TINYINT, -`col156` MEDIUMTEXT, -`col157` DOUBLE PRECISION, -`col158` TIME, -`col159` MEDIUMBLOB, -`col160` LONGBLOB, -`col161` DATETIME, -`col162` DOUBLE PRECISION, -`col163` BLOB, -`col164` ENUM ('test1','test2','test3'), -`col165` TIMESTAMP, -`col166` DATE, -`col167` TINYBLOB, -`col168` TINYBLOB, -`col169` LONGBLOB, -`col170` DATETIME, -`col171` BIGINT, -`col172` VARCHAR (30), -`col173` LONGTEXT, -`col174` TIME, -`col175` FLOAT, -KEY `idx0` (`col16`,`col156`(139),`col97`,`col120`), -KEY `idx1` (`col24`,`col0`(108)), -KEY `idx2` (`col117`,`col173`(34),`col132`,`col82`), -KEY `idx3` (`col2`(86)), -KEY `idx4` (`col2`(43)), -KEY `idx5` (`col83`,`col35`(87),`col111`), -KEY `idx6` (`col6`,`col134`,`col92`), -KEY `idx7` (`col56`), -KEY `idx8` (`col30`,`col53`,`col129`(66)), -KEY `idx9` (`col53`,`col113`(211),`col32`,`col15`(75)), -KEY `idx10` (`col34`), -KEY `idx11` (`col126`), -KEY `idx12` (`col24`) -)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; - -# Creating a table with 179 columns and 46 indexes -DROP TABLE IF EXISTS `table6`; --- error ER_TOO_BIG_ROWSIZE ---error ER_TOO_BIG_ROWSIZE -CREATE TABLE IF NOT EXISTS `table6` -(`col0` ENUM ('test1','test2','test3'), -`col1` MEDIUMBLOB, -`col2` MEDIUMBLOB, -`col3` DATETIME, -`col4` DATE, -`col5` YEAR, -`col6` REAL, -`col7` NUMERIC, -`col8` MEDIUMBLOB, -`col9` TEXT, -`col10` TIMESTAMP, -`col11` DOUBLE, -`col12` DOUBLE, -`col13` SMALLINT, -`col14` TIMESTAMP, -`col15` DECIMAL, -`col16` DATE, -`col17` TEXT, -`col18` LONGBLOB, -`col19` BIGINT, -`col20` FLOAT, -`col21` DATETIME, -`col22` TINYINT, -`col23` MEDIUMBLOB, -`col24` SET ('test1','test2','test3'), -`col25` TIME, -`col26` TEXT, -`col27` LONGTEXT, -`col28` BIGINT, -`col29` REAL, -`col30` YEAR, -`col31` MEDIUMBLOB, -`col32` MEDIUMINT, -`col33` FLOAT, -`col34` TEXT, -`col35` DATE, -`col36` TIMESTAMP, -`col37` REAL, -`col38` BLOB, -`col39` BLOB, -`col40` BLOB, -`col41` TINYBLOB, -`col42` INT, -`col43` TINYINT, -`col44` REAL, -`col45` BIGINT, -`col46` TIMESTAMP, -`col47` BLOB, -`col48` ENUM ('test1','test2','test3'), -`col49` BOOL, -`col50` CHAR (109), -`col51` DOUBLE, -`col52` DOUBLE PRECISION, -`col53` ENUM ('test1','test2','test3'), -`col54` FLOAT, -`col55` DOUBLE PRECISION, -`col56` CHAR (166), -`col57` TEXT, -`col58` TIME, -`col59` DECIMAL, -`col60` TEXT, -`col61` ENUM ('test1','test2','test3'), -`col62` LONGTEXT, -`col63` YEAR, -`col64` DOUBLE, -`col65` CHAR (87), -`col66` DATE, -`col67` BOOL, -`col68` MEDIUMBLOB, -`col69` DATETIME, -`col70` DECIMAL, -`col71` TIME, -`col72` REAL, -`col73` LONGTEXT, -`col74` BLOB, -`col75` REAL, -`col76` INT, -`col77` INT, -`col78` FLOAT, -`col79` DOUBLE, -`col80` MEDIUMINT, -`col81` ENUM ('test1','test2','test3'), -`col82` VARCHAR (221), -`col83` BIGINT, -`col84` TINYINT, -`col85` BIGINT, -`col86` FLOAT, -`col87` MEDIUMBLOB, -`col88` CHAR (126), -`col89` MEDIUMBLOB, -`col90` DATETIME, -`col91` TINYINT, -`col92` DOUBLE, -`col93` NUMERIC, -`col94` DATE, -`col95` BLOB, -`col96` DATETIME, -`col97` TIME, -`col98` LONGBLOB, -`col99` INT, -`col100` SET ('test1','test2','test3'), -`col101` TINYBLOB, -`col102` INT, -`col103` MEDIUMBLOB, -`col104` MEDIUMTEXT, -`col105` FLOAT, -`col106` TINYBLOB, -`col107` VARCHAR (26), -`col108` TINYINT, -`col109` TIME, -`col110` TINYBLOB, -`col111` LONGBLOB, -`col112` TINYTEXT, -`col113` FLOAT, -`col114` TINYINT, -`col115` NUMERIC, -`col116` TIME, -`col117` SET ('test1','test2','test3'), -`col118` DATE, -`col119` SMALLINT, -`col120` BLOB, -`col121` TINYTEXT, -`col122` REAL, -`col123` YEAR, -`col124` REAL, -`col125` BOOL, -`col126` BLOB, -`col127` REAL, -`col128` MEDIUMBLOB, -`col129` TIMESTAMP, -`col130` LONGBLOB, -`col131` MEDIUMBLOB, -`col132` YEAR, -`col133` YEAR, -`col134` INT, -`col135` MEDIUMINT, -`col136` MEDIUMINT, -`col137` TINYTEXT, -`col138` TINYBLOB, -`col139` BLOB, -`col140` SET ('test1','test2','test3'), -`col141` ENUM ('test1','test2','test3'), -`col142` ENUM ('test1','test2','test3'), -`col143` TINYTEXT, -`col144` DATETIME, -`col145` TEXT, -`col146` DOUBLE PRECISION, -`col147` DECIMAL, -`col148` MEDIUMTEXT, -`col149` TINYTEXT, -`col150` SET ('test1','test2','test3'), -`col151` MEDIUMTEXT, -`col152` CHAR (126), -`col153` DOUBLE, -`col154` CHAR (243), -`col155` SET ('test1','test2','test3'), -`col156` SET ('test1','test2','test3'), -`col157` DATETIME, -`col158` DOUBLE, -`col159` NUMERIC, -`col160` DECIMAL, -`col161` FLOAT, -`col162` LONGBLOB, -`col163` LONGTEXT, -`col164` INT, -`col165` TIME, -`col166` CHAR (27), -`col167` VARCHAR (63), -`col168` TEXT, -`col169` TINYBLOB, -`col170` TINYBLOB, -`col171` ENUM ('test1','test2','test3'), -`col172` INT, -`col173` TIME, -`col174` DECIMAL, -`col175` DOUBLE, -`col176` MEDIUMBLOB, -`col177` LONGBLOB, -`col178` CHAR (43), -KEY `idx0` (`col131`(219)), -KEY `idx1` (`col67`,`col122`,`col59`,`col87`(33)), -KEY `idx2` (`col83`,`col42`,`col57`(152)), -KEY `idx3` (`col106`(124)), -KEY `idx4` (`col173`,`col80`,`col165`,`col89`(78)), -KEY `idx5` (`col174`,`col145`(108),`col23`(228),`col141`), -KEY `idx6` (`col157`,`col140`), -KEY `idx7` (`col130`(188),`col15`), -KEY `idx8` (`col52`), -KEY `idx9` (`col144`), -KEY `idx10` (`col155`), -KEY `idx11` (`col62`(230),`col1`(109)), -KEY `idx12` (`col151`(24),`col95`(85)), -KEY `idx13` (`col114`), -KEY `idx14` (`col42`,`col98`(56),`col146`), -KEY `idx15` (`col147`,`col39`(254),`col35`), -KEY `idx16` (`col79`), -KEY `idx17` (`col65`), -KEY `idx18` (`col149`(165),`col168`(119),`col32`,`col117`), -KEY `idx19` (`col64`), -KEY `idx20` (`col93`), -KEY `idx21` (`col64`,`col113`,`col104`(182)), -KEY `idx22` (`col52`,`col111`(189)), -KEY `idx23` (`col45`), -KEY `idx24` (`col154`,`col107`,`col110`(159)), -KEY `idx25` (`col149`(1),`col87`(131)), -KEY `idx26` (`col58`,`col115`,`col63`), -KEY `idx27` (`col95`(9),`col0`,`col87`(113)), -KEY `idx28` (`col92`,`col130`(1)), -KEY `idx29` (`col151`(129),`col137`(254),`col13`), -KEY `idx30` (`col49`), -KEY `idx31` (`col28`), -KEY `idx32` (`col83`,`col146`), -KEY `idx33` (`col155`,`col90`,`col17`(245)), -KEY `idx34` (`col174`,`col169`(44),`col107`), -KEY `idx35` (`col113`), -KEY `idx36` (`col52`), -KEY `idx37` (`col16`,`col120`(190)), -KEY `idx38` (`col28`), -KEY `idx39` (`col131`(165)), -KEY `idx40` (`col135`,`col26`(86)), -KEY `idx41` (`col69`,`col94`), -KEY `idx42` (`col105`,`col151`(38),`col97`), -KEY `idx43` (`col88`), -KEY `idx44` (`col176`(100),`col42`,`col73`(189),`col94`), -KEY `idx45` (`col2`(27),`col27`(116)) -)engine=innodb ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1; - -DROP TABLE IF EXISTS table0; -DROP TABLE IF EXISTS table1; -DROP TABLE IF EXISTS table2; -DROP TABLE IF EXISTS table3; -DROP TABLE IF EXISTS table4; -DROP TABLE IF EXISTS table5; -DROP TABLE IF EXISTS table6; - -EVAL SET GLOBAL innodb_file_format=$file_format; -EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/storage/innobase/mysql-test/innodb_bug36172.result b/storage/innobase/mysql-test/innodb_bug36172.result deleted file mode 100644 index 195775f74c8..00000000000 --- a/storage/innobase/mysql-test/innodb_bug36172.result +++ /dev/null @@ -1 +0,0 @@ -SET storage_engine=InnoDB; diff --git a/storage/innobase/mysql-test/innodb_bug36172.test b/storage/innobase/mysql-test/innodb_bug36172.test deleted file mode 100644 index c6c4e6fae47..00000000000 --- a/storage/innobase/mysql-test/innodb_bug36172.test +++ /dev/null @@ -1,32 +0,0 @@ -# -# Test case for bug 36172 -# - --- source include/not_embedded.inc --- source include/have_innodb.inc - -SET storage_engine=InnoDB; - -# we do not really care about what gets printed, we are only -# interested in getting success or failure according to our -# expectations - --- disable_query_log --- disable_result_log - -let $file_format=`select @@innodb_file_format`; -let $file_format_check=`select @@innodb_file_format_check`; -let $file_per_table=`select @@innodb_file_per_table`; -SET GLOBAL innodb_file_format='Barracuda'; -SET GLOBAL innodb_file_per_table=on; - -DROP TABLE IF EXISTS `table0`; -CREATE TABLE `table0` ( `col0` tinyint(1) DEFAULT NULL, `col1` tinyint(1) DEFAULT NULL, `col2` tinyint(4) DEFAULT NULL, `col3` date DEFAULT NULL, `col4` time DEFAULT NULL, `col5` set('test1','test2','test3') DEFAULT NULL, `col6` time DEFAULT NULL, `col7` text, `col8` decimal(10,0) DEFAULT NULL, `col9` set('test1','test2','test3') DEFAULT NULL, `col10` float DEFAULT NULL, `col11` double DEFAULT NULL, `col12` enum('test1','test2','test3') DEFAULT NULL, `col13` tinyblob, `col14` year(4) DEFAULT NULL, `col15` set('test1','test2','test3') DEFAULT NULL, `col16` decimal(10,0) DEFAULT NULL, `col17` decimal(10,0) DEFAULT NULL, `col18` blob, `col19` datetime DEFAULT NULL, `col20` double DEFAULT NULL, `col21` decimal(10,0) DEFAULT NULL, `col22` datetime DEFAULT NULL, `col23` decimal(10,0) DEFAULT NULL, `col24` decimal(10,0) DEFAULT NULL, `col25` longtext, `col26` tinyblob, `col27` time DEFAULT NULL, `col28` tinyblob, `col29` enum('test1','test2','test3') DEFAULT NULL, `col30` smallint(6) DEFAULT NULL, `col31` double DEFAULT NULL, `col32` float DEFAULT NULL, `col33` char(175) DEFAULT NULL, `col34` tinytext, `col35` tinytext, `col36` tinyblob, `col37` tinyblob, `col38` tinytext, `col39` mediumblob, `col40` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `col41` double DEFAULT NULL, `col42` smallint(6) DEFAULT NULL, `col43` longblob, `col44` varchar(80) DEFAULT NULL, `col45` mediumtext, `col46` decimal(10,0) DEFAULT NULL, `col47` bigint(20) DEFAULT NULL, `col48` date DEFAULT NULL, `col49` tinyblob, `col50` date DEFAULT NULL, `col51` tinyint(1) DEFAULT NULL, `col52` mediumint(9) DEFAULT NULL, `col53` float DEFAULT NULL, `col54` tinyblob, `col55` longtext, `col56` smallint(6) DEFAULT NULL, `col57` enum('test1','test2','test3') DEFAULT NULL, `col58` datetime DEFAULT NULL, `col59` mediumtext, `col60` varchar(232) DEFAULT NULL, `col61` decimal(10,0) DEFAULT NULL, `col62` year(4) DEFAULT NULL, `col63` smallint(6) DEFAULT NULL, `col64` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `col65` blob, `col66` longblob, `col67` int(11) DEFAULT NULL, `col68` longtext, `col69` enum('test1','test2','test3') DEFAULT NULL, `col70` int(11) DEFAULT NULL, `col71` time DEFAULT NULL, `col72` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `col73` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `col74` varchar(170) DEFAULT NULL, `col75` set('test1','test2','test3') DEFAULT NULL, `col76` tinyblob, `col77` bigint(20) DEFAULT NULL, `col78` decimal(10,0) DEFAULT NULL, `col79` datetime DEFAULT NULL, `col80` year(4) DEFAULT NULL, `col81` decimal(10,0) DEFAULT NULL, `col82` longblob, `col83` text, `col84` char(83) DEFAULT NULL, `col85` decimal(10,0) DEFAULT NULL, `col86` float DEFAULT NULL, `col87` int(11) DEFAULT NULL, `col88` varchar(145) DEFAULT NULL, `col89` date DEFAULT NULL, `col90` decimal(10,0) DEFAULT NULL, `col91` decimal(10,0) DEFAULT NULL, `col92` mediumblob, `col93` time DEFAULT NULL, KEY `idx0` (`col69`,`col90`,`col8`), KEY `idx1` (`col60`), KEY `idx2` (`col60`,`col70`,`col74`), KEY `idx3` (`col22`,`col32`,`col72`,`col30`), KEY `idx4` (`col29`), KEY `idx5` (`col19`,`col45`(143)), KEY `idx6` (`col46`,`col48`,`col5`,`col39`(118)), KEY `idx7` (`col48`,`col61`), KEY `idx8` (`col93`), KEY `idx9` (`col31`), KEY `idx10` (`col30`,`col21`), KEY `idx11` (`col67`), KEY `idx12` (`col44`,`col6`,`col8`,`col38`(226)), KEY `idx13` (`col71`,`col41`,`col15`,`col49`(88)), KEY `idx14` (`col78`), KEY `idx15` (`col63`,`col67`,`col64`), KEY `idx16` (`col17`,`col86`), KEY `idx17` (`col77`,`col56`,`col10`,`col55`(24)), KEY `idx18` (`col62`), KEY `idx19` (`col31`,`col57`,`col56`,`col53`), KEY `idx20` (`col46`), KEY `idx21` (`col83`(54)), KEY `idx22` (`col51`,`col7`(120)), KEY `idx23` (`col7`(163),`col31`,`col71`,`col14`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2; -insert ignore into `table0` set `col23` = 7887371.5084383683, `col24` = 4293854615.6906948000, `col25` = 'vitalist', `col26` = 'widespread', `col27` = '3570490', `col28` = 'habitual', `col30` = -5471, `col31` = 4286985783.6771750000, `col32` = 6354540.9826654866, `col33` = 'defoliation', `col34` = 'logarithms', `col35` = 'tegument\'s', `col36` = 'scouting\'s', `col37` = 'intermittency', `col38` = 'elongates', `col39` = 'prophecies', `col40` = '20560103035939', `col41` = 4292809130.0544143000, `col42` = 22057, `col43` = 'Hess\'s', `col44` = 'bandstand', `col45` = 'phenylketonuria', `col46` = 6338767.4018677324, `col47` = 5310247, `col48` = '12592418', `col49` = 'churchman\'s', `col50` = '32226125', `col51` = -58, `col52` = -6207968, `col53` = 1244839.3255104220, `col54` = 'robotized', `col55` = 'monotonous', `col56` = -26909, `col58` = '20720107023550', `col59` = 'suggestiveness\'s', `col60` = 'gemology', `col61` = 4287800670.2229986000, `col62` = '1944', `col63` = -16827, `col64` = '20700107212324', `col65` = 'Nicolais', `col66` = 'apteryx', `col67` = 6935317, `col68` = 'stroganoff', `col70` = 3316430, `col71` = '3277608', `col72` = '19300511045918', `col73` = '20421201003327', `col74` = 'attenuant', `col75` = '15173', `col76` = 'upstroke\'s', `col77` = 8118987, `col78` = 6791516.2735374002, `col79` = '20780701144624', `col80` = '2134', `col81` = 4290682351.3127537000, `col82` = 'unexplainably', `col83` = 'Storm', `col84` = 'Greyso\'s', `col85` = 4289119212.4306774000, `col86` = 7617575.8796655172, `col87` = -6325335, `col88` = 'fondue\'s', `col89` = '40608940', `col90` = 1659421.8093508712, `col91` = 8346904.6584368423, `col92` = 'reloads', `col93` = '5188366'; -CHECK TABLE table0 EXTENDED; -INSERT IGNORE INTO `table0` SET `col19` = '19940127002709', `col20` = 2383927.9055146948, `col21` = 4293243420.5621204000, `col22` = '20511211123705', `col23` = 4289899778.6573381000, `col24` = 4293449279.0540481000, `col25` = 'emphysemic', `col26` = 'dentally', `col27` = '2347406', `col28` = 'eruct', `col30` = 1222, `col31` = 4294372994.9941406000, `col32` = 4291385574.1173744000, `col33` = 'borrowing\'s', `col34` = 'septics', `col35` = 'ratter\'s', `col36` = 'Kaye', `col37` = 'Florentia', `col38` = 'allium', `col39` = 'barkeep', `col40` = '19510407003441', `col41` = 4293559200.4215522000, `col42` = 22482, `col43` = 'decussate', `col44` = 'Brom\'s', `col45` = 'violated', `col46` = 4925506.4635456400, `col47` = 930549, `col48` = '51296066', `col49` = 'voluminously', `col50` = '29306676', `col51` = -88, `col52` = -2153690, `col53` = 4290250202.1464887000, `col54` = 'expropriation', `col55` = 'Aberdeen\'s', `col56` = 20343, `col58` = '19640415171532', `col59` = 'extern', `col60` = 'Ubana', `col61` = 4290487961.8539081000, `col62` = '2147', `col63` = -24271, `col64` = '20750801194548', `col65` = 'Cunaxa\'s', `col66` = 'pasticcio', `col67` = 2795817, `col68` = 'Indore\'s', `col70` = 6864127, `col71` = '1817832', `col72` = '20540506114211', `col73` = '20040101012300', `col74` = 'rationalized', `col75` = '45522', `col76` = 'indene', `col77` = -6964559, `col78` = 4247535.5266884370, `col79` = '20720416124357', `col80` = '2143', `col81` = 4292060102.4466386000, `col82` = 'striving', `col83` = 'boneblack\'s', `col84` = 'redolent', `col85` = 6489697.9009369183, `col86` = 4287473465.9731131000, `col87` = 7726015, `col88` = 'perplexed', `col89` = '17153791', `col90` = 5478587.1108127078, `col91` = 4287091404.7004304000, `col92` = 'Boulez\'s', `col93` = '2931278'; -CHECK TABLE table0 EXTENDED; -DROP TABLE table0; -EVAL SET GLOBAL innodb_file_format=$file_format; -EVAL SET GLOBAL innodb_file_format_check=$file_format_check; -EVAL SET GLOBAL innodb_file_per_table=$file_per_table; diff --git a/storage/innobase/mysql-test/innodb_bug40360.result b/storage/innobase/mysql-test/innodb_bug40360.result deleted file mode 100644 index ef4cf463903..00000000000 --- a/storage/innobase/mysql-test/innodb_bug40360.result +++ /dev/null @@ -1,4 +0,0 @@ -SET TX_ISOLATION='READ-COMMITTED'; -CREATE TABLE bug40360 (a INT) engine=innodb; -INSERT INTO bug40360 VALUES (1); -DROP TABLE bug40360; diff --git a/storage/innobase/mysql-test/innodb_bug40360.test b/storage/innobase/mysql-test/innodb_bug40360.test deleted file mode 100644 index e88837aab4f..00000000000 --- a/storage/innobase/mysql-test/innodb_bug40360.test +++ /dev/null @@ -1,16 +0,0 @@ -# -# Make sure http://bugs.mysql.com/40360 remains fixed. -# - --- source include/not_embedded.inc --- source include/have_innodb.inc - -SET TX_ISOLATION='READ-COMMITTED'; - -# This is the default since MySQL 5.1.29 SET BINLOG_FORMAT='STATEMENT'; - -CREATE TABLE bug40360 (a INT) engine=innodb; - -INSERT INTO bug40360 VALUES (1); - -DROP TABLE bug40360; diff --git a/storage/innobase/mysql-test/innodb_bug40565.result b/storage/innobase/mysql-test/innodb_bug40565.result deleted file mode 100644 index 21e923d9336..00000000000 --- a/storage/innobase/mysql-test/innodb_bug40565.result +++ /dev/null @@ -1,9 +0,0 @@ -create table bug40565(value decimal(4,2)) engine=innodb; -insert into bug40565 values (1), (null); -update bug40565 set value=NULL; -affected rows: 1 -info: Rows matched: 2 Changed: 1 Warnings: 0 -update bug40565 set value=NULL; -affected rows: 0 -info: Rows matched: 2 Changed: 0 Warnings: 0 -drop table bug40565; diff --git a/storage/innobase/mysql-test/innodb_bug40565.test b/storage/innobase/mysql-test/innodb_bug40565.test deleted file mode 100644 index d7aa0fd514a..00000000000 --- a/storage/innobase/mysql-test/innodb_bug40565.test +++ /dev/null @@ -1,10 +0,0 @@ -# Bug #40565 Update Query Results in "1 Row Affected" But Should Be "Zero Rows" --- source include/have_innodb.inc - -create table bug40565(value decimal(4,2)) engine=innodb; -insert into bug40565 values (1), (null); ---enable_info -update bug40565 set value=NULL; -update bug40565 set value=NULL; ---disable_info -drop table bug40565; diff --git a/storage/innobase/mysql-test/innodb_bug41904.result b/storage/innobase/mysql-test/innodb_bug41904.result deleted file mode 100644 index 6070d32d181..00000000000 --- a/storage/innobase/mysql-test/innodb_bug41904.result +++ /dev/null @@ -1,4 +0,0 @@ -CREATE TABLE bug41904 (id INT PRIMARY KEY, uniquecol CHAR(15)) ENGINE=InnoDB; -INSERT INTO bug41904 VALUES (1,NULL), (2,NULL); -CREATE UNIQUE INDEX ui ON bug41904 (uniquecol); -DROP TABLE bug41904; diff --git a/storage/innobase/mysql-test/innodb_bug41904.test b/storage/innobase/mysql-test/innodb_bug41904.test deleted file mode 100644 index 365c5229adc..00000000000 --- a/storage/innobase/mysql-test/innodb_bug41904.test +++ /dev/null @@ -1,14 +0,0 @@ -# -# Make sure http://bugs.mysql.com/41904 remains fixed. -# - --- source include/not_embedded.inc --- source include/have_innodb.inc - -CREATE TABLE bug41904 (id INT PRIMARY KEY, uniquecol CHAR(15)) ENGINE=InnoDB; - -INSERT INTO bug41904 VALUES (1,NULL), (2,NULL); - -CREATE UNIQUE INDEX ui ON bug41904 (uniquecol); - -DROP TABLE bug41904; diff --git a/storage/innobase/mysql-test/innodb_bug42101-nonzero.result b/storage/innobase/mysql-test/innodb_bug42101-nonzero.result deleted file mode 100644 index 277dfffdd35..00000000000 --- a/storage/innobase/mysql-test/innodb_bug42101-nonzero.result +++ /dev/null @@ -1,26 +0,0 @@ -set global innodb_commit_concurrency=0; -ERROR HY000: Incorrect arguments to SET -select @@innodb_commit_concurrency; -@@innodb_commit_concurrency -1 -set global innodb_commit_concurrency=1; -select @@innodb_commit_concurrency; -@@innodb_commit_concurrency -1 -set global innodb_commit_concurrency=42; -select @@innodb_commit_concurrency; -@@innodb_commit_concurrency -42 -set global innodb_commit_concurrency=DEFAULT; -select @@innodb_commit_concurrency; -@@innodb_commit_concurrency -1 -set global innodb_commit_concurrency=0; -ERROR HY000: Incorrect arguments to SET -select @@innodb_commit_concurrency; -@@innodb_commit_concurrency -1 -set global innodb_commit_concurrency=1; -select @@innodb_commit_concurrency; -@@innodb_commit_concurrency -1 diff --git a/storage/innobase/mysql-test/innodb_bug42101-nonzero.test b/storage/innobase/mysql-test/innodb_bug42101-nonzero.test deleted file mode 100644 index 685fdf20489..00000000000 --- a/storage/innobase/mysql-test/innodb_bug42101-nonzero.test +++ /dev/null @@ -1,21 +0,0 @@ -# -# Bug#42101 Race condition in innodb_commit_concurrency -# http://bugs.mysql.com/42101 -# - --- source include/have_innodb.inc - ---error ER_WRONG_ARGUMENTS -set global innodb_commit_concurrency=0; -select @@innodb_commit_concurrency; -set global innodb_commit_concurrency=1; -select @@innodb_commit_concurrency; -set global innodb_commit_concurrency=42; -select @@innodb_commit_concurrency; -set global innodb_commit_concurrency=DEFAULT; -select @@innodb_commit_concurrency; ---error ER_WRONG_ARGUMENTS -set global innodb_commit_concurrency=0; -select @@innodb_commit_concurrency; -set global innodb_commit_concurrency=1; -select @@innodb_commit_concurrency; diff --git a/storage/innobase/mysql-test/innodb_bug42101.result b/storage/innobase/mysql-test/innodb_bug42101.result deleted file mode 100644 index 805097ffe9d..00000000000 --- a/storage/innobase/mysql-test/innodb_bug42101.result +++ /dev/null @@ -1,22 +0,0 @@ -set global innodb_commit_concurrency=0; -select @@innodb_commit_concurrency; -@@innodb_commit_concurrency -0 -set global innodb_commit_concurrency=1; -ERROR HY000: Incorrect arguments to SET -select @@innodb_commit_concurrency; -@@innodb_commit_concurrency -0 -set global innodb_commit_concurrency=42; -ERROR HY000: Incorrect arguments to SET -select @@innodb_commit_concurrency; -@@innodb_commit_concurrency -0 -set global innodb_commit_concurrency=0; -select @@innodb_commit_concurrency; -@@innodb_commit_concurrency -0 -set global innodb_commit_concurrency=DEFAULT; -select @@innodb_commit_concurrency; -@@innodb_commit_concurrency -0 diff --git a/storage/innobase/mysql-test/innodb_bug42101.test b/storage/innobase/mysql-test/innodb_bug42101.test deleted file mode 100644 index b6536490d48..00000000000 --- a/storage/innobase/mysql-test/innodb_bug42101.test +++ /dev/null @@ -1,19 +0,0 @@ -# -# Bug#42101 Race condition in innodb_commit_concurrency -# http://bugs.mysql.com/42101 -# - --- source include/have_innodb.inc - -set global innodb_commit_concurrency=0; -select @@innodb_commit_concurrency; ---error ER_WRONG_ARGUMENTS -set global innodb_commit_concurrency=1; -select @@innodb_commit_concurrency; ---error ER_WRONG_ARGUMENTS -set global innodb_commit_concurrency=42; -select @@innodb_commit_concurrency; -set global innodb_commit_concurrency=0; -select @@innodb_commit_concurrency; -set global innodb_commit_concurrency=DEFAULT; -select @@innodb_commit_concurrency; diff --git a/storage/innobase/mysql-test/innodb_bug44032.result b/storage/innobase/mysql-test/innodb_bug44032.result deleted file mode 100644 index da2a000b06e..00000000000 --- a/storage/innobase/mysql-test/innodb_bug44032.result +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE bug44032(c CHAR(3) CHARACTER SET UTF8) ROW_FORMAT=REDUNDANT -ENGINE=InnoDB; -INSERT INTO bug44032 VALUES('abc'),(0xEFBCA4EFBCA4EFBCA4); -UPDATE bug44032 SET c='DDD' WHERE c=0xEFBCA4EFBCA4EFBCA4; -UPDATE bug44032 SET c=NULL WHERE c='DDD'; -UPDATE bug44032 SET c='DDD' WHERE c IS NULL; -DROP TABLE bug44032; diff --git a/storage/innobase/mysql-test/innodb_bug44032.test b/storage/innobase/mysql-test/innodb_bug44032.test deleted file mode 100644 index a963cb8b68f..00000000000 --- a/storage/innobase/mysql-test/innodb_bug44032.test +++ /dev/null @@ -1,13 +0,0 @@ -# Bug44032 no update-in-place of UTF-8 columns in ROW_FORMAT=REDUNDANT -# (btr_cur_update_in_place not invoked when updating from/to NULL; -# the update is performed by delete and insert instead) - --- source include/have_innodb.inc - -CREATE TABLE bug44032(c CHAR(3) CHARACTER SET UTF8) ROW_FORMAT=REDUNDANT -ENGINE=InnoDB; -INSERT INTO bug44032 VALUES('abc'),(0xEFBCA4EFBCA4EFBCA4); -UPDATE bug44032 SET c='DDD' WHERE c=0xEFBCA4EFBCA4EFBCA4; -UPDATE bug44032 SET c=NULL WHERE c='DDD'; -UPDATE bug44032 SET c='DDD' WHERE c IS NULL; -DROP TABLE bug44032; diff --git a/storage/innobase/mysql-test/innodb_bug44369.result b/storage/innobase/mysql-test/innodb_bug44369.result deleted file mode 100644 index e4b84ecac19..00000000000 --- a/storage/innobase/mysql-test/innodb_bug44369.result +++ /dev/null @@ -1,14 +0,0 @@ -create table bug44369 (DB_ROW_ID int) engine=innodb; -ERROR HY000: Can't create table 'test.bug44369' (errno: -1) -create table bug44369 (db_row_id int) engine=innodb; -ERROR HY000: Can't create table 'test.bug44369' (errno: -1) -show errors; -Level Code Message -Error 1005 Error creating table 'test/bug44369' with column name 'db_row_id'. 'db_row_id' is a reserved name. Please try to re-create the table with a different column name. -Error 1005 Can't create table 'test.bug44369' (errno: -1) -create table bug44369 (db_TRX_Id int) engine=innodb; -ERROR HY000: Can't create table 'test.bug44369' (errno: -1) -show errors; -Level Code Message -Error 1005 Error creating table 'test/bug44369' with column name 'db_TRX_Id'. 'db_TRX_Id' is a reserved name. Please try to re-create the table with a different column name. -Error 1005 Can't create table 'test.bug44369' (errno: -1) diff --git a/storage/innobase/mysql-test/innodb_bug44369.test b/storage/innobase/mysql-test/innodb_bug44369.test deleted file mode 100644 index 495059eb5e6..00000000000 --- a/storage/innobase/mysql-test/innodb_bug44369.test +++ /dev/null @@ -1,21 +0,0 @@ -# This is the test for bug 44369. We should -# block table creation with columns match -# some innodb internal reserved key words, -# both case sensitively and insensitely. - ---source include/have_innodb.inc - -# This create table operation should fail. ---error ER_CANT_CREATE_TABLE -create table bug44369 (DB_ROW_ID int) engine=innodb; - -# This create should fail as well ---error ER_CANT_CREATE_TABLE -create table bug44369 (db_row_id int) engine=innodb; - -show errors; - ---error ER_CANT_CREATE_TABLE -create table bug44369 (db_TRX_Id int) engine=innodb; - -show errors; diff --git a/storage/innobase/mysql-test/innodb_bug44571.result b/storage/innobase/mysql-test/innodb_bug44571.result deleted file mode 100644 index 36374edcb3e..00000000000 --- a/storage/innobase/mysql-test/innodb_bug44571.result +++ /dev/null @@ -1,9 +0,0 @@ -CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; -ALTER TABLE bug44571 CHANGE foo bar INT; -ALTER TABLE bug44571 ADD INDEX bug44571b (foo); -ERROR 42000: Key column 'foo' doesn't exist in table -ALTER TABLE bug44571 ADD INDEX bug44571b (bar); -ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it -CREATE INDEX bug44571b ON bug44571 (bar); -ERROR HY000: Incorrect key file for table 'bug44571'; try to repair it -DROP TABLE bug44571; diff --git a/storage/innobase/mysql-test/innodb_bug44571.test b/storage/innobase/mysql-test/innodb_bug44571.test deleted file mode 100644 index 685463ceff9..00000000000 --- a/storage/innobase/mysql-test/innodb_bug44571.test +++ /dev/null @@ -1,17 +0,0 @@ -# -# Bug#44571 InnoDB Plugin crashes on ADD INDEX -# http://bugs.mysql.com/44571 -# --- source include/have_innodb.inc - -CREATE TABLE bug44571 (foo INT) ENGINE=InnoDB; -ALTER TABLE bug44571 CHANGE foo bar INT; --- error ER_KEY_COLUMN_DOES_NOT_EXITS -ALTER TABLE bug44571 ADD INDEX bug44571b (foo); -# The following will fail, because the CHANGE foo bar was -# not communicated to InnoDB. ---error ER_NOT_KEYFILE -ALTER TABLE bug44571 ADD INDEX bug44571b (bar); ---error ER_NOT_KEYFILE -CREATE INDEX bug44571b ON bug44571 (bar); -DROP TABLE bug44571; diff --git a/storage/innobase/mysql-test/innodb_bug45357.result b/storage/innobase/mysql-test/innodb_bug45357.result deleted file mode 100644 index 7adeff2062f..00000000000 --- a/storage/innobase/mysql-test/innodb_bug45357.result +++ /dev/null @@ -1,7 +0,0 @@ -set session transaction isolation level read committed; -create table bug45357(a int, b int,key(b))engine=innodb; -insert into bug45357 values (25170,6122); -update bug45357 set a=1 where b=30131; -delete from bug45357 where b < 20996; -delete from bug45357 where b < 7001; -drop table bug45357; diff --git a/storage/innobase/mysql-test/innodb_bug45357.test b/storage/innobase/mysql-test/innodb_bug45357.test deleted file mode 100644 index 81727f352dd..00000000000 --- a/storage/innobase/mysql-test/innodb_bug45357.test +++ /dev/null @@ -1,10 +0,0 @@ --- source include/have_innodb.inc - -set session transaction isolation level read committed; - -create table bug45357(a int, b int,key(b))engine=innodb; -insert into bug45357 values (25170,6122); -update bug45357 set a=1 where b=30131; -delete from bug45357 where b < 20996; -delete from bug45357 where b < 7001; -drop table bug45357; diff --git a/storage/innobase/mysql-test/innodb_bug46000.result b/storage/innobase/mysql-test/innodb_bug46000.result deleted file mode 100644 index ccff888a48d..00000000000 --- a/storage/innobase/mysql-test/innodb_bug46000.result +++ /dev/null @@ -1,17 +0,0 @@ -create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; -ERROR HY000: Can't create table 'test.bug46000' (errno: -1) -create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; -ERROR HY000: Can't create table 'test.bug46000' (errno: -1) -show errors; -Level Code Message -Error 1005 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. -Error 1005 Can't create table 'test.bug46000' (errno: -1) -create table bug46000(id int) engine=innodb; -create index GEN_CLUST_INDEX on bug46000(id); -ERROR HY000: Can't create table '#sql-temporary' (errno: -1) -show errors; -Level Code Message -Error 1005 Cannot Create Index with name 'GEN_CLUST_INDEX'. The name is reserved for the system default primary index. -Error 1005 Can't create table '#sql-temporary' (errno: -1) -create index idx on bug46000(id); -drop table bug46000; diff --git a/storage/innobase/mysql-test/innodb_bug46000.test b/storage/innobase/mysql-test/innodb_bug46000.test deleted file mode 100644 index 80c18c58ef0..00000000000 --- a/storage/innobase/mysql-test/innodb_bug46000.test +++ /dev/null @@ -1,34 +0,0 @@ -# This is the test for bug 46000. We shall -# block any index creation with the name of -# "GEN_CLUST_INDEX", which is the reserved -# name for innodb default primary index. - ---source include/have_innodb.inc - -# This 'create table' operation should fail because of -# using the reserve name as its index name. ---error ER_CANT_CREATE_TABLE -create table bug46000(`id` int,key `GEN_CLUST_INDEX`(`id`))engine=innodb; - -# Mixed upper/lower case of the reserved key words ---error ER_CANT_CREATE_TABLE -create table bug46000(`id` int, key `GEN_clust_INDEX`(`id`))engine=innodb; - -show errors; - -create table bug46000(id int) engine=innodb; - -# This 'create index' operation should fail. ---replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ ---error ER_CANT_CREATE_TABLE -create index GEN_CLUST_INDEX on bug46000(id); - ---replace_regex /'[^']*test.#sql-[0-9a-f_]*'/'#sql-temporary'/ -show errors; - -# This 'create index' operation should succeed, no -# temp table left from last failed create index -# operation. -create index idx on bug46000(id); - -drop table bug46000; diff --git a/storage/innobase/mysql-test/innodb_file_format.result b/storage/innobase/mysql-test/innodb_file_format.result deleted file mode 100644 index 8e9a317308b..00000000000 --- a/storage/innobase/mysql-test/innodb_file_format.result +++ /dev/null @@ -1,45 +0,0 @@ -select @@innodb_file_format; -@@innodb_file_format -Antelope -select @@innodb_file_format_check; -@@innodb_file_format_check -Antelope -set global innodb_file_format=antelope; -set global innodb_file_format=barracuda; -set global innodb_file_format=cheetah; -ERROR HY000: Incorrect arguments to SET -select @@innodb_file_format; -@@innodb_file_format -Barracuda -set global innodb_file_format=default; -select @@innodb_file_format; -@@innodb_file_format -Antelope -set global innodb_file_format=on; -ERROR HY000: Incorrect arguments to SET -set global innodb_file_format=off; -ERROR HY000: Incorrect arguments to SET -select @@innodb_file_format; -@@innodb_file_format -Antelope -set global innodb_file_format_check=antelope; -set global innodb_file_format_check=barracuda; -set global innodb_file_format_check=cheetah; -ERROR HY000: Incorrect arguments to SET -select @@innodb_file_format_check; -@@innodb_file_format_check -Barracuda -set global innodb_file_format_check=default; -Warnings: -Warning 1210 Ignoring SET innodb_file_format=on -select @@innodb_file_format_check; -@@innodb_file_format_check -Barracuda -set global innodb_file_format=on; -ERROR HY000: Incorrect arguments to SET -set global innodb_file_format=off; -ERROR HY000: Incorrect arguments to SET -select @@innodb_file_format_check; -@@innodb_file_format_check -Barracuda -set global innodb_file_format_check=antelope; diff --git a/storage/innobase/mysql-test/innodb_file_format.test b/storage/innobase/mysql-test/innodb_file_format.test deleted file mode 100644 index d63c9b0228f..00000000000 --- a/storage/innobase/mysql-test/innodb_file_format.test +++ /dev/null @@ -1,29 +0,0 @@ --- source include/have_innodb.inc - -select @@innodb_file_format; -select @@innodb_file_format_check; -set global innodb_file_format=antelope; -set global innodb_file_format=barracuda; ---error ER_WRONG_ARGUMENTS -set global innodb_file_format=cheetah; -select @@innodb_file_format; -set global innodb_file_format=default; -select @@innodb_file_format; ---error ER_WRONG_ARGUMENTS -set global innodb_file_format=on; ---error ER_WRONG_ARGUMENTS -set global innodb_file_format=off; -select @@innodb_file_format; -set global innodb_file_format_check=antelope; -set global innodb_file_format_check=barracuda; ---error ER_WRONG_ARGUMENTS -set global innodb_file_format_check=cheetah; -select @@innodb_file_format_check; -set global innodb_file_format_check=default; -select @@innodb_file_format_check; ---error ER_WRONG_ARGUMENTS -set global innodb_file_format=on; ---error ER_WRONG_ARGUMENTS -set global innodb_file_format=off; -select @@innodb_file_format_check; -set global innodb_file_format_check=antelope; diff --git a/storage/innobase/mysql-test/innodb_information_schema.result b/storage/innobase/mysql-test/innodb_information_schema.result deleted file mode 100644 index 396cae579ce..00000000000 --- a/storage/innobase/mysql-test/innodb_information_schema.result +++ /dev/null @@ -1,23 +0,0 @@ -lock_mode lock_type lock_table lock_index lock_rec lock_data -X RECORD `test`.```t'\"_str` `PRIMARY` 2 '1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc''''' -X RECORD `test`.```t'\"_str` `PRIMARY` 2 '1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc''''' -X RECORD `test`.```t'\"_str` `PRIMARY` 3 '2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""' -X RECORD `test`.```t'\"_str` `PRIMARY` 3 '2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""' -X RECORD `test`.```t'\"_str` `PRIMARY` 4 '3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\' -X RECORD `test`.```t'\"_str` `PRIMARY` 4 '3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\' -X RECORD `test`.```t'\"_str` `PRIMARY` 5 '4', 'abc', '\0abc', 'abc\0', 'a\0bc', 'a\0bc\0', 'a\0bc\0\0' -X RECORD `test`.```t'\"_str` `PRIMARY` 5 '4', 'abc', '\0abc', 'abc\0', 'a\0bc', 'a\0bc\0', 'a\0bc\0\0' -X RECORD `test`.`t_min` `PRIMARY` 2 -128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0 -X RECORD `test`.`t_min` `PRIMARY` 2 -128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0 -X RECORD `test`.`t_max` `PRIMARY` 2 127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615 -X RECORD `test`.`t_max` `PRIMARY` 2 127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615 -X RECORD `test`.```t'\"_str` `PRIMARY` 1 supremum pseudo-record -X RECORD `test`.```t'\"_str` `PRIMARY` 1 supremum pseudo-record -lock_table COUNT(*) -`test`.`t_max` 2 -`test`.`t_min` 2 -`test`.```t'\"_str` 10 -lock_table COUNT(*) -"test"."t_max" 2 -"test"."t_min" 2 -"test"."`t'\""_str" 10 diff --git a/storage/innobase/mysql-test/innodb_information_schema.test b/storage/innobase/mysql-test/innodb_information_schema.test deleted file mode 100644 index eaed653854a..00000000000 --- a/storage/innobase/mysql-test/innodb_information_schema.test +++ /dev/null @@ -1,145 +0,0 @@ -# -# Test that user data is correctly "visualized" in -# INFORMATION_SCHEMA.innodb_locks.lock_data -# - --- source include/have_innodb.inc - --- disable_query_log --- disable_result_log - -SET storage_engine=InnoDB; - --- disable_warnings -DROP TABLE IF EXISTS t_min, t_max; --- enable_warnings - -let $table_def = -( - c01 TINYINT, - c02 TINYINT UNSIGNED, - c03 SMALLINT, - c04 SMALLINT UNSIGNED, - c05 MEDIUMINT, - c06 MEDIUMINT UNSIGNED, - c07 INT, - c08 INT UNSIGNED, - c09 BIGINT, - c10 BIGINT UNSIGNED, - PRIMARY KEY(c01, c02, c03, c04, c05, c06, c07, c08, c09, c10) -); - --- eval CREATE TABLE t_min $table_def; -INSERT INTO t_min VALUES -(-128, 0, - -32768, 0, - -8388608, 0, - -2147483648, 0, - -9223372036854775808, 0); - --- eval CREATE TABLE t_max $table_def; -INSERT INTO t_max VALUES -(127, 255, - 32767, 65535, - 8388607, 16777215, - 2147483647, 4294967295, - 9223372036854775807, 18446744073709551615); - -CREATE TABLE ```t'\"_str` ( - c1 VARCHAR(32), - c2 VARCHAR(32), - c3 VARCHAR(32), - c4 VARCHAR(32), - c5 VARCHAR(32), - c6 VARCHAR(32), - c7 VARCHAR(32), - PRIMARY KEY(c1, c2, c3, c4, c5, c6, c7) -); -INSERT INTO ```t'\"_str` VALUES -('1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc'''''); -INSERT INTO ```t'\"_str` VALUES -('2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""'); -INSERT INTO ```t'\"_str` VALUES -('3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\'); -INSERT INTO ```t'\"_str` VALUES -('4', 'abc', 0x00616263, 0x61626300, 0x61006263, 0x6100626300, 0x610062630000); - --- connect (con_lock,localhost,root,,) --- connect (con_min_trylock,localhost,root,,) --- connect (con_max_trylock,localhost,root,,) --- connect (con_str_insert_supremum,localhost,root,,) --- connect (con_str_lock_row1,localhost,root,,) --- connect (con_str_lock_row2,localhost,root,,) --- connect (con_str_lock_row3,localhost,root,,) --- connect (con_str_lock_row4,localhost,root,,) --- connect (con_verify_innodb_locks,localhost,root,,) - --- connection con_lock -SET autocommit=0; -SELECT * FROM t_min FOR UPDATE; -SELECT * FROM t_max FOR UPDATE; -SELECT * FROM ```t'\"_str` FOR UPDATE; - --- connection con_min_trylock --- send -SELECT * FROM t_min FOR UPDATE; - --- connection con_max_trylock --- send -SELECT * FROM t_max FOR UPDATE; - --- connection con_str_insert_supremum --- send -INSERT INTO ```t'\"_str` VALUES -('z', 'z', 'z', 'z', 'z', 'z', 'z'); - --- connection con_str_lock_row1 --- send -SELECT * FROM ```t'\"_str` WHERE c1 = '1' FOR UPDATE; - --- connection con_str_lock_row2 --- send -SELECT * FROM ```t'\"_str` WHERE c1 = '2' FOR UPDATE; - --- connection con_str_lock_row3 --- send -SELECT * FROM ```t'\"_str` WHERE c1 = '3' FOR UPDATE; - --- connection con_str_lock_row4 --- send -SELECT * FROM ```t'\"_str` WHERE c1 = '4' FOR UPDATE; - -# Give time to the above 2 queries to execute before continuing. -# Without this sleep it sometimes happens that the SELECT from innodb_locks -# executes before some of them, resulting in less than expected number -# of rows being selected from innodb_locks. --- sleep 0.1 - --- enable_result_log --- connection con_verify_innodb_locks -SELECT lock_mode, lock_type, lock_table, lock_index, lock_rec, lock_data -FROM INFORMATION_SCHEMA.INNODB_LOCKS ORDER BY lock_data; - -SELECT lock_table,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS -GROUP BY lock_table; - -set @save_sql_mode = @@sql_mode; -SET SQL_MODE='ANSI_QUOTES'; -SELECT lock_table,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS -GROUP BY lock_table; -SET @@sql_mode=@save_sql_mode; --- disable_result_log - --- connection default - --- disconnect con_lock --- disconnect con_min_trylock --- disconnect con_max_trylock --- disconnect con_str_insert_supremum --- disconnect con_str_lock_row1 --- disconnect con_str_lock_row2 --- disconnect con_str_lock_row3 --- disconnect con_str_lock_row4 --- disconnect con_verify_innodb_locks - -DROP TABLE t_min, t_max, ```t'\"_str`; diff --git a/storage/innobase/mysql-test/innodb_trx_weight.inc b/storage/innobase/mysql-test/innodb_trx_weight.inc deleted file mode 100644 index 56d3d47da36..00000000000 --- a/storage/innobase/mysql-test/innodb_trx_weight.inc +++ /dev/null @@ -1,51 +0,0 @@ --- connect (con1,localhost,root,,) --- connect (con2,localhost,root,,) - --- connection con1 -SET autocommit=0; -SELECT * FROM t1 FOR UPDATE; --- if ($con1_extra_sql_present) { - -- eval $con1_extra_sql --- } - --- connection con2 -SET autocommit=0; -SELECT * FROM t2 FOR UPDATE; --- if ($con2_extra_sql_present) { - -- eval $con2_extra_sql --- } - --- if ($con1_should_be_rolledback) { - -- connection con1 - -- send - INSERT INTO t2 VALUES (0); - - -- connection con2 - INSERT INTO t1 VALUES (0); - ROLLBACK; - - -- connection con1 - -- error ER_LOCK_DEADLOCK - -- reap --- } -# else --- if (!$con1_should_be_rolledback) { - -- connection con2 - -- send - INSERT INTO t1 VALUES (0); - - -- connection con1 - INSERT INTO t2 VALUES (0); - ROLLBACK; - - -- connection con2 - -- error ER_LOCK_DEADLOCK - -- reap --- } - --- connection default - -DELETE FROM t5_nontrans; - --- disconnect con1 --- disconnect con2 diff --git a/storage/innobase/mysql-test/innodb_trx_weight.result b/storage/innobase/mysql-test/innodb_trx_weight.result deleted file mode 100644 index 195775f74c8..00000000000 --- a/storage/innobase/mysql-test/innodb_trx_weight.result +++ /dev/null @@ -1 +0,0 @@ -SET storage_engine=InnoDB; diff --git a/storage/innobase/mysql-test/innodb_trx_weight.test b/storage/innobase/mysql-test/innodb_trx_weight.test deleted file mode 100644 index b72eaad345f..00000000000 --- a/storage/innobase/mysql-test/innodb_trx_weight.test +++ /dev/null @@ -1,108 +0,0 @@ -# -# Ensure that the number of locks (SELECT FOR UPDATE for example) is -# added to the number of altered rows when choosing the smallest -# transaction to kill as a victim when a deadlock is detected. -# Also transactions what had edited non-transactional tables should -# be heavier than ones that had not. -# - --- source include/have_innodb.inc - -SET storage_engine=InnoDB; - -# we do not really care about what gets printed, we are only -# interested in getting the deadlock resolved according to our -# expectations --- disable_query_log --- disable_result_log - -# we want to use "-- eval statement1; statement2" which does not work with -# prepared statements. Because this test should not behave differently with -# or without prepared statements we disable them so the test does not fail -# if someone runs ./mysql-test-run.pl --ps-protocol --- disable_ps_protocol - --- disable_warnings -DROP TABLE IF EXISTS t1, t2, t3, t4, t5_nontrans; --- enable_warnings - -# we will create a simple deadlock with t1, t2 and two connections -CREATE TABLE t1 (a INT); -CREATE TABLE t2 (a INT); - -# auxiliary table with a bulk of rows which will be locked by a -# transaction to increase its weight -CREATE TABLE t3 (a INT); - -# auxiliary empty table which will be inserted by a -# transaction to increase its weight -CREATE TABLE t4 (a INT); - -# auxiliary non-transactional table which will be edited by a -# transaction to tremendously increase its weight -CREATE TABLE t5_nontrans (a INT) ENGINE=MyISAM; - -INSERT INTO t1 VALUES (1); -INSERT INTO t2 VALUES (1); -# insert a lot of rows in t3 -INSERT INTO t3 VALUES (1); -INSERT INTO t3 SELECT * FROM t3; -INSERT INTO t3 SELECT * FROM t3; -INSERT INTO t3 SELECT * FROM t3; -INSERT INTO t3 SELECT * FROM t3; -INSERT INTO t3 SELECT * FROM t3; -INSERT INTO t3 SELECT * FROM t3; -INSERT INTO t3 SELECT * FROM t3; -INSERT INTO t3 SELECT * FROM t3; -INSERT INTO t3 SELECT * FROM t3; -INSERT INTO t3 SELECT * FROM t3; -INSERT INTO t3 SELECT * FROM t3; - -# test locking weight - --- let $con1_extra_sql = --- let $con1_extra_sql_present = 0 --- let $con2_extra_sql = SELECT * FROM t3 FOR UPDATE --- let $con2_extra_sql_present = 1 --- let $con1_should_be_rolledback = 1 --- source include/innodb_trx_weight.inc - --- let $con1_extra_sql = INSERT INTO t4 VALUES (1), (1) --- let $con1_extra_sql_present = 1 --- let $con2_extra_sql = SELECT * FROM t3 FOR UPDATE --- let $con2_extra_sql_present = 1 --- let $con1_should_be_rolledback = 1 --- source include/innodb_trx_weight.inc - --- let $con1_extra_sql = INSERT INTO t4 VALUES (1), (1), (1), (1), (1), (1) --- let $con1_extra_sql_present = 1 --- let $con2_extra_sql = SELECT * FROM t3 FOR UPDATE --- let $con2_extra_sql_present = 1 --- let $con1_should_be_rolledback = 0 --- source include/innodb_trx_weight.inc - -# test weight when non-transactional tables are edited - --- let $con1_extra_sql = INSERT INTO t4 VALUES (1), (1), (1) --- let $con1_extra_sql_present = 1 --- let $con2_extra_sql = --- let $con2_extra_sql_present = 0 --- let $con1_should_be_rolledback = 0 --- source include/innodb_trx_weight.inc - --- let $con1_extra_sql = INSERT INTO t4 VALUES (1), (1), (1) --- let $con1_extra_sql_present = 1 --- let $con2_extra_sql = INSERT INTO t5_nontrans VALUES (1) --- let $con2_extra_sql_present = 1 --- let $con1_should_be_rolledback = 1 --- source include/innodb_trx_weight.inc - --- let $con1_extra_sql = INSERT INTO t4 VALUES (1), (1), (1) --- let $con1_extra_sql = $con1_extra_sql; INSERT INTO t5_nontrans VALUES (1) --- let $con1_extra_sql_present = 1 --- let $con2_extra_sql = INSERT INTO t5_nontrans VALUES (1) --- let $con2_extra_sql_present = 1 --- let $con1_should_be_rolledback = 0 --- source include/innodb_trx_weight.inc - -DROP TABLE t1, t2, t3, t4, t5_nontrans; diff --git a/storage/innobase/mysql-test/patches/innodb-index.diff b/storage/innobase/mysql-test/patches/innodb-index.diff deleted file mode 100644 index 0b008c96f25..00000000000 --- a/storage/innobase/mysql-test/patches/innodb-index.diff +++ /dev/null @@ -1,62 +0,0 @@ -This part of the innodb-index test causes mysqld to print some warnings -and subsequently the whole mysql-test suite to fail. - -A permanent solution is probably to remove the printouts from the source -code or to somehow tell the mysql-test suite that warnings are expected. -Currently we simply do not execute the problematic tests. Please -coordinate a permanent solution with Marko, who added those tests. - -This cannot be proposed to MySQL because it touches files that are not -in the MySQL source repository. - -Index: storage/innobase/mysql-test/innodb-index.result -=================================================================== ---- storage/innobase/mysql-test/innodb-index.result (revision 2870) -+++ storage/innobase/mysql-test/innodb-index.result (working copy) -@@ -43,19 +43,12 @@ t1 CREATE TABLE `t1` ( - `b` int(11) DEFAULT NULL, - `c` char(10) NOT NULL, - `d` varchar(20) DEFAULT NULL, - KEY `d2` (`d`), - KEY `b` (`b`) - ) ENGINE=InnoDB DEFAULT CHARSET=latin1 --CREATE TABLE `t1#1`(a INT PRIMARY KEY) ENGINE=InnoDB; --alter table t1 add unique index (c), add index (d); --ERROR HY000: Table 'test.t1#1' already exists --rename table `t1#1` to `t1#2`; --alter table t1 add unique index (c), add index (d); --ERROR HY000: Table 'test.t1#2' already exists --drop table `t1#2`; - alter table t1 add unique index (c), add index (d); - show create table t1; - Table Create Table - t1 CREATE TABLE `t1` ( - `a` int(11) NOT NULL, - `b` int(11) DEFAULT NULL, -Index: storage/innobase/mysql-test/innodb-index.test -=================================================================== ---- storage/innobase/mysql-test/innodb-index.test (revision 2870) -+++ storage/innobase/mysql-test/innodb-index.test (working copy) -@@ -14,22 +14,12 @@ select * from t1 force index (d2) order - --error ER_DUP_ENTRY - alter table t1 add unique index (b); - show create table t1; - alter table t1 add index (b); - show create table t1; - --# Check how existing tables interfere with temporary tables. --CREATE TABLE `t1#1`(a INT PRIMARY KEY) ENGINE=InnoDB; -- ----error 156 --alter table t1 add unique index (c), add index (d); --rename table `t1#1` to `t1#2`; ----error 156 --alter table t1 add unique index (c), add index (d); --drop table `t1#2`; -- - alter table t1 add unique index (c), add index (d); - show create table t1; - explain select * from t1 force index(c) order by c; - alter table t1 add primary key (a), drop index c; - show create table t1; - --error ER_MULTIPLE_PRI_KEY diff --git a/storage/innobase/mysql-test/patches/innodb_change_buffering_basic.diff b/storage/innobase/mysql-test/patches/innodb_change_buffering_basic.diff new file mode 100644 index 00000000000..bfa1609a97c --- /dev/null +++ b/storage/innobase/mysql-test/patches/innodb_change_buffering_basic.diff @@ -0,0 +1,60 @@ +--- mysql-test/suite/sys_vars/t/innodb_change_buffering_basic.test.orig Mon Mar 15 16:15:22 2010 ++++ mysql-test/suite/sys_vars/t/innodb_change_buffering_basic.test Fri Mar 19 01:19:09 2010 +@@ -11,8 +11,8 @@ + # + # exists as global only + # +---echo Valid values are 'inserts' and 'none' +-select @@global.innodb_change_buffering in ('inserts', 'none'); ++--echo Valid values are 'inserts', 'deletes', 'changes', 'purges', 'all', and 'none' ++select @@global.innodb_change_buffering in ('inserts', 'deletes', 'changes', 'purges', 'all', 'none'); + select @@global.innodb_change_buffering; + --error ER_INCORRECT_GLOBAL_LOCAL_VAR + select @@session.innodb_change_buffering; + +--- mysql-test/suite/sys_vars/r/innodb_change_buffering_basic.result.orig Mon Mar 15 16:15:22 2010 ++++ mysql-test/suite/sys_vars/r/innodb_change_buffering_basic.result Fri Mar 19 01:23:58 2010 +@@ -1,28 +1,28 @@ + SET @start_global_value = @@global.innodb_change_buffering; + SELECT @start_global_value; + @start_global_value +-inserts +-Valid values are 'inserts' and 'none' +-select @@global.innodb_change_buffering in ('inserts', 'none'); +-@@global.innodb_change_buffering in ('inserts', 'none') ++all ++Valid values are 'inserts', 'deletes', 'changes', 'purges', 'all', and 'none' ++select @@global.innodb_change_buffering in ('inserts', 'deletes', 'changes', 'purges', 'all', 'none'); ++@@global.innodb_change_buffering in ('inserts', 'deletes', 'changes', 'purges', 'all', 'none') + 1 + select @@global.innodb_change_buffering; + @@global.innodb_change_buffering +-inserts ++all + select @@session.innodb_change_buffering; + ERROR HY000: Variable 'innodb_change_buffering' is a GLOBAL variable + show global variables like 'innodb_change_buffering'; + Variable_name Value +-innodb_change_buffering inserts ++innodb_change_buffering all + show session variables like 'innodb_change_buffering'; + Variable_name Value +-innodb_change_buffering inserts ++innodb_change_buffering all + select * from information_schema.global_variables where variable_name='innodb_change_buffering'; + VARIABLE_NAME VARIABLE_VALUE +-INNODB_CHANGE_BUFFERING inserts ++INNODB_CHANGE_BUFFERING all + select * from information_schema.session_variables where variable_name='innodb_change_buffering'; + VARIABLE_NAME VARIABLE_VALUE +-INNODB_CHANGE_BUFFERING inserts ++INNODB_CHANGE_BUFFERING all + set global innodb_change_buffering='none'; + select @@global.innodb_change_buffering; + @@global.innodb_change_buffering +@@ -60,4 +60,4 @@ + SET @@global.innodb_change_buffering = @start_global_value; + SELECT @@global.innodb_change_buffering; + @@global.innodb_change_buffering +-inserts ++all diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c index 37edad442db..c07f8f4bf95 100644 --- a/storage/innobase/os/os0file.c +++ b/storage/innobase/os/os0file.c @@ -1,23 +1,6 @@ -/***************************************************************************** - -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. - -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; 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, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ /*********************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2009, Percona Inc. Portions of this file contain modifications contributed and copyrighted @@ -50,6 +33,11 @@ Created 10/21/1995 Heikki Tuuri *******************************************************/ #include "os0file.h" + +#ifdef UNIV_NONINL +#include "os0file.ic" +#endif + #include "ut0mem.h" #include "srv0srv.h" #include "srv0start.h" @@ -67,6 +55,10 @@ Created 10/21/1995 Heikki Tuuri # endif /* __WIN__ */ #endif /* !UNIV_HOTBACKUP */ +#if defined(LINUX_NATIVE_AIO) +#include <libaio.h> +#endif + /* This specifies the file permissions InnoDB uses when it creates files in Unix; the value of os_innodb_umask is initialized in ha_innodb.cc to my_umask */ @@ -88,9 +80,7 @@ UNIV_INTERN ibool os_do_not_call_flush_at_each_write = FALSE; /* We do not call os_file_flush in every os_file_write. */ #endif /* UNIV_DO_FLUSH */ -#ifdef UNIV_HOTBACKUP -# define os_aio_use_native_aio FALSE -#else /* UNIV_HOTBACKUP */ +#ifndef UNIV_HOTBACKUP /* We use these mutexes to protect lseek + file i/o operation, if the OS does not provide an atomic pread or pwrite, or similar */ #define OS_FILE_N_SEEK_MUTEXES 16 @@ -99,15 +89,70 @@ UNIV_INTERN os_mutex_t os_file_seek_mutexes[OS_FILE_N_SEEK_MUTEXES]; /* In simulated aio, merge at most this many consecutive i/os */ #define OS_AIO_MERGE_N_CONSECUTIVE 64 -/** If this flag is TRUE, then we will use the native aio of the -OS (provided we compiled Innobase with it in), otherwise we will -use simulated aio we build below with threads */ - -UNIV_INTERN ibool os_aio_use_native_aio = FALSE; +/********************************************************************** + +InnoDB AIO Implementation: +========================= + +We support native AIO for windows and linux. For rest of the platforms +we simulate AIO by special io-threads servicing the IO-requests. + +Simulated AIO: +============== + +In platforms where we 'simulate' AIO following is a rough explanation +of the high level design. +There are four io-threads (for ibuf, log, read, write). +All synchronous IO requests are serviced by the calling thread using +os_file_write/os_file_read. The Asynchronous requests are queued up +in an array (there are four such arrays) by the calling thread. +Later these requests are picked up by the io-thread and are serviced +synchronously. + +Windows native AIO: +================== + +If srv_use_native_aio is not set then windows follow the same +code as simulated AIO. If the flag is set then native AIO interface +is used. On windows, one of the limitation is that if a file is opened +for AIO no synchronous IO can be done on it. Therefore we have an +extra fifth array to queue up synchronous IO requests. +There are innodb_file_io_threads helper threads. These threads work +on the four arrays mentioned above in Simulated AIO. No thread is +required for the sync array. +If a synchronous IO request is made, it is first queued in the sync +array. Then the calling thread itself waits on the request, thus +making the call synchronous. +If an AIO request is made the calling thread not only queues it in the +array but also submits the requests. The helper thread then collects +the completed IO request and calls completion routine on it. + +Linux native AIO: +================= + +If we have libaio installed on the system and innodb_use_native_aio +is set to TRUE we follow the code path of native AIO, otherwise we +do simulated AIO. +There are innodb_file_io_threads helper threads. These threads work +on the four arrays mentioned above in Simulated AIO. +If a synchronous IO request is made, it is handled by calling +os_file_write/os_file_read. +If an AIO request is made the calling thread not only queues it in the +array but also submits the requests. The helper thread then collects +the completed IO request and calls completion routine on it. + +**********************************************************************/ /** Flag: enable debug printout for asynchronous i/o */ UNIV_INTERN ibool os_aio_print_debug = FALSE; +#ifdef UNIV_PFS_IO +/* Keys to register InnoDB I/O with performance schema */ +UNIV_INTERN mysql_pfs_key_t innodb_file_data_key; +UNIV_INTERN mysql_pfs_key_t innodb_file_log_key; +UNIV_INTERN mysql_pfs_key_t innodb_file_temp_key; +#endif /* UNIV_PFS_IO */ + /** The asynchronous i/o array slot structure */ typedef struct os_aio_slot_struct os_aio_slot_t; @@ -142,6 +187,10 @@ struct os_aio_slot_struct{ OVERLAPPED struct */ OVERLAPPED control; /*!< Windows control block for the aio request */ +#elif defined(LINUX_NATIVE_AIO) + struct iocb control; /* Linux control block for aio */ + int n_bytes; /* bytes written/read. */ + int ret; /* AIO return code */ #endif }; @@ -167,6 +216,10 @@ struct os_aio_array_struct{ array of pending aio requests. A thread can wait separately for any one of the segments. */ + ulint cur_seg;/*!< We reserve IO requests in round + robin fashion to different segments. + This points to the segment that is to + be used to service next IO request. */ ulint n_reserved; /*!< Number of reserved slots in the aio array outside the ibuf segment */ @@ -180,8 +233,31 @@ struct os_aio_array_struct{ WaitForMultipleObjects; used only in Windows */ #endif + +#if defined(LINUX_NATIVE_AIO) + io_context_t* aio_ctx; + /* completion queue for IO. There is + one such queue per segment. Each thread + will work on one ctx exclusively. */ + struct io_event* aio_events; + /* The array to collect completed IOs. + There is one such event for each + possible pending IO. The size of the + array is equal to n_slots. */ +#endif }; +#if defined(LINUX_NATIVE_AIO) +/** timeout for each io_getevents() call = 500ms. */ +#define OS_AIO_REAP_TIMEOUT (500000000UL) + +/** time to sleep, in microseconds if io_setup() returns EAGAIN. */ +#define OS_AIO_IO_SETUP_RETRY_SLEEP (500000UL) + +/** number of attempts before giving up on io_setup(). */ +#define OS_AIO_IO_SETUP_RETRY_ATTEMPTS 5 +#endif + /** Array of events used in simulated aio */ static os_event_t* os_aio_segment_wait_events = NULL; @@ -200,7 +276,7 @@ static ulint os_aio_n_segments = ULINT_UNDEFINED; /** If the following is TRUE, read i/o handler threads try to wait until a batch of new read requests have been posted */ static ibool os_aio_recommend_sleep_for_read_threads = FALSE; -#endif /* UNIV_HOTBACKUP */ +#endif /* !UNIV_HOTBACKUP */ UNIV_INTERN ulint os_n_file_reads = 0; UNIV_INTERN ulint os_bytes_read_since_printout = 0; @@ -406,17 +482,29 @@ os_file_get_last_error( fflush(stderr); - if (err == ENOSPC) { + switch (err) { + case ENOSPC: return(OS_FILE_DISK_FULL); - } else if (err == ENOENT) { + case ENOENT: return(OS_FILE_NOT_FOUND); - } else if (err == EEXIST) { + case EEXIST: return(OS_FILE_ALREADY_EXISTS); - } else if (err == EXDEV || err == ENOTDIR || err == EISDIR) { + case EXDEV: + case ENOTDIR: + case EISDIR: return(OS_FILE_PATH_ERROR); - } else { - return(100 + err); + case EAGAIN: + if (srv_use_native_aio) { + return(OS_FILE_AIO_RESOURCES_RESERVED); + } + break; + case EINTR: + if (srv_use_native_aio) { + return(OS_FILE_AIO_INTERRUPTED); + } + break; } + return(100 + err); #endif } @@ -466,6 +554,9 @@ os_file_handle_error_cond_exit( } else if (err == OS_FILE_AIO_RESOURCES_RESERVED) { return(TRUE); + } else if (err == OS_FILE_AIO_INTERRUPTED) { + + return(TRUE); } else if (err == OS_FILE_ALREADY_EXISTS || err == OS_FILE_PATH_ERROR) { @@ -806,7 +897,15 @@ next_file: #ifdef HAVE_READDIR_R ret = readdir_r(dir, (struct dirent*)dirent_buf, &ent); - if (ret != 0) { + if (ret != 0 +#ifdef UNIV_AIX + /* On AIX, only if we got non-NULL 'ent' (result) value and + a non-zero 'ret' (return) value, it indicates a failed + readdir_r() call. An NULL 'ent' with an non-zero 'ret' + would indicate the "end of the directory" is reached. */ + && ent != NULL +#endif + ) { fprintf(stderr, "InnoDB: cannot read directory %s, error %lu\n", dirname, (ulong)ret); @@ -933,13 +1032,15 @@ os_file_create_directory( } /****************************************************************//** +NOTE! Use the corresponding macro os_file_create_simple(), not directly +this function! A simple function to open or create a file. @return own: handle to the file, not defined if error, error number can be retrieved with os_file_get_last_error */ UNIV_INTERN os_file_t -os_file_create_simple( -/*==================*/ +os_file_create_simple_func( +/*=======================*/ const char* name, /*!< in: name of the file or path as a null-terminated string */ ulint create_mode,/*!< in: OS_FILE_OPEN if an existing file is @@ -1074,13 +1175,15 @@ try_again: } /****************************************************************//** +NOTE! Use the corresponding macro +os_file_create_simple_no_error_handling(), not directly this function! A simple function to open or create a file. @return own: handle to the file, not defined if error, error number can be retrieved with os_file_get_last_error */ UNIV_INTERN os_file_t -os_file_create_simple_no_error_handling( -/*====================================*/ +os_file_create_simple_no_error_handling_func( +/*=========================================*/ const char* name, /*!< in: name of the file or path as a null-terminated string */ ulint create_mode,/*!< in: OS_FILE_OPEN if an existing file @@ -1229,13 +1332,15 @@ os_file_set_nocache( } /****************************************************************//** +NOTE! Use the corresponding macro os_file_create(), not directly +this function! Opens an existing file or creates a new. @return own: handle to the file, not defined if error, error number can be retrieved with os_file_get_last_error */ UNIV_INTERN os_file_t -os_file_create( -/*===========*/ +os_file_create_func( +/*================*/ const char* name, /*!< in: name of the file or path as a null-terminated string */ ulint create_mode,/*!< in: OS_FILE_OPEN if an existing file @@ -1285,7 +1390,7 @@ try_again: buffering of writes in the OS */ attributes = 0; #ifdef WIN_ASYNC_IO - if (os_aio_use_native_aio) { + if (srv_use_native_aio) { attributes = attributes | FILE_FLAG_OVERLAPPED; } #endif @@ -1620,13 +1725,14 @@ loop: } /***********************************************************************//** +NOTE! Use the corresponding macro os_file_rename(), not directly this function! Renames a file (can also move it to another directory). It is safest that the file is closed before calling this function. @return TRUE if success */ UNIV_INTERN ibool -os_file_rename( -/*===========*/ +os_file_rename_func( +/*================*/ const char* oldpath,/*!< in: old file path as a null-terminated string */ const char* newpath)/*!< in: new file path */ @@ -1659,13 +1765,14 @@ os_file_rename( } /***********************************************************************//** +NOTE! Use the corresponding macro os_file_close(), not directly this function! Closes a file handle. In case of error, error number can be retrieved with os_file_get_last_error. @return TRUE if success */ UNIV_INTERN ibool -os_file_close( -/*==========*/ +os_file_close_func( +/*===============*/ os_file_t file) /*!< in, own: handle to a file */ { #ifdef __WIN__ @@ -1961,12 +2068,13 @@ os_file_fsync( #endif /* !__WIN__ */ /***********************************************************************//** +NOTE! Use the corresponding macro os_file_flush(), not directly this function! Flushes the write buffers of a given file to the disk. @return TRUE if success */ UNIV_INTERN ibool -os_file_flush( -/*==========*/ +os_file_flush_func( +/*===============*/ os_file_t file) /*!< in, own: handle to a file */ { #ifdef __WIN__ @@ -2273,12 +2381,14 @@ func_exit: #endif /*******************************************************************//** +NOTE! Use the corresponding macro os_file_read(), not directly this +function! Requests a synchronous positioned read operation. @return TRUE if request was successful, FALSE if fail */ UNIV_INTERN ibool -os_file_read( -/*=========*/ +os_file_read_func( +/*==============*/ os_file_t file, /*!< in: handle to a file */ void* buf, /*!< in: buffer where to read */ ulint offset, /*!< in: least significant 32 bits of file @@ -2396,13 +2506,15 @@ error_handling: } /*******************************************************************//** +NOTE! Use the corresponding macro os_file_read_no_error_handling(), +not directly this function! Requests a synchronous positioned read operation. This function does not do any error handling. In case of error it returns FALSE. @return TRUE if request was successful, FALSE if fail */ UNIV_INTERN ibool -os_file_read_no_error_handling( -/*===========================*/ +os_file_read_no_error_handling_func( +/*================================*/ os_file_t file, /*!< in: handle to a file */ void* buf, /*!< in: buffer where to read */ ulint offset, /*!< in: least significant 32 bits of file @@ -2524,12 +2636,14 @@ os_file_read_string( } /*******************************************************************//** +NOTE! Use the corresponding macro os_file_write(), not directly +this function! Requests a synchronous write operation. @return TRUE if request was successful, FALSE if fail */ UNIV_INTERN ibool -os_file_write( -/*==========*/ +os_file_write_func( +/*===============*/ const char* name, /*!< in: name of the file or path as a null-terminated string */ os_file_t file, /*!< in: handle to a file */ @@ -2988,15 +3102,106 @@ os_aio_array_get_nth_slot( return((array->slots) + index); } -/************************************************************************//** -Creates an aio wait array. -@return own: aio array */ +#if defined(LINUX_NATIVE_AIO) +/******************************************************************//** +Creates an io_context for native linux AIO. +@return TRUE on success. */ +static +ibool +os_aio_linux_create_io_ctx( +/*=======================*/ + ulint max_events, /*!< in: number of events. */ + io_context_t* io_ctx) /*!< out: io_ctx to initialize. */ +{ + int ret; + ulint retries = 0; + +retry: + memset(io_ctx, 0x0, sizeof(*io_ctx)); + + /* Initialize the io_ctx. Tell it how many pending + IO requests this context will handle. */ + + ret = io_setup(max_events, io_ctx); + if (ret == 0) { +#if defined(UNIV_AIO_DEBUG) + fprintf(stderr, + "InnoDB: Linux native AIO:" + " initialized io_ctx for segment\n"); +#endif + /* Success. Return now. */ + return(TRUE); + } + + /* If we hit EAGAIN we'll make a few attempts before failing. */ + + switch (ret) { + case -EAGAIN: + if (retries == 0) { + /* First time around. */ + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Warning: io_setup() failed" + " with EAGAIN. Will make %d attempts" + " before giving up.\n", + OS_AIO_IO_SETUP_RETRY_ATTEMPTS); + } + + if (retries < OS_AIO_IO_SETUP_RETRY_ATTEMPTS) { + ++retries; + fprintf(stderr, + "InnoDB: Warning: io_setup() attempt" + " %lu failed.\n", + retries); + os_thread_sleep(OS_AIO_IO_SETUP_RETRY_SLEEP); + goto retry; + } + + /* Have tried enough. Better call it a day. */ + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Error: io_setup() failed" + " with EAGAIN after %d attempts.\n", + OS_AIO_IO_SETUP_RETRY_ATTEMPTS); + break; + + case -ENOSYS: + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Error: Linux Native AIO interface" + " is not supported on this platform. Please" + " check your OS documentation and install" + " appropriate binary of InnoDB.\n"); + + break; + + default: + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Error: Linux Native AIO setup" + " returned following error[%d]\n", -ret); + break; + } + + fprintf(stderr, + "InnoDB: You can disable Linux Native AIO by" + " setting innodb_native_aio = off in my.cnf\n"); + return(FALSE); +} +#endif /* LINUX_NATIVE_AIO */ + +/******************************************************************//** +Creates an aio wait array. Note that we return NULL in case of failure. +We don't care about freeing memory here because we assume that a +failure will result in server refusing to start up. +@return own: aio array, NULL on failure */ static os_aio_array_t* os_aio_array_create( /*================*/ - ulint n, /*!< in: maximum number of pending aio operations - allowed; n must be divisible by n_segments */ + ulint n, /*!< in: maximum number of pending aio + operations allowed; n must be + divisible by n_segments */ ulint n_segments) /*!< in: number of segments in the aio array */ { os_aio_array_t* array; @@ -3004,6 +3209,8 @@ os_aio_array_create( os_aio_slot_t* slot; #ifdef WIN_ASYNC_IO OVERLAPPED* over; +#elif defined(LINUX_NATIVE_AIO) + struct io_event* io_event = NULL; #endif ut_a(n > 0); ut_a(n_segments > 0); @@ -3019,10 +3226,44 @@ os_aio_array_create( array->n_slots = n; array->n_segments = n_segments; array->n_reserved = 0; + array->cur_seg = 0; array->slots = ut_malloc(n * sizeof(os_aio_slot_t)); #ifdef __WIN__ array->native_events = ut_malloc(n * sizeof(os_native_event_t)); #endif + +#if defined(LINUX_NATIVE_AIO) + /* If we are not using native aio interface then skip this + part of initialization. */ + if (!srv_use_native_aio) { + goto skip_native_aio; + } + + /* Initialize the io_context array. One io_context + per segment in the array. */ + + array->aio_ctx = ut_malloc(n_segments * + sizeof(*array->aio_ctx)); + for (i = 0; i < n_segments; ++i) { + if (!os_aio_linux_create_io_ctx(n/n_segments, + &array->aio_ctx[i])) { + /* If something bad happened during aio setup + we should call it a day and return right away. + We don't care about any leaks because a failure + to initialize the io subsystem means that the + server (or atleast the innodb storage engine) + is not going to startup. */ + return(NULL); + } + } + + /* Initialize the event array. One event per slot. */ + io_event = ut_malloc(n * sizeof(*io_event)); + memset(io_event, 0x0, sizeof(*io_event) * n); + array->aio_events = io_event; + +skip_native_aio: +#endif /* LINUX_NATIVE_AIO */ for (i = 0; i < n; i++) { slot = os_aio_array_get_nth_slot(array, i); @@ -3036,6 +3277,12 @@ os_aio_array_create( over->hEvent = slot->event->handle; *((array->native_events) + i) = over->hEvent; + +#elif defined(LINUX_NATIVE_AIO) + + memset(&slot->control, 0x0, sizeof(slot->control)); + slot->n_bytes = 0; + slot->ret = 0; #endif } @@ -3078,7 +3325,7 @@ respectively. The caller must create an i/o handler thread for each segment in these arrays. This function also creates the sync array. No i/o handler thread needs to be created for that */ UNIV_INTERN -void +ibool os_aio_init( /*========*/ ulint n_per_seg, /*<! in: maximum number of pending aio @@ -3103,15 +3350,25 @@ os_aio_init( /* fprintf(stderr, "Array n per seg %lu\n", n_per_seg); */ os_aio_ibuf_array = os_aio_array_create(n_per_seg, 1); + if (os_aio_ibuf_array == NULL) { + goto err_exit; + } srv_io_thread_function[0] = "insert buffer thread"; os_aio_log_array = os_aio_array_create(n_per_seg, 1); + if (os_aio_log_array == NULL) { + goto err_exit; + } srv_io_thread_function[1] = "log thread"; os_aio_read_array = os_aio_array_create(n_read_segs * n_per_seg, n_read_segs); + if (os_aio_read_array == NULL) { + goto err_exit; + } + for (i = 2; i < 2 + n_read_segs; i++) { ut_a(i < SRV_MAX_N_IO_THREADS); srv_io_thread_function[i] = "read thread"; @@ -3119,12 +3376,20 @@ os_aio_init( os_aio_write_array = os_aio_array_create(n_write_segs * n_per_seg, n_write_segs); + if (os_aio_write_array == NULL) { + goto err_exit; + } + for (i = 2 + n_read_segs; i < n_segments; i++) { ut_a(i < SRV_MAX_N_IO_THREADS); srv_io_thread_function[i] = "write thread"; } os_aio_sync_array = os_aio_array_create(n_slots_sync, 1); + if (os_aio_sync_array == NULL) { + goto err_exit; + } + os_aio_n_segments = n_segments; @@ -3138,6 +3403,11 @@ os_aio_init( os_last_printout = time(NULL); + return(TRUE); + +err_exit: + return(FALSE); + } /*********************************************************************** @@ -3204,6 +3474,19 @@ os_aio_wake_all_threads_at_shutdown(void) os_aio_array_wake_win_aio_at_shutdown(os_aio_write_array); os_aio_array_wake_win_aio_at_shutdown(os_aio_ibuf_array); os_aio_array_wake_win_aio_at_shutdown(os_aio_log_array); + +#elif defined(LINUX_NATIVE_AIO) + + /* When using native AIO interface the io helper threads + wait on io_getevents with a timeout value of 500ms. At + each wake up these threads check the server status. + No need to do anything to wake them up. */ + + if (srv_use_native_aio) { + return; + } + /* Fall through to simulated AIO handler wakeup if we are + not using native AIO. */ #endif /* This loop wakes up all simulated ai/o threads */ @@ -3321,11 +3604,18 @@ os_aio_array_reserve_slot( offset */ ulint len) /*!< in: length of the block to read or write */ { - os_aio_slot_t* slot; + os_aio_slot_t* slot = NULL; #ifdef WIN_ASYNC_IO OVERLAPPED* control; + +#elif defined(LINUX_NATIVE_AIO) + + struct iocb* iocb; + off_t aio_offset; + #endif ulint i; + ulint counter; ulint slots_per_seg; ulint local_seg; @@ -3344,7 +3634,7 @@ loop: if (array->n_reserved == array->n_slots) { os_mutex_exit(array->mutex); - if (!os_aio_use_native_aio) { + if (!srv_use_native_aio) { /* If the handler threads are suspended, wake them so that we get more slots */ @@ -3356,17 +3646,13 @@ loop: goto loop; } - /* First try to find a slot in the preferred local segment */ - for (i = local_seg * slots_per_seg; i < array->n_slots; i++) { - slot = os_aio_array_get_nth_slot(array, i); + /* We start our search for an available slot from our preferred + local segment and do a full scan of the array. We are + guaranteed to find a slot in full scan. */ + for (i = local_seg * slots_per_seg, counter = 0; + counter < array->n_slots; i++, counter++) { - if (slot->reserved == FALSE) { - goto found; - } - } - - /* Fall back to a full scan. We are guaranteed to find a slot */ - for (i = 0;; i++) { + i %= array->n_slots; slot = os_aio_array_get_nth_slot(array, i); if (slot->reserved == FALSE) { @@ -3374,6 +3660,9 @@ loop: } } + /* We MUST always be able to get hold of a reserved slot. */ + ut_error; + found: ut_a(slot->reserved == FALSE); array->n_reserved++; @@ -3404,8 +3693,42 @@ found: control->Offset = (DWORD)offset; control->OffsetHigh = (DWORD)offset_high; os_event_reset(slot->event); -#endif +#elif defined(LINUX_NATIVE_AIO) + + /* If we are not using native AIO skip this part. */ + if (!srv_use_native_aio) { + goto skip_native_aio; + } + + /* Check if we are dealing with 64 bit arch. + If not then make sure that offset fits in 32 bits. */ + if (sizeof(aio_offset) == 8) { + aio_offset = offset_high; + aio_offset <<= 32; + aio_offset += offset; + } else { + ut_a(offset_high == 0); + aio_offset = offset; + } + + iocb = &slot->control; + + if (type == OS_FILE_READ) { + io_prep_pread(iocb, file, buf, len, aio_offset); + } else { + ut_a(type == OS_FILE_WRITE); + io_prep_pwrite(iocb, file, buf, len, aio_offset); + } + + iocb->data = (void*)slot; + slot->n_bytes = 0; + slot->ret = 0; + /*fprintf(stderr, "Filled up Linux native iocb.\n");*/ + + +skip_native_aio: +#endif /* LINUX_NATIVE_AIO */ os_mutex_exit(array->mutex); return(slot); @@ -3440,7 +3763,23 @@ os_aio_array_free_slot( } #ifdef WIN_ASYNC_IO + os_event_reset(slot->event); + +#elif defined(LINUX_NATIVE_AIO) + + if (srv_use_native_aio) { + memset(&slot->control, 0x0, sizeof(slot->control)); + slot->n_bytes = 0; + slot->ret = 0; + /*fprintf(stderr, "Freed up Linux native slot.\n");*/ + } else { + /* These fields should not be used if we are not + using native AIO. */ + ut_ad(slot->n_bytes == 0); + ut_ad(slot->ret == 0); + } + #endif os_mutex_exit(array->mutex); } @@ -3460,7 +3799,7 @@ os_aio_simulated_wake_handler_thread( ulint n; ulint i; - ut_ad(!os_aio_use_native_aio); + ut_ad(!srv_use_native_aio); segment = os_aio_get_array_and_local_segment(&array, global_segment); @@ -3496,7 +3835,7 @@ os_aio_simulated_wake_handler_threads(void) { ulint i; - if (os_aio_use_native_aio) { + if (srv_use_native_aio) { /* We do not use simulated aio: do nothing */ return; @@ -3528,7 +3867,7 @@ readahead requests. */ os_aio_array_t* array; ulint g; - if (os_aio_use_native_aio) { + if (srv_use_native_aio) { /* We do not use simulated aio: do nothing */ return; @@ -3547,13 +3886,62 @@ readahead requests. */ #endif /* __WIN__ */ } +#if defined(LINUX_NATIVE_AIO) +/*******************************************************************//** +Dispatch an AIO request to the kernel. +@return TRUE on success. */ +static +ibool +os_aio_linux_dispatch( +/*==================*/ + os_aio_array_t* array, /*!< in: io request array. */ + os_aio_slot_t* slot) /*!< in: an already reserved slot. */ +{ + int ret; + ulint io_ctx_index; + struct iocb* iocb; + + ut_ad(slot != NULL); + ut_ad(array); + + ut_a(slot->reserved); + + /* Find out what we are going to work with. + The iocb struct is directly in the slot. + The io_context is one per segment. */ + + iocb = &slot->control; + io_ctx_index = (slot->pos * array->n_segments) / array->n_slots; + + ret = io_submit(array->aio_ctx[io_ctx_index], 1, &iocb); + +#if defined(UNIV_AIO_DEBUG) + fprintf(stderr, + "io_submit[%c] ret[%d]: slot[%p] ctx[%p] seg[%lu]\n", + (slot->type == OS_FILE_WRITE) ? 'w' : 'r', ret, slot, + array->aio_ctx[io_ctx_index], (ulong)io_ctx_index); +#endif + + /* io_submit returns number of successfully + queued requests or -errno. */ + if (UNIV_UNLIKELY(ret != 1)) { + errno = -ret; + return(FALSE); + } + + return(TRUE); +} +#endif /* LINUX_NATIVE_AIO */ + + /*******************************************************************//** +NOTE! Use the corresponding macro os_aio(), not directly this function! Requests an asynchronous i/o operation. @return TRUE if request was queued successfully, FALSE if fail */ UNIV_INTERN ibool -os_aio( -/*===*/ +os_aio_func( +/*========*/ ulint type, /*!< in: OS_FILE_READ or OS_FILE_WRITE */ ulint mode, /*!< in: OS_AIO_NORMAL, ..., possibly ORed to OS_AIO_SIMULATED_WAKE_LATER: the @@ -3596,8 +3984,7 @@ os_aio( struct fil_node_struct * dummy_mess1; void* dummy_mess2; ulint dummy_type; -#endif - ulint err = 0; +#endif /* WIN_ASYNC_IO */ ibool retry; ulint wake_later; @@ -3613,8 +4000,8 @@ os_aio( if (mode == OS_AIO_SYNC #ifdef WIN_ASYNC_IO - && !os_aio_use_native_aio -#endif + && !srv_use_native_aio +#endif /* WIN_ASYNC_IO */ ) { /* This is actually an ordinary synchronous read or write: no need to use an i/o-handler thread. NOTE that if we use @@ -3653,6 +4040,11 @@ try_again: array = os_aio_log_array; } else if (mode == OS_AIO_SYNC) { array = os_aio_sync_array; + +#if defined(LINUX_NATIVE_AIO) + /* In Linux native AIO we don't use sync IO array. */ + ut_a(!srv_use_native_aio); +#endif /* LINUX_NATIVE_AIO */ } else { array = NULL; /* Eliminate compiler warning */ ut_error; @@ -3661,13 +4053,17 @@ try_again: slot = os_aio_array_reserve_slot(type, array, message1, message2, file, name, buf, offset, offset_high, n); if (type == OS_FILE_READ) { - if (os_aio_use_native_aio) { -#ifdef WIN_ASYNC_IO + if (srv_use_native_aio) { os_n_file_reads++; - os_bytes_read_since_printout += len; - + os_bytes_read_since_printout += n; +#ifdef WIN_ASYNC_IO ret = ReadFile(file, buf, (DWORD)n, &len, &(slot->control)); + +#elif defined(LINUX_NATIVE_AIO) + if (!os_aio_linux_dispatch(array, slot)) { + goto err_exit; + } #endif } else { if (!wake_later) { @@ -3677,11 +4073,16 @@ try_again: } } } else if (type == OS_FILE_WRITE) { - if (os_aio_use_native_aio) { -#ifdef WIN_ASYNC_IO + if (srv_use_native_aio) { os_n_file_writes++; +#ifdef WIN_ASYNC_IO ret = WriteFile(file, buf, (DWORD)n, &len, &(slot->control)); + +#elif defined(LINUX_NATIVE_AIO) + if (!os_aio_linux_dispatch(array, slot)) { + goto err_exit; + } #endif } else { if (!wake_later) { @@ -3695,7 +4096,7 @@ try_again: } #ifdef WIN_ASYNC_IO - if (os_aio_use_native_aio) { + if (srv_use_native_aio) { if ((ret && len == n) || (!ret && GetLastError() == ERROR_IO_PENDING)) { /* aio was queued successfully! */ @@ -3718,15 +4119,15 @@ try_again: return(TRUE); } - err = 1; /* Fall through the next if */ - } -#endif - if (err == 0) { - /* aio was queued successfully! */ - - return(TRUE); + goto err_exit; } +#endif /* WIN_ASYNC_IO */ + /* aio was queued successfully! */ + return(TRUE); +#if defined LINUX_NATIVE_AIO || defined WIN_ASYNC_IO +err_exit: +#endif /* LINUX_NATIVE_AIO || WIN_ASYNC_IO */ os_aio_array_free_slot(array, slot); retry = os_file_handle_error(name, @@ -3830,7 +4231,9 @@ os_aio_windows_handle( #ifdef UNIV_DO_FLUSH if (slot->type == OS_FILE_WRITE && !os_do_not_call_flush_at_each_write) { - ut_a(TRUE == os_file_flush(slot->file)); + if (!os_file_flush(slot->file)) { + ut_error; + } } #endif /* UNIV_DO_FLUSH */ } else if (os_file_handle_error(slot->name, "Windows aio")) { @@ -3847,6 +4250,18 @@ os_aio_windows_handle( /* retry failed read/write operation synchronously. No need to hold array->mutex. */ +#ifdef UNIV_PFS_IO + /* This read/write does not go through os_file_read + and os_file_write APIs, need to register with + performance schema explicitly here. */ + struct PSI_file_locker* locker = NULL; + register_pfs_file_io_begin(locker, slot->file, slot->len, + (slot->type == OS_FILE_WRITE) + ? PSI_FILE_WRITE + : PSI_FILE_READ, + __FILE__, __LINE__); +#endif + switch (slot->type) { case OS_FILE_WRITE: ret = WriteFile(slot->file, slot->buf, @@ -3864,6 +4279,10 @@ os_aio_windows_handle( ut_error; } +#ifdef UNIV_PFS_IO + register_pfs_file_io_end(locker, len); +#endif + if (!ret && GetLastError() == ERROR_IO_PENDING) { /* aio was queued successfully! We want a synchronous i/o operation on a @@ -3885,6 +4304,256 @@ os_aio_windows_handle( } #endif +#if defined(LINUX_NATIVE_AIO) +/******************************************************************//** +This function is only used in Linux native asynchronous i/o. This is +called from within the io-thread. If there are no completed IO requests +in the slot array, the thread calls this function to collect more +requests from the kernel. +The io-thread waits on io_getevents(), which is a blocking call, with +a timeout value. Unless the system is very heavy loaded, keeping the +io-thread very busy, the io-thread will spend most of its time waiting +in this function. +The io-thread also exits in this function. It checks server status at +each wakeup and that is why we use timed wait in io_getevents(). */ +static +void +os_aio_linux_collect( +/*=================*/ + os_aio_array_t* array, /*!< in/out: slot array. */ + ulint segment, /*!< in: local segment no. */ + ulint seg_size) /*!< in: segment size. */ +{ + int i; + int ret; + ulint start_pos; + ulint end_pos; + struct timespec timeout; + struct io_event* events; + struct io_context* io_ctx; + + /* sanity checks. */ + ut_ad(array != NULL); + ut_ad(seg_size > 0); + ut_ad(segment < array->n_segments); + + /* Which part of event array we are going to work on. */ + events = &array->aio_events[segment * seg_size]; + + /* Which io_context we are going to use. */ + io_ctx = array->aio_ctx[segment]; + + /* Starting point of the segment we will be working on. */ + start_pos = segment * seg_size; + + /* End point. */ + end_pos = start_pos + seg_size; + +retry: + + /* Go down if we are in shutdown mode. + In case of srv_fast_shutdown == 2, there may be pending + IO requests but that should be OK as we essentially treat + that as a crash of InnoDB. */ + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + os_thread_exit(NULL); + } + + /* Initialize the events. The timeout value is arbitrary. + We probably need to experiment with it a little. */ + memset(events, 0, sizeof(*events) * seg_size); + timeout.tv_sec = 0; + timeout.tv_nsec = OS_AIO_REAP_TIMEOUT; + + ret = io_getevents(io_ctx, 1, seg_size, events, &timeout); + + /* This error handling is for any error in collecting the + IO requests. The errors, if any, for any particular IO + request are simply passed on to the calling routine. */ + + /* Not enough resources! Try again. */ + if (ret == -EAGAIN) { + goto retry; + } + + /* Interrupted! I have tested the behaviour in case of an + interrupt. If we have some completed IOs available then + the return code will be the number of IOs. We get EINTR only + if there are no completed IOs and we have been interrupted. */ + if (ret == -EINTR) { + goto retry; + } + + /* No pending request! Go back and check again. */ + if (ret == 0) { + goto retry; + } + + /* All other errors! should cause a trap for now. */ + if (UNIV_UNLIKELY(ret < 0)) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: unexpected ret_code[%d] from" + " io_getevents()!\n", ret); + ut_error; + } + + ut_a(ret > 0); + + for (i = 0; i < ret; i++) { + os_aio_slot_t* slot; + struct iocb* control; + + control = (struct iocb *)events[i].obj; + ut_a(control != NULL); + + slot = (os_aio_slot_t *) control->data; + + /* Some sanity checks. */ + ut_a(slot != NULL); + ut_a(slot->reserved); + +#if defined(UNIV_AIO_DEBUG) + fprintf(stderr, + "io_getevents[%c]: slot[%p] ctx[%p]" + " seg[%lu]\n", + (slot->type == OS_FILE_WRITE) ? 'w' : 'r', + slot, io_ctx, segment); +#endif + + /* We are not scribbling previous segment. */ + ut_a(slot->pos >= start_pos); + + /* We have not overstepped to next segment. */ + ut_a(slot->pos < end_pos); + + /* Mark this request as completed. The error handling + will be done in the calling function. */ + os_mutex_enter(array->mutex); + slot->n_bytes = events[i].res; + slot->ret = events[i].res2; + slot->io_already_done = TRUE; + os_mutex_exit(array->mutex); + } + + return; +} + +/**********************************************************************//** +This function is only used in Linux native asynchronous i/o. +Waits for an aio operation to complete. This function is used to wait for +the completed requests. The aio array of pending requests is divided +into segments. The thread specifies which segment or slot it wants to wait +for. NOTE: this function will also take care of freeing the aio slot, +therefore no other thread is allowed to do the freeing! +@return TRUE if the IO was successful */ +UNIV_INTERN +ibool +os_aio_linux_handle( +/*================*/ + ulint global_seg, /*!< in: segment number in the aio array + to wait for; segment 0 is the ibuf + i/o thread, segment 1 is log i/o thread, + then follow the non-ibuf read threads, + and the last are the non-ibuf write + threads. */ + fil_node_t**message1, /*!< out: the messages passed with the */ + void** message2, /*!< aio request; note that in case the + aio operation failed, these output + parameters are valid and can be used to + restart the operation. */ + ulint* type) /*!< out: OS_FILE_WRITE or ..._READ */ +{ + ulint segment; + os_aio_array_t* array; + os_aio_slot_t* slot; + ulint n; + ulint i; + ibool ret = FALSE; + + /* Should never be doing Sync IO here. */ + ut_a(global_seg != ULINT_UNDEFINED); + + /* Find the array and the local segment. */ + segment = os_aio_get_array_and_local_segment(&array, global_seg); + n = array->n_slots / array->n_segments; + + /* Loop until we have found a completed request. */ + for (;;) { + os_mutex_enter(array->mutex); + for (i = 0; i < n; ++i) { + slot = os_aio_array_get_nth_slot( + array, i + segment * n); + if (slot->reserved && slot->io_already_done) { + /* Something for us to work on. */ + goto found; + } + } + + os_mutex_exit(array->mutex); + + /* We don't have any completed request. + Wait for some request. Note that we return + from wait iff we have found a request. */ + + srv_set_io_thread_op_info(global_seg, + "waiting for completed aio requests"); + os_aio_linux_collect(array, segment, n); + } + +found: + /* Note that it may be that there are more then one completed + IO requests. We process them one at a time. We may have a case + here to improve the performance slightly by dealing with all + requests in one sweep. */ + srv_set_io_thread_op_info(global_seg, + "processing completed aio requests"); + + /* Ensure that we are scribbling only our segment. */ + ut_a(i < n); + + ut_ad(slot != NULL); + ut_ad(slot->reserved); + ut_ad(slot->io_already_done); + + *message1 = slot->message1; + *message2 = slot->message2; + + *type = slot->type; + + if ((slot->ret == 0) && (slot->n_bytes == (long)slot->len)) { + ret = TRUE; + +#ifdef UNIV_DO_FLUSH + if (slot->type == OS_FILE_WRITE + && !os_do_not_call_flush_at_each_write) + && !os_file_flush(slot->file) { + ut_error; + } +#endif /* UNIV_DO_FLUSH */ + } else { + errno = -slot->ret; + + /* os_file_handle_error does tell us if we should retry + this IO. As it stands now, we don't do this retry when + reaping requests from a different context than + the dispatcher. This non-retry logic is the same for + windows and linux native AIO. + We should probably look into this to transparently + re-submit the IO. */ + os_file_handle_error(slot->name, "Linux aio"); + + ret = FALSE; + } + + os_mutex_exit(array->mutex); + + os_aio_array_free_slot(array, slot); + + return(ret); +} +#endif /* LINUX_NATIVE_AIO */ + /**********************************************************************//** Does simulated aio. This function should be called by an i/o-handler thread. @@ -3923,6 +4592,9 @@ os_aio_simulated_handle( ulint n; ulint i; + /* Fix compiler warning */ + *consecutive_ios = NULL; + segment = os_aio_get_array_and_local_segment(&array, global_segment); restart: @@ -4034,6 +4706,11 @@ restart: goto wait_for_io; } + /* if n_consecutive != 0, then we have assigned + something valid to consecutive_ios[0] */ + ut_ad(n_consecutive != 0); + ut_ad(consecutive_ios[0] != NULL); + slot = consecutive_ios[0]; /* Check if there are several consecutive blocks to read or write */ @@ -4260,6 +4937,40 @@ os_aio_validate(void) } /**********************************************************************//** +Prints pending IO requests per segment of an aio array. +We probably don't need per segment statistics but they can help us +during development phase to see if the IO requests are being +distributed as expected. */ +static +void +os_aio_print_segment_info( +/*======================*/ + FILE* file, /*!< in: file where to print */ + ulint* n_seg, /*!< in: pending IO array */ + os_aio_array_t* array) /*!< in: array to process */ +{ + ulint i; + + ut_ad(array); + ut_ad(n_seg); + ut_ad(array->n_segments > 0); + + if (array->n_segments == 1) { + return; + } + + fprintf(file, " ["); + for (i = 0; i < array->n_segments; i++) { + if (i != 0) { + fprintf(file, ", "); + } + + fprintf(file, "%lu", n_seg[i]); + } + fprintf(file, "] "); +} + +/**********************************************************************//** Prints info of the aio arrays. */ UNIV_INTERN void @@ -4270,6 +4981,7 @@ os_aio_print( os_aio_array_t* array; os_aio_slot_t* slot; ulint n_reserved; + ulint n_res_seg[SRV_MAX_N_IO_THREADS]; time_t current_time; double time_elapsed; double avg_bytes_read; @@ -4302,11 +5014,17 @@ loop: n_reserved = 0; + memset(n_res_seg, 0x0, sizeof(n_res_seg)); + for (i = 0; i < array->n_slots; i++) { + ulint seg_no; + slot = os_aio_array_get_nth_slot(array, i); + seg_no = (i * array->n_segments) / array->n_slots; if (slot->reserved) { n_reserved++; + n_res_seg[seg_no]++; #if 0 fprintf(stderr, "Reserved slot, messages %p %p\n", (void*) slot->message1, @@ -4320,6 +5038,8 @@ loop: fprintf(file, " %lu", (ulong) n_reserved); + os_aio_print_segment_info(file, n_res_seg, array); + os_mutex_exit(array->mutex); if (array == os_aio_read_array) { diff --git a/storage/innobase/os/os0thread.c b/storage/innobase/os/os0thread.c index ac733373646..78df66d7834 100644 --- a/storage/innobase/os/os0thread.c +++ b/storage/innobase/os/os0thread.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. 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 @@ -212,6 +212,11 @@ os_thread_exit( fprintf(stderr, "Thread exits, id %lu\n", os_thread_pf(os_thread_get_curr_id())); #endif + +#ifdef UNIV_PFS_THREAD + pfs_delete_thread(); +#endif + os_mutex_enter(os_sync_mutex); os_thread_count--; os_mutex_exit(os_sync_mutex); diff --git a/storage/innobase/page/page0page.c b/storage/innobase/page/page0page.c index ab2ba60570e..10008f9ac25 100644 --- a/storage/innobase/page/page0page.c +++ b/storage/innobase/page/page0page.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. 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 @@ -658,6 +658,14 @@ page_copy_rec_list_end( index, mtr); } + /* Update PAGE_MAX_TRX_ID on the uncompressed page. + Modifications will be redo logged and copied to the compressed + page in page_zip_compress() or page_zip_reorganize() below. */ + if (dict_index_is_sec_or_ibuf(index) && page_is_leaf(page)) { + page_update_max_trx_id(new_block, NULL, + page_get_max_trx_id(page), mtr); + } + if (UNIV_LIKELY_NULL(new_page_zip)) { mtr_set_log_mode(mtr, log_mode); @@ -696,15 +704,10 @@ page_copy_rec_list_end( } } - /* Update the lock table, MAX_TRX_ID, and possible hash index */ + /* Update the lock table and possible hash index */ lock_move_rec_list_end(new_block, block, rec); - if (dict_index_is_sec_or_ibuf(index) && page_is_leaf(page)) { - page_update_max_trx_id(new_block, new_page_zip, - page_get_max_trx_id(page), mtr); - } - btr_search_move_or_delete_hash_entries(new_block, block, index); return(ret); @@ -772,6 +775,16 @@ page_copy_rec_list_start( mem_heap_free(heap); } + /* Update PAGE_MAX_TRX_ID on the uncompressed page. + Modifications will be redo logged and copied to the compressed + page in page_zip_compress() or page_zip_reorganize() below. */ + if (dict_index_is_sec_or_ibuf(index) + && page_is_leaf(page_align(rec))) { + page_update_max_trx_id(new_block, NULL, + page_get_max_trx_id(page_align(rec)), + mtr); + } + if (UNIV_LIKELY_NULL(new_page_zip)) { mtr_set_log_mode(mtr, log_mode); @@ -809,14 +822,7 @@ page_copy_rec_list_start( } } - /* Update MAX_TRX_ID, the lock table, and possible hash index */ - - if (dict_index_is_sec_or_ibuf(index) - && page_is_leaf(page_align(rec))) { - page_update_max_trx_id(new_block, new_page_zip, - page_get_max_trx_id(page_align(rec)), - mtr); - } + /* Update the lock table and possible hash index */ lock_move_rec_list_start(new_block, block, rec, ret); @@ -2408,8 +2414,13 @@ page_validate( } offs = page_offset(rec_get_start(rec, offsets)); + i = rec_offs_size(offsets); + if (UNIV_UNLIKELY(offs + i >= UNIV_PAGE_SIZE)) { + fputs("InnoDB: record offset out of bounds\n", stderr); + goto func_exit; + } - for (i = rec_offs_size(offsets); i--; ) { + while (i--) { if (UNIV_UNLIKELY(buf[offs + i])) { /* No other record may overlap this */ @@ -2517,8 +2528,13 @@ n_owned_zero: count++; offs = page_offset(rec_get_start(rec, offsets)); + i = rec_offs_size(offsets); + if (UNIV_UNLIKELY(offs + i >= UNIV_PAGE_SIZE)) { + fputs("InnoDB: record offset out of bounds\n", stderr); + goto func_exit; + } - for (i = rec_offs_size(offsets); i--; ) { + while (i--) { if (UNIV_UNLIKELY(buf[offs + i])) { fputs("InnoDB: Record overlaps another" diff --git a/storage/innobase/page/page0zip.c b/storage/innobase/page/page0zip.c index aa5e39ff04a..14ec3e7a94f 100644 --- a/storage/innobase/page/page0zip.c +++ b/storage/innobase/page/page0zip.c @@ -571,7 +571,7 @@ page_zip_dir_encode( /* Traverse the list of stored records in the collation order, starting from the first user record. */ - rec = page + PAGE_NEW_INFIMUM, TRUE; + rec = page + PAGE_NEW_INFIMUM; i = 0; @@ -3117,8 +3117,13 @@ page_zip_validate_low( temp_page_zip in a debugger when running valgrind --db-attach. */ VALGRIND_GET_VBITS(page, temp_page, UNIV_PAGE_SIZE); UNIV_MEM_ASSERT_RW(page, UNIV_PAGE_SIZE); +# if UNIV_WORD_SIZE == 4 VALGRIND_GET_VBITS(page_zip, &temp_page_zip, sizeof temp_page_zip); + /* On 32-bit systems, there is no padding in page_zip_des_t. + On other systems, Valgrind could complain about uninitialized + pad bytes. */ UNIV_MEM_ASSERT_RW(page_zip, sizeof *page_zip); +# endif VALGRIND_GET_VBITS(page_zip->data, temp_page, page_zip_get_size(page_zip)); UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip)); @@ -4416,6 +4421,7 @@ page_zip_reorganize( dict_index_t* index, /*!< in: index of the B-tree node */ mtr_t* mtr) /*!< in: mini-transaction */ { + buf_pool_t* buf_pool = buf_pool_from_block(block); page_zip_des_t* page_zip = buf_block_get_page_zip(block); page_t* page = buf_block_get_frame(block); buf_block_t* temp_block; @@ -4433,7 +4439,7 @@ page_zip_reorganize( log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE); #ifndef UNIV_HOTBACKUP - temp_block = buf_block_alloc(0); + temp_block = buf_block_alloc(buf_pool, 0); btr_search_drop_page_hash_index(block); block->check_index_page_at_flush = TRUE; #else /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/pars/pars0pars.c b/storage/innobase/pars/pars0pars.c index 9faf36d00a8..613e7962f0e 100644 --- a/storage/innobase/pars/pars0pars.c +++ b/storage/innobase/pars/pars0pars.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -2031,6 +2031,29 @@ pars_info_add_int4_literal( Equivalent to: char buf[8]; +mach_write_ull(buf, val); +pars_info_add_literal(info, name, buf, 8, DATA_INT, 0); + +except that the buffer is dynamically allocated from the info struct's +heap. */ +UNIV_INTERN +void +pars_info_add_uint64_literal( +/*=========================*/ + pars_info_t* info, /*!< in: info struct */ + const char* name, /*!< in: name */ + ib_uint64_t val) /*!< in: value */ +{ + byte* buf = mem_heap_alloc(info->heap, 8); + + mach_write_ull(buf, val); + pars_info_add_literal(info, name, buf, 8, DATA_INT, 0); +} + +/****************************************************************//** +Equivalent to: + +char buf[8]; mach_write_to_8(buf, val); pars_info_add_literal(info, name, buf, 8, DATA_FIXBINARY, 0); diff --git a/storage/innobase/plug.in b/storage/innobase/plug.in index 09a95ecc157..4ca1b520526 100644 --- a/storage/innobase/plug.in +++ b/storage/innobase/plug.in @@ -1,5 +1,5 @@ # -# Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved. +# Copyright (c) 2006, 2010, Innobase Oy. All Rights Reserved. # # 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 @@ -14,7 +14,7 @@ # Place, Suite 330, Boston, MA 02111-1307 USA # -MYSQL_STORAGE_ENGINE(innobase, innodb, [InnoDB Storage Engine], +MYSQL_STORAGE_ENGINE(innobase, innodb, [InnoDB Storage Engine], [Transactional Tables using InnoDB], [max,max-no-ndb]) MYSQL_PLUGIN_DIRECTORY(innobase, [storage/innobase]) MYSQL_PLUGIN_STATIC(innobase, [libinnobase.a]) @@ -28,6 +28,14 @@ MYSQL_PLUGIN_ACTIONS(innobase, [ AC_C_BIGENDIAN case "$target_os" in lin*) + AC_CHECK_HEADER(libaio.h, + AC_CHECK_LIB(aio, io_setup, + LIBS="$LIBS -laio" + AC_DEFINE(LINUX_NATIVE_AIO, [1], + [Linux native async I/O support]), + AC_MSG_WARN([No Linux native async I/O])), + AC_MSG_WARN([No Linux native async I/O])) + CFLAGS="$CFLAGS -DUNIV_LINUX";; hpux10*) CFLAGS="$CFLAGS -DUNIV_MUST_NOT_INLINE -DUNIV_HPUX -DUNIV_HPUX10";; diff --git a/storage/innobase/que/que0que.c b/storage/innobase/que/que0que.c index 2fe046fa9b8..3dcb9e89565 100644 --- a/storage/innobase/que/que0que.c +++ b/storage/innobase/que/que0que.c @@ -29,7 +29,6 @@ Created 5/27/1996 Heikki Tuuri #include "que0que.ic" #endif -#include "srv0que.h" #include "usr0sess.h" #include "trx0trx.h" #include "trx0roll.h" diff --git a/storage/innobase/rem/rem0cmp.c b/storage/innobase/rem/rem0cmp.c index e6dab0bc66b..35b67992558 100644 --- a/storage/innobase/rem/rem0cmp.c +++ b/storage/innobase/rem/rem0cmp.c @@ -706,7 +706,9 @@ cmp_rec_rec_simple( const rec_t* rec2, /*!< in: physical record */ const ulint* offsets1,/*!< in: rec_get_offsets(rec1, ...) */ const ulint* offsets2,/*!< in: rec_get_offsets(rec2, ...) */ - const dict_index_t* index) /*!< in: data dictionary index */ + const dict_index_t* index, /*!< in: data dictionary index */ + ibool* null_eq)/*!< out: set to TRUE if + found matching null values */ { ulint rec1_f_len; /*!< length of current field in rec1 */ const byte* rec1_b_ptr; /*!< pointer to the current byte @@ -753,6 +755,9 @@ cmp_rec_rec_simple( || rec2_f_len == UNIV_SQL_NULL) { if (rec1_f_len == rec2_f_len) { + if (null_eq) { + *null_eq = TRUE; + } goto next_field; diff --git a/storage/innobase/rem/rem0rec.c b/storage/innobase/rem/rem0rec.c index 1c8b3fd8c1e..37ba8ca2ffe 100644 --- a/storage/innobase/rem/rem0rec.c +++ b/storage/innobase/rem/rem0rec.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. 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 @@ -212,6 +212,13 @@ rec_get_n_extern_new( const dict_col_t* col = dict_field_get_col(field); len = *lens--; + /* If the maximum length of the field is up + to 255 bytes, the actual length is always + stored in one byte. If the maximum length is + more than 255 bytes, the actual length is + stored in one byte for 0..127. The length + will be encoded in two bytes when it is 128 or + more, or when the field is stored externally. */ if (UNIV_UNLIKELY(col->len > 255) || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) { if (len & 0x80) { @@ -294,6 +301,13 @@ rec_init_offsets_comp_ordinary( const dict_col_t* col = dict_field_get_col(field); len = *lens--; + /* If the maximum length of the field is up + to 255 bytes, the actual length is always + stored in one byte. If the maximum length is + more than 255 bytes, the actual length is + stored in one byte for 0..127. The length + will be encoded in two bytes when it is 128 or + more, or when the field is stored externally. */ if (UNIV_UNLIKELY(col->len > 255) || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) { @@ -425,6 +439,15 @@ rec_init_offsets( const dict_col_t* col = dict_field_get_col(field); len = *lens--; + /* If the maximum length of the field + is up to 255 bytes, the actual length + is always stored in one byte. If the + maximum length is more than 255 bytes, + the actual length is stored in one + byte for 0..127. The length will be + encoded in two bytes when it is 128 or + more, or when the field is stored + externally. */ if (UNIV_UNLIKELY(col->len > 255) || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) { @@ -647,6 +670,13 @@ rec_get_offsets_reverse( const dict_col_t* col = dict_field_get_col(field); len = *lens++; + /* If the maximum length of the field is up + to 255 bytes, the actual length is always + stored in one byte. If the maximum length is + more than 255 bytes, the actual length is + stored in one byte for 0..127. The length + will be encoded in two bytes when it is 128 or + more, or when the field is stored externally. */ if (UNIV_UNLIKELY(col->len > 255) || UNIV_UNLIKELY(col->mtype == DATA_BLOB)) { if (len & 0x80) { @@ -695,19 +725,9 @@ rec_get_nth_field_offs_old( ulint os; ulint next_os; - ut_ad(rec && len); - ut_ad(n < rec_get_n_fields_old(rec)); - - if (UNIV_UNLIKELY(n > REC_MAX_N_FIELDS)) { - fprintf(stderr, "Error: trying to access field %lu in rec\n", - (ulong) n); - ut_error; - } - - if (UNIV_UNLIKELY(rec == NULL)) { - fputs("Error: rec is NULL pointer\n", stderr); - ut_error; - } + ut_ad(len); + ut_a(rec); + ut_a(n < rec_get_n_fields_old(rec)); if (rec_get_1byte_offs_flag(rec)) { os = rec_1_get_field_start_offs(rec, n); @@ -791,12 +811,20 @@ rec_get_converted_size_comp_prefix( ut_ad(len <= col->len || col->mtype == DATA_BLOB); + /* If the maximum length of a variable-length field + is up to 255 bytes, the actual length is always stored + in one byte. If the maximum length is more than 255 + bytes, the actual length is stored in one byte for + 0..127. The length will be encoded in two bytes when + it is 128 or more, or when the field is stored externally. */ + if (field->fixed_len) { ut_ad(len == field->fixed_len); /* dict_index_add_col() should guarantee this */ ut_ad(!field->prefix_len || field->fixed_len == field->prefix_len); } else if (dfield_is_ext(&fields[i])) { + ut_ad(col->len >= 256 || col->mtype == DATA_BLOB); extra_size += 2; } else if (len < 128 || (col->len < 256 && col->mtype != DATA_BLOB)) { @@ -1096,6 +1124,8 @@ rec_convert_dtuple_to_rec_comp( /* Store the data and the offsets */ for (i = 0, field = fields; i < n_fields; i++, field++) { + const dict_field_t* ifield; + type = dfield_get_type(field); len = dfield_get_len(field); @@ -1130,12 +1160,20 @@ rec_convert_dtuple_to_rec_comp( /* only nullable fields can be null */ ut_ad(!dfield_is_null(field)); - fixed_len = dict_index_get_nth_field(index, i)->fixed_len; - + ifield = dict_index_get_nth_field(index, i); + fixed_len = ifield->fixed_len; + /* If the maximum length of a variable-length field + is up to 255 bytes, the actual length is always stored + in one byte. If the maximum length is more than 255 + bytes, the actual length is stored in one byte for + 0..127. The length will be encoded in two bytes when + it is 128 or more, or when the field is stored externally. */ if (fixed_len) { ut_ad(len == fixed_len); ut_ad(!dfield_is_ext(field)); } else if (dfield_is_ext(field)) { + ut_ad(ifield->col->len >= 256 + || ifield->col->mtype == DATA_BLOB); ut_ad(len <= REC_MAX_INDEX_COL_LEN + BTR_EXTERN_FIELD_REF_SIZE); *lens-- = (byte) (len >> 8) | 0xc0; @@ -1225,11 +1263,20 @@ rec_convert_dtuple_to_rec( mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; const ulint* offsets; + ulint i; rec_offs_init(offsets_); offsets = rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap); ut_ad(rec_validate(rec, offsets)); + ut_ad(dtuple_get_n_fields(dtuple) + == rec_offs_n_fields(offsets)); + + for (i = 0; i < rec_offs_n_fields(offsets); i++) { + ut_ad(!dfield_is_ext(dtuple_get_nth_field(dtuple, i)) + == !rec_offs_nth_extern(offsets, i)); + } + if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } @@ -1412,6 +1459,13 @@ rec_copy_prefix_to_buf( prefix_len += field->fixed_len; } else { ulint len = *lens--; + /* If the maximum length of the column is up + to 255 bytes, the actual length is always + stored in one byte. If the maximum length is + more than 255 bytes, the actual length is + stored in one byte for 0..127. The length + will be encoded in two bytes when it is 128 or + more, or when the column is stored externally. */ if (col->len > 255 || col->mtype == DATA_BLOB) { if (len & 0x80) { /* 1exxxxxx */ diff --git a/storage/innobase/revert_gen.sh b/storage/innobase/revert_gen.sh deleted file mode 100755 index 231e05a21e0..00000000000 --- a/storage/innobase/revert_gen.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -# -# revert changes to all generated files. this is useful in some situations -# when merging changes between branches. - -set -eu - -svn revert include/pars0grm.h pars/pars0grm.h pars/lexyy.c pars/pars0grm.c diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index fe51fce82c4..c882a065cd1 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -1121,9 +1121,9 @@ nonstandard_exit_func: /*********************************************************************//** Sets a shared lock on a record. Used in locking possible duplicate key records and also in checking foreign key constraints. -@return DB_SUCCESS or error code */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */ static -ulint +enum db_err row_ins_set_shared_rec_lock( /*========================*/ ulint type, /*!< in: LOCK_ORDINARY, LOCK_GAP, or @@ -1134,7 +1134,7 @@ row_ins_set_shared_rec_lock( const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ que_thr_t* thr) /*!< in: query thread */ { - ulint err; + enum db_err err; ut_ad(rec_offs_validate(rec, index, offsets)); @@ -1152,9 +1152,9 @@ row_ins_set_shared_rec_lock( /*********************************************************************//** Sets a exclusive lock on a record. Used in locking possible duplicate key records -@return DB_SUCCESS or error code */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */ static -ulint +enum db_err row_ins_set_exclusive_rec_lock( /*===========================*/ ulint type, /*!< in: LOCK_ORDINARY, LOCK_GAP, or @@ -1165,7 +1165,7 @@ row_ins_set_exclusive_rec_lock( const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ que_thr_t* thr) /*!< in: query thread */ { - ulint err; + enum db_err err; ut_ad(rec_offs_validate(rec, index, offsets)); @@ -1205,7 +1205,6 @@ row_ins_check_foreign_constraint( dict_index_t* check_index; ulint n_fields_cmp; btr_pcur_t pcur; - ibool moved; int cmp; ulint err; ulint i; @@ -1336,13 +1335,13 @@ run_again: /* Scan index records and check if there is a matching record */ - for (;;) { + do { const rec_t* rec = btr_pcur_get_rec(&pcur); const buf_block_t* block = btr_pcur_get_block(&pcur); if (page_rec_is_infimum(rec)) { - goto next_rec; + continue; } offsets = rec_get_offsets(rec, check_index, @@ -1353,12 +1352,13 @@ run_again: err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, block, rec, check_index, offsets, thr); - if (err != DB_SUCCESS) { - - break; + switch (err) { + case DB_SUCCESS_LOCKED_REC: + case DB_SUCCESS: + continue; + default: + goto end_scan; } - - goto next_rec; } cmp = cmp_dtuple_rec(entry, rec, offsets); @@ -1369,9 +1369,12 @@ run_again: err = row_ins_set_shared_rec_lock( LOCK_ORDINARY, block, rec, check_index, offsets, thr); - if (err != DB_SUCCESS) { - + switch (err) { + case DB_SUCCESS_LOCKED_REC: + case DB_SUCCESS: break; + default: + goto end_scan; } } else { /* Found a matching record. Lock only @@ -1382,15 +1385,18 @@ run_again: LOCK_REC_NOT_GAP, block, rec, check_index, offsets, thr); - if (err != DB_SUCCESS) { - + switch (err) { + case DB_SUCCESS_LOCKED_REC: + case DB_SUCCESS: break; + default: + goto end_scan; } if (check_ref) { err = DB_SUCCESS; - break; + goto end_scan; } else if (foreign->type != 0) { /* There is an ON UPDATE or ON DELETE condition: check them in a separate @@ -1416,7 +1422,7 @@ run_again: err = DB_FOREIGN_DUPLICATE_KEY; } - break; + goto end_scan; } /* row_ins_foreign_check_on_constraint @@ -1429,49 +1435,41 @@ run_again: thr, foreign, rec, entry); err = DB_ROW_IS_REFERENCED; - break; + goto end_scan; } } - } + } else { + ut_a(cmp < 0); - if (cmp < 0) { err = row_ins_set_shared_rec_lock( LOCK_GAP, block, rec, check_index, offsets, thr); - if (err != DB_SUCCESS) { - - break; - } - if (check_ref) { - err = DB_NO_REFERENCED_ROW; - row_ins_foreign_report_add_err( - trx, foreign, rec, entry); - } else { - err = DB_SUCCESS; + switch (err) { + case DB_SUCCESS_LOCKED_REC: + case DB_SUCCESS: + if (check_ref) { + err = DB_NO_REFERENCED_ROW; + row_ins_foreign_report_add_err( + trx, foreign, rec, entry); + } else { + err = DB_SUCCESS; + } } - break; + goto end_scan; } + } while (btr_pcur_move_to_next(&pcur, &mtr)); - ut_a(cmp == 0); -next_rec: - moved = btr_pcur_move_to_next(&pcur, &mtr); - - if (!moved) { - if (check_ref) { - rec = btr_pcur_get_rec(&pcur); - row_ins_foreign_report_add_err( - trx, foreign, rec, entry); - err = DB_NO_REFERENCED_ROW; - } else { - err = DB_SUCCESS; - } - - break; - } + if (check_ref) { + row_ins_foreign_report_add_err( + trx, foreign, btr_pcur_get_rec(&pcur), entry); + err = DB_NO_REFERENCED_ROW; + } else { + err = DB_SUCCESS; } +end_scan: btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -1719,9 +1717,13 @@ row_ins_scan_sec_index_for_duplicate( rec, index, offsets, thr); } - if (err != DB_SUCCESS) { - + switch (err) { + case DB_SUCCESS_LOCKED_REC: + err = DB_SUCCESS; + case DB_SUCCESS: break; + default: + goto end_scan; } if (page_rec_is_supremum(rec)) { @@ -1738,17 +1740,15 @@ row_ins_scan_sec_index_for_duplicate( thr_get_trx(thr)->error_info = index; - break; + goto end_scan; } + } else { + ut_a(cmp < 0); + goto end_scan; } - - if (cmp < 0) { - break; - } - - ut_a(cmp == 0); } while (btr_pcur_move_to_next(&pcur, &mtr)); +end_scan: if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } @@ -1837,7 +1837,11 @@ row_ins_duplicate_error_in_clust( cursor->index, offsets, thr); } - if (err != DB_SUCCESS) { + switch (err) { + case DB_SUCCESS_LOCKED_REC: + case DB_SUCCESS: + break; + default: goto func_exit; } @@ -1877,7 +1881,11 @@ row_ins_duplicate_error_in_clust( rec, cursor->index, offsets, thr); } - if (err != DB_SUCCESS) { + switch (err) { + case DB_SUCCESS_LOCKED_REC: + case DB_SUCCESS: + break; + default: goto func_exit; } @@ -1965,7 +1973,7 @@ row_ins_index_entry_low( que_thr_t* thr) /*!< in: query thread */ { btr_cur_t cursor; - ulint ignore_sec_unique = 0; + ulint search_mode; ulint modify = 0; /* remove warning */ rec_t* insert_rec; rec_t* rec; @@ -1985,18 +1993,23 @@ row_ins_index_entry_low( the function will return in both low_match and up_match of the cursor sensible values */ - if (!(thr_get_trx(thr)->check_unique_secondary)) { - ignore_sec_unique = BTR_IGNORE_SEC_UNIQUE; + if (dict_index_is_clust(index)) { + search_mode = mode; + } else if (!(thr_get_trx(thr)->check_unique_secondary)) { + search_mode = mode | BTR_INSERT | BTR_IGNORE_SEC_UNIQUE; + } else { + search_mode = mode | BTR_INSERT; } btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, - mode | BTR_INSERT | ignore_sec_unique, - &cursor, 0, &mtr); + search_mode, + &cursor, 0, __FILE__, __LINE__, &mtr); if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) { /* The insertion was made to the insert buffer already during the search: we are done */ + ut_ad(search_mode & BTR_INSERT); err = DB_SUCCESS; goto function_exit; @@ -2049,7 +2062,8 @@ row_ins_index_entry_low( btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, mode | BTR_INSERT, - &cursor, 0, &mtr); + &cursor, 0, + __FILE__, __LINE__, &mtr); } } @@ -2104,7 +2118,8 @@ function_exit: mtr_start(&mtr); btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, - BTR_MODIFY_TREE, &cursor, 0, &mtr); + BTR_MODIFY_TREE, &cursor, 0, + __FILE__, __LINE__, &mtr); rec = btr_cur_get_rec(&cursor); offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap); diff --git a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c index 232211e5ce7..d9084bb4ffd 100644 --- a/storage/innobase/row/row0merge.c +++ b/storage/innobase/row/row0merge.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2005, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 2005, 2010, Innobase Oy. All Rights Reserved. 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 @@ -57,6 +57,11 @@ Completed by Sunny Bains and Marko Makela #include "ut0sort.h" #include "handler0alter.h" +/* Ignore posix_fadvise() on those platforms where it does not exist */ +#if defined __WIN__ +# define posix_fadvise(fd, offset, len, advice) /* nothing */ +#endif /* __WIN__ */ + #ifdef UNIV_DEBUG /** Set these in order ot enable debug printout. */ /* @{ */ @@ -269,6 +274,7 @@ row_merge_buf_add( const dict_index_t* index; dfield_t* entry; dfield_t* field; + const dict_field_t* ifield; if (buf->n_tuples >= buf->max_tuples) { return(FALSE); @@ -287,14 +293,14 @@ row_merge_buf_add( data_size = 0; extra_size = UT_BITS_IN_BYTES(index->n_nullable); - for (i = 0; i < n_fields; i++, field++) { - const dict_field_t* ifield; + ifield = dict_index_get_nth_field(index, 0); + + for (i = 0; i < n_fields; i++, field++, ifield++) { const dict_col_t* col; ulint col_no; const dfield_t* row_field; ulint len; - ifield = dict_index_get_nth_field(index, i); col = ifield->col; col_no = dict_col_get_no(col); row_field = dtuple_get_nth_field(row, col_no); @@ -424,14 +430,13 @@ row_merge_dup_report( row_merge_dup_t* dup, /*!< in/out: for reporting duplicates */ const dfield_t* entry) /*!< in: duplicate index entry */ { - mrec_buf_t buf; + mrec_buf_t* buf; const dtuple_t* tuple; dtuple_t tuple_store; const rec_t* rec; const dict_index_t* index = dup->index; ulint n_fields= dict_index_get_n_fields(index); - mem_heap_t* heap = NULL; - ulint offsets_[REC_OFFS_NORMAL_SIZE]; + mem_heap_t* heap; ulint* offsets; ulint n_ext; @@ -441,22 +446,22 @@ row_merge_dup_report( return; } - rec_offs_init(offsets_); - /* Convert the tuple to a record and then to MySQL format. */ + heap = mem_heap_create((1 + REC_OFFS_HEADER_SIZE + n_fields) + * sizeof *offsets + + sizeof *buf); + + buf = mem_heap_alloc(heap, sizeof *buf); tuple = dtuple_from_fields(&tuple_store, entry, n_fields); n_ext = dict_index_is_clust(index) ? dtuple_get_n_ext(tuple) : 0; - rec = rec_convert_dtuple_to_rec(buf, index, tuple, n_ext); - offsets = rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, - &heap); + rec = rec_convert_dtuple_to_rec(*buf, index, tuple, n_ext); + offsets = rec_get_offsets(rec, index, NULL, ULINT_UNDEFINED, &heap); innobase_rec_to_mysql(dup->table, rec, index, offsets); - if (UNIV_LIKELY_NULL(heap)) { - mem_heap_free(heap); - } + mem_heap_free(heap); } /*************************************************************//** @@ -627,22 +632,26 @@ row_merge_buf_write( } /******************************************************//** -Create a memory heap and allocate space for row_merge_rec_offsets(). +Create a memory heap and allocate space for row_merge_rec_offsets() +and mrec_buf_t[3]. @return memory heap */ static mem_heap_t* row_merge_heap_create( /*==================*/ const dict_index_t* index, /*!< in: record descriptor */ + mrec_buf_t** buf, /*!< out: 3 buffers */ ulint** offsets1, /*!< out: offsets */ ulint** offsets2) /*!< out: offsets */ { ulint i = 1 + REC_OFFS_HEADER_SIZE + dict_index_get_n_fields(index); - mem_heap_t* heap = mem_heap_create(2 * i * sizeof *offsets1); + mem_heap_t* heap = mem_heap_create(2 * i * sizeof **offsets1 + + 3 * sizeof **buf); - *offsets1 = mem_heap_alloc(heap, i * sizeof *offsets1); - *offsets2 = mem_heap_alloc(heap, i * sizeof *offsets2); + *buf = mem_heap_alloc(heap, 3 * sizeof **buf); + *offsets1 = mem_heap_alloc(heap, i * sizeof **offsets1); + *offsets2 = mem_heap_alloc(heap, i * sizeof **offsets2); (*offsets1)[0] = (*offsets2)[0] = i; (*offsets1)[1] = (*offsets2)[1] = dict_index_get_n_fields(index); @@ -687,7 +696,9 @@ ibool row_merge_read( /*===========*/ int fd, /*!< in: file descriptor */ - ulint offset, /*!< in: offset where to read */ + ulint offset, /*!< in: offset where to read + in number of row_merge_block_t + elements */ row_merge_block_t* buf) /*!< out: data */ { ib_uint64_t ofs = ((ib_uint64_t) offset) * sizeof *buf; @@ -704,6 +715,11 @@ row_merge_read( (ulint) (ofs & 0xFFFFFFFF), (ulint) (ofs >> 32), sizeof *buf); +#ifdef POSIX_FADV_DONTNEED + /* Each block is read exactly once. Free up the file cache. */ + posix_fadvise(fd, ofs, sizeof *buf, POSIX_FADV_DONTNEED); +#endif /* POSIX_FADV_DONTNEED */ + if (UNIV_UNLIKELY(!success)) { ut_print_timestamp(stderr); fprintf(stderr, @@ -714,18 +730,25 @@ row_merge_read( } /********************************************************************//** -Read a merge block from the file system. +Write a merge block to the file system. @return TRUE if request was successful, FALSE if fail */ static ibool row_merge_write( /*============*/ int fd, /*!< in: file descriptor */ - ulint offset, /*!< in: offset where to write */ + ulint offset, /*!< in: offset where to write, + in number of row_merge_block_t elements */ const void* buf) /*!< in: data */ { - ib_uint64_t ofs = ((ib_uint64_t) offset) - * sizeof(row_merge_block_t); + size_t buf_len = sizeof(row_merge_block_t); + ib_uint64_t ofs = buf_len * (ib_uint64_t) offset; + ibool ret; + + ret = os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf, + (ulint) (ofs & 0xFFFFFFFF), + (ulint) (ofs >> 32), + buf_len); #ifdef UNIV_DEBUG if (row_merge_print_block_write) { @@ -734,10 +757,13 @@ row_merge_write( } #endif /* UNIV_DEBUG */ - return(UNIV_LIKELY(os_file_write("(merge)", OS_FILE_FROM_FD(fd), buf, - (ulint) (ofs & 0xFFFFFFFF), - (ulint) (ofs >> 32), - sizeof(row_merge_block_t)))); +#ifdef POSIX_FADV_DONTNEED + /* The block will be needed on the next merge pass, + but it can be evicted from the file cache meanwhile. */ + posix_fadvise(fd, ofs, buf_len, POSIX_FADV_DONTNEED); +#endif /* POSIX_FADV_DONTNEED */ + + return(UNIV_LIKELY(ret)); } /********************************************************************//** @@ -1072,11 +1098,14 @@ row_merge_cmp( record to be compared */ const ulint* offsets1, /*!< in: first record offsets */ const ulint* offsets2, /*!< in: second record offsets */ - const dict_index_t* index) /*!< in: index */ + const dict_index_t* index, /*!< in: index */ + ibool* null_eq) /*!< out: set to TRUE if + found matching null values */ { int cmp; - cmp = cmp_rec_rec_simple(mrec1, mrec2, offsets1, offsets2, index); + cmp = cmp_rec_rec_simple(mrec1, mrec2, offsets1, offsets2, index, + null_eq); #ifdef UNIV_DEBUG if (row_merge_print_cmp) { @@ -1394,7 +1423,8 @@ row_merge_blocks( { mem_heap_t* heap; /*!< memory heap for offsets0, offsets1 */ - mrec_buf_t buf[3]; /*!< buffer for handling split mrec in block[] */ + mrec_buf_t* buf; /*!< buffer for handling + split mrec in block[] */ const byte* b0; /*!< pointer to block[0] */ const byte* b1; /*!< pointer to block[1] */ byte* b2; /*!< pointer to block[2] */ @@ -1414,7 +1444,7 @@ row_merge_blocks( } #endif /* UNIV_DEBUG */ - heap = row_merge_heap_create(index, &offsets0, &offsets1); + heap = row_merge_heap_create(index, &buf, &offsets0, &offsets1); /* Write a record and read the next record. Split the output file in two halves, which can be merged on the following pass. */ @@ -1441,11 +1471,13 @@ corrupt: } while (mrec0 && mrec1) { + ibool null_eq = FALSE; switch (row_merge_cmp(mrec0, mrec1, - offsets0, offsets1, index)) { + offsets0, offsets1, index, + &null_eq)) { case 0: if (UNIV_UNLIKELY - (dict_index_is_unique(index))) { + (dict_index_is_unique(index) && !null_eq)) { innobase_rec_to_mysql(table, mrec0, index, offsets0); mem_heap_free(heap); @@ -1500,7 +1532,7 @@ row_merge_blocks_copy( { mem_heap_t* heap; /*!< memory heap for offsets0, offsets1 */ - mrec_buf_t buf[3]; /*!< buffer for handling + mrec_buf_t* buf; /*!< buffer for handling split mrec in block[] */ const byte* b0; /*!< pointer to block[0] */ byte* b2; /*!< pointer to block[2] */ @@ -1518,7 +1550,7 @@ row_merge_blocks_copy( } #endif /* UNIV_DEBUG */ - heap = row_merge_heap_create(index, &offsets0, &offsets1); + heap = row_merge_heap_create(index, &buf, &offsets0, &offsets1); /* Write a record and read the next record. Split the output file in two halves, which can be merged on the following pass. */ @@ -1589,6 +1621,14 @@ row_merge( of.offset = 0; of.n_rec = 0; +#ifdef POSIX_FADV_SEQUENTIAL + /* The input file will be read sequentially, starting from the + beginning and the middle. In Linux, the POSIX_FADV_SEQUENTIAL + affects the entire file. Each block will be read exactly once. */ + posix_fadvise(file->fd, 0, 0, + POSIX_FADV_SEQUENTIAL | POSIX_FADV_NOREUSE); +#endif /* POSIX_FADV_SEQUENTIAL */ + /* Merge blocks to the output file. */ ohalf = 0; foffs0 = 0; @@ -1760,7 +1800,6 @@ row_merge_insert_index_tuples( int fd, /*!< in: file descriptor */ row_merge_block_t* block) /*!< in/out: file buffer */ { - mrec_buf_t buf; const byte* b; que_thr_t* thr; ins_node_t* node; @@ -1779,7 +1818,7 @@ row_merge_insert_index_tuples( trx->op_info = "inserting index entries"; - graph_heap = mem_heap_create(500); + graph_heap = mem_heap_create(500 + sizeof(mrec_buf_t)); node = ins_node_create(INS_DIRECT, table, graph_heap); thr = pars_complete_graph_for_exec(node, trx, graph_heap); @@ -1801,12 +1840,14 @@ row_merge_insert_index_tuples( if (!row_merge_read(fd, foffs, block)) { error = DB_CORRUPTION; } else { + mrec_buf_t* buf = mem_heap_alloc(graph_heap, sizeof *buf); + for (;;) { const mrec_t* mrec; dtuple_t* dtuple; ulint n_ext; - b = row_merge_read_rec(block, &buf, b, index, + b = row_merge_read_rec(block, buf, b, index, fd, &foffs, &mrec, offsets); if (UNIV_UNLIKELY(!b)) { /* End of list, or I/O error */ @@ -1977,14 +2018,12 @@ row_merge_drop_index( /* Drop the field definitions of the index. */ "DELETE FROM SYS_FIELDS WHERE INDEX_ID = :indexid;\n" /* Drop the index definition and the B-tree. */ - "DELETE FROM SYS_INDEXES WHERE ID = :indexid\n" - " AND TABLE_ID = :tableid;\n" + "DELETE FROM SYS_INDEXES WHERE ID = :indexid;\n" "END;\n"; ut_ad(index && table && trx); pars_info_add_dulint_literal(info, "indexid", index->id); - pars_info_add_dulint_literal(info, "tableid", table->id); trx_start_if_not_started(trx); trx->op_info = "dropping index"; @@ -2033,47 +2072,82 @@ row_merge_drop_temp_indexes(void) /*=============================*/ { trx_t* trx; - ulint err; - - /* We use the private SQL parser of Innobase to generate the - query graphs needed in deleting the dictionary data from system - tables in Innobase. Deleting a row from SYS_INDEXES table also - frees the file segments of the B-tree associated with the index. */ - static const char drop_temp_indexes[] = - "PROCEDURE DROP_TEMP_INDEXES_PROC () IS\n" - "indexid CHAR;\n" - "DECLARE CURSOR c IS SELECT ID FROM SYS_INDEXES\n" - "WHERE SUBSTR(NAME,0,1)='" TEMP_INDEX_PREFIX_STR "';\n" - "BEGIN\n" - "\tOPEN c;\n" - "\tWHILE 1=1 LOOP\n" - "\t\tFETCH c INTO indexid;\n" - "\t\tIF (SQL % NOTFOUND) THEN\n" - "\t\t\tEXIT;\n" - "\t\tEND IF;\n" - "\t\tDELETE FROM SYS_FIELDS WHERE INDEX_ID = indexid;\n" - "\t\tDELETE FROM SYS_INDEXES WHERE ID = indexid;\n" - "\tEND LOOP;\n" - "\tCLOSE c;\n" - "\tCOMMIT WORK;\n" - "END;\n"; + btr_pcur_t pcur; + mtr_t mtr; + /* Load the table definitions that contain partially defined + indexes, so that the data dictionary information can be checked + when accessing the tablename.ibd files. */ trx = trx_allocate_for_background(); trx->op_info = "dropping partially created indexes"; row_mysql_lock_data_dictionary(trx); - /* Incomplete transactions may be holding some locks on the - data dictionary tables. However, they should never have been - able to lock the records corresponding to the partially - created indexes that we are attempting to delete, because the - table was locked when the indexes were being created. We will - drop the partially created indexes before the rollback of - incomplete transactions is initiated. Thus, this should not - interfere with the incomplete transactions. */ - trx->isolation_level = TRX_ISO_READ_UNCOMMITTED; - err = que_eval_sql(NULL, drop_temp_indexes, FALSE, trx); - ut_a(err == DB_SUCCESS); + mtr_start(&mtr); + + btr_pcur_open_at_index_side( + TRUE, + dict_table_get_first_index(dict_sys->sys_indexes), + BTR_SEARCH_LEAF, &pcur, TRUE, &mtr); + + for (;;) { + const rec_t* rec; + const byte* field; + ulint len; + dulint table_id; + dict_table_t* table; + + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + + if (!btr_pcur_is_on_user_rec(&pcur)) { + break; + } + + rec = btr_pcur_get_rec(&pcur); + field = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_NAME_FIELD, + &len); + if (len == UNIV_SQL_NULL || len == 0 + || (char) *field != TEMP_INDEX_PREFIX) { + continue; + } + + /* This is a temporary index. */ + + field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len); + if (len != 8) { + /* Corrupted TABLE_ID */ + continue; + } + + table_id = mach_read_from_8(field); + btr_pcur_store_position(&pcur, &mtr); + btr_pcur_commit_specify_mtr(&pcur, &mtr); + + table = dict_table_get_on_id_low(table_id); + + if (table) { + dict_index_t* index; + dict_index_t* next_index; + + for (index = dict_table_get_first_index(table); + index; index = next_index) { + + next_index = dict_table_get_next_index(index); + + if (*index->name == TEMP_INDEX_PREFIX) { + row_merge_drop_index(index, table, trx); + trx_commit_for_mysql(trx); + } + } + } + + mtr_start(&mtr); + btr_pcur_restore_position(BTR_SEARCH_LEAF, + &pcur, &mtr); + } + + btr_pcur_close(&pcur); + mtr_commit(&mtr); row_mysql_unlock_data_dictionary(trx); trx_free_for_background(trx); } @@ -2086,9 +2160,22 @@ row_merge_file_create( /*==================*/ merge_file_t* merge_file) /*!< out: merge file structure */ { +#ifdef UNIV_PFS_IO + /* This temp file open does not go through normal + file APIs, add instrumentation to register with + performance schema */ + struct PSI_file_locker* locker = NULL; + register_pfs_file_open_begin(locker, innodb_file_temp_key, + PSI_FILE_OPEN, + "Innodb Merge Temp File", + __FILE__, __LINE__); +#endif merge_file->fd = innobase_mysql_tmpfile(); merge_file->offset = 0; merge_file->n_rec = 0; +#ifdef UNIV_PFS_IO + register_pfs_file_open_end(locker, merge_file->fd); +#endif } /*********************************************************************//** @@ -2099,10 +2186,19 @@ row_merge_file_destroy( /*===================*/ merge_file_t* merge_file) /*!< out: merge file structure */ { +#ifdef UNIV_PFS_IO + struct PSI_file_locker* locker = NULL; + register_pfs_file_io_begin(locker, merge_file->fd, 0, PSI_FILE_CLOSE, + __FILE__, __LINE__); +#endif if (merge_file->fd != -1) { close(merge_file->fd); merge_file->fd = -1; } + +#ifdef UNIV_PFS_IO + register_pfs_file_io_end(locker, 0); +#endif } /*********************************************************************//** diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 181c39de881..1f7f98a59a2 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2000, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 2000, 2010, Innobase Oy. All Rights Reserved. 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 @@ -485,7 +485,7 @@ next_column: /****************************************************************//** Handles user errors and lock waits detected by the database engine. @return TRUE if it was a lock wait and we should continue running the -query thread */ +query thread and in that case the thr is ALREADY in the running state. */ UNIV_INTERN ibool row_mysql_handle_errors( @@ -522,6 +522,7 @@ handle_new_error: case DB_CANNOT_ADD_CONSTRAINT: case DB_TOO_MANY_CONCURRENT_TRXS: case DB_OUT_OF_FILE_SPACE: + case DB_INTERRUPTED: if (savept) { /* Roll back the latest, possibly incomplete insertion or update */ @@ -624,6 +625,8 @@ row_create_prebuilt( prebuilt->select_lock_type = LOCK_NONE; prebuilt->stored_select_lock_type = 99999999; + UNIV_MEM_INVALID(&prebuilt->stored_select_lock_type, + sizeof prebuilt->stored_select_lock_type); prebuilt->search_tuple = dtuple_create( heap, 2 * dict_table_get_n_cols(table)); @@ -1427,27 +1430,26 @@ run_again: } /*********************************************************************//** -This can only be used when srv_locks_unsafe_for_binlog is TRUE or -this session is using a READ COMMITTED isolation level. Before -calling this function we must use trx_reset_new_rec_lock_info() and -trx_register_new_rec_lock() to store the information which new record locks -really were set. This function removes a newly set lock under prebuilt->pcur, -and also under prebuilt->clust_pcur. Currently, this is only used and tested -in the case of an UPDATE or a DELETE statement, where the row lock is of the -LOCK_X type. -Thus, this implements a 'mini-rollback' that releases the latest record -locks we set. -@return error code or DB_SUCCESS */ +This can only be used when srv_locks_unsafe_for_binlog is TRUE or this +session is using a READ COMMITTED or READ UNCOMMITTED isolation level. +Before calling this function row_search_for_mysql() must have +initialized prebuilt->new_rec_locks to store the information which new +record locks really were set. This function removes a newly set +clustered index record lock under prebuilt->pcur or +prebuilt->clust_pcur. Thus, this implements a 'mini-rollback' that +releases the latest clustered index record lock we set. +@return error code or DB_SUCCESS */ UNIV_INTERN int row_unlock_for_mysql( /*=================*/ - row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in MySQL + row_prebuilt_t* prebuilt, /*!< in/out: prebuilt struct in MySQL handle */ - ibool has_latches_on_recs)/*!< TRUE if called so that we have - the latches on the records under pcur - and clust_pcur, and we do not need to - reposition the cursors. */ + ibool has_latches_on_recs)/*!< in: TRUE if called so + that we have the latches on + the records under pcur and + clust_pcur, and we do not need + to reposition the cursors. */ { btr_pcur_t* pcur = prebuilt->pcur; btr_pcur_t* clust_pcur = prebuilt->clust_pcur; @@ -1458,7 +1460,7 @@ row_unlock_for_mysql( if (UNIV_UNLIKELY (!srv_locks_unsafe_for_binlog - && trx->isolation_level != TRX_ISO_READ_COMMITTED)) { + && trx->isolation_level > TRX_ISO_READ_COMMITTED)) { fprintf(stderr, "InnoDB: Error: calling row_unlock_for_mysql though\n" @@ -1645,37 +1647,6 @@ row_table_got_default_clust_index( } /*********************************************************************//** -Calculates the key number used inside MySQL for an Innobase index. We have -to take into account if we generated a default clustered index for the table -@return the key number used inside MySQL */ -UNIV_INTERN -ulint -row_get_mysql_key_number_for_index( -/*===============================*/ - const dict_index_t* index) /*!< in: index */ -{ - const dict_index_t* ind; - ulint i; - - ut_a(index); - - i = 0; - ind = dict_table_get_first_index(index->table); - - while (index != ind) { - ind = dict_table_get_next_index(ind); - i++; - } - - if (row_table_got_default_clust_index(index->table)) { - ut_a(i > 0); - i--; - } - - return(i); -} - -/*********************************************************************//** Locks the data dictionary in shared mode from modifications, for performing foreign key check, rollback, or other operation invisible to MySQL. */ UNIV_INTERN @@ -2059,6 +2030,7 @@ row_table_add_foreign_constraints( FOREIGN KEY (a, b) REFERENCES table2(c, d), table2 can be written also with the database name before it: test.table2 */ + size_t sql_length, /*!< in: length of sql_string */ const char* name, /*!< in: table full name in the normalized form database_name/table_name */ @@ -2080,8 +2052,8 @@ row_table_add_foreign_constraints( trx_set_dict_operation(trx, TRX_DICT_OP_TABLE); - err = dict_create_foreign_constraints(trx, sql_string, name, - reject_fks); + err = dict_create_foreign_constraints(trx, sql_string, sql_length, + name, reject_fks); if (err == DB_SUCCESS) { /* Check that also referencing constraints are ok */ err = dict_load_foreigns(name, TRUE); @@ -2425,7 +2397,7 @@ row_discard_tablespace_for_mysql( goto funct_exit; } - new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); + dict_hdr_get_new_id(&new_id, NULL, NULL); /* Remove all locks except the table-level S and X locks. */ lock_remove_all_on_table(table, FALSE); @@ -2787,10 +2759,11 @@ row_truncate_table_for_mysql( dict_index_t* index; - space = 0; + dict_hdr_get_new_id(NULL, NULL, &space); - if (fil_create_new_single_table_tablespace( - &space, table->name, FALSE, flags, + if (space == ULINT_UNDEFINED + || fil_create_new_single_table_tablespace( + space, table->name, FALSE, flags, FIL_IBD_FILE_INITIAL_SIZE) != DB_SUCCESS) { ut_print_timestamp(stderr); fprintf(stderr, @@ -2895,7 +2868,7 @@ next_rec: mem_heap_free(heap); - new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); + dict_hdr_get_new_id(&new_id, NULL, NULL); info = pars_info_create(); @@ -3255,19 +3228,13 @@ check_next_foreign: "END;\n" , FALSE, trx); - if (err != DB_SUCCESS) { - ut_a(err == DB_OUT_OF_FILE_SPACE); - - err = DB_MUST_GET_MORE_FILE_SPACE; - - row_mysql_handle_errors(&err, trx, NULL, NULL); - - ut_error; - } else { - ibool is_path; + switch (err) { + ibool is_temp; const char* name_or_path; mem_heap_t* heap; + case DB_SUCCESS: + heap = mem_heap_create(200); /* Clone the name, in case it has been allocated @@ -3277,17 +3244,18 @@ check_next_foreign: space_id = table->space; if (table->dir_path_of_temp_table != NULL) { - is_path = TRUE; name_or_path = mem_heap_strdup( heap, table->dir_path_of_temp_table); + is_temp = TRUE; } else { - is_path = FALSE; name_or_path = name; + is_temp = (table->flags >> DICT_TF2_SHIFT) + & DICT_TF2_TEMPORARY; } dict_table_remove_from_cache(table); - if (dict_load_table(name) != NULL) { + if (dict_load_table(name, TRUE) != NULL) { ut_print_timestamp(stderr); fputs(" InnoDB: Error: not able to remove table ", stderr); @@ -3302,8 +3270,8 @@ check_next_foreign: if (err == DB_SUCCESS && space_id > 0) { if (!fil_space_for_table_exists_in_mem(space_id, name_or_path, - is_path, - FALSE, TRUE)) { + is_temp, FALSE, + !is_temp)) { err = DB_SUCCESS; fprintf(stderr, @@ -3332,7 +3300,27 @@ check_next_foreign: } mem_heap_free(heap); + break; + + case DB_TOO_MANY_CONCURRENT_TRXS: + /* Cannot even find a free slot for the + the undo log. We can directly exit here + and return the DB_TOO_MANY_CONCURRENT_TRXS + error. */ + break; + + case DB_OUT_OF_FILE_SPACE: + err = DB_MUST_GET_MORE_FILE_SPACE; + + row_mysql_handle_errors(&err, trx, NULL, NULL); + + /* Fall through to raise error */ + + default: + /* No other possible error returns */ + ut_error; } + funct_exit: if (locked_dictionary) { @@ -3348,6 +3336,90 @@ funct_exit: return((int) err); } +/*********************************************************************//** +Drop all temporary tables during crash recovery. */ +UNIV_INTERN +void +row_mysql_drop_temp_tables(void) +/*============================*/ +{ + trx_t* trx; + btr_pcur_t pcur; + mtr_t mtr; + mem_heap_t* heap; + + trx = trx_allocate_for_background(); + trx->op_info = "dropping temporary tables"; + row_mysql_lock_data_dictionary(trx); + + heap = mem_heap_create(200); + + mtr_start(&mtr); + + btr_pcur_open_at_index_side( + TRUE, + dict_table_get_first_index(dict_sys->sys_tables), + BTR_SEARCH_LEAF, &pcur, TRUE, &mtr); + + for (;;) { + const rec_t* rec; + const byte* field; + ulint len; + const char* table_name; + dict_table_t* table; + + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + + if (!btr_pcur_is_on_user_rec(&pcur)) { + break; + } + + rec = btr_pcur_get_rec(&pcur); + field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len); + if (len != 4 || !(mach_read_from_4(field) & 0x80000000UL)) { + continue; + } + + /* Because this is not a ROW_FORMAT=REDUNDANT table, + the is_temp flag is valid. Examine it. */ + + field = rec_get_nth_field_old(rec, 7/*MIX_LEN*/, &len); + if (len != 4 + || !(mach_read_from_4(field) & DICT_TF2_TEMPORARY)) { + continue; + } + + /* This is a temporary table. */ + field = rec_get_nth_field_old(rec, 0/*NAME*/, &len); + if (len == UNIV_SQL_NULL || len == 0) { + /* Corrupted SYS_TABLES.NAME */ + continue; + } + + table_name = mem_heap_strdupl(heap, (const char*) field, len); + + btr_pcur_store_position(&pcur, &mtr); + btr_pcur_commit_specify_mtr(&pcur, &mtr); + + table = dict_load_table(table_name, TRUE); + + if (table) { + row_drop_table_for_mysql(table_name, trx, FALSE); + trx_commit_for_mysql(trx); + } + + mtr_start(&mtr); + btr_pcur_restore_position(BTR_SEARCH_LEAF, + &pcur, &mtr); + } + + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap); + row_mysql_unlock_data_dictionary(trx); + trx_free_for_background(trx); +} + /*******************************************************************//** Drop all foreign keys in a database, see Bug#18942. Called at the end of row_drop_database_for_mysql(). @@ -3899,14 +3971,15 @@ Checks that the index contains entries in an ascending order, unique constraint is not broken, and calculates the number of index entries in the read view of the current transaction. @return TRUE if ok */ -static +UNIV_INTERN ibool -row_scan_and_check_index( -/*=====================*/ - row_prebuilt_t* prebuilt, /*!< in: prebuilt struct in MySQL */ - dict_index_t* index, /*!< in: index */ - ulint* n_rows) /*!< out: number of entries seen in the - current consistent read */ +row_check_index_for_mysql( +/*======================*/ + row_prebuilt_t* prebuilt, /*!< in: prebuilt struct + in MySQL handle */ + const dict_index_t* index, /*!< in: index */ + ulint* n_rows) /*!< out: number of entries + seen in the consistent read */ { dtuple_t* prev_entry = NULL; ulint matched_fields; @@ -3927,31 +4000,9 @@ row_scan_and_check_index( *n_rows = 0; - if (!row_merge_is_index_usable(prebuilt->trx, index)) { - /* A newly created index may lack some delete-marked - records that may exist in the read view of - prebuilt->trx. Thus, such indexes must not be - accessed by consistent read. */ - return(is_ok); - } - buf = mem_alloc(UNIV_PAGE_SIZE); heap = mem_heap_create(100); - /* Make a dummy template in prebuilt, which we will use - in scanning the index entries */ - - prebuilt->index = index; - /* row_merge_is_index_usable() was already checked above. */ - prebuilt->index_usable = TRUE; - prebuilt->sql_stat_start = TRUE; - prebuilt->template_type = ROW_MYSQL_DUMMY_TEMPLATE; - prebuilt->n_template = 0; - prebuilt->need_to_access_clustered = FALSE; - - dtuple_set_n_fields(prebuilt->search_tuple, 0); - - prebuilt->select_lock_type = LOCK_NONE; cnt = 1000; ret = row_search_for_mysql(buf, PAGE_CUR_G, prebuilt, 0, 0); @@ -4070,119 +4121,6 @@ not_ok: } /*********************************************************************//** -Checks a table for corruption. -@return DB_ERROR or DB_SUCCESS */ -UNIV_INTERN -ulint -row_check_table_for_mysql( -/*======================*/ - row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in MySQL - handle */ -{ - dict_table_t* table = prebuilt->table; - dict_index_t* index; - ulint n_rows; - ulint n_rows_in_table = ULINT_UNDEFINED; - ulint ret = DB_SUCCESS; - ulint old_isolation_level; - - if (table->ibd_file_missing) { - ut_print_timestamp(stderr); - fprintf(stderr, " InnoDB: Error:\n" - "InnoDB: MySQL is trying to use a table handle" - " but the .ibd file for\n" - "InnoDB: table %s does not exist.\n" - "InnoDB: Have you deleted the .ibd file" - " from the database directory under\n" - "InnoDB: the MySQL datadir, or have you" - " used DISCARD TABLESPACE?\n" - "InnoDB: Look from\n" - "InnoDB: " REFMAN "innodb-troubleshooting.html\n" - "InnoDB: how you can resolve the problem.\n", - table->name); - return(DB_ERROR); - } - - prebuilt->trx->op_info = "checking table"; - - old_isolation_level = prebuilt->trx->isolation_level; - - /* We must run the index record counts at an isolation level - >= READ COMMITTED, because a dirty read can see a wrong number - of records in some index; to play safe, we use always - REPEATABLE READ here */ - - prebuilt->trx->isolation_level = TRX_ISO_REPEATABLE_READ; - - /* Enlarge the fatal lock wait timeout during CHECK TABLE. */ - mutex_enter(&kernel_mutex); - srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */ - mutex_exit(&kernel_mutex); - - index = dict_table_get_first_index(table); - - while (index != NULL) { - /* fputs("Validating index ", stderr); - ut_print_name(stderr, trx, FALSE, index->name); - putc('\n', stderr); */ - - if (!btr_validate_index(index, prebuilt->trx)) { - ret = DB_ERROR; - } else { - if (!row_scan_and_check_index(prebuilt,index, &n_rows)){ - ret = DB_ERROR; - } - - if (trx_is_interrupted(prebuilt->trx)) { - ret = DB_INTERRUPTED; - break; - } - - /* fprintf(stderr, "%lu entries in index %s\n", n_rows, - index->name); */ - - if (index == dict_table_get_first_index(table)) { - n_rows_in_table = n_rows; - } else if (n_rows != n_rows_in_table) { - - ret = DB_ERROR; - - fputs("Error: ", stderr); - dict_index_name_print(stderr, - prebuilt->trx, index); - fprintf(stderr, - " contains %lu entries," - " should be %lu\n", - (ulong) n_rows, - (ulong) n_rows_in_table); - } - } - - index = dict_table_get_next_index(index); - } - - /* Restore the original isolation level */ - prebuilt->trx->isolation_level = old_isolation_level; - - /* We validate also the whole adaptive hash index for all tables - at every CHECK TABLE */ - - if (!btr_search_validate()) { - - ret = DB_ERROR; - } - - /* Restore the fatal lock wait timeout after CHECK TABLE. */ - mutex_enter(&kernel_mutex); - srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */ - mutex_exit(&kernel_mutex); - - prebuilt->trx->op_info = ""; - - return(ret); -} - -/*********************************************************************//** Determines if a table is a magic monitor table. @return TRUE if monitor table */ UNIV_INTERN diff --git a/storage/innobase/row/row0purge.c b/storage/innobase/row/row0purge.c index 500ebe571ab..da9d31f333f 100644 --- a/storage/innobase/row/row0purge.c +++ b/storage/innobase/row/row0purge.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved. 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 @@ -215,33 +215,71 @@ retry: } /***********************************************************//** -Removes a secondary index entry if possible. +Determines if it is possible to remove a secondary index entry. +Removal is possible if the secondary index entry does not refer to any +not delete marked version of a clustered index record where DB_TRX_ID +is newer than the purge view. + +NOTE: This function should only be called by the purge thread, only +while holding a latch on the leaf page of the secondary index entry +(or keeping the buffer pool watch on the page). It is possible that +this function first returns TRUE and then FALSE, if a user transaction +inserts a record that the secondary index entry would refer to. +However, in that case, the user transaction would also re-insert the +secondary index entry after purge has removed it and released the leaf +page latch. +@return TRUE if the secondary index record can be purged */ +UNIV_INTERN +ibool +row_purge_poss_sec( +/*===============*/ + purge_node_t* node, /*!< in/out: row purge node */ + dict_index_t* index, /*!< in: secondary index */ + const dtuple_t* entry) /*!< in: secondary index entry */ +{ + ibool can_delete; + mtr_t mtr; + + ut_ad(!dict_index_is_clust(index)); + mtr_start(&mtr); + + can_delete = !row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr) + || !row_vers_old_has_index_entry(TRUE, + btr_pcur_get_rec(&node->pcur), + &mtr, index, entry); + + btr_pcur_commit_specify_mtr(&node->pcur, &mtr); + + return(can_delete); +} + +/*************************************************************** +Removes a secondary index entry if possible, by modifying the +index tree. Does not try to buffer the delete. @return TRUE if success or if not found */ static ibool -row_purge_remove_sec_if_poss_low( -/*=============================*/ +row_purge_remove_sec_if_poss_tree( +/*==============================*/ purge_node_t* node, /*!< in: row purge node */ dict_index_t* index, /*!< in: index */ - const dtuple_t* entry, /*!< in: index entry */ - ulint mode) /*!< in: latch mode BTR_MODIFY_LEAF or - BTR_MODIFY_TREE */ + const dtuple_t* entry) /*!< in: index entry */ { - btr_pcur_t pcur; - btr_cur_t* btr_cur; - ibool success; - ibool old_has = 0; /* remove warning */ - ibool found; - ulint err; - mtr_t mtr; - mtr_t mtr_vers; + btr_pcur_t pcur; + btr_cur_t* btr_cur; + ibool success = TRUE; + ulint err; + mtr_t mtr; + enum row_search_result search_result; log_free_check(); mtr_start(&mtr); - found = row_search_index_entry(index, entry, mode, &pcur, &mtr); + search_result = row_search_index_entry(index, entry, BTR_MODIFY_TREE, + &pcur, &mtr); - if (!found) { + switch (search_result) { + case ROW_NOT_FOUND: /* Not found. This is a legitimate condition. In a rollback, InnoDB will remove secondary recs that would be purged anyway. Then the actual purge will not find @@ -254,11 +292,15 @@ row_purge_remove_sec_if_poss_low( /* fputs("PURGE:........sec entry not found\n", stderr); */ /* dtuple_print(stderr, entry); */ - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(TRUE); + goto func_exit; + case ROW_FOUND: + break; + case ROW_BUFFERED: + case ROW_NOT_DELETED_REF: + /* These are invalid outcomes, because the mode passed + to row_search_index_entry() did not include any of the + flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */ + ut_error; } btr_cur = btr_pcur_get_btr_cur(&pcur); @@ -267,38 +309,102 @@ row_purge_remove_sec_if_poss_low( which cannot be purged yet, requires its existence. If some requires, we should do nothing. */ - mtr_start(&mtr_vers); - - success = row_purge_reposition_pcur(BTR_SEARCH_LEAF, node, &mtr_vers); - - if (success) { - old_has = row_vers_old_has_index_entry( - TRUE, btr_pcur_get_rec(&(node->pcur)), - &mtr_vers, index, entry); - } - - btr_pcur_commit_specify_mtr(&(node->pcur), &mtr_vers); + if (row_purge_poss_sec(node, index, entry)) { + /* Remove the index record, which should have been + marked for deletion. */ + ut_ad(REC_INFO_DELETED_FLAG + & rec_get_info_bits(btr_cur_get_rec(btr_cur), + dict_table_is_comp(index->table))); - if (!success || !old_has) { - /* Remove the index record */ - - if (mode == BTR_MODIFY_LEAF) { - success = btr_cur_optimistic_delete(btr_cur, &mtr); - } else { - ut_ad(mode == BTR_MODIFY_TREE); - btr_cur_pessimistic_delete(&err, FALSE, btr_cur, - RB_NONE, &mtr); - success = err == DB_SUCCESS; - ut_a(success || err == DB_OUT_OF_FILE_SPACE); + btr_cur_pessimistic_delete(&err, FALSE, btr_cur, + RB_NONE, &mtr); + switch (UNIV_EXPECT(err, DB_SUCCESS)) { + case DB_SUCCESS: + break; + case DB_OUT_OF_FILE_SPACE: + success = FALSE; + break; + default: + ut_error; } } +func_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); return(success); } +/*************************************************************** +Removes a secondary index entry without modifying the index tree, +if possible. +@return TRUE if success or if not found */ +static +ibool +row_purge_remove_sec_if_poss_leaf( +/*==============================*/ + purge_node_t* node, /*!< in: row purge node */ + dict_index_t* index, /*!< in: index */ + const dtuple_t* entry) /*!< in: index entry */ +{ + mtr_t mtr; + btr_pcur_t pcur; + enum row_search_result search_result; + + log_free_check(); + + mtr_start(&mtr); + + /* Set the purge node for the call to row_purge_poss_sec(). */ + pcur.btr_cur.purge_node = node; + /* Set the query thread, so that ibuf_insert_low() will be + able to invoke thd_get_trx(). */ + pcur.btr_cur.thr = que_node_get_parent(node); + + search_result = row_search_index_entry( + index, entry, BTR_MODIFY_LEAF | BTR_DELETE, &pcur, &mtr); + + switch (search_result) { + ibool success; + case ROW_FOUND: + /* Before attempting to purge a record, check + if it is safe to do so. */ + if (row_purge_poss_sec(node, index, entry)) { + btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur); + + /* Only delete-marked records should be purged. */ + ut_ad(REC_INFO_DELETED_FLAG + & rec_get_info_bits( + btr_cur_get_rec(btr_cur), + dict_table_is_comp(index->table))); + + if (!btr_cur_optimistic_delete(btr_cur, &mtr)) { + + /* The index entry could not be deleted. */ + success = FALSE; + goto func_exit; + } + } + /* fall through (the index entry is still needed, + or the deletion succeeded) */ + case ROW_NOT_DELETED_REF: + /* The index entry is still needed. */ + case ROW_BUFFERED: + /* The deletion was buffered. */ + case ROW_NOT_FOUND: + /* The index entry does not exist, nothing to do. */ + success = TRUE; + func_exit: + btr_pcur_close(&pcur); + mtr_commit(&mtr); + return(success); + } + + ut_error; + return(FALSE); +} + /***********************************************************//** Removes a secondary index entry if possible. */ UNIV_INLINE @@ -314,15 +420,12 @@ row_purge_remove_sec_if_poss( /* fputs("Purge: Removing secondary record\n", stderr); */ - success = row_purge_remove_sec_if_poss_low(node, index, entry, - BTR_MODIFY_LEAF); - if (success) { + if (row_purge_remove_sec_if_poss_leaf(node, index, entry)) { return; } retry: - success = row_purge_remove_sec_if_poss_low(node, index, entry, - BTR_MODIFY_TREE); + success = row_purge_remove_sec_if_poss_tree(node, index, entry); /* The delete operation may fail if we have little file space left: TODO: easiest to crash the database and restart with more file space */ diff --git a/storage/innobase/row/row0row.c b/storage/innobase/row/row0row.c index 128ac3ba3e8..6cdfa410c15 100644 --- a/storage/innobase/row/row0row.c +++ b/storage/innobase/row/row0row.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -730,9 +730,9 @@ row_get_clust_rec( /***************************************************************//** Searches an index record. -@return TRUE if found */ +@return whether the record was found or buffered */ UNIV_INTERN -ibool +enum row_search_result row_search_index_entry( /*===================*/ dict_index_t* index, /*!< in: index */ @@ -749,13 +749,38 @@ row_search_index_entry( ut_ad(dtuple_check_typed(entry)); btr_pcur_open(index, entry, PAGE_CUR_LE, mode, pcur, mtr); + + switch (btr_pcur_get_btr_cur(pcur)->flag) { + case BTR_CUR_DELETE_REF: + ut_a(mode & BTR_DELETE); + return(ROW_NOT_DELETED_REF); + + case BTR_CUR_DEL_MARK_IBUF: + case BTR_CUR_DELETE_IBUF: + case BTR_CUR_INSERT_TO_IBUF: + return(ROW_BUFFERED); + + case BTR_CUR_HASH: + case BTR_CUR_HASH_FAIL: + case BTR_CUR_BINARY: + break; + } + low_match = btr_pcur_get_low_match(pcur); rec = btr_pcur_get_rec(pcur); n_fields = dtuple_get_n_fields(entry); - return(!page_rec_is_infimum(rec) && low_match == n_fields); + if (page_rec_is_infimum(rec)) { + + return(ROW_NOT_FOUND); + } else if (low_match != n_fields) { + + return(ROW_NOT_FOUND); + } + + return(ROW_FOUND); } #include <my_sys.h> @@ -915,6 +940,10 @@ row_raw_format( ret = row_raw_format_int(data, data_len, prtype, buf, buf_size, &format_in_hex); + if (format_in_hex) { + + goto format_in_hex; + } break; case DATA_CHAR: case DATA_VARCHAR: @@ -923,14 +952,15 @@ row_raw_format( ret = row_raw_format_str(data, data_len, prtype, buf, buf_size, &format_in_hex); + if (format_in_hex) { + + goto format_in_hex; + } + break; /* XXX support more data types */ default: - - format_in_hex = TRUE; - } - - if (format_in_hex) { + format_in_hex: if (UNIV_LIKELY(buf_size > 2)) { diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index 3ef9726588e..a5bf361661b 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -132,7 +132,8 @@ index record. NOTE: the comparison is NOT done as a binary comparison, but character fields are compared with collation! @return TRUE if the secondary record is equal to the corresponding -fields in the clustered record, when compared with collation */ +fields in the clustered record, when compared with collation; +FALSE if not equal or if the clustered record has been marked for deletion */ static ibool row_sel_sec_rec_is_for_clust_rec( @@ -431,10 +432,6 @@ row_sel_fetch_columns( data = rec_get_nth_field(rec, offsets, field_no, &len); - if (len == UNIV_SQL_NULL) { - len = UNIV_SQL_NULL; - } - needs_copy = column->copy_val; } @@ -855,7 +852,7 @@ row_sel_get_clust_rec( trx = thr_get_trx(thr); if (srv_locks_unsafe_for_binlog - || trx->isolation_level == TRX_ISO_READ_COMMITTED) { + || trx->isolation_level <= TRX_ISO_READ_COMMITTED) { lock_type = LOCK_REC_NOT_GAP; } else { lock_type = LOCK_ORDINARY; @@ -866,8 +863,14 @@ row_sel_get_clust_rec( clust_rec, index, offsets, node->row_lock_mode, lock_type, thr); - if (err != DB_SUCCESS) { - + switch (err) { + case DB_SUCCESS: + case DB_SUCCESS_LOCKED_REC: + /* Declare the variable uninitialized in Valgrind. + It should be set to DB_SUCCESS at func_exit. */ + UNIV_MEM_INVALID(&err, sizeof err); + break; + default: goto err_exit; } } else { @@ -937,9 +940,9 @@ err_exit: /*********************************************************************//** Sets a lock on a record. -@return DB_SUCCESS or error code */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */ UNIV_INLINE -ulint +enum db_err sel_set_rec_lock( /*=============*/ const buf_block_t* block, /*!< in: buffer block of rec */ @@ -951,8 +954,8 @@ sel_set_rec_lock( LOC_REC_NOT_GAP */ que_thr_t* thr) /*!< in: query thread */ { - trx_t* trx; - ulint err; + trx_t* trx; + enum db_err err; trx = thr_get_trx(thr); @@ -1468,7 +1471,7 @@ rec_loop: if (srv_locks_unsafe_for_binlog || trx->isolation_level - == TRX_ISO_READ_COMMITTED) { + <= TRX_ISO_READ_COMMITTED) { if (page_rec_is_supremum(next_rec)) { @@ -1485,11 +1488,15 @@ rec_loop: node->row_lock_mode, lock_type, thr); - if (err != DB_SUCCESS) { + switch (err) { + case DB_SUCCESS_LOCKED_REC: + err = DB_SUCCESS; + case DB_SUCCESS: + break; + default: /* Note that in this case we will store in pcur the PREDECESSOR of the record we are waiting the lock for */ - goto lock_wait_or_error; } } @@ -1525,7 +1532,7 @@ skip_lock: trx = thr_get_trx(thr); if (srv_locks_unsafe_for_binlog - || trx->isolation_level == TRX_ISO_READ_COMMITTED) { + || trx->isolation_level <= TRX_ISO_READ_COMMITTED) { if (page_rec_is_supremum(rec)) { @@ -1541,8 +1548,12 @@ skip_lock: rec, index, offsets, node->row_lock_mode, lock_type, thr); - if (err != DB_SUCCESS) { - + switch (err) { + case DB_SUCCESS_LOCKED_REC: + err = DB_SUCCESS; + case DB_SUCCESS: + break; + default: goto lock_wait_or_error; } } @@ -2170,36 +2181,6 @@ row_fetch_print( return((void*)42); } -/****************************************************************//** -Callback function for fetch that stores an unsigned 4 byte integer to the -location pointed. The column's type must be DATA_INT, DATA_UNSIGNED, length -= 4. -@return always returns NULL */ -UNIV_INTERN -void* -row_fetch_store_uint4( -/*==================*/ - void* row, /*!< in: sel_node_t* */ - void* user_arg) /*!< in: data pointer */ -{ - sel_node_t* node = row; - ib_uint32_t* val = user_arg; - ulint tmp; - - dfield_t* dfield = que_node_get_val(node->select_list); - const dtype_t* type = dfield_get_type(dfield); - ulint len = dfield_get_len(dfield); - - ut_a(dtype_get_mtype(type) == DATA_INT); - ut_a(dtype_get_prtype(type) & DATA_UNSIGNED); - ut_a(len == 4); - - tmp = mach_read_from_4(dfield_get_data(dfield)); - *val = (ib_uint32_t) tmp; - - return(NULL); -} - /***********************************************************//** Prints a row in a select result. @return query thread to run next or NULL */ @@ -2531,6 +2512,7 @@ row_sel_field_store_in_mysql_format( byte* pad_ptr; ut_ad(len != UNIV_SQL_NULL); + UNIV_MEM_ASSERT_RW(data, len); switch (templ->type) { case DATA_INT: @@ -2779,6 +2761,9 @@ row_sel_store_mysql_rec( /* MySQL assumes that the field for an SQL NULL value is set to the default value. */ + UNIV_MEM_ASSERT_RW(prebuilt->default_rec + + templ->mysql_col_offset, + templ->mysql_col_len); mysql_rec[templ->mysql_null_byte_offset] |= (byte) templ->mysql_null_bit_mask; memcpy(mysql_rec + templ->mysql_col_offset, @@ -2830,9 +2815,9 @@ row_sel_build_prev_vers_for_mysql( Retrieves the clustered index record corresponding to a record in a non-clustered index. Does the necessary locking. Used in the MySQL interface. -@return DB_SUCCESS or error code */ +@return DB_SUCCESS, DB_SUCCESS_LOCKED_REC, or error code */ static -ulint +enum db_err row_sel_get_clust_rec_for_mysql( /*============================*/ row_prebuilt_t* prebuilt,/*!< in: prebuilt struct in the handle */ @@ -2859,7 +2844,7 @@ row_sel_get_clust_rec_for_mysql( dict_index_t* clust_index; const rec_t* clust_rec; rec_t* old_vers; - ulint err; + enum db_err err; trx_t* trx; *out_rec = NULL; @@ -2918,6 +2903,7 @@ row_sel_get_clust_rec_for_mysql( clust_rec = NULL; + err = DB_SUCCESS; goto func_exit; } @@ -2933,8 +2919,11 @@ row_sel_get_clust_rec_for_mysql( 0, btr_pcur_get_block(prebuilt->clust_pcur), clust_rec, clust_index, *offsets, prebuilt->select_lock_type, LOCK_REC_NOT_GAP, thr); - if (err != DB_SUCCESS) { - + switch (err) { + case DB_SUCCESS: + case DB_SUCCESS_LOCKED_REC: + break; + default: goto err_exit; } } else { @@ -2981,6 +2970,7 @@ row_sel_get_clust_rec_for_mysql( if (clust_rec && (old_vers + || trx->isolation_level <= TRX_ISO_READ_UNCOMMITTED || rec_get_deleted_flag(rec, dict_table_is_comp( sec_index->table))) && !row_sel_sec_rec_is_for_clust_rec( @@ -2993,6 +2983,8 @@ row_sel_get_clust_rec_for_mysql( rec, sec_index, clust_rec, clust_index)); #endif } + + err = DB_SUCCESS; } func_exit: @@ -3005,7 +2997,6 @@ func_exit: btr_pcur_store_position(prebuilt->clust_pcur, mtr); } - err = DB_SUCCESS; err_exit: return(err); } @@ -3102,6 +3093,11 @@ row_sel_pop_cached_row_for_mysql( for (i = 0; i < prebuilt->n_template; i++) { templ = prebuilt->mysql_template + i; +#if 0 /* Some of the cached_rec may legitimately be uninitialized. */ + UNIV_MEM_ASSERT_RW(cached_rec + + templ->mysql_col_offset, + templ->mysql_col_len); +#endif ut_memcpy(buf + templ->mysql_col_offset, cached_rec + templ->mysql_col_offset, templ->mysql_col_len); @@ -3116,6 +3112,11 @@ row_sel_pop_cached_row_for_mysql( } } else { +#if 0 /* Some of the cached_rec may legitimately be uninitialized. */ + UNIV_MEM_ASSERT_RW(prebuilt->fetch_cache + [prebuilt->fetch_cache_first], + prebuilt->mysql_prefix_len); +#endif ut_memcpy(buf, prebuilt->fetch_cache[prebuilt->fetch_cache_first], prebuilt->mysql_prefix_len); @@ -3166,6 +3167,8 @@ row_sel_push_cache_row_for_mysql( } ut_ad(prebuilt->fetch_cache_first == 0); + UNIV_MEM_INVALID(prebuilt->fetch_cache[prebuilt->n_fetch_cached], + prebuilt->mysql_row_len); if (UNIV_UNLIKELY(!row_sel_store_mysql_rec( prebuilt->fetch_cache[ @@ -3202,14 +3205,17 @@ row_sel_try_search_shortcut_for_mysql( ut_ad(dict_index_is_clust(index)); ut_ad(!prebuilt->templ_contains_blob); +#ifndef UNIV_SEARCH_DEBUG btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, pcur, -#ifndef UNIV_SEARCH_DEBUG RW_S_LATCH, -#else + mtr); +#else /* UNIV_SEARCH_DEBUG */ + btr_pcur_open_with_no_init(index, search_tuple, PAGE_CUR_GE, + BTR_SEARCH_LEAF, pcur, 0, -#endif mtr); +#endif /* UNIV_SEARCH_DEBUG */ rec = btr_pcur_get_rec(pcur); if (!page_rec_is_user_rec(rec)) { @@ -3624,6 +3630,13 @@ shortcut_fails_too_big_rec: trx->has_search_latch = FALSE; } + ut_ad(prebuilt->sql_stat_start || trx->conc_state == TRX_ACTIVE); + ut_ad(trx->conc_state == TRX_NOT_STARTED + || trx->conc_state == TRX_ACTIVE); + ut_ad(prebuilt->sql_stat_start + || prebuilt->select_lock_type != LOCK_NONE + || trx->read_view); + trx_start_if_not_started(trx); if (trx->isolation_level <= TRX_ISO_READ_COMMITTED @@ -3694,7 +3707,7 @@ shortcut_fails_too_big_rec: && !page_rec_is_supremum(rec) && set_also_gap_locks && !(srv_locks_unsafe_for_binlog - || trx->isolation_level == TRX_ISO_READ_COMMITTED) + || trx->isolation_level <= TRX_ISO_READ_COMMITTED) && prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a gap lock on the next index record @@ -3708,8 +3721,12 @@ shortcut_fails_too_big_rec: prebuilt->select_lock_type, LOCK_GAP, thr); - if (err != DB_SUCCESS) { - + switch (err) { + case DB_SUCCESS_LOCKED_REC: + err = DB_SUCCESS; + case DB_SUCCESS: + break; + default: goto lock_wait_or_error; } } @@ -3790,7 +3807,7 @@ rec_loop: if (set_also_gap_locks && !(srv_locks_unsafe_for_binlog - || trx->isolation_level == TRX_ISO_READ_COMMITTED) + || trx->isolation_level <= TRX_ISO_READ_COMMITTED) && prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a lock on the index record */ @@ -3807,8 +3824,12 @@ rec_loop: prebuilt->select_lock_type, LOCK_ORDINARY, thr); - if (err != DB_SUCCESS) { - + switch (err) { + case DB_SUCCESS_LOCKED_REC: + err = DB_SUCCESS; + case DB_SUCCESS: + break; + default: goto lock_wait_or_error; } } @@ -3924,7 +3945,7 @@ wrong_offs: if (set_also_gap_locks && !(srv_locks_unsafe_for_binlog || trx->isolation_level - == TRX_ISO_READ_COMMITTED) + <= TRX_ISO_READ_COMMITTED) && prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a gap lock on the index @@ -3938,8 +3959,11 @@ wrong_offs: prebuilt->select_lock_type, LOCK_GAP, thr); - if (err != DB_SUCCESS) { - + switch (err) { + case DB_SUCCESS_LOCKED_REC: + case DB_SUCCESS: + break; + default: goto lock_wait_or_error; } } @@ -3960,7 +3984,7 @@ wrong_offs: if (set_also_gap_locks && !(srv_locks_unsafe_for_binlog || trx->isolation_level - == TRX_ISO_READ_COMMITTED) + <= TRX_ISO_READ_COMMITTED) && prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a gap lock on the index @@ -3974,8 +3998,11 @@ wrong_offs: prebuilt->select_lock_type, LOCK_GAP, thr); - if (err != DB_SUCCESS) { - + switch (err) { + case DB_SUCCESS_LOCKED_REC: + case DB_SUCCESS: + break; + default: goto lock_wait_or_error; } } @@ -4008,7 +4035,7 @@ wrong_offs: if (!set_also_gap_locks || srv_locks_unsafe_for_binlog - || trx->isolation_level == TRX_ISO_READ_COMMITTED + || trx->isolation_level <= TRX_ISO_READ_COMMITTED || (unique_search && !UNIV_UNLIKELY(rec_get_deleted_flag(rec, comp)))) { @@ -4045,17 +4072,24 @@ no_gap_lock: switch (err) { const rec_t* old_vers; - case DB_SUCCESS: + case DB_SUCCESS_LOCKED_REC: if (srv_locks_unsafe_for_binlog - || trx->isolation_level == TRX_ISO_READ_COMMITTED) { + || trx->isolation_level + <= TRX_ISO_READ_COMMITTED) { /* Note that a record of prebuilt->index was locked. */ prebuilt->new_rec_locks = 1; } + err = DB_SUCCESS; + case DB_SUCCESS: break; case DB_LOCK_WAIT: + /* Never unlock rows that were part of a conflict. */ + prebuilt->new_rec_locks = 0; + if (UNIV_LIKELY(prebuilt->row_read_type != ROW_READ_TRY_SEMI_CONSISTENT) + || unique_search || index != clust_index) { goto lock_wait_or_error; @@ -4082,7 +4116,6 @@ no_gap_lock: if (UNIV_LIKELY(trx->wait_lock != NULL)) { lock_cancel_waiting_and_release( trx->wait_lock); - prebuilt->new_rec_locks = 0; } else { mutex_exit(&kernel_mutex); @@ -4094,9 +4127,6 @@ no_gap_lock: ULINT_UNDEFINED, &heap); err = DB_SUCCESS; - /* Note that a record of - prebuilt->index was locked. */ - prebuilt->new_rec_locks = 1; break; } mutex_exit(&kernel_mutex); @@ -4179,7 +4209,7 @@ no_gap_lock: /* The record is delete-marked: we can skip it */ if ((srv_locks_unsafe_for_binlog - || trx->isolation_level == TRX_ISO_READ_COMMITTED) + || trx->isolation_level <= TRX_ISO_READ_COMMITTED) && prebuilt->select_lock_type != LOCK_NONE && !did_semi_consistent_read) { @@ -4233,33 +4263,36 @@ requires_clust_rec: err = row_sel_get_clust_rec_for_mysql(prebuilt, index, rec, thr, &clust_rec, &offsets, &heap, &mtr); - if (err != DB_SUCCESS) { + switch (err) { + case DB_SUCCESS: + if (clust_rec == NULL) { + /* The record did not exist in the read view */ + ut_ad(prebuilt->select_lock_type == LOCK_NONE); + goto next_rec; + } + break; + case DB_SUCCESS_LOCKED_REC: + ut_a(clust_rec != NULL); + if (srv_locks_unsafe_for_binlog + || trx->isolation_level + <= TRX_ISO_READ_COMMITTED) { + /* Note that the clustered index record + was locked. */ + prebuilt->new_rec_locks = 2; + } + err = DB_SUCCESS; + break; + default: goto lock_wait_or_error; } - if (clust_rec == NULL) { - /* The record did not exist in the read view */ - ut_ad(prebuilt->select_lock_type == LOCK_NONE); - - goto next_rec; - } - - if ((srv_locks_unsafe_for_binlog - || trx->isolation_level == TRX_ISO_READ_COMMITTED) - && prebuilt->select_lock_type != LOCK_NONE) { - /* Note that both the secondary index record - and the clustered index record were locked. */ - ut_ad(prebuilt->new_rec_locks == 1); - prebuilt->new_rec_locks = 2; - } - if (UNIV_UNLIKELY(rec_get_deleted_flag(clust_rec, comp))) { /* The record is delete marked: we can skip it */ if ((srv_locks_unsafe_for_binlog - || trx->isolation_level == TRX_ISO_READ_COMMITTED) + || trx->isolation_level <= TRX_ISO_READ_COMMITTED) && prebuilt->select_lock_type != LOCK_NONE) { /* No need to keep a lock on a delete-marked @@ -4470,7 +4503,7 @@ lock_wait_or_error: moves_up, &mtr); if ((srv_locks_unsafe_for_binlog - || trx->isolation_level == TRX_ISO_READ_COMMITTED) + || trx->isolation_level <= TRX_ISO_READ_COMMITTED) && !same_user_rec) { /* Since we were not able to restore the cursor @@ -4616,6 +4649,7 @@ row_search_autoinc_read_column( dict_index_t* index, /*!< in: index to read from */ const rec_t* rec, /*!< in: current rec */ ulint col_no, /*!< in: column number */ + ulint mtype, /*!< in: column main type */ ibool unsigned_type) /*!< in: signed or unsigned flag */ { ulint len; @@ -4632,10 +4666,26 @@ row_search_autoinc_read_column( data = rec_get_nth_field(rec, offsets, col_no, &len); ut_a(len != UNIV_SQL_NULL); - ut_a(len <= sizeof value); - /* we assume AUTOINC value cannot be negative */ - value = mach_read_int_type(data, len, unsigned_type); + switch (mtype) { + case DATA_INT: + ut_a(len <= sizeof value); + value = mach_read_int_type(data, len, unsigned_type); + break; + + case DATA_FLOAT: + ut_a(len == sizeof(float)); + value = (ib_uint64_t) mach_float_read(data); + break; + + case DATA_DOUBLE: + ut_a(len == sizeof(double)); + value = (ib_uint64_t) mach_double_read(data); + break; + + default: + ut_error; + } if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); @@ -4721,7 +4771,8 @@ row_search_max_autoinc( dfield->col->prtype & DATA_UNSIGNED); *value = row_search_autoinc_read_column( - index, rec, i, unsigned_type); + index, rec, i, + dfield->col->mtype, unsigned_type); } } diff --git a/storage/innobase/row/row0uins.c b/storage/innobase/row/row0uins.c index 9f9c814f1a5..c35f1ef7a44 100644 --- a/storage/innobase/row/row0uins.c +++ b/storage/innobase/row/row0uins.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved. 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 @@ -145,37 +145,39 @@ row_undo_ins_remove_sec_low( dict_index_t* index, /*!< in: index */ dtuple_t* entry) /*!< in: index entry to remove */ { - btr_pcur_t pcur; - btr_cur_t* btr_cur; - ibool found; - ibool success; - ulint err; - mtr_t mtr; + btr_pcur_t pcur; + btr_cur_t* btr_cur; + ulint err; + mtr_t mtr; + enum row_search_result search_result; log_free_check(); mtr_start(&mtr); - found = row_search_index_entry(index, entry, mode, &pcur, &mtr); - btr_cur = btr_pcur_get_btr_cur(&pcur); - if (!found) { - /* Not found */ - - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(DB_SUCCESS); + ut_ad(mode == BTR_MODIFY_TREE || mode == BTR_MODIFY_LEAF); + + search_result = row_search_index_entry(index, entry, mode, + &pcur, &mtr); + + switch (search_result) { + case ROW_NOT_FOUND: + err = DB_SUCCESS; + goto func_exit; + case ROW_FOUND: + break; + case ROW_BUFFERED: + case ROW_NOT_DELETED_REF: + /* These are invalid outcomes, because the mode passed + to row_search_index_entry() did not include any of the + flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */ + ut_error; } if (mode == BTR_MODIFY_LEAF) { - success = btr_cur_optimistic_delete(btr_cur, &mtr); - - if (success) { - err = DB_SUCCESS; - } else { - err = DB_FAIL; - } + err = btr_cur_optimistic_delete(btr_cur, &mtr) + ? DB_SUCCESS : DB_FAIL; } else { ut_ad(mode == BTR_MODIFY_TREE); @@ -188,7 +190,7 @@ row_undo_ins_remove_sec_low( btr_cur_pessimistic_delete(&err, FALSE, btr_cur, RB_NORMAL, &mtr); } - +func_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); diff --git a/storage/innobase/row/row0umod.c b/storage/innobase/row/row0umod.c index 6be475d8c78..75de18a0b7d 100644 --- a/storage/innobase/row/row0umod.c +++ b/storage/innobase/row/row0umod.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1997, 2010, Innobase Oy. All Rights Reserved. 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 @@ -144,13 +144,17 @@ row_undo_mod_clust_low( /***********************************************************//** Removes a clustered index record after undo if possible. +This is attempted when the record was inserted by updating a +delete-marked record and there no longer exist transactions +that would see the delete-marked record. In other words, we +roll back the insert by purging the record. @return DB_SUCCESS, DB_FAIL, or error code: we may run out of file space */ static ulint row_undo_mod_remove_clust_low( /*==========================*/ undo_node_t* node, /*!< in: row undo node */ - que_thr_t* thr __attribute__((unused)), /*!< in: query thread */ + que_thr_t* thr, /*!< in: query thread */ mtr_t* mtr, /*!< in: mtr */ ulint mode) /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE */ { @@ -159,6 +163,7 @@ row_undo_mod_remove_clust_low( ulint err; ibool success; + ut_ad(node->rec_type == TRX_UNDO_UPD_DEL_REC); pcur = &(node->pcur); btr_cur = btr_pcur_get_btr_cur(pcur); @@ -190,11 +195,13 @@ row_undo_mod_remove_clust_low( } else { ut_ad(mode == BTR_MODIFY_TREE); - /* Note that since this operation is analogous to purge, - we can free also inherited externally stored fields: - hence the RB_NONE in the call below */ + /* This operation is analogous to purge, we can free also + inherited externally stored fields */ - btr_cur_pessimistic_delete(&err, FALSE, btr_cur, RB_NONE, mtr); + btr_cur_pessimistic_delete(&err, FALSE, btr_cur, + thr_is_recv(thr) + ? RB_RECOVERY_PURGE_REC + : RB_NONE, mtr); /* The delete operation may fail if we have little file space left: TODO: easiest to crash the database @@ -307,23 +314,27 @@ row_undo_mod_del_mark_or_remove_sec_low( ulint mode) /*!< in: latch mode BTR_MODIFY_LEAF or BTR_MODIFY_TREE */ { - ibool found; - btr_pcur_t pcur; - btr_cur_t* btr_cur; - ibool success; - ibool old_has; - ulint err; - mtr_t mtr; - mtr_t mtr_vers; + btr_pcur_t pcur; + btr_cur_t* btr_cur; + ibool success; + ibool old_has; + ulint err; + mtr_t mtr; + mtr_t mtr_vers; + enum row_search_result search_result; log_free_check(); mtr_start(&mtr); - found = row_search_index_entry(index, entry, mode, &pcur, &mtr); - btr_cur = btr_pcur_get_btr_cur(&pcur); - if (!found) { + ut_ad(mode == BTR_MODIFY_TREE || mode == BTR_MODIFY_LEAF); + + search_result = row_search_index_entry(index, entry, mode, + &pcur, &mtr); + + switch (UNIV_EXPECT(search_result, ROW_FOUND)) { + case ROW_NOT_FOUND: /* In crash recovery, the secondary index record may be missing if the UPDATE did not have time to insert the secondary index records before the crash. When we @@ -334,10 +345,16 @@ row_undo_mod_del_mark_or_remove_sec_low( before it has inserted all updated secondary index records, then the undo will not find those records. */ - btr_pcur_close(&pcur); - mtr_commit(&mtr); - - return(DB_SUCCESS); + err = DB_SUCCESS; + goto func_exit; + case ROW_FOUND: + break; + case ROW_BUFFERED: + case ROW_NOT_DELETED_REF: + /* These are invalid outcomes, because the mode passed + to row_search_index_entry() did not include any of the + flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */ + ut_error; } /* We should remove the index record if no prior version of the row, @@ -370,10 +387,11 @@ row_undo_mod_del_mark_or_remove_sec_low( } else { ut_ad(mode == BTR_MODIFY_TREE); - /* No need to distinguish RB_RECOVERY here, because we - are deleting a secondary index record: the distinction - between RB_NORMAL and RB_RECOVERY only matters when - deleting a record that contains externally stored + /* No need to distinguish RB_RECOVERY_PURGE here, + because we are deleting a secondary index record: + the distinction between RB_NORMAL and + RB_RECOVERY_PURGE only matters when deleting a + record that contains externally stored columns. */ ut_ad(!dict_index_is_clust(index)); btr_cur_pessimistic_delete(&err, FALSE, btr_cur, @@ -386,6 +404,8 @@ row_undo_mod_del_mark_or_remove_sec_low( } btr_pcur_commit_specify_mtr(&(node->pcur), &mtr_vers); + +func_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); @@ -438,15 +458,17 @@ row_undo_mod_del_unmark_sec_and_undo_update( BTR_MODIFY_TREE */ que_thr_t* thr, /*!< in: query thread */ dict_index_t* index, /*!< in: index */ - dtuple_t* entry) /*!< in: index entry */ + const dtuple_t* entry) /*!< in: index entry */ { - mem_heap_t* heap; - btr_pcur_t pcur; - upd_t* update; - ulint err = DB_SUCCESS; - big_rec_t* dummy_big_rec; - mtr_t mtr; - trx_t* trx = thr_get_trx(thr); + mem_heap_t* heap; + btr_pcur_t pcur; + btr_cur_t* btr_cur; + upd_t* update; + ulint err = DB_SUCCESS; + big_rec_t* dummy_big_rec; + mtr_t mtr; + trx_t* trx = thr_get_trx(thr); + enum row_search_result search_result; /* Ignore indexes that are being created. */ if (UNIV_UNLIKELY(*index->name == TEMP_INDEX_PREFIX)) { @@ -457,8 +479,19 @@ row_undo_mod_del_unmark_sec_and_undo_update( log_free_check(); mtr_start(&mtr); - if (UNIV_UNLIKELY(!row_search_index_entry(index, entry, - mode, &pcur, &mtr))) { + ut_ad(mode == BTR_MODIFY_TREE || mode == BTR_MODIFY_LEAF); + + search_result = row_search_index_entry(index, entry, mode, + &pcur, &mtr); + + switch (search_result) { + case ROW_BUFFERED: + case ROW_NOT_DELETED_REF: + /* These are invalid outcomes, because the mode passed + to row_search_index_entry() did not include any of the + flags BTR_INSERT, BTR_DELETE, or BTR_DELETE_MARK. */ + ut_error; + case ROW_NOT_FOUND: fputs("InnoDB: error in sec index entry del undo in\n" "InnoDB: ", stderr); dict_index_name_print(stderr, trx, index); @@ -473,9 +506,9 @@ row_undo_mod_del_unmark_sec_and_undo_update( fputs("\n" "InnoDB: Submit a detailed bug report" " to http://bugs.mysql.com\n", stderr); - } else { - btr_cur_t* btr_cur = btr_pcur_get_btr_cur(&pcur); - + break; + case ROW_FOUND: + btr_cur = btr_pcur_get_btr_cur(&pcur); err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG, btr_cur, FALSE, thr, &mtr); ut_a(err == DB_SUCCESS); @@ -533,6 +566,7 @@ row_undo_mod_upd_del_sec( dict_index_t* index; ulint err = DB_SUCCESS; + ut_ad(node->rec_type == TRX_UNDO_UPD_DEL_REC); heap = mem_heap_create(1024); while (node->index != NULL) { @@ -550,7 +584,7 @@ row_undo_mod_upd_del_sec( does not exist. However, this situation may only occur during the rollback of incomplete transactions. */ - ut_a(trx_is_recv(thr_get_trx(thr))); + ut_a(thr_is_recv(thr)); } else { err = row_undo_mod_del_mark_or_remove_sec( node, thr, index, entry); @@ -648,24 +682,55 @@ row_undo_mod_upd_exist_sec( /* Build the newest version of the index entry */ entry = row_build_index_entry(node->row, node->ext, index, heap); - ut_a(entry); - /* NOTE that if we updated the fields of a - delete-marked secondary index record so that - alphabetically they stayed the same, e.g., - 'abc' -> 'aBc', we cannot return to the original - values because we do not know them. But this should - not cause problems because in row0sel.c, in queries - we always retrieve the clustered index record or an - earlier version of it, if the secondary index record - through which we do the search is delete-marked. */ - - err = row_undo_mod_del_mark_or_remove_sec(node, thr, - index, - entry); - if (err != DB_SUCCESS) { - mem_heap_free(heap); - - return(err); + if (UNIV_UNLIKELY(!entry)) { + /* The server must have crashed in + row_upd_clust_rec_by_insert(), in + row_ins_index_entry_low() before + btr_store_big_rec_extern_fields() + has written the externally stored columns + (BLOBs) of the new clustered index entry. */ + + /* The table must be in DYNAMIC or COMPRESSED + format. REDUNDANT and COMPACT formats + store a local 768-byte prefix of each + externally stored column. */ + ut_a(dict_table_get_format(index->table) + >= DICT_TF_FORMAT_ZIP); + + /* This is only legitimate when + rolling back an incomplete transaction + after crash recovery. */ + ut_a(thr_get_trx(thr)->is_recovered); + + /* The server must have crashed before + completing the insert of the new + clustered index entry and before + inserting to the secondary indexes. + Because node->row was not yet written + to this index, we can ignore it. But + we must restore node->undo_row. */ + } else { + /* NOTE that if we updated the fields of a + delete-marked secondary index record so that + alphabetically they stayed the same, e.g., + 'abc' -> 'aBc', we cannot return to the + original values because we do not know them. + But this should not cause problems because + in row0sel.c, in queries we always retrieve + the clustered index record or an earlier + version of it, if the secondary index record + through which we do the search is + delete-marked. */ + + err = row_undo_mod_del_mark_or_remove_sec( + node, thr, index, entry); + if (err != DB_SUCCESS) { + mem_heap_free(heap); + + return(err); + } + + mem_heap_empty(heap); } /* We may have to update the delete mark in the @@ -674,7 +739,6 @@ row_undo_mod_upd_exist_sec( the secondary index record if we updated its fields but alphabetically they stayed the same, e.g., 'abc' -> 'aBc'. */ - mem_heap_empty(heap); entry = row_build_index_entry(node->undo_row, node->undo_ext, index, heap); diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index 58dfd43ead9..f1a90a3bf1c 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -1344,9 +1344,6 @@ row_upd_copy_columns( data = rec_get_nth_field(rec, offsets, column->field_nos[SYM_CLUST_FIELD_NO], &len); - if (len == UNIV_SQL_NULL) { - len = UNIV_SQL_NULL; - } eval_node_copy_and_alloc_val(column, data, len); column = UT_LIST_GET_NEXT(col_var_list, column); @@ -1434,21 +1431,22 @@ row_upd_sec_index_entry( upd_node_t* node, /*!< in: row update node */ que_thr_t* thr) /*!< in: query thread */ { - ibool check_ref; - ibool found; - dict_index_t* index; - dtuple_t* entry; - btr_pcur_t pcur; - btr_cur_t* btr_cur; - mem_heap_t* heap; - rec_t* rec; - ulint err = DB_SUCCESS; - mtr_t mtr; - trx_t* trx = thr_get_trx(thr); + mtr_t mtr; + const rec_t* rec; + btr_pcur_t pcur; + mem_heap_t* heap; + dtuple_t* entry; + dict_index_t* index; + btr_cur_t* btr_cur; + ibool referenced; + ulint err = DB_SUCCESS; + trx_t* trx = thr_get_trx(thr); + ulint mode = BTR_MODIFY_LEAF; + enum row_search_result search_result; index = node->index; - check_ref = row_upd_index_is_referenced(index, trx); + referenced = row_upd_index_is_referenced(index, trx); heap = mem_heap_create(1024); @@ -1459,13 +1457,33 @@ row_upd_sec_index_entry( log_free_check(); mtr_start(&mtr); - found = row_search_index_entry(index, entry, BTR_MODIFY_LEAF, &pcur, - &mtr); + /* Set the query thread, so that ibuf_insert_low() will be + able to invoke thd_get_trx(). */ + btr_pcur_get_btr_cur(&pcur)->thr = thr; + + /* We can only try to use the insert/delete buffer to buffer + delete-mark operations if the index we're modifying has no foreign + key constraints referring to it. */ + if (!referenced) { + mode |= BTR_DELETE_MARK; + } + + search_result = row_search_index_entry(index, entry, mode, + &pcur, &mtr); + btr_cur = btr_pcur_get_btr_cur(&pcur); rec = btr_cur_get_rec(btr_cur); - if (UNIV_UNLIKELY(!found)) { + switch (search_result) { + case ROW_NOT_DELETED_REF: /* should only occur for BTR_DELETE */ + ut_error; + break; + case ROW_BUFFERED: + /* Entry was delete marked already. */ + break; + + case ROW_NOT_FOUND: fputs("InnoDB: error in sec index entry update in\n" "InnoDB: ", stderr); dict_index_name_print(stderr, trx, index); @@ -1482,20 +1500,26 @@ row_upd_sec_index_entry( fputs("\n" "InnoDB: Submit a detailed bug report" " to http://bugs.mysql.com\n", stderr); - } else { + break; + case ROW_FOUND: /* Delete mark the old index record; it can already be delete marked if we return after a lock wait in row_ins_index_entry below */ - if (!rec_get_deleted_flag(rec, - dict_table_is_comp(index->table))) { - err = btr_cur_del_mark_set_sec_rec(0, btr_cur, TRUE, - thr, &mtr); - if (err == DB_SUCCESS && check_ref) { + if (!rec_get_deleted_flag( + rec, dict_table_is_comp(index->table))) { + + err = btr_cur_del_mark_set_sec_rec( + 0, btr_cur, TRUE, thr, &mtr); + + if (err == DB_SUCCESS && referenced) { + + ulint* offsets; + + offsets = rec_get_offsets( + rec, index, NULL, ULINT_UNDEFINED, + &heap); - ulint* offsets = rec_get_offsets( - rec, index, NULL, - ULINT_UNDEFINED, &heap); /* NOTE that the following call loses the position of pcur ! */ err = row_upd_check_references_constraints( @@ -1503,6 +1527,7 @@ row_upd_sec_index_entry( index, offsets, thr, &mtr); } } + break; } btr_pcur_close(&pcur); @@ -1566,7 +1591,7 @@ row_upd_clust_rec_by_insert( upd_node_t* node, /*!< in: row update node */ dict_index_t* index, /*!< in: clustered index of the record */ que_thr_t* thr, /*!< in: query thread */ - ibool check_ref,/*!< in: TRUE if index may be referenced in + ibool referenced,/*!< in: TRUE if index may be referenced in a foreign key constraint */ mtr_t* mtr) /*!< in: mtr; gets committed here */ { @@ -1612,16 +1637,21 @@ row_upd_clust_rec_by_insert( btr_cur_mark_extern_inherited_fields( btr_cur_get_page_zip(btr_cur), rec, index, offsets, node->update, mtr); - if (check_ref) { + if (referenced) { /* NOTE that the following call loses the position of pcur ! */ + err = row_upd_check_references_constraints( node, pcur, table, index, offsets, thr, mtr); + if (err != DB_SUCCESS) { + mtr_commit(mtr); + if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } + return(err); } } @@ -1776,7 +1806,8 @@ row_upd_del_mark_clust_rec( ulint* offsets,/*!< in/out: rec_get_offsets() for the record under the cursor */ que_thr_t* thr, /*!< in: query thread */ - ibool check_ref,/*!< in: TRUE if index may be referenced in + ibool referenced, + /*!< in: TRUE if index may be referenced in a foreign key constraint */ mtr_t* mtr) /*!< in: mtr; gets committed here */ { @@ -1801,13 +1832,11 @@ row_upd_del_mark_clust_rec( err = btr_cur_del_mark_set_clust_rec(BTR_NO_LOCKING_FLAG, btr_cur, TRUE, thr, mtr); - if (err == DB_SUCCESS && check_ref) { + if (err == DB_SUCCESS && referenced) { /* NOTE that the following call loses the position of pcur ! */ - err = row_upd_check_references_constraints(node, - pcur, index->table, - index, offsets, - thr, mtr); + err = row_upd_check_references_constraints( + node, pcur, index->table, index, offsets, thr, mtr); } mtr_commit(mtr); @@ -1829,7 +1858,6 @@ row_upd_clust_step( dict_index_t* index; btr_pcur_t* pcur; ibool success; - ibool check_ref; ulint err; mtr_t* mtr; mtr_t mtr_buf; @@ -1837,11 +1865,12 @@ row_upd_clust_step( mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets; + ibool referenced; rec_offs_init(offsets_); index = dict_table_get_first_index(node->table); - check_ref = row_upd_index_is_referenced(index, thr_get_trx(thr)); + referenced = row_upd_index_is_referenced(index, thr_get_trx(thr)); pcur = node->pcur; @@ -1911,8 +1940,9 @@ row_upd_clust_step( /* NOTE: the following function calls will also commit mtr */ if (node->is_delete) { - err = row_upd_del_mark_clust_rec(node, index, offsets, - thr, check_ref, mtr); + err = row_upd_del_mark_clust_rec( + node, index, offsets, thr, referenced, mtr); + if (err == DB_SUCCESS) { node->state = UPD_NODE_UPDATE_ALL_SEC; node->index = dict_table_get_next_index(index); @@ -1960,8 +1990,9 @@ exit_func: choosing records to update. MySQL solves now the problem externally! */ - err = row_upd_clust_rec_by_insert(node, index, thr, check_ref, - mtr); + err = row_upd_clust_rec_by_insert( + node, index, thr, referenced, mtr); + if (err != DB_SUCCESS) { return(err); diff --git a/storage/innobase/scripts/export.sh b/storage/innobase/scripts/export.sh deleted file mode 100755 index 2a4355c1e43..00000000000 --- a/storage/innobase/scripts/export.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash -# -# export current working directory in a format suitable for sending to MySQL -# as a snapshot. also generates the actual snapshot and sends it to MySQL. - -set -eu - -die () { - echo $* - exit 1 -} - -if [ $# -ne 2 ] ; then - die "Usage: export.sh revision-number-of-last-snapshot current-revision-number" -fi - -# If we are run from within the scripts/ directory then change directory to -# one level up so that the relative paths work. -DIR=`basename $PWD` - -if [ "${DIR}" = "scripts" ]; then - cd .. -fi - -START_REV=$(($1 + 1)) -END_REV=$2 - -set +u -if test -z $EDITOR; then - die "\$EDITOR is not set" -fi -set -u - -rm -rf to-mysql -mkdir to-mysql{,/storage,/patches,/mysql-test{,/t,/r,/include}} -svn log -v -r "$START_REV:BASE" > to-mysql/log -svn export -q . to-mysql/storage/innobase - -REV=$START_REV -while [ $REV -le $END_REV ] -do - PATCH=to-mysql/patches/r$REV.patch - svn log -v -r$REV > $PATCH - if [ $(wc -c < $PATCH) -gt 73 ] - then - svn diff -r$(($REV-1)):$REV >> $PATCH - else - rm $PATCH - fi - REV=$(($REV + 1)) -done - -cd to-mysql/storage/innobase - -mv mysql-test/*.test mysql-test/*.opt ../../mysql-test/t -mv mysql-test/*.result ../../mysql-test/r -mv mysql-test/*.inc ../../mysql-test/include -rmdir mysql-test - -rm setup.sh export.sh revert_gen.sh compile-innodb-debug compile-innodb - -cd ../.. -$EDITOR log -cd .. - -fname="innodb-5.1-ss$2.tar.gz" - -rm -f $fname -tar czf $fname to-mysql -scp $fname mysql:snapshots -rm $fname -rm -rf to-mysql - -echo "Sent $fname to MySQL" diff --git a/storage/innobase/scripts/install_innodb_plugins.sql b/storage/innobase/scripts/install_innodb_plugins.sql deleted file mode 100644 index 3fdb8f11e22..00000000000 --- a/storage/innobase/scripts/install_innodb_plugins.sql +++ /dev/null @@ -1,9 +0,0 @@ --- execute these to install InnoDB if it is built as a dynamic plugin -INSTALL PLUGIN innodb SONAME 'ha_innodb.so'; -INSTALL PLUGIN innodb_trx SONAME 'ha_innodb.so'; -INSTALL PLUGIN innodb_locks SONAME 'ha_innodb.so'; -INSTALL PLUGIN innodb_lock_waits SONAME 'ha_innodb.so'; -INSTALL PLUGIN innodb_cmp SONAME 'ha_innodb.so'; -INSTALL PLUGIN innodb_cmp_reset SONAME 'ha_innodb.so'; -INSTALL PLUGIN innodb_cmpmem SONAME 'ha_innodb.so'; -INSTALL PLUGIN innodb_cmpmem_reset SONAME 'ha_innodb.so'; diff --git a/storage/innobase/scripts/install_innodb_plugins_win.sql b/storage/innobase/scripts/install_innodb_plugins_win.sql deleted file mode 100644 index 8c94b4e240d..00000000000 --- a/storage/innobase/scripts/install_innodb_plugins_win.sql +++ /dev/null @@ -1,9 +0,0 @@ --- execute these to install InnoDB if it is built as a dynamic plugin
-INSTALL PLUGIN innodb SONAME 'ha_innodb.dll';
-INSTALL PLUGIN innodb_trx SONAME 'ha_innodb.dll';
-INSTALL PLUGIN innodb_locks SONAME 'ha_innodb.dll';
-INSTALL PLUGIN innodb_lock_waits SONAME 'ha_innodb.dll';
-INSTALL PLUGIN innodb_cmp SONAME 'ha_innodb.dll';
-INSTALL PLUGIN innodb_cmp_reset SONAME 'ha_innodb.dll';
-INSTALL PLUGIN innodb_cmpmem SONAME 'ha_innodb.dll';
-INSTALL PLUGIN innodb_cmpmem_reset SONAME 'ha_innodb.dll';
diff --git a/storage/innobase/setup.sh b/storage/innobase/setup.sh deleted file mode 100755 index 23fe729a406..00000000000 --- a/storage/innobase/setup.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. -# -# 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; 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, write to the Free Software Foundation, Inc., 59 Temple -# Place, Suite 330, Boston, MA 02111-1307 USA -# -# Prepare the MySQL source code tree for building -# with checked-out InnoDB Subversion directory. - -# This script assumes that the current directory is storage/innobase. - -set -eu - -TARGETDIR=../storage/innobase - -# link the build scripts -BUILDSCRIPTS="compile-innodb compile-innodb-debug" -for script in $BUILDSCRIPTS ; do - ln -sf $TARGETDIR/$script ../../BUILD/ -done - -cd ../../mysql-test/t -ln -sf ../$TARGETDIR/mysql-test/*.test ../$TARGETDIR/mysql-test/*.opt . -cd ../r -ln -sf ../$TARGETDIR/mysql-test/*.result . -cd ../include -ln -sf ../$TARGETDIR/mysql-test/*.inc . - -# Apply any patches that are needed to make the mysql-test suite successful. -# These patches are usually needed because of deviations of behavior between -# the stock InnoDB and the InnoDB Plugin. -cd ../.. -for patch in storage/innobase/mysql-test/patches/*.diff ; do - if [ "${patch}" != "storage/innobase/mysql-test/patches/*.diff" ] ; then - patch -p0 < ${patch} - fi -done diff --git a/storage/innobase/srv/srv0que.c b/storage/innobase/srv/srv0que.c deleted file mode 100644 index fc50a86a55c..00000000000 --- a/storage/innobase/srv/srv0que.c +++ /dev/null @@ -1,49 +0,0 @@ -/***************************************************************************** - -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. - -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; 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, write to the Free Software Foundation, Inc., 59 Temple -Place, Suite 330, Boston, MA 02111-1307 USA - -*****************************************************************************/ - -/**************************************************//** -@file srv/srv0que.c -Server query execution - -Created 6/5/1996 Heikki Tuuri -*******************************************************/ - -#include "srv0que.h" - -#include "srv0srv.h" -#include "sync0sync.h" -#include "os0thread.h" -#include "usr0sess.h" -#include "que0que.h" - -/**********************************************************************//** -Enqueues a task to server task queue and releases a worker thread, if there -is a suspended one. */ -UNIV_INTERN -void -srv_que_task_enqueue_low( -/*=====================*/ - que_thr_t* thr) /*!< in: query thread */ -{ - ut_ad(thr); - ut_ad(mutex_own(&kernel_mutex)); - - UT_LIST_ADD_LAST(queue, srv_sys->tasks, thr); - - srv_release_threads(SRV_WORKER, 1); -} diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index 3b0e29b9b48..b1f3a543b07 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -1,7 +1,8 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. +Copyright (c) 2009, Percona Inc. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -9,6 +10,13 @@ briefly in the InnoDB documentation. The contributions by Google are incorporated with their permission, and subject to the conditions contained in the file COPYING.Google. +Portions of this file contain modifications contributed and copyrighted +by Percona Inc.. Those modifications are +gratefully acknowledged and are described briefly in the InnoDB +documentation. The contributions by Percona Inc. are incorporated with +their permission, and subject to the conditions contained in the file +COPYING.Percona. + 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; version 2 of the License. @@ -22,32 +30,6 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ -/*********************************************************************** - -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. -Copyright (c) 2009, Percona Inc. - -Portions of this file contain modifications contributed and copyrighted -by Percona Inc.. Those modifications are -gratefully acknowledged and are described briefly in the InnoDB -documentation. The contributions by Percona Inc. are incorporated with -their permission, and subject to the conditions contained in the file -COPYING.Percona. - -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; 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, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -***********************************************************************/ /**************************************************//** @file srv/srv0srv.c @@ -86,7 +68,6 @@ Created 10/8/1995 Heikki Tuuri #include "sync0sync.h" #include "thr0loc.h" #include "que0que.h" -#include "srv0que.h" #include "log0recv.h" #include "pars0pars.h" #include "usr0sess.h" @@ -119,7 +100,8 @@ UNIV_INTERN ulint srv_fatal_semaphore_wait_threshold = 600; in microseconds, in order to reduce the lagging of the purge thread. */ UNIV_INTERN ulint srv_dml_needed_delay = 0; -UNIV_INTERN ibool srv_lock_timeout_and_monitor_active = FALSE; +UNIV_INTERN ibool srv_lock_timeout_active = FALSE; +UNIV_INTERN ibool srv_monitor_active = FALSE; UNIV_INTERN ibool srv_error_monitor_active = FALSE; UNIV_INTERN const char* srv_main_thread_op_info = ""; @@ -154,6 +136,12 @@ UNIV_INTERN ulint srv_check_file_format_at_startup = DICT_TF_FORMAT_MAX; on duplicate key checking and foreign key checking */ UNIV_INTERN ibool srv_locks_unsafe_for_binlog = FALSE; +/* If this flag is TRUE, then we will use the native aio of the +OS (provided we compiled Innobase with it in), otherwise we will +use simulated aio we build below with threads. +Currently we support native aio on windows and linux */ +UNIV_INTERN my_bool srv_use_native_aio = TRUE; + UNIV_INTERN ulint srv_n_data_files = 0; UNIV_INTERN char** srv_data_file_names = NULL; /* size in database pages */ @@ -188,7 +176,17 @@ UNIV_INTERN ulong srv_flush_log_at_trx_commit = 1; the checkpoints. */ UNIV_INTERN char srv_adaptive_flushing = TRUE; -/* The sort order table of the MySQL latin1_swedish_ci character set +/** Maximum number of times allowed to conditionally acquire +mutex before switching to blocking wait on the mutex */ +#define MAX_MUTEX_NOWAIT 20 + +/** Check whether the number of failed nonblocking mutex +acquisition attempts exceeds maximum allowed value. If so, +srv_printf_innodb_monitor() will request mutex acquisition +with mutex_enter(), which will wait until it gets the mutex. */ +#define MUTEX_NOWAIT(mutex_skipped) ((mutex_skipped) < MAX_MUTEX_NOWAIT) + +/** The sort order table of the MySQL latin1_swedish_ci character set collation */ UNIV_INTERN const byte* srv_latin1_ordering; @@ -196,6 +194,8 @@ UNIV_INTERN const byte* srv_latin1_ordering; UNIV_INTERN my_bool srv_use_sys_malloc = TRUE; /* requested size in kilobytes */ UNIV_INTERN ulint srv_buf_pool_size = ULINT_MAX; +/* requested number of buffer pool instances */ +UNIV_INTERN ulint srv_buf_pool_instances = 1; /* previously requested size */ UNIV_INTERN ulint srv_buf_pool_old_size; /* current size in kilobytes */ @@ -247,6 +247,12 @@ that during a time of heavy update/insert activity. */ UNIV_INTERN ulong srv_max_buf_pool_modified_pct = 75; +/* the number of purge threads to use from the worker pool (currently 0 or 1).*/ +UNIV_INTERN ulong srv_n_purge_threads = 0; + +/* the number of records to purge in one batch */ +UNIV_INTERN ulong srv_purge_batch_size = 20; + /* variable counts amount of data read in total (in bytes) */ UNIV_INTERN ulint srv_data_read = 0; @@ -424,6 +430,20 @@ UNIV_INTERN mutex_t srv_innodb_monitor_mutex; /* Mutex for locking srv_monitor_file */ UNIV_INTERN mutex_t srv_monitor_file_mutex; + +#ifdef UNIV_PFS_MUTEX +/* Key to register kernel_mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t kernel_mutex_key; +/* Key to register srv_innodb_monitor_mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t srv_innodb_monitor_mutex_key; +/* Key to register srv_monitor_file_mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t srv_monitor_file_mutex_key; +/* Key to register srv_dict_tmpfile_mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t srv_dict_tmpfile_mutex_key; +/* Key to register the mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t srv_misc_tmpfile_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + /* Temporary file for innodb monitor output */ UNIV_INTERN FILE* srv_monitor_file; /* Mutex for locking srv_dict_tmpfile. @@ -691,6 +711,16 @@ are indexed by the type of the thread. */ UNIV_INTERN ulint srv_n_threads_active[SRV_MASTER + 1]; UNIV_INTERN ulint srv_n_threads[SRV_MASTER + 1]; +/*********************************************************************//** +Asynchronous purge thread. +@return a dummy parameter */ +UNIV_INTERN +os_thread_ret_t +srv_purge_thread( +/*=============*/ + void* arg __attribute__((unused))); /*!< in: a dummy parameter + required by os_thread_create */ + /*********************************************************************** Prints counters for work done by srv_master_thread. */ static @@ -939,9 +969,10 @@ srv_init(void) srv_sys = mem_alloc(sizeof(srv_sys_t)); kernel_mutex_temp = mem_alloc(sizeof(mutex_t)); - mutex_create(&kernel_mutex, SYNC_KERNEL); + mutex_create(kernel_mutex_key, &kernel_mutex, SYNC_KERNEL); - mutex_create(&srv_innodb_monitor_mutex, SYNC_NO_ORDER_CHECK); + mutex_create(srv_innodb_monitor_mutex_key, + &srv_innodb_monitor_mutex, SYNC_NO_ORDER_CHECK); srv_sys->threads = mem_alloc(OS_THREAD_MAX_N * sizeof(srv_slot_t)); @@ -1618,6 +1649,11 @@ srv_suspend_mysql_thread( trx->error_state = DB_LOCK_WAIT_TIMEOUT; } + + if (trx_is_interrupted(trx)) { + + trx->error_state = DB_INTERRUPTED; + } } /********************************************************************//** @@ -1669,7 +1705,7 @@ srv_refresh_innodb_monitor_stats(void) log_refresh_stats(); - buf_refresh_io_stats(); + buf_refresh_io_stats_all(); srv_n_rows_inserted_old = srv_n_rows_inserted; srv_n_rows_updated_old = srv_n_rows_updated; @@ -1680,12 +1716,15 @@ srv_refresh_innodb_monitor_stats(void) } /******************************************************************//** -Outputs to a file the output of the InnoDB Monitor. */ +Outputs to a file the output of the InnoDB Monitor. +@return FALSE if not all information printed +due to failure to obtain necessary mutex */ UNIV_INTERN -void +ibool srv_printf_innodb_monitor( /*======================*/ FILE* file, /*!< in: output stream */ + ibool nowait, /*!< in: whether to wait for kernel mutex */ ulint* trx_start, /*!< out: file position of the start of the list of active transactions */ ulint* trx_end) /*!< out: file position of the end of @@ -1694,6 +1733,7 @@ srv_printf_innodb_monitor( double time_elapsed; time_t current_time; ulint n_reserved; + ibool ret; mutex_enter(&srv_innodb_monitor_mutex); @@ -1717,9 +1757,9 @@ srv_printf_innodb_monitor( "Per second averages calculated from the last %lu seconds\n", (ulong)time_elapsed); - fputs("----------\n" - "BACKGROUND THREAD\n" - "----------\n", file); + fputs("-----------------\n" + "BACKGROUND THREAD\n" + "-----------------\n", file); srv_print_master_thread_info(file); fputs("----------\n" @@ -1743,24 +1783,31 @@ srv_printf_innodb_monitor( mutex_exit(&dict_foreign_err_mutex); - lock_print_info_summary(file); - if (trx_start) { - long t = ftell(file); - if (t < 0) { - *trx_start = ULINT_UNDEFINED; - } else { - *trx_start = (ulint) t; + /* Only if lock_print_info_summary proceeds correctly, + before we call the lock_print_info_all_transactions + to print all the lock information. */ + ret = lock_print_info_summary(file, nowait); + + if (ret) { + if (trx_start) { + long t = ftell(file); + if (t < 0) { + *trx_start = ULINT_UNDEFINED; + } else { + *trx_start = (ulint) t; + } } - } - lock_print_info_all_transactions(file); - if (trx_end) { - long t = ftell(file); - if (t < 0) { - *trx_end = ULINT_UNDEFINED; - } else { - *trx_end = (ulint) t; + lock_print_info_all_transactions(file); + if (trx_end) { + long t = ftell(file); + if (t < 0) { + *trx_end = ULINT_UNDEFINED; + } else { + *trx_end = (ulint) t; + } } } + fputs("--------\n" "FILE I/O\n" "--------\n", file); @@ -1858,6 +1905,8 @@ srv_printf_innodb_monitor( "============================\n", file); mutex_exit(&srv_innodb_monitor_mutex); fflush(file); + + return(ret); } /******************************************************************//** @@ -1867,6 +1916,14 @@ void srv_export_innodb_status(void) /*==========================*/ { + buf_pool_stat_t stat; + ulint LRU_len; + ulint free_len; + ulint flush_list_len; + + buf_get_total_stat(&stat); + buf_get_total_list_len(&LRU_len, &free_len, &flush_list_len); + mutex_enter(&srv_innodb_monitor_mutex); export_vars.innodb_data_pending_reads @@ -1881,31 +1938,27 @@ srv_export_innodb_status(void) export_vars.innodb_data_reads = os_n_file_reads; export_vars.innodb_data_writes = os_n_file_writes; export_vars.innodb_data_written = srv_data_written; - export_vars.innodb_buffer_pool_read_requests = buf_pool->stat.n_page_gets; + export_vars.innodb_buffer_pool_read_requests = stat.n_page_gets; export_vars.innodb_buffer_pool_write_requests = srv_buf_pool_write_requests; export_vars.innodb_buffer_pool_wait_free = srv_buf_pool_wait_free; export_vars.innodb_buffer_pool_pages_flushed = srv_buf_pool_flushed; export_vars.innodb_buffer_pool_reads = srv_buf_pool_reads; export_vars.innodb_buffer_pool_read_ahead - = buf_pool->stat.n_ra_pages_read; + = stat.n_ra_pages_read; export_vars.innodb_buffer_pool_read_ahead_evicted - = buf_pool->stat.n_ra_pages_evicted; - export_vars.innodb_buffer_pool_pages_data - = UT_LIST_GET_LEN(buf_pool->LRU); - export_vars.innodb_buffer_pool_pages_dirty - = UT_LIST_GET_LEN(buf_pool->flush_list); - export_vars.innodb_buffer_pool_pages_free - = UT_LIST_GET_LEN(buf_pool->free); + = stat.n_ra_pages_evicted; + export_vars.innodb_buffer_pool_pages_data = LRU_len; + export_vars.innodb_buffer_pool_pages_dirty = flush_list_len; + export_vars.innodb_buffer_pool_pages_free = free_len; #ifdef UNIV_DEBUG export_vars.innodb_buffer_pool_pages_latched = buf_get_latched_pages_number(); #endif /* UNIV_DEBUG */ - export_vars.innodb_buffer_pool_pages_total = buf_pool->curr_size; + export_vars.innodb_buffer_pool_pages_total = buf_pool_get_n_pages(); - export_vars.innodb_buffer_pool_pages_misc = buf_pool->curr_size - - UT_LIST_GET_LEN(buf_pool->LRU) - - UT_LIST_GET_LEN(buf_pool->free); + export_vars.innodb_buffer_pool_pages_misc + = buf_pool_get_n_pages() - LRU_len - free_len; #ifdef HAVE_ATOMIC_BUILTINS export_vars.innodb_have_atomic_builtins = 1; #else @@ -1921,9 +1974,9 @@ srv_export_innodb_status(void) export_vars.innodb_log_writes = srv_log_writes; export_vars.innodb_dblwr_pages_written = srv_dblwr_pages_written; export_vars.innodb_dblwr_writes = srv_dblwr_writes; - export_vars.innodb_pages_created = buf_pool->stat.n_pages_created; - export_vars.innodb_pages_read = buf_pool->stat.n_pages_read; - export_vars.innodb_pages_written = buf_pool->stat.n_pages_written; + export_vars.innodb_pages_created = stat.n_pages_created; + export_vars.innodb_pages_read = stat.n_pages_read; + export_vars.innodb_pages_written = stat.n_pages_written; export_vars.innodb_row_lock_waits = srv_n_lock_wait_count; export_vars.innodb_row_lock_current_waits = srv_n_lock_wait_current_count; @@ -1945,43 +1998,47 @@ srv_export_innodb_status(void) } /*********************************************************************//** -A thread which wakes up threads whose lock wait may have lasted too long. -This also prints the info output by various InnoDB monitors. +A thread which prints the info output by various InnoDB monitors. @return a dummy parameter */ UNIV_INTERN os_thread_ret_t -srv_lock_timeout_and_monitor_thread( -/*================================*/ +srv_monitor_thread( +/*===============*/ void* arg __attribute__((unused))) /*!< in: a dummy parameter required by os_thread_create */ { - srv_slot_t* slot; double time_elapsed; time_t current_time; time_t last_table_monitor_time; time_t last_tablespace_monitor_time; time_t last_monitor_time; - ibool some_waits; - double wait_time; - ulint i; + ulint mutex_skipped; + ibool last_srv_print_monitor; #ifdef UNIV_DEBUG_THREAD_CREATION fprintf(stderr, "Lock timeout thread starts, id %lu\n", os_thread_pf(os_thread_get_curr_id())); #endif + +#ifdef UNIV_PFS_THREAD + pfs_register_thread(srv_monitor_thread_key); +#endif + UT_NOT_USED(arg); srv_last_monitor_time = time(NULL); last_table_monitor_time = time(NULL); last_tablespace_monitor_time = time(NULL); last_monitor_time = time(NULL); + mutex_skipped = 0; + last_srv_print_monitor = srv_print_innodb_monitor; loop: - srv_lock_timeout_and_monitor_active = TRUE; + srv_monitor_active = TRUE; - /* When someone is waiting for a lock, we wake up every second - and check if a timeout has passed for a lock wait */ + /* Wake up every 5 seconds to see if we need to print + monitor information. */ - os_thread_sleep(1000000); + os_thread_sleep(5000000); current_time = time(NULL); @@ -1991,14 +2048,40 @@ loop: last_monitor_time = time(NULL); if (srv_print_innodb_monitor) { - srv_printf_innodb_monitor(stderr, NULL, NULL); + /* Reset mutex_skipped counter everytime + srv_print_innodb_monitor changes. This is to + ensure we will not be blocked by kernel_mutex + for short duration information printing, + such as requested by sync_array_print_long_waits() */ + if (!last_srv_print_monitor) { + mutex_skipped = 0; + last_srv_print_monitor = TRUE; + } + + if (!srv_printf_innodb_monitor(stderr, + MUTEX_NOWAIT(mutex_skipped), + NULL, NULL)) { + mutex_skipped++; + } else { + /* Reset the counter */ + mutex_skipped = 0; + } + } else { + last_srv_print_monitor = FALSE; } + if (srv_innodb_status) { mutex_enter(&srv_monitor_file_mutex); rewind(srv_monitor_file); - srv_printf_innodb_monitor(srv_monitor_file, NULL, - NULL); + if (!srv_printf_innodb_monitor(srv_monitor_file, + MUTEX_NOWAIT(mutex_skipped), + NULL, NULL)) { + mutex_skipped++; + } else { + mutex_skipped = 0; + } + os_file_set_eof(srv_monitor_file); mutex_exit(&srv_monitor_file_mutex); } @@ -2051,6 +2134,60 @@ loop: } } + if (srv_shutdown_state >= SRV_SHUTDOWN_CLEANUP) { + goto exit_func; + } + + if (srv_print_innodb_monitor + || srv_print_innodb_lock_monitor + || srv_print_innodb_tablespace_monitor + || srv_print_innodb_table_monitor) { + goto loop; + } + + srv_monitor_active = FALSE; + + goto loop; + +exit_func: + srv_monitor_active = FALSE; + + /* We count the number of threads in os_thread_exit(). A created + thread should always use that to exit and not use return() to exit. */ + + os_thread_exit(NULL); + + OS_THREAD_DUMMY_RETURN; +} + +/*********************************************************************//** +A thread which wakes up threads whose lock wait may have lasted too long. +@return a dummy parameter */ +UNIV_INTERN +os_thread_ret_t +srv_lock_timeout_thread( +/*====================*/ + void* arg __attribute__((unused))) + /* in: a dummy parameter required by + os_thread_create */ +{ + srv_slot_t* slot; + ibool some_waits; + double wait_time; + ulint i; + +#ifdef UNIV_PFS_THREAD + pfs_register_thread(srv_lock_timeout_thread_key); +#endif + +loop: + /* When someone is waiting for a lock, we wake up every second + and check if a timeout has passed for a lock wait */ + + os_thread_sleep(1000000); + + srv_lock_timeout_active = TRUE; + mutex_enter(&kernel_mutex); some_waits = FALSE; @@ -2074,9 +2211,10 @@ loop: lock_wait_timeout = thd_lock_wait_timeout( trx->mysql_thd); - if (lock_wait_timeout < 100000000 - && (wait_time > (double) lock_wait_timeout - || wait_time < 0)) { + if (trx_is_interrupted(trx) + || (lock_wait_timeout < 100000000 + && (wait_time > (double) lock_wait_timeout + || wait_time < 0))) { /* Timeout exceeded or a wrap-around in system time counter: cancel the lock request queued @@ -2101,17 +2239,11 @@ loop: goto exit_func; } - if (some_waits || srv_print_innodb_monitor - || srv_print_innodb_lock_monitor - || srv_print_innodb_tablespace_monitor - || srv_print_innodb_table_monitor) { + if (some_waits) { goto loop; } - /* No one was waiting for a lock and no monitor was active: - suspend this thread */ - - srv_lock_timeout_and_monitor_active = FALSE; + srv_lock_timeout_active = FALSE; #if 0 /* The following synchronisation is disabled, since @@ -2121,7 +2253,7 @@ loop: goto loop; exit_func: - srv_lock_timeout_and_monitor_active = FALSE; + srv_lock_timeout_active = FALSE; /* We count the number of threads in os_thread_exit(). A created thread should always use that to exit and not use return() to exit. */ @@ -2154,6 +2286,11 @@ srv_error_monitor_thread( fprintf(stderr, "Error monitor thread starts, id %lu\n", os_thread_pf(os_thread_get_curr_id())); #endif + +#ifdef UNIV_PFS_THREAD + pfs_register_thread(srv_error_monitor_thread_key); +#endif + loop: srv_error_monitor_active = TRUE; @@ -2234,18 +2371,69 @@ loop: OS_THREAD_DUMMY_RETURN; } +/******************************************************************//** +Increment the server activity count. */ +UNIV_INLINE +void +srv_inc_activity_count_low(void) +/*============================*/ +{ + mutex_enter(&kernel_mutex); + + ++srv_activity_count; + + mutex_exit(&kernel_mutex); +} + +/******************************************************************//** +Increment the server activity count. */ +UNIV_INTERN +void +srv_inc_activity_count(void) +/*========================*/ +{ + srv_inc_activity_count_low(); +} + +/**********************************************************************//** +Check whether any background thread is active. +@return FALSE if all are are suspended or have exited. */ +UNIV_INTERN +ibool +srv_is_any_background_thread_active(void) +/*=====================================*/ +{ + ulint i; + ibool ret = FALSE; + + mutex_enter(&kernel_mutex); + + for (i = SRV_COM; i <= SRV_MASTER; ++i) { + if (srv_n_threads_active[i] != 0) { + ret = TRUE; + break; + } + } + + mutex_exit(&kernel_mutex); + + return(ret); +} + /*******************************************************************//** Tells the InnoDB server that there has been activity in the database and wakes up the master thread if it is suspended (not sleeping). Used in the MySQL interface. Note that there is a small chance that the master -thread stays suspended (we do not protect our operation with the kernel -mutex, for performace reasons). */ +thread stays suspended (we do not protect our operation with the +srv_sys_t->mutex, for performance reasons). */ UNIV_INTERN void srv_active_wake_master_thread(void) /*===============================*/ { - srv_activity_count++; + ut_ad(!mutex_own(&kernel_mutex)); + + srv_inc_activity_count_low(); if (srv_n_threads_active[SRV_MASTER] == 0) { @@ -2258,6 +2446,30 @@ srv_active_wake_master_thread(void) } /*******************************************************************//** +Tells the purge thread that there has been activity in the database +and wakes up the purge thread if it is suspended (not sleeping). Note +that there is a small chance that the purge thread stays suspended +(we do not protect our operation with the kernel mutex, for +performace reasons). */ +UNIV_INTERN +void +srv_wake_purge_thread_if_not_active(void) +/*=====================================*/ +{ + ut_ad(!mutex_own(&kernel_mutex)); + + if (srv_n_purge_threads > 0 + && srv_n_threads_active[SRV_WORKER] == 0) { + + mutex_enter(&kernel_mutex); + + srv_release_threads(SRV_WORKER, 1); + + mutex_exit(&kernel_mutex); + } +} + +/*******************************************************************//** Wakes up the master thread if it is suspended or being suspended. */ UNIV_INTERN void @@ -2273,6 +2485,25 @@ srv_wake_master_thread(void) mutex_exit(&kernel_mutex); } +/*******************************************************************//** +Wakes up the purge thread if it's not already awake. */ +UNIV_INTERN +void +srv_wake_purge_thread(void) +/*=======================*/ +{ + ut_ad(!mutex_own(&kernel_mutex)); + + if (srv_n_purge_threads > 0) { + + mutex_enter(&kernel_mutex); + + srv_release_threads(SRV_WORKER, 1); + + mutex_exit(&kernel_mutex); + } +} + /********************************************************************** The master thread is tasked to ensure that flush of log file happens once every second in the background. This is to ensure that not more @@ -2293,6 +2524,34 @@ srv_sync_log_buffer_in_background(void) } } +/********************************************************************//** +Do a full purge, reconfigure the purge sub-system if a dynamic +change is detected. */ +static +void +srv_master_do_purge(void) +/*=====================*/ +{ + ulint n_pages_purged; + + ut_ad(!mutex_own(&kernel_mutex)); + + ut_a(srv_n_purge_threads == 0); + + do { + /* Check for shutdown and change in purge config. */ + if (srv_fast_shutdown && srv_shutdown_state > 0) { + /* Nothing to purge. */ + n_pages_purged = 0; + } else { + n_pages_purged = trx_purge(srv_purge_batch_size); + } + + srv_sync_log_buffer_in_background(); + + } while (n_pages_purged > 0); +} + /*********************************************************************//** The master thread controlling the server. @return a dummy parameter */ @@ -2304,6 +2563,7 @@ srv_master_thread( /*!< in: a dummy parameter required by os_thread_create */ { + buf_pool_stat_t buf_stat; os_event_t event; ulint old_activity_count; ulint n_pages_purged = 0; @@ -2315,13 +2575,18 @@ srv_master_thread( ulint n_ios_old; ulint n_ios_very_old; ulint n_pend_ios; - ibool skip_sleep = FALSE; + ulint next_itr_time; ulint i; #ifdef UNIV_DEBUG_THREAD_CREATION fprintf(stderr, "Master thread starts, id %lu\n", os_thread_pf(os_thread_get_curr_id())); #endif + +#ifdef UNIV_PFS_THREAD + pfs_register_thread(srv_master_thread_key); +#endif + srv_main_thread_process_no = os_proc_get_number(); srv_main_thread_id = os_thread_pf(os_thread_get_curr_id()); @@ -2340,8 +2605,9 @@ loop: srv_main_thread_op_info = "reserving kernel mutex"; - n_ios_very_old = log_sys->n_log_ios + buf_pool->stat.n_pages_read - + buf_pool->stat.n_pages_written; + buf_get_total_stat(&buf_stat); + n_ios_very_old = log_sys->n_log_ios + buf_stat.n_pages_read + + buf_stat.n_pages_written; mutex_enter(&kernel_mutex); /* Store the user activity counter at the start of this loop */ @@ -2358,21 +2624,32 @@ loop: when there is database activity */ srv_last_log_flush_time = time(NULL); - skip_sleep = FALSE; + next_itr_time = ut_time_ms(); for (i = 0; i < 10; i++) { - n_ios_old = log_sys->n_log_ios + buf_pool->stat.n_pages_read - + buf_pool->stat.n_pages_written; + ulint cur_time = ut_time_ms(); + + buf_get_total_stat(&buf_stat); + + n_ios_old = log_sys->n_log_ios + buf_stat.n_pages_read + + buf_stat.n_pages_written; + srv_main_thread_op_info = "sleeping"; srv_main_1_second_loops++; - if (!skip_sleep) { + if (next_itr_time > cur_time) { - os_thread_sleep(1000000); + /* Get sleep interval in micro seconds. We use + ut_min() to avoid long sleep in case of + wrap around. */ + os_thread_sleep(ut_min(1000000, + (next_itr_time - cur_time) + * 1000)); srv_main_sleeps++; } - skip_sleep = FALSE; + /* Each iteration should happen at 1 second interval. */ + next_itr_time = ut_time_ms() + 1000; /* ALTER TABLE in MySQL requires on Unix that the table handler can drop tables lazily after there no longer are SELECT @@ -2396,13 +2673,14 @@ loop: log_free_check(); /* If i/os during one second sleep were less than 5% of - capacity, we assume that there is free disk i/o capacity - available, and it makes sense to do an insert buffer merge. */ + capacity, we assume that there is free disk i/o capacity + available, and it makes sense to do an insert buffer merge. */ + buf_get_total_stat(&buf_stat); n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes; - n_ios = log_sys->n_log_ios + buf_pool->stat.n_pages_read - + buf_pool->stat.n_pages_written; + n_ios = log_sys->n_log_ios + buf_stat.n_pages_read + + buf_stat.n_pages_written; if (n_pend_ios < SRV_PEND_IO_THRESHOLD && (n_ios - n_ios_old < SRV_RECENT_IO_ACTIVITY)) { srv_main_thread_op_info = "doing insert buffer merge"; @@ -2420,16 +2698,9 @@ loop: srv_main_thread_op_info = "flushing buffer pool pages"; - n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, - PCT_IO(100), - IB_ULONGLONG_MAX); + n_pages_flushed = buf_flush_list( + PCT_IO(100), IB_ULONGLONG_MAX); - /* If we had to do the flush, it may have taken - even more than 1 second, and also, there may be more - to flush. Do not sleep 1 second during the next - iteration of this loop. */ - - skip_sleep = TRUE; } else if (srv_adaptive_flushing) { /* Try to keep the rate of flushing of dirty @@ -2442,11 +2713,9 @@ loop: "flushing buffer pool pages"; n_flush = ut_min(PCT_IO(100), n_flush); n_pages_flushed = - buf_flush_batch( - BUF_FLUSH_LIST, + buf_flush_list( n_flush, IB_ULONGLONG_MAX); - skip_sleep = TRUE; } } @@ -2476,17 +2745,17 @@ loop: loop above requests writes for that case. The writes done here are not required, and may be disabled. */ + buf_get_total_stat(&buf_stat); n_pend_ios = buf_get_n_pending_ios() + log_sys->n_pending_writes; - n_ios = log_sys->n_log_ios + buf_pool->stat.n_pages_read - + buf_pool->stat.n_pages_written; + n_ios = log_sys->n_log_ios + buf_stat.n_pages_read + + buf_stat.n_pages_written; srv_main_10_second_loops++; if (n_pend_ios < SRV_PEND_IO_THRESHOLD && (n_ios - n_ios_very_old < SRV_PAST_IO_ACTIVITY)) { srv_main_thread_op_info = "flushing buffer pool pages"; - buf_flush_batch(BUF_FLUSH_LIST, PCT_IO(100), - IB_ULONGLONG_MAX); + buf_flush_list(PCT_IO(100), IB_ULONGLONG_MAX); /* Flush logs if needed */ srv_sync_log_buffer_in_background(); @@ -2501,22 +2770,16 @@ loop: /* Flush logs if needed */ srv_sync_log_buffer_in_background(); - /* We run a full purge every 10 seconds, even if the server - were active */ - do { + if (srv_n_purge_threads == 0) { + srv_main_thread_op_info = "master purging"; + + srv_master_do_purge(); if (srv_fast_shutdown && srv_shutdown_state > 0) { goto background_loop; } - - srv_main_thread_op_info = "purging"; - n_pages_purged = trx_purge(); - - /* Flush logs if needed */ - srv_sync_log_buffer_in_background(); - - } while (n_pages_purged); + } srv_main_thread_op_info = "flushing buffer pool pages"; @@ -2528,17 +2791,15 @@ loop: (> 70 %), we assume we can afford reserving the disk(s) for the time it requires to flush 100 pages */ - n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, - PCT_IO(100), - IB_ULONGLONG_MAX); + n_pages_flushed = buf_flush_list( + PCT_IO(100), IB_ULONGLONG_MAX); } else { /* Otherwise, we only flush a small number of pages so that we do not unnecessarily use much disk i/o capacity from other work */ - n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, - PCT_IO(10), - IB_ULONGLONG_MAX); + n_pages_flushed = buf_flush_list( + PCT_IO(10), IB_ULONGLONG_MAX); } srv_main_thread_op_info = "making checkpoint"; @@ -2585,22 +2846,11 @@ background_loop: os_thread_sleep(100000); } - srv_main_thread_op_info = "purging"; - - /* Run a full purge */ - do { - if (srv_fast_shutdown && srv_shutdown_state > 0) { - - break; - } - - srv_main_thread_op_info = "purging"; - n_pages_purged = trx_purge(); + if (srv_n_purge_threads == 0) { + srv_main_thread_op_info = "master purging"; - /* Flush logs if needed */ - srv_sync_log_buffer_in_background(); - - } while (n_pages_purged); + srv_master_do_purge(); + } srv_main_thread_op_info = "reserving kernel mutex"; @@ -2618,7 +2868,7 @@ background_loop: } else { /* This should do an amount of IO similar to the number of dirty pages that will be flushed in the call to - buf_flush_batch below. Otherwise, the system favors + buf_flush_list below. Otherwise, the system favors clean pages over cleanup throughput. */ n_bytes_merged = ibuf_contract_for_n_pages(FALSE, PCT_IO(100)); @@ -2637,9 +2887,8 @@ flush_loop: srv_main_thread_op_info = "flushing buffer pool pages"; srv_main_flush_loops++; if (srv_fast_shutdown < 2) { - n_pages_flushed = buf_flush_batch(BUF_FLUSH_LIST, - PCT_IO(100), - IB_ULONGLONG_MAX); + n_pages_flushed = buf_flush_list( + PCT_IO(100), IB_ULONGLONG_MAX); } else { /* In the fastest shutdown we do not flush the buffer pool to data files: we set n_pages_flushed to 0 artificially. */ @@ -2657,7 +2906,7 @@ flush_loop: mutex_exit(&kernel_mutex); srv_main_thread_op_info = "waiting for buffer pool flush to end"; - buf_flush_wait_batch_end(BUF_FLUSH_LIST); + buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); /* Flush logs if needed */ srv_sync_log_buffer_in_background(); @@ -2744,6 +2993,7 @@ suspend_thread: already when the event wait ends */ os_thread_exit(NULL); + } /* When there is user activity, InnoDB will set the event and the @@ -2753,3 +3003,131 @@ suspend_thread: OS_THREAD_DUMMY_RETURN; /* Not reached, avoid compiler warning */ } + +/*********************************************************************//** +Asynchronous purge thread. +@return a dummy parameter */ +UNIV_INTERN +os_thread_ret_t +srv_purge_thread( +/*=============*/ + void* arg __attribute__((unused))) /*!< in: a dummy parameter + required by os_thread_create */ +{ + srv_slot_t* slot; + ulint slot_no = ULINT_UNDEFINED; + ulint n_total_purged = ULINT_UNDEFINED; + + ut_a(srv_n_purge_threads == 1); + +#ifdef UNIV_PFS_THREAD + pfs_register_thread(srv_purge_thread_key); +#endif /* UNIV_PFS_THREAD */ + +#ifdef UNIV_DEBUG_THREAD_CREATION + fprintf(stderr, "InnoDB: Purge thread running, id %lu\n", + os_thread_pf(os_thread_get_curr_id())); +#endif /* UNIV_DEBUG_THREAD_CREATION */ + + mutex_enter(&kernel_mutex); + + slot_no = srv_table_reserve_slot(SRV_WORKER); + + ++srv_n_threads_active[SRV_WORKER]; + + mutex_exit(&kernel_mutex); + + while (srv_shutdown_state != SRV_SHUTDOWN_EXIT_THREADS) { + + ulint n_pages_purged; + + /* If there are very few records to purge or the last + purge didn't purge any records then wait for activity. + We peek at the history len without holding any mutex + because in the worst case we will end up waiting for + the next purge event. */ + if (trx_sys->rseg_history_len < srv_purge_batch_size + || n_total_purged == 0) { + + os_event_t event; + + mutex_enter(&kernel_mutex); + + event = srv_suspend_thread(); + + mutex_exit(&kernel_mutex); + + os_event_wait(event); + } + + /* Check for shutdown and whether we should do purge at all. */ + if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND + || srv_shutdown_state != 0 + || srv_fast_shutdown) { + + break; + } + + n_total_purged = 0; + + /* Purge until there are no more records to purge and there is + no change in configuration or server state. */ + do { + n_pages_purged = trx_purge(srv_purge_batch_size); + + n_total_purged += n_pages_purged; + + } while (n_pages_purged > 0 && !srv_fast_shutdown); + + srv_sync_log_buffer_in_background(); + } + + mutex_enter(&kernel_mutex); + + /* Decrement the active count. */ + srv_suspend_thread(); + + mutex_exit(&kernel_mutex); + + /* Free the thread local memory. */ + thr_local_free(os_thread_get_curr_id()); + + mutex_enter(&kernel_mutex); + + /* Free the slot for reuse. */ + slot = srv_table_get_nth_slot(slot_no); + slot->in_use = FALSE; + + mutex_exit(&kernel_mutex); + +#ifdef UNIV_DEBUG_THREAD_CREATION + fprintf(stderr, "InnoDB: Purge thread exiting, id %lu\n", + os_thread_pf(os_thread_get_curr_id())); +#endif /* UNIV_DEBUG_THREAD_CREATION */ + + /* We count the number of threads in os_thread_exit(). A created + thread should always use that to exit and not use return() to exit. */ + os_thread_exit(NULL); + + OS_THREAD_DUMMY_RETURN; /* Not reached, avoid compiler warning */ +} + +/**********************************************************************//** +Enqueues a task to server task queue and releases a worker thread, if there +is a suspended one. */ +UNIV_INTERN +void +srv_que_task_enqueue_low( +/*=====================*/ + que_thr_t* thr) /*!< in: query thread */ +{ + ut_ad(thr); + + mutex_enter(&kernel_mutex); + + UT_LIST_ADD_LAST(queue, srv_sys->tasks, thr); + + srv_release_threads(SRV_WORKER, 1); + + mutex_exit(&kernel_mutex); +} diff --git a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c index d5f6120ca31..1b96a2f4708 100644 --- a/storage/innobase/srv/srv0start.c +++ b/storage/innobase/srv/srv0start.c @@ -1,7 +1,8 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. +Copyright (c) 2009, Percona Inc. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -9,6 +10,13 @@ briefly in the InnoDB documentation. The contributions by Google are incorporated with their permission, and subject to the conditions contained in the file COPYING.Google. +Portions of this file contain modifications contributed and copyrighted +by Percona Inc.. Those modifications are +gratefully acknowledged and are described briefly in the InnoDB +documentation. The contributions by Percona Inc. are incorporated with +their permission, and subject to the conditions contained in the file +COPYING.Percona. + 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; version 2 of the License. @@ -22,32 +30,6 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ -/*********************************************************************** - -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. -Copyright (c) 2009, Percona Inc. - -Portions of this file contain modifications contributed and copyrighted -by Percona Inc.. Those modifications are -gratefully acknowledged and are described briefly in the InnoDB -documentation. The contributions by Percona Inc. are incorporated with -their permission, and subject to the conditions contained in the file -COPYING.Percona. - -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; 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, write to the Free Software Foundation, Inc., -59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -***********************************************************************/ /********************************************************************//** @file srv/srv0start.c @@ -105,6 +87,7 @@ Created 2/16/1996 Heikki Tuuri # include "btr0pcur.h" # include "thr0loc.h" # include "os0sync.h" /* for INNODB_RW_LOCKS_USE_ATOMICS */ +# include "zlib.h" /* for ZLIB_VERSION */ /** Log sequence number immediately after startup */ UNIV_INTERN ib_uint64_t srv_start_lsn; @@ -143,9 +126,9 @@ static mutex_t ios_mutex; static ulint ios; /** io_handler_thread parameters for thread identification */ -static ulint n[SRV_MAX_N_IO_THREADS + 5]; +static ulint n[SRV_MAX_N_IO_THREADS + 6]; /** io_handler_thread identifiers */ -static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 5]; +static os_thread_id_t thread_ids[SRV_MAX_N_IO_THREADS + 6]; /** We use this mutex to test the return value of pthread_mutex_trylock on successful locking. HP-UX does NOT return 0, though Linux et al do. */ @@ -159,6 +142,20 @@ static char* srv_monitor_file_name; #define SRV_N_PENDING_IOS_PER_THREAD OS_AIO_N_PENDING_IOS_PER_THREAD #define SRV_MAX_N_PENDING_SYNC_IOS 100 +#ifdef UNIV_PFS_THREAD +/* Keys to register InnoDB threads with performance schema */ +UNIV_INTERN mysql_pfs_key_t io_handler_thread_key; +UNIV_INTERN mysql_pfs_key_t srv_lock_timeout_thread_key; +UNIV_INTERN mysql_pfs_key_t srv_error_monitor_thread_key; +UNIV_INTERN mysql_pfs_key_t srv_monitor_thread_key; +UNIV_INTERN mysql_pfs_key_t srv_master_thread_key; +UNIV_INTERN mysql_pfs_key_t srv_purge_thread_key; +#endif /* UNIV_PFS_THREAD */ + +#ifdef UNIV_PFS_MUTEX +/* Key to register ios_mutex_key with performance schema */ +UNIV_INTERN mysql_pfs_key_t ios_mutex_key; +#endif /* UNIV_PFS_MUTEX */ /*********************************************************************//** Convert a numeric string that optionally ends in G or M, to a number @@ -488,6 +485,11 @@ io_handler_thread( fprintf(stderr, "Io handler thread %lu starts, id %lu\n", segment, os_thread_pf(os_thread_get_curr_id())); #endif + +#ifdef UNIV_PFS_THREAD + pfs_register_thread(io_handler_thread_key); +#endif /* UNIV_PFS_THREAD */ + for (i = 0;; i++) { fil_aio_wait(segment); @@ -601,7 +603,8 @@ open_or_create_log_file( sprintf(name + dirnamelen, "%s%lu", "ib_logfile", (ulong) i); - files[i] = os_file_create(name, OS_FILE_CREATE, OS_FILE_NORMAL, + files[i] = os_file_create(innodb_file_log_key, name, + OS_FILE_CREATE, OS_FILE_NORMAL, OS_LOG_FILE, &ret); if (ret == FALSE) { if (os_file_get_last_error(FALSE) != OS_FILE_ALREADY_EXISTS @@ -619,7 +622,8 @@ open_or_create_log_file( return(DB_ERROR); } - files[i] = os_file_create(name, OS_FILE_OPEN, OS_FILE_AIO, + files[i] = os_file_create(innodb_file_log_key, name, + OS_FILE_OPEN, OS_FILE_AIO, OS_LOG_FILE, &ret); if (!ret) { fprintf(stderr, @@ -784,7 +788,8 @@ open_or_create_data_files( /* First we try to create the file: if it already exists, ret will get value FALSE */ - files[i] = os_file_create(name, OS_FILE_CREATE, + files[i] = os_file_create(innodb_file_data_key, + name, OS_FILE_CREATE, OS_FILE_NORMAL, OS_DATA_FILE, &ret); @@ -811,7 +816,8 @@ open_or_create_data_files( srv_start_raw_disk_in_use = TRUE; srv_created_new_raw = TRUE; - files[i] = os_file_create(name, OS_FILE_OPEN_RAW, + files[i] = os_file_create(innodb_file_data_key, + name, OS_FILE_OPEN_RAW, OS_FILE_NORMAL, OS_DATA_FILE, &ret); if (!ret) { @@ -844,14 +850,17 @@ open_or_create_data_files( if (srv_data_file_is_raw_partition[i] == SRV_OLD_RAW) { files[i] = os_file_create( + innodb_file_data_key, name, OS_FILE_OPEN_RAW, OS_FILE_NORMAL, OS_DATA_FILE, &ret); } else if (i == 0) { files[i] = os_file_create( + innodb_file_data_key, name, OS_FILE_OPEN_RETRY, OS_FILE_NORMAL, OS_DATA_FILE, &ret); } else { files[i] = os_file_create( + innodb_file_data_key, name, OS_FILE_OPEN, OS_FILE_NORMAL, OS_DATA_FILE, &ret); } @@ -994,7 +1003,7 @@ skip_size_check: ios = 0; - mutex_create(&ios_mutex, SYNC_NO_ORDER_CHECK); + mutex_create(ios_mutex_key, &ios_mutex, SYNC_NO_ORDER_CHECK); return(DB_SUCCESS); } @@ -1008,7 +1017,6 @@ int innobase_start_or_create_for_mysql(void) /*====================================*/ { - buf_pool_t* ret; ibool create_new_db; ibool log_file_created; ibool log_created = FALSE; @@ -1074,7 +1082,11 @@ innobase_start_or_create_for_mysql(void) #ifdef UNIV_IBUF_DEBUG fprintf(stderr, "InnoDB: !!!!!!!! UNIV_IBUF_DEBUG switched on !!!!!!!!!\n" - "InnoDB: Crash recovery will fail with UNIV_IBUF_DEBUG\n"); +# ifdef UNIV_IBUF_COUNT_DEBUG + "InnoDB: !!!!!!!! UNIV_IBUF_COUNT_DEBUG switched on !!!!!!!!!\n" + "InnoDB: Crash recovery will fail with UNIV_IBUF_COUNT_DEBUG\n" +# endif + ); #endif #ifdef UNIV_SYNC_DEBUG @@ -1101,7 +1113,15 @@ innobase_start_or_create_for_mysql(void) "InnoDB: The InnoDB memory heap is disabled\n"); } - fprintf(stderr, "InnoDB: %s\n", IB_ATOMICS_STARTUP_MSG); + fputs("InnoDB: " IB_ATOMICS_STARTUP_MSG + "\nInnoDB: Compressed tables use zlib " ZLIB_VERSION +#ifdef UNIV_ZIP_DEBUG + " with validation" +#endif /* UNIV_ZIP_DEBUG */ +#ifdef UNIV_ZIP_COPY + " and extra copying" +#endif /* UNIV_ZIP_COPY */ + "\n" , stderr); /* Since InnoDB does not currently clean up all its internal data structures in MySQL Embedded Server Library server_end(), we @@ -1127,7 +1147,6 @@ innobase_start_or_create_for_mysql(void) srv_is_being_started = TRUE; srv_startup_is_before_trx_rollback_phase = TRUE; - os_aio_use_native_aio = FALSE; #ifdef __WIN__ switch (os_get_os_version()) { @@ -1139,14 +1158,29 @@ innobase_start_or_create_for_mysql(void) but when run in conjunction with InnoDB Hot Backup, it seemed to corrupt the data files. */ - os_aio_use_native_aio = FALSE; + srv_use_native_aio = FALSE; break; default: /* On Win 2000 and XP use async i/o */ - os_aio_use_native_aio = TRUE; + srv_use_native_aio = TRUE; break; } + +#elif defined(LINUX_NATIVE_AIO) + + if (srv_use_native_aio) { + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: Using Linux native AIO\n"); + } +#else + /* Currently native AIO is supported only on windows and linux + and that also when the support is compiled in. In all other + cases, we ignore the setting of innodb_use_native_aio. */ + srv_use_native_aio = FALSE; + #endif + if (srv_file_flush_method_str == NULL) { /* These are the default options */ @@ -1171,11 +1205,11 @@ innobase_start_or_create_for_mysql(void) #else } else if (0 == ut_strcmp(srv_file_flush_method_str, "normal")) { srv_win_file_flush_method = SRV_WIN_IO_NORMAL; - os_aio_use_native_aio = FALSE; + srv_use_native_aio = FALSE; } else if (0 == ut_strcmp(srv_file_flush_method_str, "unbuffered")) { srv_win_file_flush_method = SRV_WIN_IO_UNBUFFERED; - os_aio_use_native_aio = FALSE; + srv_use_native_aio = FALSE; } else if (0 == ut_strcmp(srv_file_flush_method_str, "async_unbuffered")) { @@ -1207,13 +1241,16 @@ innobase_start_or_create_for_mysql(void) #else if (srv_buf_pool_size >= 1000 * 1024 * 1024) { /* If buffer pool is less than 1000 MB, - assume fewer threads. */ + assume fewer threads. Also use only one + buffer pool instance */ srv_max_n_threads = 50000; } else if (srv_buf_pool_size >= 8 * 1024 * 1024) { + srv_buf_pool_instances = 1; srv_max_n_threads = 10000; } else { + srv_buf_pool_instances = 1; srv_max_n_threads = 1000; /* saves several MB of memory, especially in 64-bit computers */ @@ -1226,7 +1263,8 @@ innobase_start_or_create_for_mysql(void) return((int) err); } - mutex_create(&srv_monitor_file_mutex, SYNC_NO_ORDER_CHECK); + mutex_create(srv_monitor_file_mutex_key, + &srv_monitor_file_mutex, SYNC_NO_ORDER_CHECK); if (srv_innodb_status) { srv_monitor_file_name = mem_alloc( @@ -1248,14 +1286,16 @@ innobase_start_or_create_for_mysql(void) } } - mutex_create(&srv_dict_tmpfile_mutex, SYNC_DICT_OPERATION); + mutex_create(srv_dict_tmpfile_mutex_key, + &srv_dict_tmpfile_mutex, SYNC_DICT_OPERATION); srv_dict_tmpfile = os_file_create_tmpfile(); if (!srv_dict_tmpfile) { return(DB_ERROR); } - mutex_create(&srv_misc_tmpfile_mutex, SYNC_ANY_LATCH); + mutex_create(srv_misc_tmpfile_mutex_key, + &srv_misc_tmpfile_mutex, SYNC_ANY_LATCH); srv_misc_tmpfile = os_file_create_tmpfile(); if (!srv_misc_tmpfile) { @@ -1280,7 +1320,7 @@ innobase_start_or_create_for_mysql(void) /* TODO: Investigate if SRV_N_PENDING_IOS_PER_THREAD (32) limit still applies to windows. */ - if (!os_aio_use_native_aio) { + if (!srv_use_native_aio) { io_limit = 8 * SRV_N_PENDING_IOS_PER_THREAD; } else { io_limit = SRV_N_PENDING_IOS_PER_THREAD; @@ -1294,9 +1334,9 @@ innobase_start_or_create_for_mysql(void) fil_init(srv_file_per_table ? 50000 : 5000, srv_max_n_open_files); - ret = buf_pool_init(); + err = buf_pool_init(srv_buf_pool_size, srv_buf_pool_instances); - if (ret == NULL) { + if (err != DB_SUCCESS) { fprintf(stderr, "InnoDB: Fatal error: cannot allocate the memory" " for the buffer pool\n"); @@ -1493,12 +1533,19 @@ innobase_start_or_create_for_mysql(void) if (create_new_db) { mtr_start(&mtr); + fsp_header_init(0, sum_of_new_sizes, &mtr); mtr_commit(&mtr); + /* To maintain backward compatibility we create only + the first rollback segment before the double write buffer. + All the remaining rollback segments will be created later, + after the double write buffer has been created. */ trx_sys_create(); + dict_create(); + srv_startup_is_before_trx_rollback_phase = FALSE; #ifdef UNIV_LOG_ARCHIVE @@ -1517,7 +1564,9 @@ innobase_start_or_create_for_mysql(void) in any disk i/o, first call dict_boot */ dict_boot(); + trx_sys_init_at_db_start(); + srv_startup_is_before_trx_rollback_phase = FALSE; /* Initialize the fsp free limit global variable in the log @@ -1575,6 +1624,14 @@ innobase_start_or_create_for_mysql(void) dict_boot(); trx_sys_init_at_db_start(); + /* Initialize the fsp free limit global variable in the log + system */ + fsp_header_get_free_limit(); + + /* recv_recovery_from_checkpoint_finish needs trx lists which + are initialized in trx_sys_init_at_db_start(). */ + + recv_recovery_from_checkpoint_finish(); if (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) { /* The following call is necessary for the insert buffer to work with multiple tablespaces. We must @@ -1590,26 +1647,14 @@ innobase_start_or_create_for_mysql(void) every table in the InnoDB data dictionary that has an .ibd file. - We also determine the maximum tablespace id used. - - TODO: We may have incomplete transactions in the - data dictionary tables. Does that harm the scanning of - the data dictionary below? */ + We also determine the maximum tablespace id used. */ dict_check_tablespaces_and_store_max_id( recv_needed_recovery); } srv_startup_is_before_trx_rollback_phase = FALSE; - - /* Initialize the fsp free limit global variable in the log - system */ - fsp_header_get_free_limit(); - - /* recv_recovery_from_checkpoint_finish needs trx lists which - are initialized in trx_sys_init_at_db_start(). */ - - recv_recovery_from_checkpoint_finish(); + recv_recovery_rollback_active(); /* It is possible that file_format tag has never been set. In this case we initialize it to minimum @@ -1658,15 +1703,18 @@ innobase_start_or_create_for_mysql(void) /* fprintf(stderr, "Max allowed record size %lu\n", page_get_free_space_of_empty() / 2); */ - /* Create the thread which watches the timeouts for lock waits - and prints InnoDB monitor info */ - - os_thread_create(&srv_lock_timeout_and_monitor_thread, NULL, + /* Create the thread which watches the timeouts for lock waits */ + os_thread_create(&srv_lock_timeout_thread, NULL, thread_ids + 2 + SRV_MAX_N_IO_THREADS); /* Create the thread which warns of long semaphore waits */ os_thread_create(&srv_error_monitor_thread, NULL, thread_ids + 3 + SRV_MAX_N_IO_THREADS); + + /* Create the thread which prints InnoDB monitor info */ + os_thread_create(&srv_monitor_thread, NULL, + thread_ids + 4 + SRV_MAX_N_IO_THREADS); + srv_is_being_started = FALSE; if (trx_doublewrite == NULL) { @@ -1675,6 +1723,14 @@ innobase_start_or_create_for_mysql(void) trx_sys_create_doublewrite_buf(); } + /* Here the double write buffer has already been created and so + any new rollback segments will be allocated after the double + write buffer. The default segment should already exist. + We create the new segments only if it's a new database or + the database was shutdown cleanly. */ + + trx_sys_create_rsegs(TRX_SYS_N_RSEGS - 1); + err = dict_create_or_check_foreign_constraint_tables(); if (err != DB_SUCCESS) { @@ -1686,6 +1742,16 @@ innobase_start_or_create_for_mysql(void) os_thread_create(&srv_master_thread, NULL, thread_ids + (1 + SRV_MAX_N_IO_THREADS)); + + /* Currently we allow only a single purge thread. */ + ut_a(srv_n_purge_threads == 0 || srv_n_purge_threads == 1); + + /* If the user has requested a separate purge thread then + start the purge thread. */ + if (srv_n_purge_threads == 1) { + os_thread_create(&srv_purge_thread, NULL, NULL); + } + #ifdef UNIV_DEBUG /* buf_debug_prints = TRUE; */ #endif /* UNIV_DEBUG */ @@ -1779,7 +1845,7 @@ innobase_start_or_create_for_mysql(void) if (srv_print_verbose_log) { ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB Plugin %s started; " + " InnoDB %s started; " "log sequence number %llu\n", INNODB_VERSION_STR, srv_start_lsn); } @@ -1939,7 +2005,10 @@ innobase_shutdown_for_mysql(void) /* c. We wake the master thread so that it exits */ srv_wake_master_thread(); - /* d. Exit the i/o threads */ + /* d. We wake the purge thread so that it exits */ + srv_wake_purge_thread(); + + /* e. Exit the i/o threads */ os_aio_wake_all_threads_at_shutdown(); @@ -2023,10 +2092,14 @@ innobase_shutdown_for_mysql(void) pars_lexer_close(); log_mem_free(); - buf_pool_free(); - ut_free_all_mem(); + buf_pool_free(srv_buf_pool_instances); mem_close(); + /* ut_free_all_mem() frees all allocated memory not freed yet + in shutdown, and it will also free the ut_list_mutex, so it + should be the last one for all operation */ + ut_free_all_mem(); + if (os_thread_count != 0 || os_event_count != 0 || os_mutex_count != 0 diff --git a/storage/innobase/sync/sync0arr.c b/storage/innobase/sync/sync0arr.c index ed9e25bf2f2..248bd2cd25d 100644 --- a/storage/innobase/sync/sync0arr.c +++ b/storage/innobase/sync/sync0arr.c @@ -138,6 +138,11 @@ struct sync_array_struct { since creation of the array */ }; +#ifdef UNIV_PFS_MUTEX +/* Key to register the mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t syn_arr_mutex_key; +#endif + #ifdef UNIV_SYNC_DEBUG /******************************************************************//** This function is called only in the debug version. Detects a deadlock @@ -247,7 +252,8 @@ sync_array_create( if (protection == SYNC_ARRAY_OS_MUTEX) { arr->os_mutex = os_mutex_create(NULL); } else if (protection == SYNC_ARRAY_MUTEX) { - mutex_create(&arr->mutex, SYNC_NO_ORDER_CHECK); + mutex_create(syn_arr_mutex_key, + &arr->mutex, SYNC_NO_ORDER_CHECK); } else { ut_error; } @@ -498,7 +504,9 @@ sync_array_cell_print( || type == RW_LOCK_WAIT_EX || type == RW_LOCK_SHARED) { - fputs(type == RW_LOCK_EX ? "X-lock on" : "S-lock on", file); + fputs(type == RW_LOCK_EX ? "X-lock on" + : type == RW_LOCK_WAIT_EX ? "X-lock (wait_ex) on" + : "S-lock on", file); rwlock = cell->old_wait_rw_lock; diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c index d231b6acdf7..4dbaaa97bd9 100644 --- a/storage/innobase/sync/sync0rw.c +++ b/storage/innobase/sync/sync0rw.c @@ -168,12 +168,22 @@ UNIV_INTERN ib_int64_t rw_x_exit_count = 0; UNIV_INTERN rw_lock_list_t rw_lock_list; UNIV_INTERN mutex_t rw_lock_list_mutex; +#ifdef UNIV_PFS_MUTEX +UNIV_INTERN mysql_pfs_key_t rw_lock_list_mutex_key; +UNIV_INTERN mysql_pfs_key_t rw_lock_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + #ifdef UNIV_SYNC_DEBUG /* The global mutex which protects debug info lists of all rw-locks. To modify the debug info list of an rw-lock, this mutex has to be acquired in addition to the mutex protecting the lock. */ UNIV_INTERN mutex_t rw_lock_debug_mutex; + +# ifdef UNIV_PFS_MUTEX +UNIV_INTERN mysql_pfs_key_t rw_lock_debug_mutex_key; +# endif + /* If deadlock detection does not get immediately the mutex, it may wait for this event */ UNIV_INTERN os_event_t rw_lock_debug_event; @@ -231,7 +241,7 @@ rw_lock_create_func( # ifdef UNIV_SYNC_DEBUG ulint level, /*!< in: level */ # endif /* UNIV_SYNC_DEBUG */ - const char* cmutex_name, /*!< in: mutex name */ + const char* cmutex_name, /*!< in: mutex name */ #endif /* UNIV_DEBUG */ const char* cfile_name, /*!< in: file name where created */ ulint cline) /*!< in: file line where created */ @@ -240,7 +250,8 @@ rw_lock_create_func( created, then the following call initializes the sync system. */ #ifndef INNODB_RW_LOCKS_USE_ATOMICS - mutex_create(rw_lock_get_mutex(lock), SYNC_NO_ORDER_CHECK); + mutex_create(rw_lock_mutex_key, rw_lock_get_mutex(lock), + SYNC_NO_ORDER_CHECK); lock->mutex.cfile_name = cfile_name; lock->mutex.cline = cline; @@ -267,7 +278,7 @@ rw_lock_create_func( lock->level = level; #endif /* UNIV_SYNC_DEBUG */ - lock->magic_n = RW_LOCK_MAGIC_N; + ut_d(lock->magic_n = RW_LOCK_MAGIC_N); lock->cfile_name = cfile_name; lock->cline = (unsigned int) cline; @@ -282,10 +293,8 @@ rw_lock_create_func( mutex_enter(&rw_lock_list_mutex); - if (UT_LIST_GET_LEN(rw_lock_list) > 0) { - ut_a(UT_LIST_GET_FIRST(rw_lock_list)->magic_n - == RW_LOCK_MAGIC_N); - } + ut_ad(UT_LIST_GET_FIRST(rw_lock_list) == NULL + || UT_LIST_GET_FIRST(rw_lock_list)->magic_n == RW_LOCK_MAGIC_N); UT_LIST_ADD_FIRST(list, rw_lock_list, lock); @@ -298,15 +307,13 @@ the rw-lock is freed. Removes an rw-lock object from the global list. The rw-lock is checked to be in the non-locked state. */ UNIV_INTERN void -rw_lock_free( -/*=========*/ +rw_lock_free_func( +/*==============*/ rw_lock_t* lock) /*!< in: rw-lock */ { ut_ad(rw_lock_validate(lock)); ut_a(lock->lock_word == X_LOCK_DECR); - lock->magic_n = 0; - #ifndef INNODB_RW_LOCKS_USE_ATOMICS mutex_free(rw_lock_get_mutex(lock)); #endif /* INNODB_RW_LOCKS_USE_ATOMICS */ @@ -316,16 +323,16 @@ rw_lock_free( os_event_free(lock->wait_ex_event); - if (UT_LIST_GET_PREV(list, lock)) { - ut_a(UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N); - } - if (UT_LIST_GET_NEXT(list, lock)) { - ut_a(UT_LIST_GET_NEXT(list, lock)->magic_n == RW_LOCK_MAGIC_N); - } + ut_ad(UT_LIST_GET_PREV(list, lock) == NULL + || UT_LIST_GET_PREV(list, lock)->magic_n == RW_LOCK_MAGIC_N); + ut_ad(UT_LIST_GET_NEXT(list, lock) == NULL + || UT_LIST_GET_NEXT(list, lock)->magic_n == RW_LOCK_MAGIC_N); UT_LIST_REMOVE(list, rw_lock_list, lock); mutex_exit(&rw_lock_list_mutex); + + ut_d(lock->magic_n = 0); } #ifdef UNIV_DEBUG @@ -339,12 +346,15 @@ rw_lock_validate( /*=============*/ rw_lock_t* lock) /*!< in: rw-lock */ { + ulint waiters; + lint lock_word; + ut_a(lock); - ulint waiters = rw_lock_get_waiters(lock); - lint lock_word = lock->lock_word; + waiters = rw_lock_get_waiters(lock); + lock_word = lock->lock_word; - ut_a(lock->magic_n == RW_LOCK_MAGIC_N); + ut_ad(lock->magic_n == RW_LOCK_MAGIC_N); ut_a(waiters == 0 || waiters == 1); ut_a(lock_word > -X_LOCK_DECR ||(-lock_word) % X_LOCK_DECR == 0); @@ -607,7 +617,7 @@ rw_lock_x_lock_func( { ulint index; /*!< index of the reserved wait cell */ ulint i; /*!< spin round count */ - ibool spinning = FALSE; + ibool spinning = FALSE; ut_ad(rw_lock_validate(lock)); diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index 569fc6328c4..235f733382d 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2008, Google Inc. Portions of this file contain modifications contributed and copyrighted by @@ -198,6 +198,10 @@ UNIV_INTERN sync_thread_t* sync_thread_level_arrays; /** Mutex protecting sync_thread_level_arrays */ UNIV_INTERN mutex_t sync_thread_mutex; + +# ifdef UNIV_PFS_MUTEX +UNIV_INTERN mysql_pfs_key_t sync_thread_mutex_key; +# endif /* UNIV_PFS_MUTEX */ #endif /* UNIV_SYNC_DEBUG */ /** Global list of database mutexes (not OS mutexes) created. */ @@ -206,6 +210,10 @@ UNIV_INTERN ut_list_base_node_t mutex_list; /** Mutex protecting the mutex_list variable */ UNIV_INTERN mutex_t mutex_list_mutex; +#ifdef UNIV_PFS_MUTEX +UNIV_INTERN mysql_pfs_key_t mutex_list_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + #ifdef UNIV_SYNC_DEBUG /** Latching order checks start when this is set TRUE */ UNIV_INTERN ibool sync_order_checks_on = FALSE; @@ -302,19 +310,29 @@ mutex_create_func( } /******************************************************************//** +NOTE! Use the corresponding macro mutex_free(), not directly this function! Calling this function is obligatory only if the memory buffer containing the mutex is freed. Removes a mutex object from the mutex list. The mutex is checked to be in the reset state. */ UNIV_INTERN void -mutex_free( -/*=======*/ +mutex_free_func( +/*============*/ mutex_t* mutex) /*!< in: mutex */ { ut_ad(mutex_validate(mutex)); ut_a(mutex_get_lock_word(mutex) == 0); ut_a(mutex_get_waiters(mutex) == 0); +#ifdef UNIV_MEM_DEBUG + if (mutex == &mem_hash_mutex) { + ut_ad(UT_LIST_GET_LEN(mutex_list) == 1); + ut_ad(UT_LIST_GET_FIRST(mutex_list) == &mem_hash_mutex); + UT_LIST_REMOVE(list, mutex_list, mutex); + goto func_exit; + } +#endif /* UNIV_MEM_DEBUG */ + if (mutex != &mutex_list_mutex #ifdef UNIV_SYNC_DEBUG && mutex != &sync_thread_mutex @@ -336,7 +354,9 @@ mutex_free( } os_event_free(mutex->event); - +#ifdef UNIV_MEM_DEBUG +func_exit: +#endif /* UNIV_MEM_DEBUG */ #if !defined(HAVE_ATOMIC_BUILTINS) os_fast_mutex_free(&(mutex->os_fast_mutex)); #endif @@ -947,12 +967,62 @@ sync_thread_levels_contain( } /******************************************************************//** +Checks if the level array for the current thread contains a +mutex or rw-latch at the specified level. +@return a matching latch, or NULL if not found */ +UNIV_INTERN +void* +sync_thread_levels_contains( +/*========================*/ + ulint level) /*!< in: latching order level + (SYNC_DICT, ...)*/ +{ + sync_level_t* arr; + sync_thread_t* thread_slot; + sync_level_t* slot; + ulint i; + + if (!sync_order_checks_on) { + + return(NULL); + } + + mutex_enter(&sync_thread_mutex); + + thread_slot = sync_thread_level_arrays_find_slot(); + + if (thread_slot == NULL) { + + mutex_exit(&sync_thread_mutex); + + return(NULL); + } + + arr = thread_slot->levels; + + for (i = 0; i < SYNC_THREAD_N_LEVELS; i++) { + + slot = sync_thread_levels_get_nth(arr, i); + + if (slot->latch != NULL && slot->level == level) { + + mutex_exit(&sync_thread_mutex); + return(slot->latch); + } + } + + mutex_exit(&sync_thread_mutex); + + return(NULL); +} + +/******************************************************************//** Checks that the level array for the current thread is empty. -@return TRUE if empty except the exceptions specified below */ +@return a latch, or NULL if empty except the exceptions specified below */ UNIV_INTERN -ibool -sync_thread_levels_empty_gen( -/*=========================*/ +void* +sync_thread_levels_nonempty_gen( +/*============================*/ ibool dict_mutex_allowed) /*!< in: TRUE if dictionary mutex is allowed to be owned by the thread, also purge_is_running mutex is @@ -965,7 +1035,7 @@ sync_thread_levels_empty_gen( if (!sync_order_checks_on) { - return(TRUE); + return(NULL); } mutex_enter(&sync_thread_mutex); @@ -976,7 +1046,7 @@ sync_thread_levels_empty_gen( mutex_exit(&sync_thread_mutex); - return(TRUE); + return(NULL); } arr = thread_slot->levels; @@ -993,13 +1063,13 @@ sync_thread_levels_empty_gen( mutex_exit(&sync_thread_mutex); ut_error; - return(FALSE); + return(slot->latch); } } mutex_exit(&sync_thread_mutex); - return(TRUE); + return(NULL); } /******************************************************************//** @@ -1087,12 +1157,12 @@ sync_thread_add_level( case SYNC_RECV: case SYNC_WORK_QUEUE: case SYNC_LOG: + case SYNC_LOG_FLUSH_ORDER: case SYNC_THR_LOCAL: case SYNC_ANY_LATCH: case SYNC_TRX_SYS_HEADER: case SYNC_FILE_FORMAT_TAG: case SYNC_DOUBLEWRITE: - case SYNC_BUF_POOL: case SYNC_SEARCH_SYS: case SYNC_SEARCH_SYS_CONF: case SYNC_TRX_LOCK_HEAP: @@ -1114,6 +1184,18 @@ sync_thread_add_level( ut_error; } break; + case SYNC_BUF_FLUSH_LIST: + case SYNC_BUF_POOL: + /* We can have multiple mutexes of this type therefore we + can only check whether the greater than condition holds. */ + if (!sync_thread_levels_g(array, level-1, TRUE)) { + fprintf(stderr, + "InnoDB: sync_thread_levels_g(array, %lu)" + " does not hold!\n", level-1); + ut_error; + } + break; + case SYNC_BUF_BLOCK: /* Either the thread must own the buffer pool mutex (buf_pool_mutex), or it is allowed to latch only ONE @@ -1337,18 +1419,22 @@ sync_init(void) /* Init the mutex list and create the mutex to protect it. */ UT_LIST_INIT(mutex_list); - mutex_create(&mutex_list_mutex, SYNC_NO_ORDER_CHECK); + mutex_create(mutex_list_mutex_key, &mutex_list_mutex, + SYNC_NO_ORDER_CHECK); #ifdef UNIV_SYNC_DEBUG - mutex_create(&sync_thread_mutex, SYNC_NO_ORDER_CHECK); + mutex_create(sync_thread_mutex_key, &sync_thread_mutex, + SYNC_NO_ORDER_CHECK); #endif /* UNIV_SYNC_DEBUG */ /* Init the rw-lock list and create the mutex to protect it. */ UT_LIST_INIT(rw_lock_list); - mutex_create(&rw_lock_list_mutex, SYNC_NO_ORDER_CHECK); + mutex_create(rw_lock_list_mutex_key, &rw_lock_list_mutex, + SYNC_NO_ORDER_CHECK); #ifdef UNIV_SYNC_DEBUG - mutex_create(&rw_lock_debug_mutex, SYNC_NO_ORDER_CHECK); + mutex_create(rw_lock_debug_mutex_key, &rw_lock_debug_mutex, + SYNC_NO_ORDER_CHECK); rw_lock_debug_event = os_event_create(NULL); rw_lock_debug_waiters = FALSE; @@ -1370,6 +1456,12 @@ sync_close(void) mutex = UT_LIST_GET_FIRST(mutex_list); while (mutex) { +#ifdef UNIV_MEM_DEBUG + if (mutex == &mem_hash_mutex) { + mutex = UT_LIST_GET_NEXT(list, mutex); + continue; + } +#endif /* UNIV_MEM_DEBUG */ mutex_free(mutex); mutex = UT_LIST_GET_FIRST(mutex_list); } diff --git a/storage/innobase/thr/thr0loc.c b/storage/innobase/thr/thr0loc.c index 59a234a6b72..045ff3e9fb1 100644 --- a/storage/innobase/thr/thr0loc.c +++ b/storage/innobase/thr/thr0loc.c @@ -53,6 +53,11 @@ static hash_table_t* thr_local_hash = NULL; /** Thread local data */ typedef struct thr_local_struct thr_local_t; +#ifdef UNIV_PFS_MUTEX +/* Key to register the mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t thr_local_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + /** @brief Thread local data. The private data for each thread should be put to the structure below and the accessor functions written @@ -244,7 +249,8 @@ thr_local_init(void) thr_local_hash = hash_create(OS_THREAD_MAX_N + 100); - mutex_create(&thr_local_mutex, SYNC_THR_LOCAL); + mutex_create(thr_local_mutex_key, + &thr_local_mutex, SYNC_THR_LOCAL); } /******************************************************************** diff --git a/storage/innobase/trx/trx0i_s.c b/storage/innobase/trx/trx0i_s.c index a3f73e0c9e8..8b719646023 100644 --- a/storage/innobase/trx/trx0i_s.c +++ b/storage/innobase/trx/trx0i_s.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2007, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 2007, 2010, Innobase Oy. All Rights Reserved. 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 @@ -193,6 +193,15 @@ INFORMATION SCHEMA tables is fetched and later retrieved by the C++ code in handler/i_s.cc. */ UNIV_INTERN trx_i_s_cache_t* trx_i_s_cache = &trx_i_s_cache_static; +/* Key to register the lock/mutex with performance schema */ +#ifdef UNIV_PFS_RWLOCK +UNIV_INTERN mysql_pfs_key_t trx_i_s_cache_lock_key; +#endif /* UNIV_PFS_RWLOCK */ + +#ifdef UNIV_PFS_MUTEX +UNIV_INTERN mysql_pfs_key_t cache_last_read_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + /*******************************************************************//** For a record lock that is in waiting state retrieves the only bit that is set, for a table lock returns ULINT_UNDEFINED. @@ -429,6 +438,12 @@ fill_trx_row( which to copy volatile strings */ { + const char* stmt; + size_t stmt_len; + const char* s; + + ut_ad(mutex_own(&kernel_mutex)); + row->trx_id = trx_get_id(trx); row->trx_started = (ib_time_t) trx->start_time; row->trx_state = trx_get_que_state_str(trx); @@ -449,37 +464,32 @@ fill_trx_row( row->trx_weight = (ullint) ut_conv_dulint_to_longlong(TRX_WEIGHT(trx)); - if (trx->mysql_thd != NULL) { - row->trx_mysql_thread_id - = thd_get_thread_id(trx->mysql_thd); - } else { + if (trx->mysql_thd == NULL) { /* For internal transactions e.g., purge and transactions being recovered at startup there is no associated MySQL thread data structure. */ row->trx_mysql_thread_id = 0; + row->trx_query = NULL; + goto thd_done; } - if (trx->mysql_query_str != NULL && *trx->mysql_query_str != NULL) { + row->trx_mysql_thread_id = thd_get_thread_id(trx->mysql_thd); + stmt = innobase_get_stmt(trx->mysql_thd, &stmt_len); - if (strlen(*trx->mysql_query_str) - > TRX_I_S_TRX_QUERY_MAX_LEN) { + if (stmt != NULL) { - char query[TRX_I_S_TRX_QUERY_MAX_LEN + 1]; + char query[TRX_I_S_TRX_QUERY_MAX_LEN + 1]; - memcpy(query, *trx->mysql_query_str, - TRX_I_S_TRX_QUERY_MAX_LEN); - query[TRX_I_S_TRX_QUERY_MAX_LEN] = '\0'; + if (stmt_len > TRX_I_S_TRX_QUERY_MAX_LEN) { + stmt_len = TRX_I_S_TRX_QUERY_MAX_LEN; + } - row->trx_query = ha_storage_put_memlim( - cache->storage, query, - TRX_I_S_TRX_QUERY_MAX_LEN + 1, - MAX_ALLOWED_FOR_STORAGE(cache)); - } else { + memcpy(query, stmt, stmt_len); + query[stmt_len] = '\0'; - row->trx_query = ha_storage_put_str_memlim( - cache->storage, *trx->mysql_query_str, - MAX_ALLOWED_FOR_STORAGE(cache)); - } + row->trx_query = ha_storage_put_memlim( + cache->storage, stmt, stmt_len + 1, + MAX_ALLOWED_FOR_STORAGE(cache)); if (row->trx_query == NULL) { @@ -490,6 +500,79 @@ fill_trx_row( row->trx_query = NULL; } +thd_done: + s = trx->op_info; + + if (s != NULL && s[0] != '\0') { + + TRX_I_S_STRING_COPY(s, row->trx_operation_state, + TRX_I_S_TRX_OP_STATE_MAX_LEN, cache); + + if (row->trx_operation_state == NULL) { + + return(FALSE); + } + } else { + + row->trx_operation_state = NULL; + } + + row->trx_tables_in_use = trx->n_mysql_tables_in_use; + + row->trx_tables_locked = trx->mysql_n_tables_locked; + + row->trx_lock_structs = UT_LIST_GET_LEN(trx->trx_locks); + + row->trx_lock_memory_bytes = mem_heap_get_size(trx->lock_heap); + + row->trx_rows_locked = lock_number_of_rows_locked(trx); + + row->trx_rows_modified = ut_conv_dulint_to_longlong(trx->undo_no); + + row->trx_concurrency_tickets = trx->n_tickets_to_enter_innodb; + + switch (trx->isolation_level) { + case TRX_ISO_READ_UNCOMMITTED: + row->trx_isolation_level = "READ UNCOMMITTED"; + break; + case TRX_ISO_READ_COMMITTED: + row->trx_isolation_level = "READ COMMITTED"; + break; + case TRX_ISO_REPEATABLE_READ: + row->trx_isolation_level = "REPEATABLE READ"; + break; + case TRX_ISO_SERIALIZABLE: + row->trx_isolation_level = "SERIALIZABLE"; + break; + /* Should not happen as TRX_ISO_READ_COMMITTED is default */ + default: + row->trx_isolation_level = "UNKNOWN"; + } + + row->trx_unique_checks = (ibool) trx->check_unique_secondary; + + row->trx_foreign_key_checks = (ibool) trx->check_foreigns; + + s = trx->detailed_error; + + if (s != NULL && s[0] != '\0') { + + TRX_I_S_STRING_COPY(s, + row->trx_foreign_key_error, + TRX_I_S_TRX_FK_ERROR_MAX_LEN, cache); + + if (row->trx_foreign_key_error == NULL) { + + return(FALSE); + } + } else { + row->trx_foreign_key_error = NULL; + } + + row->trx_has_search_latch = (ibool) trx->has_search_latch; + + row->trx_search_latch_timeout = trx->search_latch_timeout; + return(TRUE); } @@ -1253,11 +1336,13 @@ trx_i_s_cache_init( release trx_i_s_cache_t::last_read_mutex release trx_i_s_cache_t::rw_lock */ - rw_lock_create(&cache->rw_lock, SYNC_TRX_I_S_RWLOCK); + rw_lock_create(trx_i_s_cache_lock_key, &cache->rw_lock, + SYNC_TRX_I_S_RWLOCK); cache->last_read = 0; - mutex_create(&cache->last_read_mutex, SYNC_TRX_I_S_LAST_READ); + mutex_create(cache_last_read_mutex_key, + &cache->last_read_mutex, SYNC_TRX_I_S_LAST_READ); table_cache_init(&cache->innodb_trx, sizeof(i_s_trx_row_t)); table_cache_init(&cache->innodb_locks, sizeof(i_s_locks_row_t)); diff --git a/storage/innobase/trx/trx0purge.c b/storage/innobase/trx/trx0purge.c index abbfa3d7f81..550a8c9c4b3 100644 --- a/storage/innobase/trx/trx0purge.c +++ b/storage/innobase/trx/trx0purge.c @@ -41,7 +41,7 @@ Created 3/26/1996 Heikki Tuuri #include "row0purge.h" #include "row0upd.h" #include "trx0rec.h" -#include "srv0que.h" +#include "srv0srv.h" #include "os0thread.h" /** The global data structure coordinating a purge */ @@ -51,6 +51,16 @@ UNIV_INTERN trx_purge_t* purge_sys = NULL; which needs no purge */ UNIV_INTERN trx_undo_rec_t trx_purge_dummy_rec; +#ifdef UNIV_PFS_RWLOCK +/* Key to register trx_purge_latch with performance schema */ +UNIV_INTERN mysql_pfs_key_t trx_purge_latch_key; +#endif /* UNIV_PFS_RWLOCK */ + +#ifdef UNIV_PFS_MUTEX +/* Key to register purge_sys_mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t purge_sys_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + /*****************************************************************//** Checks if trx_id is >= purge_view: then it is guaranteed that its update undo log still exists in the system. @@ -227,9 +237,11 @@ trx_purge_sys_create(void) purge_sys->purge_undo_no = ut_dulint_zero; purge_sys->next_stored = FALSE; - rw_lock_create(&purge_sys->latch, SYNC_PURGE_LATCH); + rw_lock_create(trx_purge_latch_key, + &purge_sys->latch, SYNC_PURGE_LATCH); - mutex_create(&purge_sys->mutex, SYNC_PURGE_SYS); + mutex_create(purge_sys_mutex_key, + &purge_sys->mutex, SYNC_PURGE_SYS); purge_sys->heap = mem_heap_create(256); @@ -352,6 +364,11 @@ trx_purge_add_update_undo_to_history( trx_sys->rseg_history_len++; mutex_exit(&kernel_mutex); + if (!(trx_sys->rseg_history_len % srv_purge_batch_size)) { + /* Inform the purge thread that there is work to do. */ + srv_wake_purge_thread_if_not_active(); + } + /* Write the trx number to the undo log header */ mlog_write_dulint(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr); /* Write information about delete markings to the undo log header */ @@ -1084,8 +1101,10 @@ This function runs a purge batch. @return number of undo log pages handled in the batch */ UNIV_INTERN ulint -trx_purge(void) -/*===========*/ +trx_purge( +/*======*/ + ulint limit) /*!< in: the maximum number of records to + purge in one batch */ { que_thr_t* thr; /* que_thr_t* thr2; */ @@ -1146,9 +1165,7 @@ trx_purge(void) purge_sys->state = TRX_PURGE_ON; - /* Handle at most 20 undo log pages in one purge batch */ - - purge_sys->handle_limit = purge_sys->n_pages_handled + 20; + purge_sys->handle_limit = purge_sys->n_pages_handled + limit; old_pages_handled = purge_sys->n_pages_handled; diff --git a/storage/innobase/trx/trx0rec.c b/storage/innobase/trx/trx0rec.c index 5097cf18dcd..f50e10ed756 100644 --- a/storage/innobase/trx/trx0rec.c +++ b/storage/innobase/trx/trx0rec.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -350,8 +350,13 @@ trx_undo_rec_get_col_val( ut_ad(*orig_len >= BTR_EXTERN_FIELD_REF_SIZE); ut_ad(*len > *orig_len); - ut_ad(*len >= REC_MAX_INDEX_COL_LEN + /* @see dtuple_convert_big_rec() */ + ut_ad(*len >= BTR_EXTERN_FIELD_REF_SIZE * 2); + /* we do not have access to index->table here + ut_ad(dict_table_get_format(index->table) >= DICT_TF_FORMAT_ZIP + || *len >= REC_MAX_INDEX_COL_LEN + BTR_EXTERN_FIELD_REF_SIZE); + */ *len += UNIV_EXTERN_STORAGE_FIELD; break; @@ -977,6 +982,7 @@ trx_undo_update_rec_get_update( fprintf(stderr, "\n" "InnoDB: n_fields = %lu, i = %lu, ptr %p\n", (ulong) n_fields, (ulong) i, ptr); + *upd = NULL; return(NULL); } @@ -1074,11 +1080,15 @@ trx_undo_rec_get_partial_row( /* If the prefix of this column is indexed, ensure that enough prefix is stored in the undo log record. */ - ut_a(ignore_prefix - || !col->ord_part - || dfield_get_len(dfield) - >= REC_MAX_INDEX_COL_LEN - + BTR_EXTERN_FIELD_REF_SIZE); + if (!ignore_prefix && col->ord_part) { + ut_a(dfield_get_len(dfield) + >= 2 * BTR_EXTERN_FIELD_REF_SIZE); + ut_a(dict_table_get_format(index->table) + >= DICT_TF_FORMAT_ZIP + || dfield_get_len(dfield) + >= REC_MAX_INDEX_COL_LEN + + BTR_EXTERN_FIELD_REF_SIZE); + } } } diff --git a/storage/innobase/trx/trx0roll.c b/storage/innobase/trx/trx0roll.c index c925478cdf4..4f1a71a5531 100644 --- a/storage/innobase/trx/trx0roll.c +++ b/storage/innobase/trx/trx0roll.c @@ -37,7 +37,6 @@ Created 3/26/1996 Heikki Tuuri #include "trx0rec.h" #include "que0que.h" #include "usr0sess.h" -#include "srv0que.h" #include "srv0start.h" #include "row0undo.h" #include "row0mysql.h" @@ -615,6 +614,10 @@ trx_rollback_or_clean_all_recovered( /*!< in: a dummy parameter required by os_thread_create */ { +#ifdef UNIV_PFS_THREAD + pfs_register_thread(trx_rollback_clean_thread_key); +#endif /* UNIV_PFS_THREAD */ + trx_rollback_or_clean_recovered(TRUE); /* We count the number of threads in os_thread_exit(). A created diff --git a/storage/innobase/trx/trx0rseg.c b/storage/innobase/trx/trx0rseg.c index 8d754788e2a..b458364b05d 100644 --- a/storage/innobase/trx/trx0rseg.c +++ b/storage/innobase/trx/trx0rseg.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -34,6 +34,11 @@ Created 3/26/1996 Heikki Tuuri #include "srv0srv.h" #include "trx0purge.h" +#ifdef UNIV_PFS_MUTEX +/* Key to register rseg_mutex_key with performance schema */ +UNIV_INTERN mysql_pfs_key_t rseg_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + /******************************************************************//** Looks for a rollback segment, based on the rollback segment id. @return rollback segment */ @@ -46,11 +51,9 @@ trx_rseg_get_on_id( trx_rseg_t* rseg; rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list); - ut_ad(rseg); - while (rseg->id != id) { + while (rseg && rseg->id != id) { rseg = UT_LIST_GET_NEXT(rseg_list, rseg); - ut_ad(rseg); } return(rseg); @@ -68,7 +71,7 @@ trx_rseg_header_create( ulint zip_size, /*!< in: compressed page size in bytes or 0 for uncompressed pages */ ulint max_size, /*!< in: max size in pages */ - ulint* slot_no, /*!< out: rseg id == slot number in trx sys */ + ulint rseg_slot_no, /*!< in: rseg id == slot number in trx sys */ mtr_t* mtr) /*!< in: mtr */ { ulint page_no; @@ -81,14 +84,6 @@ trx_rseg_header_create( ut_ad(mutex_own(&kernel_mutex)); ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL), MTR_MEMO_X_LOCK)); - sys_header = trx_sysf_get(mtr); - - *slot_no = trx_sysf_rseg_find_free(mtr); - - if (*slot_no == ULINT_UNDEFINED) { - - return(FIL_NULL); - } /* Allocate a new file segment for the rollback segment */ block = fseg_create(space, 0, @@ -122,11 +117,13 @@ trx_rseg_header_create( trx_rsegf_set_nth_undo(rsegf, i, FIL_NULL, mtr); } - /* Add the rollback segment info to the free slot in the trx system - header */ + /* Add the rollback segment info to the free slot in + the trx system header */ - trx_sysf_rseg_set_space(sys_header, *slot_no, space, mtr); - trx_sysf_rseg_set_page_no(sys_header, *slot_no, page_no, mtr); + sys_header = trx_sysf_get(mtr); + + trx_sysf_rseg_set_space(sys_header, rseg_slot_no, space, mtr); + trx_sysf_rseg_set_page_no(sys_header, rseg_slot_no, page_no, mtr); return(page_no); } @@ -191,23 +188,23 @@ trx_rseg_mem_create( ulint page_no, /*!< in: page number of the segment header */ mtr_t* mtr) /*!< in: mtr */ { - trx_rsegf_t* rseg_header; + ulint len; trx_rseg_t* rseg; - trx_ulogf_t* undo_log_hdr; fil_addr_t node_addr; + trx_rsegf_t* rseg_header; + trx_ulogf_t* undo_log_hdr; ulint sum_of_undo_sizes; - ulint len; ut_ad(mutex_own(&kernel_mutex)); - rseg = mem_alloc(sizeof(trx_rseg_t)); + rseg = mem_zalloc(sizeof(trx_rseg_t)); rseg->id = id; rseg->space = space; rseg->zip_size = zip_size; rseg->page_no = page_no; - mutex_create(&rseg->mutex, SYNC_RSEG); + mutex_create(rseg_mutex_key, &rseg->mutex, SYNC_RSEG); UT_LIST_ADD_LAST(rseg_list, trx_sys->rseg_list, rseg); @@ -250,75 +247,108 @@ trx_rseg_mem_create( return(rseg); } -/*********************************************************************//** -Creates the memory copies for rollback segments and initializes the +/******************************************************************** +Creates the memory copies for the rollback segments and initializes the rseg list and array in trx_sys at a database startup. */ -UNIV_INTERN +static void -trx_rseg_list_and_array_init( -/*=========================*/ +trx_rseg_create_instance( +/*=====================*/ trx_sysf_t* sys_header, /*!< in: trx system header */ mtr_t* mtr) /*!< in: mtr */ { - ulint i; - ulint page_no; - ulint space; - - UT_LIST_INIT(trx_sys->rseg_list); - - trx_sys->rseg_history_len = 0; + ulint i; for (i = 0; i < TRX_SYS_N_RSEGS; i++) { + ulint page_no; page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr); if (page_no == FIL_NULL) { - trx_sys_set_nth_rseg(trx_sys, i, NULL); } else { - ulint zip_size; + ulint space; + ulint zip_size; + trx_rseg_t* rseg = NULL; + + ut_a(!trx_rseg_get_on_id(i)); space = trx_sysf_rseg_get_space(sys_header, i, mtr); zip_size = space ? fil_space_get_zip_size(space) : 0; - trx_rseg_mem_create(i, space, zip_size, page_no, mtr); + rseg = trx_rseg_mem_create( + i, space, zip_size, page_no, mtr); + + ut_a(rseg->id == i); } } } -/****************************************************************//** -Creates a new rollback segment to the database. -@return the created segment object, NULL if fail */ +/********************************************************************* +Creates a rollback segment. +@return pointer to new rollback segment if create successful */ UNIV_INTERN trx_rseg_t* -trx_rseg_create( -/*============*/ - ulint space, /*!< in: space id */ - ulint max_size, /*!< in: max size in pages */ - ulint* id, /*!< out: rseg id */ - mtr_t* mtr) /*!< in: mtr */ +trx_rseg_create(void) +/*=================*/ { - ulint flags; - ulint zip_size; - ulint page_no; - trx_rseg_t* rseg; + mtr_t mtr; + ulint slot_no; + trx_rseg_t* rseg = NULL; + + mtr_start(&mtr); + + /* To obey the latching order, acquire the file space + x-latch before the kernel mutex. */ + mtr_x_lock(fil_space_get_latch(TRX_SYS_SPACE, NULL), &mtr); - mtr_x_lock(fil_space_get_latch(space, &flags), mtr); - zip_size = dict_table_flags_to_zip_size(flags); mutex_enter(&kernel_mutex); - page_no = trx_rseg_header_create(space, zip_size, max_size, id, mtr); + slot_no = trx_sysf_rseg_find_free(&mtr); - if (page_no == FIL_NULL) { + if (slot_no != ULINT_UNDEFINED) { + ulint space; + ulint page_no; + ulint zip_size; + trx_sysf_t* sys_header; - mutex_exit(&kernel_mutex); - return(NULL); - } + page_no = trx_rseg_header_create( + TRX_SYS_SPACE, 0, ULINT_MAX, slot_no, &mtr); + + ut_a(page_no != FIL_NULL); + + ut_ad(!trx_rseg_get_on_id(slot_no)); - rseg = trx_rseg_mem_create(*id, space, zip_size, page_no, mtr); + sys_header = trx_sysf_get(&mtr); + + space = trx_sysf_rseg_get_space(sys_header, slot_no, &mtr); + + zip_size = space ? fil_space_get_zip_size(space) : 0; + + rseg = trx_rseg_mem_create( + slot_no, space, zip_size, page_no, &mtr); + } mutex_exit(&kernel_mutex); + mtr_commit(&mtr); return(rseg); } + +/******************************************************************** +Initialize the rollback instance list. */ +UNIV_INTERN +void +trx_rseg_list_and_array_init( +/*=========================*/ + trx_sysf_t* sys_header, /* in: trx system header */ + mtr_t* mtr) /* in: mtr */ +{ + UT_LIST_INIT(trx_sys->rseg_list); + + trx_sys->rseg_history_len = 0; + + trx_rseg_create_instance(sys_header, mtr); +} + diff --git a/storage/innobase/trx/trx0sys.c b/storage/innobase/trx/trx0sys.c index 79e5af1c677..9c531e64662 100644 --- a/storage/innobase/trx/trx0sys.c +++ b/storage/innobase/trx/trx0sys.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -39,6 +39,7 @@ Created 3/26/1996 Heikki Tuuri #include "srv0srv.h" #include "trx0purge.h" #include "log0log.h" +#include "log0recv.h" #include "os0file.h" #include "read0read.h" @@ -126,6 +127,12 @@ static const char* file_format_name_map[] = { static const ulint FILE_FORMAT_NAME_N = sizeof(file_format_name_map) / sizeof(file_format_name_map[0]); +#ifdef UNIV_PFS_MUTEX +/* Key to register the mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t trx_doublewrite_mutex_key; +UNIV_INTERN mysql_pfs_key_t file_format_max_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + #ifndef UNIV_HOTBACKUP /** This is used to track the maximum file format id known to InnoDB. It's updated via SET GLOBAL innodb_file_format_check = 'x' or when we open @@ -179,7 +186,8 @@ trx_doublewrite_init( os_do_not_call_flush_at_each_write = TRUE; #endif /* UNIV_DO_FLUSH */ - mutex_create(&trx_doublewrite->mutex, SYNC_DOUBLEWRITE); + mutex_create(trx_doublewrite_mutex_key, + &trx_doublewrite->mutex, SYNC_DOUBLEWRITE); trx_doublewrite->first_free = 0; @@ -584,8 +592,8 @@ trx_sys_doublewrite_init_or_restore_pages( " recover the database" " with the my.cnf\n" "InnoDB: option:\n" - "InnoDB: set-variable=" - "innodb_force_recovery=6\n"); + "InnoDB:" + " innodb_force_recovery=6\n"); exit(1); } @@ -870,7 +878,8 @@ trx_sysf_create( buf_block_t* block; page_t* page; ulint page_no; - ulint i; + byte* ptr; + ulint len; ut_ad(mtr); @@ -903,32 +912,31 @@ trx_sysf_create( sys_header = trx_sysf_get(mtr); /* Start counting transaction ids from number 1 up */ - mlog_write_dulint(sys_header + TRX_SYS_TRX_ID_STORE, - ut_dulint_create(0, 1), mtr); + mach_write_to_8(sys_header + TRX_SYS_TRX_ID_STORE, + ut_dulint_create(0, 1)); - /* Reset the rollback segment slots */ - for (i = 0; i < TRX_SYS_N_RSEGS; i++) { + /* Reset the rollback segment slots. Old versions of InnoDB + define TRX_SYS_N_RSEGS as 256 (TRX_SYS_OLD_N_RSEGS) and expect + that the whole array is initialized. */ + ptr = TRX_SYS_RSEGS + sys_header; + len = ut_max(TRX_SYS_OLD_N_RSEGS, TRX_SYS_N_RSEGS) + * TRX_SYS_RSEG_SLOT_SIZE; + memset(ptr, 0xff, len); + ptr += len; + ut_a(ptr <= page + (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END)); - trx_sysf_rseg_set_space(sys_header, i, ULINT_UNDEFINED, mtr); - trx_sysf_rseg_set_page_no(sys_header, i, FIL_NULL, mtr); - } + /* Initialize all of the page. This part used to be uninitialized. */ + memset(ptr, 0, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + page - ptr); - /* The remaining area (up to the page trailer) is uninitialized. - Silence Valgrind warnings about it. */ - UNIV_MEM_VALID(sys_header + (TRX_SYS_RSEGS - + TRX_SYS_N_RSEGS * TRX_SYS_RSEG_SLOT_SIZE - + TRX_SYS_RSEG_SPACE), - (UNIV_PAGE_SIZE - FIL_PAGE_DATA_END - - (TRX_SYS_RSEGS - + TRX_SYS_N_RSEGS * TRX_SYS_RSEG_SLOT_SIZE - + TRX_SYS_RSEG_SPACE)) - + page - sys_header); + mlog_log_string(sys_header, UNIV_PAGE_SIZE - FIL_PAGE_DATA_END + + page - sys_header, mtr); /* Create the first rollback segment in the SYSTEM tablespace */ - page_no = trx_rseg_header_create(TRX_SYS_SPACE, 0, ULINT_MAX, &slot_no, + slot_no = trx_sysf_rseg_find_free(mtr); + page_no = trx_rseg_header_create(TRX_SYS_SPACE, 0, ULINT_MAX, slot_no, mtr); ut_a(slot_no == TRX_SYS_SYSTEM_RSEG_ID); - ut_a(page_no != FIL_NULL); + ut_a(page_no == FSP_FIRST_RSEG_PAGE_NO); mutex_exit(&kernel_mutex); } @@ -1283,7 +1291,8 @@ void trx_sys_file_format_init(void) /*==========================*/ { - mutex_create(&file_format_max.mutex, SYNC_FILE_FORMAT_TAG); + mutex_create(file_format_max_mutex_key, + &file_format_max.mutex, SYNC_FILE_FORMAT_TAG); /* We don't need a mutex here, as this function should only be called once at start up. */ @@ -1302,6 +1311,40 @@ trx_sys_file_format_close(void) { /* Does nothing at the moment */ } + +/********************************************************************* +Creates the rollback segments */ +UNIV_INTERN +void +trx_sys_create_rsegs( +/*=================*/ + ulint n_rsegs) /*!< number of rollback segments to create */ +{ + ulint new_rsegs = 0; + + /* Do not create additional rollback segments if + innodb_force_recovery has been set and the database + was not shutdown cleanly. */ + if (!srv_force_recovery && !recv_needed_recovery) { + ulint i; + + for (i = 0; i < n_rsegs; ++i) { + + if (trx_rseg_create() != NULL) { + ++new_rsegs; + } else { + break; + } + } + } + + if (new_rsegs > 0) { + fprintf(stderr, + "InnoDB: %lu rollback segment(s) active.\n", + new_rsegs); + } +} + #else /* !UNIV_HOTBACKUP */ /*****************************************************************//** Prints to stderr the MySQL binlog info in the system header if the @@ -1376,8 +1419,9 @@ trx_sys_read_file_format_id( dulint file_format_id; *format_id = ULINT_UNDEFINED; - + file = os_file_create_simple_no_error_handling( + innodb_file_data_key, pathname, OS_FILE_OPEN, OS_FILE_READ_ONLY, @@ -1456,8 +1500,9 @@ trx_sys_read_pertable_file_format_id( ib_uint32_t flags; *format_id = ULINT_UNDEFINED; - + file = os_file_create_simple_no_error_handling( + innodb_file_data_key, pathname, OS_FILE_OPEN, OS_FILE_READ_ONLY, @@ -1535,6 +1580,7 @@ trx_sys_file_format_id_to_name( #endif /* !UNIV_HOTBACKUP */ +#ifndef UNIV_HOTBACKUP /********************************************************************* Shutdown/Close the transaction system. */ UNIV_INTERN @@ -1611,3 +1657,4 @@ trx_sys_close(void) trx_sys = NULL; mutex_exit(&kernel_mutex); } +#endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index 0951b98b79f..c794671f7be 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1996, 2010, Innobase Oy. All Rights Reserved. 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 @@ -51,6 +51,11 @@ UNIV_INTERN sess_t* trx_dummy_sess = NULL; the kernel mutex */ UNIV_INTERN ulint trx_n_mysql_transactions = 0; +#ifdef UNIV_PFS_MUTEX +/* Key to register the mutex with performance schema */ +UNIV_INTERN mysql_pfs_key_t trx_undo_mutex_key; +#endif /* UNIV_PFS_MUTEX */ + /*************************************************************//** Set detailed error message for the transaction. */ UNIV_INTERN @@ -119,7 +124,6 @@ trx_create( trx->table_id = ut_dulint_zero; trx->mysql_thd = NULL; - trx->mysql_query_str = NULL; trx->active_trans = 0; trx->duplicates = 0; @@ -129,7 +133,7 @@ trx_create( trx->mysql_log_file_name = NULL; trx->mysql_log_offset = 0; - mutex_create(&trx->undo_mutex, SYNC_TRX_UNDO); + mutex_create(trx_undo_mutex_key, &trx->undo_mutex, SYNC_TRX_UNDO); trx->rseg = NULL; @@ -425,6 +429,7 @@ trx_lists_init_at_db_start(void) trx_undo_t* undo; trx_t* trx; + ut_ad(mutex_own(&kernel_mutex)); UT_LIST_INIT(trx_sys->trx_list); /* Look from the rollback segments if there exist undo logs for @@ -758,7 +763,6 @@ trx_commit_off_kernel( if (undo) { mutex_enter(&kernel_mutex); trx->no = trx_sys_get_new_trx_no(); - mutex_exit(&kernel_mutex); /* It is not necessary to obtain trx->undo_mutex here @@ -842,7 +846,7 @@ trx_commit_off_kernel( recovery i.e.: back ground rollback thread is still active then there is a chance that the rollback thread may see this trx as COMMITTED_IN_MEMORY and goes adhead to clean it - up calling trx_cleanup_at_db_startup(). This can happen + up calling trx_cleanup_at_db_startup(). This can happen in the case we are committing a trx here that is left in PREPARED state during the crash. Note that commit of the rollback of a PREPARED trx happens in the recovery thread @@ -939,7 +943,6 @@ trx_commit_off_kernel( trx->rseg = NULL; trx->undo_no = ut_dulint_zero; trx->last_sql_stat_start.least_undo_no = ut_dulint_zero; - trx->mysql_query_str = NULL; ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0); ut_ad(UT_LIST_GET_LEN(trx->trx_locks) == 0); diff --git a/storage/innobase/trx/trx0undo.c b/storage/innobase/trx/trx0undo.c index 3bb1b1cdf6c..eb5112c4d31 100644 --- a/storage/innobase/trx/trx0undo.c +++ b/storage/innobase/trx/trx0undo.c @@ -1938,7 +1938,8 @@ trx_undo_update_cleanup( UT_LIST_ADD_FIRST(undo_list, rseg->update_undo_cached, undo); } else { - ut_ad(undo->state == TRX_UNDO_TO_PURGE); + ut_ad(undo->state == TRX_UNDO_TO_PURGE + || undo->state == TRX_UNDO_TO_FREE); trx_undo_mem_free(undo); } diff --git a/storage/innobase/ut/ut0mem.c b/storage/innobase/ut/ut0mem.c index 35a325b9ccd..f2baab67f09 100644 --- a/storage/innobase/ut/ut0mem.c +++ b/storage/innobase/ut/ut0mem.c @@ -290,17 +290,20 @@ ut_test_malloc( #endif /* !UNIV_HOTBACKUP */ /**********************************************************************//** -Frees a memory block allocated with ut_malloc. */ +Frees a memory block allocated with ut_malloc. Freeing a NULL pointer is +a nop. */ UNIV_INTERN void ut_free( /*====*/ - void* ptr) /*!< in, own: memory block */ + void* ptr) /*!< in, own: memory block, can be NULL */ { #ifndef UNIV_HOTBACKUP ut_mem_block_t* block; - if (UNIV_LIKELY(srv_use_sys_malloc)) { + if (ptr == NULL) { + return; + } else if (UNIV_LIKELY(srv_use_sys_malloc)) { free(ptr); return; } diff --git a/storage/innobase/ut/ut0rbt.c b/storage/innobase/ut/ut0rbt.c new file mode 100644 index 00000000000..3d7cfa7636f --- /dev/null +++ b/storage/innobase/ut/ut0rbt.c @@ -0,0 +1,1254 @@ +/***************************************************************************//** + +Copyright (c) 2007, 2010, Innobase Oy. All Rights Reserved. + +Portions of this file contain modifications contributed and copyrighted by +Sun Microsystems, Inc. Those modifications are gratefully acknowledged and +are described briefly in the InnoDB documentation. The contributions by +Sun Microsystems are incorporated with their permission, and subject to the +conditions contained in the file COPYING.Sun_Microsystems. + +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; 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, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +*****************************************************************************/ +/********************************************************************//** +Red-Black tree implementation + +(c) 2007 Oracle/Innobase Oy + +Created 2007-03-20 Sunny Bains +***********************************************************************/ + +#include "ut0rbt.h" + +/**********************************************************************//** +Definition of a red-black tree +============================== + +A red-black tree is a binary search tree which has the following +red-black properties: + + 1. Every node is either red or black. + 2. Every leaf (NULL - in our case tree->nil) is black. + 3. If a node is red, then both its children are black. + 4. Every simple path from a node to a descendant leaf contains the + same number of black nodes. + + from (3) above, the implication is that on any path from the root + to a leaf, red nodes must not be adjacent. + + However, any number of black nodes may appear in a sequence. + */ + +#if defined(IB_RBT_TESTING) +#warning "Testing enabled!" +#endif + +#define ROOT(t) (t->root->left) +#define SIZEOF_NODE(t) ((sizeof(ib_rbt_node_t) + t->sizeof_value) - 1) + +/**********************************************************************//** +Print out the sub-tree recursively. */ +static +void +rbt_print_subtree( +/*==============*/ + const ib_rbt_t* tree, /*!< in: tree to traverse */ + const ib_rbt_node_t* node, /*!< in: node to print */ + ib_rbt_print_node print) /*!< in: print key function */ +{ + /* FIXME: Doesn't do anything yet */ + if (node != tree->nil) { + print(node); + rbt_print_subtree(tree, node->left, print); + rbt_print_subtree(tree, node->right, print); + } +} + +/**********************************************************************//** +Verify that the keys are in order. +@return TRUE of OK. FALSE if not ordered */ +static +ibool +rbt_check_ordering( +/*===============*/ + const ib_rbt_t* tree) /*!< in: tree to verfify */ +{ + const ib_rbt_node_t* node; + const ib_rbt_node_t* prev = NULL; + + /* Iterate over all the nodes, comparing each node with the prev */ + for (node = rbt_first(tree); node; node = rbt_next(tree, prev)) { + + if (prev && tree->compare(prev->value, node->value) >= 0) { + return(FALSE); + } + + prev = node; + } + + return(TRUE); +} + +/**********************************************************************//** +Check that every path from the root to the leaves has the same count. +Count is expressed in the number of black nodes. +@return 0 on failure else black height of the subtree */ +static +ibool +rbt_count_black_nodes( +/*==================*/ + const ib_rbt_t* tree, /*!< in: tree to verify */ + const ib_rbt_node_t* node) /*!< in: start of sub-tree */ +{ + ulint result; + + if (node != tree->nil) { + ulint left_height = rbt_count_black_nodes(tree, node->left); + + ulint right_height = rbt_count_black_nodes(tree, node->right); + + if (left_height == 0 + || right_height == 0 + || left_height != right_height) { + + result = 0; + } else if (node->color == IB_RBT_RED) { + + /* Case 3 */ + if (node->left->color != IB_RBT_BLACK + || node->right->color != IB_RBT_BLACK) { + + result = 0; + } else { + result = left_height; + } + /* Check if it's anything other than RED or BLACK. */ + } else if (node->color != IB_RBT_BLACK) { + + result = 0; + } else { + + result = right_height + 1; + } + } else { + result = 1; + } + + return(result); +} + +/**********************************************************************//** +Turn the node's right child's left sub-tree into node's right sub-tree. +This will also make node's right child it's parent. */ +static +void +rbt_rotate_left( +/*============*/ + const ib_rbt_node_t* nil, /*!< in: nil node of the tree */ + ib_rbt_node_t* node) /*!< in: node to rotate */ +{ + ib_rbt_node_t* right = node->right; + + node->right = right->left; + + if (right->left != nil) { + right->left->parent = node; + } + + /* Right's new parent was node's parent. */ + right->parent = node->parent; + + /* Since root's parent is tree->nil and root->parent->left points + back to root, we can avoid the check. */ + if (node == node->parent->left) { + /* Node was on the left of its parent. */ + node->parent->left = right; + } else { + /* Node must have been on the right. */ + node->parent->right = right; + } + + /* Finally, put node on right's left. */ + right->left = node; + node->parent = right; +} + +/**********************************************************************//** +Turn the node's left child's right sub-tree into node's left sub-tree. +This also make node's left child it's parent. */ +static +void +rbt_rotate_right( +/*=============*/ + const ib_rbt_node_t* nil, /*!< in: nil node of tree */ + ib_rbt_node_t* node) /*!< in: node to rotate */ +{ + ib_rbt_node_t* left = node->left; + + node->left = left->right; + + if (left->right != nil) { + left->right->parent = node; + } + + /* Left's new parent was node's parent. */ + left->parent = node->parent; + + /* Since root's parent is tree->nil and root->parent->left points + back to root, we can avoid the check. */ + if (node == node->parent->right) { + /* Node was on the left of its parent. */ + node->parent->right = left; + } else { + /* Node must have been on the left. */ + node->parent->left = left; + } + + /* Finally, put node on left's right. */ + left->right = node; + node->parent = left; +} + +/**********************************************************************//** +Append a node to the tree. */ +static +ib_rbt_node_t* +rbt_tree_add_child( +/*===============*/ + const ib_rbt_t* tree, + ib_rbt_bound_t* parent, + ib_rbt_node_t* node) +{ + /* Cast away the const. */ + ib_rbt_node_t* last = (ib_rbt_node_t*) parent->last; + + if (last == tree->root || parent->result < 0) { + last->left = node; + } else { + /* FIXME: We don't handle duplicates (yet)! */ + ut_a(parent->result != 0); + + last->right = node; + } + + node->parent = last; + + return(node); +} + +/**********************************************************************//** +Generic binary tree insert */ +static +ib_rbt_node_t* +rbt_tree_insert( +/*============*/ + ib_rbt_t* tree, + const void* key, + ib_rbt_node_t* node) +{ + ib_rbt_bound_t parent; + ib_rbt_node_t* current = ROOT(tree); + + parent.result = 0; + parent.last = tree->root; + + /* Regular binary search. */ + while (current != tree->nil) { + + parent.last = current; + parent.result = tree->compare(key, current->value); + + if (parent.result < 0) { + current = current->left; + } else { + current = current->right; + } + } + + ut_a(current == tree->nil); + + rbt_tree_add_child(tree, &parent, node); + + return(node); +} + +/**********************************************************************//** +Balance a tree after inserting a node. */ +static +void +rbt_balance_tree( +/*=============*/ + const ib_rbt_t* tree, /*!< in: tree to balance */ + ib_rbt_node_t* node) /*!< in: node that was inserted */ +{ + const ib_rbt_node_t* nil = tree->nil; + ib_rbt_node_t* parent = node->parent; + + /* Restore the red-black property. */ + node->color = IB_RBT_RED; + + while (node != ROOT(tree) && parent->color == IB_RBT_RED) { + ib_rbt_node_t* grand_parent = parent->parent; + + if (parent == grand_parent->left) { + ib_rbt_node_t* uncle = grand_parent->right; + + if (uncle->color == IB_RBT_RED) { + + /* Case 1 - change the colors. */ + uncle->color = IB_RBT_BLACK; + parent->color = IB_RBT_BLACK; + grand_parent->color = IB_RBT_RED; + + /* Move node up the tree. */ + node = grand_parent; + + } else { + + if (node == parent->right) { + /* Right is a black node and node is + to the right, case 2 - move node + up and rotate. */ + node = parent; + rbt_rotate_left(nil, node); + } + + grand_parent = node->parent->parent; + + /* Case 3. */ + node->parent->color = IB_RBT_BLACK; + grand_parent->color = IB_RBT_RED; + + rbt_rotate_right(nil, grand_parent); + } + + } else { + ib_rbt_node_t* uncle = grand_parent->left; + + if (uncle->color == IB_RBT_RED) { + + /* Case 1 - change the colors. */ + uncle->color = IB_RBT_BLACK; + parent->color = IB_RBT_BLACK; + grand_parent->color = IB_RBT_RED; + + /* Move node up the tree. */ + node = grand_parent; + + } else { + + if (node == parent->left) { + /* Left is a black node and node is to + the right, case 2 - move node up and + rotate. */ + node = parent; + rbt_rotate_right(nil, node); + } + + grand_parent = node->parent->parent; + + /* Case 3. */ + node->parent->color = IB_RBT_BLACK; + grand_parent->color = IB_RBT_RED; + + rbt_rotate_left(nil, grand_parent); + } + } + + parent = node->parent; + } + + /* Color the root black. */ + ROOT(tree)->color = IB_RBT_BLACK; +} + +/**********************************************************************//** +Find the given node's successor. +@return successor node or NULL if no successor */ +static +ib_rbt_node_t* +rbt_find_successor( +/*===============*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + const ib_rbt_node_t* current) /*!< in: this is declared const + because it can be called via + rbt_next() */ +{ + const ib_rbt_node_t* nil = tree->nil; + ib_rbt_node_t* next = current->right; + + /* Is there a sub-tree to the right that we can follow. */ + if (next != nil) { + + /* Follow the left most links of the current right child. */ + while (next->left != nil) { + next = next->left; + } + + } else { /* We will have to go up the tree to find the successor. */ + ib_rbt_node_t* parent = current->parent; + + /* Cast away the const. */ + next = (ib_rbt_node_t*) current; + + while (parent != tree->root && next == parent->right) { + next = parent; + parent = next->parent; + } + + next = (parent == tree->root) ? NULL : parent; + } + + return(next); +} + +/**********************************************************************//** +Find the given node's precedecessor. +@return predecessor node or NULL if no predecesor */ +static +ib_rbt_node_t* +rbt_find_predecessor( +/*=================*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + const ib_rbt_node_t* current) /*!< in: this is declared const + because it can be called via + rbt_prev() */ +{ + const ib_rbt_node_t* nil = tree->nil; + ib_rbt_node_t* prev = current->left; + + /* Is there a sub-tree to the left that we can follow. */ + if (prev != nil) { + + /* Follow the right most links of the current left child. */ + while (prev->right != nil) { + prev = prev->right; + } + + } else { /* We will have to go up the tree to find the precedecessor. */ + ib_rbt_node_t* parent = current->parent; + + /* Cast away the const. */ + prev = (ib_rbt_node_t*)current; + + while (parent != tree->root && prev == parent->left) { + prev = parent; + parent = prev->parent; + } + + prev = (parent == tree->root) ? NULL : parent; + } + + return(prev); +} + +/**********************************************************************//** +Replace node with child. After applying transformations eject becomes +an orphan. */ +static +void +rbt_eject_node( +/*===========*/ + ib_rbt_node_t* eject, /*!< in: node to eject */ + ib_rbt_node_t* node) /*!< in: node to replace with */ +{ + /* Update the to be ejected node's parent's child pointers. */ + if (eject->parent->left == eject) { + eject->parent->left = node; + } else if (eject->parent->right == eject) { + eject->parent->right = node; + } else { + ut_a(0); + } + /* eject is now an orphan but otherwise its pointers + and color are left intact. */ + + node->parent = eject->parent; +} + +/**********************************************************************//** +Replace a node with another node. */ +static +void +rbt_replace_node( +/*=============*/ + ib_rbt_node_t* replace, /*!< in: node to replace */ + ib_rbt_node_t* node) /*!< in: node to replace with */ +{ + ib_rbt_color_t color = node->color; + + /* Update the node pointers. */ + node->left = replace->left; + node->right = replace->right; + + /* Update the child node pointers. */ + node->left->parent = node; + node->right->parent = node; + + /* Make the parent of replace point to node. */ + rbt_eject_node(replace, node); + + /* Swap the colors. */ + node->color = replace->color; + replace->color = color; +} + +/**********************************************************************//** +Detach node from the tree replacing it with one of it's children. +@return the child node that now occupies the position of the detached node */ +static +ib_rbt_node_t* +rbt_detach_node( +/*============*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + ib_rbt_node_t* node) /*!< in: node to detach */ +{ + ib_rbt_node_t* child; + const ib_rbt_node_t* nil = tree->nil; + + if (node->left != nil && node->right != nil) { + /* Case where the node to be deleted has two children. */ + ib_rbt_node_t* successor = rbt_find_successor(tree, node); + + ut_a(successor != nil); + ut_a(successor->parent != nil); + ut_a(successor->left == nil); + + child = successor->right; + + /* Remove the successor node and replace with its child. */ + rbt_eject_node(successor, child); + + /* Replace the node to delete with its successor node. */ + rbt_replace_node(node, successor); + } else { + ut_a(node->left == nil || node->right == nil); + + child = (node->left != nil) ? node->left : node->right; + + /* Replace the node to delete with one of it's children. */ + rbt_eject_node(node, child); + } + + /* Reset the node links. */ + node->parent = node->right = node->left = tree->nil; + + return(child); +} + +/**********************************************************************//** +Rebalance the right sub-tree after deletion. +@return node to rebalance if more rebalancing required else NULL */ +static +ib_rbt_node_t* +rbt_balance_right( +/*==============*/ + const ib_rbt_node_t* nil, /*!< in: rb tree nil node */ + ib_rbt_node_t* parent, /*!< in: parent node */ + ib_rbt_node_t* sibling) /*!< in: sibling node */ +{ + ib_rbt_node_t* node = NULL; + + ut_a(sibling != nil); + + /* Case 3. */ + if (sibling->color == IB_RBT_RED) { + + parent->color = IB_RBT_RED; + sibling->color = IB_RBT_BLACK; + + rbt_rotate_left(nil, parent); + + sibling = parent->right; + + ut_a(sibling != nil); + } + + /* Since this will violate case 3 because of the change above. */ + if (sibling->left->color == IB_RBT_BLACK + && sibling->right->color == IB_RBT_BLACK) { + + node = parent; /* Parent needs to be rebalanced too. */ + sibling->color = IB_RBT_RED; + + } else { + if (sibling->right->color == IB_RBT_BLACK) { + + ut_a(sibling->left->color == IB_RBT_RED); + + sibling->color = IB_RBT_RED; + sibling->left->color = IB_RBT_BLACK; + + rbt_rotate_right(nil, sibling); + + sibling = parent->right; + ut_a(sibling != nil); + } + + sibling->color = parent->color; + sibling->right->color = IB_RBT_BLACK; + + parent->color = IB_RBT_BLACK; + + rbt_rotate_left(nil, parent); + } + + return(node); +} + +/**********************************************************************//** +Rebalance the left sub-tree after deletion. +@return node to rebalance if more rebalancing required else NULL */ +static +ib_rbt_node_t* +rbt_balance_left( +/*=============*/ + const ib_rbt_node_t* nil, /*!< in: rb tree nil node */ + ib_rbt_node_t* parent, /*!< in: parent node */ + ib_rbt_node_t* sibling) /*!< in: sibling node */ +{ + ib_rbt_node_t* node = NULL; + + ut_a(sibling != nil); + + /* Case 3. */ + if (sibling->color == IB_RBT_RED) { + + parent->color = IB_RBT_RED; + sibling->color = IB_RBT_BLACK; + + rbt_rotate_right(nil, parent); + sibling = parent->left; + + ut_a(sibling != nil); + } + + /* Since this will violate case 3 because of the change above. */ + if (sibling->right->color == IB_RBT_BLACK + && sibling->left->color == IB_RBT_BLACK) { + + node = parent; /* Parent needs to be rebalanced too. */ + sibling->color = IB_RBT_RED; + + } else { + if (sibling->left->color == IB_RBT_BLACK) { + + ut_a(sibling->right->color == IB_RBT_RED); + + sibling->color = IB_RBT_RED; + sibling->right->color = IB_RBT_BLACK; + + rbt_rotate_left(nil, sibling); + + sibling = parent->left; + + ut_a(sibling != nil); + } + + sibling->color = parent->color; + sibling->left->color = IB_RBT_BLACK; + + parent->color = IB_RBT_BLACK; + + rbt_rotate_right(nil, parent); + } + + return(node); +} + +/**********************************************************************//** +Delete the node and rebalance the tree if necessary */ +static +void +rbt_remove_node_and_rebalance( +/*==========================*/ + ib_rbt_t* tree, /*!< in: rb tree */ + ib_rbt_node_t* node) /*!< in: node to remove */ +{ + /* Detach node and get the node that will be used + as rebalance start. */ + ib_rbt_node_t* child = rbt_detach_node(tree, node); + + if (node->color == IB_RBT_BLACK) { + ib_rbt_node_t* last = child; + + ROOT(tree)->color = IB_RBT_RED; + + while (child && child->color == IB_RBT_BLACK) { + ib_rbt_node_t* parent = child->parent; + + /* Did the deletion cause an imbalance in the + parents left sub-tree. */ + if (parent->left == child) { + + child = rbt_balance_right( + tree->nil, parent, parent->right); + + } else if (parent->right == child) { + + child = rbt_balance_left( + tree->nil, parent, parent->left); + + } else { + ut_error; + } + + if (child) { + last = child; + } + } + + ut_a(last); + + last->color = IB_RBT_BLACK; + ROOT(tree)->color = IB_RBT_BLACK; + } + + /* Note that we have removed a node from the tree. */ + --tree->n_nodes; +} + +/**********************************************************************//** +Recursively free the nodes. */ +static +void +rbt_free_node( +/*==========*/ + ib_rbt_node_t* node, /*!< in: node to free */ + ib_rbt_node_t* nil) /*!< in: rb tree nil node */ +{ + if (node != nil) { + rbt_free_node(node->left, nil); + rbt_free_node(node->right, nil); + + ut_free(node); + } +} + +/**********************************************************************//** +Free all the nodes and free the tree. */ +UNIV_INTERN +void +rbt_free( +/*=====*/ + ib_rbt_t* tree) /*!< in: rb tree to free */ +{ + rbt_free_node(tree->root, tree->nil); + ut_free(tree->nil); + ut_free(tree); +} + +/**********************************************************************//** +Create an instance of a red black tree. +@return an empty rb tree */ +UNIV_INTERN +ib_rbt_t* +rbt_create( +/*=======*/ + size_t sizeof_value, /*!< in: sizeof data item */ + ib_rbt_compare compare) /*!< in: fn to compare items */ +{ + ib_rbt_t* tree; + ib_rbt_node_t* node; + + tree = (ib_rbt_t*) ut_malloc(sizeof(*tree)); + memset(tree, 0, sizeof(*tree)); + + tree->sizeof_value = sizeof_value; + + /* Create the sentinel (NIL) node. */ + node = tree->nil = (ib_rbt_node_t*) ut_malloc(sizeof(*node)); + memset(node, 0, sizeof(*node)); + + node->color = IB_RBT_BLACK; + node->parent = node->left = node->right = node; + + /* Create the "fake" root, the real root node will be the + left child of this node. */ + node = tree->root = (ib_rbt_node_t*) ut_malloc(sizeof(*node)); + memset(node, 0, sizeof(*node)); + + node->color = IB_RBT_BLACK; + node->parent = node->left = node->right = tree->nil; + + tree->compare = compare; + + return(tree); +} + +/**********************************************************************//** +Generic insert of a value in the rb tree. +@return inserted node */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_insert( +/*=======*/ + ib_rbt_t* tree, /*!< in: rb tree */ + const void* key, /*!< in: key for ordering */ + const void* value) /*!< in: value of key, this value + is copied to the node */ +{ + ib_rbt_node_t* node; + + /* Create the node that will hold the value data. */ + node = (ib_rbt_node_t*) ut_malloc(SIZEOF_NODE(tree)); + + memcpy(node->value, value, tree->sizeof_value); + node->parent = node->left = node->right = tree->nil; + + /* Insert in the tree in the usual way. */ + rbt_tree_insert(tree, key, node); + rbt_balance_tree(tree, node); + + ++tree->n_nodes; + + return(node); +} + +/**********************************************************************//** +Add a new node to the tree, useful for data that is pre-sorted. +@return appended node */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_add_node( +/*=========*/ + ib_rbt_t* tree, /*!< in: rb tree */ + ib_rbt_bound_t* parent, /*!< in: bounds */ + const void* value) /*!< in: this value is copied + to the node */ +{ + ib_rbt_node_t* node; + + /* Create the node that will hold the value data */ + node = (ib_rbt_node_t*) ut_malloc(SIZEOF_NODE(tree)); + + memcpy(node->value, value, tree->sizeof_value); + node->parent = node->left = node->right = tree->nil; + + /* If tree is empty */ + if (parent->last == NULL) { + parent->last = tree->root; + } + + /* Append the node, the hope here is that the caller knows + what s/he is doing. */ + rbt_tree_add_child(tree, parent, node); + rbt_balance_tree(tree, node); + + ++tree->n_nodes; + +#if defined(IB_RBT_TESTING) + ut_a(rbt_validate(tree)); +#endif + return(node); +} + +/**********************************************************************//** +Find a matching node in the rb tree. +@return NULL if not found else the node where key was found */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_lookup( +/*=======*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + const void* key) /*!< in: key to use for search */ +{ + const ib_rbt_node_t* current = ROOT(tree); + + /* Regular binary search. */ + while (current != tree->nil) { + int result = tree->compare(key, current->value); + + if (result < 0) { + current = current->left; + } else if (result > 0) { + current = current->right; + } else { + break; + } + } + + return(current != tree->nil ? current : NULL); +} + +/**********************************************************************//** +Delete a node indentified by key. +@return TRUE if success FALSE if not found */ +UNIV_INTERN +ibool +rbt_delete( +/*=======*/ + ib_rbt_t* tree, /*!< in: rb tree */ + const void* key) /*!< in: key to delete */ +{ + ibool deleted = FALSE; + ib_rbt_node_t* node = (ib_rbt_node_t*) rbt_lookup(tree, key); + + if (node) { + rbt_remove_node_and_rebalance(tree, node); + + ut_free(node); + deleted = TRUE; + } + + return(deleted); +} + +/**********************************************************************//** +Remove a node from the rb tree, the node is not free'd, that is the +callers responsibility. +@return deleted node but without the const */ +UNIV_INTERN +ib_rbt_node_t* +rbt_remove_node( +/*============*/ + ib_rbt_t* tree, /*!< in: rb tree */ + const ib_rbt_node_t* const_node) /*!< in: node to delete, this + is a fudge and declared const + because the caller can access + only const nodes */ +{ + /* Cast away the const. */ + rbt_remove_node_and_rebalance(tree, (ib_rbt_node_t*) const_node); + + /* This is to make it easier to do something like this: + ut_free(rbt_remove_node(node)); + */ + + return((ib_rbt_node_t*) const_node); +} + +/**********************************************************************//** +Find the node that has the lowest key that is >= key. +@return node satisfying the lower bound constraint or NULL */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_lower_bound( +/*============*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + const void* key) /*!< in: key to search */ +{ + ib_rbt_node_t* lb_node = NULL; + ib_rbt_node_t* current = ROOT(tree); + + while (current != tree->nil) { + int result = tree->compare(key, current->value); + + if (result > 0) { + + current = current->right; + + } else if (result < 0) { + + lb_node = current; + current = current->left; + + } else { + lb_node = current; + break; + } + } + + return(lb_node); +} + +/**********************************************************************//** +Find the node that has the greatest key that is <= key. +@return node satisfying the upper bound constraint or NULL */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_upper_bound( +/*============*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + const void* key) /*!< in: key to search */ +{ + ib_rbt_node_t* ub_node = NULL; + ib_rbt_node_t* current = ROOT(tree); + + while (current != tree->nil) { + int result = tree->compare(key, current->value); + + if (result > 0) { + + ub_node = current; + current = current->right; + + } else if (result < 0) { + + current = current->left; + + } else { + ub_node = current; + break; + } + } + + return(ub_node); +} + +/**********************************************************************//** +Find the node that has the greatest key that is <= key. +@return value of result */ +UNIV_INTERN +int +rbt_search( +/*=======*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + ib_rbt_bound_t* parent, /*!< in: search bounds */ + const void* key) /*!< in: key to search */ +{ + ib_rbt_node_t* current = ROOT(tree); + + /* Every thing is greater than the NULL root. */ + parent->result = 1; + parent->last = NULL; + + while (current != tree->nil) { + + parent->last = current; + parent->result = tree->compare(key, current->value); + + if (parent->result > 0) { + current = current->right; + } else if (parent->result < 0) { + current = current->left; + } else { + break; + } + } + + return(parent->result); +} + +/**********************************************************************//** +Find the node that has the greatest key that is <= key. But use the +supplied comparison function. +@return value of result */ +UNIV_INTERN +int +rbt_search_cmp( +/*===========*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + ib_rbt_bound_t* parent, /*!< in: search bounds */ + const void* key, /*!< in: key to search */ + ib_rbt_compare compare) /*!< in: fn to compare items */ +{ + ib_rbt_node_t* current = ROOT(tree); + + /* Every thing is greater than the NULL root. */ + parent->result = 1; + parent->last = NULL; + + while (current != tree->nil) { + + parent->last = current; + parent->result = compare(key, current->value); + + if (parent->result > 0) { + current = current->right; + } else if (parent->result < 0) { + current = current->left; + } else { + break; + } + } + + return(parent->result); +} + +/**********************************************************************//** +Return the left most node in the tree. */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_first( +/*======*/ + /* out leftmost node or NULL */ + const ib_rbt_t* tree) /* in: rb tree */ +{ + ib_rbt_node_t* first = NULL; + ib_rbt_node_t* current = ROOT(tree); + + while (current != tree->nil) { + first = current; + current = current->left; + } + + return(first); +} + +/**********************************************************************//** +Return the right most node in the tree. +@return the rightmost node or NULL */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_last( +/*=====*/ + const ib_rbt_t* tree) /*!< in: rb tree */ +{ + ib_rbt_node_t* last = NULL; + ib_rbt_node_t* current = ROOT(tree); + + while (current != tree->nil) { + last = current; + current = current->right; + } + + return(last); +} + +/**********************************************************************//** +Return the next node. +@return node next from current */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_next( +/*=====*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + const ib_rbt_node_t* current) /*!< in: current node */ +{ + return(current ? rbt_find_successor(tree, current) : NULL); +} + +/**********************************************************************//** +Return the previous node. +@return node prev from current */ +UNIV_INTERN +const ib_rbt_node_t* +rbt_prev( +/*=====*/ + const ib_rbt_t* tree, /*!< in: rb tree */ + const ib_rbt_node_t* current) /*!< in: current node */ +{ + return(current ? rbt_find_predecessor(tree, current) : NULL); +} + +/**********************************************************************//** +Reset the tree. Delete all the nodes. */ +UNIV_INTERN +void +rbt_clear( +/*======*/ + ib_rbt_t* tree) /*!< in: rb tree */ +{ + rbt_free_node(ROOT(tree), tree->nil); + + tree->n_nodes = 0; + tree->root->left = tree->root->right = tree->nil; +} + +/**********************************************************************//** +Merge the node from dst into src. Return the number of nodes merged. +@return no. of recs merged */ +UNIV_INTERN +ulint +rbt_merge_uniq( +/*===========*/ + ib_rbt_t* dst, /*!< in: dst rb tree */ + const ib_rbt_t* src) /*!< in: src rb tree */ +{ + ib_rbt_bound_t parent; + ulint n_merged = 0; + const ib_rbt_node_t* src_node = rbt_first(src); + + if (rbt_empty(src) || dst == src) { + return(0); + } + + for (/* No op */; src_node; src_node = rbt_next(src, src_node)) { + + if (rbt_search(dst, &parent, src_node->value) != 0) { + rbt_add_node(dst, &parent, src_node->value); + ++n_merged; + } + } + + return(n_merged); +} + +/**********************************************************************//** +Merge the node from dst into src. Return the number of nodes merged. +Delete the nodes from src after copying node to dst. As a side effect +the duplicates will be left untouched in the src. +@return no. of recs merged */ +UNIV_INTERN +ulint +rbt_merge_uniq_destructive( +/*=======================*/ + ib_rbt_t* dst, /*!< in: dst rb tree */ + ib_rbt_t* src) /*!< in: src rb tree */ +{ + ib_rbt_bound_t parent; + ib_rbt_node_t* src_node; + ulint old_size = rbt_size(dst); + + if (rbt_empty(src) || dst == src) { + return(0); + } + + for (src_node = (ib_rbt_node_t*) rbt_first(src); src_node; /* */) { + ib_rbt_node_t* prev = src_node; + + src_node = (ib_rbt_node_t*)rbt_next(src, prev); + + /* Skip duplicates. */ + if (rbt_search(dst, &parent, prev->value) != 0) { + + /* Remove and reset the node but preserve + the node (data) value. */ + rbt_remove_node_and_rebalance(src, prev); + + /* The nil should be taken from the dst tree. */ + prev->parent = prev->left = prev->right = dst->nil; + rbt_tree_add_child(dst, &parent, prev); + rbt_balance_tree(dst, prev); + + ++dst->n_nodes; + } + } + +#if defined(IB_RBT_TESTING) + ut_a(rbt_validate(dst)); + ut_a(rbt_validate(src)); +#endif + return(rbt_size(dst) - old_size); +} + +/**********************************************************************//** +Check that every path from the root to the leaves has the same count and +the tree nodes are in order. +@return TRUE if OK FALSE otherwise */ +UNIV_INTERN +ibool +rbt_validate( +/*=========*/ + const ib_rbt_t* tree) /*!< in: RB tree to validate */ +{ + if (rbt_count_black_nodes(tree, ROOT(tree)) > 0) { + return(rbt_check_ordering(tree)); + } + + return(FALSE); +} + +/**********************************************************************//** +Iterate over the tree in depth first order. */ +UNIV_INTERN +void +rbt_print( +/*======*/ + const ib_rbt_t* tree, /*!< in: tree to traverse */ + ib_rbt_print_node print) /*!< in: print function */ +{ + rbt_print_subtree(tree, ROOT(tree), print); +} diff --git a/storage/innobase/ut/ut0ut.c b/storage/innobase/ut/ut0ut.c index 498873e290a..39978304696 100644 --- a/storage/innobase/ut/ut0ut.c +++ b/storage/innobase/ut/ut0ut.c @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved. +Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved. Copyright (c) 2009, Sun Microsystems, Inc. Portions of this file contain modifications contributed and copyrighted by @@ -623,3 +623,107 @@ ut_snprintf( return(res); } #endif /* __WIN__ */ + +/*************************************************************//** +Convert an error number to a human readable text message. The +returned string is static and should not be freed or modified. +@return string, describing the error */ +UNIV_INTERN +const char* +ut_strerr( +/*======*/ + enum db_err num) /*!< in: error number */ +{ + switch (num) { + case DB_SUCCESS: + return("Success"); + case DB_SUCCESS_LOCKED_REC: + return("Success, record lock created"); + case DB_ERROR: + return("Generic error"); + case DB_INTERRUPTED: + return("Operation interrupted"); + case DB_OUT_OF_MEMORY: + return("Cannot allocate memory"); + case DB_OUT_OF_FILE_SPACE: + return("Out of disk space"); + case DB_LOCK_WAIT: + return("Lock wait"); + case DB_DEADLOCK: + return("Deadlock"); + case DB_ROLLBACK: + return("Rollback"); + case DB_DUPLICATE_KEY: + return("Duplicate key"); + case DB_QUE_THR_SUSPENDED: + return("The queue thread has been suspended"); + case DB_MISSING_HISTORY: + return("Required history data has been deleted"); + case DB_CLUSTER_NOT_FOUND: + return("Cluster not found"); + case DB_TABLE_NOT_FOUND: + return("Table not found"); + case DB_MUST_GET_MORE_FILE_SPACE: + return("More file space needed"); + case DB_TABLE_IS_BEING_USED: + return("Table is being used"); + case DB_TOO_BIG_RECORD: + return("Record too big"); + case DB_LOCK_WAIT_TIMEOUT: + return("Lock wait timeout"); + case DB_NO_REFERENCED_ROW: + return("Referenced key value not found"); + case DB_ROW_IS_REFERENCED: + return("Row is referenced"); + case DB_CANNOT_ADD_CONSTRAINT: + return("Cannot add constraint"); + case DB_CORRUPTION: + return("Data structure corruption"); + case DB_COL_APPEARS_TWICE_IN_INDEX: + return("Column appears twice in index"); + case DB_CANNOT_DROP_CONSTRAINT: + return("Cannot drop constraint"); + case DB_NO_SAVEPOINT: + return("No such savepoint"); + case DB_TABLESPACE_ALREADY_EXISTS: + return("Tablespace already exists"); + case DB_TABLESPACE_DELETED: + return("No such tablespace"); + case DB_LOCK_TABLE_FULL: + return("Lock structs have exhausted the buffer pool"); + case DB_FOREIGN_DUPLICATE_KEY: + return("Foreign key activated with duplicate keys"); + case DB_TOO_MANY_CONCURRENT_TRXS: + return("Too many concurrent transactions"); + case DB_UNSUPPORTED: + return("Unsupported"); + case DB_PRIMARY_KEY_IS_NULL: + return("Primary key is NULL"); + case DB_STATS_DO_NOT_EXIST: + return("Persistent statistics do not exist"); + case DB_FAIL: + return("Failed, retry may succeed"); + case DB_OVERFLOW: + return("Overflow"); + case DB_UNDERFLOW: + return("Underflow"); + case DB_STRONG_FAIL: + return("Failed, retry will not succeed"); + case DB_ZIP_OVERFLOW: + return("Zip overflow"); + case DB_RECORD_NOT_FOUND: + return("Record not found"); + case DB_END_OF_INDEX: + return("End of index"); + /* do not add default: in order to produce a warning if new code + is added to the enum but not added here */ + } + + /* we abort here because if unknown error code is given, this could + mean that memory corruption has happened and someone's error-code + variable has been overwritten with bogus data */ + ut_error; + + /* NOT REACHED */ + return("Unknown error"); +} diff --git a/storage/innobase/ut/ut0wqueue.c b/storage/innobase/ut/ut0wqueue.c index 5220d1e17f4..d32086bdfc4 100644 --- a/storage/innobase/ut/ut0wqueue.c +++ b/storage/innobase/ut/ut0wqueue.c @@ -35,7 +35,9 @@ ib_wqueue_create(void) { ib_wqueue_t* wq = mem_alloc(sizeof(ib_wqueue_t)); - mutex_create(&wq->mutex, SYNC_WORK_QUEUE); + /* Function ib_wqueue_create() has not been used anywhere, + not necessary to instrument this mutex */ + mutex_create(PFS_NOT_INSTRUMENTED, &wq->mutex, SYNC_WORK_QUEUE); wq->items = ib_list_create(); wq->event = os_event_create(NULL); diff --git a/storage/myisam/CMakeLists.txt b/storage/myisam/CMakeLists.txt index 4b7007055d8..b057a62a6dd 100755 --- a/storage/myisam/CMakeLists.txt +++ b/storage/myisam/CMakeLists.txt @@ -13,7 +13,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -SET(MYISAM_SOURCES ft_boolean_search.c ft_nlq_search.c ft_parser.c ft_static.c ft_stem.c +SET(MYISAM_SOURCES ft_boolean_search.c ft_nlq_search.c ft_parser.c ft_static.c ha_myisam.cc ft_stopwords.c ft_update.c mi_cache.c mi_changed.c mi_check.c mi_checksum.c mi_close.c mi_create.c mi_dbug.c mi_delete.c @@ -23,7 +23,7 @@ SET(MYISAM_SOURCES ft_boolean_search.c ft_nlq_search.c ft_parser.c ft_static.c mi_rfirst.c mi_rlast.c mi_rnext.c mi_rnext_same.c mi_rprev.c mi_rrnd.c mi_rsame.c mi_rsamepos.c mi_scan.c mi_search.c mi_static.c mi_statrec.c mi_unique.c mi_update.c mi_write.c rt_index.c rt_key.c rt_mbr.c - rt_split.c sort.c sp_key.c ft_eval.h mi_extrafunc.h myisamdef.h + rt_split.c sort.c sp_key.c mi_extrafunc.h myisamdef.h rt_index.h mi_rkey.c) MYSQL_ADD_PLUGIN(myisam ${MYISAM_SOURCES} diff --git a/storage/myisam/Makefile.am b/storage/myisam/Makefile.am index d0f7f5b86dc..5c3370ac6c5 100644 --- a/storage/myisam/Makefile.am +++ b/storage/myisam/Makefile.am @@ -27,7 +27,7 @@ LDADD = DEFS = @DEFS@ -EXTRA_DIST = mi_test_all.sh mi_test_all.res ft_stem.c CMakeLists.txt plug.in +EXTRA_DIST = mi_test_all.sh mi_test_all.res CMakeLists.txt plug.in pkgdata_DATA = mi_test_all mi_test_all.res pkglib_LIBRARIES = libmyisam.a @@ -47,10 +47,9 @@ myisampack_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmyisam.a \ $(top_builddir)/mysys/libmysys.a \ $(top_builddir)/dbug/libdbug.a \ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@ -noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 rt_test sp_test #ft_test1 ft_eval +noinst_PROGRAMS = mi_test1 mi_test2 mi_test3 rt_test sp_test noinst_HEADERS = myisamdef.h rt_index.h rt_key.h rt_mbr.h sp_defs.h \ - fulltext.h ftdefs.h ft_test1.h ft_eval.h \ - ha_myisam.h mi_extrafunc.h + fulltext.h ftdefs.h ha_myisam.h mi_extrafunc.h mi_test1_DEPENDENCIES= $(LIBRARIES) mi_test1_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmyisam.a \ $(top_builddir)/mysys/libmysys.a \ @@ -66,8 +65,6 @@ mi_test3_LDADD= @CLIENT_EXTRA_LDFLAGS@ libmyisam.a \ $(top_builddir)/mysys/libmysys.a \ $(top_builddir)/dbug/libdbug.a \ $(top_builddir)/strings/libmystrings.a @ZLIB_LIBS@ -#ft_test1_DEPENDENCIES= $(LIBRARIES) -#ft_eval_DEPENDENCIES= $(LIBRARIES) myisam_ftdump_DEPENDENCIES= $(LIBRARIES) myisam_ftdump_LDADD = @CLIENT_EXTRA_LDFLAGS@ libmyisam.a \ $(top_builddir)/mysys/libmysys.a \ diff --git a/storage/myisam/ft_eval.c b/storage/myisam/ft_eval.c deleted file mode 100644 index f4faabe7919..00000000000 --- a/storage/myisam/ft_eval.c +++ /dev/null @@ -1,252 +0,0 @@ -/* Copyright (C) 2000-2002 MySQL AB - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Written by Sergei A. Golubchik, who has a shared copyright to this code - added support for long options (my_getopt) 22.5.2002 by Jani Tolonen */ - -#include "ftdefs.h" -#include "ft_eval.h" -#include <stdarg.h> -#include <my_getopt.h> - -static void print_error(int exit_code, const char *fmt,...); -static void get_options(int argc, char *argv[]); -static int create_record(char *pos, FILE *file); -static void usage(); - -static struct my_option my_long_options[] = -{ - {"", 's', "", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"", 'q', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", 'S', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", '#', "", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"", 'V', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", '?', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", 'h', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} -}; - -int main(int argc, char *argv[]) -{ - MI_INFO *file; - int i,j; - - MY_INIT(argv[0]); - get_options(argc,argv); - bzero((char*)recinfo,sizeof(recinfo)); - - /* First define 2 columns */ - recinfo[0].type=FIELD_SKIP_ENDSPACE; - recinfo[0].length=docid_length; - recinfo[1].type=FIELD_BLOB; - recinfo[1].length= 4+portable_sizeof_char_ptr; - - /* Define a key over the first column */ - keyinfo[0].seg=keyseg; - keyinfo[0].keysegs=1; - keyinfo[0].block_length= 0; /* Default block length */ - keyinfo[0].seg[0].type= HA_KEYTYPE_TEXT; - keyinfo[0].seg[0].flag= HA_BLOB_PART; - keyinfo[0].seg[0].start=recinfo[0].length; - keyinfo[0].seg[0].length=key_length; - keyinfo[0].seg[0].null_bit=0; - keyinfo[0].seg[0].null_pos=0; - keyinfo[0].seg[0].bit_start=4; - keyinfo[0].seg[0].language=MY_CHARSET_CURRENT; - keyinfo[0].flag = HA_FULLTEXT; - - if (!silent) - printf("- Creating isam-file\n"); - if (mi_create(filename,1,keyinfo,2,recinfo,0,NULL,(MI_CREATE_INFO*) 0,0)) - goto err; - if (!(file=mi_open(filename,2,0))) - goto err; - if (!silent) - printf("Initializing stopwords\n"); - ft_init_stopwords(stopwordlist); - - if (!silent) - printf("- Writing key:s\n"); - - my_errno=0; - i=0; - while (create_record(record,df)) - { - error=mi_write(file,record); - if (error) - printf("I= %2d mi_write: %d errno: %d\n",i,error,my_errno); - i++; - } - fclose(df); - - if (mi_close(file)) goto err; - if (!silent) - printf("- Reopening file\n"); - if (!(file=mi_open(filename,2,0))) goto err; - if (!silent) - printf("- Reading rows with key\n"); - for (i=1;create_record(record,qf);i++) - { - FT_DOCLIST *result; - double w; - int t, err; - - result=ft_nlq_init_search(file,0,blob_record,(uint) strlen(blob_record),1); - if (!result) - { - printf("Query %d failed with errno %3d\n",i,my_errno); - goto err; - } - if (!silent) - printf("Query %d. Found: %d.\n",i,result->ndocs); - for (j=0;(err=ft_nlq_read_next(result, read_record))==0;j++) - { - t=uint2korr(read_record); - w=ft_nlq_get_relevance(result); - printf("%d %.*s %f\n",i,t,read_record+2,w); - } - if (err != HA_ERR_END_OF_FILE) - { - printf("ft_read_next %d failed with errno %3d\n",j,my_errno); - goto err; - } - ft_nlq_close_search(result); - } - - if (mi_close(file)) goto err; - my_end(MY_CHECK_ERROR); - - return (0); - - err: - printf("got error: %3d when using myisam-database\n",my_errno); - return 1; /* skip warning */ - -} - - -static my_bool -get_one_option(int optid, const struct my_option *opt __attribute__((unused)), - char *argument) -{ - switch (optid) { - case 's': - if (stopwordlist && stopwordlist != ft_precompiled_stopwords) - break; - { - FILE *f; char s[HA_FT_MAXLEN]; int i=0,n=SWL_INIT; - - if (!(stopwordlist=(const char**) malloc(n*sizeof(char *)))) - print_error(1,"malloc(%d)",n*sizeof(char *)); - if (!(f=fopen(argument,"r"))) - print_error(1,"fopen(%s)",argument); - while (!feof(f)) - { - if (!(fgets(s,HA_FT_MAXLEN,f))) - print_error(1,"fgets(s,%d,%s)",HA_FT_MAXLEN,argument); - if (!(stopwordlist[i++]=strdup(s))) - print_error(1,"strdup(%s)",s); - if (i >= n) - { - n+=SWL_PLUS; - if (!(stopwordlist=(const char**) realloc((char*) stopwordlist, - n*sizeof(char *)))) - print_error(1,"realloc(%d)",n*sizeof(char *)); - } - } - fclose(f); - stopwordlist[i]=NULL; - break; - } - case 'q': silent=1; break; - case 'S': if (stopwordlist==ft_precompiled_stopwords) stopwordlist=NULL; break; - case '#': - DBUG_PUSH (argument); - break; - case 'V': - case '?': - case 'h': - usage(); - exit(1); - } - return 0; -} - - -static void get_options(int argc, char *argv[]) -{ - int ho_error; - - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) - exit(ho_error); - - if (!(d_file=argv[optind])) print_error(1,"No d_file"); - if (!(df=fopen(d_file,"r"))) - print_error(1,"fopen(%s)",d_file); - if (!(q_file=argv[optind+1])) print_error(1,"No q_file"); - if (!(qf=fopen(q_file,"r"))) - print_error(1,"fopen(%s)",q_file); - return; -} /* get options */ - - -static int create_record(char *pos, FILE *file) -{ - uint tmp; char *ptr; - - bzero((char *)pos,MAX_REC_LENGTH); - - /* column 1 - VARCHAR */ - if (!(fgets(pos+2,MAX_REC_LENGTH-32,file))) - { - if (feof(file)) - return 0; - else - print_error(1,"fgets(docid) - 1"); - } - tmp=(uint) strlen(pos+2)-1; - int2store(pos,tmp); - pos+=recinfo[0].length; - - /* column 2 - BLOB */ - - if (!(fgets(blob_record,MAX_BLOB_LENGTH,file))) - print_error(1,"fgets(docid) - 2"); - tmp=(uint) strlen(blob_record); - int4store(pos,tmp); - ptr=blob_record; - memcpy_fixed(pos+4,&ptr,sizeof(char*)); - return 1; -} - -/* VARARGS */ - -static void print_error(int exit_code, const char *fmt,...) -{ - va_list args; - - va_start(args,fmt); - fprintf(stderr,"%s: error: ",my_progname); - (void) vfprintf(stderr, fmt, args); - (void) fputc('\n',stderr); - fflush(stderr); - va_end(args); - exit(exit_code); -} - - -static void usage() -{ - printf("%s [options]\n", my_progname); - my_print_help(my_long_options); - my_print_variables(my_long_options); -} diff --git a/storage/myisam/ft_eval.h b/storage/myisam/ft_eval.h deleted file mode 100644 index 9acc1a60d09..00000000000 --- a/storage/myisam/ft_eval.h +++ /dev/null @@ -1,41 +0,0 @@ -/* Copyright (C) 2000 MySQL AB & Sergei A. Golubchik - - 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; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Written by Sergei A. Golubchik, who has a shared copyright to this code */ - -const char **stopwordlist=ft_precompiled_stopwords; - -#define MAX_REC_LENGTH 128 -#define MAX_BLOB_LENGTH 60000 -char record[MAX_REC_LENGTH], read_record[MAX_REC_LENGTH+MAX_BLOB_LENGTH]; -char blob_record[MAX_BLOB_LENGTH+20*20]; - -char *filename= (char*) "EVAL"; - -int silent=0, error=0; - -uint key_length=MAX_BLOB_LENGTH,docid_length=32; -char *d_file, *q_file; -FILE *df,*qf; - -MI_COLUMNDEF recinfo[3]; -MI_KEYDEF keyinfo[2]; -HA_KEYSEG keyseg[10]; - -#define SWL_INIT 500 -#define SWL_PLUS 50 - -#define MAX_LINE_LENGTH 128 -char line[MAX_LINE_LENGTH]; diff --git a/storage/myisam/ft_stem.c b/storage/myisam/ft_stem.c deleted file mode 100644 index dfc132fcfa9..00000000000 --- a/storage/myisam/ft_stem.c +++ /dev/null @@ -1,18 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Written by Sergei A. Golubchik, who has a shared copyright to this code */ - -/* mulitingual stem */ diff --git a/storage/myisam/ft_test1.c b/storage/myisam/ft_test1.c deleted file mode 100644 index b37935a0d7a..00000000000 --- a/storage/myisam/ft_test1.c +++ /dev/null @@ -1,315 +0,0 @@ -/* Copyright (C) 2000-2002, 2004 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Written by Sergei A. Golubchik, who has a shared copyright to this code - added support for long options (my_getopt) 22.5.2002 by Jani Tolonen */ - -#include "ftdefs.h" -#include "ft_test1.h" -#include <my_getopt.h> - -static int key_field=FIELD_VARCHAR,extra_field=FIELD_SKIP_ENDSPACE; -static uint key_length=200,extra_length=50; -static int key_type=HA_KEYTYPE_TEXT; -static int verbose=0,silent=0,skip_update=0, - no_keys=0,no_stopwords=0,no_search=0,no_fulltext=0; -static int create_flag=0,error=0; - -#define MAX_REC_LENGTH 300 -static char record[MAX_REC_LENGTH],read_record[MAX_REC_LENGTH]; - -static int run_test(const char *filename); -static void get_options(int argc, char *argv[]); -static void create_record(char *, int); -static void usage(); - -static struct my_option my_long_options[] = -{ - {"", 'v', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", '?', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", 'h', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", 'V', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", 'v', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", 's', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", 'N', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", 'S', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", 'K', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", 'F', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", 'U', "", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"", '#', "", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} -}; - -int main(int argc, char *argv[]) -{ - MY_INIT(argv[0]); - - get_options(argc,argv); - - exit(run_test("FT1")); -} - -static MI_COLUMNDEF recinfo[3]; -static MI_KEYDEF keyinfo[2]; -static HA_KEYSEG keyseg[10]; - -static int run_test(const char *filename) -{ - MI_INFO *file; - int i,j; - my_off_t pos; - - bzero((char*) recinfo,sizeof(recinfo)); - - /* First define 2 columns */ - recinfo[0].type=extra_field; - recinfo[0].length= (extra_field == FIELD_BLOB ? 4 + portable_sizeof_char_ptr : - extra_length); - if (extra_field == FIELD_VARCHAR) - recinfo[0].length+= HA_VARCHAR_PACKLENGTH(extra_length); - recinfo[1].type=key_field; - recinfo[1].length= (key_field == FIELD_BLOB ? 4+portable_sizeof_char_ptr : - key_length); - if (key_field == FIELD_VARCHAR) - recinfo[1].length+= HA_VARCHAR_PACKLENGTH(key_length); - - /* Define a key over the first column */ - keyinfo[0].seg=keyseg; - keyinfo[0].keysegs=1; - keyinfo[0].block_length= 0; /* Default block length */ - keyinfo[0].seg[0].type= key_type; - keyinfo[0].seg[0].flag= (key_field == FIELD_BLOB) ? HA_BLOB_PART: - (key_field == FIELD_VARCHAR) ? HA_VAR_LENGTH_PART:0; - keyinfo[0].seg[0].start=recinfo[0].length; - keyinfo[0].seg[0].length=key_length; - keyinfo[0].seg[0].null_bit= 0; - keyinfo[0].seg[0].null_pos=0; - keyinfo[0].seg[0].language= default_charset_info->number; - keyinfo[0].flag = (no_fulltext?HA_PACK_KEY:HA_FULLTEXT); - - if (!silent) - printf("- Creating isam-file\n"); - if (mi_create(filename,(no_keys?0:1),keyinfo,2,recinfo,0,NULL, - (MI_CREATE_INFO*) 0, create_flag)) - goto err; - if (!(file=mi_open(filename,2,0))) - goto err; - - if (!silent) - printf("- %s stopwords\n",no_stopwords?"Skipping":"Initializing"); - ft_init_stopwords(no_stopwords?NULL:ft_precompiled_stopwords); - - if (!silent) - printf("- Writing key:s\n"); - - my_errno=0; - for (i=NUPD ; i<NDATAS; i++ ) - { - create_record(record,i); - error=mi_write(file,record); - if (verbose || error) - printf("I= %2d mi_write: %d errno: %d, record: %s\n", - i,error,my_errno,data[i].f0); - } - - if (!skip_update) - { - if (!silent) - printf("- Updating rows\n"); - - /* Read through all rows and update them */ - pos=(ha_rows) 0; - i=0; - while ((error=mi_rrnd(file,read_record,pos)) == 0) - { - create_record(record,NUPD-i-1); - if (mi_update(file,read_record,record)) - { - printf("Can't update row: %.*s, error: %d\n", - keyinfo[0].seg[0].length,record,my_errno); - } - if(++i == NUPD) break; - pos=HA_OFFSET_ERROR; - } - if (i != NUPD) - printf("Found %d of %d rows\n", i,NUPD); - } - - if (mi_close(file)) goto err; - if(no_search) return 0; - if (!silent) - printf("- Reopening file\n"); - if (!(file=mi_open(filename,2,0))) goto err; - if (!silent) - printf("- Reading rows with key\n"); - for (i=0 ; i < NQUERIES ; i++) - { - FT_DOCLIST *result; - result=ft_nlq_init_search(file,0,(char*) query[i],strlen(query[i]),1); - if(!result) - { - printf("Query %d: `%s' failed with errno %3d\n",i,query[i],my_errno); - continue; - } - printf("Query %d: `%s'. Found: %d. Top five documents:\n", - i,query[i],result->ndocs); - for (j=0;j<5;j++) - { - double w; int err; - err= ft_nlq_read_next(result, read_record); - if (err==HA_ERR_END_OF_FILE) - { - printf("No more matches!\n"); - break; - } - else if (err) - { - printf("ft_read_next %d failed with errno %3d\n",j,my_errno); - break; - } - w=ft_nlq_get_relevance(result); - if (key_field == FIELD_VARCHAR) - { - uint l; - char *p; - p=recinfo[0].length+read_record; - l=uint2korr(p); - printf("%10.7f: %.*s\n",w,(int) l,p+2); - } - else - printf("%10.7f: %.*s\n",w,recinfo[1].length, - recinfo[0].length+read_record); - } - ft_nlq_close_search(result); - } - - if (mi_close(file)) goto err; - my_end(MY_CHECK_ERROR); - - return (0); -err: - printf("got error: %3d when using myisam-database\n",my_errno); - return 1; /* skip warning */ -} - -static char blob_key[MAX_REC_LENGTH]; -/* static char blob_record[MAX_REC_LENGTH+20*20]; */ - -void create_record(char *pos, int n) -{ - bzero((char*) pos,MAX_REC_LENGTH); - if (recinfo[0].type == FIELD_BLOB) - { - uint tmp; - char *ptr; - strnmov(blob_key,data[n].f0,keyinfo[0].seg[0].length); - tmp=strlen(blob_key); - int4store(pos,tmp); - ptr=blob_key; - memcpy_fixed(pos+4,&ptr,sizeof(char*)); - pos+=recinfo[0].length; - } - else if (recinfo[0].type == FIELD_VARCHAR) - { - uint tmp; - /* -1 is here because pack_length is stored in seg->length */ - uint pack_length= HA_VARCHAR_PACKLENGTH(keyinfo[0].seg[0].length-1); - strnmov(pos+pack_length,data[n].f0,keyinfo[0].seg[0].length); - tmp=strlen(pos+pack_length); - if (pack_length == 1) - *pos= (char) tmp; - else - int2store(pos,tmp); - pos+=recinfo[0].length; - } - else - { - strnmov(pos,data[n].f0,keyinfo[0].seg[0].length); - pos+=recinfo[0].length; - } - if (recinfo[1].type == FIELD_BLOB) - { - uint tmp; - char *ptr; - strnmov(blob_key,data[n].f2,keyinfo[0].seg[0].length); - tmp=strlen(blob_key); - int4store(pos,tmp); - ptr=blob_key; - memcpy_fixed(pos+4,&ptr,sizeof(char*)); - pos+=recinfo[1].length; - } - else if (recinfo[1].type == FIELD_VARCHAR) - { - uint tmp; - /* -1 is here because pack_length is stored in seg->length */ - uint pack_length= HA_VARCHAR_PACKLENGTH(keyinfo[0].seg[0].length-1); - strnmov(pos+pack_length,data[n].f2,keyinfo[0].seg[0].length); - tmp=strlen(pos+1); - if (pack_length == 1) - *pos= (char) tmp; - else - int2store(pos,tmp); - pos+=recinfo[1].length; - } - else - { - strnmov(pos,data[n].f2,keyinfo[0].seg[0].length); - pos+=recinfo[1].length; - } -} - - -static my_bool -get_one_option(int optid, const struct my_option *opt __attribute__((unused)), - char *argument) -{ - switch(optid) { - case 'v': verbose=1; break; - case 's': silent=1; break; - case 'F': no_fulltext=1; no_search=1; - case 'U': skip_update=1; break; - case 'K': no_keys=no_search=1; break; - case 'N': no_search=1; break; - case 'S': no_stopwords=1; break; - case '#': - DBUG_PUSH (argument); - break; - case 'V': - case '?': - case 'h': - usage(); - exit(1); - } - return 0; -} - -/* Read options */ - -static void get_options(int argc,char *argv[]) -{ - int ho_error; - - if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) - exit(ho_error); - return; -} /* get options */ - - -static void usage() -{ - printf("%s [options]\n", my_progname); - my_print_help(my_long_options); - my_print_variables(my_long_options); -} diff --git a/storage/myisam/ft_test1.h b/storage/myisam/ft_test1.h deleted file mode 100644 index 4b466818460..00000000000 --- a/storage/myisam/ft_test1.h +++ /dev/null @@ -1,420 +0,0 @@ -/* Copyright (C) 2000-2001 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Written by Sergei A. Golubchik, who has a shared copyright to this code */ - -#define NUPD 20 -#define NDATAS 389 -struct { const char *f0, *f2; } data[NDATAS] = { - {"1", "General Information about MySQL"}, - {"1.1", "What is MySQL?"}, - {"1.2", "About this manual"}, - {"1.3", "History of MySQL"}, - {"1.4", "The main features of MySQL"}, - {"1.5", "General SQL information and tutorials"}, - {"1.6", "Useful MySQL-related links"}, - {"1.7", "What are stored procedures and triggers and so on?"}, - {"2", "MySQL mailing lists and how to ask questions/give error (bug) reports"}, - {"2.1", "Subscribing to/un-subscribing from the MySQL mailing list"}, - {"2.2", "Asking questions or reporting bugs"}, - {"2.3", "I think I have found a bug. What information do you need to help me?"}, - {"2.3.1", "MySQL keeps crashing"}, - {"2.4", "Guidelines for answering questions on the mailing list"}, - {"3", "Licensing or When do I have/want to pay for MySQL?"}, - {"3.1", "How much does MySQL cost?"}, - {"3.2", "How do I get commercial support?"}, - {"3.2.1", "Types of commercial support"}, - {"3.2.1.1", "Basic email support"}, - {"3.2.1.2", "Extended email support"}, -/*------------------------------- NUPD=20 -------------------------------*/ - {"3.2.1.3", "Asking: Login support"}, - {"3.2.1.4", "Extended login support"}, - {"3.3", "How do I pay for licenses/support?"}, - {"3.4", "Who do I contact when I want more information about licensing/support?"}, - {"3.5", "What Copyright does MySQL use?"}, - {"3.6", "When may I distribute MySQL commercially without a fee?"}, - {"3.7", "I want to sell a product that can be configured to use MySQL"}, - {"3.8", "I am running a commercial web server using MySQL"}, - {"3.9", "Do I need a license to sell commercial Perl/tcl/PHP/Web+ etc applications?"}, - {"3.10", "Possible future changes in the licensing"}, - {"4", "Compiling and installing MySQL"}, - {"4.1", "How do I get MySQL?"}, - {"4.2", "Which MySQL version should I use?"}, - {"4.3", "How/when will you release updates?"}, - {"4.4", "What operating systems does MySQL support?"}, - {"4.5", "Compiling MySQL from source code"}, - {"4.5.1", "Quick installation overview"}, - {"4.5.2", "Usual configure switches"}, - {"4.5.3", "Applying a patch"}, - {"4.6", "Problems compiling?"}, - {"4.7", "General compilation notes"}, - {"4.8", "MIT-pthreads notes (FreeBSD)"}, - {"4.9", "Perl installation comments"}, - {"4.10", "Special things to consider for some machine/OS combinations"}, - {"4.10.1", "Solaris notes"}, - {"4.10.2", "SunOS 4 notes"}, - {"4.10.3", "Linux notes for all versions"}, - {"4.10.3.1", "Linux-x86 notes"}, - {"4.10.3.2", "RedHat 5.0"}, - {"4.10.3.3", "RedHat 5.1"}, - {"4.10.3.4", "Linux-Sparc notes"}, - {"4.10.3.5", "Linux-Alpha notes"}, - {"4.10.3.6", "MkLinux notes"}, - {"4.10.4", "Alpha-DEC-Unix notes"}, - {"4.10.5", "Alpha-DEC-OSF1 notes"}, - {"4.10.6", "SGI-IRIX notes"}, - {"4.10.7", "FreeBSD notes"}, - {"4.10.7.1", "FreeBSD-3.0 notes"}, - {"4.10.8", "BSD/OS 2.# notes"}, - {"4.10.8.1", "BSD/OS 3.# notes"}, - {"4.10.9", "SCO notes"}, - {"4.10.10", "SCO Unixware 7.0 notes"}, - {"4.10.11", "IBM-AIX notes"}, - {"4.10.12", "HP-UX notes"}, - {"4.11", "TcX binaries"}, - {"4.12", "Win32 notes"}, - {"4.13", "Installation instructions for MySQL binary releases"}, - {"4.13.1", "How to get MySQL Perl support working"}, - {"4.13.2", "Linux notes"}, - {"4.13.3", "HP-UX notes"}, - {"4.13.4", "Linking client libraries"}, - {"4.14", "Problems running mysql_install_db"}, - {"4.15", "Problems starting MySQL"}, - {"4.16", "Automatic start/stop of MySQL"}, - {"4.17", "Option files"}, - {"5", "How standards-compatible is MySQL?"}, - {"5.1", "What extensions has MySQL to ANSI SQL92?"}, - {"5.2", "What functionality is missing in MySQL?"}, - {"5.2.1", "Sub-selects"}, - {"5.2.2", "SELECT INTO TABLE"}, - {"5.2.3", "Transactions"}, - {"5.2.4", "Triggers"}, - {"5.2.5", "Foreign Keys"}, - {"5.2.5.1", "Some reasons NOT to use FOREIGN KEYS"}, - {"5.2.6", "Views"}, - {"5.2.7", "-- as start of a comment"}, - {"5.3", "What standards does MySQL follow?"}, - {"5.4", "What functions exist only for compatibility?"}, - {"5.5", "Limitations of BLOB and TEXT types"}, - {"5.6", "How to cope without COMMIT-ROLLBACK"}, - {"6", "The MySQL access privilege system"}, - {"6.1", "What the privilege system does"}, - {"6.2", "Connecting to the MySQL server"}, - {"6.2.1", "Keeping your password secure"}, - {"6.3", "Privileges provided by MySQL"}, - {"6.4", "How the privilege system works"}, - {"6.5", "The privilege tables"}, - {"6.6", "Setting up the initial MySQL privileges"}, - {"6.7", "Adding new user privileges to MySQL"}, - {"6.8", "An example permission setup"}, - {"6.9", "Causes of Access denied errors"}, - {"6.10", "How to make MySQL secure against crackers"}, - {"7", "MySQL language reference"}, - {"7.1", "Literals: how to write strings and numbers"}, - {"7.1.1", "Strings"}, - {"7.1.2", "Numbers"}, - {"7.1.3", "NULL values"}, - {"7.1.4", "Database, table, index, column and alias names"}, - {"7.1.4.1", "Case sensitivity in names"}, - {"7.2", "Column types"}, - {"7.2.1", "Column type storage requirements"}, - {"7.2.5", "Numeric types"}, - {"7.2.6", "Date and time types"}, - {"7.2.6.1", "The DATE type"}, - {"7.2.6.2", "The TIME type"}, - {"7.2.6.3", "The DATETIME type"}, - {"7.2.6.4", "The TIMESTAMP type"}, - {"7.2.6.5", "The YEAR type"}, - {"7.2.6.6", "Miscellaneous date and time properties"}, - {"7.2.7", "String types"}, - {"7.2.7.1", "The CHAR and VARCHAR types"}, - {"7.2.7.2", "The BLOB and TEXT types"}, - {"7.2.7.3", "The ENUM type"}, - {"7.2.7.4", "The SET type"}, - {"7.2.8", "Choosing the right type for a column"}, - {"7.2.9", "Column indexes"}, - {"7.2.10", "Multiple-column indexes"}, - {"7.2.11", "Using column types from other database engines"}, - {"7.3", "Functions for use in SELECT and WHERE clauses"}, - {"7.3.1", "Grouping functions"}, - {"7.3.2", "Normal arithmetic operations"}, - {"7.3.3", "Bit functions"}, - {"7.3.4", "Logical operations"}, - {"7.3.5", "Comparison operators"}, - {"7.3.6", "String comparison functions"}, - {"7.3.7", "Control flow functions"}, - {"7.3.8", "Mathematical functions"}, - {"7.3.9", "String functions"}, - {"7.3.10", "Date and time functions"}, - {"7.3.11", "Miscellaneous functions"}, - {"7.3.12", "Functions for use with GROUP BY clauses"}, - {"7.4", "CREATE DATABASE syntax"}, - {"7.5", "DROP DATABASE syntax"}, - {"7.6", "CREATE TABLE syntax"}, - {"7.7", "ALTER TABLE syntax"}, - {"7.8", "OPTIMIZE TABLE syntax"}, - {"7.9", "DROP TABLE syntax"}, - {"7.10", "DELETE syntax"}, - {"7.11", "SELECT syntax"}, - {"7.12", "JOIN syntax"}, - {"7.13", "INSERT syntax"}, - {"7.14", "REPLACE syntax"}, - {"7.15", "LOAD DATA INFILE syntax"}, - {"7.16", "UPDATE syntax"}, - {"7.17", "USE syntax"}, - {"7.18", "SHOW syntax (Get information about tables, columns...)"}, - {"7.19", "EXPLAIN syntax (Get information about a SELECT)"}, - {"7.20", "DESCRIBE syntax (Get information about columns)"}, - {"7.21", "LOCK TABLES/UNLOCK TABLES syntax"}, - {"7.22", "SET OPTION syntax"}, - {"7.23", "GRANT syntax (Compatibility function)"}, - {"7.24", "CREATE INDEX syntax (Compatibility function)"}, - {"7.25", "DROP INDEX syntax (Compatibility function)"}, - {"7.26", "Comment syntax"}, - {"7.27", "CREATE FUNCTION/DROP FUNCTION syntax"}, - {"7.28", "Is MySQL picky about reserved words?"}, - {"8", "Example SQL queries"}, - {"8.1", "Queries from twin project"}, - {"8.1.1", "Find all non-distributed twins"}, - {"8.1.2", "Show a table on twin pair status"}, - {"9", "How safe/stable is MySQL?"}, - {"9.1", "How stable is MySQL?"}, - {"9.2", "Why are there is so many releases of MySQL?"}, - {"9.3", "Checking a table for errors"}, - {"9.4", "How to repair tables"}, - {"9.5", "Is there anything special to do when upgrading/downgrading MySQL?"}, - {"9.5.1", "Upgrading from a 3.21 version to 3.22"}, - {"9.5.2", "Upgrading from a 3.20 version to 3.21"}, - {"9.5.3", "Upgrading to another architecture"}, - {"9.6", "Year 2000 compliance"}, - {"10", "MySQL Server functions"}, - {"10.1", "What languages are supported by MySQL?"}, - {"10.1.1", "Character set used for data & sorting"}, - {"10.2", "The update log"}, - {"10.3", "How big can MySQL tables be?"}, - {"11", "Getting maximum performance from MySQL"}, - {"11.1", "How does one change the size of MySQL buffers?"}, - {"11.2", "How compiling and linking affects the speed of MySQL"}, - {"11.3", "How does MySQL use memory?"}, - {"11.4", "How does MySQL use indexes?"}, - {"11.5", "What optimizations are done on WHERE clauses?"}, - {"11.6", "How does MySQL open & close tables?"}, - {"11.6.0.1", "What are the drawbacks of creating possibly thousands of tables in a database?"}, - {"11.7", "How does MySQL lock tables?"}, - {"11.8", "How should I arrange my table to be as fast/small as possible?"}, - {"11.9", "What affects the speed of INSERT statements?"}, - {"11.10", "What affects the speed DELETE statements?"}, - {"11.11", "How do I get MySQL to run at full speed?"}, - {"11.12", "What are the different row formats? Or, when should VARCHAR/CHAR be used?"}, - {"11.13", "Why so many open tables?"}, - {"12", "MySQL benchmark suite"}, - {"13", "MySQL Utilites"}, - {"13.1", "Overview of the different MySQL programs"}, - {"13.2", "The MySQL table check, optimize and repair program"}, - {"13.2.1", "isamchk memory use"}, - {"13.2.2", "Getting low-level table information"}, - {"13.3", "The MySQL compressed read-only table generator"}, - {"14", "Adding new functions to MySQL"}, - {"15", "MySQL ODBC Support"}, - {"15.1", "Operating systems supported by MyODBC"}, - {"15.2", "How to report problems with MyODBC"}, - {"15.3", "Programs known to work with MyODBC"}, - {"15.4", "How to fill in the various fields in the ODBC administrator program"}, - {"15.5", "How to get the value of an AUTO_INCREMENT column in ODBC"}, - {"16", "Problems and common errors"}, - {"16.1", "Some common errors when using MySQL"}, - {"16.1.1", "MySQL server has gone away error"}, - {"16.1.2", "Can't connect to local MySQL server error"}, - {"16.1.3", "Out of memory error"}, - {"16.1.4", "Packet too large error"}, - {"16.1.5", "The table is full error"}, - {"16.1.6", "Commands out of sync error in client"}, - {"16.1.7", "Removing user error"}, - {"16.2", "How MySQL handles a full disk"}, - {"16.3", "How to run SQL commands from a text file"}, - {"16.4", "Where MySQL stores temporary files"}, - {"16.5", "Access denied error"}, - {"16.6", "How to run MySQL as a normal user"}, - {"16.7", "Problems with file permissions"}, - {"16.8", "File not found"}, - {"16.9", "Problems using DATE columns"}, - {"16.10", "Case sensitivity in searches"}, - {"16.11", "Problems with NULL values"}, - {"17", "Solving some common problems with MySQL"}, - {"17.1", "Database replication"}, - {"17.2", "Database backups"}, - {"18", "MySQL client tools and API's"}, - {"18.1", "MySQL C API"}, - {"18.2", "C API datatypes"}, - {"18.3", "C API function overview"}, - {"18.4", "C API function descriptions"}, - {"18.4.1", "mysql_affected_rows()"}, - {"18.4.2", "mysql_close()"}, - {"18.4.3", "mysql_connect()"}, - {"18.4.4", "mysql_create_db()"}, - {"18.4.5", "mysql_data_seek()"}, - {"18.4.6", "mysql_debug()"}, - {"18.4.7", "mysql_drop_db()"}, - {"18.4.8", "mysql_dump_debug_info()"}, - {"18.4.9", "mysql_eof()"}, - {"18.4.10", "mysql_errno()"}, - {"18.4.11", "mysql_error()"}, - {"18.4.12", "mysql_escape_string()"}, - {"18.4.13", "mysql_fetch_field()"}, - {"18.4.14", "mysql_fetch_fields()"}, - {"18.4.15", "mysql_fetch_field_direct()"}, - {"18.4.16", "mysql_fetch_lengths()"}, - {"18.4.17", "mysql_fetch_row()"}, - {"18.4.18", "mysql_field_seek()"}, - {"18.4.19", "mysql_field_tell()"}, - {"18.4.20", "mysql_free_result()"}, - {"18.4.21", "mysql_get_client_info()"}, - {"18.4.22", "mysql_get_host_info()"}, - {"18.4.23", "mysql_get_proto_info()"}, - {"18.4.24", "mysql_get_server_info()"}, - {"18.4.25", "mysql_info()"}, - {"18.4.26", "mysql_init()"}, - {"18.4.27", "mysql_insert_id()"}, - {"18.4.28", "mysql_kill()"}, - {"18.4.29", "mysql_list_dbs()"}, - {"18.4.30", "mysql_list_fields()"}, - {"18.4.31", "mysql_list_processes()"}, - {"18.4.32", "mysql_list_tables()"}, - {"18.4.33", "mysql_num_fields()"}, - {"18.4.34", "mysql_num_rows()"}, - {"18.4.35", "mysql_query()"}, - {"18.4.36", "mysql_real_connect()"}, - {"18.4.37", "mysql_real_query()"}, - {"18.4.38", "mysql_reload()"}, - {"18.4.39", "mysql_row_tell()"}, - {"18.4.40", "mysql_select_db()"}, - {"18.4.41", "mysql_shutdown()"}, - {"18.4.42", "mysql_stat()"}, - {"18.4.43", "mysql_store_result()"}, - {"18.4.44", "mysql_thread_id()"}, - {"18.4.45", "mysql_use_result()"}, - {"18.4.46", "Why is it that after mysql_query() returns success, mysql_store_result() sometimes returns NULL?"}, - {"18.4.47", "What results can I get from a query?"}, - {"18.4.48", "How can I get the unique ID for the last inserted row?"}, - {"18.4.49", "Problems linking with the C API"}, - {"18.4.50", "How to make a thread-safe client"}, - {"18.5", "MySQL Perl API's"}, - {"18.5.1", "DBI with DBD::mysql"}, - {"18.5.1.1", "The DBI interface"}, - {"18.5.1.2", "More DBI/DBD information"}, - {"18.6", "MySQL Java connectivity (JDBC)"}, - {"18.7", "MySQL PHP API's"}, - {"18.8", "MySQL C++ API's"}, - {"18.9", "MySQL Python API's"}, - {"18.10", "MySQL TCL API's"}, - {"19", "How MySQL compares to other databases"}, - {"19.1", "How MySQL compares to mSQL"}, - {"19.1.1", "How to convert mSQL tools for MySQL"}, - {"19.1.2", "How mSQL and MySQL client/server communications protocols differ"}, - {"19.1.3", "How mSQL 2.0 SQL syntax differs from MySQL"}, - {"19.2", "How MySQL compares to PostgreSQL"}, - {"A", "Some users of MySQL"}, - {"B", "Contributed programs"}, - {"C", "Contributors to MySQL"}, - {"D", "MySQL change history"}, - {"19.3", "Changes in release 3.22.x (Alpha version)"}, - {"19.3.1", "Changes in release 3.22.7"}, - {"19.3.2", "Changes in release 3.22.6"}, - {"19.3.3", "Changes in release 3.22.5"}, - {"19.3.4", "Changes in release 3.22.4"}, - {"19.3.5", "Changes in release 3.22.3"}, - {"19.3.6", "Changes in release 3.22.2"}, - {"19.3.7", "Changes in release 3.22.1"}, - {"19.3.8", "Changes in release 3.22.0"}, - {"19.4", "Changes in release 3.21.x"}, - {"19.4.1", "Changes in release 3.21.33"}, - {"19.4.2", "Changes in release 3.21.32"}, - {"19.4.3", "Changes in release 3.21.31"}, - {"19.4.4", "Changes in release 3.21.30"}, - {"19.4.5", "Changes in release 3.21.29"}, - {"19.4.6", "Changes in release 3.21.28"}, - {"19.4.7", "Changes in release 3.21.27"}, - {"19.4.8", "Changes in release 3.21.26"}, - {"19.4.9", "Changes in release 3.21.25"}, - {"19.4.10", "Changes in release 3.21.24"}, - {"19.4.11", "Changes in release 3.21.23"}, - {"19.4.12", "Changes in release 3.21.22"}, - {"19.4.13", "Changes in release 3.21.21a"}, - {"19.4.14", "Changes in release 3.21.21"}, - {"19.4.15", "Changes in release 3.21.20"}, - {"19.4.16", "Changes in release 3.21.19"}, - {"19.4.17", "Changes in release 3.21.18"}, - {"19.4.18", "Changes in release 3.21.17"}, - {"19.4.19", "Changes in release 3.21.16"}, - {"19.4.20", "Changes in release 3.21.15"}, - {"19.4.21", "Changes in release 3.21.14b"}, - {"19.4.22", "Changes in release 3.21.14a"}, - {"19.4.23", "Changes in release 3.21.13"}, - {"19.4.24", "Changes in release 3.21.12"}, - {"19.4.25", "Changes in release 3.21.11"}, - {"19.4.26", "Changes in release 3.21.10"}, - {"19.4.27", "Changes in release 3.21.9"}, - {"19.4.28", "Changes in release 3.21.8"}, - {"19.4.29", "Changes in release 3.21.7"}, - {"19.4.30", "Changes in release 3.21.6"}, - {"19.4.31", "Changes in release 3.21.5"}, - {"19.4.32", "Changes in release 3.21.4"}, - {"19.4.33", "Changes in release 3.21.3"}, - {"19.4.34", "Changes in release 3.21.2"}, - {"19.4.35", "Changes in release 3.21.0"}, - {"19.5", "Changes in release 3.20.x"}, - {"19.5.1", "Changes in release 3.20.18"}, - {"19.5.2", "Changes in release 3.20.17"}, - {"19.5.3", "Changes in release 3.20.16"}, - {"19.5.4", "Changes in release 3.20.15"}, - {"19.5.5", "Changes in release 3.20.14"}, - {"19.5.6", "Changes in release 3.20.13"}, - {"19.5.7", "Changes in release 3.20.11"}, - {"19.5.8", "Changes in release 3.20.10"}, - {"19.5.9", "Changes in release 3.20.9"}, - {"19.5.10", "Changes in release 3.20.8"}, - {"19.5.11", "Changes in release 3.20.7"}, - {"19.5.12", "Changes in release 3.20.6"}, - {"19.5.13", "Changes in release 3.20.3"}, - {"19.5.14", "Changes in release 3.20.0"}, - {"19.6", "Changes in release 3.19.x"}, - {"19.6.1", "Changes in release 3.19.5"}, - {"19.6.2", "Changes in release 3.19.4"}, - {"19.6.3", "Changes in release 3.19.3"}, - {"E", "Known errors and design deficiencies in MySQL"}, - {"F", "List of things we want to add to MySQL in the future (The TODO)"}, - {"19.7", "Things that must done in the real near future"}, - {"19.8", "Things that have to be done sometime"}, - {"19.9", "Some things we don't have any plans to do"}, - {"G", "Comments on porting to other systems"}, - {"19.10", "Debugging MySQL"}, - {"19.11", "Comments about RTS threads"}, - {"19.12", "What is the difference between different thread packages?"}, - {"H", "Description of MySQL regular expression syntax"}, - {"I", "What is Unireg?"}, - {"J", "The MySQL server license"}, - {"K", "The MySQL license for Microsoft operating systems"}, - {"*", "SQL command, type and function index"}, - {"*", "Concept Index"} -}; - -#define NQUERIES 5 -const char *query[NQUERIES]={ - "mysql information and manual", - "upgrading from previous version", - "column indexes", - "against about after more right the with/without", /* stopwords test */ - "mysql license and copyright" -}; diff --git a/storage/myisam/make-ccc b/storage/myisam/make-ccc deleted file mode 100755 index 6d1303729db..00000000000 --- a/storage/myisam/make-ccc +++ /dev/null @@ -1,5 +0,0 @@ -rm -f .deps/*.P -ccc -DMAP_TO_USE_RAID -I./../include -I../include -DDBUG_OFF -fast -O3 -c mi_cache.c mi_changed.c mi_checksum.c mi_close.c mi_create.c mi_dbug.c mi_delete.c mi_delete_all.c mi_delete_table.c mi_dynrec.c mi_extra.c mi_info.c mi_key.c mi_locking.c mi_log.c mi_open.c mi_packrec.c mi_page.c mi_panic.c mi_range.c mi_rename.c mi_rfirst.c mi_rkey.c mi_rlast.c mi_rnext.c mi_rnext_same.c mi_rprev.c mi_rrnd.c mi_rsame.c mi_rsamepos.c mi_scan.c mi_search.c mi_static.c mi_statrec.c mi_unique.c mi_update.c mi_write.c ft_update.c ft_search.o ft_stem.o ft_stopwords.c ft_parser.c -make sort.o mi_check.o -rm libmyisam.a -ar -cr libmyisam.a mi_cache.o sort.o mi_check.o diff --git a/storage/myisam/mi_create.c b/storage/myisam/mi_create.c index 66d5d4fa3cd..3db03e23637 100644 --- a/storage/myisam/mi_create.c +++ b/storage/myisam/mi_create.c @@ -38,7 +38,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, MI_CREATE_INFO *ci,uint flags) { register uint i,j; - File UNINIT_VAR(dfile),file; + File UNINIT_VAR(dfile), UNINIT_VAR(file); int errpos,save_errno, create_mode= O_RDWR | O_TRUNC; myf create_flag; uint fields,length,max_key_length,packed,pointer,real_length_diff, @@ -73,8 +73,7 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, { DBUG_RETURN(my_errno=HA_WRONG_CREATE_OPTION); } - LINT_INIT(dfile); - LINT_INIT(file); + errpos=0; options=0; bzero((uchar*) &share,sizeof(share)); diff --git a/storage/myisam/mi_open.c b/storage/myisam/mi_open.c index 4cb8e90c21b..1d877748b31 100644 --- a/storage/myisam/mi_open.c +++ b/storage/myisam/mi_open.c @@ -143,7 +143,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags) (uchar*) myisam_file_magic, 4)) { DBUG_PRINT("error",("Wrong header in %s",name_buff)); - DBUG_DUMP("error_dump",(char*) share->state.header.file_version, + DBUG_DUMP("error_dump", share->state.header.file_version, head_length); my_errno=HA_ERR_NOT_A_TABLE; goto err; diff --git a/storage/myisam/mi_page.c b/storage/myisam/mi_page.c index 76fac8688a7..90e31e72532 100644 --- a/storage/myisam/mi_page.c +++ b/storage/myisam/mi_page.c @@ -49,7 +49,7 @@ uchar *_mi_fetch_keypage(register MI_INFO *info, MI_KEYDEF *keyinfo, { DBUG_PRINT("error",("page %lu had wrong page length: %u", (ulong) page, page_size)); - DBUG_DUMP("page", (char*) tmp, keyinfo->block_length); + DBUG_DUMP("page", tmp, keyinfo->block_length); info->last_keypage = HA_OFFSET_ERROR; mi_print_error(info->s, HA_ERR_CRASHED); my_errno = HA_ERR_CRASHED; diff --git a/storage/myisam/mi_search.c b/storage/myisam/mi_search.c index 95f817e47aa..c7ebf9ae220 100644 --- a/storage/myisam/mi_search.c +++ b/storage/myisam/mi_search.c @@ -819,7 +819,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, DBUG_PRINT("error", ("Found too long null packed key: %u of %u at 0x%lx", length, keyseg->length, (long) *page_pos)); - DBUG_DUMP("key",(char*) *page_pos,16); + DBUG_DUMP("key",(uchar*) *page_pos,16); mi_print_error(keyinfo->share, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; return 0; @@ -876,7 +876,7 @@ uint _mi_get_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, { DBUG_PRINT("error",("Found too long packed key: %u of %u at 0x%lx", length, keyseg->length, (long) *page_pos)); - DBUG_DUMP("key",(char*) *page_pos,16); + DBUG_DUMP("key",(uchar*) *page_pos,16); mi_print_error(keyinfo->share, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; return 0; /* Error */ @@ -948,7 +948,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, DBUG_PRINT("error", ("Found too long binary packed key: %u of %u at 0x%lx", length, keyinfo->maxlength, (long) *page_pos)); - DBUG_DUMP("key",(char*) *page_pos,16); + DBUG_DUMP("key",(uchar*) *page_pos,16); mi_print_error(keyinfo->share, HA_ERR_CRASHED); my_errno=HA_ERR_CRASHED; DBUG_RETURN(0); /* Wrong key */ diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index 6b7e60b126c..9fc868a2ebe 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -221,8 +221,10 @@ const char *ha_myisammrg::index_type(uint key_number) children_last_l -----------------------------------------+ */ -static int myisammrg_parent_open_callback(void *callback_param, - const char *filename) +CPP_UNNAMED_NS_START + +extern "C" int myisammrg_parent_open_callback(void *callback_param, + const char *filename) { ha_myisammrg *ha_myrg= (ha_myisammrg*) callback_param; TABLE *parent= ha_myrg->table_ptr(); @@ -320,6 +322,8 @@ static int myisammrg_parent_open_callback(void *callback_param, DBUG_RETURN(0); } +CPP_UNNAMED_NS_END + /** Open a MERGE parent table, but not its children. @@ -575,7 +579,9 @@ public: next child table. It is called for each child table. */ -static MI_INFO *myisammrg_attach_children_callback(void *callback_param) +CPP_UNNAMED_NS_START + +extern "C" MI_INFO *myisammrg_attach_children_callback(void *callback_param) { Mrg_attach_children_callback_param *param= (Mrg_attach_children_callback_param*) callback_param; @@ -643,6 +649,8 @@ static MI_INFO *myisammrg_attach_children_callback(void *callback_param) DBUG_RETURN(myisam); } +CPP_UNNAMED_NS_END + /** Returns a cloned instance of the current handler. diff --git a/storage/myisammrg/make-ccc b/storage/myisammrg/make-ccc deleted file mode 100755 index a7e3dfc3cdb..00000000000 --- a/storage/myisammrg/make-ccc +++ /dev/null @@ -1,3 +0,0 @@ -ccc -I./../include -I../include -DDBUG_OFF -fast -O3 -c myrg_close.c myrg_create.c myrg_delete.c myrg_extra.c myrg_info.c myrg_locking.c myrg_open.c myrg_panic.c myrg_rrnd.c myrg_rsame.c myrg_static.c myrg_update.c -rm libmyisammrg.a -ar -cr libmyisammrg.a myrg_close.o diff --git a/storage/myisammrg/myrg_queue.c b/storage/myisammrg/myrg_queue.c index d2579053784..2c447083558 100644 --- a/storage/myisammrg/myrg_queue.c +++ b/storage/myisammrg/myrg_queue.c @@ -65,7 +65,17 @@ int _myrg_init_queue(MYRG_INFO *info,int inx,enum ha_rkey_function search_flag) } } else - my_errno= error= HA_ERR_WRONG_INDEX; + { + /* + inx may be bigger than info->keys if there are no underlying tables + defined. In this case we should return empty result. As we check for + underlying tables conformance when we open a table, we may not enter + this branch with underlying table that has less keys than merge table + have. + */ + DBUG_ASSERT(!info->tables); + error= my_errno= HA_ERR_END_OF_FILE; + } return error; } diff --git a/storage/perfschema/pfs.cc b/storage/perfschema/pfs.cc index 380801c8677..f5901540ab0 100644 --- a/storage/perfschema/pfs.cc +++ b/storage/perfschema/pfs.cc @@ -806,6 +806,10 @@ static int build_prefix(const LEX_STRING *prefix, const char *category, } \ return; +/* Use C linkage for the interface functions. */ + +C_MODE_START + static void register_mutex_v1(const char *category, PSI_mutex_info_v1 *info, int count) @@ -2054,8 +2058,9 @@ static void* get_interface(int version) } } +C_MODE_END + struct PSI_bootstrap PFS_bootstrap= { get_interface }; - diff --git a/storage/perfschema/pfs_instr.cc b/storage/perfschema/pfs_instr.cc index fb40db02ca3..9507e2d2582 100644 --- a/storage/perfschema/pfs_instr.cc +++ b/storage/perfschema/pfs_instr.cc @@ -134,6 +134,10 @@ static PFS_events_waits *thread_history_array= NULL; static LF_HASH filename_hash; /** True if filename_hash is initialized. */ static bool filename_hash_inited= false; +C_MODE_START +/** Get hash table key for instrumented files. */ +static uchar *filename_hash_get_key(const uchar *, size_t *, my_bool); +C_MODE_END /** Initialize all the instruments instance buffers. diff --git a/storage/perfschema/pfs_instr_class.cc b/storage/perfschema/pfs_instr_class.cc index ac8aa64b0c5..d1535aa851b 100644 --- a/storage/perfschema/pfs_instr_class.cc +++ b/storage/perfschema/pfs_instr_class.cc @@ -118,6 +118,10 @@ PFS_instr_class global_table_class= static LF_HASH table_share_hash; /** True if table_share_hash is initialized. */ static bool table_share_hash_inited= false; +C_MODE_START +/** Get hash table key for instrumented tables. */ +static uchar *table_share_hash_get_key(const uchar *, size_t *, my_bool); +C_MODE_END static volatile uint32 file_class_dirty_count= 0; static volatile uint32 file_class_allocated_count= 0; diff --git a/storage/perfschema/pfs_server.cc b/storage/perfschema/pfs_server.cc index a1216c6ac30..f852a9fe732 100644 --- a/storage/perfschema/pfs_server.cc +++ b/storage/perfschema/pfs_server.cc @@ -32,8 +32,11 @@ PFS_global_param pfs_param; +C_MODE_START static void destroy_pfs_thread(void *key); -void cleanup_performance_schema(void); +C_MODE_END + +static void cleanup_performance_schema(void); struct PSI_bootstrap* initialize_performance_schema(const PFS_global_param *param) @@ -100,7 +103,7 @@ static void destroy_pfs_thread(void *key) destroy_thread(pfs); } -void cleanup_performance_schema(void) +static void cleanup_performance_schema(void) { cleanup_instruments(); cleanup_sync_class(); diff --git a/strings/ChangeLog b/strings/ChangeLog deleted file mode 100644 index 2d31f2946a1..00000000000 --- a/strings/ChangeLog +++ /dev/null @@ -1,38 +0,0 @@ -Thu May 20 13:45:15 1993 Michael Widenius (monty at bitch) - - * changed itoa() and ltoa() to use the same interface as microsoft:s - and zortech:s libraryes. - -Sun Mar 24 00:30:34 1991 Michael Widenius (monty at LYNX) - - * Changed int2str to return BIG converted chars. - -Sun Feb 24 00:22:54 1991 Michael Widenius (monty at LYNX) - - * Added new function strcend(string,char). Its eqvialent to - if (!(a=strchr(string,char))) - a=strend(string); - -Tue Oct 16 18:53:19 1990 Michael Widenius (monty at LYNX) - - * Added define BAD_STRING_COMPILER to set define strmov() - if compiler is very bad at stringoperations. - * Changed to use cc on sun-systems instead of gcc. - -Sat Sep 29 18:42:31 1990 Michael Widenius (monty at LYNX) - - * Added my_atof for sparc system to get some speed. - -Sun Mar 11 16:35:59 1990 Monty (monty at monty) - - * strnmov() was changed to not fill to-string with null. - * strmake() changed to point at closing null. - -Wed Feb 7 20:15:34 1990 David Axmark (davida at isil) - - * Made functon strinrstr that is reverse search. - -Fri Dec 2 03:37:59 1988 Monty (monty at monty) - - * Fixed bug in strcont; It didn't return first found character in - set. diff --git a/strings/bcopy-duff.c b/strings/bcopy-duff.c deleted file mode 100644 index 215857715fd..00000000000 --- a/strings/bcopy-duff.c +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -#define IFACTOR 4 - - void -dcopy(char *chardest, char *charsrc, int size) -{ - register int *src, *dest, intcount ; - int startcharcpy, intoffset, numints2cpy, i ; - - numints2cpy = size >> 2 ; - startcharcpy = numints2cpy << 2 ; - intcount = numints2cpy & ~(IFACTOR-1) ; - intoffset = numints2cpy - intcount ; - - src = (int *)(((int) charsrc) + intcount*sizeof(int*)) ; - dest = (int *)(((int) chardest) + intcount*sizeof(int*)) ; - - /* copy the ints */ - switch(intoffset) - do - { - case 0: dest[3] = src[3] ; - case 3: dest[2] = src[2] ; - case 2: dest[1] = src[1] ; - case 1: dest[0] = src[0] ; - intcount -= IFACTOR ; - dest -= IFACTOR ; - src -= IFACTOR ; - } while (intcount >= 0) ; - - /* copy the chars left over by the int copy at the end */ - for(i=startcharcpy ; i<size ; i++) - chardest[i] = charsrc[i] ; -} diff --git a/strings/bzero.c b/strings/bzero.c deleted file mode 100644 index b720de65eed..00000000000 --- a/strings/bzero.c +++ /dev/null @@ -1,82 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* File : bzero.c - Author : Richard A. O'Keefe. - Michael Widenius; ifdef MC68000 - Updated: 23 April 1984 - Defines: bzero() - - bzero(dst, len) moves "len" 0 bytes to "dst". - Thus to clear a disc buffer to 0s do bzero(buffer, BUFSIZ). - - Note: the "b" routines are there to exploit certain VAX order codes, - The asm code is presented for your interest and amusement. -*/ - -#ifndef BSD_FUNCS -#include "strings.h" - -#ifdef bzero -#undef bzero /* remove macro */ -#endif - -#if VaxAsm - -static void _bzero64 _A((char *dst,int len)); - -void bzero(dst, len) -char *dst; -uint len; -{ - while ((int) len >= 64*K) - { - _bzero64(dst, 64*K-1); - dst += 64*K-1; - len -= 64*K-1; - } - _bzero64(dst, len); -} - -_bzero64(dst, len) -char *dst; -int len; -{ - asm("movc5 $0,*4(ap),$0,8(ap),*4(ap)"); -} - -#else - -#if defined(MC68000) && defined(DS90) - -void bzero(dst, len) -char *dst; -uint len; -{ - bfill(dst,len,0); /* This is very optimized ! */ -} /* bzero */ - -#else - -void bzero(dst, len) -register char *dst; -register uint len; -{ - while (len-- != 0) *dst++ = 0; -} /* bzero */ - -#endif -#endif -#endif /* BSD_FUNCS */ diff --git a/strings/ctype-ucs2.c b/strings/ctype-ucs2.c index e3e13af85ef..3946f6a83b4 100644 --- a/strings/ctype-ucs2.c +++ b/strings/ctype-ucs2.c @@ -1961,12 +1961,10 @@ my_strnncoll_utf32(CHARSET_INFO *cs, const uchar *t, size_t tlen, my_bool t_is_prefix) { - my_wc_t s_wc,t_wc; + my_wc_t UNINIT_VAR(s_wc),UNINIT_VAR(t_wc); const uchar *se= s + slen; const uchar *te= t + tlen; MY_UNICASE_INFO **uni_plane= cs->caseinfo; - LINT_INIT(s_wc); - LINT_INIT(t_wc); while (s < se && t < te) { @@ -2028,11 +2026,9 @@ my_strnncollsp_utf32(CHARSET_INFO *cs, my_bool diff_if_only_endspace_difference) { int res; - my_wc_t s_wc, t_wc; + my_wc_t UNINIT_VAR(s_wc), UNINIT_VAR(t_wc); const uchar *se= s + slen, *te= t + tlen; MY_UNICASE_INFO **uni_plane= cs->caseinfo; - LINT_INIT(s_wc); - LINT_INIT(t_wc); DBUG_ASSERT((slen % 4) == 0); DBUG_ASSERT((tlen % 4) == 0); @@ -2498,11 +2494,9 @@ my_strnncoll_utf32_bin(CHARSET_INFO *cs, const uchar *t, size_t tlen, my_bool t_is_prefix) { - my_wc_t s_wc, t_wc; + my_wc_t UNINIT_VAR(s_wc), UNINIT_VAR(t_wc); const uchar *se= s + slen; const uchar *te= t + tlen; - LINT_INIT(s_wc); - LINT_INIT(t_wc); while (s < se && t < te) { @@ -2624,7 +2618,7 @@ my_like_range_utf32(CHARSET_INFO *cs, { my_wc_t wc; int res; - if ((res= my_utf32_uni(cs, &wc, ptr, end)) < 0) + if ((res= my_utf32_uni(cs, &wc, (uchar*) ptr, (uchar*) end)) < 0) { my_fill_utf32(cs, min_str, min_end - min_str, cs->min_sort_char); my_fill_utf32(cs, max_str, min_end - min_str, cs->max_sort_char); @@ -2635,15 +2629,15 @@ my_like_range_utf32(CHARSET_INFO *cs, if (wc == (my_wc_t) escape) { ptr+= 4; /* Skip escape */ - if ((res= my_utf32_uni(cs, &wc, ptr, end)) < 0) + if ((res= my_utf32_uni(cs, &wc, (uchar*) ptr, (uchar*) end)) < 0) { my_fill_utf32(cs, min_str, min_end - min_str, cs->min_sort_char); my_fill_utf32(cs, max_str, max_end - min_str, cs->max_sort_char); /* min_length and max_length are not important */ return TRUE; } - if (my_uni_utf32(cs, wc, min_str, min_end) != 4 || - my_uni_utf32(cs, wc, max_str, max_end) != 4) + if (my_uni_utf32(cs, wc, (uchar*) min_str, (uchar*) min_end) != 4 || + my_uni_utf32(cs, wc, (uchar*) max_str, (uchar*) max_end) != 4) goto pad_set_lengths; *min_str++= 4; *max_str++= 4; @@ -2652,8 +2646,8 @@ my_like_range_utf32(CHARSET_INFO *cs, if (wc == (my_wc_t) w_one) { - if (my_uni_utf32(cs, cs->min_sort_char, min_str, min_end) != 4 || - my_uni_utf32(cs, cs->max_sort_char, max_str, max_end) != 4) + if (my_uni_utf32(cs, cs->min_sort_char, (uchar*) min_str, (uchar*) min_end) != 4 || + my_uni_utf32(cs, cs->max_sort_char, (uchar*) max_str, (uchar*) max_end) != 4) goto pad_set_lengths; min_str+= 4; max_str+= 4; @@ -2675,8 +2669,8 @@ my_like_range_utf32(CHARSET_INFO *cs, } /* Normal character */ - if (my_uni_utf32(cs, wc, min_str, min_end) != 4 || - my_uni_utf32(cs, wc, max_str, max_end) != 4) + if (my_uni_utf32(cs, wc, (uchar*) min_str, (uchar*) min_end) != 4 || + my_uni_utf32(cs, wc, (uchar*) max_str, (uchar*) max_end) != 4) goto pad_set_lengths; min_str+= 4; max_str+= 4; @@ -2704,7 +2698,7 @@ my_scan_utf32(CHARSET_INFO *cs, for ( ; str < end; ) { my_wc_t wc; - int res= my_utf32_uni(cs, &wc, str, end); + int res= my_utf32_uni(cs, &wc, (uchar*) str, (uchar*) end); if (res < 0 || wc != ' ') break; str+= res; @@ -3008,7 +3002,7 @@ static int my_strnncoll_ucs2(CHARSET_INFO *cs, my_bool t_is_prefix) { int s_res,t_res; - my_wc_t UNINIT_VAR(s_wc),t_wc; + my_wc_t UNINIT_VAR(s_wc),UNINIT_VAR(t_wc); const uchar *se=s+slen; const uchar *te=t+tlen; MY_UNICASE_INFO **uni_plane= cs->caseinfo; @@ -3195,7 +3189,7 @@ int my_strnncoll_ucs2_bin(CHARSET_INFO *cs, my_bool t_is_prefix) { int s_res,t_res; - my_wc_t UNINIT_VAR(s_wc),t_wc; + my_wc_t UNINIT_VAR(s_wc),UNINIT_VAR(t_wc); const uchar *se=s+slen; const uchar *te=t+tlen; diff --git a/strings/dtoa.c b/strings/dtoa.c index 0a0e4031ea8..d64c420b499 100644 --- a/strings/dtoa.c +++ b/strings/dtoa.c @@ -551,14 +551,14 @@ typedef union { double d; ULong L[2]; } U; #if defined(WORDS_BIGENDIAN) || (defined(__FLOAT_WORD_ORDER) && \ (__FLOAT_WORD_ORDER == __BIG_ENDIAN)) -#define word0(x) ((U*)&x)->L[0] -#define word1(x) ((U*)&x)->L[1] +#define word0(x) (x)->L[0] +#define word1(x) (x)->L[1] #else -#define word0(x) ((U*)&x)->L[1] -#define word1(x) ((U*)&x)->L[0] +#define word0(x) (x)->L[1] +#define word1(x) (x)->L[0] #endif -#define dval(x) ((U*)&x)->d +#define dval(x) (x)->d /* #define P DBL_MANT_DIG */ /* Ten_pmax= floor(P*log(2)/log(5)) */ @@ -1159,15 +1159,15 @@ static Bigint *diff(Bigint *a, Bigint *b, Stack_alloc *alloc) } -static double ulp(double x) +static double ulp(U *x) { register Long L; - double a; + U u; L= (word0(x) & Exp_mask) - (P - 1)*Exp_msk1; - word0(a) = L; - word1(a) = 0; - return dval(a); + word0(&u) = L; + word1(&u) = 0; + return dval(&u); } @@ -1175,9 +1175,9 @@ static double b2d(Bigint *a, int *e) { ULong *xa, *xa0, w, y, z; int k; - double d; -#define d0 word0(d) -#define d1 word1(d) + U d; +#define d0 word0(&d) +#define d1 word1(&d) xa0= a->p.x; xa= xa0 + a->wds; @@ -1206,11 +1206,11 @@ static double b2d(Bigint *a, int *e) ret_d: #undef d0 #undef d1 - return dval(d); + return dval(&d); } -static Bigint *d2b(double d, int *e, int *bits, Stack_alloc *alloc) +static Bigint *d2b(U *d, int *e, int *bits, Stack_alloc *alloc) { Bigint *b; int de, k; @@ -1262,20 +1262,20 @@ static Bigint *d2b(double d, int *e, int *bits, Stack_alloc *alloc) static double ratio(Bigint *a, Bigint *b) { - double da, db; + U da, db; int k, ka, kb; - dval(da)= b2d(a, &ka); - dval(db)= b2d(b, &kb); + dval(&da)= b2d(a, &ka); + dval(&db)= b2d(b, &kb); k= ka - kb + 32*(a->wds - b->wds); if (k > 0) - word0(da)+= k*Exp_msk1; + word0(&da)+= k*Exp_msk1; else { k= -k; - word0(db)+= k*Exp_msk1; + word0(&db)+= k*Exp_msk1; } - return dval(da) / dval(db); + return dval(&da) / dval(&db); } static const double tens[] = @@ -1329,10 +1329,11 @@ static const double tinytens[]= static double my_strtod_int(const char *s00, char **se, int *error, char *buf, size_t buf_size) { int scale; - int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, + int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, UNINIT_VAR(c), dsign, e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; const char *s, *s0, *s1, *end = *se; - double aadj, aadj1, adj, rv, rv0; + double aadj, aadj1; + U aadj2, adj, rv, rv0; Long L; ULong y, z; Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; @@ -1343,7 +1344,6 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s int rounding; #endif Stack_alloc alloc; - LINT_INIT(c); *error= 0; @@ -1352,7 +1352,7 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s memset(alloc.freelist, 0, sizeof(alloc.freelist)); sign= nz0= nz= 0; - dval(rv)= 0.; + dval(&rv)= 0.; for (s= s00; s < end; s++) switch (*s) { case '-': @@ -1488,14 +1488,14 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s if (!nd0) nd0= nd; k= nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; - dval(rv)= y; + dval(&rv)= y; if (k > 9) { #ifdef SET_INEXACT if (k > DBL_DIG) oldinexact = get_inexact(); #endif - dval(rv)= tens[k - 9] * dval(rv) + z; + dval(&rv)= tens[k - 9] * dval(&rv) + z; } bd0= 0; if (nd <= DBL_DIG @@ -1514,11 +1514,11 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { - rv= -rv; + rv.d= -rv.d; sign= 0; } #endif - /* rv = */ rounded_product(dval(rv), tens[e]); + /* rv = */ rounded_product(dval(&rv), tens[e]); goto ret; } i= DBL_DIG - nd; @@ -1532,13 +1532,13 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { - rv= -rv; + rv.d= -rv.d; sign= 0; } #endif e-= i; - dval(rv)*= tens[i]; - /* rv = */ rounded_product(dval(rv), tens[e]); + dval(&rv)*= tens[i]; + /* rv = */ rounded_product(dval(&rv), tens[e]); goto ret; } } @@ -1549,11 +1549,11 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s /* round correctly FLT_ROUNDS = 2 or 3 */ if (sign) { - rv= -rv; + rv.d= -rv.d; sign= 0; } #endif - /* rv = */ rounded_quotient(dval(rv), tens[-e]); + /* rv = */ rounded_quotient(dval(&rv), tens[-e]); goto ret; } #endif @@ -1582,7 +1582,7 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s if (e1 > 0) { if ((i= e1 & 15)) - dval(rv)*= tens[i]; + dval(&rv)*= tens[i]; if (e1&= ~15) { if (e1 > DBL_MAX_10_EXP) @@ -1595,21 +1595,21 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s { case 0: /* toward 0 */ case 3: /* toward -infinity */ - word0(rv)= Big0; - word1(rv)= Big1; + word0(&rv)= Big0; + word1(&rv)= Big1; break; default: - word0(rv)= Exp_mask; - word1(rv)= 0; + word0(&rv)= Exp_mask; + word1(&rv)= 0; } #else /*Honor_FLT_ROUNDS*/ - word0(rv)= Exp_mask; - word1(rv)= 0; + word0(&rv)= Exp_mask; + word1(&rv)= 0; #endif /*Honor_FLT_ROUNDS*/ #ifdef SET_INEXACT /* set overflow bit */ - dval(rv0)= 1e300; - dval(rv0)*= dval(rv0); + dval(&rv0)= 1e300; + dval(&rv0)*= dval(&rv0); #endif if (bd0) goto retfree; @@ -1618,27 +1618,27 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s e1>>= 4; for(j= 0; e1 > 1; j++, e1>>= 1) if (e1 & 1) - dval(rv)*= bigtens[j]; + dval(&rv)*= bigtens[j]; /* The last multiplication could overflow. */ - word0(rv)-= P*Exp_msk1; - dval(rv)*= bigtens[j]; - if ((z= word0(rv) & Exp_mask) > Exp_msk1 * (DBL_MAX_EXP + Bias - P)) + word0(&rv)-= P*Exp_msk1; + dval(&rv)*= bigtens[j]; + if ((z= word0(&rv) & Exp_mask) > Exp_msk1 * (DBL_MAX_EXP + Bias - P)) goto ovfl; if (z > Exp_msk1 * (DBL_MAX_EXP + Bias - 1 - P)) { /* set to largest number (Can't trust DBL_MAX) */ - word0(rv)= Big0; - word1(rv)= Big1; + word0(&rv)= Big0; + word1(&rv)= Big1; } else - word0(rv)+= P*Exp_msk1; + word0(&rv)+= P*Exp_msk1; } } else if (e1 < 0) { e1= -e1; if ((i= e1 & 15)) - dval(rv)/= tens[i]; + dval(&rv)/= tens[i]; if ((e1>>= 4)) { if (e1 >= 1 << n_bigtens) @@ -1647,25 +1647,25 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s scale= 2 * P; for(j= 0; e1 > 0; j++, e1>>= 1) if (e1 & 1) - dval(rv)*= tinytens[j]; - if (scale && (j = 2 * P + 1 - ((word0(rv) & Exp_mask) >> Exp_shift)) > 0) + dval(&rv)*= tinytens[j]; + if (scale && (j = 2 * P + 1 - ((word0(&rv) & Exp_mask) >> Exp_shift)) > 0) { /* scaled rv is denormal; zap j low bits */ if (j >= 32) { - word1(rv)= 0; + word1(&rv)= 0; if (j >= 53) - word0(rv)= (P + 2) * Exp_msk1; + word0(&rv)= (P + 2) * Exp_msk1; else - word0(rv)&= 0xffffffff << (j - 32); + word0(&rv)&= 0xffffffff << (j - 32); } else - word1(rv)&= 0xffffffff << j; + word1(&rv)&= 0xffffffff << j; } - if (!dval(rv)) + if (!dval(&rv)) { undfl: - dval(rv)= 0.; + dval(&rv)= 0.; if (bd0) goto retfree; goto ret; @@ -1683,7 +1683,7 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s { bd= Balloc(bd0->k, &alloc); Bcopy(bd, bd0); - bb= d2b(dval(rv), &bbe, &bbbits, &alloc); /* rv = bb * 2^bbe */ + bb= d2b(&rv, &bbe, &bbbits, &alloc); /* rv = bb * 2^bbe */ bs= i2b(1, &alloc); if (e >= 0) @@ -1748,7 +1748,7 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s if (i < 0) { /* Error is less than an ulp */ - if (!delta->x[0] && delta->wds <= 1) + if (!delta->p.x[0] && delta->wds <= 1) { /* exact */ #ifdef SET_INEXACT @@ -1760,51 +1760,51 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s { if (dsign) { - adj= 1.; + adj.d= 1.; goto apply_adj; } } else if (!dsign) { - adj= -1.; - if (!word1(rv) && !(word0(rv) & Frac_mask)) + adj.d= -1.; + if (!word1(&rv) && !(word0(&rv) & Frac_mask)) { - y= word0(rv) & Exp_mask; + y= word0(&rv) & Exp_mask; if (!scale || y > 2*P*Exp_msk1) { - delta= lshift(delta,Log2P); + delta= lshift(delta, Log2P, &alloc); if (cmp(delta, bs) <= 0) - adj= -0.5; + adj.d= -0.5; } } apply_adj: - if (scale && (y= word0(rv) & Exp_mask) <= 2 * P * Exp_msk1) - word0(adj)+= (2 * P + 1) * Exp_msk1 - y; - dval(rv)+= adj * ulp(dval(rv)); + if (scale && (y= word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1) + word0(&adj)+= (2 * P + 1) * Exp_msk1 - y; + dval(&rv)+= adj.d * ulp(&rv); } break; } - adj= ratio(delta, bs); - if (adj < 1.) - adj= 1.; - if (adj <= 0x7ffffffe) + adj.d= ratio(delta, bs); + if (adj.d < 1.) + adj.d= 1.; + if (adj.d <= 0x7ffffffe) { /* adj = rounding ? ceil(adj) : floor(adj); */ - y= adj; - if (y != adj) + y= adj.d; + if (y != adj.d) { if (!((rounding >> 1) ^ dsign)) y++; - adj= y; + adj.d= y; } } - if (scale && (y= word0(rv) & Exp_mask) <= 2 * P * Exp_msk1) - word0(adj)+= (2 * P + 1) * Exp_msk1 - y; - adj*= ulp(dval(rv)); + if (scale && (y= word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1) + word0(&adj)+= (2 * P + 1) * Exp_msk1 - y; + adj.d*= ulp(&rv); if (dsign) - dval(rv)+= adj; + dval(&rv)+= adj.d; else - dval(rv)-= adj; + dval(&rv)-= adj.d; goto cont; } #endif /*Honor_FLT_ROUNDS*/ @@ -1815,8 +1815,8 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s Error is less than half an ulp -- check for special case of mantissa a power of two. */ - if (dsign || word1(rv) || word0(rv) & Bndry_mask || - (word0(rv) & Exp_mask) <= (2 * P + 1) * Exp_msk1) + if (dsign || word1(&rv) || word0(&rv) & Bndry_mask || + (word0(&rv) & Exp_mask) <= (2 * P + 1) * Exp_msk1) { #ifdef SET_INEXACT if (!delta->x[0] && delta->wds <= 1) @@ -1842,26 +1842,26 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s /* exactly half-way between */ if (dsign) { - if ((word0(rv) & Bndry_mask1) == Bndry_mask1 && - word1(rv) == - ((scale && (y = word0(rv) & Exp_mask) <= 2 * P * Exp_msk1) ? + if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 && + word1(&rv) == + ((scale && (y = word0(&rv) & Exp_mask) <= 2 * P * Exp_msk1) ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : 0xffffffff)) { /*boundary case -- increment exponent*/ - word0(rv)= (word0(rv) & Exp_mask) + Exp_msk1; - word1(rv) = 0; + word0(&rv)= (word0(&rv) & Exp_mask) + Exp_msk1; + word1(&rv) = 0; dsign = 0; break; } } - else if (!(word0(rv) & Bndry_mask) && !word1(rv)) + else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { drop_down: /* boundary case -- decrement exponent */ if (scale) { - L= word0(rv) & Exp_mask; + L= word0(&rv) & Exp_mask; if (L <= (2 *P + 1) * Exp_msk1) { if (L > (P + 2) * Exp_msk1) @@ -1871,19 +1871,19 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s goto undfl; } } - L= (word0(rv) & Exp_mask) - Exp_msk1; - word0(rv)= L | Bndry_mask1; - word1(rv)= 0xffffffff; + L= (word0(&rv) & Exp_mask) - Exp_msk1; + word0(&rv)= L | Bndry_mask1; + word1(&rv)= 0xffffffff; break; } - if (!(word1(rv) & LSB)) + if (!(word1(&rv) & LSB)) break; if (dsign) - dval(rv)+= ulp(dval(rv)); + dval(&rv)+= ulp(&rv); else { - dval(rv)-= ulp(dval(rv)); - if (!dval(rv)) + dval(&rv)-= ulp(&rv); + if (!dval(&rv)) goto undfl; } dsign= 1 - dsign; @@ -1893,9 +1893,9 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s { if (dsign) aadj= aadj1= 1.; - else if (word1(rv) || word0(rv) & Bndry_mask) + else if (word1(&rv) || word0(&rv) & Bndry_mask) { - if (word1(rv) == Tiny1 && !word0(rv)) + if (word1(&rv) == Tiny1 && !word0(&rv)) goto undfl; aadj= 1.; aadj1= -1.; @@ -1929,26 +1929,26 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s aadj1+= 0.5; #endif /*Check_FLT_ROUNDS*/ } - y= word0(rv) & Exp_mask; + y= word0(&rv) & Exp_mask; /* Check for overflow */ if (y == Exp_msk1 * (DBL_MAX_EXP + Bias - 1)) { - dval(rv0)= dval(rv); - word0(rv)-= P * Exp_msk1; - adj= aadj1 * ulp(dval(rv)); - dval(rv)+= adj; - if ((word0(rv) & Exp_mask) >= Exp_msk1 * (DBL_MAX_EXP + Bias - P)) + dval(&rv0)= dval(&rv); + word0(&rv)-= P * Exp_msk1; + adj.d= aadj1 * ulp(&rv); + dval(&rv)+= adj.d; + if ((word0(&rv) & Exp_mask) >= Exp_msk1 * (DBL_MAX_EXP + Bias - P)) { - if (word0(rv0) == Big0 && word1(rv0) == Big1) + if (word0(&rv0) == Big0 && word1(&rv0) == Big1) goto ovfl; - word0(rv)= Big0; - word1(rv)= Big1; + word0(&rv)= Big0; + word1(&rv)= Big1; goto cont; } else - word0(rv)+= P * Exp_msk1; + word0(&rv)+= P * Exp_msk1; } else { @@ -1961,12 +1961,21 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s aadj= z; aadj1= dsign ? aadj : -aadj; } - word0(aadj1)+= (2 * P + 1) * Exp_msk1 - y; + dval(&aadj2) = aadj1; + word0(&aadj2)+= (2 * P + 1) * Exp_msk1 - y; + aadj1= dval(&aadj2); + adj.d= aadj1 * ulp(&rv); + dval(&rv)+= adj.d; + if (rv.d == 0.) + goto undfl; + } + else + { + adj.d= aadj1 * ulp(&rv); + dval(&rv)+= adj.d; } - adj = aadj1 * ulp(dval(rv)); - dval(rv) += adj; } - z= word0(rv) & Exp_mask; + z= word0(&rv) & Exp_mask; #ifndef SET_INEXACT if (!scale) if (y == z) @@ -1975,7 +1984,7 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s L= (Long)aadj; aadj-= L; /* The tolerances below are conservative. */ - if (dsign || word1(rv) || word0(rv) & Bndry_mask) + if (dsign || word1(&rv) || word0(&rv) & Bndry_mask) { if (aadj < .4999999 || aadj > .5000001) break; @@ -1995,9 +2004,9 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s { if (!oldinexact) { - word0(rv0)= Exp_1 + (70 << Exp_shift); - word1(rv0)= 0; - dval(rv0)+= 1.; + word0(&rv0)= Exp_1 + (70 << Exp_shift); + word1(&rv0)= 0; + dval(&rv0)+= 1.; } } else if (!oldinexact) @@ -2005,16 +2014,16 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s #endif if (scale) { - word0(rv0)= Exp_1 - 2 * P * Exp_msk1; - word1(rv0)= 0; - dval(rv)*= dval(rv0); + word0(&rv0)= Exp_1 - 2 * P * Exp_msk1; + word1(&rv0)= 0; + dval(&rv)*= dval(&rv0); } #ifdef SET_INEXACT - if (inexact && !(word0(rv) & Exp_mask)) + if (inexact && !(word0(&rv) & Exp_mask)) { /* set underflow bit */ - dval(rv0)= 1e-300; - dval(rv0)*= dval(rv0); + dval(&rv0)= 1e-300; + dval(&rv0)*= dval(&rv0); } #endif retfree: @@ -2025,7 +2034,7 @@ static double my_strtod_int(const char *s00, char **se, int *error, char *buf, s Bfree(delta, &alloc); ret: *se= (char *)s; - return sign ? -dval(rv) : dval(rv); + return sign ? -dval(&rv) : dval(&rv); } @@ -2128,7 +2137,7 @@ static int quorem(Bigint *b, Bigint *S) calculation. */ -static char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, +static char *dtoa(double dd, int mode, int ndigits, int *decpt, int *sign, char **rve, char *buf, size_t buf_size) { /* @@ -2173,7 +2182,8 @@ static char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, int denorm; ULong x; Bigint *b, *b1, *delta, *mlo, *mhi, *S; - double d2, ds, eps; + U d2, eps, u; + double ds; char *s, *s0; #ifdef Honor_FLT_ROUNDS int rounding; @@ -2184,18 +2194,19 @@ static char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, alloc.end= buf + buf_size; memset(alloc.freelist, 0, sizeof(alloc.freelist)); - if (word0(d) & Sign_bit) + u.d= dd; + if (word0(&u) & Sign_bit) { /* set sign for everything, including 0's and NaNs */ *sign= 1; - word0(d) &= ~Sign_bit; /* clear sign bit */ + word0(&u) &= ~Sign_bit; /* clear sign bit */ } else *sign= 0; /* If infinity, set decpt to DTOA_OVERFLOW, if 0 set it to 1 */ - if (((word0(d) & Exp_mask) == Exp_mask && (*decpt= DTOA_OVERFLOW)) || - (!dval(d) && (*decpt= 1))) + if (((word0(&u) & Exp_mask) == Exp_mask && (*decpt= DTOA_OVERFLOW)) || + (!dval(&u) && (*decpt= 1))) { /* Infinity, NaN, 0 */ char *res= (char*) dtoa_alloc(2, &alloc); @@ -2217,12 +2228,12 @@ static char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, } #endif - b= d2b(dval(d), &be, &bbits, &alloc); - if ((i= (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) + b= d2b(&u, &be, &bbits, &alloc); + if ((i= (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) { - dval(d2)= dval(d); - word0(d2) &= Frac_mask1; - word0(d2) |= Exp_11; + dval(&d2)= dval(&u); + word0(&d2) &= Frac_mask1; + word0(&d2) |= Exp_11; /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 @@ -2255,21 +2266,21 @@ static char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, /* d is denormalized */ i= bbits + be + (Bias + (P-1) - 1); - x= i > 32 ? word0(d) << (64 - i) | word1(d) >> (i - 32) - : word1(d) << (32 - i); - dval(d2)= x; - word0(d2)-= 31*Exp_msk1; /* adjust exponent */ + x= i > 32 ? word0(&u) << (64 - i) | word1(&u) >> (i - 32) + : word1(&u) << (32 - i); + dval(&d2)= x; + word0(&d2)-= 31*Exp_msk1; /* adjust exponent */ i-= (Bias + (P-1) - 1) + 1; denorm= 1; } - ds= (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; + ds= (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; k= (int)ds; if (ds < 0. && ds != k) k--; /* want k= floor(ds) */ k_check= 1; if (k >= 0 && k <= Ten_pmax) { - if (dval(d) < tens[k]) + if (dval(&u) < tens[k]) k--; k_check= 0; } @@ -2347,7 +2358,7 @@ static char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, { /* Try to get by with floating-point arithmetic. */ i= 0; - dval(d2)= dval(d); + dval(&d2)= dval(&u); k0= k; ilim0= ilim; ieps= 2; /* conservative */ @@ -2359,7 +2370,7 @@ static char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, { /* prevent overflows */ j&= Bletch - 1; - dval(d)/= bigtens[n_bigtens-1]; + dval(&u)/= bigtens[n_bigtens-1]; ieps++; } for (; j; j>>= 1, i++) @@ -2370,75 +2381,75 @@ static char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, ds*= bigtens[i]; } } - dval(d)/= ds; + dval(&u)/= ds; } else if ((j1= -k)) { - dval(d)*= tens[j1 & 0xf]; + dval(&u)*= tens[j1 & 0xf]; for (j= j1 >> 4; j; j>>= 1, i++) { if (j & 1) { ieps++; - dval(d)*= bigtens[i]; + dval(&u)*= bigtens[i]; } } } - if (k_check && dval(d) < 1. && ilim > 0) + if (k_check && dval(&u) < 1. && ilim > 0) { if (ilim1 <= 0) goto fast_failed; ilim= ilim1; k--; - dval(d)*= 10.; + dval(&u)*= 10.; ieps++; } - dval(eps)= ieps*dval(d) + 7.; - word0(eps)-= (P-1)*Exp_msk1; + dval(&eps)= ieps*dval(&u) + 7.; + word0(&eps)-= (P-1)*Exp_msk1; if (ilim == 0) { S= mhi= 0; - dval(d)-= 5.; - if (dval(d) > dval(eps)) + dval(&u)-= 5.; + if (dval(&u) > dval(&eps)) goto one_digit; - if (dval(d) < -dval(eps)) + if (dval(&u) < -dval(&eps)) goto no_digits; goto fast_failed; } if (leftright) { /* Use Steele & White method of only generating digits needed. */ - dval(eps)= 0.5/tens[ilim-1] - dval(eps); + dval(&eps)= 0.5/tens[ilim-1] - dval(&eps); for (i= 0;;) { - L= (Long) dval(d); - dval(d)-= L; + L= (Long) dval(&u); + dval(&u)-= L; *s++= '0' + (int)L; - if (dval(d) < dval(eps)) + if (dval(&u) < dval(&eps)) goto ret1; - if (1. - dval(d) < dval(eps)) + if (1. - dval(&u) < dval(&eps)) goto bump_up; if (++i >= ilim) break; - dval(eps)*= 10.; - dval(d)*= 10.; + dval(&eps)*= 10.; + dval(&u)*= 10.; } } else { /* Generate ilim digits, then fix them up. */ - dval(eps)*= tens[ilim-1]; - for (i= 1;; i++, dval(d)*= 10.) + dval(&eps)*= tens[ilim-1]; + for (i= 1;; i++, dval(&u)*= 10.) { - L= (Long)(dval(d)); - if (!(dval(d)-= L)) + L= (Long)(dval(&u)); + if (!(dval(&u)-= L)) ilim= i; *s++= '0' + (int)L; if (i == ilim) { - if (dval(d) > 0.5 + dval(eps)) + if (dval(&u) > 0.5 + dval(&eps)) goto bump_up; - else if (dval(d) < 0.5 - dval(eps)) + else if (dval(&u) < 0.5 - dval(&eps)) { while (*--s == '0'); s++; @@ -2450,7 +2461,7 @@ static char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, } fast_failed: s= s0; - dval(d)= dval(d2); + dval(&u)= dval(&d2); k= k0; ilim= ilim0; } @@ -2464,24 +2475,24 @@ static char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, if (ndigits < 0 && ilim <= 0) { S= mhi= 0; - if (ilim < 0 || dval(d) <= 5*ds) + if (ilim < 0 || dval(&u) <= 5*ds) goto no_digits; goto one_digit; } - for (i= 1;; i++, dval(d)*= 10.) + for (i= 1;; i++, dval(&u)*= 10.) { - L= (Long)(dval(d) / ds); - dval(d)-= L*ds; + L= (Long)(dval(&u) / ds); + dval(&u)-= L*ds; #ifdef Check_FLT_ROUNDS /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (dval(d) < 0) + if (dval(&u) < 0) { L--; - dval(d)+= ds; + dval(&u)+= ds; } #endif *s++= '0' + (int)L; - if (!dval(d)) + if (!dval(&u)) { break; } @@ -2496,8 +2507,8 @@ static char *dtoa(double d, int mode, int ndigits, int *decpt, int *sign, } } #endif - dval(d)+= dval(d); - if (dval(d) > ds || (dval(d) == ds && L & 1)) + dval(&u)+= dval(&u); + if (dval(&u) > ds || (dval(&u) == ds && L & 1)) { bump_up: while (*--s == '9') @@ -2562,8 +2573,8 @@ bump_up: #endif ) { - if (!word1(d) && !(word0(d) & Bndry_mask) && - word0(d) & (Exp_mask & ~Exp_msk1) + if (!word1(&u) && !(word0(&u) & Bndry_mask) && + word0(&u) & (Exp_mask & ~Exp_msk1) ) { /* The special case */ @@ -2652,7 +2663,7 @@ one_digit: delta= diff(S, mhi, &alloc); j1= delta->sign ? 1 : cmp(b, delta); Bfree(delta, &alloc); - if (j1 == 0 && mode != 1 && !(word1(d) & 1) + if (j1 == 0 && mode != 1 && !(word1(&u) & 1) #ifdef Honor_FLT_ROUNDS && rounding >= 1 #endif @@ -2665,7 +2676,7 @@ one_digit: *s++= dig; goto ret; } - if (j < 0 || (j == 0 && mode != 1 && !(word1(d) & 1))) + if (j < 0 || (j == 0 && mode != 1 && !(word1(&u) & 1))) { if (!b->p.x[0] && b->wds <= 1) { diff --git a/strings/macros.asm b/strings/macros.asm deleted file mode 100644 index 1eedcfbb15f..00000000000 --- a/strings/macros.asm +++ /dev/null @@ -1,147 +0,0 @@ -; Copyright (C) 2000 MySQL AB -; -; This library is free software; you can redistribute it and/or -; modify it under the terms of the GNU Library General Public -; License as published by the Free Software Foundation; version 2 -; of the License. -; -; This library 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 -; Library General Public License for more details. -; -; You should have received a copy of the GNU Library General Public -; License along with this library; if not, write to the Free -; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -; MA 02111-1307, USA - -; Some useful macros
-
- .386P
- .387
-
-_FLAT equ 0 ;FLAT memory model
-_STDCALL equ 0 ;default to _stdcall
-I386 equ 1
-
-begcode macro module
- if _FLAT
-_TEXT segment dword use32 public 'CODE'
- assume CS:FLAT,DS:FLAT,SS:FLAT
- else
-_TEXT segment dword public 'CODE'
- assume CS:_TEXT
- endif
- endm
-
-endcode macro module
-_TEXT ENDS
- endm
-
-begdata macro
-
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-; Set up segments for data
-; Regular initialized data goes in _DATA
-
-_DATA segment dword public 'DATA'
-_DATA ends
-
-;Function pointers to constructors
-XIB segment dword public 'DATA'
-XIB ends
-XI segment dword public 'DATA'
-XI ends
-XIE segment dword public 'DATA'
-XIE ends
-
-;Function pointers to destructors
-XCB segment dword public 'DATA'
-XCB ends
-XC segment dword public 'DATA'
-XC ends
-XCE segment dword public 'DATA'
-XCE ends
-
-;Constant data, such as switch tables, go here.
-
-CONST segment dword public 'CONST'
-CONST ends
-
-;Segment for uninitialized data. This is set to 0 by the startup code/OS,
-;so it does not consume room in the executable file.
-
-_BSS segment dword public 'BSS'
-_BSS ends
-
-HUGE_BSS segment dword public 'HUGE_BSS'
-HUGE_BSS ends
-
-EEND segment dword public 'ENDBSS'
-EEND ends
-
-STACK segment para stack 'STACK'
-STACK ends
-DGROUP group _DATA,XIB,XI,XIE,XCB,XC,XCE,CONST,_BSS,EEND,STACK
-
-_DATA segment
- if _FLAT
- assume DS:FLAT
- else
- assume DS:DGROUP
- endif
- endm
-
-enddata macro
-_DATA ends
- endm
-
-P equ 8 ; Offset of start of parameters on the stack frame
- ; From EBP assuming EBP was pushed.
-PS equ 4 ; Offset of start of parameters on the stack frame
- ; From ESP assuming EBP was NOT pushed.
-ESeqDS equ 0
-FSeqDS equ 0
-GSeqDS equ 0
-SSeqDS equ 1
-SIZEPTR equ 4 ; Size of a pointer
-LPTR equ 0
-SPTR equ 1
-LCODE equ 0
-
-func macro name
-_&name proc near
- ifndef name
-name equ _&name
- endif
- endm
-
-callm macro name
- call _&name
- endm
-
-;Macros to replace public, extrn, and endp for C-callable assembly routines,
-; and to define labels: c_label defines labels,
-; c_public replaces public, c_extrn replaces extrn, and c_endp replaces endp
-
-c_name macro name
- name equ _&name
- endm
-
-c_label macro name
-_&name:
- endm
-
-c_endp macro name
-_&name ENDP
- endm
-
-clr macro list ;clear a register
- irp reg,<list>
- xor reg,reg
- endm
- endm
-
-jmps macro lbl
- jmp short lbl
- endm
diff --git a/strings/make-ccc b/strings/make-ccc deleted file mode 100755 index 78d5ad1ce42..00000000000 --- a/strings/make-ccc +++ /dev/null @@ -1,3 +0,0 @@ -ccc -DHAVE_CONFIG_H -I. -I. -I.. -I./../include -I../include -O -DDBUG_OFF -fast -O3 -fomit-frame-pointer -c atof.c bchange.c bcmp.c bfill.c bmove.c bmove512.c bmove_upp.c ct_init.c ctype-latin1.c int2str.c is_prefix.c llstr.c longlong2str.c r_strinstr.c str2int.c strappend.c strcend.c strcont.c strend.c strfill.c strinstr.c strmake.c strmov.c strnmov.c strstr.c strtol.c strtoll.c strtoul.c strtoull.c strxmov.c strxnmov.c -rm libmystrings.a -ar -cr libmystrings.a atof.o diff --git a/strings/memcmp.c b/strings/memcmp.c deleted file mode 100644 index 9471353f751..00000000000 --- a/strings/memcmp.c +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* memcmp(lhs, rhs, len) - compares the two memory areas lhs[0..len-1] ?? rhs[0..len-1]. It - returns an integer less than, equal to, or greater than 0 according - as lhs[-] is lexicographically less than, equal to, or greater than - rhs[-]. Note that this is not at all the same as bcmp, which tells - you *where* the difference is but not what. - - Note: suppose we have int x, y; then memcmp(&x, &y, sizeof x) need - not bear any relation to x-y. This is because byte order is machine - dependent, and also, some machines have integer representations that - are shorter than a machine word and two equal integers might have - different values in the spare bits. On a ones complement machine, - -0 == 0, but the bit patterns are different. -*/ - -#include "strings.h" - -#if !defined(HAVE_MEMCPY) - -int memcmp(lhs, rhs, len) - register char *lhs, *rhs; - register int len; -{ - while (--len >= 0) - if (*lhs++ != *rhs++) return (uchar) lhs[-1] - (uchar) rhs[-1]; - return 0; -} - -#endif diff --git a/strings/memcpy.c b/strings/memcpy.c deleted file mode 100644 index f32d346e3ec..00000000000 --- a/strings/memcpy.c +++ /dev/null @@ -1,33 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* - memcpy(dst, src, len) - moves len bytes from src to dst. The result is dst. This is not - the same as strncpy or strnmov, while move a maximum of len bytes - and stop early if they hit a NUL character. This moves len bytes - exactly, no more, no less. See also bcopy() and bmove() which do - not return a value but otherwise do the same job. -*/ - -#include "strings.h" - -char *memcpy(char *dst, register char *src, register int len) -{ - register char *d; - - for (d = dst; --len >= 0; *d++ = *src++) ; - return dst; -} diff --git a/strings/memset.c b/strings/memset.c deleted file mode 100644 index e07dc4ead85..00000000000 --- a/strings/memset.c +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* File : memset.c - Author : Richard A. O'Keefe. - Updated: 25 May 1984 - Defines: memset() - - memset(dst, chr, len) - fills the memory area dst[0..len-1] with len bytes all equal to chr. - The result is dst. See also bfill(), which has no return value and - puts the last two arguments the other way around. - - Note: the VAX assembly code version can only handle 0 <= len < 2^16. - It is presented for your interest and amusement. -*/ - -#include "strings.h" - -#if VaxAsm - -char *memset(char *dst,int chr, int len) -{ - asm("movc5 $0,*4(ap),8(ap),12(ap),*4(ap)"); - return dst; -} - -#else ~VaxAsm - -char *memset(char *dst, register pchar chr, register int len) -{ - register char *d; - - for (d = dst; --len >= 0; *d++ = chr) ; - return dst; -} - -#endif VaxAsm diff --git a/strings/ptr_cmp.asm b/strings/ptr_cmp.asm deleted file mode 100644 index b2a020d8a37..00000000000 --- a/strings/ptr_cmp.asm +++ /dev/null @@ -1,180 +0,0 @@ -; Copyright (C) 2000 MySQL AB -; -; This library is free software; you can redistribute it and/or -; modify it under the terms of the GNU Library General Public -; License as published by the Free Software Foundation; version 2 -; of the License. -; -; This library 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 -; Library General Public License for more details. -; -; You should have received a copy of the GNU Library General Public -; License along with this library; if not, write to the Free -; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -; MA 02111-1307, USA - - TITLE Optimized cmp of pointer to strings of unsigned chars - -ifndef M_I386 - .8087 - DOSSEG - .MODEL LARGE - .DATA -compare_length dw 0 - .CODE STRINGS - - PUBLIC _get_ptr_compare -_get_ptr_compare PROC - mov bx,sp - mov cx,ss:[BX+4] - mov compare_length,cx - mov dx,seg strings:_ptr_cmp - mov ax,offset _ptr_cmp_0 - jcxz @F - mov ax,offset _ptr_cmp_1 - dec cx - jz @F - mov ax,offset _ptr_cmp -@@: ret -_get_ptr_compare ENDP - -_ptr_cmp_0 PROC - mov AX,0 ; Emptyt strings are always equal - ret -_ptr_cmp_0 ENDP - - -_ptr_cmp_1 PROC - mov bx,sp - mov dx,si ; Save si and ds - mov cx,ds - lds si,DWORD PTR ss:[bx+4] ; s1 - lds si,DWORD PTR ds:[si] - mov al,ds:[si] - xor ah,ah - lds si,DWORD PTR ss:[bx+8] ; s2 - lds si,DWORD PTR ds:[si] - mov bl,ds:[si] - mov bh,ah - sub ax,bx - mov ds,cx ; restore si and ds - mov si,dx - ret -_ptr_cmp_1 ENDP - -_ptr_cmp PROC - mov bx,bp ; Save bp - mov dx,di ; Save di - mov bp,sp - push ds - push si - mov cx,compare_length ; Length of memory-area - lds si,DWORD PTR [bp+4] ; s1 - lds si,DWORD PTR ds:[si] - les di,DWORD PTR [bp+8] ; s2 - les di,DWORD PTR es:[di] -; cld ; Work uppward - xor ax,ax - repe cmpsb ; Compare strings - je @F ; Strings are equal - sbb ax,ax - cmc - adc ax,0 - -@@: pop si - pop ds - mov di,dx - mov bp,bx - ret -_ptr_cmp ENDP - -else - -include macros.asm - -fix_es MACRO fix_cld ; Load ES if neaded - ife ESeqDS - mov ax,ds - mov es,ax - endif - ifnb <fix_cld> - cld - endif - ENDM - - begdata -compare_length dd 0 ; Length of strings - enddata - - begcode get_ptr_compare - public _get_ptr_compare -_get_ptr_compare proc near - mov ecx,P-SIZEPTR[esp] - mov compare_length,ecx - mov eax,offset _TEXT:_ptr_cmp_0 - jecxz @F - mov eax,offset _TEXT:_ptr_cmp_1 - dec ecx - jz @F - mov eax,offset _TEXT:_ptr_cmp -@@: ret -_get_ptr_compare endp - endcode _get_ptr_compare - - - begcode ptr_cmp_0 -_ptr_cmp_0 PROC - mov EAX,0 ; Emptyt strings are always equal - ret -_ptr_cmp_0 ENDP - endcode ptr_cmp_0 - - - begcode ptr_cmp_1 -_ptr_cmp_1 proc near - mov edx,esi ; Save esi - mov esi,P-SIZEPTR[esp] ; *s1 - mov esi,[esi] - movzx eax,[esi] - mov esi,P[esp] ; *s2 - mov esi,[esi] - movzx ecx,[esi] - sub eax,ecx - mov esi,edx ; Restore esi - ret -_ptr_cmp_1 ENDP - endcode ptr_cmp_1 - - - begcode ptr_cmp -_ptr_cmp proc near - fix_es 1 - push ebp - mov ebp,esp - mov edx,edi ; Save esi - push esi - mov esi,P[ebp] ; *s1 - mov esi,[esi] - mov edi,P+SIZEPTR[ebp] ; *s2 - mov edi,[edi] - mov ecx,compare_length ; Length of memory-area - xor eax,eax - repe cmpsb ; Compare strings - je @F ; Strings are equal - - sbb eax,eax - cmc - adc eax,0 - -@@: pop esi - mov edi,edx - pop ebp - ret -_ptr_cmp ENDP - endcode ptr_cmp - -endif - - END diff --git a/strings/strcat.c b/strings/strcat.c deleted file mode 100644 index e69369c357f..00000000000 --- a/strings/strcat.c +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* File : strcat.c - Author : Richard A. O'Keefe. - Updated: 10 April 1984 - Defines: strcat() - - strcat(s, t) concatenates t on the end of s. There had better be - enough room in the space s points to; strcat has no way to tell. - Note that strcat has to search for the end of s, so if you are doing - a lot of concatenating it may be better to use strmov, e.g. - strmov(strmov(strmov(strmov(s,a),b),c),d) - rather than - strcat(strcat(strcat(strcpy(s,a),b),c),d). - strcat returns the old value of s. -*/ - -#include "strings.h" - -char *strcat(register char *s, register const char *t) -{ - char *save; - - for (save = s; *s++; ) ; - for (--s; *s++ = *t++; ) ; - return save; - } diff --git a/strings/strchr.c b/strings/strchr.c deleted file mode 100644 index 5ffe386c718..00000000000 --- a/strings/strchr.c +++ /dev/null @@ -1,61 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* File : strchr.c - Author : Richard A. O'Keefe. - Michael Widenius: ifdef MC68000 - Updated: 20 April 1984 - Defines: strchr(), index() - - strchr(s, c) returns a pointer to the first place in s where c - occurs, or NullS if c does not occur in s. This function is called - index in V7 and 4.?bsd systems; while not ideal the name is clearer - than strchr, so index remains in strings.h as a macro. NB: strchr - looks for single characters, not for sets or strings. To find the - NUL character which closes s, use strchr(s, '\0') or strend(s). The - parameter 'c' is declared 'int' so it will go in a register; if your - C compiler is happy with register _char_ change it to that. -*/ - -#include "strings.h" - -#if defined(MC68000) && defined(DS90) - -char* strchr(char *s, pchar c) -{ -asm(" movl 4(a7),a0 "); -asm(" movl 8(a7),d1 "); -asm(".L2: movb (a0)+,d0 "); -asm(" cmpb d0,d1 "); -asm(" beq .L1 "); -asm(" tstb d0 "); -asm(" bne .L2 "); -asm(" moveq #0,d0 "); -asm(" rts "); -asm(".L1: movl a0,d0 "); -asm(" subql #1,d0 "); -} -#else - -char *strchr(register const char *s, register pchar c) -{ - for (;;) - { - if (*s == (char) c) return (char*) s; - if (!*s++) return NullS; - } -} - -#endif diff --git a/strings/strcmp.c b/strings/strcmp.c deleted file mode 100644 index 54bbe92279b..00000000000 --- a/strings/strcmp.c +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* File : strcmp.c - Author : Richard A. O'Keefe. - Updated: 10 April 1984 - Defines: strcmp() - - strcmp(s, t) returns > 0, = 0, or < 0 when s > t, s = t, or s < t - according to the ordinary lexicographical order. To test for - equality, the macro streql(s,t) is clearer than !strcmp(s,t). Note - that if the string contains characters outside the range 0..127 the - result is machine-dependent; PDP-11s and VAXen use signed bytes, - some other machines use unsigned bytes. -*/ - -#include "strings.h" - -int strcmp(register const char *s, register const char *t) -{ - while (*s == *t++) if (!*s++) return 0; - return s[0]-t[-1]; -} diff --git a/strings/strings.asm b/strings/strings.asm deleted file mode 100644 index 2224025cc72..00000000000 --- a/strings/strings.asm +++ /dev/null @@ -1,1060 +0,0 @@ -; Copyright (C) 2000, 2003 MySQL AB -; -; This library is free software; you can redistribute it and/or -; modify it under the terms of the GNU Library General Public -; License as published by the Free Software Foundation; version 2 -; of the License. -; -; This library 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 -; Library General Public License for more details. -; -; You should have received a copy of the GNU Library General Public -; License along with this library; if not, write to the Free -; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -; MA 02111-1307, USA - -; Note that if you don't have a macro assembler (like MASM) to compile -; this file, you can instead compile all *.c files in the string -; directory. - - TITLE Stringfunctions that we use often at MSDOS / Intel 8086 - -ifndef M_I386 - .8087 - DOSSEG - .MODEL LARGE - .CODE - - ; - ; Some macros - ; - -q_movs MACRO ; as rep movsb but quicker - shr cx,1 - rep movsw ; Move 2 bytes at a time - adc cx,cx - rep movsb ; Move last byte if any - ENDM - -q_stos MACRO ; as rep stosb but quicker - mov ah,al ; For word store - shr cx,1 - rep stosw ; Move 2 bytes at a time - adc cx,cx - rep stosb ; Move last byte if any - ENDM - -ifndef ZTC ; If not using ZORTECH compiler - ; - ; Compare memory - ; Args: s1,s2,length - ; - - PUBLIC _bcmp -_bcmp PROC - mov bx,bp ; Save bp - mov dx,di ; Save di - mov bp,sp - push ds - push si - les di,DWORD PTR [bp+8] ; s2 - lds si,DWORD PTR [bp+4] ; s1 - mov cx,WORD PTR [bp+12] ; Length of memory-area - jcxz @F ; Length = 0, return same -; cld ; Work uppward - repe cmpsb ; Compare strings - jz @F ; Match found - inc cx ; return matchpoint +1 -@@: mov ax,cx ; Return 0 if match, else pos from end - pop si - pop ds - mov di,dx - mov bp,bx - ret -_bcmp ENDP - - ; - ; Find a char in a string - ; Arg: str,char - ; Ret: pointer to found char or NullS - ; - -ifdef better_stringfunctions ; Breaks window linkage (broken linking) - - PUBLIC _strchr -_strchr PROC - mov bx,bp ; Save bp and di - mov dx,di - mov bp,sp - les di,DWORD PTR [bp+4] ; str - mov ah,BYTE PTR [bp+8] ; search - xor al,al ; for scasb to find end - -@@: cmp ah,es:[di] - jz @F ; Found char - scasb - jnz @B ; Not end - xor di,di ; Not found - mov es,di -@@: mov ax,di - mov di,dx ; Restore - mov dx,es ; Seg adr - mov bp,bx ; Restore - ret -_strchr ENDP - - ; - ; Find length of string - ; arg: str - ; ret: length - ; - - PUBLIC _strlen -_strlen PROC - mov bx,sp - mov dx,di - les di,DWORD PTR ss:[bx+4] ; Str - xor al,al ; Find end of string - mov cx,-1 -; cld - repne scasb ; Find strend or length - inc cx ; Calc strlength - not cx - mov ax,cx - mov di,dx ; Restore register - ret -_strlen ENDP - -endif - - ; - ; Move a string - ; arg: dst,src - ; ret: end-null of to - ; - - PUBLIC _strmov -_strmov PROC - mov bx,bp - mov cx,si - mov bp,sp - push ds - push di - les di,DWORD PTR [bp+4] ; dst - lds si,DWORD PTR [bp+8] ; src -; cld -@@: mov al,ds:[si] - movsb ; move arg - and al,al - jnz @B ; Not last - lea ax,WORD PTR [di-1] ; Set DX:AX to point at last null - mov dx,es - pop di - pop ds - mov si,cx - mov bp,bx - ret -_strmov ENDP - - ; - ; Fill a area of memory with a walue - ; Args: to,length,fillchar - ; - - PUBLIC _bfill -_bfill PROC - mov bx,sp ; Get args through BX - mov al,BYTE PTR ss:[bx+10] ; Fill -bfill_10: - mov dx,di ; Save di - les di,DWORD PTR ss:[bx+4] ; Memory pointer - mov cx,WORD PTR ss:[bx+8] ; Length -; cld - q_stos - mov di,dx - ret -_bfill ENDP - - ; - ; Fill a area with null - ; Args: to,length - - PUBLIC _bzero -_bzero PROC - mov bx,sp ; Get args through BX - mov al,0 ; Fill with null - jmp short bfill_10 -_bzero ENDP - -endif ; ZTC - - ; - ; Move a memory area - ; Args: to,from,length - ; - - PUBLIC _bmove -_bmove PROC - mov bx,bp - mov dx,di - mov ax,si - mov bp,sp - push ds - lds si,DWORD PTR [bp+8] ; from - les di,DWORD PTR [bp+4] ; to - mov cx,WORD PTR [bp+12] ; Length of memory-area -; cld ; Work uppward - rep movsb ; Not q_movs because overlap ? - pop ds - mov si,ax - mov di,dx - mov bp,bx - ret -_bmove ENDP - - ; - ; Move a alligned, not overlapped, by (long) divided memory area - ; Args: to,from,length - ; - - PUBLIC _bmove_align -_bmove_align PROC - mov bx,bp - mov dx,di - mov ax,si - mov bp,sp - push ds - lds si,DWORD PTR [bp+8] ; from - les di,DWORD PTR [bp+4] ; to - mov cx,WORD PTR [bp+12] ; Length of memory-area -; cld ; Work uppward - inc cx ; fix if not divisible with word - shr cx,1 - rep movsw ; Move 2 bytes at a time - pop ds - mov si,ax - mov di,dx - mov bp,bx - ret -_bmove_align ENDP - - ; - ; Move a string from higher to lower - ; Arg from+1,to+1,length - ; - - PUBLIC _bmove_upp -_bmove_upp PROC - mov bx,bp - mov dx,di - mov ax,si - mov bp,sp - push ds - lds si,DWORD PTR [bp+8] ; from - les di,DWORD PTR [bp+4] ; to - mov cx,WORD PTR [bp+12] ; Length of memory-area - dec di ; Don't move last arg - dec si - std ; Work downward - rep movsb ; Not q_movs because overlap ? - cld ; C compilator want cld - pop ds - mov si,ax - mov di,dx - mov bp,bx - ret -_bmove_upp ENDP - - ; - ; Append fillchars to string - ; Args: dest,len,fill - ; - - PUBLIC _strappend -_strappend PROC - mov bx,bp - mov dx,di - mov bp,sp - les di,DWORD PTR [bp+4] ; Memory pointer - mov cx,WORD PTR [bp+8] ; Length - sub al,al ; Find end of string -; cld - repne scasb - jnz sa_99 ; String to long, shorten it - mov al,BYTE PTR [bp+10] ; Fillchar - dec di ; Point at end null - inc cx ; rep made one dec for null-char - q_stos ; Store al in string -sa_99: mov BYTE PTR es:[di],0 ; End of string - mov di,dx - mov bp,bx - ret -_strappend ENDP - - ; - ; Find if string contains any char in another string - ; Arg: str,set - ; Ret: Pointer to first found char in str - ; - - PUBLIC _strcont -_strcont PROC - mov bx,bp ; Save bp and di in regs - mov dx,di - mov bp,sp - push ds - push si - lds si,DWORD PTR [bp+4] ; str - les di,DWORD PTR [bp+8] ; Set - mov cx,di ; Save for loop - xor ah,ah ; For endtest - jmp sc_60 - -sc_10: scasb - jz sc_fo ; Found char -sc_20: cmp ah,es:[di] ; Test if null - jnz sc_10 ; Not end of set yet - inc si ; Next char in str - mov di,cx ; es:di = Set -sc_60: mov al,ds:[si] ; Test if this char exist - and al,al - jnz sc_20 ; Not end of string - sub si,si ; Return Null - mov ds,si -sc_fo: mov ax,si ; Char found here - mov di,dx ; Restore - mov dx,ds ; Seg of found char - pop si - pop ds - mov bp,bx - ret -_strcont ENDP - - ; - ; Found end of string - ; Arg: str - ; ret: Pointer to end null - ; - - PUBLIC _strend -_strend PROC - mov bx,sp - mov dx,di ; Save - les di,DWORD PTR ss:[bx+4] ; str - mov cx,-1 - sub al,al ; Find end of string -; cld - repne scasb - lea ax,WORD PTR [di-1] ; Endpos i DX:AX - mov di,dx ; Restore - mov dx,es - ret -_strend ENDP - - ; - ; Make a string with len fill-chars and endnull - ; Args: dest,len,fill - ; Ret: dest+len - ; - - PUBLIC _strfill -_strfill PROC - mov bx,bp ; Save sp - mov bp,sp - push di - les di,DWORD PTR [bp+4] ; Memory pointer - mov cx,WORD PTR [bp+8] ; Length - mov al,BYTE PTR [bp+10] ; Fill -; cld - q_stos - mov BYTE PTR es:[di],0 ; End NULL - mov ax,di ; End i DX:AX - mov dx,es - pop di - mov bp,bx - ret -_strfill ENDP - - ; - ; Find a char in or end of a string - ; Arg: str,char - ; Ret: pointer to found char or NullS - ; - - PUBLIC _strcend -_strcend PROC - mov bx,bp ; Save bp and di - mov dx,di - mov bp,sp - les di,DWORD PTR [bp+4] ; str - mov ah,BYTE PTR [bp+8] ; search - xor al,al ; for scasb to find end - -@@: cmp ah,es:[di] - jz @F ; Found char - scasb - jnz @B ; Not end - dec di ; Not found, point at end of string -@@: mov ax,di - mov di,dx ; Restore - mov dx,es ; Seg adr - mov bp,bx ; Restore - ret -_strcend ENDP - - ; - ; Test if string has a given suffix - ; - -PUBLIC _is_prefix -_is_prefix PROC - mov dx,di ; Save di - mov bx,sp ; Arguments through bx - push ds - push si - les di,DWORD PTR ss:[bx+8] ; s2 - lds si,DWORD PTR ss:[bx+4] ; s1 - mov ax,1 ; Ok and zero-test -; cld ; Work uppward -@@: cmp ah,es:[di] - jz suf_ok ; End of string; found suffix - cmpsb ; Compare strings - jz @B ; Same, possible prefix - xor ax,ax ; Not suffix -suf_ok: pop si - pop ds - mov di,dx - ret -_is_prefix ENDP - - ; - ; Find a substring in string - ; Arg: str,search - ; - - PUBLIC _strstr -_strstr PROC - mov bx,bp - mov bp,sp - push ds - push di - push si - lds si,DWORD PTR [bp+4] ; str - les di,DWORD PTR [bp+8] ; search - mov cx,di - inc cx ; CX = search+1 - mov ah,es:[di] ; AH = First char in search - jmp sf_10 - -sf_00: mov si,dx ; si = Current str-pos -sf_10: mov al,ds:[si] ; Test if this char exist - and al,al - jz sf_90 ; End of string, didn't find search - inc si - cmp al,ah - jnz sf_10 ; Didn't find first char, continue - mov dx,si ; Save str-pos in DX - mov di,cx -sf_20: cmp BYTE PTR es:[di],0 - jz sf_fo ; Found substring - cmpsb - jz sf_20 ; Char ok - jmp sf_00 ; Next str-pos - -sf_90: sub dx,dx ; Return Null - mov ds,dx - inc dx ; Because of following dec -sf_fo: mov ax,dx ; Char found here - dec ax ; Pointed one after - mov dx,ds - pop si - pop di ; End - pop ds - mov bp,bx - ret -_strstr ENDP - - ; - ; Find a substring in string, return index - ; Arg: str,search - ; - - PUBLIC _strinstr -_strinstr PROC - push bp - mov bp,sp - push di - les di,DWORD PTR [bp+10] ; search - push es - push di - les di,DWORD PTR [bp+6] ; str - push es - push di - call _strstr - mov cx,ax - or cx,dx - jz si_99 - sub ax,di ; Pos from start - inc ax ; And first pos = 1 -si_99: add sp,8 - pop di - pop bp - ret -_strinstr ENDP - - ; - ; Make a string of len length from another string - ; Arg: dst,src,length - ; ret: end of dst - ; - - PUBLIC _strmake -_strmake PROC - mov bx,bp - mov bp,sp - push ds - push di - push si - les di,DWORD PTR [bp+4] ; dst - lds si,DWORD PTR [bp+8] ; src - mov cx,WORD PTR [bp+12] ; Length of memory-area - xor al,al ; For test of end-null - jcxz sm_90 ; Nothing to move, put zero at end. -; cld ; Work uppward - -@@: cmp al,ds:[si] ; Next char to move - movsb ; move arg - jz sm_99 ; last char, we are ready - loop @B ; Continue moving -sm_90: mov BYTE PTR es:[di],al ; Set end pos - inc di ; Fix that di points at end null -sm_99: dec di ; di points now at end null - mov ax,di ; Ret value in DX:AX - mov dx,es - pop si - pop di - pop ds - mov bp,bx - ret -_strmake ENDP - - ; - ; Find length of string with maxlength - ; arg: str,maxlength - ; ret: length - ; - - PUBLIC _strnlen -_strnlen PROC - mov bx,bp - mov bp,sp - push di - les di,DWORD PTR [bp+4] ; Str - mov cx,WORD PTR [bp+8] ; length - mov dx,di ; Save str to calc length - jcxz sn_10 ; Length = 0 - xor al,al ; Find end of string -; cld - repne scasb ; Find strend or length - jnz sn_10 - dec di ; DI points at last null -sn_10: mov ax,di - sub ax,dx ; Ax = length - pop di - mov bp,bx - ret -_strnlen ENDP - - ; - ; Move a string with max len chars - ; arg: dst,src,len - ; ret: pos to first null or dst+len - - PUBLIC _strnmov -_strnmov PROC - mov bx,bp - mov bp,sp - push ds - push di - push si - les di,DWORD PTR [bp+4] ; dst - lds si,DWORD PTR [bp+8] ; src - mov cx,WORD PTR [bp+12] ; length - jcxz snm_99 ; Nothing to do - xor al,al ; For test of end-null -; cld - -@@: cmp al,ds:[si] ; Next char to move - movsb ; move arg - jz snm_20 ; last char, fill with null - loop @B ; Continue moving - inc di ; Point two after last -snm_20: dec di ; Point at first null (or last+1) -snm_99: mov ax,di ; Pointer at last char - mov dx,es ; To-segment - pop si - pop di - pop ds - mov bp,bx ; Restore - ret -_strnmov ENDP - -else ; M_I386 - -include macros.asm - -q_stos MACRO ; as rep stosb but quicker, Uses edx - mov ah,al ;(2) Set up a 32 bit pattern. - mov edx,eax ;(2) - shl edx,16 ;(3) - or eax,edx ;(2) EAX has the 32 bit pattern. - - mov edx,ecx ;(2) Save the count of bytes. - shr ecx,2 ;(2) Number of dwords. - rep stosd ;(5 + 5n) - mov cl,3 ;(2) - and ecx,edx ;(2) Fill in the remaining odd bytes. - rep stosb ; Move last bytes if any - ENDM - -fix_es MACRO fix_cld ; Load ES if neaded - ife ESeqDS - mov ax,ds - mov es,ax - endif - ifnb <fix_cld> - cld - endif - ENDM - - ; - ; Move a memory area - ; Args: to,from,length - ; Acts as one byte was moved a-time from dst to source. - ; - - begcode bmove - public _bmove -_bmove proc near - fix_es 1 - mov edx,edi - mov eax,esi - mov edi,P-SIZEPTR[esp] ;p1 - mov esi,P[esp] ;p2 - mov ecx,P+SIZEPTR[esp] - rep movsb ; Not q_movs because overlap ? - mov esi,eax - mov edi,edx - ret -_bmove ENDP - endcode bmove - - ; - ; Move a alligned, not overlapped, by (long) divided memory area - ; Args: to,from,length - ; - - begcode bmove_align - public _bmove_align -_bmove_align proc near - fix_es 1 - mov edx,edi - mov eax,esi - mov edi,P-SIZEPTR[esp] ;to - mov esi,P[esp] ;from - mov ecx,P+SIZEPTR[esp] ;length - add cx,3 ;fix if not divisible with long - shr cx,2 - rep movsd - mov esi,eax - mov edi,edx - ret -_bmove_align ENDP - endcode bmove_align - - ; - ; Move a string from higher to lower - ; Arg from+1,to+1,length - ; - - begcode bmove_upp - public _bmove_upp -_bmove_upp proc near - fix_es - std ; Work downward - mov edx,edi - mov eax,esi - mov edi,P-SIZEPTR[esp] ;p1 - mov esi,P[esp] ;p2 - mov ecx,P+SIZEPTR[esp] - dec edi ; Don't move last arg - dec esi - rep movsb ; One byte a time because overlap ! - cld ; C compilator wants cld - mov esi,eax - mov edi,edx - ret -_bmove_upp ENDP - endcode bmove_upp - - ; - ; Append fillchars to string - ; Args: dest,len,fill - ; - - begcode strappend - public _strappend -_strappend proc near - push ebp - mov ebp,esp - fix_es 1 - push edi - mov edi,P[ebp] ; Memory pointer - mov ecx,P+SIZEPTR[ebp] ; Length - clr eax ; Find end of string - repne scasb - jnz sa_99 ; String to long, shorten it - movzx eax,byte ptr P+(2*SIZEPTR)[ebp] ; Fillchar - dec edi ; Point at end null - inc ecx ; rep made one dec for null-char - q_stos ; Store al in string -sa_99: mov BYTE PTR [edi],0 ; End of string - pop edi - pop ebp - ret -_strappend ENDP - endcode strappend - - ; - ; Find if string contains any char in another string - ; Arg: str,set - ; Ret: Pointer to first found char in str - ; - - begcode strcont - PUBLIC _strcont -_strcont proc near - push ebp - mov ebp,esp - fix_es 1 - mov edx,edi - push esi - mov esi,P[ebp] ; str - mov ecx,P+SIZEPTR[ebp] ; Set - clr ah ; For endtest - jmps sc_60 - -sc_10: scasb - jz sc_fo ; Found char -sc_20: cmp ah,[edi] ; Test if null - jnz sc_10 ; Not end of set yet - inc esi ; Next char in str -sc_60: mov edi,ecx ; edi = Set - mov al,[esi] ; Test if this char exist - and al,al - jnz sc_20 ; Not end of string - clr esi ; Return Null -sc_fo: mov eax,esi ; Char found here - mov edi,edx ; Restore - pop esi - pop ebp - ret -_strcont ENDP - endcode strcont - - ; - ; Found end of string - ; Arg: str - ; ret: Pointer to end null - ; - - begcode strend - public _strend -_strend proc near - fix_es 1 - mov edx,edi ; Save - mov edi,P-SIZEPTR[esp] ; str - clr eax ; Find end of string - mov ecx,eax - dec ecx ; ECX = -1 - repne scasb - mov eax,edi - dec eax - mov edi,edx ; Restore - ret -_strend endp - endcode strend - - ; - ; Make a string with len fill-chars and endnull - ; Args: dest,len,fill - ; Ret: dest+len - ; - - begcode strfill - public _strfill -_strfill proc near - push ebp - mov ebp,esp - fix_es 1 - push edi - mov edi,P[ebp] ; Memory pointer - mov ecx,P+SIZEPTR[ebp] ; Length - movzx eax,byte ptr P+(2*SIZEPTR)[ebp] ; Fill - q_stos - mov BYTE PTR [edi],0 ; End NULL - mov eax,edi ; End i DX:AX - pop edi - pop ebp - ret -_strfill endp - endcode strfill - - ; - ; Find a char in or end of a string - ; Arg: str,char - ; Ret: pointer to found char or NullS - ; - - begcode strcend - public _strcend -_strcend proc near - push ebp - mov ebp,esp - fix_es 1 - mov edx,edi - mov edi,P[ebp] ; str - mov ah,P+SIZEPTR[ebp] ; search - clr al ; for scasb to find end - -@@: cmp ah,[edi] - jz @F ; Found char - scasb - jnz @B ; Not end - dec edi ; Not found, point at end of string -@@: mov eax,edi - mov edi,edx ; Restore - pop ebp - ret -_strcend ENDP - endcode strcend - - ; - ; Test if string has a given suffix - ; - - begcode is_prefix - public _is_prefix -_is_prefix proc near - fix_es 1 - mov edx,edi ; Save edi - mov eax,esi ; Save esi - mov esi,P[esp] ; get suffix - mov edi,P-SIZEPTR[esp] ; s1 - push eax ; push esi - mov eax,1 ; Ok and zero-test -@@: cmp ah,[esi] - jz suf_ok ; End of string; found suffix - cmpsb ; Compare strings - jz @B ; Same, possible prefix - xor eax,eax ; Not suffix -suf_ok: pop esi - mov edi,edx - ret -_is_prefix endp - endcode _is_prefix - - ; - ; Find a substring in string - ; Arg: str,search - ; - - begcode strstr - public _strstr -_strstr proc near - push ebp - mov ebp,esp - fix_es 1 - push EDI - push ESI - mov esi,P[ebp] ; str - mov edi,P+SIZEPTR[ebp] ; search - mov ecx,edi - inc ecx ; ECX = search+1 - mov ah,[edi] ; AH = First char in search - jmps sf_10 - -sf_00: mov esi,edx ; si = Current str-pos -sf_10: mov al,[esi] ; Test if this char exist - and al,al - jz sf_90 ; End of string, didn't find search - inc esi - cmp al,ah - jnz sf_10 ; Didn't find first char, continue - mov edx,esi ; Save str-pos in EDX - mov edi,ecx -sf_20: cmp BYTE PTR [edi],0 - jz sf_fo ; Found substring - cmpsb - jz sf_20 ; Char ok - jmps sf_00 ; Next str-pos - -sf_90: mov edx,1 ; Return Null -sf_fo: mov eax,edx ; Char found here - dec eax ; Pointed one after - pop ESI - pop EDI - pop ebp - ret -_strstr endp - endcode strstr - - ; - ; Find a substring in string, return index - ; Arg: str,search - ; - - begcode strinstr - public _strinstr -_strinstr proc near - push ebp - mov ebp,esp - push P+SIZEPTR[ebp] ; search - push P[ebp] ; str - call _strstr - add esp,SIZEPTR*2 - or eax,eax - jz si_99 ; Not found, return NULL - sub eax,P[ebp] ; Pos from start - inc eax ; And first pos = 1 -si_99: pop ebp - ret -_strinstr endp - endcode strinstr - - ; - ; Make a string of len length from another string - ; Arg: dst,src,length - ; ret: end of dst - ; - - begcode strmake - public _strmake -_strmake proc near - push ebp - mov ebp,esp - fix_es 1 - push EDI - push ESI - mov edi,P[ebp] ; dst - mov esi,P+SIZEPTR[ebp] ; src - mov ecx,P+SIZEPTR*2[ebp] ; Length of memory-area - clr al ; For test of end-null - jcxz sm_90 ; Nothing to move, put zero at end. - -@@: cmp al,[esi] ; Next char to move - movsb ; move arg - jz sm_99 ; last char, we are ready - loop @B ; Continue moving -sm_90: mov BYTE PTR [edi],al ; Set end pos - inc edi ; Fix that di points at end null -sm_99: dec edi ; di points now at end null - mov eax,edi ; Ret value in DX:AX - pop ESI - pop EDI - pop ebp - ret -_strmake ENDP - endcode strmake - - ; - ; Find length of string with maxlength - ; arg: str,maxlength - ; ret: length - ; - - begcode strnlen - public _strnlen -_strnlen proc near - push ebp - mov ebp,esp - fix_es 1 - push edi - mov edi,P[ebp] ; Str - mov ecx,P+SIZEPTR[ebp] ; length - mov edx,edi ; Save str to calc length - jcxz sn_10 ; Length = 0 - clr al ; Find end of string - repne scasb ; Find strend or length - jnz sn_10 - dec edi ; DI points at last null -sn_10: mov eax,edi - sub eax,edx ; Ax = length - pop edi - pop ebp - ret -_strnlen ENDP - endcode strnlen - - ; - ; Move a string with max len chars - ; arg: dst,src,len - ; ret: pos to first null or dst+len - - begcode strnmov - public _strnmov -_strnmov PROC near - push ebp - mov ebp,esp - fix_es 1 - push EDI - push ESI - mov edi,P[ebp] ; dst - mov esi,P+SIZEPTR[ebp] ; src - mov ecx,P+(SIZEPTR*2)[ebp] ; length - jcxz snm_99 ; Nothing to do - clr al ; For test of end-null - -@@: cmp al,[esi] ; Next char to move - movsb ; move arg - jz snm_20 ; last char, fill with null - loop @B ; Continue moving - inc edi ; Point two after last -snm_20: dec edi ; Point at first null (or last+1) -snm_99: mov eax,edi ; Pointer at last char - pop ESI - pop EDI - pop ebp - ret -_strnmov ENDP - endcode strnmov - -; -; Zortech has this one in standard library -; - - begcode strmov - public _strmov -_strmov proc near - mov ecx,esi ; Save old esi and edi - mov edx,edi - mov esi,P[esp] ; get source pointer (s2) - mov edi,P-SIZEPTR[esp] ; EDI -> s1 - fix_es 1 -@@: mov al,[esi] - movsb ; move arg - and al,al - jnz @B ; Not last - mov eax,edi - dec eax - mov esi,ecx ; Restore args - mov edi,edx - ret -_strmov endp - endcode strmov - -endif ; M_I386 - - END diff --git a/strings/strlen.c b/strings/strlen.c deleted file mode 100644 index 1469dd096ee..00000000000 --- a/strings/strlen.c +++ /dev/null @@ -1,65 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* File : strlen.c - Author : Richard A. O'Keefe. / Monty - Michael Widenius; ifdef MC68000 - Updated: 1986-11-30 - Defines: strlen() - - strlen(s) returns the number of characters in s, that is, the number - of non-NUL characters found before the closing NULEosCh. Note: some - non-standard C compilers for 32-bit machines take int to be 16 bits, - either put up with short strings or change int to long throughout - this package. Better yet, BOYCOTT such shoddy compilers. - Beware: the asm version works only if strlen(s) < 65536. -*/ - -#include "strings.h" - -#if VaxAsm - -size_t strlen(char *s) -{ - asm("locc $0,$65535,*4(ap)"); - asm("subl3 r0,$65535,r0"); -} - -#else -#if defined(MC68000) && defined(DS90) - -size_t strlen(char *s) -{ -asm(" movl 4(a7),a0 "); -asm(" movl a0,a1 "); -asm(".L4: tstb (a0)+ "); -asm(" jne .L4 "); -asm(" movl a0,d0 "); -asm(" subl a1,d0 "); -asm(" subql #1,d0 "); -} -#else - -size_t strlen(register char *s) -{ - register char *startpos; - - startpos = s; - while (*s++); - return ((size_t) (s-startpos-1)); -} - -#endif -#endif diff --git a/strings/strrchr.c b/strings/strrchr.c deleted file mode 100644 index cdb0479ef90..00000000000 --- a/strings/strrchr.c +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* File : strrchr.c - Author : Richard A. O'Keefe. - Updated: 10 April 1984 - Defines: strrchr(), rindex() - - strrchr(s, c) returns a pointer to the last place in s where c - occurs, or NullS if c does not occur in s. This function is called - rindex in V7 and 4.?bsd systems; while not ideal the name is clearer - than strrchr, so rindex remains in strings.h as a macro. NB: - strrchr looks for single characters, not for sets or strings. The - parameter 'c' is declared 'int' so it will go in a register; if your - C compiler is happy with register char change it to that. -*/ - -#include "strings.h" - -char *strrchr(register const char *s, register pchar c) -{ - reg3 char *t; - - t = NullS; - do if (*s == (char) c) t = (char*) s; while (*s++); - return (char*) t; -} diff --git a/strings/strxmov.asm b/strings/strxmov.asm deleted file mode 100644 index ad5d0dd3db0..00000000000 --- a/strings/strxmov.asm +++ /dev/null @@ -1,103 +0,0 @@ -; Copyright (C) 2000 MySQL AB -; -; This library is free software; you can redistribute it and/or -; modify it under the terms of the GNU Library General Public -; License as published by the Free Software Foundation; version 2 -; of the License. -; -; This library 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 -; Library General Public License for more details. -; -; You should have received a copy of the GNU Library General Public -; License along with this library; if not, write to the Free -; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -; MA 02111-1307, USA - - TITLE Optimized strxmov for MSDOS / Intel 8086 - -ifndef M_I386 - .8087 - DOSSEG - .MODEL LARGE - .CODE - - PUBLIC _strxmov -_strxmov PROC - mov bx,sp - add bx,4 - push si - push di - mov cx,ds ; Save ds -ASSUME DS: NOTHING -ASSUME ES: NOTHING - les di,DWORD PTR ss:[bx] ; dst - jmp next_str - -start_str: - mov al,ds:[si] - movsb ; move arg - and al,al - jnz start_str ; Not last - dec di - -next_str: - add bx,4 - lds si,DWORD PTR ss:[bx] - mov ax,ds - or ax,si - jnz start_str - - mov byte ptr es:[di],0 ; Force end null (if no source) - mov ds,cx - mov ax,di ; Return ptr to last 0 - mov dx,es - pop di - pop si - ret -_strxmov ENDP - -else - -include macros.asm - - begcode strxmov - public _strxmov - -_strxmov PROC near -ASSUME DS: NOTHING -ASSUME ES: NOTHING - push EBP - mov EBP,ESP - mov EDX,EBX ; Save EBX - mov ECX,ESI ; Save ESI - push EDI - mov EDI,8[EBP] ; Get destination - lea EBX,8[EBP] ; Get adress to first source - 4 - xor al,al - jmp next_str - -start_str: movsb - cmp AL,[EDI-1] - jne start_str - dec EDI ; Don't copy last null - -next_str: add EBX,4 - mov ESI,[EBX] - or ESI,ESI - jne start_str - mov byte ptr [EDI],0 ; Force last null - - mov EAX,EDI ; Return ptr to null - pop EDI - mov ESI,ECX - mov EBX,EDX - pop EBP - ret -_strxmov endp - endcode strxmov - -endif - - END diff --git a/strings/udiv.c b/strings/udiv.c deleted file mode 100644 index 81ac01ee9c3..00000000000 --- a/strings/udiv.c +++ /dev/null @@ -1,36 +0,0 @@ -/* Copyright (C) 2000 MySQL AB - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - -/* Do udiv and urem if machine dosn't have it */ - -#include <my_global.h> -#include <math.h> - -unsigned long udiv(long unsigned int a, long unsigned int b) -{ - if (a < INT_MAX32 && b < INT_MAX32) - return (unsigned long) ((long) a / (long) b); - if (!(b & 1)) - return (unsigned long) ((long) (a >> 1) / (long) (b >> 1)); - - return (unsigned long) floor(((double) a / (double) b)); -} - -unsigned long urem(long unsigned int a, long unsigned int b) -{ - if (a < INT_MAX32 && b < INT_MAX32) - return (unsigned long) ((long) a % (long) b); - return a-udiv(a,b)*b; -} diff --git a/support-files/mysql.spec.sh b/support-files/mysql.spec.sh index 657dd3fbbdf..bb15b27cd1f 100644 --- a/support-files/mysql.spec.sh +++ b/support-files/mysql.spec.sh @@ -122,20 +122,20 @@ %endif %if %{distro_specific} %if %(test -f /etc/redhat-release && echo 1 || echo 0) - %define elver %(rpm -qf --qf '%%{version}\\n' /etc/redhat-release | sed -e 's/^\\([0-9]*\\).*/\\1/g') - %if "%elver" == "4" - %define distro_description Enterprise Linux 4 - %define distro_releasetag el4 + %define rhelver %(rpm -qf --qf '%%{version}\\n' /etc/redhat-release | sed -e 's/^\\([0-9]*\\).*/\\1/g') + %if "%rhelver" == "4" + %define distro_description Red Hat Enterprise Linux 4 + %define distro_releasetag rhel4 %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel %define distro_requires chkconfig coreutils grep procps shadow-utils %else - %if "%elver" == "5" - %define distro_description Enterprise Linux 5 - %define distro_releasetag el5 + %if "%rhelver" == "5" + %define distro_description Red Hat Enterprise Linux 5 + %define distro_releasetag rhel5 %define distro_buildreq gcc-c++ gperf ncurses-devel perl readline-devel time zlib-devel %define distro_requires chkconfig coreutils grep procps shadow-utils %else - %{error:Enterprise Linux %{elver} is unsupported} + %{error:Red Hat Enterprise Linux %{rhelver} is unsupported} %endif %endif %else @@ -396,8 +396,9 @@ mkdir debug -e 's/ -ip / /' \ -e 's/^ //' \ -e 's/ $//'` - # XXX: MYSQL_UNIX_ADDR should be in cmake/* but mysql_version is included before - # XXX: install_layout so we can't just set it based on INSTALL_LAYOUT=RPM + # XXX: MYSQL_UNIX_ADDR should be in cmake/* but mysql_version is included + # XXX: before install_layout so we can't just set it based on + # XXX: INSTALL_LAYOUT=RPM ${CMAKE} ../%{src_dir} -DBUILD_CONFIG=mysql_release -DINSTALL_LAYOUT=RPM \ -DCMAKE_BUILD_TYPE=Debug \ -DMYSQL_UNIX_ADDR="/var/lib/mysql/mysql.sock" \ @@ -410,8 +411,9 @@ mkdir debug mkdir release ( cd release - # XXX: MYSQL_UNIX_ADDR should be in cmake/* but mysql_version is included before - # XXX: install_layout so we can't just set it based on INSTALL_LAYOUT=RPM + # XXX: MYSQL_UNIX_ADDR should be in cmake/* but mysql_version is included + # XXX: before install_layout so we can't just set it based on + # XXX: INSTALL_LAYOUT=RPM ${CMAKE} ../%{src_dir} -DBUILD_CONFIG=mysql_release -DINSTALL_LAYOUT=RPM \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DMYSQL_UNIX_ADDR="/var/lib/mysql/mysql.sock" \ @@ -468,8 +470,10 @@ install -d $RBR%{_sbindir} mv -v $RBR/%{_libdir}/*.a $RBR/%{_libdir}/mysql/ # Install logrotate and autostart -install -m 644 $MBD/release/support-files/mysql-log-rotate $RBR%{_sysconfdir}/logrotate.d/mysql -install -m 755 $MBD/release/support-files/mysql.server $RBR%{_sysconfdir}/init.d/mysql +install -m 644 $MBD/release/support-files/mysql-log-rotate \ + $RBR%{_sysconfdir}/logrotate.d/mysql +install -m 755 $MBD/release/support-files/mysql.server \ + $RBR%{_sysconfdir}/init.d/mysql # Create a symlink "rcmysql", pointing to the init.script. SuSE users # will appreciate that, as all services usually offer this. @@ -487,7 +491,8 @@ install -m 600 $MBD/%{src_dir}/support-files/RHEL4-SElinux/mysql.{fc,te} \ # Even though this is a shared library, put it under /usr/lib*/mysql, so it # doesn't conflict with possible shared lib by the same name in /usr/lib*. See # `mysql_config --variable=pkglibdir` and mysqld_safe for how this is used. -install -m 644 "%{malloc_lib_source}" "$RBR%{_libdir}/mysql/%{malloc_lib_target}" +install -m 644 "%{malloc_lib_source}" \ + "$RBR%{_libdir}/mysql/%{malloc_lib_target}" %endif # Remove man pages we explicitly do not want to package, avoids 'unpackaged @@ -511,15 +516,19 @@ if [ $? -eq 0 -a -n "$installed" ]; then myvendor='%{mysql_vendor}' myversion='%{mysql_version}' - old_family=`echo $version | sed -n -e 's,^\([1-9][0-9]*\.[0-9][0-9]*\)\..*$,\1,p'` - new_family=`echo $myversion | sed -n -e 's,^\([1-9][0-9]*\.[0-9][0-9]*\)\..*$,\1,p'` + old_family=`echo $version \ + | sed -n -e 's,^\([1-9][0-9]*\.[0-9][0-9]*\)\..*$,\1,p'` + new_family=`echo $myversion \ + | sed -n -e 's,^\([1-9][0-9]*\.[0-9][0-9]*\)\..*$,\1,p'` [ -z "$vendor" ] && vendor='<unknown>' [ -z "$old_family" ] && old_family="<unrecognized version $version>" [ -z "$new_family" ] && new_family="<bad package specification: version $myversion>" error_text= - if [ "$vendor" != "$myoldvendor" -a "$vendor" != "$myvendor_2" -a "$vendor" != "$myvendor" ]; then + if [ "$vendor" != "$myoldvendor" \ + -a "$vendor" != "$myvendor_2" \ + -a "$vendor" != "$myvendor" ]; then error_text="$error_text The current MySQL server package is provided by a different vendor ($vendor) than $myoldvendor, $myvendor_2, or $myvendor. @@ -569,9 +578,9 @@ fi # Shut down a previously installed server first if [ -x %{_sysconfdir}/init.d/mysql ] ; then - %{_sysconfdir}/init.d/mysql stop > /dev/null 2>&1 - echo "Giving mysqld 5 seconds to exit nicely" - sleep 5 + %{_sysconfdir}/init.d/mysql stop > /dev/null 2>&1 + echo "Giving mysqld 5 seconds to exit nicely" + sleep 5 fi %post -n MySQL-server%{product_suffix} @@ -589,10 +598,10 @@ if [ ! -d $mysql_datadir/test ] ; then mkdir $mysql_datadir/test; fi # ---------------------------------------------------------------------- # use insserv for older SuSE Linux versions if [ -x /sbin/insserv ] ; then - /sbin/insserv %{_sysconfdir}/init.d/mysql + /sbin/insserv %{_sysconfdir}/init.d/mysql # use chkconfig on Enterprise Linux and newer SuSE releases elif [ -x /sbin/chkconfig ] ; then - /sbin/chkconfig --add mysql + /sbin/chkconfig --add mysql fi # ---------------------------------------------------------------------- @@ -600,8 +609,10 @@ fi # exists. # ---------------------------------------------------------------------- groupadd -r %{mysqld_group} 2> /dev/null || true -useradd -M -r -d $mysql_datadir -s /bin/bash -c "MySQL server" -g %{mysqld_group} %{mysqld_user} 2> /dev/null || true -# The user may already exist, make sure it has the proper group nevertheless (BUG#12823) +useradd -M -r -d $mysql_datadir -s /bin/bash -c "MySQL server" \ + -g %{mysqld_group} %{mysqld_user} 2> /dev/null || true +# The user may already exist, make sure it has the proper group nevertheless +# (BUG#12823) usermod -g %{mysqld_group} %{mysqld_user} 2> /dev/null || true # ---------------------------------------------------------------------- @@ -630,32 +641,66 @@ chown -R %{mysqld_user}:%{mysqld_group} $mysql_datadir # ---------------------------------------------------------------------- chmod -R og-rw $mysql_datadir/mysql +# ---------------------------------------------------------------------- +# install SELinux files - but don't override existing ones +# ---------------------------------------------------------------------- +SETARGETDIR=/etc/selinux/targeted/src/policy +SEDOMPROG=$SETARGETDIR/domains/program +SECONPROG=$SETARGETDIR/file_contexts/program +if [ -f /etc/redhat-release ] \ + && (grep -q "Red Hat Enterprise Linux .. release 4" /etc/redhat-release \ + || grep -q "CentOS release 4" /etc/redhat-release) ; then + echo + echo + echo 'Notes regarding SELinux on this platform:' + echo '=========================================' + echo + echo 'The default policy might cause server startup to fail because it is' + echo 'not allowed to access critical files. In this case, please update' + echo 'your installation.' + echo + echo 'The default policy might also cause inavailability of SSL related' + echo 'features because the server is not allowed to access /dev/random' + echo 'and /dev/urandom. If this is a problem, please do the following:' + echo + echo ' 1) install selinux-policy-targeted-sources from your OS vendor' + echo ' 2) add the following two lines to '$SEDOMPROG/mysqld.te':' + echo ' allow mysqld_t random_device_t:chr_file read;' + echo ' allow mysqld_t urandom_device_t:chr_file read;' + echo ' 3) cd to '$SETARGETDIR' and issue the following command:' + echo ' make load' + echo + echo +fi + +if [ -x sbin/restorecon ] ; then + sbin/restorecon -R var/lib/mysql +fi + # Restart in the same way that mysqld will be started normally. -%{_sysconfdir}/init.d/mysql start +if [ -x %{_sysconfdir}/init.d/mysql ] ; then + %{_sysconfdir}/init.d/mysql start + echo "Giving mysqld 2 seconds to start" + sleep 2 +fi # Allow mysqld_safe to start mysqld and print a message before we exit sleep 2 -#echo "Thank you for installing the MySQL Community Server! For Production -#systems, we recommend MySQL Enterprise, which contains enterprise-ready -#software, intelligent advisory services, and full production support with -#scheduled service packs and more. Visit www.mysql.com/enterprise for more -#information." - %preun -n MySQL-server%{product_suffix} if [ $1 = 0 ] ; then - # Stop MySQL before uninstalling it - if [ -x %{_sysconfdir}/init.d/mysql ] ; then - %{_sysconfdir}/init.d/mysql stop > /dev/null - # Remove autostart of MySQL - # For older SuSE Linux versions - if [ -x /sbin/insserv ] ; then - /sbin/insserv -r %{_sysconfdir}/init.d/mysql - # use chkconfig on Enterprise Linux and newer SuSE releases - elif [ -x /sbin/chkconfig ] ; then - /sbin/chkconfig --del mysql - fi - fi + # Stop MySQL before uninstalling it + if [ -x %{_sysconfdir}/init.d/mysql ] ; then + %{_sysconfdir}/init.d/mysql stop > /dev/null + # Remove autostart of MySQL + # For older SuSE Linux versions + if [ -x /sbin/insserv ] ; then + /sbin/insserv -r %{_sysconfdir}/init.d/mysql + # use chkconfig on Enterprise Linux and newer SuSE releases + elif [ -x /sbin/chkconfig ] ; then + /sbin/chkconfig --del mysql + fi + fi fi # We do not remove the mysql user since it may still own a lot of @@ -665,7 +710,8 @@ fi # Clean up the BuildRoot after build is done # ---------------------------------------------------------------------- %clean -[ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] && rm -rf $RPM_BUILD_ROOT; +[ "$RPM_BUILD_ROOT" != "/" ] && [ -d $RPM_BUILD_ROOT ] \ + && rm -rf $RPM_BUILD_ROOT; ############################################################################## # Files section @@ -846,6 +892,10 @@ fi # merging BK trees) ############################################################################## %changelog +* Tue Jun 1 2010 Jonathan Perkin <jonathan.perkin@oracle.com> + +- Implement SELinux checks from distribution-specific spec file. + * Wed May 12 2010 Jonathan Perkin <jonathan.perkin@oracle.com> - Large number of changes to build using CMake diff --git a/vio/viosocket.c b/vio/viosocket.c index 6c361e4a462..9c0243db4f3 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -1057,9 +1057,11 @@ ssize_t vio_pending(Vio *vio) /** This is a wrapper for the system getnameinfo(), because different OS - differ in the getnameinfo() implementation. For instance, Solaris 10 - requires that the 2nd argument (salen) must match the actual size of the - struct sockaddr_storage passed to it. + differ in the getnameinfo() implementation: + - Solaris 10 requires that the 2nd argument (salen) must match the + actual size of the struct sockaddr_storage passed to it; + - Mac OS X has sockaddr_in::sin_len and sockaddr_in6::sin6_len and + requires them to be filled. */ int vio_getnameinfo(const struct sockaddr *sa, @@ -1072,11 +1074,17 @@ int vio_getnameinfo(const struct sockaddr *sa, switch (sa->sa_family) { case AF_INET: sa_length= sizeof (struct sockaddr_in); +#ifdef HAVE_SOCKADDR_IN_SIN_LEN + ((struct sockaddr_in *) sa)->sin_len= sa_length; +#endif /* HAVE_SOCKADDR_IN_SIN_LEN */ break; #ifdef HAVE_IPV6 case AF_INET6: sa_length= sizeof (struct sockaddr_in6); +# ifdef HAVE_SOCKADDR_IN6_SIN6_LEN + ((struct sockaddr_in6 *) sa)->sin6_len= sa_length; +# endif /* HAVE_SOCKADDR_IN6_SIN6_LEN */ break; #endif /* HAVE_IPV6 */ } |