diff options
284 files changed, 7320 insertions, 5139 deletions
diff --git a/BUILD/FINISH.sh b/BUILD/FINISH.sh index 142ff7eb08e..b7f7a1db77e 100644 --- a/BUILD/FINISH.sh +++ b/BUILD/FINISH.sh @@ -6,6 +6,7 @@ configure="./configure $base_configs $extra_configs" commands="\ $make -k maintainer-clean || true /bin/rm -rf */.deps/*.P configure config.cache storage/*/configure storage/*/config.cache autom4te.cache storage/*/autom4te.cache; +/bin/rm -rf CMakeCache.txt CMakeFiles/ path=`dirname $0` . \"$path/autorun.sh\"" diff --git a/BUILD/Makefile.am b/BUILD/Makefile.am index c7bf813c9fe..c5732d43fbf 100644 --- a/BUILD/Makefile.am +++ b/BUILD/Makefile.am @@ -20,7 +20,7 @@ EXTRA_DIST = FINISH.sh \ SETUP.sh \ autorun.sh \ - choose_configure.sh \ + cmake_configure.sh \ build_mccge.sh \ check-cpu \ cleanup \ diff --git a/BUILD/autorun.sh b/BUILD/autorun.sh index f45b1f7d08c..9fdd0486360 100755 --- a/BUILD/autorun.sh +++ b/BUILD/autorun.sh @@ -21,18 +21,24 @@ done IFS="$save_ifs" rm -rf configure -aclocal || die "Can't execute aclocal" -autoheader || die "Can't execute autoheader" -# --force means overwrite ltmain.sh script if it already exists -$LIBTOOLIZE --automake --force --copy || die "Can't execute libtoolize" - -# --add-missing instructs automake to install missing auxiliary files -# and --force to overwrite them if they already exist -automake --add-missing --force --copy || die "Can't execute automake" -autoconf || die "Can't execute autoconf" -# Do not use autotools generated configure directly. Instead, use a script -# that will either call CMake or original configure shell script at build -# time (CMake is preferred if installed). -mv configure configure.am -cp BUILD/choose_configure.sh configure -chmod a+x configure + +# Ensure that cmake and perl are available. Required for cmake based builds. +cmake -P cmake/check_minimal_version.cmake >/dev/null 2>&1 || HAVE_CMAKE=no +perl --version >/dev/null 2>&1 || HAVE_CMAKE=no + +# Whether to use the autotools configuration script or cmake. +if test "$HAVE_CMAKE" = "no" +then + aclocal || die "Can't execute aclocal" + autoheader || die "Can't execute autoheader" + # --force means overwrite ltmain.sh script if it already exists + $LIBTOOLIZE --automake --force --copy || die "Can't execute libtoolize" + # --add-missing instructs automake to install missing auxiliary files + # and --force to overwrite them if they already exist + automake --add-missing --force --copy || die "Can't execute automake" + autoconf || die "Can't execute autoconf" +else + path=`dirname $0` + cp $path/cmake_configure.sh $path/../configure + chmod +x $path/../configure +fi diff --git a/BUILD/choose_configure.sh b/BUILD/cmake_configure.sh index 80423205274..80423205274 100644 --- a/BUILD/choose_configure.sh +++ b/BUILD/cmake_configure.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index e50e24d0fa5..fed3d61be8f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,9 @@ OPTION(ENABLED_PROFILING "Enable profiling" ON) OPTION(CYBOZU "" OFF) OPTION(BACKUP_TEST "" OFF) OPTION(WITHOUT_SERVER OFF) +IF(UNIX) + OPTION(WITH_VALGRIND "Valgrind instrumentation" OFF) +ENDIF() OPTION (WITH_UNIT_TESTS "Compile MySQL with unit tests" ON) MARK_AS_ADVANCED(CYBOZU BACKUP_TEST WITHOUT_SERVER DISABLE_SHARED) diff --git a/Makefile.am b/Makefile.am index a559972969b..7ab9a9aa061 100644 --- a/Makefile.am +++ b/Makefile.am @@ -65,7 +65,7 @@ dist-hook: test ! -f $(top_srcdir)/configure.am || \ $(INSTALL_DATA) $(top_srcdir)/configure.am $(distdir) -all-local: @ABI_CHECK@ +all-local: @ABI_CHECK@ tags: support-files/build-tags @@ -314,7 +314,7 @@ abi_check_all: abi_check do_abi_check: set -ex; \ for file in $(abi_headers); do \ - @CC@ -E -nostdinc -dI \ + @CC@ -E -nostdinc -dI -DMYSQL_ABI_CHECK \ -I$(top_srcdir)/include \ -I$(top_srcdir)/include/mysql \ -I$(top_srcdir)/sql \ diff --git a/client/mysql.cc b/client/mysql.cc index d768a01eb5d..01a786c13af 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -3652,7 +3652,7 @@ xmlencode_print(const char *src, uint length) tee_fputs("NULL", PAGER); else { - for (const char *p = src; length; *p++, length--) + for (const char *p = src; length; p++, length--) { const char *t; if ((t = array_value(xmlmeta, *p))) @@ -4740,7 +4740,7 @@ static const char* construct_prompt() struct tm *t = localtime(&lclock); /* parse thru the settings for the prompt */ - for (char *c = current_prompt; *c ; *c++) + for (char *c = current_prompt; *c ; c++) { if (*c != PROMPT_CHAR) processed_prompt.append(*c); diff --git a/client/mysql_upgrade.c b/client/mysql_upgrade.c index 20436200c7e..eeab3611913 100644 --- a/client/mysql_upgrade.c +++ b/client/mysql_upgrade.c @@ -596,7 +596,10 @@ static int upgrade_already_done(void) my_fclose(in, MYF(0)); - return (strncmp(buf, MYSQL_SERVER_VERSION, + if (!res) + return 0; /* Could not read from file => not sure */ + + return (strncmp(res, MYSQL_SERVER_VERSION, sizeof(MYSQL_SERVER_VERSION)-1)==0); } diff --git a/cmake/abi_check.cmake b/cmake/abi_check.cmake index 0d5bf21f540..7911b7848a8 100644 --- a/cmake/abi_check.cmake +++ b/cmake/abi_check.cmake @@ -38,7 +38,7 @@ IF(CMAKE_COMPILER_IS_GNUCC AND CMAKE_SYSTEM_NAME MATCHES "Linux") -DCOMPILER=${COMPILER} -DSOURCE_DIR=${CMAKE_SOURCE_DIR} -DBINARY_DIR=${CMAKE_BINARY_DIR} - "-DABI_HEADERS=${API_PREPROCESSOR_HEADER}" + "-DDMYSQL_ABI_CHECK -DABI_HEADERS=${API_PREPROCESSOR_HEADER}" -P ${CMAKE_SOURCE_DIR}/cmake/do_abi_check.cmake VERBATIM ) @@ -48,7 +48,7 @@ IF(CMAKE_COMPILER_IS_GNUCC AND CMAKE_SYSTEM_NAME MATCHES "Linux") -DCMAKE_C_COMPILER=${COMPILER} -DCMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR} -DCMAKE_BINARY_DIR=${CMAKE_BINARY_DIR} - "-DABI_HEADERS=${API_PREPROCESSOR_HEADER}" + "-DMYSQL_ABI_CHECK -DABI_HEADERS=${API_PREPROCESSOR_HEADER}" -P ${CMAKE_SOURCE_DIR}/cmake/scripts/do_abi_check.cmake VERBATIM ) diff --git a/config.h.cmake b/config.h.cmake index 1b59c580503..c484edb65a5 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -308,7 +308,7 @@ #define USE_MB 1 #define USE_MB_IDENT 1 - +#cmakedefine HAVE_VALGRIND /* Types we may use */ #ifdef __APPLE__ diff --git a/configure.cmake b/configure.cmake index d032d7ed448..c2e1dc4647b 100644 --- a/configure.cmake +++ b/configure.cmake @@ -805,7 +805,7 @@ ENDIF(NOT HAVE_POSIX_SIGNALS) # Assume regular sprintf SET(SPRINTFS_RETURNS_INT 1) -IF(CMAKE_COMPILER_IS_GNUXX AND HAVE_CXXABI_H) +IF(CMAKE_COMPILER_IS_GNUCXX AND HAVE_CXXABI_H) CHECK_CXX_SOURCE_COMPILES(" #include <cxxabi.h> int main(int argc, char **argv) @@ -994,6 +994,14 @@ configuration. By default gcc built-in sync functions are used, if available and 'smp' configuration otherwise.") MARK_AS_ADVANCED(WITH_ATOMIC_LOCKS MY_ATOMIC_MODE_RWLOCK MY_ATOMIC_MODE_DUMMY) +IF(WITH_VALGRIND) + CHECK_INCLUDE_FILES("valgrind/memcheck.h;valgrind/valgrind.h" + HAVE_VALGRIND_HEADERS) + IF(HAVE_VALGRIND_HEADERS) + SET(HAVE_VALGRIND 1) + ENDIF() +ENDIF() + #-------------------------------------------------------------------- # Check for IPv6 support #-------------------------------------------------------------------- diff --git a/configure.in b/configure.in index f4db1d2b39e..7121a521f87 100644 --- a/configure.in +++ b/configure.in @@ -463,16 +463,7 @@ if test "$GCC" != "yes" || expr "$CC" : ".*icc.*" then ABI_CHECK="" else - # Workaround GCC >= 4.5 - See Bug#52514 - case `$CC -dumpversion` in - [[4-9]].[[5-9]]*) - AC_MSG_WARN([ABI check disabled (GCC >= 4.5)]) - ABI_CHECK="" - ;; - *) - ABI_CHECK="abi_check" - ;; - esac + ABI_CHECK="abi_check" fi AC_SUBST(ABI_CHECK) @@ -3045,7 +3036,8 @@ fi AC_CONFIG_FILES(Makefile extra/Makefile mysys/Makefile dnl unittest/Makefile unittest/mytap/Makefile unittest/mytap/t/Makefile dnl - unittest/mysys/Makefile unittest/examples/Makefile dnl + unittest/mysys/Makefile unittest/strings/Makefile dnl + unittest/examples/Makefile dnl strings/Makefile regex/Makefile storage/Makefile dnl man/Makefile BUILD/Makefile vio/Makefile dnl libmysql/Makefile libmysql_r/Makefile client/Makefile dnl diff --git a/extra/comp_err.c b/extra/comp_err.c index 3c56770650f..4c40e70f5b7 100644 --- a/extra/comp_err.c +++ b/extra/comp_err.c @@ -857,7 +857,6 @@ static struct message *parse_message_string(struct message *new_message, static struct errors *parse_error_string(char *str, int er_count) { struct errors *new_error; - char *start; DBUG_ENTER("parse_error_string"); DBUG_PRINT("enter", ("str: %s", str)); @@ -868,7 +867,6 @@ static struct errors *parse_error_string(char *str, int er_count) DBUG_RETURN(0); /* OOM: Fatal error */ /* getting the error name */ - start= str; str= skip_delimiters(str); if (!(new_error->er_name= get_word(&str))) diff --git a/extra/yassl/src/yassl_imp.cpp b/extra/yassl/src/yassl_imp.cpp index f079df8c7ce..86799f961ae 100644 --- a/extra/yassl/src/yassl_imp.cpp +++ b/extra/yassl/src/yassl_imp.cpp @@ -884,21 +884,19 @@ void Alert::Process(input_buffer& input, SSL& ssl) else hmac(ssl, verify, data, aSz, alert, true); - // read mac and fill + // read mac and skip fill int digestSz = ssl.getCrypto().get_digest().get_digestSize(); opaque mac[SHA_LEN]; input.read(mac, digestSz); if (ssl.getSecurity().get_parms().cipher_type_ == block) { int ivExtra = 0; - opaque fill; if (ssl.isTLSv1_1()) ivExtra = ssl.getCrypto().get_cipher().get_blockSize(); int padSz = ssl.getSecurity().get_parms().encrypt_size_ - ivExtra - aSz - digestSz; - for (int i = 0; i < padSz; i++) - fill = input[AUTO]; + input.set_current(input.get_current() + padSz); } // verify @@ -981,17 +979,17 @@ output_buffer& operator<<(output_buffer& output, const Data& data) void Data::Process(input_buffer& input, SSL& ssl) { int msgSz = ssl.getSecurity().get_parms().encrypt_size_; - int pad = 0, padByte = 0; + int pad = 0, padSz = 0; int ivExtra = 0; if (ssl.getSecurity().get_parms().cipher_type_ == block) { if (ssl.isTLSv1_1()) // IV ivExtra = ssl.getCrypto().get_cipher().get_blockSize(); pad = *(input.get_buffer() + input.get_current() + msgSz -ivExtra - 1); - padByte = 1; + padSz = 1; } int digestSz = ssl.getCrypto().get_digest().get_digestSize(); - int dataSz = msgSz - ivExtra - digestSz - pad - padByte; + int dataSz = msgSz - ivExtra - digestSz - pad - padSz; opaque verify[SHA_LEN]; const byte* rawData = input.get_buffer() + input.get_current(); @@ -1020,14 +1018,10 @@ void Data::Process(input_buffer& input, SSL& ssl) hmac(ssl, verify, rawData, dataSz, application_data, true); } - // read mac and fill + // read mac and skip fill opaque mac[SHA_LEN]; - opaque fill; input.read(mac, digestSz); - for (int i = 0; i < pad; i++) - fill = input[AUTO]; - if (padByte) - fill = input[AUTO]; + input.set_current(input.get_current() + pad + padSz); // verify if (dataSz) { @@ -2073,11 +2067,9 @@ void Finished::Process(input_buffer& input, SSL& ssl) if (ssl.isTLSv1_1()) ivExtra = ssl.getCrypto().get_cipher().get_blockSize(); - opaque fill; int padSz = ssl.getSecurity().get_parms().encrypt_size_ - ivExtra - HANDSHAKE_HEADER - finishedSz - digestSz; - for (int i = 0; i < padSz; i++) - fill = input[AUTO]; + input.set_current(input.get_current() + padSz); // verify mac if (memcmp(mac, verifyMAC, digestSz)) { diff --git a/include/my_pthread.h b/include/my_pthread.h index e5ffa0db3bb..0c89a2ed384 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -255,14 +255,13 @@ int sigwait(sigset_t *setp, int *sigp); /* Use our implemention */ we want to make sure that no such flags are set. */ #if defined(HAVE_SIGACTION) && !defined(my_sigset) -#define my_sigset(A,B) do { struct sigaction l_s; sigset_t l_set; int l_rc; \ +#define my_sigset(A,B) do { struct sigaction l_s; sigset_t l_set; \ DBUG_ASSERT((A) != 0); \ sigemptyset(&l_set); \ l_s.sa_handler = (B); \ l_s.sa_mask = l_set; \ l_s.sa_flags = 0; \ - l_rc= sigaction((A), &l_s, (struct sigaction *) NULL);\ - DBUG_ASSERT(l_rc == 0); \ + sigaction((A), &l_s, NULL); \ } while (0) #elif defined(HAVE_SIGSET) && !defined(my_sigset) #define my_sigset(A,B) sigset((A),(B)) diff --git a/include/mysql.h b/include/mysql.h index 7eef91cf55a..dc6e4eb19a6 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -44,7 +44,9 @@ extern "C" { #endif #ifndef _global_h /* If not standard header */ +#ifndef MYSQL_ABI_CHECK #include <sys/types.h> +#endif #ifdef __LCC__ #include <winsock2.h> /* For windows */ #endif diff --git a/include/mysql.h.pp b/include/mysql.h.pp index bc5d611ec84..531062aee80 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -1,4 +1,3 @@ -#include <sys/types.h> typedef char my_bool; typedef int my_socket; #include "mysql_version.h" diff --git a/include/mysql/plugin.h.pp b/include/mysql/plugin.h.pp index 3a1b03742da..ce9902ee418 100644 --- a/include/mysql/plugin.h.pp +++ b/include/mysql/plugin.h.pp @@ -1,7 +1,5 @@ #include <mysql/services.h> #include <mysql/service_my_snprintf.h> -#include <stdarg.h> -#include <stdlib.h> extern struct my_snprintf_service_st { size_t (*my_snprintf_type)(char*, size_t, const char*, ...); size_t (*my_vsnprintf_type)(char *, size_t, const char*, va_list); @@ -9,7 +7,6 @@ extern struct my_snprintf_service_st { size_t my_snprintf(char* to, size_t n, const char* fmt, ...); size_t my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap); #include <mysql/service_thd_alloc.h> -#include <stdlib.h> struct st_mysql_lex_string { char *str; diff --git a/include/mysql/service_my_snprintf.h b/include/mysql/service_my_snprintf.h index 9e5fe7f9c9f..d7f8d07e110 100644 --- a/include/mysql/service_my_snprintf.h +++ b/include/mysql/service_my_snprintf.h @@ -70,8 +70,11 @@ extern "C" { #endif +#ifndef MYSQL_ABI_CHECK #include <stdarg.h> #include <stdlib.h> +#endif + extern struct my_snprintf_service_st { size_t (*my_snprintf_type)(char*, size_t, const char*, ...); size_t (*my_vsnprintf_type)(char *, size_t, const char*, va_list); diff --git a/include/mysql/service_thd_alloc.h b/include/mysql/service_thd_alloc.h index 86158ba1359..7061c2bd4d5 100644 --- a/include/mysql/service_thd_alloc.h +++ b/include/mysql/service_thd_alloc.h @@ -27,7 +27,9 @@ allocations - they are better served with my_malloc. */ +#ifndef MYSQL_ABI_CHECK #include <stdlib.h> +#endif #ifdef __cplusplus extern "C" { diff --git a/include/mysys_err.h b/include/mysys_err.h index 9629dfec014..4067a3cfbd1 100644 --- a/include/mysys_err.h +++ b/include/mysys_err.h @@ -63,7 +63,9 @@ extern const char *globerrs[]; /* my_error_messages is here */ #define EE_UNKNOWN_COLLATION 28 #define EE_FILENOTFOUND 29 #define EE_FILE_NOT_CLOSED 30 -#define EE_ERROR_LAST 30 /* Copy last error nr */ +#define EE_CHANGE_OWNERSHIP 31 +#define EE_CHANGE_PERMISSIONS 32 +#define EE_ERROR_LAST 32 /* Copy last error nr */ /* Add error numbers before EE_ERROR_LAST and change it accordingly. */ /* exit codes for all MySQL programs */ diff --git a/include/thr_lock.h b/include/thr_lock.h index 37dc37f8017..5626c067e5e 100644 --- a/include/thr_lock.h +++ b/include/thr_lock.h @@ -89,23 +89,11 @@ typedef struct st_thr_lock_info { pthread_t thread; my_thread_id thread_id; - ulong n_cursors; } THR_LOCK_INFO; -/* - Lock owner identifier. Globally identifies the lock owner within the - thread and among all the threads. The address of an instance of this - structure is used as id. -*/ - -typedef struct st_thr_lock_owner -{ - THR_LOCK_INFO *info; -} THR_LOCK_OWNER; - typedef struct st_thr_lock_data { - THR_LOCK_OWNER *owner; + THR_LOCK_INFO *owner; struct st_thr_lock_data *next,**prev; struct st_thr_lock *lock; mysql_cond_t *cond; @@ -141,19 +129,18 @@ extern LIST *thr_lock_thread_list; extern mysql_mutex_t THR_LOCK_lock; my_bool init_thr_lock(void); /* Must be called once/thread */ -#define thr_lock_owner_init(owner, info_arg) (owner)->info= (info_arg) void thr_lock_info_init(THR_LOCK_INFO *info); void thr_lock_init(THR_LOCK *lock); void thr_lock_delete(THR_LOCK *lock); void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *status_param); enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, - THR_LOCK_OWNER *owner, + THR_LOCK_INFO *owner, enum thr_lock_type lock_type, ulong lock_wait_timeout); void thr_unlock(THR_LOCK_DATA *data); enum enum_thr_lock_result thr_multi_lock(THR_LOCK_DATA **data, - uint count, THR_LOCK_OWNER *owner, + uint count, THR_LOCK_INFO *owner, ulong lock_wait_timeout); void thr_multi_unlock(THR_LOCK_DATA **data,uint count); void diff --git a/mysql-test/include/handler.inc b/mysql-test/include/handler.inc index 0031cb68647..98988ab55ba 100644 --- a/mysql-test/include/handler.inc +++ b/mysql-test/include/handler.inc @@ -1757,3 +1757,35 @@ disconnect con51355; --echo # Connection default connection default; + +--echo # +--echo # Bug#54401 assert in Diagnostics_area::set_eof_status , HANDLER +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +DROP FUNCTION IF EXISTS f1; +--enable_warnings + +delimiter |; +CREATE FUNCTION f1() RETURNS INTEGER +BEGIN + SELECT 1 FROM t2 INTO @a; + RETURN 1; +END| +delimiter ;| + +# Get f1() parsed and cached +--error ER_NO_SUCH_TABLE +SELECT f1(); + +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1); +HANDLER t1 OPEN; +# This used to cause the assert +--error ER_NO_SUCH_TABLE +HANDLER t1 READ FIRST WHERE f1() = 1; +HANDLER t1 CLOSE; + +DROP FUNCTION f1; +DROP TABLE t1; diff --git a/mysql-test/lib/v1/mysql-test-run.pl b/mysql-test/lib/v1/mysql-test-run.pl index 489db060e99..5e785c86027 100755 --- a/mysql-test/lib/v1/mysql-test-run.pl +++ b/mysql-test/lib/v1/mysql-test-run.pl @@ -3113,7 +3113,6 @@ sub install_db ($$) { mtr_add_arg($args, "--bootstrap"); mtr_add_arg($args, "--basedir=%s", $path_my_basedir); mtr_add_arg($args, "--datadir=%s", $data_dir); - mtr_add_arg($args, "--loose-skip-innodb"); mtr_add_arg($args, "--loose-skip-ndbcluster"); mtr_add_arg($args, "--tmpdir=."); mtr_add_arg($args, "--core-file"); diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index 90dde034e10..304f562d47d 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -1370,3 +1370,16 @@ 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; +# +# Test for bug #53820 "ALTER a MEDIUMINT column table causes full +# table copy". +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a INT, b MEDIUMINT); +INSERT INTO t1 VALUES (1, 1), (2, 2); +# The below ALTER should not copy table and so no rows should +# be shown as affected. +ALTER TABLE t1 CHANGE a id INT; +affected rows: 0 +info: Records: 0 Duplicates: 0 Warnings: 0 +DROP TABLE t1; diff --git a/mysql-test/r/archive.result b/mysql-test/r/archive.result index 685e1e5ba4b..028c8b32f87 100644 --- a/mysql-test/r/archive.result +++ b/mysql-test/r/archive.result @@ -12775,3 +12775,29 @@ a 1 2 DROP TABLE t1; +# +# Bug#45377: ARCHIVE tables aren't discoverable after OPTIMIZE +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a int) ENGINE=ARCHIVE; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=ARCHIVE DEFAULT CHARSET=latin1 +INSERT INTO t1 VALUES (1); +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +FLUSH TABLES; +INSERT INTO t1 VALUES (2); +SELECT * FROM t1 ORDER BY a; +a +1 +2 +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=ARCHIVE DEFAULT CHARSET=latin1 +DROP TABLE t1; diff --git a/mysql-test/r/handler_innodb.result b/mysql-test/r/handler_innodb.result index 08d2fc58e8a..121cfa89f1c 100644 --- a/mysql-test/r/handler_innodb.result +++ b/mysql-test/r/handler_innodb.result @@ -1710,3 +1710,23 @@ ERROR 42S02: Table 'test.t1' doesn't exist HANDLER t1 CLOSE; # Connection con51355 # Connection default +# +# Bug#54401 assert in Diagnostics_area::set_eof_status , HANDLER +# +DROP TABLE IF EXISTS t1, t2; +DROP FUNCTION IF EXISTS f1; +CREATE FUNCTION f1() RETURNS INTEGER +BEGIN +SELECT 1 FROM t2 INTO @a; +RETURN 1; +END| +SELECT f1(); +ERROR 42S02: Table 'test.t2' doesn't exist +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1); +HANDLER t1 OPEN; +HANDLER t1 READ FIRST WHERE f1() = 1; +ERROR 42S02: Table 'test.t2' doesn't exist +HANDLER t1 CLOSE; +DROP FUNCTION f1; +DROP TABLE t1; diff --git a/mysql-test/r/handler_myisam.result b/mysql-test/r/handler_myisam.result index 31bc828b0b9..fd08fd12f15 100644 --- a/mysql-test/r/handler_myisam.result +++ b/mysql-test/r/handler_myisam.result @@ -1707,6 +1707,26 @@ HANDLER t1 CLOSE; # Connection con51355 # Connection default # +# Bug#54401 assert in Diagnostics_area::set_eof_status , HANDLER +# +DROP TABLE IF EXISTS t1, t2; +DROP FUNCTION IF EXISTS f1; +CREATE FUNCTION f1() RETURNS INTEGER +BEGIN +SELECT 1 FROM t2 INTO @a; +RETURN 1; +END| +SELECT f1(); +ERROR 42S02: Table 'test.t2' doesn't exist +CREATE TABLE t1(a INT); +INSERT INTO t1 VALUES (1); +HANDLER t1 OPEN; +HANDLER t1 READ FIRST WHERE f1() = 1; +ERROR 42S02: Table 'test.t2' doesn't exist +HANDLER t1 CLOSE; +DROP FUNCTION f1; +DROP TABLE t1; +# # BUG #46456: HANDLER OPEN + TRUNCATE + DROP (temporary) TABLE, crash # CREATE TABLE t1 AS SELECT 1 AS f1; diff --git a/mysql-test/r/heap_hash.result b/mysql-test/r/heap_hash.result index 7cc76611fb8..e3a3e0e9740 100644 --- a/mysql-test/r/heap_hash.result +++ b/mysql-test/r/heap_hash.result @@ -382,3 +382,14 @@ INSERT INTO t1 VALUES('A ', 'A '); ERROR 23000: Duplicate entry 'A -A ' for key 'key1' DROP TABLE t1; End of 5.0 tests +# +# Bug #55472: Assertion failed in heap_rfirst function of hp_rfirst.c +# on DELETE statement +# +CREATE TABLE t1 (col_int_nokey INT, +col_int_key INT, +INDEX(col_int_key) USING HASH) ENGINE = HEAP; +INSERT INTO t1 (col_int_nokey, col_int_key) VALUES (3, 0), (4, 0), (3, 1); +DELETE FROM t1 WHERE col_int_nokey = 5 ORDER BY col_int_key LIMIT 2; +DROP TABLE t1; +End of 5.5 tests diff --git a/mysql-test/r/innodb_mysql_lock.result b/mysql-test/r/innodb_mysql_lock.result index 95adf712cb4..bf1c3a89f40 100644 --- a/mysql-test/r/innodb_mysql_lock.result +++ b/mysql-test/r/innodb_mysql_lock.result @@ -116,3 +116,35 @@ 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; +# +# Bug#49891 View DDL breaks REPEATABLE READ +# +DROP TABLE IF EXISTS t1, t2; +DROP VIEW IF EXISTS v2; +CREATE TABLE t1 ( f1 INTEGER ) ENGINE = innodb; +CREATE TABLE t2 ( f1 INTEGER ); +CREATE VIEW v1 AS SELECT 1 FROM t1; +# Connection con3 +LOCK TABLE t1 WRITE; +# Connection default +START TRANSACTION; +# Sending: +SELECT * FROM v1; +# Connection con2 +# Waiting for 'SELECT * FROM v1' to sync in. +# Sending: +ALTER VIEW v1 AS SELECT 2 FROM t2; +# Connection con3 +# Waiting for 'ALTER VIEW v1 AS SELECT 2 FROM t2' to sync in. +UNLOCK TABLES; +# Connection default; +# Reaping: SELECT * FROM v1 +1 +SELECT * FROM v1; +1 +COMMIT; +# Connection con2 +# Reaping: ALTER VIEW v1 AS SELECT 2 FROM t2 +# Connection default +DROP TABLE t1, t2; +DROP VIEW v1; diff --git a/mysql-test/r/innodb_mysql_sync.result b/mysql-test/r/innodb_mysql_sync.result index 0e75e62b13a..43a98829d4e 100644 --- a/mysql-test/r/innodb_mysql_sync.result +++ b/mysql-test/r/innodb_mysql_sync.result @@ -48,3 +48,21 @@ Warnings: Error 1146 Table 'test.t1' doesn't exist # Connection default SET DEBUG_SYNC= "RESET"; +# +# Bug#53757 assert in mysql_truncate_by_delete +# +DROP TABLE IF EXISTS t1, t2; +CREATE TABLE t1(a INT) Engine=InnoDB; +CREATE TABLE t2(id INT); +INSERT INTO t1 VALUES (1), (2); +INSERT INTO t2 VALUES(connection_id()); +SET DEBUG_SYNC= "open_and_process_table SIGNAL opening WAIT_FOR killed"; +# Sending: (not reaped since connection is killed later) +TRUNCATE t1; +SET DEBUG_SYNC= "now WAIT_FOR opening"; +SELECT ((@id := id) - id) FROM t2; +((@id := id) - id) +0 +KILL @id; +SET DEBUG_SYNC= "now SIGNAL killed"; +DROP TABLE t1, t2; diff --git a/mysql-test/r/lowercase_table2.result b/mysql-test/r/lowercase_table2.result index 26a151b55aa..caee7a7662b 100644 --- a/mysql-test/r/lowercase_table2.result +++ b/mysql-test/r/lowercase_table2.result @@ -56,6 +56,7 @@ CREATE DATABASE `TEST_$1`; SHOW DATABASES LIKE "TEST%"; Database (TEST%) TEST_$1 +test DROP DATABASE `test_$1`; CREATE TABLE T1 (a int) engine=innodb; INSERT INTO T1 VALUES (1); @@ -171,7 +172,7 @@ create table myUC (i int); select TABLE_SCHEMA,TABLE_NAME FROM information_schema.TABLES where TABLE_SCHEMA ='mysqltest_LC2'; TABLE_SCHEMA TABLE_NAME -mysqltest_LC2 myUC +mysqltest_lc2 myUC use test; drop database mysqltest_LC2; # End of 5.1 tests diff --git a/mysql-test/r/mdl_sync.result b/mysql-test/r/mdl_sync.result index 67d778211dd..0fd408b0208 100644 --- a/mysql-test/r/mdl_sync.result +++ b/mysql-test/r/mdl_sync.result @@ -2527,3 +2527,240 @@ 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; +# +# Tests for schema-scope locks +# +DROP DATABASE IF EXISTS db1; +DROP DATABASE IF EXISTS db2; +# Test 1: +# CREATE DATABASE blocks database DDL on the same database, but +# not database DDL on different databases. Tests X vs X lock. +# +# Connection default +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +# Sending: +CREATE DATABASE db1; +# Connection con2 +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +# Sending: +CREATE DATABASE db1; +# Connection con3 +CREATE DATABASE db2; +ALTER DATABASE db2 DEFAULT CHARACTER SET utf8; +DROP DATABASE db2; +SET DEBUG_SYNC= 'now SIGNAL blocked'; +# Connection default +# Reaping: CREATE DATABASE db1 +# Connection con2 +# Reaping: CREATE DATABASE db1 +ERROR HY000: Can't create database 'db1'; database exists +# Test 2: +# ALTER DATABASE blocks database DDL on the same database, but +# not database DDL on different databases. Tests X vs X lock. +# +# Connection default +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +# Sending: +ALTER DATABASE db1 DEFAULT CHARACTER SET utf8; +# Connection con2 +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +# Sending: +ALTER DATABASE db1 DEFAULT CHARACTER SET utf8; +# Connection con3 +CREATE DATABASE db2; +ALTER DATABASE db2 DEFAULT CHARACTER SET utf8; +DROP DATABASE db2; +SET DEBUG_SYNC= 'now SIGNAL blocked'; +# Connection default +# Reaping: ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 +# Connection con2 +# Reaping: ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 +# Connection default +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +# Sending: +ALTER DATABASE db1 DEFAULT CHARACTER SET utf8; +# Connection con2 +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +# Sending: +DROP DATABASE db1; +# Connection con3 +SET DEBUG_SYNC= 'now SIGNAL blocked'; +# Connection default +# Reaping: ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 +# Connection con2 +# Reaping: DROP DATABASE db1 +CREATE DATABASE db1; +# Test 3: +# Two ALTER..UPGRADE of the same database are mutually exclusive, but +# two ALTER..UPGRADE of different databases are not. Tests X vs X lock. +# +# Connection default +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +# Sending: +ALTER DATABASE `#mysql50#a-b-c` UPGRADE DATA DIRECTORY NAME; +# Connection con2 +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +# Sending: +ALTER DATABASE `#mysql50#a-b-c` UPGRADE DATA DIRECTORY NAME; +# Connection con3 +ALTER DATABASE `#mysql50#a-b-c-d` UPGRADE DATA DIRECTORY NAME; +SET DEBUG_SYNC= 'now SIGNAL blocked'; +# Connection default +# Reaping: ALTER DATABASE '#mysql50#a-b-c' UPGRADE DATA DIRECTORY NAME +# Connection con2 +# Reaping: ALTER DATABASE '#mysql50#a-b-c' UPGRADE DATA DIRECTORY NAME +ERROR 42000: Unknown database '#mysql50#a-b-c' +DROP DATABASE `a-b-c`; +DROP DATABASE `a-b-c-d`; +# Test 4: +# DROP DATABASE blocks database DDL on the same database, but +# not database DDL on different databases. Tests X vs X lock. +# +# Connection default +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +# Sending: +DROP DATABASE db1; +# Connection con2 +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +# Sending: +DROP DATABASE db1; +# Connection con3 +CREATE DATABASE db2; +ALTER DATABASE db2 DEFAULT CHARACTER SET utf8; +DROP DATABASE db2; +SET DEBUG_SYNC= 'now SIGNAL blocked'; +# Connection default +# Reaping: DROP DATABASE db1 +# Connection con2 +# Reaping: DROP DATABASE db1 +ERROR HY000: Can't drop database 'db1'; database doesn't exist +# Connection default +CREATE DATABASE db1; +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +# Sending: +DROP DATABASE db1; +# Connection con2 +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +# Sending: +ALTER DATABASE db1 DEFAULT CHARACTER SET utf8; +# Connection con3 +SET DEBUG_SYNC= 'now SIGNAL blocked'; +# Connection default +# Reaping: DROP DATABASE db1 +# Connection con2 +# Reaping: ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 +Got one of the listed errors +# Test 5: +# Locked database name prevents CREATE of tables in that database. +# Tests X vs IX lock. +# +# Connection default +CREATE DATABASE db1; +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +# Sending: +DROP DATABASE db1; +# Connection con2 +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +# Sending: +CREATE TABLE db1.t1 (a INT); +# Connection con3 +SET DEBUG_SYNC= 'now SIGNAL blocked'; +# Connection default +# Reaping: DROP DATABASE db1 +# Connection con2 +# Reaping: CREATE TABLE db1.t1 (a INT) +ERROR 42000: Unknown database 'db1' +# Test 6: +# Locked database name prevents RENAME of tables to/from that database. +# Tests X vs IX lock. +# +# Connection default +CREATE DATABASE db1; +CREATE TABLE db1.t1 (a INT); +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +# Sending: +DROP DATABASE db1; +# Connection con2 +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +# Sending: +RENAME TABLE db1.t1 TO test.t1; +# Connection con3 +SET DEBUG_SYNC= 'now SIGNAL blocked'; +# Connection default +# Reaping: DROP DATABASE db1 +# Connection con2 +# Reaping: RENAME TABLE db1.t1 TO test.t1 +Got one of the listed errors +# Connection default +CREATE DATABASE db1; +CREATE TABLE test.t2 (a INT); +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +# Sending: +DROP DATABASE db1; +# Connection con2 +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +# Sending: +RENAME TABLE test.t2 TO db1.t2; +# Connection con3 +SET DEBUG_SYNC= 'now SIGNAL blocked'; +# Connection default +# Reaping: DROP DATABASE db1 +# Connection con2 +# Reaping: RENAME TABLE test.t2 TO db1.t2 +Got one of the listed errors +DROP TABLE test.t2; +# Test 7: +# Locked database name prevents DROP of tables in that database. +# Tests X vs IX lock. +# +# Connection default +CREATE DATABASE db1; +CREATE TABLE db1.t1 (a INT); +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +# Sending: +DROP DATABASE db1; +# Connection con2 +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +# Sending: +DROP TABLE db1.t1; +# Connection con3 +SET DEBUG_SYNC= 'now SIGNAL blocked'; +# Connection default +# Reaping: DROP DATABASE db1 +# Connection con2 +# Reaping: DROP TABLE db1.t1 +ERROR 42S02: Unknown table 't1' +# Connection default +SET DEBUG_SYNC= 'RESET'; +# +# End of tests for schema-scope locks +# +# +# Tests of granted global S lock (FLUSH TABLE WITH READ LOCK) +# +CREATE DATABASE db1; +CREATE TABLE db1.t1(a INT); +# Connection default +FLUSH TABLE WITH READ LOCK; +# Connection con2 +CREATE TABLE db1.t2(a INT); +# Connection default +UNLOCK TABLES; +# Connection con2 +# Reaping CREATE TABLE db1.t2(a INT) +# Connection default +FLUSH TABLE WITH READ LOCK; +# Connection con2 +ALTER DATABASE db1 DEFAULT CHARACTER SET utf8; +# Connection default +UNLOCK TABLES; +# Connection con2 +# Reaping ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 +# Connection default +FLUSH TABLE WITH READ LOCK; +# Connection con2 +FLUSH TABLE WITH READ LOCK; +UNLOCK TABLES; +# Connection default +UNLOCK TABLES; +DROP DATABASE db1; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 87d4f75dc8d..f7f0cea3b19 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -1,3 +1,5 @@ +set global storage_engine=myisam; +set session storage_engine=myisam; drop table if exists t1,t2,t3,t4,t5,t6; drop database if exists mysqltest; create table t1 (a int not null primary key auto_increment, message char(20)); @@ -584,7 +586,9 @@ INSERT INTO t1 VALUES (1); INSERT INTO t2 VALUES (2); CREATE TEMPORARY TABLE t3 (c1 INT NOT NULL) ENGINE=MRG_MYISAM UNION=(t1,t2); SELECT * FROM t3; -ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +c1 +1 +2 CREATE TEMPORARY TABLE t4 (c1 INT NOT NULL); CREATE TEMPORARY TABLE t5 (c1 INT NOT NULL); INSERT INTO t4 VALUES (4); @@ -613,7 +617,9 @@ ERROR HY000: Unable to open underlying table which is differently defined or of drop table t3; create temporary table t3 (a int not null) ENGINE=MERGE UNION=(t1,t2); select * from t3; -ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +a +1 +2 drop table t3, t2, t1; # CREATE...SELECT is not implemented for MERGE tables. CREATE TEMPORARY TABLE t1 (c1 INT NOT NULL); @@ -1196,12 +1202,13 @@ ERROR HY000: Table 't4' was not locked with LOCK TABLES # it can even be used. CREATE TEMPORARY TABLE t4 LIKE t3; SHOW CREATE TABLE t4; -ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +Table Create Table +t4 CREATE TEMPORARY TABLE `t4` ( + `c1` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) INSERT INTO t4 VALUES (4); -ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist UNLOCK TABLES; INSERT INTO t4 VALUES (4); -ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist DROP TABLE t4; # # Rename child. @@ -1229,6 +1236,8 @@ c1 2 3 4 +4 +4 RENAME TABLE t2 TO t5; SELECT * FROM t3 ORDER BY c1; ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist @@ -1239,6 +1248,8 @@ c1 2 3 4 +4 +4 # # 3. Normal rename with locked tables. LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE; @@ -1248,6 +1259,8 @@ c1 2 3 4 +4 +4 RENAME TABLE t2 TO t5; ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction SELECT * FROM t3 ORDER BY c1; @@ -1256,6 +1269,8 @@ c1 2 3 4 +4 +4 RENAME TABLE t5 TO t2; ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction SELECT * FROM t3 ORDER BY c1; @@ -1264,6 +1279,8 @@ c1 2 3 4 +4 +4 UNLOCK TABLES; # # 4. Alter table rename. @@ -1277,6 +1294,8 @@ c1 2 3 4 +4 +4 # # 5. Alter table rename with locked tables. LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE; @@ -1293,6 +1312,8 @@ c1 2 3 4 +4 +4 # # Rename parent. # @@ -1304,6 +1325,8 @@ c1 2 3 4 +4 +4 RENAME TABLE t3 TO t5; ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction SELECT * FROM t3 ORDER BY c1; @@ -1312,6 +1335,8 @@ c1 2 3 4 +4 +4 RENAME TABLE t5 TO t3; ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction SELECT * FROM t3 ORDER BY c1; @@ -1320,6 +1345,8 @@ c1 2 3 4 +4 +4 # # 5. Alter table rename with locked tables. ALTER TABLE t3 RENAME TO t5; @@ -1335,6 +1362,8 @@ c1 2 3 4 +4 +4 DROP TABLE t1, t2, t3; # # Drop locked tables. @@ -2650,6 +2679,705 @@ test.t1 optimize Error Unable to open underlying table which is differently defi test.t1 optimize note The storage engine for the table doesn't support optimize DROP TABLE t1; # +# Bug#36171 - CREATE TEMPORARY TABLE and MERGE engine +# More tests with TEMPORARY MERGE table and permanent children. +# First without locked tables. +# +DROP TABLE IF EXISTS t1, t2, t3, t4, m1, m2; +# +CREATE TABLE t1 (c1 INT, c2 INT) ENGINE=MyISAM; +CREATE TABLE t2 (c1 INT, c2 INT) ENGINE=MyISAM; +CREATE TEMPORARY TABLE m1 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SHOW CREATE TABLE m1; +Table Create Table +m1 CREATE TEMPORARY TABLE `m1` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) +SELECT * FROM m1; +c1 c2 +INSERT INTO t1 VALUES (111, 121); +INSERT INTO m1 VALUES (211, 221); +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +SELECT * FROM t1; +c1 c2 +111 121 +SELECT * FROM t2; +c1 c2 +211 221 +# +ALTER TABLE m1 RENAME m2; +SHOW CREATE TABLE m2; +Table Create Table +m2 CREATE TEMPORARY TABLE `m2` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) +SELECT * FROM m2; +c1 c2 +111 121 +211 221 +# +CREATE TEMPORARY TABLE m1 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +ALTER TABLE m2 RENAME m1; +ERROR 42S01: Table 'm1' already exists +DROP TABLE m1; +ALTER TABLE m2 RENAME m1; +SHOW CREATE TABLE m1; +Table Create Table +m1 CREATE TEMPORARY TABLE `m1` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +# +ALTER TABLE m1 ADD COLUMN c3 INT; +INSERT INTO m1 VALUES (212, 222, 232); +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +SELECT * FROM m1; +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +ALTER TABLE t1 ADD COLUMN c3 INT; +ALTER TABLE t2 ADD COLUMN c3 INT; +INSERT INTO m1 VALUES (212, 222, 232); +SELECT * FROM m1; +c1 c2 c3 +111 121 NULL +211 221 NULL +212 222 232 +# +ALTER TABLE m1 DROP COLUMN c3; +INSERT INTO m1 VALUES (213, 223); +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +SELECT * FROM m1; +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +ALTER TABLE t1 DROP COLUMN c3; +ALTER TABLE t2 DROP COLUMN c3; +INSERT INTO m1 VALUES (213, 223); +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +212 222 +213 223 +# +CREATE TABLE t3 (c1 INT, c2 INT) ENGINE=MyISAM; +ALTER TABLE m1 UNION=(t1,t2,t3); +INSERT INTO m1 VALUES (311, 321); +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +212 222 +213 223 +311 321 +SELECT * FROM t1; +c1 c2 +111 121 +SELECT * FROM t2; +c1 c2 +211 221 +212 222 +213 223 +SELECT * FROM t3; +c1 c2 +311 321 +# +CREATE TEMPORARY TABLE t4 (c1 INT, c2 INT) ENGINE=MyISAM; +ALTER TABLE m1 UNION=(t1,t2,t3,t4); +INSERT INTO m1 VALUES (411, 421); +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +212 222 +213 223 +311 321 +411 421 +SELECT * FROM t1; +c1 c2 +111 121 +SELECT * FROM t2; +c1 c2 +211 221 +212 222 +213 223 +SELECT * FROM t3; +c1 c2 +311 321 +SELECT * FROM t4; +c1 c2 +411 421 +# +ALTER TABLE m1 ENGINE=MyISAM; +SHOW CREATE TABLE m1; +Table Create Table +m1 CREATE TEMPORARY TABLE `m1` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO m1 VALUES (511, 521); +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +212 222 +213 223 +311 321 +411 421 +511 521 +# +ALTER TABLE m1 ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +212 222 +213 223 +SELECT * FROM t1; +c1 c2 +111 121 +SELECT * FROM t2; +c1 c2 +211 221 +212 222 +213 223 +# +CREATE TEMPORARY TABLE t1 (c1 INT, c2 INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (611, 621); +SELECT * FROM m1; +c1 c2 +611 621 +211 221 +212 222 +213 223 +DROP TABLE t1; +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +212 222 +213 223 +# +# +SHOW CREATE TABLE m1; +Table Create Table +m1 CREATE TEMPORARY TABLE `m1` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) +# +CREATE TABLE m2 SELECT * FROM m1; +SHOW CREATE TABLE m2; +Table Create Table +m2 CREATE TABLE `m2` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM m2; +c1 c2 +111 121 +211 221 +212 222 +213 223 +DROP TABLE m2; +# +CREATE TEMPORARY TABLE m2 SELECT * FROM m1; +SHOW CREATE TABLE m2; +Table Create Table +m2 CREATE TEMPORARY TABLE `m2` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM m2; +c1 c2 +111 121 +211 221 +212 222 +213 223 +DROP TABLE m2; +# +CREATE TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) +INSERT_METHOD=LAST; +SELECT * FROM m2; +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +DROP TABLE m2; +# +CREATE TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) +INSERT_METHOD=LAST SELECT * FROM m1; +ERROR HY000: 'test.m2' is not BASE TABLE +# +CREATE TEMPORARY TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) +INSERT_METHOD=LAST SELECT * FROM m1; +ERROR HY000: 'test.m2' is not BASE TABLE +# +CREATE TABLE m2 LIKE m1; +SHOW CREATE TABLE m2; +Table Create Table +m2 CREATE TABLE `m2` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) +SELECT * FROM m2; +c1 c2 +111 121 +211 221 +212 222 +213 223 +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 c2 +111 121 +211 221 +212 222 +213 223 +111 121 +211 221 +212 222 +213 223 +DROP TABLE m2; +# +CREATE TEMPORARY TABLE m2 LIKE m1; +SHOW CREATE TABLE m2; +Table Create Table +m2 CREATE TEMPORARY TABLE `m2` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) +SELECT * FROM m2; +c1 c2 +111 121 +211 221 +212 222 +213 223 +111 121 +211 221 +212 222 +213 223 +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 c2 +111 121 +211 221 +212 222 +213 223 +111 121 +211 221 +212 222 +213 223 +111 121 +211 221 +212 222 +213 223 +111 121 +211 221 +212 222 +213 223 +DROP TABLE m2; +# +CREATE TEMPORARY TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) +INSERT_METHOD=LAST; +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 c2 +311 321 +411 421 +111 121 +211 221 +212 222 +213 223 +111 121 +211 221 +212 222 +213 223 +111 121 +211 221 +212 222 +213 223 +111 121 +211 221 +212 222 +213 223 +# +# +LOCK TABLE m1 WRITE, m2 WRITE; +SELECT * FROM m1,m2 WHERE m1.c1=m2.c1; +c1 c2 c1 c2 +111 121 111 121 +111 121 111 121 +111 121 111 121 +111 121 111 121 +211 221 211 221 +211 221 211 221 +211 221 211 221 +211 221 211 221 +212 222 212 222 +212 222 212 222 +212 222 212 222 +212 222 212 222 +213 223 213 223 +213 223 213 223 +213 223 213 223 +213 223 213 223 +111 121 111 121 +111 121 111 121 +111 121 111 121 +111 121 111 121 +211 221 211 221 +211 221 211 221 +211 221 211 221 +211 221 211 221 +212 222 212 222 +212 222 212 222 +212 222 212 222 +212 222 212 222 +213 223 213 223 +213 223 213 223 +213 223 213 223 +213 223 213 223 +111 121 111 121 +111 121 111 121 +111 121 111 121 +111 121 111 121 +211 221 211 221 +211 221 211 221 +211 221 211 221 +211 221 211 221 +212 222 212 222 +212 222 212 222 +212 222 212 222 +212 222 212 222 +213 223 213 223 +213 223 213 223 +213 223 213 223 +213 223 213 223 +111 121 111 121 +111 121 111 121 +111 121 111 121 +111 121 111 121 +211 221 211 221 +211 221 211 221 +211 221 211 221 +211 221 211 221 +212 222 212 222 +212 222 212 222 +212 222 212 222 +212 222 212 222 +213 223 213 223 +213 223 213 223 +213 223 213 223 +213 223 213 223 +UNLOCK TABLES; +DROP TABLE t1, t2, t3, t4, m1, m2; +# +# Bug#36171 - CREATE TEMPORARY TABLE and MERGE engine +# More tests with TEMPORARY MERGE table and permanent children. +# (continued) Now the same with locked table. +# +CREATE TABLE t1 (c1 INT, c2 INT) ENGINE=MyISAM; +CREATE TABLE t2 (c1 INT, c2 INT) ENGINE=MyISAM; +CREATE TEMPORARY TABLE m1 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SHOW CREATE TABLE m1; +Table Create Table +m1 CREATE TEMPORARY TABLE `m1` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) +SELECT * FROM m1; +c1 c2 +INSERT INTO t1 VALUES (111, 121); +INSERT INTO m1 VALUES (211, 221); +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +SELECT * FROM t1; +c1 c2 +111 121 +SELECT * FROM t2; +c1 c2 +211 221 +# +LOCK TABLE m1 WRITE, t1 WRITE, t2 WRITE; +# +ALTER TABLE m1 RENAME m2; +SHOW CREATE TABLE m2; +Table Create Table +m2 CREATE TEMPORARY TABLE `m2` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) +SELECT * FROM m2; +c1 c2 +111 121 +211 221 +# +CREATE TEMPORARY TABLE m1 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +ALTER TABLE m2 RENAME m1; +ERROR 42S01: Table 'm1' already exists +DROP TABLE m1; +ALTER TABLE m2 RENAME m1; +SHOW CREATE TABLE m1; +Table Create Table +m1 CREATE TEMPORARY TABLE `m1` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +# +ALTER TABLE m1 ADD COLUMN c3 INT; +INSERT INTO m1 VALUES (212, 222, 232); +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +SELECT * FROM m1; +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +ALTER TABLE t1 ADD COLUMN c3 INT; +ALTER TABLE t2 ADD COLUMN c3 INT; +INSERT INTO m1 VALUES (212, 222, 232); +SELECT * FROM m1; +c1 c2 c3 +111 121 NULL +211 221 NULL +212 222 232 +# +ALTER TABLE m1 DROP COLUMN c3; +INSERT INTO m1 VALUES (213, 223); +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +SELECT * FROM m1; +ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +ALTER TABLE t1 DROP COLUMN c3; +ALTER TABLE t2 DROP COLUMN c3; +INSERT INTO m1 VALUES (213, 223); +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +212 222 +213 223 +# +UNLOCK TABLES; +CREATE TABLE t3 (c1 INT, c2 INT) ENGINE=MyISAM; +ALTER TABLE m1 UNION=(t1,t2,t3); +LOCK TABLE m1 WRITE; +INSERT INTO m1 VALUES (311, 321); +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +212 222 +213 223 +311 321 +SELECT * FROM t1; +c1 c2 +111 121 +SELECT * FROM t2; +c1 c2 +211 221 +212 222 +213 223 +SELECT * FROM t3; +c1 c2 +311 321 +# +CREATE TEMPORARY TABLE t4 (c1 INT, c2 INT) ENGINE=MyISAM; +ALTER TABLE m1 UNION=(t1,t2,t3,t4); +INSERT INTO m1 VALUES (411, 421); +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +212 222 +213 223 +311 321 +411 421 +SELECT * FROM t1; +c1 c2 +111 121 +SELECT * FROM t2; +c1 c2 +211 221 +212 222 +213 223 +SELECT * FROM t3; +c1 c2 +311 321 +SELECT * FROM t4; +c1 c2 +411 421 +# +ALTER TABLE m1 ENGINE=MyISAM; +SHOW CREATE TABLE m1; +Table Create Table +m1 CREATE TEMPORARY TABLE `m1` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +INSERT INTO m1 VALUES (511, 521); +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +212 222 +213 223 +311 321 +411 421 +511 521 +# +ALTER TABLE m1 ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +212 222 +213 223 +SELECT * FROM t1; +c1 c2 +111 121 +SELECT * FROM t2; +c1 c2 +211 221 +212 222 +213 223 +# +CREATE TEMPORARY TABLE t1 (c1 INT, c2 INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (611, 621); +SELECT * FROM m1; +c1 c2 +611 621 +211 221 +212 222 +213 223 +DROP TABLE t1; +SELECT * FROM m1; +c1 c2 +111 121 +211 221 +212 222 +213 223 +# +# +SHOW CREATE TABLE m1; +Table Create Table +m1 CREATE TEMPORARY TABLE `m1` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) +CREATE TABLE m2 SELECT * FROM m1; +ERROR HY000: Table 'm2' was not locked with LOCK TABLES +# +CREATE TEMPORARY TABLE m2 SELECT * FROM m1; +SHOW CREATE TABLE m2; +Table Create Table +m2 CREATE TEMPORARY TABLE `m2` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SELECT * FROM m2; +c1 c2 +111 121 +211 221 +212 222 +213 223 +DROP TABLE m2; +# +CREATE TEMPORARY TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) +INSERT_METHOD=LAST; +SELECT * FROM m2; +c1 c2 +311 321 +411 421 +LOCK TABLE m1 WRITE, m2 WRITE; +UNLOCK TABLES; +DROP TABLE m2; +LOCK TABLE m1 WRITE; +# +# ER_TABLE_NOT_LOCKED is returned in ps-protocol +CREATE TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) +INSERT_METHOD=LAST SELECT * FROM m1; +Got one of the listed errors +# +CREATE TEMPORARY TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) +INSERT_METHOD=LAST SELECT * FROM m1; +ERROR HY000: 'test.m2' is not BASE TABLE +# +CREATE TEMPORARY TABLE m2 LIKE m1; +SHOW CREATE TABLE m2; +Table Create Table +m2 CREATE TEMPORARY TABLE `m2` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) +LOCK TABLE m1 WRITE, m2 WRITE; +SHOW CREATE TABLE m2; +Table Create Table +m2 CREATE TEMPORARY TABLE `m2` ( + `c1` int(11) DEFAULT NULL, + `c2` int(11) DEFAULT NULL +) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`) +SELECT * FROM m2; +c1 c2 +111 121 +211 221 +212 222 +213 223 +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 c2 +111 121 +211 221 +212 222 +213 223 +111 121 +211 221 +212 222 +213 223 +DROP TABLE m2; +# +CREATE TEMPORARY TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) +INSERT_METHOD=LAST; +LOCK TABLE m1 WRITE, m2 WRITE; +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 c2 +311 321 +411 421 +111 121 +211 221 +212 222 +213 223 +111 121 +211 221 +212 222 +213 223 +# +UNLOCK TABLES; +DROP TABLE t1, t2, t3, t4, m1, m2; +# # Bug47098 assert in MDL_context::destroy on HANDLER # <damaged merge table> OPEN # @@ -2745,4 +3473,106 @@ m2 CREATE TABLE `m2` ( `i` int(11) DEFAULT NULL ) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=FIRST UNION=(`t1`) drop tables m1, m2, t1; +# +# Test case for Bug#54811 "Assert in mysql_lock_have_duplicate()" +# Check that unique_table() works correctly for merge tables. +# +drop table if exists t1, t2, t3, m1, m2; +create table t1 (a int); +create table t2 (a int); +create table t3 (b int); +create view v1 as select * from t3,t1; +create table m1 (a int) engine=merge union (t1, t2) insert_method=last; +create table m2 (a int) engine=merge union (t1, t2) insert_method=first; +create temporary table tmp (b int); +insert into tmp (b) values (1); +insert into t1 (a) values (1); +insert into t3 (b) values (1); +insert into m1 (a) values ((select max(a) from m1)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +insert into m1 (a) values ((select max(a) from m2)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +insert into m1 (a) values ((select max(a) from t1)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +insert into m1 (a) values ((select max(a) from t2)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +insert into m1 (a) values ((select max(a) from t3, m1)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +insert into m1 (a) values ((select max(a) from t3, m2)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +insert into m1 (a) values ((select max(a) from t3, t1)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +insert into m1 (a) values ((select max(a) from t3, t2)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +insert into m1 (a) values ((select max(a) from tmp, m1)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +insert into m1 (a) values ((select max(a) from tmp, m2)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +insert into m1 (a) values ((select max(a) from tmp, t1)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +insert into m1 (a) values ((select max(a) from tmp, t2)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +insert into m1 (a) values ((select max(a) from v1)); +ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'm1'. +insert into m1 (a) values ((select max(a) from tmp, v1)); +ERROR HY000: The definition of table 'v1' prevents operation INSERT on table 'm1'. +update m1 set a = ((select max(a) from m1)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +update m1 set a = ((select max(a) from m2)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +update m1 set a = ((select max(a) from t1)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +update m1 set a = ((select max(a) from t2)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +update m1 set a = ((select max(a) from t3, m1)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +update m1 set a = ((select max(a) from t3, m2)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +update m1 set a = ((select max(a) from t3, t1)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +update m1 set a = ((select max(a) from t3, t2)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +update m1 set a = ((select max(a) from tmp, m1)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +update m1 set a = ((select max(a) from tmp, m2)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +update m1 set a = ((select max(a) from tmp, t1)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +update m1 set a = ((select max(a) from tmp, t2)); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +update m1 set a = ((select max(a) from v1)); +ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 'm1'. +update m1 set a = ((select max(a) from tmp, v1)); +ERROR HY000: The definition of table 'v1' prevents operation UPDATE on table 'm1'. +delete from m1 where a = (select max(a) from m1); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +delete from m1 where a = (select max(a) from m2); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +delete from m1 where a = (select max(a) from t1); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +delete from m1 where a = (select max(a) from t2); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +delete from m1 where a = (select max(a) from t3, m1); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +delete from m1 where a = (select max(a) from t3, m2); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +delete from m1 where a = (select max(a) from t3, t1); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +delete from m1 where a = (select max(a) from t3, t2); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +delete from m1 where a = (select max(a) from tmp, m1); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +delete from m1 where a = (select max(a) from tmp, m2); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +delete from m1 where a = (select max(a) from tmp, t1); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +delete from m1 where a = (select max(a) from tmp, t2); +ERROR HY000: You can't specify target table 'm1' for update in FROM clause +delete from m1 where a = (select max(a) from v1); +ERROR HY000: The definition of table 'v1' prevents operation DELETE on table 'm1'. +delete from m1 where a = (select max(a) from tmp, v1); +ERROR HY000: The definition of table 'v1' prevents operation DELETE on table 'm1'. +drop view v1; +drop temporary table tmp; +drop table t1, t2, t3, m1, m2; End of 6.0 tests diff --git a/mysql-test/r/merge_mmap.result b/mysql-test/r/merge_mmap.result new file mode 100644 index 00000000000..e8014259a4a --- /dev/null +++ b/mysql-test/r/merge_mmap.result @@ -0,0 +1,190 @@ +SET GLOBAL storage_engine = MyISAM; +SET SESSION storage_engine = MyISAM; +DROP TABLE IF EXISTS t1, t2, m1, m2; +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +CREATE TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 +1 +2 +3 +4 +1 +2 +3 +4 +SELECT * FROM t2; +c1 +2 +3 +4 +1 +2 +3 +4 +DROP TABLE m2, m1, t2, t1; +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TEMPORARY TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +CREATE TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 +1 +2 +3 +4 +1 +2 +3 +4 +DROP TABLE m2, m1, t2, t1; +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +CREATE TEMPORARY TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 +1 +2 +3 +4 +1 +2 +3 +4 +DROP TABLE m2, m1, t2, t1; +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TEMPORARY TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +CREATE TEMPORARY TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 +1 +2 +3 +4 +1 +2 +3 +4 +DROP TABLE m2, m1, t2, t1; +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +CREATE TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +LOCK TABLE m1 WRITE, m2 WRITE; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 +1 +2 +3 +4 +1 +2 +3 +4 +SELECT * FROM t2; +c1 +2 +3 +4 +1 +2 +3 +4 +UNLOCK TABLES; +DROP TABLE m2, m1, t2, t1; +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TEMPORARY TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +CREATE TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +LOCK TABLE m1 WRITE, m2 WRITE; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 +1 +2 +3 +4 +1 +2 +3 +4 +UNLOCK TABLES; +DROP TABLE m2, m1, t2, t1; +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +CREATE TEMPORARY TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +LOCK TABLE m1 WRITE, m2 WRITE; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 +1 +2 +3 +4 +1 +2 +3 +4 +UNLOCK TABLES; +DROP TABLE m2, m1, t2, t1; +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TEMPORARY TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +CREATE TEMPORARY TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) +INSERT_METHOD=LAST; +LOCK TABLE m1 WRITE, m2 WRITE; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +c1 +1 +2 +3 +4 +1 +2 +3 +4 +UNLOCK TABLES; +DROP TABLE m2, m1, t2, t1; +End of 6.0 tests diff --git a/mysql-test/r/partition_debug_sync.result b/mysql-test/r/partition_debug_sync.result index 5ab1044934b..0e3241cf88e 100644 --- a/mysql-test/r/partition_debug_sync.result +++ b/mysql-test/r/partition_debug_sync.result @@ -47,7 +47,7 @@ ENGINE = MYISAM PARTITION p1 VALUES LESS THAN (20), PARTITION p2 VALUES LESS THAN (100), PARTITION p3 VALUES LESS THAN MAXVALUE ) */; -SET DEBUG_SYNC= 'open_tables_acquire_upgradable_mdl SIGNAL removing_partitions WAIT_FOR waiting_for_alter'; +SET DEBUG_SYNC= 'alter_table_before_open_tables SIGNAL removing_partitions WAIT_FOR waiting_for_alter'; SET DEBUG_SYNC= 'alter_table_before_rename_result_table WAIT_FOR delete_done'; ALTER TABLE t2 REMOVE PARTITIONING; # Con default diff --git a/mysql-test/r/schema.result b/mysql-test/r/schema.result index 2919606d74a..853c3bcf575 100644 --- a/mysql-test/r/schema.result +++ b/mysql-test/r/schema.result @@ -16,19 +16,21 @@ drop schema foo; # Bug #48940 MDL deadlocks against mysql_rm_db # DROP SCHEMA IF EXISTS schema1; +DROP SCHEMA IF EXISTS schema2; # Connection default CREATE SCHEMA schema1; +CREATE SCHEMA schema2; CREATE TABLE schema1.t1 (a INT); SET autocommit= FALSE; INSERT INTO schema1.t1 VALUES (1); # Connection 2 DROP SCHEMA schema1; # Connection default -ALTER SCHEMA schema1 DEFAULT CHARACTER SET utf8; -Got one of the listed errors +ALTER SCHEMA schema2 DEFAULT CHARACTER SET utf8; SET autocommit= TRUE; # Connection 2 # Connection default +DROP SCHEMA schema2; # # Bug #49988 MDL deadlocks with mysql_create_db, reload_acl_and_cache # @@ -48,3 +50,48 @@ ERROR HY000: Can't execute the given command because you have active locked tabl UNLOCK TABLES; # Connection con2 # Connection default +# +# Bug#54360 Deadlock DROP/ALTER/CREATE DATABASE with open HANDLER +# +CREATE DATABASE db1; +CREATE TABLE db1.t1 (a INT); +INSERT INTO db1.t1 VALUES (1), (2); +# Connection con1 +HANDLER db1.t1 OPEN; +# Connection default +# Sending: +DROP DATABASE db1; +# Connection con2 +# Connection con1 +CREATE DATABASE db2; +ALTER DATABASE db2 DEFAULT CHARACTER SET utf8; +DROP DATABASE db2; +HANDLER t1 CLOSE; +# Connection default +# Reaping: DROP DATABASE db1 +# +# Tests for increased CREATE/ALTER/DROP DATABASE concurrency with +# database name locks. +# +DROP DATABASE IF EXISTS db1; +DROP DATABASE IF EXISTS db2; +# Connection default +CREATE DATABASE db1; +CREATE TABLE db1.t1 (id INT); +START TRANSACTION; +INSERT INTO db1.t1 VALUES (1); +# Connection 2 +# DROP DATABASE should block due to the active transaction +# Sending: +DROP DATABASE db1; +# Connection 3 +# But it should still be possible to CREATE/ALTER/DROP other databases. +CREATE DATABASE db2; +ALTER DATABASE db2 DEFAULT CHARACTER SET utf8; +DROP DATABASE db2; +# Connection default +# End the transaction so DROP DATABASE db1 can continue +COMMIT; +# Connection 2 +# Reaping: DROP DATABASE db1 +# Connection default; diff --git a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result index ef2277fef38..c1a75281e0e 100644 --- a/mysql-test/r/show_check.result +++ b/mysql-test/r/show_check.result @@ -1466,3 +1466,51 @@ t1 CREATE TABLE `t1` ( # Switching to connection 'default'. UNLOCK TABLES; DROP TABLE t1; +# +# Bug#54905 Connection with WRITE lock cannot ALTER table due to +# concurrent SHOW CREATE +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1(a INT); +# Connection con1 +LOCK TABLE t1 WRITE; +# Connection default +START TRANSACTION; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +# Connection con1 +ALTER TABLE t1 CHARACTER SET = utf8; +UNLOCK TABLES; +# Connection default +COMMIT; +DROP TABLE t1; +# +# Bug#55498 SHOW CREATE TRIGGER takes wrong type of metadata lock. +# +DROP TABLE IF EXISTS t1; +CREATE TABLE t1 (a INT); +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a = 1; +# Test 1: SHOW CREATE TRIGGER with WRITE locked table. +# Connection con1 +LOCK TABLE t1 WRITE; +# Connection default +SHOW CREATE TRIGGER t1_bi; +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +t1_bi CREATE DEFINER=`root`@`localhost` TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a = 1 utf8 utf8_general_ci latin1_swedish_ci +# Connection con1 +UNLOCK TABLES; +# Test 2: ALTER TABLE with SHOW CREATE TRIGGER in transaction +# Connection default +START TRANSACTION; +SHOW CREATE TRIGGER t1_bi; +Trigger sql_mode SQL Original Statement character_set_client collation_connection Database Collation +t1_bi CREATE DEFINER=`root`@`localhost` TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a = 1 utf8 utf8_general_ci latin1_swedish_ci +# Connection con1 +ALTER TABLE t1 CHARACTER SET = utf8; +# Connection default +COMMIT; +DROP TRIGGER t1_bi; +DROP TABLE t1; diff --git a/mysql-test/r/temp_table.result b/mysql-test/r/temp_table.result index ba6b9f81a2d..33f5c6b5165 100644 --- a/mysql-test/r/temp_table.result +++ b/mysql-test/r/temp_table.result @@ -210,4 +210,16 @@ UPDATE t1,t2 SET t1.a = t2.a; INSERT INTO t2 SELECT f1(); DROP TABLE t1,t2,t3; DROP FUNCTION f1; +# +# Bug #48067: A temp table with the same name as an existing table, +# makes drop database fail. +# +DROP TEMPORARY TABLE IF EXISTS bug48067.t1; +DROP DATABASE IF EXISTS bug48067; +CREATE DATABASE bug48067; +CREATE TABLE bug48067.t1 (c1 int); +INSERT INTO bug48067.t1 values (1); +CREATE TEMPORARY TABLE bug48067.t1 (c1 int); +DROP DATABASE bug48067; +DROP TEMPORARY table bug48067.t1; End of 5.1 tests diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result index b6ad1ff31bf..be81afe1a43 100644 --- a/mysql-test/r/variables.result +++ b/mysql-test/r/variables.result @@ -1677,3 +1677,25 @@ SET @@sql_quote_show_create = @sql_quote_show_create_saved; # End of Bug#34828. +# Make sure we can manipulate with autocommit in the +# along with other variables. +drop table if exists t1; +drop function if exists t1_max; +drop function if exists t1_min; +create table t1 (a int) engine=innodb; +insert into t1(a) values (0), (1); +create function t1_max() returns int return (select max(a) from t1); +create function t1_min() returns int return (select min(a) from t1); +select t1_min(); +t1_min() +0 +select t1_max(); +t1_max() +1 +set @@session.autocommit=t1_min(), @@session.autocommit=t1_max(), +@@session.autocommit=t1_min(), @@session.autocommit=t1_max(), +@@session.autocommit=t1_min(), @@session.autocommit=t1_max(); +# Cleanup. +drop table t1; +drop function t1_min; +drop function t1_max; diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index e1c1d6f4128..96b45f0d5bb 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -1955,15 +1955,15 @@ CHECK TABLE v1, v2, v3, v4, v5, v6; Table Op Msg_type Msg_text test.v1 check Error FUNCTION test.f1 does not exist test.v1 check Error View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -test.v1 check status Operation failed +test.v1 check error Corrupt test.v2 check status OK test.v3 check Error FUNCTION test.f1 does not exist test.v3 check Error View 'test.v3' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -test.v3 check status Operation failed +test.v3 check error Corrupt test.v4 check status OK test.v5 check Error FUNCTION test.f1 does not exist test.v5 check Error View 'test.v5' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them -test.v5 check status Operation failed +test.v5 check error Corrupt test.v6 check status OK create function f1 () returns int return (select max(col1) from t1); DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/innodb_bug52199.result b/mysql-test/suite/innodb/r/innodb_bug52199.result new file mode 100644 index 00000000000..7e8c1ee46e0 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug52199.result @@ -0,0 +1,5 @@ +CREATE TABLE bug52199 (a INT NOT NULL, +b CHAR(125) CHARACTER SET utf32 COLLATE utf32_bin NOT NULL +)ENGINE=InnoDB; +CREATE UNIQUE INDEX idx ON bug52199(a); +DROP TABLE bug52199; diff --git a/mysql-test/suite/innodb/r/innodb_bug54679.result b/mysql-test/suite/innodb/r/innodb_bug54679.result new file mode 100644 index 00000000000..948696fb31d --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_bug54679.result @@ -0,0 +1,88 @@ +SET GLOBAL innodb_file_format='Barracuda'; +SET GLOBAL innodb_file_per_table=ON; +SET innodb_strict_mode=ON; +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables +WHERE TABLE_NAME='bug54679'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +bug54679 Compressed row_format=COMPRESSED +ALTER TABLE bug54679 ADD COLUMN b INT; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables +WHERE TABLE_NAME='bug54679'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +bug54679 Compressed row_format=COMPRESSED +DROP TABLE bug54679; +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables +WHERE TABLE_NAME='bug54679'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +bug54679 Compact +ALTER TABLE bug54679 KEY_BLOCK_SIZE=1; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables +WHERE TABLE_NAME='bug54679'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +bug54679 Compressed KEY_BLOCK_SIZE=1 +ALTER TABLE bug54679 ROW_FORMAT=REDUNDANT; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +DROP TABLE bug54679; +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=REDUNDANT; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables +WHERE TABLE_NAME='bug54679'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +bug54679 Redundant row_format=REDUNDANT +ALTER TABLE bug54679 KEY_BLOCK_SIZE=2; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables +WHERE TABLE_NAME='bug54679'; +TABLE_NAME ROW_FORMAT CREATE_OPTIONS +bug54679 Compressed row_format=REDUNDANT KEY_BLOCK_SIZE=2 +SET GLOBAL innodb_file_format=Antelope; +ALTER TABLE bug54679 KEY_BLOCK_SIZE=4; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE bug54679 ROW_FORMAT=DYNAMIC; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope. +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. +Warning 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +DROP TABLE bug54679; +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +ERROR HY000: Can't create table 'test.bug54679' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope. +Error 1005 Can't create table 'test.bug54679' (errno: 1478) +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB; +SET GLOBAL innodb_file_format=Barracuda; +SET GLOBAL innodb_file_per_table=OFF; +ALTER TABLE bug54679 KEY_BLOCK_SIZE=4; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +ALTER TABLE bug54679 ROW_FORMAT=DYNAMIC; +ERROR HY000: Can't create table '#sql-temporary' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table. +Error 1005 Can't create table '#sql-temporary' (errno: 1478) +DROP TABLE bug54679; +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +ERROR HY000: Can't create table 'test.bug54679' (errno: 1478) +SHOW WARNINGS; +Level Code Message +Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table. +Error 1005 Can't create table 'test.bug54679' (errno: 1478) +SET GLOBAL innodb_file_per_table=ON; +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +DROP TABLE bug54679; diff --git a/mysql-test/suite/innodb/r/innodb_information_schema.result b/mysql-test/suite/innodb/r/innodb_information_schema.result index 1737dab2ff0..13de084bc09 100644 --- a/mysql-test/suite/innodb/r/innodb_information_schema.result +++ b/mysql-test/suite/innodb/r/innodb_information_schema.result @@ -42,21 +42,7 @@ 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_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 diff --git a/mysql-test/suite/innodb/t/innodb_bug52199.test b/mysql-test/suite/innodb/t/innodb_bug52199.test new file mode 100644 index 00000000000..0fec64ba243 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug52199.test @@ -0,0 +1,7 @@ +-- source include/have_innodb.inc + +CREATE TABLE bug52199 (a INT NOT NULL, +b CHAR(125) CHARACTER SET utf32 COLLATE utf32_bin NOT NULL +)ENGINE=InnoDB; +CREATE UNIQUE INDEX idx ON bug52199(a); +DROP TABLE bug52199; diff --git a/mysql-test/suite/innodb/t/innodb_bug54679.test b/mysql-test/suite/innodb/t/innodb_bug54679.test new file mode 100644 index 00000000000..c5e308acb5e --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_bug54679.test @@ -0,0 +1,101 @@ +# Test Bug #54679 alter table causes compressed row_format to revert to compact + +--source include/have_innodb.inc + +let $file_format=`select @@innodb_file_format`; +let $file_format_max=`select @@innodb_file_format_max`; +let $file_per_table=`select @@innodb_file_per_table`; +SET GLOBAL innodb_file_format='Barracuda'; +SET GLOBAL innodb_file_per_table=ON; +SET innodb_strict_mode=ON; + +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=COMPRESSED; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables +WHERE TABLE_NAME='bug54679'; + +# The ROW_FORMAT of the table should be preserved when it is not specified +# in ALTER TABLE. +ALTER TABLE bug54679 ADD COLUMN b INT; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables +WHERE TABLE_NAME='bug54679'; + +DROP TABLE bug54679; + +# Check that the ROW_FORMAT conversion to/from COMPRESSED works. + +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables +WHERE TABLE_NAME='bug54679'; + +# KEY_BLOCK_SIZE implies COMPRESSED. +ALTER TABLE bug54679 KEY_BLOCK_SIZE=1; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables +WHERE TABLE_NAME='bug54679'; + +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE bug54679 ROW_FORMAT=REDUNDANT; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +DROP TABLE bug54679; +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=REDUNDANT; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables +WHERE TABLE_NAME='bug54679'; + +ALTER TABLE bug54679 KEY_BLOCK_SIZE=2; +SELECT TABLE_NAME,ROW_FORMAT,CREATE_OPTIONS FROM information_schema.tables +WHERE TABLE_NAME='bug54679'; + +# This prevents other than REDUNDANT or COMPACT ROW_FORMAT for new tables. +SET GLOBAL innodb_file_format=Antelope; + +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE bug54679 KEY_BLOCK_SIZE=4; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE bug54679 ROW_FORMAT=DYNAMIC; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +DROP TABLE bug54679; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB; + +SET GLOBAL innodb_file_format=Barracuda; +# This will prevent ROW_FORMAT=COMPRESSED, because the system tablespace +# cannot be compressed. +SET GLOBAL innodb_file_per_table=OFF; + +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE bug54679 KEY_BLOCK_SIZE=4; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +ALTER TABLE bug54679 ROW_FORMAT=DYNAMIC; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +DROP TABLE bug54679; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +--error ER_CANT_CREATE_TABLE +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +--replace_regex /'[^']*test\.#sql-[0-9a-f_]*'/'#sql-temporary'/ +SHOW WARNINGS; +SET GLOBAL innodb_file_per_table=ON; +CREATE TABLE bug54679 (a INT) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; +DROP TABLE bug54679; + +# restore original values, quietly so the test does not fail if those +# defaults are changed +-- disable_query_log +EVAL SET GLOBAL innodb_file_format=$file_format; +EVAL SET GLOBAL innodb_file_format_max=$file_format_max; +EVAL SET GLOBAL innodb_file_per_table=$file_per_table; +-- enable_query_log diff --git a/mysql-test/suite/perfschema/r/server_init.result b/mysql-test/suite/perfschema/r/server_init.result index 70205c7f104..8c35425029e 100644 --- a/mysql-test/suite/perfschema/r/server_init.result +++ b/mysql-test/suite/perfschema/r/server_init.result @@ -40,18 +40,10 @@ where name like "wait/synch/cond/mysys/THR_COND_threads"; count(name) 1 select count(name) from MUTEX_INSTANCES -where name like "wait/synch/mutex/sql/LOCK_mysql_create_db"; -count(name) -1 -select count(name) from MUTEX_INSTANCES where name like "wait/synch/mutex/sql/LOCK_open"; count(name) 1 select count(name) from MUTEX_INSTANCES -where name like "wait/synch/mutex/sql/LOCK_lock_db"; -count(name) -1 -select count(name) from MUTEX_INSTANCES where name like "wait/synch/mutex/sql/LOCK_thread_count"; count(name) 1 diff --git a/mysql-test/suite/perfschema/t/server_init.test b/mysql-test/suite/perfschema/t/server_init.test index b0bbe7b1bae..2e19d2c843a 100644 --- a/mysql-test/suite/perfschema/t/server_init.test +++ b/mysql-test/suite/perfschema/t/server_init.test @@ -69,15 +69,9 @@ select count(name) from COND_INSTANCES # Verify that these global mutexes have been properly initilized in sql select count(name) from MUTEX_INSTANCES - where name like "wait/synch/mutex/sql/LOCK_mysql_create_db"; - -select count(name) from MUTEX_INSTANCES where name like "wait/synch/mutex/sql/LOCK_open"; select count(name) from MUTEX_INSTANCES - where name like "wait/synch/mutex/sql/LOCK_lock_db"; - -select count(name) from MUTEX_INSTANCES where name like "wait/synch/mutex/sql/LOCK_thread_count"; select count(name) from MUTEX_INSTANCES diff --git a/mysql-test/suite/rpl/r/rpl_conditional_comments.result b/mysql-test/suite/rpl/r/rpl_conditional_comments.result new file mode 100644 index 00000000000..f3de3e5eb70 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_conditional_comments.result @@ -0,0 +1,67 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +CREATE TABLE t1(c1 INT); +show binlog events from <binlog_start>; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query # # use `test`; CREATE TABLE t1(c1 INT) + +# Case 1: +# ------------------------------------------------------------------ +# In a statement, some CCs are applied while others are not. The CCs +# which are not applied on master will be binlogged as common comments. +/*!99999 --- */INSERT /*!INTO*/ /*!10000 t1 */ VALUES(10) /*!99999 ,(11)*/; +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`; /* 99999 --- */INSERT /*!INTO*/ /*!10000 t1 */ VALUES(10) /* 99999 ,(11)*/ +master-bin.000001 # Query # # COMMIT +Comparing tables master:test.t1 and slave:test.t1 + +# Case 2: +# ----------------------------------------------------------------- +# Verify whether it can be binlogged correctly when executing prepared +# statement. +PREPARE stmt FROM 'INSERT INTO /*!99999 blabla*/ t1 VALUES(60) /*!99999 ,(61)*/'; +EXECUTE stmt; +DROP TABLE t1; +CREATE TABLE t1(c1 INT); +EXECUTE stmt; +Comparing tables master:test.t1 and slave:test.t1 + +SET @value=62; +PREPARE stmt FROM 'INSERT INTO /*!99999 blabla */ t1 VALUES(?) /*!99999 ,(63)*/'; +EXECUTE stmt USING @value; +DROP TABLE t1; +CREATE TABLE t1(c1 INT); +EXECUTE stmt USING @value; +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`; INSERT INTO /* 99999 blabla*/ t1 VALUES(60) /* 99999 ,(61)*/ +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # use `test`; DROP TABLE t1 +master-bin.000001 # Query # # use `test`; CREATE TABLE t1(c1 INT) +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO /* 99999 blabla*/ t1 VALUES(60) /* 99999 ,(61)*/ +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO /* 99999 blabla */ t1 VALUES(62) /* 99999 ,(63)*/ +master-bin.000001 # Query # # COMMIT +master-bin.000001 # Query # # use `test`; DROP TABLE t1 +master-bin.000001 # Query # # use `test`; CREATE TABLE t1(c1 INT) +master-bin.000001 # Query # # BEGIN +master-bin.000001 # Query # # use `test`; INSERT INTO /* 99999 blabla */ t1 VALUES(62) /* 99999 ,(63)*/ +master-bin.000001 # Query # # COMMIT +Comparing tables master:test.t1 and slave:test.t1 + +# Case 3: +# ----------------------------------------------------------------- +# Verify it can restore the '!', if the it is an uncomplete conditional +# comments +SELECT c1 FROM /*!99999 t1 WHEREN; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '/*!99999 t1 WHEREN' at line 1 +DROP TABLE t1; diff --git a/mysql-test/suite/rpl/r/rpl_packet.result b/mysql-test/suite/rpl/r/rpl_packet.result index 0a9495751fe..1ec9259a1fb 100644 --- a/mysql-test/suite/rpl/r/rpl_packet.result +++ b/mysql-test/suite/rpl/r/rpl_packet.result @@ -49,6 +49,14 @@ Slave_IO_Running = No (expect No) SELECT "Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master'" AS Last_IO_Error; Last_IO_Error Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master' +STOP SLAVE; +RESET SLAVE; +RESET MASTER; +SET @max_allowed_packet_0= @@session.max_allowed_packet; +SHOW BINLOG EVENTS; +SET @max_allowed_packet_1= @@session.max_allowed_packet; +SHOW BINLOG EVENTS; +SET @max_allowed_packet_2= @@session.max_allowed_packet; ==== clean up ==== DROP TABLE t1; SET @@global.max_allowed_packet= 1024; diff --git a/mysql-test/suite/rpl/r/rpl_row_implicit_commit_binlog.result b/mysql-test/suite/rpl/r/rpl_row_implicit_commit_binlog.result index 896ba90b865..459dc83e01d 100644 --- a/mysql-test/suite/rpl/r/rpl_row_implicit_commit_binlog.result +++ b/mysql-test/suite/rpl/r/rpl_row_implicit_commit_binlog.result @@ -165,10 +165,6 @@ master-bin.000001 # Table_map # # table_id: # (test.tt_1) master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Query # # use `test`; SET PASSWORD FOR 'user'@'localhost'='*D8DECEC305209EEFEC43008E1D420E1AA06B19E0' -master-bin.000001 # Query # # BEGIN -master-bin.000001 # Table_map # # table_id: # (mysql.user) -master-bin.000001 # Update_rows # # table_id: # flags: STMT_END_F -master-bin.000001 # Query # # COMMIT -e-e-e-e-e-e-e-e-e-e-e- >> << -e-e-e-e-e-e-e-e-e-e-e- -b-b-b-b-b-b-b-b-b-b-b- >> << -b-b-b-b-b-b-b-b-b-b-b- diff --git a/mysql-test/suite/rpl/t/rpl_conditional_comments.test b/mysql-test/suite/rpl/t/rpl_conditional_comments.test new file mode 100644 index 00000000000..14251d5eb37 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_conditional_comments.test @@ -0,0 +1,74 @@ +############################################################################### +# After the patch for BUG#49124: +# - Use ' ' instead of '!' in the conditional comments which are not applied on +# master. So they become common comments and will not be applied on slave. +# +# - Example: +# 'INSERT INTO t1 VALUES (1) /*!10000, (2)*/ /*!99999 ,(3)*/ +# will be binlogged as +# 'INSERT INTO t1 VALUES (1) /*!10000, (2)*/ /* 99999 ,(3)*/'. +############################################################################### +source include/master-slave.inc; +source include/have_binlog_format_statement.inc; + +CREATE TABLE t1(c1 INT); +source include/show_binlog_events.inc; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); + +--echo +--echo # Case 1: +--echo # ------------------------------------------------------------------ +--echo # In a statement, some CCs are applied while others are not. The CCs +--echo # which are not applied on master will be binlogged as common comments. + +/*!99999 --- */INSERT /*!INTO*/ /*!10000 t1 */ VALUES(10) /*!99999 ,(11)*/; + +source include/show_binlog_events.inc; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); +sync_slave_with_master; +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; + +--echo +--echo # Case 2: +--echo # ----------------------------------------------------------------- +--echo # Verify whether it can be binlogged correctly when executing prepared +--echo # statement. +PREPARE stmt FROM 'INSERT INTO /*!99999 blabla*/ t1 VALUES(60) /*!99999 ,(61)*/'; +EXECUTE stmt; +DROP TABLE t1; +CREATE TABLE t1(c1 INT); +EXECUTE stmt; + +sync_slave_with_master; +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; + +--echo +SET @value=62; +PREPARE stmt FROM 'INSERT INTO /*!99999 blabla */ t1 VALUES(?) /*!99999 ,(63)*/'; +EXECUTE stmt USING @value; +DROP TABLE t1; +CREATE TABLE t1(c1 INT); +EXECUTE stmt USING @value; + +source include/show_binlog_events.inc; +let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1); + +sync_slave_with_master; +let $diff_table_1=master:test.t1; +let $diff_table_2=slave:test.t1; +source include/diff_tables.inc; + +--echo +--echo # Case 3: +--echo # ----------------------------------------------------------------- +--echo # Verify it can restore the '!', if the it is an uncomplete conditional +--echo # comments +--error 1064 +SELECT c1 FROM /*!99999 t1 WHEREN; + +DROP TABLE t1; +source include/master-slave-end.inc; diff --git a/mysql-test/suite/rpl/t/rpl_packet.test b/mysql-test/suite/rpl/t/rpl_packet.test index 61a1ad9d987..38b868cb59d 100644 --- a/mysql-test/suite/rpl/t/rpl_packet.test +++ b/mysql-test/suite/rpl/t/rpl_packet.test @@ -1,7 +1,12 @@ +# ==== Purpose ==== # # Check replication protocol packet size handling -# Bug#19402 SQL close to the size of the max_allowed_packet fails on slave # +# ==== Related bugs ==== +# Bug#19402 SQL close to the size of the max_allowed_packet fails on slave +# BUG#23755: Replicated event larger that max_allowed_packet infinitely re-transmits +# BUG#42914: No LAST_IO_ERROR for max_allowed_packet errors +# BUG#55322: SHOW BINLOG EVENTS increases @@SESSION.MAX_ALLOWED_PACKET # max-out size db name source include/master-slave.inc; @@ -114,6 +119,38 @@ let $slave_io_running= query_get_value(SHOW SLAVE STATUS, Slave_IO_Running, 1); let $last_io_error= query_get_value(SHOW SLAVE STATUS, Last_IO_Error, 1); eval SELECT "$last_io_error" AS Last_IO_Error; +# Remove the bad binlog and clear error status on slave. +STOP SLAVE; +RESET SLAVE; +--connection master +RESET MASTER; + + +# +# BUG#55322: SHOW BINLOG EVENTS increases @@SESSION.MAX_ALLOWED_PACKET +# +# In BUG#55322, @@session.max_allowed_packet increased each time SHOW +# BINLOG EVENTS was issued. To verify that this bug is fixed, we +# execute SHOW BINLOG EVENTS twice and check that max_allowed_packet +# never changes. We turn off the result log because we don't care +# about the contents of the binlog. + +--disable_result_log +SET @max_allowed_packet_0= @@session.max_allowed_packet; +SHOW BINLOG EVENTS; +SET @max_allowed_packet_1= @@session.max_allowed_packet; +SHOW BINLOG EVENTS; +SET @max_allowed_packet_2= @@session.max_allowed_packet; +--enable_result_log +if (`SELECT NOT(@max_allowed_packet_0 = @max_allowed_packet_1 AND @max_allowed_packet_1 = @max_allowed_packet_2)`) +{ + --echo ERROR: max_allowed_packet changed after executing SHOW BINLOG EVENTS + --source include/show_rpl_debug_info.inc + SELECT @max_allowed_packet_0, @max_allowed_packet_1, @max_allowed_packet_2; + --die @max_allowed_packet changed after executing SHOW BINLOG EVENTS +} + + --echo ==== clean up ==== connection master; DROP TABLE t1; diff --git a/mysql-test/suite/rpl/t/rpl_sync-slave.opt b/mysql-test/suite/rpl/t/rpl_sync-slave.opt index 7d6147ed59a..fba451a5b3e 100644 --- a/mysql-test/suite/rpl/t/rpl_sync-slave.opt +++ b/mysql-test/suite/rpl/t/rpl_sync-slave.opt @@ -1 +1 @@ ---sync-relay-log-info=1 --relay-log-recovery=1 --innodb_file_format_check='ON' --default-storage-engine=MyISAM --innodb-file-per-table=0 +--sync-relay-log-info=1 --relay-log-recovery=1 --innodb_file_format_check=1 --default-storage-engine=MyISAM --innodb-file-per-table=0 diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index d7f7a12cbf8..5b5fdf50c16 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -1128,3 +1128,19 @@ INSERT INTO t1 VALUES (1), (2); ALTER TABLE t1 ADD COLUMN (f1 INT), ADD COLUMN (f2 INT), ADD KEY f2k(f2); DROP TABLE t1; + +--echo # +--echo # Test for bug #53820 "ALTER a MEDIUMINT column table causes full +--echo # table copy". +--echo # +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings +CREATE TABLE t1 (a INT, b MEDIUMINT); +INSERT INTO t1 VALUES (1, 1), (2, 2); +--echo # The below ALTER should not copy table and so no rows should +--echo # be shown as affected. +--enable_info +ALTER TABLE t1 CHANGE a id INT; +--disable_info +DROP TABLE t1; diff --git a/mysql-test/t/archive.test b/mysql-test/t/archive.test index a3665e5f455..c3a080612a9 100644 --- a/mysql-test/t/archive.test +++ b/mysql-test/t/archive.test @@ -1701,3 +1701,24 @@ SELECT * FROM t1; REPAIR TABLE t1 EXTENDED; SELECT * FROM t1; DROP TABLE t1; + + +--echo # +--echo # Bug#45377: ARCHIVE tables aren't discoverable after OPTIMIZE +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (a int) ENGINE=ARCHIVE; +SHOW CREATE TABLE t1; +INSERT INTO t1 VALUES (1); +OPTIMIZE TABLE t1; +let $MYSQLD_DATADIR= `select @@datadir`; +remove_file $MYSQLD_DATADIR/test/t1.frm; +FLUSH TABLES; +INSERT INTO t1 VALUES (2); +SELECT * FROM t1 ORDER BY a; +SHOW CREATE TABLE t1; +DROP TABLE t1; diff --git a/mysql-test/t/heap_hash.test b/mysql-test/t/heap_hash.test index 1e3491f89a9..748347021fc 100644 --- a/mysql-test/t/heap_hash.test +++ b/mysql-test/t/heap_hash.test @@ -284,3 +284,20 @@ INSERT INTO t1 VALUES('A ', 'A '); DROP TABLE t1; --echo End of 5.0 tests + +--echo # +--echo # Bug #55472: Assertion failed in heap_rfirst function of hp_rfirst.c +--echo # on DELETE statement +--echo # + +CREATE TABLE t1 (col_int_nokey INT, + col_int_key INT, + INDEX(col_int_key) USING HASH) ENGINE = HEAP; +INSERT INTO t1 (col_int_nokey, col_int_key) VALUES (3, 0), (4, 0), (3, 1); + +DELETE FROM t1 WHERE col_int_nokey = 5 ORDER BY col_int_key LIMIT 2; + +DROP TABLE t1; + +--echo End of 5.5 tests + diff --git a/mysql-test/t/innodb_mysql_lock.test b/mysql-test/t/innodb_mysql_lock.test index 36d09b4c411..c8ece729b19 100644 --- a/mysql-test/t/innodb_mysql_lock.test +++ b/mysql-test/t/innodb_mysql_lock.test @@ -209,6 +209,74 @@ disconnect con1; DROP TABLE t1; +--echo # +--echo # Bug#49891 View DDL breaks REPEATABLE READ +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +DROP VIEW IF EXISTS v2; +--enable_warnings + +CREATE TABLE t1 ( f1 INTEGER ) ENGINE = innodb; +CREATE TABLE t2 ( f1 INTEGER ); +CREATE VIEW v1 AS SELECT 1 FROM t1; + +connect (con2, localhost, root); +connect (con3, localhost, root); + +--echo # Connection con3 +connection con3; +LOCK TABLE t1 WRITE; + +--echo # Connection default +connection default; +START TRANSACTION; +# This should block due to t1 being locked. +--echo # Sending: +--send SELECT * FROM v1 + +--echo # Connection con2 +connection con2; +--echo # Waiting for 'SELECT * FROM v1' to sync in. +let $wait_condition= + SELECT COUNT(*) = 1 FROM information_schema.processlist + WHERE state = "Waiting for table" AND info = "SELECT * FROM v1"; +--source include/wait_condition.inc +# This should block due to v1 being locked. +--echo # Sending: +--send ALTER VIEW v1 AS SELECT 2 FROM t2 + +--echo # Connection con3 +connection con3; +--echo # Waiting for 'ALTER VIEW v1 AS SELECT 2 FROM t2' to sync in. +let $wait_condition= + SELECT COUNT(*) = 1 FROM information_schema.processlist + WHERE state = "Waiting for table" AND info = "ALTER VIEW v1 AS SELECT 2 FROM t2"; +--source include/wait_condition.inc +# Unlock t1 allowing SELECT * FROM v1 to proceed. +UNLOCK TABLES; + +--echo # Connection default; +connection default; +--echo # Reaping: SELECT * FROM v1 +--reap +SELECT * FROM v1; +COMMIT; + +--echo # Connection con2 +connection con2; +--echo # Reaping: ALTER VIEW v1 AS SELECT 2 FROM t2 +--reap + +--echo # Connection default +connection default; +DROP TABLE t1, t2; +DROP VIEW v1; +disconnect con2; +disconnect con3; + + # 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_sync.test b/mysql-test/t/innodb_mysql_sync.test index ee92ee9f52e..07f75afec40 100644 --- a/mysql-test/t/innodb_mysql_sync.test +++ b/mysql-test/t/innodb_mysql_sync.test @@ -80,6 +80,32 @@ disconnect con1; SET DEBUG_SYNC= "RESET"; +--echo # +--echo # Bug#53757 assert in mysql_truncate_by_delete +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1, t2; +--enable_warnings + +CREATE TABLE t1(a INT) Engine=InnoDB; +CREATE TABLE t2(id INT); +INSERT INTO t1 VALUES (1), (2); + +connect (con1, localhost, root); +INSERT INTO t2 VALUES(connection_id()); +SET DEBUG_SYNC= "open_and_process_table SIGNAL opening WAIT_FOR killed"; +--echo # Sending: (not reaped since connection is killed later) +--send TRUNCATE t1 + +connection default; +SET DEBUG_SYNC= "now WAIT_FOR opening"; +SELECT ((@id := id) - id) FROM t2; +KILL @id; +SET DEBUG_SYNC= "now SIGNAL killed"; +DROP TABLE t1, t2; + + # 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/mdl_sync.test b/mysql-test/t/mdl_sync.test index 19f9b396087..6b721ace07f 100644 --- a/mysql-test/t/mdl_sync.test +++ b/mysql-test/t/mdl_sync.test @@ -3705,6 +3705,481 @@ DROP TABLE t1; disconnect con1; +--echo # +--echo # Tests for schema-scope locks +--echo # + +--disable_warnings +DROP DATABASE IF EXISTS db1; +DROP DATABASE IF EXISTS db2; +--enable_warnings + +connect (con2, localhost, root); +connect (con3, localhost, root); + +--echo # Test 1: +--echo # CREATE DATABASE blocks database DDL on the same database, but +--echo # not database DDL on different databases. Tests X vs X lock. +--echo # + +--echo # Connection default +connection default; +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +--echo # Sending: +--send CREATE DATABASE db1 + +--echo # Connection con2 +connection con2; +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +--echo # Sending: +# This should block. +--send CREATE DATABASE db1 + +--echo # Connection con3 +connection con3; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for table' AND info='CREATE DATABASE db1'; +--source include/wait_condition.inc +# This should not block. +CREATE DATABASE db2; +ALTER DATABASE db2 DEFAULT CHARACTER SET utf8; +DROP DATABASE db2; +SET DEBUG_SYNC= 'now SIGNAL blocked'; + +--echo # Connection default +connection default; +--echo # Reaping: CREATE DATABASE db1 +--reap + +--echo # Connection con2 +connection con2; +--echo # Reaping: CREATE DATABASE db1 +--error ER_DB_CREATE_EXISTS +--reap + +--echo # Test 2: +--echo # ALTER DATABASE blocks database DDL on the same database, but +--echo # not database DDL on different databases. Tests X vs X lock. +--echo # + +--echo # Connection default +connection default; +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +--echo # Sending: +--send ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 + +--echo # Connection con2 +connection con2; +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +--echo # Sending: +# This should block. +--send ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 + +--echo # Connection con3 +connection con3; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for table' + AND info='ALTER DATABASE db1 DEFAULT CHARACTER SET utf8'; +--source include/wait_condition.inc +# This should not block. +CREATE DATABASE db2; +ALTER DATABASE db2 DEFAULT CHARACTER SET utf8; +DROP DATABASE db2; +SET DEBUG_SYNC= 'now SIGNAL blocked'; + +--echo # Connection default +connection default; +--echo # Reaping: ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 +--reap + +--echo # Connection con2 +connection con2; +--echo # Reaping: ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 +--reap + +--echo # Connection default +connection default; +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +--echo # Sending: +--send ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 + +--echo # Connection con2 +connection con2; +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +--echo # Sending: +# This should also block. +--send DROP DATABASE db1 + +--echo # Connection con3 +connection con3; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for table' AND info='DROP DATABASE db1'; +--source include/wait_condition.inc +SET DEBUG_SYNC= 'now SIGNAL blocked'; + +--echo # Connection default +connection default; +--echo # Reaping: ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 +--reap + +--echo # Connection con2 +connection con2; +--echo # Reaping: DROP DATABASE db1 +--reap +# Recreate the database +CREATE DATABASE db1; + +--echo # Test 3: +--echo # Two ALTER..UPGRADE of the same database are mutually exclusive, but +--echo # two ALTER..UPGRADE of different databases are not. Tests X vs X lock. +--echo # + +let $MYSQLD_DATADIR= `select @@datadir`; +# Manually make a 5.0 database from the template +--mkdir $MYSQLD_DATADIR/a-b-c +--copy_file $MYSQLD_DATADIR/db1/db.opt $MYSQLD_DATADIR/a-b-c/db.opt +--mkdir $MYSQLD_DATADIR/a-b-c-d +--copy_file $MYSQLD_DATADIR/db1/db.opt $MYSQLD_DATADIR/a-b-c-d/db.opt + +--echo # Connection default +connection default; +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +--echo # Sending: +--send ALTER DATABASE `#mysql50#a-b-c` UPGRADE DATA DIRECTORY NAME + +--echo # Connection con2 +connection con2; +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +--echo # Sending: +# This should block. +--send ALTER DATABASE `#mysql50#a-b-c` UPGRADE DATA DIRECTORY NAME + +--echo # Connection con3 +connection con3; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for table' + AND info='ALTER DATABASE `#mysql50#a-b-c` UPGRADE DATA DIRECTORY NAME'; +--source include/wait_condition.inc +# This should not block. +ALTER DATABASE `#mysql50#a-b-c-d` UPGRADE DATA DIRECTORY NAME; +SET DEBUG_SYNC= 'now SIGNAL blocked'; + +--echo # Connection default +connection default; +--echo # Reaping: ALTER DATABASE '#mysql50#a-b-c' UPGRADE DATA DIRECTORY NAME +--reap + +--echo # Connection con2 +connection con2; +--echo # Reaping: ALTER DATABASE '#mysql50#a-b-c' UPGRADE DATA DIRECTORY NAME +--error ER_BAD_DB_ERROR +--reap +DROP DATABASE `a-b-c`; +DROP DATABASE `a-b-c-d`; + +--echo # Test 4: +--echo # DROP DATABASE blocks database DDL on the same database, but +--echo # not database DDL on different databases. Tests X vs X lock. +--echo # + +--echo # Connection default +connection default; +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +--echo # Sending: +--send DROP DATABASE db1 + +--echo # Connection con2 +connection con2; +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +--echo # Sending: +# This should block. +--send DROP DATABASE db1 + +--echo # Connection con3 +connection con3; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for table' AND info='DROP DATABASE db1'; +--source include/wait_condition.inc +# This should not block. +CREATE DATABASE db2; +ALTER DATABASE db2 DEFAULT CHARACTER SET utf8; +DROP DATABASE db2; +SET DEBUG_SYNC= 'now SIGNAL blocked'; + +--echo # Connection default +connection default; +--echo # Reaping: DROP DATABASE db1 +--reap + +--echo # Connection con2 +connection con2; +--echo # Reaping: DROP DATABASE db1 +--error ER_DB_DROP_EXISTS +--reap + +--echo # Connection default +connection default; +CREATE DATABASE db1; +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +--echo # Sending: +--send DROP DATABASE db1 + +--echo # Connection con2 +connection con2; +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +--echo # Sending: +# This should also block. +--send ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 + +--echo # Connection con3 +connection con3; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for table' + AND info='ALTER DATABASE db1 DEFAULT CHARACTER SET utf8'; +--source include/wait_condition.inc +SET DEBUG_SYNC= 'now SIGNAL blocked'; + +--echo # Connection default +connection default; +--echo # Reaping: DROP DATABASE db1 +--reap + +--echo # Connection con2 +connection con2; +--echo # Reaping: ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 +--error 1,1 # Wrong error pending followup patch for bug#54360 +--reap + + +--echo # Test 5: +--echo # Locked database name prevents CREATE of tables in that database. +--echo # Tests X vs IX lock. +--echo # + +--echo # Connection default +connection default; +CREATE DATABASE db1; +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +--echo # Sending: +--send DROP DATABASE db1 + +--echo # Connection con2 +connection con2; +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +--echo # Sending: +# This should block. +--send CREATE TABLE db1.t1 (a INT) + +--echo # Connection con3 +connection con3; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for table' AND info='CREATE TABLE db1.t1 (a INT)'; +--source include/wait_condition.inc +SET DEBUG_SYNC= 'now SIGNAL blocked'; + +--echo # Connection default +connection default; +--echo # Reaping: DROP DATABASE db1 +--reap + +--echo # Connection con2 +connection con2; +--echo # Reaping: CREATE TABLE db1.t1 (a INT) +--error ER_BAD_DB_ERROR +--reap + +--echo # Test 6: +--echo # Locked database name prevents RENAME of tables to/from that database. +--echo # Tests X vs IX lock. +--echo # + +--echo # Connection default +connection default; +CREATE DATABASE db1; +CREATE TABLE db1.t1 (a INT); +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +--echo # Sending: +--send DROP DATABASE db1 + +--echo # Connection con2 +connection con2; +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +--echo # Sending: +# This should block. +--send RENAME TABLE db1.t1 TO test.t1 + +--echo # Connection con3 +connection con3; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for table' AND info='RENAME TABLE db1.t1 TO test.t1'; +--source include/wait_condition.inc +SET DEBUG_SYNC= 'now SIGNAL blocked'; + +--echo # Connection default +connection default; +--echo # Reaping: DROP DATABASE db1 +--reap + +--echo # Connection con2 +connection con2; +--echo # Reaping: RENAME TABLE db1.t1 TO test.t1 +--error ER_FILE_NOT_FOUND, ER_FILE_NOT_FOUND +--reap + +--echo # Connection default +connection default; +CREATE DATABASE db1; +CREATE TABLE test.t2 (a INT); +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +--echo # Sending: +--send DROP DATABASE db1 + +--echo # Connection con2 +connection con2; +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +--echo # Sending: +# This should block. +--send RENAME TABLE test.t2 TO db1.t2 + +--echo # Connection con3 +connection con3; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for table' AND info='RENAME TABLE test.t2 TO db1.t2'; +--source include/wait_condition.inc +SET DEBUG_SYNC= 'now SIGNAL blocked'; + +--echo # Connection default +connection default; +--echo # Reaping: DROP DATABASE db1 +--reap + +--echo # Connection con2 +connection con2; +--echo # Reaping: RENAME TABLE test.t2 TO db1.t2 +--error 7, 7 # Wrong error pending followup patch for bug#54360 +--reap +DROP TABLE test.t2; + + +--echo # Test 7: +--echo # Locked database name prevents DROP of tables in that database. +--echo # Tests X vs IX lock. +--echo # + +--echo # Connection default +connection default; +CREATE DATABASE db1; +CREATE TABLE db1.t1 (a INT); +SET DEBUG_SYNC= 'after_wait_locked_schema_name SIGNAL locked WAIT_FOR blocked'; +--echo # Sending: +--send DROP DATABASE db1 + +--echo # Connection con2 +connection con2; +SET DEBUG_SYNC= 'now WAIT_FOR locked'; +--echo # Sending: +# This should block. +--send DROP TABLE db1.t1 + +--echo # Connection con3 +connection con3; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for table' AND info='DROP TABLE db1.t1'; +--source include/wait_condition.inc +SET DEBUG_SYNC= 'now SIGNAL blocked'; + +--echo # Connection default +connection default; +--echo # Reaping: DROP DATABASE db1 +--reap + +--echo # Connection con2 +connection con2; +--echo # Reaping: DROP TABLE db1.t1 +--error ER_BAD_TABLE_ERROR +--reap + +--echo # Connection default +connection default; +disconnect con2; +disconnect con3; +SET DEBUG_SYNC= 'RESET'; + +--echo # +--echo # End of tests for schema-scope locks +--echo # + +--echo # +--echo # Tests of granted global S lock (FLUSH TABLE WITH READ LOCK) +--echo # + +CREATE DATABASE db1; +CREATE TABLE db1.t1(a INT); +connect(con2, localhost, root); +connect(con3, localhost, root); + +--echo # Connection default +connection default; +FLUSH TABLE WITH READ LOCK; + +--echo # Connection con2 +connection con2; +# IX global lock should block +--send CREATE TABLE db1.t2(a INT) + +--echo # Connection default +connection default; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for release of readlock' + AND info='CREATE TABLE db1.t2(a INT)'; +--source include/wait_condition.inc +UNLOCK TABLES; + +--echo # Connection con2 +connection con2; +--echo # Reaping CREATE TABLE db1.t2(a INT) +--reap + +--echo # Connection default +connection default; +FLUSH TABLE WITH READ LOCK; + +--echo # Connection con2 +connection con2; +# X global lock should block +--send ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 + +--echo # Connection default +connection default; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for release of readlock' + AND info='ALTER DATABASE db1 DEFAULT CHARACTER SET utf8'; +--source include/wait_condition.inc +UNLOCK TABLES; + +--echo # Connection con2 +connection con2; +--echo # Reaping ALTER DATABASE db1 DEFAULT CHARACTER SET utf8 +--reap + +--echo # Connection default +connection default; +FLUSH TABLE WITH READ LOCK; + +--echo # Connection con2 +connection con2; +# S global lock should not block +FLUSH TABLE WITH READ LOCK; +UNLOCK TABLES; + +--echo # Connection default +connection default; +UNLOCK TABLES; +DROP DATABASE db1; +disconnect con2; +disconnect con3; + + # 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/merge-big.test b/mysql-test/t/merge-big.test index 33bd93791f1..509c7742dac 100644 --- a/mysql-test/t/merge-big.test +++ b/mysql-test/t/merge-big.test @@ -51,7 +51,7 @@ connection default; #--sleep 8 #SELECT ID,STATE,INFO FROM INFORMATION_SCHEMA.PROCESSLIST; let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE ID = $con1_id AND STATE = 'Table lock'; + WHERE ID = $con1_id AND STATE = 'Waiting for table'; --source include/wait_condition.inc #SELECT NOW(); --echo # Kick INSERT out of thr_multi_lock(). @@ -61,7 +61,7 @@ FLUSH TABLES; #--sleep 8 #SELECT ID,STATE,INFO FROM INFORMATION_SCHEMA.PROCESSLIST; let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST - WHERE ID = $con1_id AND STATE = 'Table lock'; + WHERE ID = $con1_id AND STATE = 'Waiting for table'; --source include/wait_condition.inc #SELECT NOW(); --echo # Unlock and close table and wait for con1 to close too. diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index a06da03cbcd..31bc8a5e881 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -2,6 +2,12 @@ # Test of MERGE TABLES # +# MERGE tables require MyISAM tables +let $default=`select @@global.storage_engine`; +set global storage_engine=myisam; +set session storage_engine=myisam; + +# Clean up resources used in this test case. --disable_warnings drop table if exists t1,t2,t3,t4,t5,t6; drop database if exists mysqltest; @@ -222,7 +228,6 @@ CREATE TABLE t2 (c1 INT NOT NULL); INSERT INTO t1 VALUES (1); INSERT INTO t2 VALUES (2); CREATE TEMPORARY TABLE t3 (c1 INT NOT NULL) ENGINE=MRG_MYISAM UNION=(t1,t2); ---error ER_WRONG_MRG_TABLE SELECT * FROM t3; CREATE TEMPORARY TABLE t4 (c1 INT NOT NULL); CREATE TEMPORARY TABLE t5 (c1 INT NOT NULL); @@ -254,7 +259,6 @@ create table t3 (a int not null) ENGINE=MERGE UNION=(t1,t2); select * from t3; drop table t3; create temporary table t3 (a int not null) ENGINE=MERGE UNION=(t1,t2); ---error ER_WRONG_MRG_TABLE select * from t3; drop table t3, t2, t1; --echo # CREATE...SELECT is not implemented for MERGE tables. @@ -891,12 +895,9 @@ INSERT INTO t4 VALUES (4); --echo # If the temporary MERGE table uses the locked children only, --echo # it can even be used. CREATE TEMPORARY TABLE t4 LIKE t3; ---error ER_WRONG_MRG_TABLE SHOW CREATE TABLE t4; ---error ER_WRONG_MRG_TABLE INSERT INTO t4 VALUES (4); UNLOCK TABLES; ---error ER_WRONG_MRG_TABLE INSERT INTO t4 VALUES (4); DROP TABLE t4; # @@ -2117,6 +2118,325 @@ OPTIMIZE TABLE t1; DROP TABLE t1; --echo # +--echo # Bug#36171 - CREATE TEMPORARY TABLE and MERGE engine +--echo # More tests with TEMPORARY MERGE table and permanent children. +--echo # First without locked tables. +--echo # +--disable_warnings +DROP TABLE IF EXISTS t1, t2, t3, t4, m1, m2; +--enable_warnings +# +--echo # +CREATE TABLE t1 (c1 INT, c2 INT) ENGINE=MyISAM; +CREATE TABLE t2 (c1 INT, c2 INT) ENGINE=MyISAM; +CREATE TEMPORARY TABLE m1 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +SHOW CREATE TABLE t1; +SHOW CREATE TABLE m1; +SELECT * FROM m1; +INSERT INTO t1 VALUES (111, 121); +INSERT INTO m1 VALUES (211, 221); +SELECT * FROM m1; +SELECT * FROM t1; +SELECT * FROM t2; +# +--echo # +ALTER TABLE m1 RENAME m2; +SHOW CREATE TABLE m2; +SELECT * FROM m2; +# +--echo # +CREATE TEMPORARY TABLE m1 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +--error ER_TABLE_EXISTS_ERROR +ALTER TABLE m2 RENAME m1; +DROP TABLE m1; +ALTER TABLE m2 RENAME m1; +SHOW CREATE TABLE m1; +SELECT * FROM m1; +# +--echo # +ALTER TABLE m1 ADD COLUMN c3 INT; +--error ER_WRONG_MRG_TABLE +INSERT INTO m1 VALUES (212, 222, 232); +--error ER_WRONG_MRG_TABLE +SELECT * FROM m1; +ALTER TABLE t1 ADD COLUMN c3 INT; +ALTER TABLE t2 ADD COLUMN c3 INT; +INSERT INTO m1 VALUES (212, 222, 232); +SELECT * FROM m1; +# +--echo # +ALTER TABLE m1 DROP COLUMN c3; +--error ER_WRONG_MRG_TABLE +INSERT INTO m1 VALUES (213, 223); +--error ER_WRONG_MRG_TABLE +SELECT * FROM m1; +ALTER TABLE t1 DROP COLUMN c3; +ALTER TABLE t2 DROP COLUMN c3; +INSERT INTO m1 VALUES (213, 223); +SELECT * FROM m1; +# +--echo # +CREATE TABLE t3 (c1 INT, c2 INT) ENGINE=MyISAM; +ALTER TABLE m1 UNION=(t1,t2,t3); +INSERT INTO m1 VALUES (311, 321); +SELECT * FROM m1; +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; +# +--echo # +CREATE TEMPORARY TABLE t4 (c1 INT, c2 INT) ENGINE=MyISAM; +ALTER TABLE m1 UNION=(t1,t2,t3,t4); +INSERT INTO m1 VALUES (411, 421); +SELECT * FROM m1; +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; +SELECT * FROM t4; +# +--echo # +ALTER TABLE m1 ENGINE=MyISAM; +SHOW CREATE TABLE m1; +INSERT INTO m1 VALUES (511, 521); +SELECT * FROM m1; +# +--echo # +ALTER TABLE m1 ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +SELECT * FROM m1; +SELECT * FROM t1; +SELECT * FROM t2; +# +--echo # +CREATE TEMPORARY TABLE t1 (c1 INT, c2 INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (611, 621); +SELECT * FROM m1; +DROP TABLE t1; +SELECT * FROM m1; +# +# +--echo # +--echo # +SHOW CREATE TABLE m1; +# +--echo # +CREATE TABLE m2 SELECT * FROM m1; +SHOW CREATE TABLE m2; +SELECT * FROM m2; +DROP TABLE m2; +# +--echo # +CREATE TEMPORARY TABLE m2 SELECT * FROM m1; +SHOW CREATE TABLE m2; +SELECT * FROM m2; +DROP TABLE m2; +# +--echo # +CREATE TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) + INSERT_METHOD=LAST; +--error ER_WRONG_MRG_TABLE +SELECT * FROM m2; +DROP TABLE m2; +# +--echo # +--error ER_WRONG_OBJECT +CREATE TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) + INSERT_METHOD=LAST SELECT * FROM m1; +# +--echo # +--error ER_WRONG_OBJECT +CREATE TEMPORARY TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) + INSERT_METHOD=LAST SELECT * FROM m1; +# +--echo # +CREATE TABLE m2 LIKE m1; +SHOW CREATE TABLE m2; +SELECT * FROM m2; +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +DROP TABLE m2; +# +--echo # +CREATE TEMPORARY TABLE m2 LIKE m1; +SHOW CREATE TABLE m2; +SELECT * FROM m2; +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +DROP TABLE m2; +# +--echo # +CREATE TEMPORARY TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) + INSERT_METHOD=LAST; +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +# +# +--echo # +--echo # +LOCK TABLE m1 WRITE, m2 WRITE; +SELECT * FROM m1,m2 WHERE m1.c1=m2.c1; +UNLOCK TABLES; +# +DROP TABLE t1, t2, t3, t4, m1, m2; +# +# +# +--echo # +--echo # Bug#36171 - CREATE TEMPORARY TABLE and MERGE engine +--echo # More tests with TEMPORARY MERGE table and permanent children. +--echo # (continued) Now the same with locked table. +--echo # +CREATE TABLE t1 (c1 INT, c2 INT) ENGINE=MyISAM; +CREATE TABLE t2 (c1 INT, c2 INT) ENGINE=MyISAM; +CREATE TEMPORARY TABLE m1 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +SHOW CREATE TABLE t1; +SHOW CREATE TABLE m1; +SELECT * FROM m1; +INSERT INTO t1 VALUES (111, 121); +INSERT INTO m1 VALUES (211, 221); +SELECT * FROM m1; +SELECT * FROM t1; +SELECT * FROM t2; +# +--echo # +LOCK TABLE m1 WRITE, t1 WRITE, t2 WRITE; +# +--echo # +ALTER TABLE m1 RENAME m2; +SHOW CREATE TABLE m2; +SELECT * FROM m2; +# +--echo # +CREATE TEMPORARY TABLE m1 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +--error ER_TABLE_EXISTS_ERROR +ALTER TABLE m2 RENAME m1; +DROP TABLE m1; +ALTER TABLE m2 RENAME m1; +SHOW CREATE TABLE m1; +SELECT * FROM m1; +# +--echo # +ALTER TABLE m1 ADD COLUMN c3 INT; +--error ER_WRONG_MRG_TABLE +INSERT INTO m1 VALUES (212, 222, 232); +--error ER_WRONG_MRG_TABLE +SELECT * FROM m1; +ALTER TABLE t1 ADD COLUMN c3 INT; +ALTER TABLE t2 ADD COLUMN c3 INT; +INSERT INTO m1 VALUES (212, 222, 232); +SELECT * FROM m1; +# +--echo # +ALTER TABLE m1 DROP COLUMN c3; +--error ER_WRONG_MRG_TABLE +INSERT INTO m1 VALUES (213, 223); +--error ER_WRONG_MRG_TABLE +SELECT * FROM m1; +ALTER TABLE t1 DROP COLUMN c3; +ALTER TABLE t2 DROP COLUMN c3; +INSERT INTO m1 VALUES (213, 223); +SELECT * FROM m1; +# +--echo # +UNLOCK TABLES; +CREATE TABLE t3 (c1 INT, c2 INT) ENGINE=MyISAM; +ALTER TABLE m1 UNION=(t1,t2,t3); +LOCK TABLE m1 WRITE; +INSERT INTO m1 VALUES (311, 321); +SELECT * FROM m1; +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; +# +--echo # +CREATE TEMPORARY TABLE t4 (c1 INT, c2 INT) ENGINE=MyISAM; +ALTER TABLE m1 UNION=(t1,t2,t3,t4); +INSERT INTO m1 VALUES (411, 421); +SELECT * FROM m1; +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; +SELECT * FROM t4; +# +--echo # +ALTER TABLE m1 ENGINE=MyISAM; +SHOW CREATE TABLE m1; +INSERT INTO m1 VALUES (511, 521); +SELECT * FROM m1; +# +--echo # +ALTER TABLE m1 ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +SELECT * FROM m1; +SELECT * FROM t1; +SELECT * FROM t2; +# +--echo # +CREATE TEMPORARY TABLE t1 (c1 INT, c2 INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (611, 621); +SELECT * FROM m1; +DROP TABLE t1; +SELECT * FROM m1; +# +# +--echo # +--echo # +SHOW CREATE TABLE m1; +--error ER_TABLE_NOT_LOCKED +CREATE TABLE m2 SELECT * FROM m1; +# +--echo # +CREATE TEMPORARY TABLE m2 SELECT * FROM m1; +SHOW CREATE TABLE m2; +SELECT * FROM m2; +DROP TABLE m2; +# +--echo # +CREATE TEMPORARY TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) + INSERT_METHOD=LAST; +SELECT * FROM m2; +LOCK TABLE m1 WRITE, m2 WRITE; +UNLOCK TABLES; +DROP TABLE m2; +LOCK TABLE m1 WRITE; +# +--echo # +--echo # ER_TABLE_NOT_LOCKED is returned in ps-protocol +--error ER_WRONG_OBJECT, ER_TABLE_NOT_LOCKED +CREATE TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) + INSERT_METHOD=LAST SELECT * FROM m1; +# +--echo # +--error ER_WRONG_OBJECT +CREATE TEMPORARY TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) + INSERT_METHOD=LAST SELECT * FROM m1; +# +--echo # +CREATE TEMPORARY TABLE m2 LIKE m1; +SHOW CREATE TABLE m2; +LOCK TABLE m1 WRITE, m2 WRITE; +SHOW CREATE TABLE m2; +SELECT * FROM m2; +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +DROP TABLE m2; +# +--echo # +CREATE TEMPORARY TABLE m2 (c1 INT, c2 INT) ENGINE=MRG_MyISAM UNION=(t3,t4) + INSERT_METHOD=LAST; +LOCK TABLE m1 WRITE, m2 WRITE; +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +# +--echo # +UNLOCK TABLES; +DROP TABLE t1, t2, t3, t4, m1, m2; + +--echo # --echo # Bug47098 assert in MDL_context::destroy on HANDLER --echo # <damaged merge table> OPEN --echo # @@ -2225,6 +2545,130 @@ show create table m1; show create table m2; drop tables m1, m2, t1; +--echo # +--echo # Test case for Bug#54811 "Assert in mysql_lock_have_duplicate()" +--echo # Check that unique_table() works correctly for merge tables. +--echo # +--disable_warnings +drop table if exists t1, t2, t3, m1, m2; +--enable_warnings +create table t1 (a int); +create table t2 (a int); +create table t3 (b int); +create view v1 as select * from t3,t1; +create table m1 (a int) engine=merge union (t1, t2) insert_method=last; +create table m2 (a int) engine=merge union (t1, t2) insert_method=first; +create temporary table tmp (b int); +insert into tmp (b) values (1); + +insert into t1 (a) values (1); +insert into t3 (b) values (1); +--error ER_UPDATE_TABLE_USED +insert into m1 (a) values ((select max(a) from m1)); +--error ER_UPDATE_TABLE_USED +insert into m1 (a) values ((select max(a) from m2)); +--error ER_UPDATE_TABLE_USED +insert into m1 (a) values ((select max(a) from t1)); +--error ER_UPDATE_TABLE_USED +insert into m1 (a) values ((select max(a) from t2)); + +--error ER_UPDATE_TABLE_USED +insert into m1 (a) values ((select max(a) from t3, m1)); +--error ER_UPDATE_TABLE_USED +insert into m1 (a) values ((select max(a) from t3, m2)); +--error ER_UPDATE_TABLE_USED +insert into m1 (a) values ((select max(a) from t3, t1)); +--error ER_UPDATE_TABLE_USED +insert into m1 (a) values ((select max(a) from t3, t2)); + +--error ER_UPDATE_TABLE_USED +insert into m1 (a) values ((select max(a) from tmp, m1)); +--error ER_UPDATE_TABLE_USED +insert into m1 (a) values ((select max(a) from tmp, m2)); +--error ER_UPDATE_TABLE_USED +insert into m1 (a) values ((select max(a) from tmp, t1)); +--error ER_UPDATE_TABLE_USED +insert into m1 (a) values ((select max(a) from tmp, t2)); + +--error ER_VIEW_PREVENT_UPDATE +insert into m1 (a) values ((select max(a) from v1)); +--error ER_VIEW_PREVENT_UPDATE +insert into m1 (a) values ((select max(a) from tmp, v1)); + + +--error ER_UPDATE_TABLE_USED +update m1 set a = ((select max(a) from m1)); +--error ER_UPDATE_TABLE_USED +update m1 set a = ((select max(a) from m2)); +--error ER_UPDATE_TABLE_USED +update m1 set a = ((select max(a) from t1)); +--error ER_UPDATE_TABLE_USED +update m1 set a = ((select max(a) from t2)); + +--error ER_UPDATE_TABLE_USED +update m1 set a = ((select max(a) from t3, m1)); +--error ER_UPDATE_TABLE_USED +update m1 set a = ((select max(a) from t3, m2)); +--error ER_UPDATE_TABLE_USED +update m1 set a = ((select max(a) from t3, t1)); +--error ER_UPDATE_TABLE_USED +update m1 set a = ((select max(a) from t3, t2)); + +--error ER_UPDATE_TABLE_USED +update m1 set a = ((select max(a) from tmp, m1)); +--error ER_UPDATE_TABLE_USED +update m1 set a = ((select max(a) from tmp, m2)); +--error ER_UPDATE_TABLE_USED +update m1 set a = ((select max(a) from tmp, t1)); +--error ER_UPDATE_TABLE_USED +update m1 set a = ((select max(a) from tmp, t2)); + +--error ER_VIEW_PREVENT_UPDATE +update m1 set a = ((select max(a) from v1)); +--error ER_VIEW_PREVENT_UPDATE +update m1 set a = ((select max(a) from tmp, v1)); + + +--error ER_UPDATE_TABLE_USED +delete from m1 where a = (select max(a) from m1); +--error ER_UPDATE_TABLE_USED +delete from m1 where a = (select max(a) from m2); +--error ER_UPDATE_TABLE_USED +delete from m1 where a = (select max(a) from t1); +--error ER_UPDATE_TABLE_USED +delete from m1 where a = (select max(a) from t2); + +--error ER_UPDATE_TABLE_USED +delete from m1 where a = (select max(a) from t3, m1); +--error ER_UPDATE_TABLE_USED +delete from m1 where a = (select max(a) from t3, m2); +--error ER_UPDATE_TABLE_USED +delete from m1 where a = (select max(a) from t3, t1); +--error ER_UPDATE_TABLE_USED +delete from m1 where a = (select max(a) from t3, t2); + +--error ER_UPDATE_TABLE_USED +delete from m1 where a = (select max(a) from tmp, m1); +--error ER_UPDATE_TABLE_USED +delete from m1 where a = (select max(a) from tmp, m2); +--error ER_UPDATE_TABLE_USED +delete from m1 where a = (select max(a) from tmp, t1); +--error ER_UPDATE_TABLE_USED +delete from m1 where a = (select max(a) from tmp, t2); + +--error ER_VIEW_PREVENT_UPDATE +delete from m1 where a = (select max(a) from v1); +--error ER_VIEW_PREVENT_UPDATE +delete from m1 where a = (select max(a) from tmp, v1); + +drop view v1; +drop temporary table tmp; +drop table t1, t2, t3, m1, m2; --echo End of 6.0 tests +--disable_result_log +--disable_query_log +eval set global storage_engine=$default; +--enable_result_log +--enable_query_log diff --git a/mysql-test/t/merge_mmap-master.opt b/mysql-test/t/merge_mmap-master.opt new file mode 100644 index 00000000000..9606fb57187 --- /dev/null +++ b/mysql-test/t/merge_mmap-master.opt @@ -0,0 +1 @@ +--myisam-use-mmap diff --git a/mysql-test/t/merge_mmap.test b/mysql-test/t/merge_mmap.test new file mode 100644 index 00000000000..c97b029754d --- /dev/null +++ b/mysql-test/t/merge_mmap.test @@ -0,0 +1,151 @@ +# +# Test of MERGE TABLES with MyISAM memory mapping enabled (--myisam-use-mmap) +# + +# MERGE tables require MyISAM tables +--let $default=`SELECT @@global.storage_engine` +SET GLOBAL storage_engine = MyISAM; +SET SESSION storage_engine = MyISAM; + +# Clean up resources used in this test case. +--disable_warnings +DROP TABLE IF EXISTS t1, t2, m1, m2; +--enable_warnings + +#################### +## No locked tables. +#################### +# +# INSERT-SELECT with no TEMPORARY table. +# +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +CREATE TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +SELECT * FROM t2; +DROP TABLE m2, m1, t2, t1; +# +# INSERT-SELECT with TEMPORARY select table. +# +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TEMPORARY TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +CREATE TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +DROP TABLE m2, m1, t2, t1; +# +# INSERT-SELECT with TEMPORARY insert table. +# +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +CREATE TEMPORARY TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +DROP TABLE m2, m1, t2, t1; +# +# INSERT-SELECT with TEMPORARY both tables. +# +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TEMPORARY TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +CREATE TEMPORARY TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +DROP TABLE m2, m1, t2, t1; + +#################### +## With LOCK TABLES. +#################### +# +# INSERT-SELECT with no TEMPORARY table. +# +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +CREATE TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +LOCK TABLE m1 WRITE, m2 WRITE; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +SELECT * FROM t2; +UNLOCK TABLES; +DROP TABLE m2, m1, t2, t1; +# +# INSERT-SELECT with TEMPORARY select table. +# +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TEMPORARY TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +CREATE TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +LOCK TABLE m1 WRITE, m2 WRITE; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +UNLOCK TABLES; +DROP TABLE m2, m1, t2, t1; +# +# INSERT-SELECT with TEMPORARY insert table. +# +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +CREATE TEMPORARY TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +LOCK TABLE m1 WRITE, m2 WRITE; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +UNLOCK TABLES; +DROP TABLE m2, m1, t2, t1; +# +# INSERT-SELECT with TEMPORARY both tables. +# +CREATE TABLE t1 (c1 INT); +CREATE TABLE t2 (c1 INT); +CREATE TEMPORARY TABLE m1 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +CREATE TEMPORARY TABLE m2 (c1 INT) ENGINE=MRG_MyISAM UNION=(t1,t2) + INSERT_METHOD=LAST; +LOCK TABLE m1 WRITE, m2 WRITE; +INSERT INTO t1 VALUES (1); +INSERT INTO t2 VALUES (2), (3), (4); +INSERT INTO m2 SELECT * FROM m1; +SELECT * FROM m2; +UNLOCK TABLES; +DROP TABLE m2, m1, t2, t1; + +--echo End of 6.0 tests + +--disable_result_log +--disable_query_log +eval SET GLOBAL storage_engine = $default; +--enable_result_log +--enable_query_log diff --git a/mysql-test/t/partition_debug_sync.test b/mysql-test/t/partition_debug_sync.test index 9165006f537..cde94856ae6 100644 --- a/mysql-test/t/partition_debug_sync.test +++ b/mysql-test/t/partition_debug_sync.test @@ -65,7 +65,7 @@ ENGINE = MYISAM PARTITION p1 VALUES LESS THAN (20), PARTITION p2 VALUES LESS THAN (100), PARTITION p3 VALUES LESS THAN MAXVALUE ) */; -SET DEBUG_SYNC= 'open_tables_acquire_upgradable_mdl SIGNAL removing_partitions WAIT_FOR waiting_for_alter'; +SET DEBUG_SYNC= 'alter_table_before_open_tables SIGNAL removing_partitions WAIT_FOR waiting_for_alter'; SET DEBUG_SYNC= 'alter_table_before_rename_result_table WAIT_FOR delete_done'; --send ALTER TABLE t2 REMOVE PARTITIONING connection default; diff --git a/mysql-test/t/schema.test b/mysql-test/t/schema.test index f106b9e4865..ed3b98ec2f7 100644 --- a/mysql-test/t/schema.test +++ b/mysql-test/t/schema.test @@ -23,6 +23,7 @@ drop schema foo; --disable_warnings DROP SCHEMA IF EXISTS schema1; +DROP SCHEMA IF EXISTS schema2; --enable_warnings connect(con2, localhost, root); @@ -31,6 +32,7 @@ connect(con2, localhost, root); connection default; CREATE SCHEMA schema1; +CREATE SCHEMA schema2; CREATE TABLE schema1.t1 (a INT); SET autocommit= FALSE; @@ -46,9 +48,7 @@ let $wait_condition= SELECT COUNT(*)= 1 FROM information_schema.processlist WHERE state= 'Waiting for table' AND info='DROP SCHEMA schema1'; --source include/wait_condition.inc -# Listing the error twice to prevent result diffences based on filename ---error 1,1 -ALTER SCHEMA schema1 DEFAULT CHARACTER SET utf8; +ALTER SCHEMA schema2 DEFAULT CHARACTER SET utf8; SET autocommit= TRUE; --echo # Connection 2 @@ -57,6 +57,7 @@ connection con2; --echo # Connection default connection default; +DROP SCHEMA schema2; disconnect con2; @@ -102,6 +103,98 @@ connection con2; connection default; disconnect con2; + +--echo # +--echo # Bug#54360 Deadlock DROP/ALTER/CREATE DATABASE with open HANDLER +--echo # + +CREATE DATABASE db1; +CREATE TABLE db1.t1 (a INT); +INSERT INTO db1.t1 VALUES (1), (2); + +--echo # Connection con1 +connect (con1, localhost, root); +HANDLER db1.t1 OPEN; + +--echo # Connection default +connection default; +--echo # Sending: +--send DROP DATABASE db1 + +--echo # Connection con2 +connect (con2, localhost, root); +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for table' AND info='DROP DATABASE db1'; +--source include/wait_condition.inc + +--echo # Connection con1 +connection con1; +# All these statements before resulted in deadlock. +CREATE DATABASE db2; +ALTER DATABASE db2 DEFAULT CHARACTER SET utf8; +DROP DATABASE db2; +HANDLER t1 CLOSE; + +--echo # Connection default +connection default; +--echo # Reaping: DROP DATABASE db1 +--reap +disconnect con1; +disconnect con2; + + +--echo # +--echo # Tests for increased CREATE/ALTER/DROP DATABASE concurrency with +--echo # database name locks. +--echo # + +--disable_warnings +DROP DATABASE IF EXISTS db1; +DROP DATABASE IF EXISTS db2; +--enable_warnings + +connect (con2, localhost, root); +connect (con3, localhost, root); + +--echo # Connection default +connection default; +CREATE DATABASE db1; +CREATE TABLE db1.t1 (id INT); +START TRANSACTION; +INSERT INTO db1.t1 VALUES (1); + +--echo # Connection 2 +connection con2; +--echo # DROP DATABASE should block due to the active transaction +--echo # Sending: +--send DROP DATABASE db1 + +--echo # Connection 3 +connection con3; +let $wait_condition=SELECT COUNT(*)=1 FROM information_schema.processlist + WHERE state='Waiting for table' and info='DROP DATABASE db1'; +--source include/wait_condition.inc +--echo # But it should still be possible to CREATE/ALTER/DROP other databases. +CREATE DATABASE db2; +ALTER DATABASE db2 DEFAULT CHARACTER SET utf8; +DROP DATABASE db2; + +--echo # Connection default +connection default; +--echo # End the transaction so DROP DATABASE db1 can continue +COMMIT; + +--echo # Connection 2 +connection con2; +--echo # Reaping: DROP DATABASE db1 +--reap + +--echo # Connection default; +connection default; +disconnect con2; +disconnect con3; + + # 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/show_check.test b/mysql-test/t/show_check.test index 3821701ad19..fa9dc7472fe 100644 --- a/mysql-test/t/show_check.test +++ b/mysql-test/t/show_check.test @@ -1246,6 +1246,85 @@ UNLOCK TABLES; DROP TABLE t1; +--echo # +--echo # Bug#54905 Connection with WRITE lock cannot ALTER table due to +--echo # concurrent SHOW CREATE +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1(a INT); + +--echo # Connection con1 +connect (con1,localhost,root); +LOCK TABLE t1 WRITE; + +--echo # Connection default +connection default; +START TRANSACTION; +SHOW CREATE TABLE t1; + +--echo # Connection con1 +connection con1; +# Used to block +ALTER TABLE t1 CHARACTER SET = utf8; +UNLOCK TABLES; + +--echo # Connection default +connection default; +COMMIT; +disconnect con1; +DROP TABLE t1; + + +--echo # +--echo # Bug#55498 SHOW CREATE TRIGGER takes wrong type of metadata lock. +--echo # + +--disable_warnings +DROP TABLE IF EXISTS t1; +--enable_warnings + +CREATE TABLE t1 (a INT); +CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET new.a = 1; + +--echo # Test 1: SHOW CREATE TRIGGER with WRITE locked table. + +--echo # Connection con1 +connect (con1, localhost, root); +LOCK TABLE t1 WRITE; + +--echo # Connection default +connection default; +# Should not block. +SHOW CREATE TRIGGER t1_bi; + +--echo # Connection con1 +connection con1; +UNLOCK TABLES; + +--echo # Test 2: ALTER TABLE with SHOW CREATE TRIGGER in transaction + +--echo # Connection default +connection default; +START TRANSACTION; +SHOW CREATE TRIGGER t1_bi; + +--echo # Connection con1 +connection con1; +# Should not block. +ALTER TABLE t1 CHARACTER SET = utf8; + +--echo # Connection default +connection default; +COMMIT; +DROP TRIGGER t1_bi; +DROP TABLE t1; +disconnect con1; + + # Wait till all disconnects are completed --source include/wait_until_count_sessions.inc diff --git a/mysql-test/t/temp_table.test b/mysql-test/t/temp_table.test index 2bfa4936c91..92c22242cdb 100644 --- a/mysql-test/t/temp_table.test +++ b/mysql-test/t/temp_table.test @@ -235,4 +235,19 @@ INSERT INTO t2 SELECT f1(); DROP TABLE t1,t2,t3; DROP FUNCTION f1; +--echo # +--echo # Bug #48067: A temp table with the same name as an existing table, +--echo # makes drop database fail. +--echo # +--disable_warnings +DROP TEMPORARY TABLE IF EXISTS bug48067.t1; +DROP DATABASE IF EXISTS bug48067; +--enable_warnings +CREATE DATABASE bug48067; +CREATE TABLE bug48067.t1 (c1 int); +INSERT INTO bug48067.t1 values (1); +CREATE TEMPORARY TABLE bug48067.t1 (c1 int); +DROP DATABASE bug48067; +DROP TEMPORARY table bug48067.t1; + --echo End of 5.1 tests diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test index d865851841f..75099523062 100644 --- a/mysql-test/t/variables.test +++ b/mysql-test/t/variables.test @@ -1405,4 +1405,30 @@ SET @@sql_quote_show_create = @sql_quote_show_create_saved; --echo # End of Bug#34828. --echo +--echo # Make sure we can manipulate with autocommit in the +--echo # along with other variables. + + +--disable_warnings +drop table if exists t1; +drop function if exists t1_max; +drop function if exists t1_min; +--enable_warnings + +create table t1 (a int) engine=innodb; +insert into t1(a) values (0), (1); +create function t1_max() returns int return (select max(a) from t1); +create function t1_min() returns int return (select min(a) from t1); +select t1_min(); +select t1_max(); +set @@session.autocommit=t1_min(), @@session.autocommit=t1_max(), + @@session.autocommit=t1_min(), @@session.autocommit=t1_max(), + @@session.autocommit=t1_min(), @@session.autocommit=t1_max(); + +--echo # Cleanup. +drop table t1; +drop function t1_min; +drop function t1_max; + + ########################################################################### diff --git a/mysys/errors.c b/mysys/errors.c index 9342ab2d2dd..8bc310652f1 100644 --- a/mysys/errors.c +++ b/mysys/errors.c @@ -49,7 +49,9 @@ const char *globerrs[GLOBERRS]= "Can't sync file '%s' to disk (Errcode: %d)", "Collation '%s' is not a compiled collation and is not specified in the '%s' file", "File '%s' not found (Errcode: %d)", - "File '%s' (fileno: %d) was not closed" + "File '%s' (fileno: %d) was not closed", + "Can't change ownership of the file '%s' (Errcode: %d)", + "Can't change permissions of the file '%s' (Errcode: %d)", }; void init_glob_errs(void) @@ -90,6 +92,8 @@ void init_glob_errs() EE(EE_UNKNOWN_COLLATION)= "Collation '%s' is not a compiled collation and is not specified in the %s file"; EE(EE_FILENOTFOUND) = "File '%s' not found (Errcode: %d)"; EE(EE_FILE_NOT_CLOSED) = "File '%s' (fileno: %d) was not closed"; + EE(EE_CHANGE_OWNERSHIP) = "Can't change ownership of the file '%s' (Errcode: %d)"; + EE(EE_CHANGE_PERMISSIONS) = "Can't change permissions of the file '%s' (Errcode: %d)"; } #endif diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c index c4bba9c4e72..173b678cdd1 100644 --- a/mysys/mf_iocache.c +++ b/mysys/mf_iocache.c @@ -454,7 +454,9 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, RETURN 0 we succeeded in reading all data - 1 Error: can't read requested characters + 1 Error: couldn't read requested characters. In this case: + If info->error == -1, we got a read error. + Otherwise info->error contains the number of bytes in Buffer. */ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count) @@ -463,6 +465,7 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count) my_off_t pos_in_file; DBUG_ENTER("_my_b_read"); + /* If the buffer is not empty yet, copy what is available. */ if ((left_length= (size_t) (info->read_end-info->read_pos))) { DBUG_ASSERT(Count >= left_length); /* User is not using my_b_read() */ @@ -474,7 +477,7 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count) /* pos_in_file always point on where info->buffer was read */ pos_in_file=info->pos_in_file+ (size_t) (info->read_end - info->buffer); - /* + /* Whenever a function which operates on IO_CACHE flushes/writes some part of the IO_CACHE to disk it will set the property "seek_not_done" to indicate this to other functions operating @@ -501,19 +504,38 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count) } } + /* + Calculate, how much we are within a IO_SIZE block. Ideally this + should be zero. + */ diff_length= (size_t) (pos_in_file & (IO_SIZE-1)); + + /* + If more than a block plus the rest of the current block is wanted, + we do read directly, without filling the buffer. + */ if (Count >= (size_t) (IO_SIZE+(IO_SIZE-diff_length))) { /* Fill first intern buffer */ size_t read_length; if (info->end_of_file <= pos_in_file) - { /* End of file */ + { + /* End of file. Return, what we did copy from the buffer. */ info->error= (int) left_length; DBUG_RETURN(1); } + /* + Crop the wanted count to a multiple of IO_SIZE and subtract, + what we did already read from a block. That way, the read will + end aligned with a block. + */ length=(Count & (size_t) ~(IO_SIZE-1))-diff_length; if ((read_length= my_read(info->file,Buffer, length, info->myflags)) != length) { + /* + If we didn't get, what we wanted, we either return -1 for a read + error, or (it's end of file), how much we got in total. + */ info->error= (read_length == (size_t) -1 ? -1 : (int) (read_length+left_length)); DBUG_RETURN(1); @@ -525,15 +547,27 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count) diff_length=0; } + /* + At this point, we want less than one and a partial block. + We will read a full cache, minus the number of bytes, we are + within a block already. So we will reach new alignment. + */ max_length= info->read_length-diff_length; + /* We will not read past end of file. */ if (info->type != READ_FIFO && max_length > (info->end_of_file - pos_in_file)) max_length= (size_t) (info->end_of_file - pos_in_file); + /* + If there is nothing left to read, + we either are done, or we failed to fulfill the request. + Otherwise, we read max_length into the cache. + */ if (!max_length) { if (Count) { - info->error= left_length; /* We only got this many char */ + /* We couldn't fulfil the request. Return, how much we got. */ + info->error= left_length; DBUG_RETURN(1); } length=0; /* Didn't read any chars */ @@ -542,13 +576,23 @@ int _my_b_read(register IO_CACHE *info, uchar *Buffer, size_t Count) info->myflags)) < Count || length == (size_t) -1) { + /* + We got an read error, or less than requested (end of file). + If not a read error, copy, what we got. + */ if (length != (size_t) -1) memcpy(Buffer, info->buffer, length); info->pos_in_file= pos_in_file; + /* For a read error, return -1, otherwise, what we got in total. */ info->error= length == (size_t) -1 ? -1 : (int) (length+left_length); info->read_pos=info->read_end=info->buffer; DBUG_RETURN(1); } + /* + Count is the remaining number of bytes requested. + length is the amount of data in the cache. + Read Count bytes from the cache. + */ info->read_pos=info->buffer+Count; info->read_end=info->buffer+length; info->pos_in_file=pos_in_file; @@ -1702,16 +1746,19 @@ int my_block_write(register IO_CACHE *info, const uchar *Buffer, size_t Count, #endif -int my_b_flush_io_cache(IO_CACHE *info, int need_append_buffer_lock) +int my_b_flush_io_cache(IO_CACHE *info, + int need_append_buffer_lock __attribute__((unused))) { size_t length; - my_bool append_cache; my_off_t pos_in_file; + my_bool append_cache= (info->type == SEQ_READ_APPEND); DBUG_ENTER("my_b_flush_io_cache"); DBUG_PRINT("enter", ("cache: 0x%lx", (long) info)); - if (!(append_cache = (info->type == SEQ_READ_APPEND))) - need_append_buffer_lock=0; +#ifdef THREAD + if (!append_cache) + need_append_buffer_lock= 0; +#endif if (info->type == WRITE_CACHE || append_cache) { diff --git a/mysys/my_copy.c b/mysys/my_copy.c index 878aebd3684..35324dd4cef 100644 --- a/mysys/my_copy.c +++ b/mysys/my_copy.c @@ -16,6 +16,7 @@ #include "mysys_priv.h" #include <my_dir.h> /* for stat */ #include <m_string.h> +#include "mysys_err.h" #if defined(HAVE_UTIME_H) #include <utime.h> #elif defined(HAVE_SYS_UTIME_H) @@ -56,7 +57,6 @@ int my_copy(const char *from, const char *to, myf MyFlags) File from_file,to_file; uchar buff[IO_SIZE]; MY_STAT stat_buff,new_stat_buff; - int res; DBUG_ENTER("my_copy"); DBUG_PRINT("my",("from %s to %s MyFlags %d", from, to, MyFlags)); @@ -102,9 +102,23 @@ int my_copy(const char *from, const char *to, myf MyFlags) if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat) DBUG_RETURN(0); /* File copyed but not stat */ - res= chmod(to, stat_buff.st_mode & 07777); /* Copy modes */ + /* Copy modes */ + if (chmod(to, stat_buff.st_mode & 07777)) + { + my_errno= errno; + if (MyFlags & (MY_FAE+MY_WME)) + my_error(EE_CHANGE_PERMISSIONS, MYF(ME_BELL+ME_WAITTANG), from, errno); + goto err; + } #if !defined(__WIN__) - res= chown(to, stat_buff.st_uid,stat_buff.st_gid); /* Copy ownership */ + /* Copy ownership */ + if (chown(to, stat_buff.st_uid, stat_buff.st_gid)) + { + my_errno= errno; + if (MyFlags & (MY_FAE+MY_WME)) + my_error(EE_CHANGE_OWNERSHIP, MYF(ME_BELL+ME_WAITTANG), from, errno); + goto err; + } #endif if (MyFlags & MY_COPYTIME) diff --git a/mysys/my_redel.c b/mysys/my_redel.c index 300bac6e296..92aa6e42073 100644 --- a/mysys/my_redel.c +++ b/mysys/my_redel.c @@ -76,11 +76,8 @@ end: int my_copystat(const char *from, const char *to, int MyFlags) { struct stat statbuf; -#if !defined(__WIN__) - int res; -#endif - if (stat((char*) from, &statbuf)) + if (stat(from, &statbuf)) { my_errno=errno; if (MyFlags & (MY_FAE+MY_WME)) @@ -89,7 +86,15 @@ int my_copystat(const char *from, const char *to, int MyFlags) } if ((statbuf.st_mode & S_IFMT) != S_IFREG) return 1; - (void) chmod(to, statbuf.st_mode & 07777); /* Copy modes */ + + /* Copy modes */ + if (chmod(to, statbuf.st_mode & 07777)) + { + my_errno= errno; + if (MyFlags & (MY_FAE+MY_WME)) + my_error(EE_CHANGE_PERMISSIONS, MYF(ME_BELL+ME_WAITTANG), from, errno); + return -1; + } #if !defined(__WIN__) if (statbuf.st_nlink > 1 && MyFlags & MY_LINK_WARNING) @@ -97,7 +102,14 @@ int my_copystat(const char *from, const char *to, int MyFlags) if (MyFlags & MY_LINK_WARNING) my_error(EE_LINK_WARNING,MYF(ME_BELL+ME_WAITTANG),from,statbuf.st_nlink); } - res= chown(to, statbuf.st_uid, statbuf.st_gid); /* Copy ownership */ + /* Copy ownership */ + if (chown(to, statbuf.st_uid, statbuf.st_gid)) + { + my_errno= errno; + if (MyFlags & (MY_FAE+MY_WME)) + my_error(EE_CHANGE_OWNERSHIP, MYF(ME_BELL+ME_WAITTANG), from, errno); + return -1; + } #endif /* !__WIN__ */ if (MyFlags & MY_COPYTIME) diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c index 9d10ba1fb01..7ba0490cb29 100644 --- a/mysys/thr_lock.c +++ b/mysys/thr_lock.c @@ -107,7 +107,7 @@ my_bool init_thr_lock() } static inline my_bool -thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs) +thr_lock_owner_equal(THR_LOCK_INFO *rhs, THR_LOCK_INFO *lhs) { return rhs == lhs; } @@ -122,7 +122,7 @@ static int check_lock(struct st_lock_list *list, const char* lock_type, { THR_LOCK_DATA *data,**prev; uint count=0; - THR_LOCK_OWNER *UNINIT_VAR(first_owner); + THR_LOCK_INFO *UNINIT_VAR(first_owner); prev= &list->data; if (list->data) @@ -341,7 +341,6 @@ void thr_lock_info_init(THR_LOCK_INFO *info) struct st_my_thread_var *tmp= my_thread_var; info->thread= tmp->pthread_self; info->thread_id= tmp->id; - info->n_cursors= 0; } /* Initialize a lock instance */ @@ -357,7 +356,7 @@ void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *param) static inline my_bool -has_old_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner) +has_old_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner) { for ( ; data ; data=data->next) { @@ -506,13 +505,12 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, enum enum_thr_lock_result -thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, +thr_lock(THR_LOCK_DATA *data, THR_LOCK_INFO *owner, enum thr_lock_type lock_type, ulong lock_wait_timeout) { THR_LOCK *lock=data->lock; enum enum_thr_lock_result result= THR_LOCK_SUCCESS; struct st_lock_list *wait_queue; - THR_LOCK_DATA *lock_owner; DBUG_ENTER("thr_lock"); data->next=0; @@ -521,7 +519,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, data->owner= owner; /* Must be reset ! */ mysql_mutex_lock(&lock->mutex); DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx type: %d", - (long) data, data->owner->info->thread_id, + (long) data, data->owner->thread_id, (long) lock, (int) lock_type)); check_locks(lock,(uint) lock_type <= (uint) TL_READ_NO_INSERT ? "enter read_lock" : "enter write_lock",0); @@ -558,7 +556,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, */ DBUG_PRINT("lock",("write locked 1 by thread: 0x%lx", - lock->write.data->owner->info->thread_id)); + lock->write.data->owner->thread_id)); if (thr_lock_owner_equal(data->owner, lock->write.data->owner) || (lock->write.data->type <= TL_WRITE_DELAYED && (((int) lock_type <= (int) TL_READ_HIGH_PRIORITY) || @@ -707,7 +705,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, goto end; } DBUG_PRINT("lock",("write locked 2 by thread: 0x%lx", - lock->write.data->owner->info->thread_id)); + lock->write.data->owner->thread_id)); } else { @@ -743,23 +741,10 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, } } DBUG_PRINT("lock",("write locked 3 by thread: 0x%lx type: %d", - lock->read.data->owner->info->thread_id, data->type)); + lock->read.data->owner->thread_id, data->type)); } wait_queue= &lock->write_wait; } - /* - Try to detect a trivial deadlock when using cursors: attempt to - lock a table that is already locked by an open cursor within the - same connection. lock_owner can be zero if we succumbed to a high - priority writer in the write_wait queue. - */ - lock_owner= lock->read.data ? lock->read.data : lock->write.data; - if (lock_owner && lock_owner->owner->info == owner->info) - { - DBUG_PRINT("lock",("deadlock")); - result= THR_LOCK_DEADLOCK; - goto end; - } /* Can't get lock yet; Wait for it */ DBUG_RETURN(wait_for_lock(wait_queue, data, 0, lock_wait_timeout)); end: @@ -807,7 +792,7 @@ static inline void free_all_read_locks(THR_LOCK *lock, } /* purecov: begin inspected */ DBUG_PRINT("lock",("giving read lock to thread: 0x%lx", - data->owner->info->thread_id)); + data->owner->thread_id)); /* purecov: end */ data->cond=0; /* Mark thread free */ mysql_cond_signal(cond); @@ -826,7 +811,7 @@ void thr_unlock(THR_LOCK_DATA *data) enum thr_lock_type lock_type=data->type; DBUG_ENTER("thr_unlock"); DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx", - (long) data, data->owner->info->thread_id, (long) lock)); + (long) data, data->owner->thread_id, (long) lock)); mysql_mutex_lock(&lock->mutex); check_locks(lock,"start of release lock",0); @@ -915,7 +900,7 @@ static void wake_up_waiters(THR_LOCK *lock) data->type=TL_WRITE; /* Upgrade lock */ /* purecov: begin inspected */ DBUG_PRINT("lock",("giving write lock of type %d to thread: 0x%lx", - data->type, data->owner->info->thread_id)); + data->type, data->owner->thread_id)); /* purecov: end */ { mysql_cond_t *cond= data->cond; @@ -1020,7 +1005,7 @@ static void sort_locks(THR_LOCK_DATA **data,uint count) enum enum_thr_lock_result -thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner, +thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_INFO *owner, ulong lock_wait_timeout) { THR_LOCK_DATA **pos,**end; @@ -1144,7 +1129,7 @@ void thr_multi_unlock(THR_LOCK_DATA **data,uint count) else { DBUG_PRINT("lock",("Free lock: data: 0x%lx thread: 0x%lx lock: 0x%lx", - (long) *pos, (*pos)->owner->info->thread_id, + (long) *pos, (*pos)->owner->thread_id, (long) (*pos)->lock)); } } @@ -1200,7 +1185,7 @@ my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id) mysql_mutex_lock(&lock->mutex); for (data= lock->read_wait.data; data ; data= data->next) { - if (data->owner->info->thread_id == thread_id) /* purecov: tested */ + if (data->owner->thread_id == thread_id) /* purecov: tested */ { DBUG_PRINT("info",("Aborting read-wait lock")); data->type= TL_UNLOCK; /* Mark killed */ @@ -1217,7 +1202,7 @@ my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread_id) } for (data= lock->write_wait.data; data ; data= data->next) { - if (data->owner->info->thread_id == thread_id) /* purecov: tested */ + if (data->owner->thread_id == thread_id) /* purecov: tested */ { DBUG_PRINT("info",("Aborting write-wait lock")); data->type= TL_UNLOCK; @@ -1387,7 +1372,7 @@ static void thr_print_lock(const char* name,struct st_lock_list *list) prev= &list->data; for (data=list->data; data && count++ < MAX_LOCKS ; data=data->next) { - printf("0x%lx (%lu:%d); ", (ulong) data, data->owner->info->thread_id, + printf("0x%lx (%lu:%d); ", (ulong) data, data->owner->thread_id, (int) data->type); if (data->prev != prev) printf("\nWarning: prev didn't point at previous lock\n"); @@ -1525,7 +1510,6 @@ static void *test_thread(void *arg) { int i,j,param=*((int*) arg); THR_LOCK_DATA data[MAX_LOCK_COUNT]; - THR_LOCK_OWNER owner; THR_LOCK_INFO lock_info; THR_LOCK_DATA *multi_locks[MAX_LOCK_COUNT]; my_thread_init(); @@ -1534,7 +1518,6 @@ static void *test_thread(void *arg) thr_lock_info_init(&lock_info); - thr_lock_owner_init(&owner, &lock_info); for (i=0; i < lock_counts[param] ; i++) thr_lock_data_init(locks+tests[param][i].lock_nr,data+i,NULL); for (j=1 ; j < 10 ; j++) /* try locking 10 times */ @@ -1544,7 +1527,7 @@ static void *test_thread(void *arg) multi_locks[i]= &data[i]; data[i].type= tests[param][i].lock_type; } - thr_multi_lock(multi_locks, lock_counts[param], &owner, TEST_TIMEOUT); + thr_multi_lock(multi_locks, lock_counts[param], &lock_info, TEST_TIMEOUT); mysql_mutex_lock(&LOCK_thread_count); { int tmp=rand() & 7; /* Do something from 0-2 sec */ diff --git a/regex/engine.c b/regex/engine.c index 1968ca61a96..be08adf8601 100644 --- a/regex/engine.c +++ b/regex/engine.c @@ -256,7 +256,6 @@ sopno stopst; register char *ssp; /* start of string matched by subsubRE */ register char *sep; /* end of string matched by subsubRE */ register char *oldssp; /* previous ssp */ - register char *dp; /* used in debug mode to check asserts */ AT("diss", start, stop, startst, stopst); sp = start; @@ -314,11 +313,9 @@ sopno stopst; ssub = ss + 1; esub = es - 1; /* did innards match? */ - if (slow(charset, m, sp, rest, ssub, esub) != NULL) { - dp = dissect(charset, m, sp, rest, ssub, esub); - assert(dp == rest); - } else /* no */ - assert(sp == rest); + if (slow(charset, m, sp, rest, ssub, esub) != NULL) + sp = dissect(charset, m, sp, rest, ssub, esub); + assert(sp == rest); sp = rest; break; case OPLUS_: @@ -353,8 +350,8 @@ sopno stopst; } assert(sep == rest); /* must exhaust substring */ assert(slow(charset, m, ssp, sep, ssub, esub) == rest); - dp = dissect(charset, m, ssp, sep, ssub, esub); - assert(dp == sep); + sp = dissect(charset, m, ssp, sep, ssub, esub); + assert(sp == sep); sp = rest; break; case OCH_: @@ -388,8 +385,8 @@ sopno stopst; else assert(OP(m->g->strip[esub]) == O_CH); } - dp = dissect(charset, m, sp, rest, ssub, esub); - assert(dp == rest); + sp = dissect(charset, m, sp, rest, ssub, esub); + assert(sp == rest); sp = rest; break; case O_PLUS: diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc index dd1845b29bc..52c509621ac 100644 --- a/sql/event_data_objects.cc +++ b/sql/event_data_objects.cc @@ -1402,6 +1402,8 @@ Event_job_data::execute(THD *thd, bool drop) */ thd->set_db(dbname.str, dbname.length); + lex_start(thd); + #ifndef NO_EMBEDDED_ACCESS_CHECKS if (event_sctx.change_security_context(thd, &definer_user, &definer_host, @@ -1411,7 +1413,7 @@ Event_job_data::execute(THD *thd, bool drop) "[%s].[%s.%s] execution failed, " "failed to authenticate the user.", definer.str, dbname.str, name.str); - goto end_no_lex_start; + goto end; } #endif @@ -1427,11 +1429,11 @@ Event_job_data::execute(THD *thd, bool drop) "[%s].[%s.%s] execution failed, " "user no longer has EVENT privilege.", definer.str, dbname.str, name.str); - goto end_no_lex_start; + goto end; } if (construct_sp_sql(thd, &sp_sql)) - goto end_no_lex_start; + goto end; /* Set up global thread attributes to reflect the properties of @@ -1451,8 +1453,6 @@ Event_job_data::execute(THD *thd, bool drop) if (parser_state.init(thd, thd->query(), thd->query_length())) goto end; - lex_start(thd); - if (parse_sql(thd, & parser_state, creation_ctx)) { sql_print_error("Event Scheduler: " @@ -1484,13 +1484,6 @@ Event_job_data::execute(THD *thd, bool drop) } end: - if (thd->lex->sphead) /* NULL only if a parse error */ - { - delete thd->lex->sphead; - thd->lex->sphead= NULL; - } - -end_no_lex_start: if (drop && !thd->is_fatal_error) { /* @@ -1529,7 +1522,6 @@ end_no_lex_start: if (save_sctx) event_sctx.restore_security_context(thd, save_sctx); #endif - lex_end(thd->lex); thd->lex->unit.cleanup(); thd->end_statement(); thd->cleanup_after_query(); diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc index b7c01f10066..d47f1641bb0 100644 --- a/sql/event_db_repository.cc +++ b/sql/event_db_repository.cc @@ -518,17 +518,20 @@ Event_db_repository::table_scan_all_for_i_s(THD *thd, TABLE *schema_table, */ bool -Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables, +Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *i_s_table, const char *db) { - TABLE *schema_table= tables->table; - TABLE *event_table= NULL; + TABLE *schema_table= i_s_table->table; + Open_tables_backup open_tables_backup; + TABLE_LIST event_table; int ret= 0; DBUG_ENTER("Event_db_repository::fill_schema_events"); DBUG_PRINT("info",("db=%s", db? db:"(null)")); - if (open_event_table(thd, TL_READ, &event_table)) + event_table.init_one_table("mysql", 5, "event", 5, "event", TL_READ); + + if (open_system_tables_for_read(thd, &event_table, &open_tables_backup)) DBUG_RETURN(TRUE); /* @@ -541,11 +544,11 @@ Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables, every single row's `db` with the schema which we show. */ if (db) - ret= index_read_for_db_for_i_s(thd, schema_table, event_table, db); + ret= index_read_for_db_for_i_s(thd, schema_table, event_table.table, db); else - ret= table_scan_all_for_i_s(thd, schema_table, event_table); + ret= table_scan_all_for_i_s(thd, schema_table, event_table.table); - close_thread_tables(thd); + close_system_tables(thd, &open_tables_backup); DBUG_PRINT("info", ("Return code=%d", ret)); DBUG_RETURN(ret); @@ -584,10 +587,7 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type, tables.init_one_table("mysql", 5, "event", 5, "event", lock_type); if (open_and_lock_tables(thd, &tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) - { - close_thread_tables(thd); DBUG_RETURN(TRUE); - } *table= tables.table; tables.table->use_all_columns(); @@ -700,7 +700,8 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data, end: if (table) - close_thread_tables(thd); + close_mysql_tables(thd); + thd->variables.sql_mode= saved_mode; DBUG_RETURN(test(ret)); } @@ -811,7 +812,8 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data, end: if (table) - close_thread_tables(thd); + close_mysql_tables(thd); + thd->variables.sql_mode= saved_mode; DBUG_RETURN(test(ret)); } @@ -865,7 +867,7 @@ Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name, end: if (table) - close_thread_tables(thd); + close_mysql_tables(thd); DBUG_RETURN(test(ret)); } @@ -934,33 +936,13 @@ Event_db_repository::find_named_event(LEX_STRING db, LEX_STRING name, void Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema) { - DBUG_ENTER("Event_db_repository::drop_schema_events"); - drop_events_by_field(thd, ET_FIELD_DB, schema); - DBUG_VOID_RETURN; -} - - -/** - Drops all events which have a specific value of a field. - - @pre The thread handle has no open tables. - - @param[in,out] thd Thread - @param[in,out] table mysql.event TABLE - @param[in] field Which field of the row to use for matching - @param[in] field_value The value that should match -*/ - -void -Event_db_repository::drop_events_by_field(THD *thd, - enum enum_events_table_field field, - LEX_STRING field_value) -{ int ret= 0; TABLE *table= NULL; READ_RECORD read_record_info; - DBUG_ENTER("Event_db_repository::drop_events_by_field"); - DBUG_PRINT("enter", ("field=%d field_value=%s", field, field_value.str)); + enum enum_events_table_field field= ET_FIELD_DB; + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); + DBUG_ENTER("Event_db_repository::drop_schema_events"); + DBUG_PRINT("enter", ("field=%d schema=%s", field, schema.str)); if (open_event_table(thd, TL_WRITE, &table)) DBUG_VOID_RETURN; @@ -979,7 +961,7 @@ Event_db_repository::drop_events_by_field(THD *thd, get_field(thd->mem_root, table->field[ET_FIELD_NAME]))); - if (!sortcmp_lex_string(et_field_lex, field_value, system_charset_info)) + if (!sortcmp_lex_string(et_field_lex, schema, system_charset_info)) { DBUG_PRINT("info", ("Dropping")); if ((ret= table->file->ha_delete_row(table->record[0]))) @@ -989,6 +971,11 @@ Event_db_repository::drop_events_by_field(THD *thd, } end_read_record(&read_record_info); close_thread_tables(thd); + /* + Make sure to only release the MDL lock on mysql.event, not other + metadata locks DROP DATABASE might have acquired. + */ + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); DBUG_VOID_RETURN; } @@ -1026,7 +1013,7 @@ Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname, else if ((ret= etn->load_from_row(thd, table))) my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event"); - close_thread_tables(thd); + close_mysql_tables(thd); } thd->variables.sql_mode= saved_mode; @@ -1104,7 +1091,8 @@ update_timing_fields_for_event(THD *thd, end: if (table) - close_thread_tables(thd); + close_mysql_tables(thd); + /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -1151,7 +1139,7 @@ Event_db_repository::check_system_tables(THD *thd) if (table_intact.check(tables.table, &mysql_db_table_def)) ret= 1; - close_thread_tables(thd); + close_mysql_tables(thd); } /* Check mysql.user */ tables.init_one_table("mysql", 5, "user", 4, "user", TL_READ); @@ -1171,7 +1159,7 @@ Event_db_repository::check_system_tables(THD *thd) event_priv_column_position); ret= 1; } - close_thread_tables(thd); + close_mysql_tables(thd); } /* Check mysql.event */ tables.init_one_table("mysql", 5, "event", 5, "event", TL_READ); @@ -1185,7 +1173,7 @@ Event_db_repository::check_system_tables(THD *thd) { if (table_intact.check(tables.table, &event_table_def)) ret= 1; - close_thread_tables(thd); + close_mysql_tables(thd); } DBUG_RETURN(test(ret)); diff --git a/sql/event_db_repository.h b/sql/event_db_repository.h index ef778407d1e..ea7f3bbac0e 100644 --- a/sql/event_db_repository.h +++ b/sql/event_db_repository.h @@ -91,7 +91,7 @@ public: bool load_named_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et); - bool + static bool open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table); bool @@ -109,9 +109,6 @@ public: static bool check_system_tables(THD *thd); private: - void - drop_events_by_field(THD *thd, enum enum_events_table_field field, - LEX_STRING field_value); bool index_read_for_db_for_i_s(THD *thd, TABLE *schema_table, TABLE *event_table, const char *db); diff --git a/sql/events.cc b/sql/events.cc index a548bda53e2..5379ec2c9eb 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -16,7 +16,7 @@ #include "sql_priv.h" #include "unireg.h" #include "sql_parse.h" // check_access -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // close_mysql_tables #include "sql_show.h" // append_definer #include "events.h" #include "sql_db.h" // check_db_dir_existence @@ -754,7 +754,6 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) { char *db= NULL; int ret; - Open_tables_backup open_tables_backup; DBUG_ENTER("Events::fill_schema_events"); if (check_if_system_tables_error()) @@ -773,15 +772,7 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) DBUG_RETURN(1); db= thd->lex->select_lex.db; } - /* - Reset and backup of the currently open tables in this thread - is a way to allow SELECTs from INFORMATION_SCHEMA.events under - LOCK TABLES and in pre-locked mode. See also - Events::show_create_event for additional comments. - */ - thd->reset_n_backup_open_tables_state(&open_tables_backup); ret= db_repository->fill_schema_events(thd, tables, db); - thd->restore_backup_open_tables_state(&open_tables_backup); DBUG_RETURN(ret); } @@ -1161,8 +1152,7 @@ Events::load_events_from_db(THD *thd) end: end_read_record(&read_record_info); - close_thread_tables(thd); - + close_mysql_tables(thd); DBUG_RETURN(ret); } diff --git a/sql/field.cc b/sql/field.cc index 75576c59876..3c93ffadac5 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -5446,7 +5446,6 @@ int Field_date::store(const char *from, uint len,CHARSET_INFO *cs) int Field_date::store(double nr) { longlong tmp; - int error= 0; if (nr >= 19000000000000.0 && nr <= 99991231235959.0) nr=floor(nr/1000000.0); // Timestamp to date if (nr < 0.0 || nr > 99991231.0) @@ -5455,7 +5454,6 @@ int Field_date::store(double nr) set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_DATE); - error= 1; } else tmp= (longlong) rint(nr); diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index ecf2984a4c0..d4a98265c49 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -36,6 +36,7 @@ #include "discover.h" // readfrm #include "sql_acl.h" // wild_case_compare #include "rpl_mi.h" +#include "transaction.h" /* There is an incompatibility between GNU ar and the Solaris linker @@ -7417,7 +7418,8 @@ int ndbcluster_find_files(handlerton *hton, THD *thd, FALSE, /* drop_temporary */ FALSE, /* drop_view */ TRUE /* dont_log_query*/); - + trans_commit_implicit(thd); /* Safety, should be unnecessary. */ + thd->mdl_context.release_transactional_locks(); /* Clear error message that is returned when table is deleted */ thd->clear_error(); } diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 4f8bb66fcb0..26fdb8e1425 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -36,6 +36,7 @@ #include "lock.h" // MYSQL_LOCK_IGNORE_FLUSH, // mysql_unlock_tables #include "sql_parse.h" // mysql_parse +#include "transaction.h" #ifdef ndb_dynamite #undef assert @@ -298,13 +299,6 @@ static void run_query(THD *thd, char *buf, char *end, thd_ndb->m_error_code, (int) thd->is_error(), thd->is_slave_error); } - - /* - After executing statement we should unlock and close tables open - by it as well as release meta-data locks obtained by it. - */ - close_thread_tables(thd); - /* XXX: this code is broken. mysql_parse()/mysql_reset_thd_for_next_command() can not be called from within a statement, and @@ -2422,7 +2416,11 @@ int ndb_add_ndb_binlog_index(THD *thd, void *_row) } add_ndb_binlog_index_err: + thd->stmt_da->can_overwrite_status= TRUE; + thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); ndb_binlog_index= 0; thd->variables.option_bits= saved_options; return error; @@ -3969,7 +3967,9 @@ restart: { if (ndb_binlog_index->s->needs_reopen()) { + trans_commit_stmt(thd); close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); ndb_binlog_index= 0; } } @@ -4280,7 +4280,9 @@ restart: if (do_ndbcluster_binlog_close_connection == BCCC_restart) { ndb_binlog_tables_inited= FALSE; + trans_commit_stmt(thd); close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); ndb_binlog_index= 0; goto restart; } @@ -4288,7 +4290,11 @@ err: sql_print_information("Stopping Cluster Binlog"); DBUG_PRINT("info",("Shutting down cluster binlog thread")); thd->proc_info= "Shutting down"; + thd->stmt_da->can_overwrite_status= TRUE; + thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); mysql_mutex_lock(&injector_mutex); /* don't mess with the injector_ndb anymore from other threads */ injector_thd= 0; diff --git a/sql/handler.cc b/sql/handler.cc index efbc335f9b2..9893b3cac16 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1132,6 +1132,7 @@ int ha_commit_trans(THD *thd, bool all) if (thd->in_sub_stmt) { + DBUG_ASSERT(0); /* Since we don't support nested statement transactions in 5.0, we can't commit or rollback stmt transactions while we are inside @@ -1146,7 +1147,6 @@ int ha_commit_trans(THD *thd, bool all) bail out with error even before ha_commit_trans() call. To be 100% safe let us throw error in non-debug builds. */ - DBUG_ASSERT(0); my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); DBUG_RETURN(2); } @@ -1329,6 +1329,7 @@ int ha_rollback_trans(THD *thd, bool all) if (thd->in_sub_stmt) { + DBUG_ASSERT(0); /* If we are inside stored function or trigger we should not commit or rollback current statement transaction. See comment in ha_commit_trans() @@ -1336,7 +1337,6 @@ int ha_rollback_trans(THD *thd, bool all) */ if (!all) DBUG_RETURN(0); - DBUG_ASSERT(0); my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); DBUG_RETURN(1); } diff --git a/sql/handler.h b/sql/handler.h index a7951ddf781..cad97c1f751 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -842,6 +842,7 @@ struct THD_TRANS bool modified_non_trans_table; void reset() { no_2pc= FALSE; modified_non_trans_table= FALSE; } + bool is_empty() const { return ha_list == NULL; } }; diff --git a/sql/item.cc b/sql/item.cc index 92cf2df8a4c..8210f4e6caf 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -301,11 +301,10 @@ my_decimal *Item::val_decimal_from_int(my_decimal *decimal_value) my_decimal *Item::val_decimal_from_string(my_decimal *decimal_value) { String *res; - char *end_ptr; + if (!(res= val_str(&str_value))) - return 0; // NULL or EOM + return NULL; - end_ptr= (char*) res->ptr()+ res->length(); if (str2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_BAD_NUM, res->ptr(), res->length(), res->charset(), decimal_value) & E_DEC_BAD_NUM) diff --git a/sql/lock.cc b/sql/lock.cc index 0743120ec6b..1a77b576e67 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -313,7 +313,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks + sql_lock->lock_count, sql_lock->lock_count, - thd->lock_id, timeout)]; + &thd->lock_info, timeout)]; if (rc) { if (sql_lock->table_count) @@ -627,110 +627,6 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b) } -/** - Find duplicate lock in tables. - - Temporary tables are ignored here like they are ignored in - get_lock_data(). If we allow two opens on temporary tables later, - both functions should be checked. - - @param thd The current thread. - @param needle The table to check for duplicate lock. - @param haystack The list of tables to search for the dup lock. - - @note - This is mainly meant for MERGE tables in INSERT ... SELECT - situations. The 'real', underlying tables can be found only after - the MERGE tables are opened. This function assumes that the tables are - already locked. - - @retval - NULL No duplicate lock found. - @retval - !NULL First table from 'haystack' that matches a lock on 'needle'. -*/ - -TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle, - TABLE_LIST *haystack) -{ - MYSQL_LOCK *mylock; - TABLE **lock_tables; - TABLE *table; - TABLE *table2; - THR_LOCK_DATA **lock_locks; - THR_LOCK_DATA **table_lock_data; - THR_LOCK_DATA **end_data; - THR_LOCK_DATA **lock_data2; - THR_LOCK_DATA **end_data2; - DBUG_ENTER("mysql_lock_have_duplicate"); - - /* - Table may not be defined for derived or view tables. - Table may not be part of a lock for delayed operations. - */ - if (! (table= needle->table) || ! table->lock_count) - goto end; - - /* A temporary table does not have locks. */ - if (table->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE) - goto end; - - /* Get command lock or LOCK TABLES lock. Maybe empty for INSERT DELAYED. */ - if (! (mylock= thd->lock)) - goto end; - - /* If we have less than two tables, we cannot have duplicates. */ - if (mylock->table_count < 2) - goto end; - - lock_locks= mylock->locks; - lock_tables= mylock->table; - - /* Prepare table related variables that don't change in loop. */ - DBUG_ASSERT((table->lock_position < mylock->table_count) && - (table == lock_tables[table->lock_position])); - table_lock_data= lock_locks + table->lock_data_start; - end_data= table_lock_data + table->lock_count; - - for (; haystack; haystack= haystack->next_global) - { - if (haystack->placeholder()) - continue; - table2= haystack->table; - if (table2->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE) - continue; - - /* All tables in list must be in lock. */ - DBUG_ASSERT((table2->lock_position < mylock->table_count) && - (table2 == lock_tables[table2->lock_position])); - - for (lock_data2= lock_locks + table2->lock_data_start, - end_data2= lock_data2 + table2->lock_count; - lock_data2 < end_data2; - lock_data2++) - { - THR_LOCK_DATA **lock_data; - THR_LOCK *lock2= (*lock_data2)->lock; - - for (lock_data= table_lock_data; - lock_data < end_data; - lock_data++) - { - if ((*lock_data)->lock == lock2) - { - DBUG_PRINT("info", ("haystack match: '%s'", haystack->table_name)); - DBUG_RETURN(haystack); - } - } - } - } - - end: - DBUG_PRINT("info", ("no duplicate found")); - DBUG_RETURN(NULL); -} - - /** Unlock a set of external. */ static int unlock_external(THD *thd, TABLE **table,uint count) @@ -851,62 +747,48 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, } -/***************************************************************************** - Lock table based on the name. - This is used when we need total access to a closed, not open table -*****************************************************************************/ - /** - Obtain exclusive metadata locks on the list of tables. + Obtain an exclusive metadata lock on a schema name. - @param thd Thread handle - @param table_list List of tables to lock + @param thd Thread handle. + @param db The database name. - @note This function assumes that no metadata locks were acquired - before calling it. Also it cannot be called while holding - LOCK_open mutex. Both these invariants are enforced by asserts - in MDL_context::acquire_locks(). - @note Initialization of MDL_request members of TABLE_LIST elements - is a responsibility of the caller. + This function cannot be called while holding LOCK_open mutex. + To avoid deadlocks, we do not try to obtain exclusive metadata + locks in LOCK TABLES mode, since in this mode there may be + other metadata locks already taken by the current connection, + and we must not wait for MDL locks while holding locks. - @retval FALSE Success. - @retval TRUE Failure (OOM or thread was killed). + @retval FALSE Success. + @retval TRUE Failure: we're in LOCK TABLES mode, or out of memory, + or this connection was killed. */ -bool lock_table_names(THD *thd, TABLE_LIST *table_list) +bool lock_schema_name(THD *thd, const char *db) { MDL_request_list mdl_requests; MDL_request global_request; - TABLE_LIST *lock_table; + MDL_request mdl_request; - global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE); + if (thd->locked_tables_mode) + { + my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, + ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); + return TRUE; + } - for (lock_table= table_list; lock_table; lock_table= lock_table->next_local) - mdl_requests.push_front(&lock_table->mdl_request); + global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE); + mdl_request.init(MDL_key::SCHEMA, db, "", MDL_EXCLUSIVE); + mdl_requests.push_front(&mdl_request); mdl_requests.push_front(&global_request); if (thd->mdl_context.acquire_locks(&mdl_requests, thd->variables.lock_wait_timeout)) - return 1; - - return 0; -} - - -/** - Release all metadata locks previously obtained by lock_table_names(). - - @param thd Thread handle. - - @note Cannot be called while holding LOCK_open mutex. -*/ + return TRUE; -void unlock_table_names(THD *thd) -{ - DBUG_ENTER("unlock_table_names"); - thd->mdl_context.release_transactional_locks(); - DBUG_VOID_RETURN; + DEBUG_SYNC(thd, "after_wait_locked_schema_name"); + return FALSE; } @@ -941,6 +823,7 @@ bool lock_routine_name(THD *thd, bool is_function, MDL_key::PROCEDURE); MDL_request_list mdl_requests; MDL_request global_request; + MDL_request schema_request; MDL_request mdl_request; if (thd->locked_tables_mode) @@ -954,9 +837,11 @@ bool lock_routine_name(THD *thd, bool is_function, DEBUG_SYNC(thd, "before_wait_locked_pname"); global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE); + schema_request.init(MDL_key::SCHEMA, db, "", MDL_INTENTION_EXCLUSIVE); mdl_request.init(mdl_type, db, name, MDL_EXCLUSIVE); mdl_requests.push_front(&mdl_request); + mdl_requests.push_front(&schema_request); mdl_requests.push_front(&global_request); if (thd->mdl_context.acquire_locks(&mdl_requests, diff --git a/sql/lock.h b/sql/lock.h index 84c7bce0679..0083dd3ba18 100644 --- a/sql/lock.h +++ b/sql/lock.h @@ -60,12 +60,9 @@ void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table); void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock); 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); void broadcast_refresh(void); /* Lock based on name */ -bool lock_table_names(THD *thd, TABLE_LIST *table_list); -void unlock_table_names(THD *thd); +bool lock_schema_name(THD *thd, const char *db); /* Lock based on stored routine name */ bool lock_routine_name(THD *thd, bool is_function, const char *db, const char *name); diff --git a/sql/log.cc b/sql/log.cc index b398cb1e73f..1e4682e4bc3 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -27,7 +27,7 @@ #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "log.h" -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // open_log_table #include "sql_repl.h" #include "sql_delete.h" // mysql_truncate #include "sql_parse.h" // command_name @@ -5447,6 +5447,22 @@ void sql_perror(const char *message) } +/* + Unfortunately, there seems to be no good way + to restore the original streams upon failure. +*/ +static bool redirect_std_streams(const char *file) +{ + if (freopen(file, "a+", stdout) && freopen(file, "a+", stderr)) + { + setbuf(stderr, NULL); + return FALSE; + } + + return TRUE; +} + + bool flush_error_log() { bool result=0; @@ -5474,11 +5490,7 @@ bool flush_error_log() setbuf(stderr, NULL); my_delete(err_renamed, MYF(0)); my_rename(log_error_file, err_renamed, MYF(0)); - if (freopen(log_error_file,"a+",stdout)) - { - freopen(log_error_file,"a+",stderr); - setbuf(stderr, NULL); - } + redirect_std_streams(log_error_file); if ((fd= my_open(err_temp, O_RDONLY, MYF(0))) >= 0) { @@ -5493,13 +5505,7 @@ bool flush_error_log() result= 1; #else my_rename(log_error_file, err_renamed, MYF(0)); - if (freopen(log_error_file,"a+",stdout)) - { - FILE *reopen; - reopen= freopen(log_error_file,"a+",stderr); - setbuf(stderr, NULL); - } - else + if (redirect_std_streams(log_error_file)) result= 1; #endif mysql_mutex_unlock(&LOCK_error_log); @@ -5551,25 +5557,9 @@ static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff, #endif /* _WIN32 */ -/** - Prints a printf style message to the error log and, under NT, to the - Windows event log. - - This function prints the message into a buffer and then sends that buffer - to other functions to write that message to other logging sources. - - @param event_type Type of event to write (Error, Warning, or Info) - @param format Printf style format of message - @param args va_list list of arguments for the message - - @returns - The function always returns 0. The return value is present in the - signature to be compatible with other logging routines, which could - return an error (e.g. logging to the log tables) -*/ - #ifndef EMBEDDED_LIBRARY -static void print_buffer_to_file(enum loglevel level, const char *buffer) +static void print_buffer_to_file(enum loglevel level, const char *buffer, + size_t length) { time_t skr; struct tm tm_tmp; @@ -5583,7 +5573,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer) localtime_r(&skr, &tm_tmp); start=&tm_tmp; - fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d [%s] %s\n", + fprintf(stderr, "%02d%02d%02d %2d:%02d:%02d [%s] %.*s\n", start->tm_year % 100, start->tm_mon+1, start->tm_mday, @@ -5592,7 +5582,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer) start->tm_sec, (level == ERROR_LEVEL ? "ERROR" : level == WARNING_LEVEL ? "Warning" : "Note"), - buffer); + (int) length, buffer); fflush(stderr); @@ -5600,7 +5590,22 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer) DBUG_VOID_RETURN; } +/** + Prints a printf style message to the error log and, under NT, to the + Windows event log. + This function prints the message into a buffer and then sends that buffer + to other functions to write that message to other logging sources. + + @param level The level of the msg significance + @param format Printf style format of message + @param args va_list list of arguments for the message + + @returns + The function always returns 0. The return value is present in the + signature to be compatible with other logging routines, which could + return an error (e.g. logging to the log tables) +*/ int vprint_msg_to_log(enum loglevel level, const char *format, va_list args) { char buff[1024]; @@ -5608,7 +5613,7 @@ int vprint_msg_to_log(enum loglevel level, const char *format, va_list args) DBUG_ENTER("vprint_msg_to_log"); length= my_vsnprintf(buff, sizeof(buff), format, args); - print_buffer_to_file(level, buff); + print_buffer_to_file(level, buff, length); #ifdef _WIN32 print_buffer_to_nt_eventlog(level, buff, length, sizeof(buff)); @@ -5616,7 +5621,7 @@ int vprint_msg_to_log(enum loglevel level, const char *format, va_list args) DBUG_RETURN(0); } -#endif /*EMBEDDED_LIBRARY*/ +#endif /* EMBEDDED_LIBRARY */ void sql_print_error(const char *format, ...) diff --git a/sql/log_event.cc b/sql/log_event.cc index 5236a2794cf..ea7f4b4b245 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -3332,6 +3332,19 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, thd->table_map_for_update= (table_map)table_map_for_update; thd->set_invoker(&user, &host); + /* + Flag if we need to rollback the statement transaction on + slave if it by chance succeeds. + If we expected a non-zero error code and get nothing and, + it is a concurrency issue or ignorable issue, effects + of the statement should be rolled back. + */ + if (expected_error && + (ignored_error_code(expected_error) || + concurrency_error_code(expected_error))) + { + thd->variables.option_bits|= OPTION_MASTER_SQL_ERROR; + } /* Execute the query (note that we bypass dispatch_command()) */ Parser_state parser_state; if (!parser_state.init(thd, thd->query(), thd->query_length())) @@ -3340,6 +3353,8 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, log_slow_statement(thd); } + thd->variables.option_bits&= ~OPTION_MASTER_SQL_ERROR; + /* Resetting the enable_slow_log thd variable. @@ -3382,7 +3397,6 @@ START SLAVE; . Query: '%s'", expected_error, thd->query()); general_log_write(thd, COM_QUERY, thd->query(), thd->query_length()); compare_errors: - /* In the slave thread, we may sometimes execute some DROP / * 40005 TEMPORARY * / TABLE that come from parts of binlogs (likely if we @@ -3430,26 +3444,8 @@ Default database: '%s'. Query: '%s'", DBUG_PRINT("info",("error ignored")); clear_all_errors(thd, const_cast<Relay_log_info*>(rli)); thd->killed= THD::NOT_KILLED; - /* - When an error is expected and matches the actual error the - slave does not report any error and by consequence changes - on transactional tables are not rolled back in the function - close_thread_tables(). For that reason, we explicitly roll - them back here. - */ - if (expected_error && expected_error == actual_error) - trans_rollback_stmt(thd); } /* - 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 && - (concurrency_error_code(expected_error) || - ignored_error_code(expected_error))) - trans_rollback_stmt(thd); - - /* Other cases: mostly we expected no error and get one. */ else if (thd->is_slave_error || thd->is_fatal_error) @@ -3516,7 +3512,6 @@ 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); /* 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 @@ -3719,6 +3714,7 @@ bool Start_log_event_v3::write(IO_CACHE* file) int Start_log_event_v3::do_apply_event(Relay_log_info const *rli) { DBUG_ENTER("Start_log_event_v3::do_apply_event"); + int error= 0; switch (binlog_version) { case 3: @@ -3731,7 +3727,7 @@ int Start_log_event_v3::do_apply_event(Relay_log_info const *rli) */ if (created) { - close_temporary_tables(thd); + error= close_temporary_tables(thd); cleanup_load_tmpdir(); } else @@ -3759,7 +3755,7 @@ int Start_log_event_v3::do_apply_event(Relay_log_info const *rli) Can distinguish, based on the value of 'created': this event was generated at master startup. */ - close_temporary_tables(thd); + error= close_temporary_tables(thd); } /* Otherwise, can't distinguish a Start_log_event generated at @@ -3771,7 +3767,7 @@ int Start_log_event_v3::do_apply_event(Relay_log_info const *rli) /* this case is impossible */ DBUG_RETURN(1); } - DBUG_RETURN(0); + DBUG_RETURN(error); } #endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */ @@ -4946,7 +4942,22 @@ error: thd->catalog= 0; thd->set_db(NULL, 0); /* will free the current database */ thd->set_query(NULL, 0); + thd->stmt_da->can_overwrite_status= TRUE; + thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; close_thread_tables(thd); + /* + - If inside a multi-statement transaction, + defer the release of metadata locks until the current + transaction is either committed or rolled back. This prevents + other statements from modifying the table for the entire + duration of this transaction. This provides commit ordering + and guarantees serializability across multiple transactions. + - If in autocommit mode, or outside a transactional context, + automatically release metadata locks of the current statement. + */ + if (! thd->in_multi_stmt_transaction_mode()) + thd->mdl_context.release_transactional_locks(); DBUG_EXECUTE_IF("LOAD_DATA_INFILE_has_fatal_error", thd->is_slave_error= 0; thd->is_fatal_error= 1;); @@ -5531,11 +5542,9 @@ int Xid_log_event::do_apply_event(Relay_log_info const *rli) /* For a slave Xid_log_event is COMMIT */ general_log_print(thd, COM_QUERY, "COMMIT /* implicit, from Xid_log_event */"); - if (!(res= trans_commit(thd))) - { - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); - } + res= trans_commit(thd); /* Automatically rolls back on error. */ + thd->mdl_context.release_transactional_locks(); + return res; } @@ -7610,8 +7619,6 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli) We should not honour --slave-skip-errors at this point as we are having severe errors which should not be skiped. */ - mysql_unlock_tables(thd, thd->lock); - thd->lock= 0; thd->is_slave_error= 1; const_cast<Relay_log_info*>(rli)->slave_close_thread_tables(thd); DBUG_RETURN(ERR_BAD_TABLE_DEF); diff --git a/sql/mdl.cc b/sql/mdl.cc index 0426a410d98..ca66799baed 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -284,8 +284,6 @@ public: public: /** The key of the object (data) being protected. */ MDL_key key; - void *cached_object; - mdl_cached_object_release_hook cached_object_release_hook; /** Read-write lock protecting this lock context. @@ -362,8 +360,6 @@ public: MDL_lock(const MDL_key *key_arg) : key(key_arg), - cached_object(NULL), - cached_object_release_hook(NULL), m_ref_usage(0), m_ref_release(0), m_is_destroyed(FALSE) @@ -405,14 +401,15 @@ public: /** - An implementation of the global metadata lock. The only locking modes - which are supported at the moment are SHARED and INTENTION EXCLUSIVE. + An implementation of the scoped metadata lock. The only locking modes + which are supported at the moment are SHARED and INTENTION EXCLUSIVE + and EXCLUSIVE */ -class MDL_global_lock : public MDL_lock +class MDL_scoped_lock : public MDL_lock { public: - MDL_global_lock(const MDL_key *key_arg) + MDL_scoped_lock(const MDL_key *key_arg) : MDL_lock(key_arg) { } @@ -674,9 +671,6 @@ void MDL_map::remove(MDL_lock *lock) { uint ref_usage, ref_release; - if (lock->cached_object) - (*lock->cached_object_release_hook)(lock->cached_object); - /* Destroy the MDL_lock object, but ensure that anyone that is holding a reference to the object is not remaining, if so he @@ -838,7 +832,8 @@ inline MDL_lock *MDL_lock::create(const MDL_key *mdl_key) switch (mdl_key->mdl_namespace()) { case MDL_key::GLOBAL: - return new MDL_global_lock(mdl_key); + case MDL_key::SCHEMA: + return new MDL_scoped_lock(mdl_key); default: return new MDL_object_lock(mdl_key); } @@ -886,67 +881,6 @@ uint MDL_ticket::get_deadlock_weight() const } -/** - Helper functions and macros to be used for killable waiting in metadata - locking subsystem. - - @sa THD::enter_cond()/exit_cond()/killed. - - @note We can't use THD::enter_cond()/exit_cond()/killed directly here - since this will make metadata subsystem dependent on THD class - and thus prevent us from writing unit tests for it. And usage of - wrapper functions to access THD::killed/enter_cond()/exit_cond() - will probably introduce too much overhead. -*/ - -#define MDL_ENTER_COND(A, B, C, D) \ - mdl_enter_cond(A, B, C, D, __func__, __FILE__, __LINE__) - -static inline const char *mdl_enter_cond(THD *thd, - st_my_thread_var *mysys_var, - mysql_cond_t *cond, - mysql_mutex_t *mutex, - const char *calling_func, - const char *calling_file, - const unsigned int calling_line) -{ - mysql_mutex_assert_owner(mutex); - - mysys_var->current_mutex= mutex; - mysys_var->current_cond= cond; - - DEBUG_SYNC(thd, "mdl_enter_cond"); - - return set_thd_proc_info(thd, "Waiting for table", - calling_func, calling_file, calling_line); -} - -#define MDL_EXIT_COND(A, B, C, D) \ - mdl_exit_cond(A, B, C, D, __func__, __FILE__, __LINE__) - -static inline void mdl_exit_cond(THD *thd, - st_my_thread_var *mysys_var, - mysql_mutex_t *mutex, - const char* old_msg, - const char *calling_func, - const char *calling_file, - const unsigned int calling_line) -{ - DBUG_ASSERT(mutex == mysys_var->current_mutex); - - mysql_mutex_unlock(mutex); - mysql_mutex_lock(&mysys_var->mutex); - mysys_var->current_mutex= NULL; - mysys_var->current_cond= NULL; - mysql_mutex_unlock(&mysys_var->mutex); - - DEBUG_SYNC(thd, "mdl_exit_cond"); - - (void) set_thd_proc_info(thd, old_msg, calling_func, - calling_file, calling_line); -} - - /** Construct an empty wait slot. */ MDL_wait::MDL_wait() @@ -1026,15 +960,14 @@ MDL_wait::timed_wait(THD *thd, struct timespec *abs_timeout, { const char *old_msg; enum_wait_status result; - st_my_thread_var *mysys_var= my_thread_var; int wait_result= 0; mysql_mutex_lock(&m_LOCK_wait_status); - old_msg= MDL_ENTER_COND(thd, mysys_var, &m_COND_wait_status, - &m_LOCK_wait_status); + old_msg= thd_enter_cond(thd, &m_COND_wait_status, &m_LOCK_wait_status, + "Waiting for table"); - while (!m_wait_status && !mysys_var->abort && + while (!m_wait_status && !thd_killed(thd) && wait_result != ETIMEDOUT && wait_result != ETIME) wait_result= mysql_cond_timedwait(&m_COND_wait_status, &m_LOCK_wait_status, abs_timeout); @@ -1053,14 +986,14 @@ MDL_wait::timed_wait(THD *thd, struct timespec *abs_timeout, false, which means that the caller intends to restart the wait. */ - if (mysys_var->abort) + if (thd_killed(thd)) m_wait_status= KILLED; else if (set_status_on_timeout) m_wait_status= TIMEOUT; } result= m_wait_status; - MDL_EXIT_COND(thd, mysys_var, &m_LOCK_wait_status, old_msg); + thd_exit_cond(thd, old_msg); return result; } @@ -1181,11 +1114,6 @@ void MDL_lock::reschedule_waiters() */ m_waiting.remove_ticket(ticket); m_granted.add_ticket(ticket); - - /* If we are granting an X lock, release the cached object. */ - if (ticket->get_type() == MDL_EXCLUSIVE && cached_object) - (*cached_object_release_hook)(cached_object); - cached_object= NULL; } /* If we could not update the wait slot of the waiter, @@ -1201,61 +1129,66 @@ void MDL_lock::reschedule_waiters() /** - Compatibility (or rather "incompatibility") matrices for global metadata + Compatibility (or rather "incompatibility") matrices for scoped metadata lock. Arrays of bitmaps which elements specify which granted/waiting locks are incompatible with type of lock being requested. - Here is how types of individual locks are translated to type of global lock: + Here is how types of individual locks are translated to type of scoped lock: ----------------+-------------+ Type of request | Correspond. | - for indiv. lock | global lock | + for indiv. lock | scoped lock | ----------------+-------------+ S, SH, SR, SW | IS | SNW, SNRW, X | IX | SNW, SNRW -> X | IX (*) | The first array specifies if particular type of request can be satisfied - if there is granted global lock of certain type. + if there is granted scoped lock of certain type. - | Type of active | - Request | global lock | - type | IS(**) IX S | - ---------+----------------+ - IS | + + + | - IX | + + - | - S | + - + | + | Type of active | + Request | scoped lock | + type | IS(**) IX S X | + ---------+------------------+ + IS | + + + + | + IX | + + - - | + S | + - + - | + X | + - - - | The second array specifies if particular type of request can be satisfied - if there is already waiting request for the global lock of certain type. + if there is already waiting request for the scoped lock of certain type. I.e. it specifies what is the priority of different lock types. - | Pending | - Request | global lock | - type | IS(**) IX S | - ---------+--------------+ - IS | + + + | - IX | + + - | - S | + + + | + | Pending | + Request | scoped lock | + type | IS(**) IX S X | + ---------+-----------------+ + IS | + + + + | + IX | + + - - | + S | + + + - | + X | + + + + | Here: "+" -- means that request can be satisfied "-" -- means that request can't be satisfied and should wait - (*) Since for upgradable locks we always take intention exclusive global + (*) Since for upgradable locks we always take intention exclusive scoped lock at the same time when obtaining the shared lock, there is no need to obtain such lock during the upgrade itself. - (**) Since intention shared global locks are compatible with all other + (**) Since intention shared scoped locks are compatible with all other type of locks we don't even have any accounting for them. */ -const MDL_lock::bitmap_t MDL_global_lock::m_granted_incompatible[MDL_TYPE_END] = +const MDL_lock::bitmap_t MDL_scoped_lock::m_granted_incompatible[MDL_TYPE_END] = { - MDL_BIT(MDL_SHARED), MDL_BIT(MDL_INTENTION_EXCLUSIVE), 0, 0, 0, 0, 0, 0 + MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED), + MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_INTENTION_EXCLUSIVE), 0, 0, 0, 0, 0, + MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED) | MDL_BIT(MDL_INTENTION_EXCLUSIVE) }; -const MDL_lock::bitmap_t MDL_global_lock::m_waiting_incompatible[MDL_TYPE_END] = +const MDL_lock::bitmap_t MDL_scoped_lock::m_waiting_incompatible[MDL_TYPE_END] = { - MDL_BIT(MDL_SHARED), 0, 0, 0, 0, 0, 0, 0 + MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED), + MDL_BIT(MDL_EXCLUSIVE), 0, 0, 0, 0, 0, 0 }; @@ -1655,10 +1588,6 @@ MDL_context::try_acquire_lock_impl(MDL_request *mdl_request, { lock->m_granted.add_ticket(ticket); - if (mdl_request->type == MDL_EXCLUSIVE && lock->cached_object) - (*lock->cached_object_release_hook)(lock->cached_object); - lock->cached_object= NULL; - mysql_prlock_unlock(&lock->m_rwlock); m_tickets.push_front(ticket); @@ -1894,7 +1823,7 @@ extern "C" int mdl_request_ptr_cmp(const void* ptr1, const void* ptr2) @note The list of requests should not contain non-exclusive lock requests. There should not be any acquired locks in the context. - @note Assumes that one already owns global intention exclusive lock. + @note Assumes that one already owns scoped intention exclusive lock. @retval FALSE Success @retval TRUE Failure @@ -1911,13 +1840,6 @@ bool MDL_context::acquire_locks(MDL_request_list *mdl_requests, if (req_count == 0) return FALSE; - /* - To reduce deadlocks, the server acquires all exclusive - locks at once. For shared locks, try_acquire_lock() is - used instead. - */ - DBUG_ASSERT(m_tickets.is_empty() || m_tickets.front() == m_trans_sentinel); - /* Sort requests according to MDL_key. */ if (! (sort_buf= (MDL_request **)my_malloc(req_count * sizeof(MDL_request*), @@ -2434,69 +2356,6 @@ bool MDL_ticket::has_pending_conflicting_lock() const /** - Associate pointer to an opaque object with a lock. - - @param cached_object Pointer to the object - @param release_hook Cleanup function to be called when MDL subsystem - decides to remove lock or associate another object. - - This is used to cache a pointer to TABLE_SHARE in the lock - structure. Such caching can save one acquisition of LOCK_open - and one table definition cache lookup for every table. - - Since the pointer may be stored only inside an acquired lock, - the caching is only effective when there is more than one lock - granted on a given table. - - This function has the following usage pattern: - - try to acquire an MDL lock - - when done, call for mdl_get_cached_object(). If it returns NULL, our - thread has the only lock on this table. - - look up TABLE_SHARE in the table definition cache - - call mdl_set_cache_object() to assign the share to the opaque pointer. - - The release hook is invoked when the last shared metadata - lock on this name is released. -*/ - -void -MDL_ticket::set_cached_object(void *cached_object, - mdl_cached_object_release_hook release_hook) -{ - DBUG_ENTER("mdl_set_cached_object"); - DBUG_PRINT("enter", ("db=%s name=%s cached_object=%p", - m_lock->key.db_name(), m_lock->key.name(), - cached_object)); - /* - TODO: This assumption works now since we do get_cached_object() - and set_cached_object() in the same critical section. Once - this becomes false we will have to call release_hook here and - use additional mutex protecting 'cached_object' member. - */ - DBUG_ASSERT(!m_lock->cached_object); - - m_lock->cached_object= cached_object; - m_lock->cached_object_release_hook= release_hook; - - DBUG_VOID_RETURN; -} - - -/** - Get a pointer to an opaque object that associated with the lock. - - @param ticket Lock ticket for the lock which the object is associated to. - - @return Pointer to an opaque object associated with the lock. -*/ - -void *MDL_ticket::get_cached_object() -{ - return m_lock->cached_object; -} - - -/** Releases metadata locks that were acquired after a specific savepoint. @note Used to release tickets acquired during a savepoint unit. diff --git a/sql/mdl.h b/sql/mdl.h index 43d88c143c0..c8acd69c0f1 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -40,15 +40,16 @@ class Deadlock_detection_visitor; Type of metadata lock request. @sa Comments for MDL_object_lock::can_grant_lock() and - MDL_global_lock::can_grant_lock() for details. + MDL_scoped_lock::can_grant_lock() for details. */ enum enum_mdl_type { /* - An intention exclusive metadata lock. Used only for global locks. + An intention exclusive metadata lock. Used only for scoped locks. Owner of this type of lock can acquire upgradable exclusive locks on individual objects. - Compatible with other IX locks, but is incompatible with global S lock. + Compatible with other IX locks, but is incompatible with scoped S and + X locks. */ MDL_INTENTION_EXCLUSIVE= 0, /* @@ -179,6 +180,7 @@ public: MDL_key is also used outside of the MDL subsystem. */ enum enum_mdl_namespace { GLOBAL=0, + SCHEMA, TABLE, FUNCTION, PROCEDURE, @@ -396,9 +398,6 @@ public: public: bool has_pending_conflicting_lock() const; - void *get_cached_object(); - void set_cached_object(void *cached_object, - mdl_cached_object_release_hook release_hook); MDL_context *get_ctx() const { return m_ctx; } bool is_upgradable_or_exclusive() const { @@ -646,6 +645,8 @@ private: closes all open HANDLERs. However, one can open a few HANDLERs after entering the read only mode. + * LOCK TABLES locks include intention exclusive locks on + involved schemas. */ Ticket_list m_tickets; /** @@ -720,10 +721,10 @@ void mdl_destroy(); extern bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use, bool needs_thr_lock_abort); -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); +extern "C" const char* thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond, + mysql_mutex_t *mutex, const char *msg); +extern "C" void thd_exit_cond(MYSQL_THD thd, const char *old_msg); + #ifndef DBUG_OFF extern mysql_mutex_t LOCK_open; #endif diff --git a/sql/mysqld.cc b/sql/mysqld.cc index cb579324644..afc515a9d8c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -27,8 +27,8 @@ // reset_status_vars #include "strfunc.h" // find_set_from_flags #include "parse_file.h" // File_parser_dummy_hook -#include "sql_db.h" // my_database_names_free, - // my_database_names_init +#include "sql_db.h" // my_dboptions_cache_free + // my_dboptions_cache_init #include "sql_table.h" // release_ddl_log, execute_ddl_log_recovery #include "sql_connect.h" // free_max_user_conn, init_max_user_conn, // handle_one_connection @@ -183,7 +183,7 @@ typedef fp_except fp_except_t; # define fpu_control_t unsigned int # define _FPU_EXTENDED 0x300 # define _FPU_DOUBLE 0x200 -# if defined(__GNUC__) || defined(__SUNPRO_CC) +# if defined(__GNUC__) || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x590) # define _FPU_GETCW(cw) asm volatile ("fnstcw %0" : "=m" (*&cw)) # define _FPU_SETCW(cw) asm volatile ("fldcw %0" : : "m" (*&cw)) # else @@ -601,7 +601,7 @@ SHOW_COMP_OPTION have_profiling; pthread_key(MEM_ROOT**,THR_MALLOC); pthread_key(THD*, THR_THD); mysql_mutex_t LOCK_thread_count; -mysql_mutex_t LOCK_mysql_create_db, LOCK_open, +mysql_mutex_t LOCK_open, LOCK_status, LOCK_global_read_lock, LOCK_error_log, LOCK_uuid_generator, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, @@ -1420,7 +1420,7 @@ void clean_up(bool print_message) bitmap_free(&slave_error_mask); #endif my_tz_free(); - my_database_names_free(); + my_dboptions_cache_free(); #ifndef NO_EMBEDDED_ACCESS_CHECKS servers_free(1); acl_free(1); @@ -1525,8 +1525,6 @@ static void wait_for_signal_thread_to_end() static void clean_up_mutexes() { - mysql_mutex_destroy(&LOCK_mysql_create_db); - mysql_mutex_destroy(&LOCK_lock_db); mysql_rwlock_destroy(&LOCK_grant); mysql_mutex_destroy(&LOCK_open); mysql_mutex_destroy(&LOCK_thread_count); @@ -3445,7 +3443,7 @@ static int init_common_variables() use_temp_pool= 0; #endif - if (my_database_names_init()) + if (my_dboptions_cache_init()) return 1; /* @@ -3502,9 +3500,6 @@ You should consider changing lower_case_table_names to 1 or 2", static int init_thread_environment() { - mysql_mutex_init(key_LOCK_mysql_create_db, - &LOCK_mysql_create_db, MY_MUTEX_INIT_SLOW); - mysql_mutex_init(key_LOCK_lock_db, &LOCK_lock_db, MY_MUTEX_INIT_SLOW); mysql_mutex_init(key_LOCK_open, &LOCK_open, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_thread_count, &LOCK_thread_count, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_status, &LOCK_status, MY_MUTEX_INIT_FAST); @@ -3703,7 +3698,6 @@ static void end_ssl() static int init_server_components() { - FILE *reopen; DBUG_ENTER("init_server_components"); /* We need to call each of these following functions to ensure that @@ -3751,8 +3745,8 @@ static int init_server_components() if (freopen(log_error_file, "a+", stdout)) #endif { - reopen= freopen(log_error_file, "a+", stderr); - setbuf(stderr, NULL); + if (freopen(log_error_file, "a+", stderr)) + setbuf(stderr, NULL); } } } @@ -6967,7 +6961,7 @@ mysqld_get_one_option(int optid, *val= 0; val+= 2; while (*val && my_isspace(mysqld_charset, *val)) - *val++; + val++; if (!*val) { sql_print_error("Bad syntax in replicate-rewrite-db - empty TO db!\n"); @@ -7685,8 +7679,8 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids, key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create, key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log, key_LOCK_gdl, key_LOCK_global_read_lock, key_LOCK_global_system_variables, - key_LOCK_lock_db, key_LOCK_manager, - key_LOCK_mysql_create_db, key_LOCK_open, key_LOCK_prepared_stmt_count, + key_LOCK_manager, + key_LOCK_open, key_LOCK_prepared_stmt_count, key_LOCK_rpl_status, key_LOCK_server_started, key_LOCK_status, key_LOCK_system_variables_hash, key_LOCK_table_share, key_LOCK_thd_data, key_LOCK_user_conn, key_LOCK_uuid_generator, key_LOG_LOCK_log, @@ -7724,9 +7718,7 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_gdl, "LOCK_gdl", PSI_FLAG_GLOBAL}, { &key_LOCK_global_read_lock, "LOCK_global_read_lock", PSI_FLAG_GLOBAL}, { &key_LOCK_global_system_variables, "LOCK_global_system_variables", PSI_FLAG_GLOBAL}, - { &key_LOCK_lock_db, "LOCK_lock_db", PSI_FLAG_GLOBAL}, { &key_LOCK_manager, "LOCK_manager", PSI_FLAG_GLOBAL}, - { &key_LOCK_mysql_create_db, "LOCK_mysql_create_db", PSI_FLAG_GLOBAL}, { &key_LOCK_open, "LOCK_open", PSI_FLAG_GLOBAL}, { &key_LOCK_prepared_stmt_count, "LOCK_prepared_stmt_count", PSI_FLAG_GLOBAL}, { &key_LOCK_rpl_status, "LOCK_rpl_status", PSI_FLAG_GLOBAL}, diff --git a/sql/mysqld.h b/sql/mysqld.h index 91bdc600cda..22e757e6e8a 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -228,8 +228,8 @@ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_prep_xids, key_LOCK_connection_count, key_LOCK_crypt, key_LOCK_delayed_create, key_LOCK_delayed_insert, key_LOCK_delayed_status, key_LOCK_error_log, key_LOCK_gdl, key_LOCK_global_read_lock, key_LOCK_global_system_variables, - key_LOCK_lock_db, key_LOCK_logger, key_LOCK_manager, - key_LOCK_mysql_create_db, key_LOCK_open, key_LOCK_prepared_stmt_count, + key_LOCK_logger, key_LOCK_manager, + key_LOCK_open, key_LOCK_prepared_stmt_count, key_LOCK_rpl_status, key_LOCK_server_started, key_LOCK_status, key_LOCK_table_share, key_LOCK_thd_data, key_LOCK_user_conn, key_LOCK_uuid_generator, key_LOG_LOCK_log, @@ -316,7 +316,7 @@ extern MYSQL_PLUGIN_IMPORT key_map key_map_full; /* Should be threaded /* Server mutex locks and condition variables. */ -extern mysql_mutex_t LOCK_mysql_create_db, LOCK_open, LOCK_lock_db, +extern mysql_mutex_t LOCK_open, LOCK_user_locks, LOCK_status, LOCK_error_log, LOCK_delayed_insert, LOCK_uuid_generator, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 43934551016..caf28fdd83e 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -1535,13 +1535,11 @@ bool partition_info::set_up_charset_field_preps() i= 0; while ((field= *(ptr++))) { - CHARSET_INFO *cs; uchar *field_buf; LINT_INIT(field_buf); if (!field_is_partition_charset(field)) continue; - cs= ((Field_str*)field)->charset(); size= field->pack_length(); if (!(field_buf= (uchar*) sql_calloc(size))) goto error; diff --git a/sql/protocol.cc b/sql/protocol.cc index 87a54eaf10d..953656d3a4f 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -658,7 +658,11 @@ void Protocol::end_partial_result_set(THD *thd_arg) bool Protocol::flush() { #ifndef EMBEDDED_LIBRARY - return net_flush(&thd->net); + bool error; + thd->stmt_da->can_overwrite_status= TRUE; + error= net_flush(&thd->net); + thd->stmt_da->can_overwrite_status= FALSE; + return error; #else return 0; #endif @@ -698,7 +702,8 @@ bool Protocol::send_result_set_metadata(List<Item> *list, uint flags) if (flags & SEND_NUM_ROWS) { // Packet with number of elements uchar *pos= net_store_length(buff, list->elements); - (void) my_net_write(&thd->net, buff, (size_t) (pos-buff)); + if (my_net_write(&thd->net, buff, (size_t) (pos-buff))) + DBUG_RETURN(1); } #ifndef DBUG_OFF @@ -803,7 +808,7 @@ bool Protocol::send_result_set_metadata(List<Item> *list, uint flags) if (flags & SEND_DEFAULTS) item->send(&prot, &tmp); // Send default value if (prot.write()) - break; /* purecov: inspected */ + DBUG_RETURN(1); #ifndef DBUG_OFF field_types[count++]= field.type; #endif @@ -816,8 +821,9 @@ bool Protocol::send_result_set_metadata(List<Item> *list, uint flags) to show that there is no cursor. Send no warning information, as it will be sent at statement end. */ - write_eof_packet(thd, &thd->net, thd->server_status, - thd->warning_info->statement_warn_count()); + if (write_eof_packet(thd, &thd->net, thd->server_status, + thd->warning_info->statement_warn_count())) + DBUG_RETURN(1); } DBUG_RETURN(prepare_for_send(list->elements)); diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc index 03c369394bf..af9b452acd8 100644 --- a/sql/rpl_rli.cc +++ b/sql/rpl_rli.cc @@ -1257,7 +1257,23 @@ void Relay_log_info::clear_tables_to_lock() void Relay_log_info::slave_close_thread_tables(THD *thd) { + thd->stmt_da->can_overwrite_status= TRUE; + thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; + close_thread_tables(thd); + /* + - If inside a multi-statement transaction, + defer the release of metadata locks until the current + transaction is either committed or rolled back. This prevents + other statements from modifying the table for the entire + duration of this transaction. This provides commit ordering + and guarantees serializability across multiple transactions. + - If in autocommit mode, or outside a transactional context, + automatically release metadata locks of the current statement. + */ + if (! thd->in_multi_stmt_transaction_mode()) + thd->mdl_context.release_transactional_locks(); clear_tables_to_lock(); } #endif diff --git a/sql/set_var.cc b/sql/set_var.cc index ec9c09f02a3..9daaf883ea8 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -27,7 +27,6 @@ #include "mysqld.h" // lc_messages_dir #include "sys_vars_shared.h" #include "transaction.h" -#include "sql_base.h" // close_thread_tables #include "sql_locale.h" // my_locale_by_number, // my_locale_by_name #include "strfunc.h" // find_set_from_flags, find_set diff --git a/sql/slave.cc b/sql/slave.cc index 25860138cf2..dff6b6946d4 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3032,7 +3032,6 @@ err: change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE); DBUG_ASSERT(thd->net.buff != 0); net_end(&thd->net); // destructor will not free it, because net.vio is 0 - close_thread_tables(thd); mysql_mutex_lock(&LOCK_thread_count); THD_CHECK_SENTRY(thd); delete thd; @@ -3263,11 +3262,8 @@ log '%s' at position %s, relay log '%s' position: %s", RPL_LOG_NAME, mysql_mutex_lock(&rli->data_lock); if (rli->slave_skip_counter) { - char *pos; - pos= strmake(saved_log_name, rli->group_relay_log_name, FN_REFLEN - 1); - pos= '\0'; - pos= strmake(saved_master_log_name, rli->group_master_log_name, FN_REFLEN - 1); - pos= '\0'; + strmake(saved_log_name, rli->group_relay_log_name, FN_REFLEN - 1); + strmake(saved_master_log_name, rli->group_master_log_name, FN_REFLEN - 1); saved_log_pos= rli->group_relay_log_pos; saved_master_log_pos= rli->group_master_log_pos; saved_skip= rli->slave_skip_counter; diff --git a/sql/sp.cc b/sql/sp.cc index 5328471f4c0..0265ef45a2a 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -450,10 +450,7 @@ static TABLE *open_proc_table_for_update(THD *thd) if (!proc_table_intact.check(table, &proc_table_def)) DBUG_RETURN(table); - close_thread_tables(thd); - DBUG_RETURN(NULL); - } @@ -856,6 +853,7 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp, } end: + thd->lex->sphead= NULL; lex_end(thd->lex); thd->lex= old_lex; return ret; @@ -1159,8 +1157,6 @@ sp_create_routine(THD *thd, int type, sp_head *sp) done: thd->count_cuted_fields= saved_count_cuted_fields; thd->variables.sql_mode= saved_mode; - - close_thread_tables(thd); /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -1239,8 +1235,6 @@ sp_drop_routine(THD *thd, int type, sp_name *name) sp_cache_flush_obsolete(spc, &sp); } } - - close_thread_tables(thd); /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -1348,7 +1342,6 @@ sp_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics) sp_cache_invalidate(); } err: - close_thread_tables(thd); /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -1370,6 +1363,7 @@ sp_drop_db_routines(THD *thd, char *db) TABLE *table; int ret; uint key_len; + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); DBUG_ENTER("sp_drop_db_routines"); DBUG_PRINT("enter", ("db: %s", db)); @@ -1410,6 +1404,11 @@ sp_drop_db_routines(THD *thd, char *db) table->file->ha_index_end(); close_thread_tables(thd); + /* + Make sure to only release the MDL lock on mysql.proc, not other + metadata locks DROP DATABASE might have acquired. + */ + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); err: DBUG_RETURN(ret); @@ -2142,6 +2141,7 @@ sp_load_for_information_schema(THD *thd, TABLE *proc_table, String *db, newlex.current_select= NULL; sp= sp_compile(thd, &defstr, sql_mode, creation_ctx); *free_sp_head= 1; + thd->lex->sphead= NULL; lex_end(thd->lex); thd->lex= old_lex; return sp; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index f75acf11984..11f138e67be 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -38,6 +38,7 @@ #include "set_var.h" #include "sql_parse.h" // cleanup_items #include "sql_base.h" // close_thread_tables +#include "transaction.h" // trans_commit_stmt /* Sufficient max length of printed destinations and frame offsets (all uints). @@ -795,6 +796,7 @@ sp_head::~sp_head() while ((lex= (LEX *)m_lex.pop())) { THD *thd= lex->thd; + thd->lex->sphead= NULL; lex_end(thd->lex); delete thd->lex; thd->lex= lex; @@ -1995,16 +1997,23 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) arguments evaluation. If arguments evaluation required prelocking mode, we'll leave it here. */ + thd->lex->unit.cleanup(); + if (!thd->in_sub_stmt) { - thd->lex->unit.cleanup(); + thd->stmt_da->can_overwrite_status= TRUE; + thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; + } - thd_proc_info(thd, "closing tables"); - close_thread_tables(thd); - thd_proc_info(thd, 0); + thd_proc_info(thd, "closing tables"); + close_thread_tables(thd); + thd_proc_info(thd, 0); - thd->rollback_item_tree_changes(); - } + if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode()) + thd->mdl_context.release_transactional_locks(); + + thd->rollback_item_tree_changes(); DBUG_PRINT("info",(" %.*s: eval args done", (int) m_name.length, m_name.str)); @@ -2197,6 +2206,7 @@ sp_head::restore_lex(THD *thd) merge_table_list(thd, sublex->query_tables, sublex); if (! sublex->sp_lex_in_use) { + sublex->sphead= NULL; lex_end(sublex); delete sublex; } @@ -2806,12 +2816,27 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, DBUG_PRINT("info",("exec_core returned: %d", res)); } - m_lex->unit.cleanup(); + /* + Call after unit->cleanup() to close open table + key read. + */ + if (open_tables) + { + m_lex->unit.cleanup(); + /* Here we also commit or rollback the current statement. */ + if (! thd->in_sub_stmt) + { + thd->stmt_da->can_overwrite_status= TRUE; + thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; + } + thd_proc_info(thd, "closing tables"); + close_thread_tables(thd); + thd_proc_info(thd, 0); - thd_proc_info(thd, "closing tables"); - /* Here we also commit or rollback the current statement. */ - close_thread_tables(thd); - thd_proc_info(thd, 0); + if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode()) + thd->mdl_context.release_transactional_locks(); + } if (m_lex->query_tables_own_last) { diff --git a/sql/sp_head.h b/sql/sp_head.h index 9796c49fdfb..b2446c8f680 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -682,6 +682,8 @@ public: { if (m_lex_resp) { + /* Prevent endless recursion. */ + m_lex->sphead= NULL; lex_end(m_lex); delete m_lex; } diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 047cec76486..b08f8008b59 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -525,8 +525,7 @@ sp_cursor::open(THD *thd) MYF(0)); return -1; } - if (mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR, &result, - &server_side_cursor)) + if (mysql_open_cursor(thd, &result, &server_side_cursor)) return -1; return 0; } diff --git a/sql/spatial.cc b/sql/spatial.cc index f96196cb836..f1dd0e6cebd 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -142,11 +142,10 @@ Geometry *Geometry::construct(Geometry_buffer *buffer, { uint32 geom_type; Geometry *result; - char byte_order; if (data_len < SRID_SIZE + WKB_HEADER_SIZE) // < 4 + (1 + 4) return NULL; - byte_order= data[SRID_SIZE]; + /* + 1 to skip the byte order (stored in position SRID_SIZE). */ geom_type= uint4korr(data + SRID_SIZE + 1); if (!(result= create_by_typeid(buffer, (int) geom_type))) return NULL; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 074f1047d67..19373507955 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -27,7 +27,7 @@ #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */ #include "sql_priv.h" #include "sql_acl.h" // MYSQL_DB_FIELD_COUNT, ACL_ACCESS -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // close_mysql_tables #include "key.h" // key_copy, key_cmp_if_same, key_restore #include "sql_show.h" // append_identifier #include "sql_table.h" // build_table_filename @@ -678,16 +678,15 @@ my_bool acl_reload(THD *thd) To avoid deadlocks we should obtain table locks before obtaining acl_cache->lock mutex. */ - bzero((char*) tables, sizeof(tables)); - tables[0].alias= tables[0].table_name= (char*) "host"; - tables[1].alias= tables[1].table_name= (char*) "user"; - tables[2].alias= tables[2].table_name= (char*) "db"; - tables[0].db=tables[1].db=tables[2].db=(char*) "mysql"; + tables[0].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("host"), "host", TL_READ); + tables[1].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("user"), "user", TL_READ); + tables[2].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("db"), "db", TL_READ); tables[0].next_local= tables[0].next_global= tables+1; tables[1].next_local= tables[1].next_global= tables+2; - tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ; tables[0].open_type= tables[1].open_type= tables[2].open_type= OT_BASE_ONLY; - init_mdl_requests(tables); if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { @@ -731,9 +730,7 @@ my_bool acl_reload(THD *thd) if (old_initialized) mysql_mutex_unlock(&acl_cache->lock); end: - trans_commit_implicit(thd); - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); + close_mysql_tables(thd); DBUG_RETURN(return_val); } @@ -1586,6 +1583,7 @@ bool change_password(THD *thd, const char *host, const char *user, /* Buffer should be extended when password length is extended. */ char buff[512]; ulong query_length; + bool save_binlog_row_based; uint new_password_len= (uint) strlen(new_password); bool result= 1; DBUG_ENTER("change_password"); @@ -1615,10 +1613,17 @@ bool change_password(THD *thd, const char *host, const char *user, DBUG_RETURN(0); } #endif - if (!(table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT))) DBUG_RETURN(1); + /* + This statement will be replicated as a statement, even when using + row-based replication. The flag will be reset at the end of the + statement. + */ + if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row())) + thd->clear_current_stmt_binlog_format_row(); + mysql_mutex_lock(&acl_cache->lock); ACL_USER *acl_user; if (!(acl_user= find_acl_user(host, user, TRUE))) @@ -1653,7 +1658,13 @@ bool change_password(THD *thd, const char *host, const char *user, FALSE, FALSE, FALSE, 0); } end: - close_thread_tables(thd); + close_mysql_tables(thd); + + /* Restore the state of binlog format */ + DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); + if (save_binlog_row_based) + thd->set_current_stmt_binlog_format_row(); + DBUG_RETURN(result); } @@ -1924,9 +1935,8 @@ static bool test_if_create_new_users(THD *thd) { TABLE_LIST tl; ulong db_access; - bzero((char*) &tl,sizeof(tl)); - tl.db= (char*) "mysql"; - tl.table_name= (char*) "user"; + tl.init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("user"), "user", TL_WRITE); create_new_users= 1; db_access=acl_get(sctx->host, sctx->ip, @@ -3062,7 +3072,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, class LEX_COLUMN *column; List_iterator <LEX_COLUMN> column_iter(columns); - if (open_and_lock_tables(thd, table_list, TRUE, 0)) + if (open_normal_and_derived_tables(thd, table_list, 0)) DBUG_RETURN(TRUE); while ((column = column_iter++)) @@ -3084,7 +3094,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, DBUG_RETURN(TRUE); column_priv|= column->rights; } - close_thread_tables(thd); + close_mysql_tables(thd); } else { @@ -3116,20 +3126,18 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, /* open the mysql.tables_priv and mysql.columns_priv tables */ - bzero((char*) &tables,sizeof(tables)); - tables[0].alias=tables[0].table_name= (char*) "user"; - tables[1].alias=tables[1].table_name= (char*) "tables_priv"; - tables[2].alias=tables[2].table_name= (char*) "columns_priv"; + tables[0].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("user"), "user", TL_WRITE); + tables[1].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("tables_priv"), + "tables_priv", TL_WRITE); + tables[2].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("columns_priv"), + "columns_priv", TL_WRITE); tables[0].next_local= tables[0].next_global= tables+1; /* Don't open column table if we don't need it ! */ - tables[1].next_local= - tables[1].next_global= ((column_priv || - (revoke_grant && - ((rights & COL_ACLS) || columns.elements))) - ? tables+2 : 0); - tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE; - tables[0].db=tables[1].db=tables[2].db=(char*) "mysql"; - init_mdl_requests(tables); + if (column_priv || (revoke_grant && ((rights & COL_ACLS) || columns.elements))) + tables[1].next_local= tables[1].next_global= tables+2; /* This statement will be replicated as a statement, even when using @@ -3176,7 +3184,6 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, 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 */ /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -3363,13 +3370,11 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, /* open the mysql.user and mysql.procs_priv tables */ - bzero((char*) &tables,sizeof(tables)); - tables[0].alias=tables[0].table_name= (char*) "user"; - tables[1].alias=tables[1].table_name= (char*) "procs_priv"; + tables[0].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("user"), "user", TL_WRITE); + tables[1].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("procs_priv"), "procs_priv", TL_WRITE); tables[0].next_local= tables[0].next_global= tables+1; - tables[0].lock_type=tables[1].lock_type=TL_WRITE; - tables[0].db=tables[1].db=(char*) "mysql"; - init_mdl_requests(tables); /* This statement will be replicated as a statement, even when using @@ -3404,7 +3409,6 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc, if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // Should never happen - close_thread_tables(thd); /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -3520,13 +3524,11 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, } /* open the mysql.user and mysql.db tables */ - bzero((char*) &tables,sizeof(tables)); - tables[0].alias=tables[0].table_name=(char*) "user"; - tables[1].alias=tables[1].table_name=(char*) "db"; + tables[0].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("user"), "user", TL_WRITE); + tables[1].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("db"), "db", TL_WRITE); tables[0].next_local= tables[0].next_global= tables+1; - tables[0].lock_type=tables[1].lock_type=TL_WRITE; - tables[0].db=tables[1].db=(char*) "mysql"; - init_mdl_requests(tables); /* This statement will be replicated as a statement, even when using @@ -3561,7 +3563,6 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // This should never happen - close_thread_tables(thd); /* purecov: deadcode */ /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -3621,7 +3622,6 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list, } mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); if (!result) my_ok(thd); @@ -3882,10 +3882,7 @@ static my_bool grant_reload_procs_priv(THD *thd) table.open_type= OT_BASE_ONLY; if (open_and_lock_tables(thd, &table, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) - { - close_thread_tables(thd); DBUG_RETURN(TRUE); - } mysql_rwlock_wrlock(&LOCK_grant); /* Save a copy of the current hash if we need to undo the grant load */ @@ -3907,7 +3904,7 @@ static my_bool grant_reload_procs_priv(THD *thd) } mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); + close_mysql_tables(thd); DBUG_RETURN(return_val); } @@ -3939,14 +3936,14 @@ my_bool grant_reload(THD *thd) if (!initialized) DBUG_RETURN(0); - bzero((char*) tables, sizeof(tables)); - tables[0].alias= tables[0].table_name= (char*) "tables_priv"; - tables[1].alias= tables[1].table_name= (char*) "columns_priv"; - tables[0].db= tables[1].db= (char *) "mysql"; + tables[0].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("tables_priv"), + "tables_priv", TL_READ); + tables[1].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("columns_priv"), + "columns_priv", TL_READ); tables[0].next_local= tables[0].next_global= tables+1; - tables[0].lock_type= tables[1].lock_type= TL_READ; tables[0].open_type= tables[1].open_type= OT_BASE_ONLY; - init_mdl_requests(tables); /* To avoid deadlocks we should obtain table locks before @@ -3978,9 +3975,7 @@ my_bool grant_reload(THD *thd) free_root(&old_mem,MYF(0)); } mysql_rwlock_unlock(&LOCK_grant); - trans_commit_implicit(thd); - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); + close_mysql_tables(thd); /* It is OK failing to load procs_priv table because we may be @@ -5218,22 +5213,23 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables) DBUG_RETURN(-1); } - bzero((char*) tables, GRANT_TABLES*sizeof(*tables)); - tables->alias= tables->table_name= (char*) "user"; - (tables+1)->alias= (tables+1)->table_name= (char*) "db"; - (tables+2)->alias= (tables+2)->table_name= (char*) "tables_priv"; - (tables+3)->alias= (tables+3)->table_name= (char*) "columns_priv"; - (tables+4)->alias= (tables+4)->table_name= (char*) "procs_priv"; + tables->init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("user"), "user", TL_WRITE); + (tables+1)->init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("db"), "db", TL_WRITE); + (tables+2)->init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("tables_priv"), + "tables_priv", TL_WRITE); + (tables+3)->init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("columns_priv"), + "columns_priv", TL_WRITE); + (tables+4)->init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("procs_priv"), + "procs_priv", TL_WRITE); tables->next_local= tables->next_global= tables+1; (tables+1)->next_local= (tables+1)->next_global= tables+2; (tables+2)->next_local= (tables+2)->next_global= tables+3; (tables+3)->next_local= (tables+3)->next_global= tables+4; - tables->lock_type= (tables+1)->lock_type= - (tables+2)->lock_type= (tables+3)->lock_type= - (tables+4)->lock_type= TL_WRITE; - tables->db= (tables+1)->db= (tables+2)->db= - (tables+3)->db= (tables+4)->db= (char*) "mysql"; - init_mdl_requests(tables); #ifdef HAVE_REPLICATION /* @@ -5257,7 +5253,6 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables) if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT)) { // This should never happen - close_thread_tables(thd); DBUG_RETURN(-1); } @@ -5831,7 +5826,6 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) { int result; String wrong_users; - ulong sql_mode; LEX_USER *user_name, *tmp_user_name; List_iterator <LEX_USER> user_list(list); TABLE_LIST tables[GRANT_TABLES]; @@ -5880,7 +5874,6 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) } some_users_created= TRUE; - sql_mode= thd->variables.sql_mode; if (replace_user_table(thd, tables[0].table, *user_name, 0, 0, 1, 0)) { append_user(&wrong_users, user_name); @@ -5897,7 +5890,6 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list) result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -5982,7 +5974,6 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list) result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); thd->variables.sql_mode= old_sql_mode; /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); @@ -6079,7 +6070,6 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length()); mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -6277,8 +6267,6 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) write_bin_log(thd, FALSE, thd->query(), thd->query_length()); mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); - /* Restore the state of binlog format */ DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); if (save_binlog_row_based) @@ -6425,7 +6413,6 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, mysql_mutex_unlock(&acl_cache->lock); mysql_rwlock_unlock(&LOCK_grant); - close_thread_tables(thd); thd->pop_internal_handler(); /* Restore the state of binlog format */ diff --git a/sql/sql_base.cc b/sql/sql_base.cc index f746edef83f..e810d5fc091 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -53,6 +53,7 @@ #include "rpl_filter.h" #include "sql_table.h" // build_table_filename #include "datadict.h" // dd_frm_type() +#include "sql_hset.h" // Hash_set #ifdef __WIN__ #include <io.h> #endif @@ -755,27 +756,6 @@ TABLE_SHARE *get_cached_table_share(const char *db, const char *table_name) } -#ifdef DISABLED_UNTIL_GRL_IS_MADE_PART_OF_MDL -/** - @brief Mark table share as having one more user (increase its reference - count). - - @param share Table share for which reference count should be increased. -*/ - -static void reference_table_share(TABLE_SHARE *share) -{ - DBUG_ENTER("reference_table_share"); - DBUG_ASSERT(share->ref_count); - mysql_mutex_assert_owner(&LOCK_open); - share->ref_count++; - DBUG_PRINT("exit", ("share: 0x%lx ref_count: %u", - (ulong) share, share->ref_count)); - DBUG_VOID_RETURN; -} -#endif - - /* Create a list for all open tables matching SQL expression @@ -1422,6 +1402,9 @@ void close_thread_tables(THD *thd) DEBUG_SYNC(thd, "before_close_thread_tables"); #endif + DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt || + (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)); + /* Detach MERGE children after every statement. Even under LOCK TABLES. */ for (table= thd->open_tables; table; table= table->next) { @@ -1466,28 +1449,6 @@ void close_thread_tables(THD *thd) Mark all temporary tables used by this statement as free for reuse. */ mark_temp_tables_as_free_for_reuse(thd); - /* - Let us commit transaction for statement. Since in 5.0 we only have - one statement transaction and don't allow several nested statement - transactions this call will do nothing if we are inside of stored - function or trigger (i.e. statement transaction is already active and - does not belong to statement for which we do close_thread_tables()). - TODO: This should be fixed in later releases. - */ - if (!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL)) - { - thd->stmt_da->can_overwrite_status= TRUE; - thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); - thd->stmt_da->can_overwrite_status= FALSE; - - /* - Reset transaction state, but only if we're not inside a - sub-statement of a prelocked statement. - */ - if (thd->locked_tables_mode <= LTM_LOCK_TABLES || - thd->lex->requires_prelocking()) - thd->transaction.stmt.reset(); - } if (thd->locked_tables_mode) { @@ -1548,26 +1509,6 @@ void close_thread_tables(THD *thd) if (thd->open_tables) close_open_tables(thd); - /* - - If inside a multi-statement transaction, - defer the release of metadata locks until the current - transaction is either committed or rolled back. This prevents - other statements from modifying the table for the entire - duration of this transaction. This provides commit ordering - and guarantees serializability across multiple transactions. - - If closing a system table, defer the release of metadata locks - to the caller. We have no sentinel in MDL subsystem to guard - transactional locks from system tables locks, so don't know - which locks are which here. - - If in autocommit mode, or outside a transactional context, - automatically release metadata locks of the current statement. - */ - if (! thd->in_multi_stmt_transaction_mode() && - ! (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)) - { - thd->mdl_context.release_transactional_locks(); - } - DBUG_VOID_RETURN; } @@ -1582,7 +1523,14 @@ bool close_thread_table(THD *thd, TABLE **table_ptr) DBUG_ASSERT(table->key_read == 0); DBUG_ASSERT(!table->file || table->file->inited == handler::NONE); mysql_mutex_assert_not_owner(&LOCK_open); - + /* + The metadata lock must be released after giving back + the table to the table cache. + */ + DBUG_ASSERT(thd->mdl_context.is_lock_owner(MDL_key::TABLE, + table->s->db.str, + table->s->table_name.str, + MDL_SHARED)); table->mdl_ticket= NULL; mysql_mutex_lock(&thd->LOCK_thd_data); @@ -1634,7 +1582,7 @@ static inline uint tmpkeyval(THD *thd, TABLE *table) creates one DROP TEMPORARY TABLE binlog event for each pseudo-thread */ -void close_temporary_tables(THD *thd) +bool close_temporary_tables(THD *thd) { DBUG_ENTER("close_temporary_tables"); TABLE *table; @@ -1642,9 +1590,10 @@ void close_temporary_tables(THD *thd) TABLE *prev_table; /* Assume thd->variables.option_bits has OPTION_QUOTE_SHOW_CREATE */ bool was_quote_show= TRUE; + bool error= 0; if (!thd->temporary_tables) - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); if (!mysql_bin_log.is_open()) { @@ -1655,7 +1604,7 @@ void close_temporary_tables(THD *thd) close_temporary(table, 1, 1); } thd->temporary_tables= 0; - DBUG_VOID_RETURN; + DBUG_RETURN(FALSE); } /* Better add "if exists", in case a RESET MASTER has been done */ @@ -1754,11 +1703,27 @@ void close_temporary_tables(THD *thd) qinfo.db= db.ptr(); qinfo.db_len= db.length(); thd->variables.character_set_client= cs_save; - if (mysql_bin_log.write(&qinfo)) + + thd->stmt_da->can_overwrite_status= TRUE; + if ((error= (mysql_bin_log.write(&qinfo) || error))) { - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, MYF(0), - "Failed to write the DROP statement for temporary tables to binary log"); + /* + If we're here following THD::cleanup, thence the connection + has been closed already. So lets print a message to the + error log instead of pushing yet another error into the + stmt_da. + + Also, we keep the error flag so that we propagate the error + up in the stack. This way, if we're the SQL thread we notice + that close_temporary_tables failed. (Actually, the SQL + thread only calls close_temporary_tables while applying old + Start_log_event_v3 events.) + */ + sql_print_error("Failed to write the DROP statement for " + "temporary tables to binary log"); } + thd->stmt_da->can_overwrite_status= FALSE; + thd->variables.pseudo_thread_id= save_pseudo_thread_id; thd->thread_specific_used= save_thread_specific_used; } @@ -1771,7 +1736,8 @@ void close_temporary_tables(THD *thd) if (!was_quote_show) thd->variables.option_bits&= ~OPTION_QUOTE_SHOW_CREATE; /* restore option */ thd->temporary_tables=0; - DBUG_VOID_RETURN; + + DBUG_RETURN(error); } /* @@ -1809,15 +1775,13 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, } -/* +/** Test that table is unique (It's only exists once in the table list) - SYNOPSIS - unique_table() - thd thread handle - table table which should be checked - table_list list of tables - check_alias whether to check tables' aliases + @param thd thread handle + @param table table which should be checked + @param table_list list of tables + @param check_alias whether to check tables' aliases NOTE: to exclude derived tables from check we use following mechanism: a) during derived table processing set THD::derived_tables_processing @@ -1828,7 +1792,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, processing loop, because multi-update call fix_fields() for some its items (which mean JOIN::prepare for subqueries) before unique_table call to detect which tables should be locked for write). - c) unique_table skip all tables which belong to SELECT with + c) find_dup_table skip all tables which belong to SELECT with SELECT::exclude_from_table_unique_test set. Also SELECT::exclude_from_table_unique_test used to exclude from check tables of main SELECT of multi-delete and multi-update @@ -1840,17 +1804,17 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table, TODO: when we will have table/view change detection we can do this check only once for PS/SP - RETURN - found duplicate - 0 if table is unique + @retval !=0 found duplicate + @retval 0 if table is unique */ -TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, - bool check_alias) +static +TABLE_LIST* find_dup_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, + bool check_alias) { TABLE_LIST *res; const char *d_name, *t_name, *t_alias; - DBUG_ENTER("unique_table"); + DBUG_ENTER("find_dup_table"); DBUG_PRINT("enter", ("table alias: %s", table->alias)); /* @@ -1865,6 +1829,9 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, */ if (table->table) { + /* All MyISAMMRG children are plain MyISAM tables. */ + DBUG_ASSERT(table->table->file->ht->db_type != DB_TYPE_MRG_MYISAM); + /* temporary table is always unique */ if (table->table && table->table->s->tmp_table != NO_TMP_TABLE) DBUG_RETURN(0); @@ -1886,8 +1853,7 @@ TABLE_LIST* unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, Table is unique if it is present only once in the global list of tables and once in the list of table locks. */ - if (! (res= find_table_in_global_list(table_list, d_name, t_name)) && - ! (res= mysql_lock_have_duplicate(thd, table, table_list))) + if (! (res= find_table_in_global_list(table_list, d_name, t_name))) break; /* Skip if same underlying table. */ @@ -1926,6 +1892,42 @@ next: } +/** + Test that the subject table of INSERT/UPDATE/DELETE/CREATE + or (in case of MyISAMMRG) one of its children are not used later + in the query. + + For MyISAMMRG tables, it is assumed that all the underlying + tables of @c table (if any) are listed right after it and that + their @c parent_l field points at the main table. + + + @retval non-NULL The table list element for the table that + represents the duplicate. + @retval NULL No duplicates found. +*/ + +TABLE_LIST* +unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, + bool check_alias) +{ + TABLE_LIST *dup; + if (table->table && table->table->file->ht->db_type == DB_TYPE_MRG_MYISAM) + { + TABLE_LIST *child; + dup= NULL; + /* Check duplicates of all merge children. */ + for (child= table->next_global; child && child->parent_l == table; + child= child->next_global) + { + if ((dup= find_dup_table(thd, child, child->next_global, check_alias))) + break; + } + } + else + dup= find_dup_table(thd, table, table_list, check_alias); + return dup; +} /* Issue correct error message in case we found 2 duplicate tables which prevent some update operation @@ -2253,51 +2255,6 @@ void drop_open_table(THD *thd, TABLE *table, const char *db_name, } -/* - Wait for condition but allow the user to send a kill to mysqld - - SYNOPSIS - wait_for_condition() - thd Thread handler - mutex mutex that is currently hold that is associated with condition - Will be unlocked on return - cond Condition to wait for -*/ - -void wait_for_condition(THD *thd, mysql_mutex_t *mutex, mysql_cond_t *cond) -{ - /* Wait until the current table is up to date */ - const char *proc_info; - thd->mysys_var->current_mutex= mutex; - thd->mysys_var->current_cond= cond; - proc_info=thd->proc_info; - thd_proc_info(thd, "Waiting for table"); - DBUG_ENTER("wait_for_condition"); - DEBUG_SYNC(thd, "waiting_for_table"); - if (!thd->killed) - mysql_cond_wait(cond, mutex); - - /* - We must unlock mutex first to avoid deadlock becasue conditions are - sent to this thread by doing locks in the following order: - lock(mysys_var->mutex) - lock(mysys_var->current_mutex) - - One by effect of this that one can only use wait_for_condition with - condition variables that are guranteed to not disapper (freed) even if this - mutex is unlocked - */ - - mysql_mutex_unlock(mutex); - mysql_mutex_lock(&thd->mysys_var->mutex); - thd->mysys_var->current_mutex= 0; - thd->mysys_var->current_cond= 0; - thd_proc_info(thd, proc_info); - mysql_mutex_unlock(&thd->mysys_var->mutex); - DBUG_VOID_RETURN; -} - - /** Check that table exists in table definition cache, on disk or in some storage engine. @@ -2363,20 +2320,6 @@ end: /** - @brief Helper function used by MDL subsystem for releasing TABLE_SHARE - objects in cases when it no longer wants to cache reference to it. -*/ - -void table_share_release_hook(void *share) -{ - mysql_mutex_lock(&LOCK_open); - release_table_share((TABLE_SHARE*) share); - broadcast_refresh(); - mysql_mutex_unlock(&LOCK_open); -} - - -/** An error handler which converts, if possible, ER_LOCK_DEADLOCK error that can occur when we are trying to acquire a metadata lock to a request for back-off and re-start of open_tables() process. @@ -2868,96 +2811,61 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, DBUG_RETURN(FALSE); mysql_mutex_lock(&LOCK_open); -#ifdef DISABLED_UNTIL_GRL_IS_MADE_PART_OF_MDL - if (!(share= (TABLE_SHARE *) mdl_ticket->get_cached_object())) -#endif - { - if (!(share= get_table_share_with_create(thd, table_list, key, - key_length, OPEN_VIEW, - &error, - hash_value))) - goto err_unlock2; - - if (share->is_view) - { - /* - If parent_l of the table_list is non null then a merge table - has this view as child table, which is not supported. - */ - if (table_list->parent_l) - { - my_error(ER_WRONG_MRG_TABLE, MYF(0)); - goto err_unlock; - } - - /* - This table is a view. Validate its metadata version: in particular, - that it was a view when the statement was prepared. - */ - if (check_and_update_table_version(thd, table_list, share)) - goto err_unlock; - if (table_list->i_s_requested_object & OPEN_TABLE_ONLY) - goto err_unlock; - - /* Open view */ - if (open_new_frm(thd, share, alias, - (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | - HA_GET_INDEX | HA_TRY_READ_ONLY), - READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD, - thd->open_options, - 0, table_list, mem_root)) - goto err_unlock; - - /* TODO: Don't free this */ - release_table_share(share); - DBUG_ASSERT(table_list->view); + if (!(share= get_table_share_with_create(thd, table_list, key, + key_length, OPEN_VIEW, + &error, + hash_value))) + goto err_unlock2; - mysql_mutex_unlock(&LOCK_open); - DBUG_RETURN(FALSE); - } + if (share->is_view) + { /* - Note that situation when we are trying to open a table for what - was a view during previous execution of PS will be handled in by - the caller. Here we should simply open our table even if - TABLE_LIST::view is true. + If parent_l of the table_list is non null then a merge table + has this view as child table, which is not supported. */ - - if (table_list->i_s_requested_object & OPEN_VIEW_ONLY) + if (table_list->parent_l) + { + my_error(ER_WRONG_MRG_TABLE, MYF(0)); goto err_unlock; + } -#ifdef DISABLED_UNTIL_GRL_IS_MADE_PART_OF_MDL /* - We are going to to store extra reference to the share in MDL-subsystem - so we need to increase reference counter; + This table is a view. Validate its metadata version: in particular, + that it was a view when the statement was prepared. */ - reference_table_share(share); - mdl_ticket->set_cached_object(share, table_share_release_hook); -#endif - } -#ifdef DISABLED_UNTIL_GRL_IS_MADE_PART_OF_MDL - else - { - if (table_list->view) - { - DBUG_ASSERT(thd->m_reprepare_observer); - check_and_update_table_version(thd, table_list, share); - /* Always an error. */ - DBUG_ASSERT(thd->is_error()); + if (check_and_update_table_version(thd, table_list, share)) goto err_unlock; - } - /* When we have cached TABLE_SHARE we know that is not a view. */ - if (table_list->i_s_requested_object & OPEN_VIEW_ONLY) + if (table_list->i_s_requested_object & OPEN_TABLE_ONLY) goto err_unlock; - /* - We are going to use this share for construction of new TABLE object - so reference counter should be increased. - */ - reference_table_share(share); + /* Open view */ + if (open_new_frm(thd, share, alias, + (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | + HA_GET_INDEX | HA_TRY_READ_ONLY), + READ_KEYINFO | COMPUTE_TYPES | EXTRA_RECORD, + thd->open_options, + 0, table_list, mem_root)) + goto err_unlock; + + /* TODO: Don't free this */ + release_table_share(share); + + DBUG_ASSERT(table_list->view); + + mysql_mutex_unlock(&LOCK_open); + DBUG_RETURN(FALSE); } -#endif + /* + Note that situation when we are trying to open a table for what + was a view during previous execution of PS will be handled in by + the caller. Here we should simply open our table even if + TABLE_LIST::view is true. + */ + + if (table_list->i_s_requested_object & OPEN_VIEW_ONLY) + goto err_unlock; /* If the version changes while we're opening the tables, @@ -3095,8 +3003,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, table_list->table= table; DBUG_ASSERT(table->key_read == 0); /* Tables may be reused in a sub statement. */ - if (table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN)) - table->file->extra(HA_EXTRA_DETACH_CHILDREN); + DBUG_ASSERT(! table->file->extra(HA_EXTRA_IS_ATTACHED_CHILDREN)); DBUG_RETURN(FALSE); err_lock: @@ -3267,6 +3174,7 @@ Locked_tables_list::init_locked_tables(THD *thd) return FALSE; } + /** Leave LTM_LOCK_TABLES mode if it's been entered. @@ -3303,7 +3211,12 @@ Locked_tables_list::unlock_locked_tables(THD *thd) } thd->leave_locked_tables_mode(); + DBUG_ASSERT(thd->transaction.stmt.is_empty()); close_thread_tables(thd); + /* + We rely on the caller to implicitly commit the + transaction and release transactional locks. + */ } /* After closing tables we can free memory used for storing lock @@ -3885,38 +3798,15 @@ end_unlock: Open_table_context::Open_table_context(THD *thd, uint flags) :m_failed_table(NULL), m_start_of_statement_svp(thd->mdl_context.mdl_savepoint()), - m_global_mdl_request(NULL), m_timeout(flags & MYSQL_LOCK_IGNORE_TIMEOUT ? LONG_TIMEOUT : thd->variables.lock_wait_timeout), m_flags(flags), m_action(OT_NO_ACTION), - m_has_locks((thd->in_multi_stmt_transaction_mode() && - thd->mdl_context.has_locks()) || - thd->mdl_context.trans_sentinel()) + m_has_locks(thd->mdl_context.has_locks()) {} /** - Get MDL_request object for global intention exclusive lock which - is acquired during opening tables for statements which take - upgradable shared metadata locks. -*/ - -MDL_request *Open_table_context::get_global_mdl_request(THD *thd) -{ - if (! m_global_mdl_request) - { - if ((m_global_mdl_request= new (thd->mem_root) MDL_request())) - { - m_global_mdl_request->init(MDL_key::GLOBAL, "", "", - MDL_INTENTION_EXCLUSIVE); - } - } - return m_global_mdl_request; -} - - -/** Check if we can back-off and set back off action if we can. Otherwise report and return error. @@ -3964,13 +3854,23 @@ request_backoff_action(enum_open_table_action action_arg, my_error(ER_LOCK_DEADLOCK, MYF(0)); return TRUE; } - m_action= action_arg; /* If auto-repair or discovery are requested, a pointer to table list element must be provided. */ - DBUG_ASSERT((m_action != OT_DISCOVER && m_action != OT_REPAIR) || table); - m_failed_table= table; + if (table) + { + DBUG_ASSERT(action_arg == OT_DISCOVER || action_arg == OT_REPAIR); + m_failed_table= (TABLE_LIST*) current_thd->alloc(sizeof(TABLE_LIST)); + if (m_failed_table == NULL) + return TRUE; + m_failed_table->init_one_table(table->db, table->db_length, + table->table_name, + table->table_name_length, + table->alias, TL_WRITE); + m_failed_table->mdl_request.set_type(MDL_EXCLUSIVE); + } + m_action= action_arg; return FALSE; } @@ -3992,11 +3892,6 @@ Open_table_context:: recover_from_failed_open(THD *thd) { bool result= FALSE; - /* - Remove reference to released ticket from MDL_request. - */ - if (m_global_mdl_request) - m_global_mdl_request->ticket= NULL; /* Execute the action. */ switch (m_action) { @@ -4008,19 +3903,9 @@ recover_from_failed_open(THD *thd) break; case OT_DISCOVER: { - MDL_request mdl_global_request; - MDL_request mdl_xlock_request(&m_failed_table->mdl_request); - MDL_request_list mdl_requests; - - mdl_global_request.init(MDL_key::GLOBAL, "", "", - MDL_INTENTION_EXCLUSIVE); - mdl_xlock_request.set_type(MDL_EXCLUSIVE); - - mdl_requests.push_front(&mdl_xlock_request); - mdl_requests.push_front(&mdl_global_request); - - if ((result= - thd->mdl_context.acquire_locks(&mdl_requests, get_timeout()))) + if ((result= lock_table_names(thd, m_failed_table, NULL, + get_timeout(), + MYSQL_OPEN_SKIP_TEMPORARY))) break; mysql_mutex_lock(&LOCK_open); @@ -4037,19 +3922,9 @@ recover_from_failed_open(THD *thd) } case OT_REPAIR: { - MDL_request mdl_global_request; - MDL_request mdl_xlock_request(&m_failed_table->mdl_request); - MDL_request_list mdl_requests; - - mdl_global_request.init(MDL_key::GLOBAL, "", "", - MDL_INTENTION_EXCLUSIVE); - mdl_xlock_request.set_type(MDL_EXCLUSIVE); - - mdl_requests.push_front(&mdl_xlock_request); - mdl_requests.push_front(&mdl_global_request); - - if ((result= - thd->mdl_context.acquire_locks(&mdl_requests, get_timeout()))) + if ((result= lock_table_names(thd, m_failed_table, NULL, + get_timeout(), + MYSQL_OPEN_SKIP_TEMPORARY))) break; mysql_mutex_lock(&LOCK_open); @@ -4320,6 +4195,7 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables, bool error= FALSE; bool safe_to_ignore_table= FALSE; DBUG_ENTER("open_and_process_table"); + DEBUG_SYNC(thd, "open_and_process_table"); /* Ignore placeholders for derived tables. After derived tables @@ -4543,32 +4419,40 @@ end: DBUG_RETURN(error); } +extern "C" uchar *schema_set_get_key(const uchar *record, size_t *length, + my_bool not_used __attribute__((unused))) +{ + TABLE_LIST *table=(TABLE_LIST*) record; + *length= table->db_length; + return (uchar*) table->db; +} /** - Acquire upgradable (SNW, SNRW) metadata locks on tables to be opened - for LOCK TABLES or a DDL statement. Under LOCK TABLES, we can't take + Acquire upgradable (SNW, SNRW) metadata locks on tables used by + LOCK TABLES or by a DDL statement. Under LOCK TABLES, we can't take new locks, so use open_tables_check_upgradable_mdl() instead. - @param thd Thread context. - @param tables_start Start of list of tables on which upgradable locks - should be acquired. - @param tables_end End of list of tables. - @param ot_ctx Context of open_tables() operation. - @param flags Bitmap of flags to modify how the tables will be - open, see open_table() description for details. + @param thd Thread context. + @param tables_start Start of list of tables on which upgradable locks + should be acquired. + @param tables_end End of list of tables. + @param lock_wait_timeout Seconds to wait before timeout. + @param flags Bitmap of flags to modify how the tables will be + open, see open_table() description for details. @retval FALSE Success. @retval TRUE Failure (e.g. connection was killed) */ -static bool -open_tables_acquire_upgradable_mdl(THD *thd, TABLE_LIST *tables_start, - TABLE_LIST *tables_end, - Open_table_context *ot_ctx, - uint flags) +bool +lock_table_names(THD *thd, + TABLE_LIST *tables_start, TABLE_LIST *tables_end, + ulong lock_wait_timeout, uint flags) { MDL_request_list mdl_requests; TABLE_LIST *table; + MDL_request global_request; + Hash_set<TABLE_LIST, schema_set_get_key> schema_set; DBUG_ASSERT(!thd->locked_tables_mode); @@ -4581,30 +4465,37 @@ open_tables_acquire_upgradable_mdl(THD *thd, TABLE_LIST *tables_start, (table->open_type != OT_BASE_ONLY && ! (flags & MYSQL_OPEN_SKIP_TEMPORARY) && find_temporary_table(thd, table)))) + { + if (schema_set.insert(table)) + return TRUE; mdl_requests.push_front(&table->mdl_request); + } } if (! mdl_requests.is_empty()) { - DEBUG_SYNC(thd, "open_tables_acquire_upgradable_mdl"); - - MDL_request *global_request= ot_ctx->get_global_mdl_request(thd); - - if (global_request == NULL) - return TRUE; - mdl_requests.push_front(global_request); + /* + Scoped locks: Take intention exclusive locks on all involved + schemas. + */ + Hash_set<TABLE_LIST, schema_set_get_key>::Iterator it(schema_set); + while ((table= it++)) + { + MDL_request *schema_request= new (thd->mem_root) MDL_request; + if (schema_request == NULL) + return TRUE; + schema_request->init(MDL_key::SCHEMA, table->db, "", + MDL_INTENTION_EXCLUSIVE); + mdl_requests.push_front(schema_request); + } + /* Take the global intention exclusive lock. */ + global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE); + mdl_requests.push_front(&global_request); } - if (thd->mdl_context.acquire_locks(&mdl_requests, ot_ctx->get_timeout())) + if (thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout)) return TRUE; - for (table= tables_start; table && table != tables_end; - table= table->next_global) - { - if (table->mdl_request.type >= MDL_SHARED_NO_WRITE) - table->mdl_request.ticket= NULL; - } - return FALSE; } @@ -4776,12 +4667,21 @@ restart: goto err; } } - else if (open_tables_acquire_upgradable_mdl(thd, *start, - thd->lex->first_not_own_table(), - &ot_ctx, flags)) + else { - error= TRUE; - goto err; + TABLE_LIST *table; + if (lock_table_names(thd, *start, thd->lex->first_not_own_table(), + ot_ctx.get_timeout(), flags)) + { + error= TRUE; + goto err; + } + for (table= *start; table && table != thd->lex->first_not_own_table(); + table= table->next_global) + { + if (table->mdl_request.type >= MDL_SHARED_NO_WRITE) + table->mdl_request.ticket= NULL; + } } } @@ -5354,6 +5254,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type, table= 0; end: + if (table == NULL) + close_thread_tables(thd); thd_proc_info(thd, 0); DBUG_RETURN(table); } @@ -5372,7 +5274,8 @@ end: should work for this statement. @note - The lock will automaticaly be freed by close_thread_tables() + The thr_lock locks will automatically be freed by + close_thread_tables(). @retval FALSE OK. @retval TRUE Error @@ -5383,11 +5286,12 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, Prelocking_strategy *prelocking_strategy) { uint counter; + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); DBUG_ENTER("open_and_lock_tables"); DBUG_PRINT("enter", ("derived handling: %d", derived)); if (open_tables(thd, &tables, &counter, flags, prelocking_strategy)) - DBUG_RETURN(TRUE); + goto err; DBUG_EXECUTE_IF("sleep_open_and_lock_after_open", { const char *old_proc_info= thd->proc_info; @@ -5396,15 +5300,22 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, thd->proc_info= old_proc_info;}); if (lock_tables(thd, tables, counter, flags)) - DBUG_RETURN(TRUE); + goto err; if (derived && (mysql_handle_derived(thd->lex, &mysql_derived_prepare) || (thd->fill_derived_tables() && mysql_handle_derived(thd->lex, &mysql_derived_filling)))) - DBUG_RETURN(TRUE); /* purecov: inspected */ + goto err; DBUG_RETURN(FALSE); +err: + if (! thd->in_sub_stmt) + trans_rollback_stmt(thd); /* Necessary if derived handling failed. */ + close_thread_tables(thd); + /* Don't keep locks for a failed statement. */ + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + DBUG_RETURN(TRUE); } @@ -5430,13 +5341,24 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags) { + DML_prelocking_strategy prelocking_strategy; uint counter; + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); DBUG_ENTER("open_normal_and_derived_tables"); DBUG_ASSERT(!thd->fill_derived_tables()); - if (open_tables(thd, &tables, &counter, flags) || + if (open_tables(thd, &tables, &counter, flags, &prelocking_strategy) || mysql_handle_derived(thd->lex, &mysql_derived_prepare)) - DBUG_RETURN(TRUE); /* purecov: inspected */ + goto end; + DBUG_RETURN(0); +end: + /* No need to rollback statement transaction, it's not started. */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); + close_thread_tables(thd); + /* Don't keep locks for a failed statement. */ + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + + DBUG_RETURN(TRUE); /* purecov: inspected */ } @@ -5453,11 +5375,25 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags) or schema tables) as free for reuse. */ -static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table) +static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table_list) { - for (; table; table= table->next_global) + TABLE_LIST *table; + for (table= table_list; table; table= table->next_global) if (!table->placeholder()) + { table->table->query_id= 0; + } + for (table= table_list; table; table= table->next_global) + if (!table->placeholder()) + { + /* + Detach children of MyISAMMRG tables used in + sub-statements, they will be reattached at open. + This has to be done in a separate loop to make sure + that children have had their query_id cleared. + */ + table->table->file->extra(HA_EXTRA_DETACH_CHILDREN); + } } @@ -5683,6 +5619,14 @@ void close_tables_for_reopen(THD *thd, TABLE_LIST **tables, /* We have to cleanup translation tables of views. */ tmp->cleanup_items(); } + /* + No need to commit/rollback the statement transaction: it's + either not started or we're filling in an INFORMATION_SCHEMA + table on the fly, and thus mustn't manipulate with the + transaction of the enclosing statement. + */ + DBUG_ASSERT(thd->transaction.stmt.is_empty() || + (thd->state_flags & Open_tables_state::BACKUPS_AVAIL)); close_thread_tables(thd); thd->mdl_context.rollback_to_savepoint(start_of_statement_svp); } @@ -5820,7 +5764,7 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table) DBUG_ENTER("update_field_dependencies"); if (thd->mark_used_columns != MARK_COLUMNS_NONE) { - MY_BITMAP *current_bitmap, *other_bitmap; + MY_BITMAP *bitmap; /* We always want to register the used keys, as the column bitmap may have @@ -5831,15 +5775,9 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table) table->merge_keys.merge(field->part_of_key); if (thd->mark_used_columns == MARK_COLUMNS_READ) - { - current_bitmap= table->read_set; - other_bitmap= table->write_set; - } + bitmap= table->read_set; else - { - current_bitmap= table->write_set; - other_bitmap= table->read_set; - } + bitmap= table->write_set; /* The test-and-set mechanism in the bitmap is not reliable during @@ -5848,7 +5786,7 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table) only those columns that are used in the SET clause. I.e they are being set here. See multi_update::prepare() */ - if (bitmap_fast_test_and_set(current_bitmap, field->field_index)) + if (bitmap_fast_test_and_set(bitmap, field->field_index)) { if (thd->mark_used_columns == MARK_COLUMNS_WRITE) { @@ -8756,6 +8694,7 @@ void tdc_remove_table(THD *thd, enum_tdc_remove_table_type remove_type, automatically deleted once it is no longer referenced. */ share->version= 0; + while ((table= it++)) free_cache_entry(table); } @@ -9109,7 +9048,8 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, MYSQL_LOCK_IGNORE_TIMEOUT)) { lex->restore_backup_query_tables_list(&query_tables_list_backup); - goto error; + thd->restore_backup_open_tables_state(backup); + DBUG_RETURN(TRUE); } for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global) @@ -9120,11 +9060,6 @@ open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, lex->restore_backup_query_tables_list(&query_tables_list_backup); DBUG_RETURN(FALSE); - -error: - close_system_tables(thd, backup); - - DBUG_RETURN(TRUE); } @@ -9147,6 +9082,38 @@ close_system_tables(THD *thd, Open_tables_backup *backup) } +/** + A helper function to close a mysql.* table opened + in an auxiliary THD during bootstrap or in the main + connection, when we know that there are no locks + held by the connection due to a preceding implicit + commit. + + This function assumes that there is no + statement transaction started for the operation + itself, since mysql.* tables are not transactional + and when they are used the binlog is off (DDL + binlogging is always statement-based. + + We need this function since we'd like to not + just close the system table, but also release + the metadata lock on it. + + Note, that in LOCK TABLES mode this function + does not release the metadata lock. But in this + mode the table can be opened only if it is locked + explicitly with LOCK TABLES. +*/ + +void +close_mysql_tables(THD *thd) +{ + /* No need to commit/rollback statement transaction, it's not started. */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); + close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); +} + /* Open and lock one system table for update. @@ -9218,16 +9185,7 @@ open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup) table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; } else - { - /* - If error in mysql_lock_tables(), open_ltable doesn't close the - table. Thread kill during mysql_lock_tables() is such error. But - open tables cannot be accepted when restoring the open tables - state. - */ - close_thread_tables(thd); thd->restore_backup_open_tables_state(backup); - } thd->utime_after_lock= save_utime_after_lock; DBUG_RETURN(table); diff --git a/sql/sql_base.h b/sql/sql_base.h index 20a068e27d7..45f1408e2f5 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -203,8 +203,9 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds); int setup_ftfuncs(SELECT_LEX* select); int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); -void wait_for_condition(THD *thd, mysql_mutex_t *mutex, - mysql_cond_t *cond); +bool lock_table_names(THD *thd, TABLE_LIST *table_list, + TABLE_LIST *table_list_end, ulong lock_wait_timeout, + uint flags); bool open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags, Prelocking_strategy *prelocking_strategy); /* open_and_lock_tables with optional derived handling */ @@ -222,7 +223,7 @@ int decide_logging_format(THD *thd, TABLE_LIST *tables); void free_io_cache(TABLE *entry); void intern_close_table(TABLE *entry); bool close_thread_table(THD *thd, TABLE **table_ptr); -void close_temporary_tables(THD *thd); +bool close_temporary_tables(THD *thd); TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, bool check_alias); int drop_temporary_table(THD *thd, TABLE_LIST *table_list); @@ -239,6 +240,7 @@ bool is_equal(const LEX_STRING *a, const LEX_STRING *b); bool open_system_tables_for_read(THD *thd, TABLE_LIST *table_list, Open_tables_backup *backup); void close_system_tables(THD *thd, Open_tables_backup *backup); +void close_mysql_tables(THD *thd); TABLE *open_system_table_for_update(THD *thd, TABLE_LIST *one_table); TABLE *open_log_table(THD *thd, TABLE_LIST *one_table, Open_tables_backup *backup); void close_log_table(THD *thd, Open_tables_backup *backup); @@ -480,8 +482,6 @@ public: return m_start_of_statement_svp; } - MDL_request *get_global_mdl_request(THD *thd); - inline ulong get_timeout() const { return m_timeout; @@ -499,11 +499,6 @@ private: TABLE_LIST *m_failed_table; MDL_ticket *m_start_of_statement_svp; /** - Request object for global intention exclusive lock which is acquired during - opening tables for statements which take upgradable shared metadata locks. - */ - MDL_request *m_global_mdl_request; - /** Lock timeout in seconds. Initialized to LONG_TIMEOUT when opening system tables or to the "lock_wait_timeout" system variable for regular tables. */ diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index b73de320ef5..d6dc9edc502 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -1673,7 +1673,8 @@ def_week_frmt: %lu, in_trans: %d, autocommit: %d", thd->limit_found_rows = query->found_rows(); thd->status_var.last_query_cost= 0.0; - thd->stmt_da->disable_status(); + if (!thd->stmt_da->is_set()) + thd->stmt_da->disable_status(); BLOCK_UNLOCK_RD(query_block); MYSQL_QUERY_CACHE_HIT(thd->query(), (ulong) thd->limit_found_rows); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 9c5e9e84cfc..7eb4911c744 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -29,7 +29,6 @@ #include "sql_priv.h" #include "unireg.h" // REQUIRED: for other includes #include "sql_class.h" -#include "lock.h" // unlock_global_read_lock, mysql_unlock_tables #include "sql_cache.h" // query_cache_abort #include "sql_base.h" // close_thread_tables #include "sql_time.h" // date_time_format_copy @@ -491,7 +490,6 @@ THD::THD() :Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION, /* statement id */ 0), rli_fake(0), - lock_id(&main_lock_id), user_time(0), in_sub_stmt(0), binlog_unsafe_warning_flags(0), stmt_accessed_table_flag(0), @@ -625,7 +623,6 @@ THD::THD() randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::global_query_id); substitute_null_with_insert_id = FALSE; thr_lock_info_init(&lock_info); /* safety: will be reset after start */ - thr_lock_owner_init(&main_lock_id, &lock_info); m_internal_handler= NULL; current_user_used= FALSE; @@ -1114,7 +1111,6 @@ THD::~THD() } #endif stmt_map.reset(); /* close all prepared statements */ - DBUG_ASSERT(lock_info.n_cursors == 0); if (!cleanup_done) cleanup(); @@ -1817,12 +1813,6 @@ bool select_send::send_eof() */ ha_release_temporary_latches(thd); - /* Unlock tables before sending packet to gain some speed */ - if (thd->lock && ! thd->locked_tables_mode) - { - mysql_unlock_tables(thd, thd->lock); - thd->lock=0; - } /* Don't send EOF if we're in error condition (which implies we've already sent or are sending an error) @@ -2596,7 +2586,6 @@ Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg, id(id_arg), mark_used_columns(MARK_COLUMNS_READ), lex(lex_arg), - cursor(0), db(NULL), db_length(0) { @@ -2618,7 +2607,6 @@ void Statement::set_statement(Statement *stmt) mark_used_columns= stmt->mark_used_columns; lex= stmt->lex; query_string= stmt->query_string; - cursor= stmt->cursor; } diff --git a/sql/sql_class.h b/sql/sql_class.h index 1afd4fe097c..c719f5a09ad 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -38,7 +38,7 @@ #include "protocol.h" /* Protocol_text, Protocol_binary */ #include "violite.h" /* vio_is_connected */ #include "thr_lock.h" /* thr_lock_type, THR_LOCK_DATA, - THR_LOCK_INFO, THR_LOCK_OWNER */ + THR_LOCK_INFO */ class Reprepare_observer; @@ -723,7 +723,6 @@ public: ENGINE INNODB STATUS. */ LEX_STRING query_string; - Server_side_cursor *cursor; inline char *query() { return query_string.str; } inline uint32 query_length() { return query_string.length; } @@ -1416,9 +1415,6 @@ public: struct system_status_var status_var; // Per thread statistic vars struct system_status_var *initial_status_var; /* used by show status */ THR_LOCK_INFO lock_info; // Locking info of this thread - THR_LOCK_OWNER main_lock_id; // To use for conventional queries - THR_LOCK_OWNER *lock_id; // If not main_lock_id, points to - // the lock_id of a cursor. /** Protects THD data accessed from other threads: - thd->query and thd->query_length (used by SHOW ENGINE diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc index ca724ec262f..7a9834b4cde 100644 --- a/sql/sql_cursor.cc +++ b/sql/sql_cursor.cc @@ -19,7 +19,6 @@ #include "sql_priv.h" #include "unireg.h" #include "sql_cursor.h" -#include "sql_select.h" #include "probes_mysql.h" #include "sql_parse.h" // mysql_execute_command @@ -28,51 +27,6 @@ ****************************************************************************/ /** - Sensitive_cursor -- a sensitive non-materialized server side - cursor. An instance of this class cursor has its own runtime - state -- list of used items and memory root for runtime memory, - open and locked tables, change list for the changes of the - parsed tree. This state is freed when the cursor is closed. -*/ - -class Sensitive_cursor: public Server_side_cursor -{ - MEM_ROOT main_mem_root; - Query_arena *stmt_arena; - JOIN *join; - TABLE *open_tables; - MYSQL_LOCK *lock; - TABLE *derived_tables; - /* List of items created during execution */ - query_id_t query_id; - struct Engine_info - { - handlerton *ht; - void *read_view; - }; - Engine_info ht_info[MAX_HA]; - Item_change_list change_list; - my_bool close_at_commit; - THR_LOCK_OWNER lock_id; -private: - /* bzero cursor state in THD */ - void reset_thd(THD *thd); -public: - Sensitive_cursor(THD *thd, select_result *result_arg); - - THR_LOCK_OWNER *get_lock_id() { return &lock_id; } - /* Save THD state into cursor */ - void post_open(THD *thd); - - virtual bool is_open() const { return join != 0; } - virtual int open(JOIN *join); - virtual void fetch(ulong num_rows); - virtual void close(); - virtual ~Sensitive_cursor(); -}; - - -/** Materialized_cursor -- an insensitive materialized server-side cursor. The result set of this cursor is saved in a temporary table at open. The cursor itself is simply an interface for the @@ -124,10 +78,9 @@ public: /**************************************************************************/ /** - Attempt to open a materialized or non-materialized cursor. + Attempt to open a materialized cursor. @param thd thread handle - @param[in] flags create a materialized cursor or not @param[in] result result class of the caller used as a destination for the rows fetched from the cursor @param[out] pcursor a pointer to store a pointer to cursor in @@ -140,37 +93,21 @@ public: non-zero an error, 'pcursor' has been left intact. */ -int mysql_open_cursor(THD *thd, uint flags, select_result *result, +int mysql_open_cursor(THD *thd, select_result *result, Server_side_cursor **pcursor) { - Sensitive_cursor *sensitive_cursor; select_result *save_result; Select_materialize *result_materialize; LEX *lex= thd->lex; int rc; - /* - The lifetime of the sensitive cursor is the same or less as the - lifetime of the runtime memory of the statement it's opened for. - */ if (! (result_materialize= new (thd->mem_root) Select_materialize(result))) return 1; - if (! (sensitive_cursor= new (thd->mem_root) Sensitive_cursor(thd, result))) - { - delete result_materialize; - result_materialize= NULL; - return 1; - } - save_result= lex->result; lex->result= result_materialize; - if (! (flags & (uint) ALWAYS_MATERIALIZED_CURSOR)) - { - thd->lock_id= sensitive_cursor->get_lock_id(); - thd->cursor= sensitive_cursor; - } + MYSQL_QUERY_EXEC_START(thd->query(), thd->thread_id, (char *) (thd->db ? thd->db : ""), @@ -181,20 +118,14 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result, MYSQL_QUERY_EXEC_DONE(rc); lex->result= save_result; - thd->lock_id= &thd->main_lock_id; - thd->cursor= 0; - /* Possible options here: - - a sensitive cursor is open. In this case rc is 0 and - result_materialize->materialized_cursor is NULL, or - a materialized cursor is open. In this case rc is 0 and result_materialize->materialized is not NULL - an error occurred during materialization. result_materialize->materialized_cursor is not NULL, but rc != 0 - successful completion of mysql_execute_command without - a cursor: rc is 0, result_materialize->materialized_cursor is NULL, - sensitive_cursor is not open. + a cursor: rc is 0, result_materialize->materialized_cursor is NULL. This is possible if some command writes directly to the network, bypassing select_result mechanism. An example of such command is SHOW VARIABLES or SHOW STATUS. @@ -203,23 +134,10 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result, { if (result_materialize->materialized_cursor) delete result_materialize->materialized_cursor; - goto err_open; - } - - if (sensitive_cursor->is_open()) - { - DBUG_ASSERT(!result_materialize->materialized_cursor); - /* - It's safer if we grab THD state after mysql_execute_command - is finished and not in Sensitive_cursor::open(), because - currently the call to Sensitive_cursor::open is buried deep - in JOIN::exec of the top level join. - */ - sensitive_cursor->post_open(thd); - *pcursor= sensitive_cursor; goto end; } - else if (result_materialize->materialized_cursor) + + if (result_materialize->materialized_cursor) { Materialized_cursor *materialized_cursor= result_materialize->materialized_cursor; @@ -227,18 +145,13 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result, if ((rc= materialized_cursor->open(0))) { delete materialized_cursor; - materialized_cursor= NULL; - goto err_open; + goto end; } *pcursor= materialized_cursor; thd->stmt_arena->cleanup_stmt(); - goto end; } -err_open: - DBUG_ASSERT(! (sensitive_cursor && sensitive_cursor->is_open())); - delete sensitive_cursor; end: delete result_materialize; return rc; @@ -270,279 +183,6 @@ void Server_side_cursor::operator delete(void *ptr, size_t size) DBUG_VOID_RETURN; } -/**************************************************************************** - Sensitive_cursor -****************************************************************************/ - -Sensitive_cursor::Sensitive_cursor(THD *thd, select_result *result_arg) - :Server_side_cursor(&main_mem_root, result_arg), - stmt_arena(0), - join(0), - close_at_commit(FALSE) -{ - /* We will overwrite it at open anyway. */ - init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); - thr_lock_owner_init(&lock_id, &thd->lock_info); - bzero((void*) ht_info, sizeof(ht_info)); -} - - -/** - Save THD state into cursor. - - @todo - - What problems can we have with it if cursor is open? - - TODO: must be fixed because of the prelocked mode. -*/ -void -Sensitive_cursor::post_open(THD *thd) -{ - Engine_info *info; - /* - We need to save and reset thd->mem_root, otherwise it'll be - freed later in mysql_parse. - - We can't just change thd->mem_root here as we want to keep the - things that are already allocated in thd->mem_root for - Sensitive_cursor::fetch() - */ - *mem_root= *thd->mem_root; - stmt_arena= thd->stmt_arena; - state= stmt_arena->state; - /* Allocate a new memory root for thd */ - init_sql_alloc(thd->mem_root, - thd->variables.query_alloc_block_size, - thd->variables.query_prealloc_size); - - /* - Save tables and zero THD pointers to prevent table close in - close_thread_tables. - */ - derived_tables= thd->derived_tables; - open_tables= thd->open_tables; - lock= thd->lock; - query_id= thd->query_id; - free_list= thd->free_list; - thd->change_list.move_elements_to(&change_list); - reset_thd(thd); - /* Now we have an active cursor and can cause a deadlock */ - thd->lock_info.n_cursors++; - - close_at_commit= FALSE; /* reset in case we're reusing the cursor */ - info= &ht_info[0]; - for (Ha_trx_info *ha_trx_info= thd->transaction.stmt.ha_list; - ha_trx_info; ha_trx_info= ha_trx_info->next()) - { - handlerton *ht= ha_trx_info->ht(); - close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT); - if (ht->create_cursor_read_view) - { - info->ht= ht; - info->read_view= (ht->create_cursor_read_view)(ht, thd); - ++info; - } - } - /* - What problems can we have with it if cursor is open? - TODO: must be fixed because of the prelocked mode. - */ -} - - -/** - bzero cursor state in THD. -*/ - -void -Sensitive_cursor::reset_thd(THD *thd) -{ - thd->derived_tables= 0; - thd->set_open_tables(NULL); - thd->lock= 0; - thd->free_list= 0; - thd->change_list.empty(); -} - - -int -Sensitive_cursor::open(JOIN *join_arg) -{ - join= join_arg; - THD *thd= join->thd; - /* First non-constant table */ - JOIN_TAB *join_tab= join->join_tab + join->const_tables; - DBUG_ENTER("Sensitive_cursor::open"); - - join->change_result(result); - /* - Send fields description to the client; server_status is sent - in 'EOF' packet, which follows send_result_set_metadata(). - We don't simply use SEND_EOF flag of send_result_set_metadata because we also - want to flush the network buffer, which is done only in a standalone - send_eof(). - */ - result->send_result_set_metadata(*join->fields, Protocol::SEND_NUM_ROWS); - thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; - result->send_eof(); - thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; - - /* Prepare JOIN for reading rows. */ - join->tmp_table= 0; - join->join_tab[join->tables-1].next_select= setup_end_select_func(join); - join->send_records= 0; - join->fetch_limit= join->unit->offset_limit_cnt; - - /* Disable JOIN CACHE as it is not working with cursors yet */ - for (JOIN_TAB *tab= join_tab; - tab != join->join_tab + join->tables - 1; - tab++) - { - if (tab->next_select == sub_select_cache) - tab->next_select= sub_select; - } - - DBUG_ASSERT(join_tab->table->reginfo.not_exists_optimize == 0); - DBUG_ASSERT(join_tab->not_used_in_distinct == 0); - /* - null_row is set only if row not found and it's outer join: should never - happen for the first table in join_tab list - */ - DBUG_ASSERT(join_tab->table->null_row == 0); - DBUG_RETURN(0); -} - - -/** - Fetch next num_rows rows from the cursor and send them to the client. - - Precondition: - - Sensitive_cursor is open - - @param num_rows fetch up to this number of rows (maybe less) -*/ - -void -Sensitive_cursor::fetch(ulong num_rows) -{ - THD *thd= join->thd; - JOIN_TAB *join_tab= join->join_tab + join->const_tables; - enum_nested_loop_state error= NESTED_LOOP_OK; - Query_arena backup_arena; - Engine_info *info; - DBUG_ENTER("Sensitive_cursor::fetch"); - DBUG_PRINT("enter",("rows: %lu", num_rows)); - - DBUG_ASSERT(thd->derived_tables == 0 && thd->open_tables == 0 && - thd->lock == 0); - - thd->derived_tables= derived_tables; - thd->set_open_tables(open_tables); - thd->lock= lock; - thd->set_query_id(query_id); - change_list.move_elements_to(&thd->change_list); - /* save references to memory allocated during fetch */ - thd->set_n_backup_active_arena(this, &backup_arena); - - for (info= ht_info; info->read_view ; info++) - (info->ht->set_cursor_read_view)(info->ht, thd, info->read_view); - - join->fetch_limit+= num_rows; - - error= sub_select(join, join_tab, 0); - if (error == NESTED_LOOP_OK || error == NESTED_LOOP_NO_MORE_ROWS) - error= sub_select(join,join_tab,1); - if (error == NESTED_LOOP_QUERY_LIMIT) - error= NESTED_LOOP_OK; /* select_limit used */ - if (error == NESTED_LOOP_CURSOR_LIMIT) - join->resume_nested_loop= TRUE; - - ha_release_temporary_latches(thd); - - /* Grab free_list here to correctly free it in close */ - thd->restore_active_arena(this, &backup_arena); - - thd->change_list.move_elements_to(&change_list); - reset_thd(thd); - - for (info= ht_info; info->read_view; info++) - (info->ht->set_cursor_read_view)(info->ht, thd, 0); - - if (error == NESTED_LOOP_CURSOR_LIMIT) - { - /* Fetch limit worked, possibly more rows are there */ - thd->server_status|= SERVER_STATUS_CURSOR_EXISTS; - result->send_eof(); - thd->server_status&= ~SERVER_STATUS_CURSOR_EXISTS; - } - else - { - close(); - if (error == NESTED_LOOP_OK) - { - thd->server_status|= SERVER_STATUS_LAST_ROW_SENT; - result->send_eof(); - thd->server_status&= ~SERVER_STATUS_LAST_ROW_SENT; - } - else if (error != NESTED_LOOP_KILLED) - my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - } - DBUG_VOID_RETURN; -} - - -/** - @todo - Another hack: we need to set THD state as if in a fetch to be - able to call stmt close. -*/ -void -Sensitive_cursor::close() -{ - THD *thd= join->thd; - DBUG_ENTER("Sensitive_cursor::close"); - - for (Engine_info *info= ht_info; info->read_view; info++) - { - (info->ht->close_cursor_read_view)(info->ht, thd, info->read_view); - info->read_view= 0; - info->ht= 0; - } - - change_list.move_elements_to(&thd->change_list); - { - /* - XXX: Another hack: we need to set THD state as if in a fetch to be - able to call stmt close. - */ - DBUG_ASSERT(lock || open_tables || derived_tables); - - TABLE *tmp_derived_tables= thd->derived_tables; - MYSQL_LOCK *tmp_lock= thd->lock; - - thd->set_open_tables(open_tables); - thd->derived_tables= derived_tables; - thd->lock= lock; - - /* Is expected to at least close tables and empty thd->change_list */ - stmt_arena->cleanup_stmt(); - - thd->set_open_tables(tmp_derived_tables); - thd->derived_tables= tmp_derived_tables; - thd->lock= tmp_lock; - } - thd->lock_info.n_cursors--; /* Decrease the number of active cursors */ - join= 0; - stmt_arena= 0; - free_items(); - DBUG_VOID_RETURN; -} - - -Sensitive_cursor::~Sensitive_cursor() -{ - if (is_open()) - close(); -} /*************************************************************************** Materialized_cursor @@ -568,7 +208,8 @@ Materialized_cursor::Materialized_cursor(select_result *result_arg, @param send_result_set_metadata List of fields that would be sent. */ -int Materialized_cursor::fill_item_list(THD *thd, List<Item> &send_result_set_metadata) +int Materialized_cursor::fill_item_list(THD *thd, + List<Item> &send_result_set_metadata) { Query_arena backup_arena; int rc; @@ -606,6 +247,7 @@ end: return rc || thd->is_error(); } + int Materialized_cursor::open(JOIN *join __attribute__((unused))) { THD *thd= fake_unit.thd; @@ -664,7 +306,12 @@ void Materialized_cursor::fetch(ulong num_rows) if ((res= table->file->rnd_next(table->record[0]))) break; /* Send data only if the read was successful. */ - result->send_data(item_list); + /* + If network write failed (i.e. due to a closed socked), + the error has already been set. Just return. + */ + if (result->send_data(item_list)) + return; } switch (res) { diff --git a/sql/sql_cursor.h b/sql/sql_cursor.h index 2a394e281b4..ed7bfac821a 100644 --- a/sql/sql_cursor.h +++ b/sql/sql_cursor.h @@ -32,11 +32,11 @@ class JOIN; */ /** - Server_side_cursor -- an interface for materialized and - sensitive (non-materialized) implementation of cursors. All - cursors are self-contained (created in their own memory root). - For that reason they must be deleted only using a pointer to - Server_side_cursor, not to its base class. + Server_side_cursor -- an interface for materialized + implementation of cursors. All cursors are self-contained + (created in their own memory root). For that reason they must + be deleted only using a pointer to Server_side_cursor, not to + its base class. */ class Server_side_cursor: protected Query_arena, public Sql_alloc @@ -60,11 +60,7 @@ public: }; -int mysql_open_cursor(THD *thd, uint flags, - select_result *result, +int mysql_open_cursor(THD *thd, select_result *result, Server_side_cursor **res); -/** Possible values for flags */ -enum { ANY_CURSOR= 1, ALWAYS_MATERIALIZED_CURSOR= 2 }; - #endif /* _sql_cusor_h_ */ diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 1040fc92851..517cb9139e9 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -21,14 +21,12 @@ #include "unireg.h" #include "sql_db.h" #include "sql_cache.h" // query_cache_* -#include "lock.h" // wait_if_global_read_lock, - // start_waiting_global_read_lock +#include "lock.h" // lock_schema_name #include "sql_table.h" // build_table_filename, // filename_to_tablename #include "sql_rename.h" // mysql_rename_tables #include "sql_acl.h" // SELECT_ACL, DB_ACLS, // acl_get, check_grant_db -#include "sql_base.h" // wait_for_condition #include "log_event.h" // Query_log_event #include <mysys_err.h> #include "sp.h" @@ -58,106 +56,6 @@ static void mysql_change_db_impl(THD *thd, CHARSET_INFO *new_db_charset); -/* Database lock hash */ -HASH lock_db_cache; -mysql_mutex_t LOCK_lock_db; -int creating_database= 0; // how many database locks are made - - -/* Structure for database lock */ -typedef struct my_dblock_st -{ - char *name; /* Database name */ - uint name_length; /* Database length name */ -} my_dblock_t; - - -/* - lock_db key. -*/ - -extern "C" uchar* lock_db_get_key(my_dblock_t *, size_t *, my_bool not_used); - -uchar* lock_db_get_key(my_dblock_t *ptr, size_t *length, - my_bool not_used __attribute__((unused))) -{ - *length= ptr->name_length; - return (uchar*) ptr->name; -} - - -/* - Free lock_db hash element. -*/ - -extern "C" void lock_db_free_element(void *ptr); - -void lock_db_free_element(void *ptr) -{ - my_free(ptr); -} - - -/* - Put a database lock entry into the hash. - - DESCRIPTION - Insert a database lock entry into hash. - LOCK_db_lock must be previously locked. - - RETURN VALUES - 0 on success. - 1 on error. -*/ - -static my_bool lock_db_insert(const char *dbname, uint length) -{ - my_dblock_t *opt; - my_bool error= 0; - DBUG_ENTER("lock_db_insert"); - - mysql_mutex_assert_owner(&LOCK_lock_db); - - if (!(opt= (my_dblock_t*) my_hash_search(&lock_db_cache, - (uchar*) dbname, length))) - { - /* Db is not in the hash, insert it */ - char *tmp_name; - if (!my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), - &opt, (uint) sizeof(*opt), &tmp_name, (uint) length+1, - NullS)) - { - error= 1; - goto end; - } - - opt->name= tmp_name; - strmov(opt->name, dbname); - opt->name_length= length; - - if ((error= my_hash_insert(&lock_db_cache, (uchar*) opt))) - my_free(opt); - } - -end: - DBUG_RETURN(error); -} - - -/* - Delete a database lock entry from hash. -*/ - -void lock_db_delete(const char *name, uint length) -{ - my_dblock_t *opt; - mysql_mutex_assert_owner(&LOCK_lock_db); - if ((opt= (my_dblock_t *)my_hash_search(&lock_db_cache, - (const uchar*) name, length))) - my_hash_delete(&lock_db_cache, (uchar*) opt); -} - - /* Database options hash */ static HASH dboptions; static my_bool dboptions_init= 0; @@ -233,21 +131,16 @@ static void init_database_names_psi_keys(void) } #endif -/* - Initialize database option hash and locked database hash. - - SYNOPSIS - my_database_names() +/** + Initialize database option cache. - NOTES - Must be called before any other database function is called. + @note Must be called before any other database function is called. - RETURN - 0 ok - 1 Fatal error + @retval 0 ok + @retval 1 Fatal error */ -bool my_database_names_init(void) +bool my_dboptions_cache_init(void) { #ifdef HAVE_PSI_INTERFACE init_database_names_psi_keys(); @@ -261,36 +154,30 @@ bool my_database_names_init(void) error= my_hash_init(&dboptions, lower_case_table_names ? &my_charset_bin : system_charset_info, 32, 0, 0, (my_hash_get_key) dboptions_get_key, - free_dbopt,0) || - my_hash_init(&lock_db_cache, lower_case_table_names ? - &my_charset_bin : system_charset_info, - 32, 0, 0, (my_hash_get_key) lock_db_get_key, - lock_db_free_element,0); - + free_dbopt,0); } return error; } -/* +/** Free database option hash and locked databases hash. */ -void my_database_names_free(void) +void my_dboptions_cache_free(void) { if (dboptions_init) { dboptions_init= 0; my_hash_free(&dboptions); mysql_rwlock_destroy(&LOCK_dboptions); - my_hash_free(&lock_db_cache); } } -/* - Cleanup cached options +/** + Cleanup cached options. */ void my_dbopt_cleanup(void) @@ -395,7 +282,7 @@ end: Deletes database options from the hash. */ -void del_dbopt(const char *path) +static void del_dbopt(const char *path) { my_dbopt_t *opt; mysql_rwlock_wrlock(&LOCK_dboptions); @@ -664,25 +551,8 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, DBUG_RETURN(-1); } - /* - Do not create database if another thread is holding read lock. - Wait for global read lock before acquiring LOCK_mysql_create_db. - After wait_if_global_read_lock() we have protection against another - global read lock. If we would acquire LOCK_mysql_create_db first, - another thread could step in and get the global read lock before we - reach wait_if_global_read_lock(). If this thread tries the same as we - (admin a db), it would then go and wait on LOCK_mysql_create_db... - Furthermore wait_if_global_read_lock() checks if the current thread - has the global read lock and refuses the operation with - ER_CANT_UPDATE_WITH_READLOCK if applicable. - */ - if (thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE)) - { - error= -1; - goto exit2; - } - - mysql_mutex_lock(&LOCK_mysql_create_db); + if (lock_schema_name(thd, db)) + DBUG_RETURN(-1); /* Check directory */ path_len= build_table_filename(path, sizeof(path) - 1, db, "", "", 0); @@ -786,7 +656,10 @@ not_silent: qinfo.db = db; qinfo.db_len = strlen(db); - /* These DDL methods and logging protected with LOCK_mysql_create_db */ + /* + These DDL methods and logging are protected with the exclusive + metadata lock on the schema + */ if (mysql_bin_log.write(&qinfo)) { error= -1; @@ -797,9 +670,6 @@ not_silent: } exit: - mysql_mutex_unlock(&LOCK_mysql_create_db); - thd->global_read_lock.start_waiting_global_read_lock(thd); -exit2: DBUG_RETURN(error); } @@ -813,22 +683,8 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) int error= 0; DBUG_ENTER("mysql_alter_db"); - /* - Do not alter database if another thread is holding read lock. - Wait for global read lock before acquiring LOCK_mysql_create_db. - After wait_if_global_read_lock() we have protection against another - global read lock. If we would acquire LOCK_mysql_create_db first, - another thread could step in and get the global read lock before we - reach wait_if_global_read_lock(). If this thread tries the same as we - (admin a db), it would then go and wait on LOCK_mysql_create_db... - Furthermore wait_if_global_read_lock() checks if the current thread - has the global read lock and refuses the operation with - ER_CANT_UPDATE_WITH_READLOCK if applicable. - */ - if ((error= thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE))) - goto exit2; - - mysql_mutex_lock(&LOCK_mysql_create_db); + if (lock_schema_name(thd, db)) + DBUG_RETURN(TRUE); /* Recreate db options file: /dbpath/.db.opt @@ -866,16 +722,16 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) qinfo.db = db; qinfo.db_len = strlen(db); - /* These DDL methods and logging protected with LOCK_mysql_create_db */ + /* + These DDL methods and logging are protected with the exclusive + metadata lock on the schema. + */ if ((error= mysql_bin_log.write(&qinfo))) goto exit; } my_ok(thd, result); exit: - mysql_mutex_unlock(&LOCK_mysql_create_db); - thd->global_read_lock.start_waiting_global_read_lock(thd); -exit2: DBUG_RETURN(error); } @@ -907,25 +763,9 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) TABLE_LIST* dropped_tables= 0; DBUG_ENTER("mysql_rm_db"); - /* - Do not drop database if another thread is holding read lock. - Wait for global read lock before acquiring LOCK_mysql_create_db. - After wait_if_global_read_lock() we have protection against another - global read lock. If we would acquire LOCK_mysql_create_db first, - another thread could step in and get the global read lock before we - reach wait_if_global_read_lock(). If this thread tries the same as we - (admin a db), it would then go and wait on LOCK_mysql_create_db... - Furthermore wait_if_global_read_lock() checks if the current thread - has the global read lock and refuses the operation with - ER_CANT_UPDATE_WITH_READLOCK if applicable. - */ - if (thd->global_read_lock.wait_if_global_read_lock(thd, FALSE, TRUE)) - { - error= -1; - goto exit2; - } - mysql_mutex_lock(&LOCK_mysql_create_db); + if (lock_schema_name(thd, db)) + DBUG_RETURN(TRUE); length= build_table_filename(path, sizeof(path) - 1, db, "", "", 0); strmov(path+length, MY_DB_OPT_FILE); // Append db option file name @@ -1013,7 +853,10 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) qinfo.db = db; qinfo.db_len = strlen(db); - /* These DDL methods and logging protected with LOCK_mysql_create_db */ + /* + These DDL methods and logging are protected with the exclusive + metadata lock on the schema. + */ if (mysql_bin_log.write(&qinfo)) { error= -1; @@ -1045,7 +888,10 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) tbl_name_len= strlen(tbl->table_name) + 3; if (query_pos + tbl_name_len + 1 >= query_end) { - /* These DDL methods and logging protected with LOCK_mysql_create_db */ + /* + These DDL methods and logging are protected with the exclusive + metadata lock on the schema. + */ if (write_to_binlog(thd, query, query_pos -1 - query, db, db_len)) { error= -1; @@ -1062,7 +908,10 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) if (query_pos != query_data_start) { - /* These DDL methods and logging protected with LOCK_mysql_create_db */ + /* + These DDL methods and logging are protected with the exclusive + metadata lock on the schema. + */ if (write_to_binlog(thd, query, query_pos -1 - query, db, db_len)) { error= -1; @@ -1080,9 +929,6 @@ exit: */ if (thd->db && !strcmp(thd->db, db) && error == 0) mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server); - mysql_mutex_unlock(&LOCK_mysql_create_db); - thd->global_read_lock.start_waiting_global_read_lock(thd); -exit2: DBUG_RETURN(error); } @@ -1099,12 +945,12 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, long deleted=0; ulong found_other_files=0; char filePath[FN_REFLEN]; - TABLE_LIST *tot_list=0, **tot_list_next; + TABLE_LIST *tot_list=0, **tot_list_next_local, **tot_list_next_global; List<String> raid_dirs; DBUG_ENTER("mysql_rm_known_files"); DBUG_PRINT("enter",("path: %s", org_path)); - tot_list_next= &tot_list; + tot_list_next_local= tot_list_next_global= &tot_list; for (uint idx=0 ; idx < (uint) dirp->number_off_files && !thd->killed ; @@ -1192,22 +1038,28 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, if (!table_list) goto err; table_list->db= (char*) (table_list+1); - table_list->table_name= strmov(table_list->db, db) + 1; - (void) filename_to_tablename(file->name, table_list->table_name, - MYSQL50_TABLE_NAME_PREFIX_LENGTH + - strlen(file->name) + 1); + table_list->db_length= strmov(table_list->db, db) - table_list->db; + table_list->table_name= table_list->db + table_list->db_length + 1; + table_list->table_name_length= filename_to_tablename(file->name, + table_list->table_name, + MYSQL50_TABLE_NAME_PREFIX_LENGTH + + strlen(file->name) + 1); + table_list->open_type= OT_BASE_ONLY; /* To be able to correctly look up the table in the table cache. */ if (lower_case_table_names) - my_casedn_str(files_charset_info, table_list->table_name); + table_list->table_name_length= my_casedn_str(files_charset_info, + table_list->table_name); table_list->alias= table_list->table_name; // If lower_case_table_names=2 table_list->internal_tmp_table= is_prefix(file->name, tmp_file_prefix); table_list->mdl_request.init(MDL_key::TABLE, table_list->db, table_list->table_name, MDL_EXCLUSIVE); /* Link into list */ - (*tot_list_next)= table_list; - tot_list_next= &table_list->next_local; + (*tot_list_next_local)= table_list; + (*tot_list_next_global)= table_list; + tot_list_next_local= &table_list->next_local; + tot_list_next_global= &table_list->next_global; deleted++; } else @@ -1769,60 +1621,6 @@ bool mysql_opt_change_db(THD *thd, } -static int -lock_databases(THD *thd, const char *db1, uint length1, - const char *db2, uint length2) -{ - mysql_mutex_lock(&LOCK_lock_db); - while (!thd->killed && - (my_hash_search(&lock_db_cache,(uchar*) db1, length1) || - my_hash_search(&lock_db_cache,(uchar*) db2, length2))) - { - wait_for_condition(thd, &LOCK_lock_db, &COND_refresh); - mysql_mutex_lock(&LOCK_lock_db); - } - - if (thd->killed) - { - mysql_mutex_unlock(&LOCK_lock_db); - return 1; - } - - lock_db_insert(db1, length1); - lock_db_insert(db2, length2); - creating_database++; - - /* - Wait if a concurent thread is creating a table at the same time. - The assumption here is that it will not take too long until - there is a point in time when a table is not created. - */ - - while (!thd->killed && creating_table) - { - wait_for_condition(thd, &LOCK_lock_db, &COND_refresh); - mysql_mutex_lock(&LOCK_lock_db); - } - - if (thd->killed) - { - lock_db_delete(db1, length1); - lock_db_delete(db2, length2); - creating_database--; - mysql_mutex_unlock(&LOCK_lock_db); - mysql_cond_signal(&COND_refresh); - return(1); - } - - /* - We can unlock now as the hash will protect against anyone creating a table - in the databases we are using - */ - mysql_mutex_unlock(&LOCK_lock_db); - return 0; -} - - /** Upgrade a 5.0 database. This function is invoked whenever an ALTER DATABASE UPGRADE query is executed: @@ -1864,9 +1662,9 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db) new_db.str= old_db->str + MYSQL50_TABLE_NAME_PREFIX_LENGTH; new_db.length= old_db->length - MYSQL50_TABLE_NAME_PREFIX_LENGTH; - if (lock_databases(thd, old_db->str, old_db->length, - new_db.str, new_db.length)) - DBUG_RETURN(1); + /* Lock the old name, the new name will be locked by mysql_create_db().*/ + if (lock_schema_name(thd, old_db->str)) + DBUG_RETURN(-1); /* Let's remember if we should do "USE newdb" afterwards. @@ -2033,15 +1831,6 @@ bool mysql_upgrade_db(THD *thd, LEX_STRING *old_db) error|= mysql_change_db(thd, & new_db, FALSE); exit: - mysql_mutex_lock(&LOCK_lock_db); - /* Remove the databases from db lock cache */ - lock_db_delete(old_db->str, old_db->length); - lock_db_delete(new_db.str, new_db.length); - creating_database--; - /* Signal waiting CREATE TABLE's to continue */ - mysql_cond_signal(&COND_refresh); - mysql_mutex_unlock(&LOCK_lock_db); - DBUG_RETURN(error); } diff --git a/sql/sql_db.h b/sql/sql_db.h index 96b3de80d3a..ecb8deaa397 100644 --- a/sql/sql_db.h +++ b/sql/sql_db.h @@ -35,8 +35,8 @@ bool mysql_opt_change_db(THD *thd, LEX_STRING *saved_db_name, bool force_switch, bool *cur_db_changed); -bool my_database_names_init(void); -void my_database_names_free(void); +bool my_dboptions_cache_init(void); +void my_dboptions_cache_free(void); bool check_db_dir_existence(const char *db_name); bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create); bool load_db_opt_by_name(THD *thd, const char *db_name, @@ -45,9 +45,6 @@ CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name); bool my_dbopt_init(void); void my_dbopt_cleanup(void); -extern int creating_database; // How many database locks are made -extern HASH lock_db_cache; - #define MY_DB_OPT_FILE "db.opt" #endif /* SQL_DB_INCLUDED */ diff --git a/sql/sql_do.cc b/sql/sql_do.cc index 79e488ac2a5..085473c24b8 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -39,9 +39,10 @@ bool mysql_do(THD *thd, List<Item> &values) /* Rollback the effect of the statement, since next instruction will clear the error and the rollback in the end of - dispatch_command() won't work. + mysql_execute_command() won't work. */ - trans_rollback_stmt(thd); + if (! thd->in_sub_stmt) + trans_rollback_stmt(thd); thd->clear_error(); // DO always is OK } my_ok(thd); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 06a453f7b12..f1dddbb2eb5 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -59,7 +59,7 @@ #include "key.h" // key_copy #include "sql_base.h" // insert_fields #include "sql_select.h" -#include <assert.h> +#include "transaction.h" #define HANDLER_TABLES_HASH_SIZE 120 @@ -309,9 +309,15 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen) } if (error) { + /* + No need to rollback statement transaction, it's not started. + If called with reopen flag, no need to rollback either, + it will be done at statement end. + */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); close_thread_tables(thd); - thd->set_open_tables(backup_open_tables); thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + thd->set_open_tables(backup_open_tables); if (!reopen) my_hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables); else @@ -578,6 +584,11 @@ retry: if (sql_handler_lock_error.need_reopen()) { DBUG_ASSERT(!lock && !thd->is_error()); + /* + Always close statement transaction explicitly, + so that the engine doesn't have to count locks. + */ + trans_rollback_stmt(thd); mysql_ha_close_table(thd, hash_tables); goto retry; } @@ -747,7 +758,11 @@ retry: goto ok; } if (cond && !cond->val_int()) + { + if (thd->is_error()) + goto err; continue; + } if (num_rows >= offset_limit_cnt) { protocol->prepare_for_resend(); @@ -760,12 +775,18 @@ retry: num_rows++; } ok: + /* + Always close statement transaction explicitly, + so that the engine doesn't have to count locks. + */ + trans_commit_stmt(thd); mysql_unlock_tables(thd,lock); my_eof(thd); DBUG_PRINT("exit",("OK")); DBUG_RETURN(FALSE); err: + trans_rollback_stmt(thd); mysql_unlock_tables(thd,lock); err0: DBUG_PRINT("exit",("ERROR")); diff --git a/sql/sql_help.cc b/sql/sql_help.cc index 7bea236269a..4e3df950134 100644 --- a/sql/sql_help.cc +++ b/sql/sql_help.cc @@ -643,23 +643,24 @@ bool mysqld_help(THD *thd, const char *mask) MEM_ROOT *mem_root= thd->mem_root; DBUG_ENTER("mysqld_help"); - bzero((uchar*)tables,sizeof(tables)); - tables[0].alias= tables[0].table_name= (char*) "help_topic"; - tables[0].lock_type= TL_READ; + tables[0].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("help_topic"), + "help_topic", TL_READ); + tables[1].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("help_category"), + "help_category", TL_READ); + tables[2].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("help_relation"), + "help_relation", TL_READ); + tables[3].init_one_table(C_STRING_WITH_LEN("mysql"), + C_STRING_WITH_LEN("help_keyword"), + "help_keyword", TL_READ); tables[0].next_global= tables[0].next_local= tables[0].next_name_resolution_table= &tables[1]; - tables[1].alias= tables[1].table_name= (char*) "help_category"; - tables[1].lock_type= TL_READ; tables[1].next_global= tables[1].next_local= tables[1].next_name_resolution_table= &tables[2]; - tables[2].alias= tables[2].table_name= (char*) "help_relation"; - tables[2].lock_type= TL_READ; tables[2].next_global= tables[2].next_local= tables[2].next_name_resolution_table= &tables[3]; - tables[3].alias= tables[3].table_name= (char*) "help_keyword"; - tables[3].lock_type= TL_READ; - tables[0].db= tables[1].db= tables[2].db= tables[3].db= (char*) "mysql"; - init_mdl_requests(tables); /* HELP must be available under LOCK TABLES. diff --git a/sql/sql_hset.h b/sql/sql_hset.h new file mode 100644 index 00000000000..2ea70b91da8 --- /dev/null +++ b/sql/sql_hset.h @@ -0,0 +1,97 @@ +#ifndef SQL_HSET_INCLUDED +#define SQL_HSET_INCLUDED +/* 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 */ + +#include "my_global.h" +#include "hash.h" + + +/** + A type-safe wrapper around mysys HASH. +*/ + +template <typename T, my_hash_get_key K> +class Hash_set +{ +public: + typedef T Value_type; + enum { START_SIZE= 8 }; + /** + Constructs an empty hash. Does not allocate memory, it is done upon + the first insert. Thus does not cause or return errors. + */ + Hash_set() + { + my_hash_clear(&m_hash); + } + /** + Destroy the hash by freeing the buckets table. Does + not call destructors for the elements. + */ + ~Hash_set() + { + my_hash_free(&m_hash); + } + /** + Insert a single value into a hash. Does not tell whether + the value was inserted -- if an identical value existed, + it is not replaced. + + @retval TRUE Out of memory. + @retval FALSE OK. The value either was inserted or existed + in the hash. + */ + bool insert(T *value) + { + my_hash_init_opt(&m_hash, &my_charset_bin, START_SIZE, 0, 0, K, 0, MYF(0)); + size_t key_len; + const uchar *key= K(reinterpret_cast<uchar*>(value), &key_len, FALSE); + if (my_hash_search(&m_hash, key, key_len) == NULL) + return my_hash_insert(&m_hash, reinterpret_cast<uchar *>(value)); + return FALSE; + } + /** Is this hash set empty? */ + bool is_empty() const { return m_hash.records == 0; } + /** Returns the number of unique elements. */ + size_t size() const { return static_cast<size_t>(m_hash.records); } + /** An iterator over hash elements. Is not insert-stable. */ + class Iterator + { + public: + Iterator(Hash_set &hash_set) + : m_hash(&hash_set.m_hash), + m_idx(0) + {} + /** + Return the current element and reposition the iterator to the next + element. + */ + inline T *operator++(int) + { + if (m_idx < m_hash->records) + return reinterpret_cast<T*>(my_hash_element(m_hash, m_idx++)); + return NULL; + } + void rewind() { m_idx= 0; } + private: + HASH *m_hash; + uint m_idx; + }; +private: + HASH m_hash; +}; + +#endif // SQL_HSET_INCLUDED diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 58609ead548..a0d347f48de 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1862,7 +1862,10 @@ public: while ((row=rows.get())) delete row; if (table) + { close_thread_tables(&thd); + thd.mdl_context.release_transactional_locks(); + } mysql_mutex_lock(&LOCK_thread_count); mysql_mutex_destroy(&mutex); mysql_cond_destroy(&cond); @@ -2414,6 +2417,8 @@ bool Delayed_insert::open_and_lock_table() } if (!(table->file->ha_table_flags() & HA_CAN_INSERT_DELAYED)) { + /* To rollback InnoDB statement transaction. */ + trans_rollback_stmt(&thd); my_error(ER_DELAYED_NOT_SUPPORTED, MYF(ME_FATALERROR), table_list.table_name); return TRUE; @@ -2480,12 +2485,6 @@ pthread_handler_t handle_delayed_insert(void *arg) goto err; } - /* - Open table requires an initialized lex in case the table is - partitioned. The .frm file contains a partial SQL string which is - parsed using a lex, that depends on initialized thd->lex. - */ - lex_start(thd); thd->lex->sql_command= SQLCOM_INSERT; // For innodb::store_lock() /* Statement-based replication of INSERT DELAYED has problems with RAND() @@ -2619,28 +2618,11 @@ pthread_handler_t handle_delayed_insert(void *arg) } err: - /* - mysql_lock_tables() can potentially start a transaction and write - a table map. In the event of an error, that transaction has to be - rolled back. We only need to roll back a potential statement - transaction, since real transactions are rolled back in - close_thread_tables(). - - TODO: This is not true any more, table maps are generated on the - first call to ha_*_row() instead. Remove code that are used to - cover for the case outlined above. - */ - trans_rollback_stmt(thd); - DBUG_LEAVE; } - /* - di should be unlinked from the thread handler list and have no active - clients - */ - close_thread_tables(thd); // Free the table + thd->mdl_context.release_transactional_locks(); di->table=0; thd->killed= THD::KILL_CONNECTION; // If error mysql_cond_broadcast(&di->cond_client); // Safety @@ -2648,6 +2630,10 @@ pthread_handler_t handle_delayed_insert(void *arg) mysql_mutex_lock(&LOCK_delayed_create); // Because of delayed_get_table mysql_mutex_lock(&LOCK_delayed_insert); + /* + di should be unlinked from the thread handler list and have no active + clients + */ delete di; mysql_mutex_unlock(&LOCK_delayed_insert); mysql_mutex_unlock(&LOCK_delayed_create); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 568640b574a..6411b194a8a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -152,7 +152,7 @@ st_parsing_options::reset() */ bool Lex_input_stream::init(THD *thd, - const char* buff, + char* buff, unsigned int length) { DBUG_EXECUTE_IF("bug42064_simulate_oom", @@ -182,7 +182,7 @@ bool Lex_input_stream::init(THD *thd, */ void -Lex_input_stream::reset(const char *buffer, unsigned int length) +Lex_input_stream::reset(char *buffer, unsigned int length) { yylineno= 1; yytoklen= 0; @@ -449,6 +449,9 @@ void lex_end(LEX *lex) } reset_dynamic(&lex->plugins); + delete lex->sphead; + lex->sphead= NULL; + DBUG_VOID_RETURN; } @@ -1424,11 +1427,10 @@ int lex_one_token(void *arg, void *yythd) ulong version; version=strtol(version_str, NULL, 10); - /* Accept 'M' 'm' 'm' 'd' 'd' */ - lip->yySkipn(5); - if (version <= MYSQL_VERSION_ID) { + /* Accept 'M' 'm' 'm' 'd' 'd' */ + lip->yySkipn(5); /* Expand the content of the special comment as real code */ lip->set_echo(TRUE); state=MY_LEX_START; @@ -1436,7 +1438,19 @@ int lex_one_token(void *arg, void *yythd) } else { + const char* version_mark= lip->get_ptr() - 1; + DBUG_ASSERT(*version_mark == '!'); + /* + Patch and skip the conditional comment to avoid it + being propagated infinitely (eg. to a slave). + */ + char *pcom= lip->yyUnput(' '); comment_closed= ! consume_comment(lip, 1); + if (! comment_closed) + { + DBUG_ASSERT(pcom == version_mark); + *pcom= '!'; + } /* version allowed to have one level of comment inside. */ } } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 784a69cf9c1..f1b558b8be4 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -1392,9 +1392,9 @@ public: @retval FALSE OK @retval TRUE Error */ - bool init(THD *thd, const char *buff, unsigned int length); + bool init(THD *thd, char *buff, unsigned int length); - void reset(const char *buff, unsigned int length); + void reset(char *buff, unsigned int length); /** Set the echo mode. @@ -1510,6 +1510,20 @@ public: } /** + Puts a character back into the stream, canceling + the effect of the last yyGet() or yySkip(). + Note that the echo mode should not change between calls + to unput, get, or skip from the stream. + */ + char *yyUnput(char ch) + { + *--m_ptr= ch; + if (m_echo) + m_cpp_ptr--; + return m_ptr; + } + + /** End of file indicator for the query text to parse. @return true if there are no more characters to parse */ @@ -1666,7 +1680,7 @@ public: private: /** Pointer to the current position in the raw input stream. */ - const char *m_ptr; + char *m_ptr; /** Starting position of the last token parsed, in the raw buffer. */ const char *m_tok_start; @@ -2348,7 +2362,7 @@ public: @retval FALSE OK @retval TRUE Error */ - bool init(THD *thd, const char *buff, unsigned int length) + bool init(THD *thd, char *buff, unsigned int length) { return m_lip.init(thd, buff, length); } @@ -2359,7 +2373,7 @@ public: Lex_input_stream m_lip; Yacc_state m_yacc; - void reset(const char *found_semicolon, unsigned int length) + void reset(char *found_semicolon, unsigned int length) { m_lip.reset(found_semicolon, length); m_yacc.reset(); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index b2a816a69dd..d367c1c4fde 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -175,6 +175,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, bool is_fifo=0; #ifndef EMBEDDED_LIBRARY LOAD_FILE_INFO lf_info; + THD::killed_state killed_status= THD::NOT_KILLED; #endif char *db = table_list->db; // This is never null /* @@ -186,7 +187,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ulong skip_lines= ex->skip_lines; bool transactional_table; bool is_concurrent; - THD::killed_state killed_status= THD::NOT_KILLED; DBUG_ENTER("mysql_load"); #ifdef EMBEDDED_LIBRARY @@ -510,7 +510,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, error=1; thd->killed= THD::KILL_QUERY; };); - killed_status= (error == 0)? THD::NOT_KILLED : thd->killed; + +#ifndef EMBEDDED_LIBRARY + killed_status= (error == 0) ? THD::NOT_KILLED : thd->killed; +#endif + /* We must invalidate the table in query cache before binlog writing and ha_autocommit_... @@ -553,7 +557,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (lf_info.wrote_create_file) { int errcode= query_error_code(thd, killed_status == THD::NOT_KILLED); - + /* since there is already an error, the possible error of writing binary log will be ignored */ if (thd->transaction.stmt.modified_non_trans_table) @@ -767,12 +771,9 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, List_iterator_fast<Item> it(fields_vars); Item_field *sql_field; TABLE *table= table_list->table; - ulonglong id; bool err; DBUG_ENTER("read_fixed_length"); - id= 0; - while (!read_info.read_fixed_length()) { if (thd->killed) @@ -901,12 +902,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, Item *item; TABLE *table= table_list->table; uint enclosed_length; - ulonglong id; bool err; DBUG_ENTER("read_sep_field"); enclosed_length=enclosed.length(); - id= 0; for (;;it.rewind()) { diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 56461f1174b..2ef8e9761b1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -115,6 +115,7 @@ "FUNCTION" : "PROCEDURE") static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); +static void sql_kill(THD *thd, ulong id, bool only_kill_query); const char *any_db="*any*"; // Special symbol for check_access @@ -270,10 +271,10 @@ void init_update_queries(void) sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | 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; - sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL; + sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL; + sql_command_flags[SQLCOM_ALTER_DB_UPGRADE]= CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL; + sql_command_flags[SQLCOM_ALTER_DB]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS | CF_PROTECT_AGAINST_GRL; sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE | @@ -413,6 +414,9 @@ void init_update_queries(void) sql_command_flags[SQLCOM_FLUSH]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_RESET]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_CHECK]= CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_CREATE_SERVER]= CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_ALTER_SERVER]= CF_AUTO_COMMIT_TRANS; + sql_command_flags[SQLCOM_DROP_SERVER]= CF_AUTO_COMMIT_TRANS; } bool sqlcom_can_generate_row_events(const THD *thd) @@ -568,7 +572,6 @@ static void handle_bootstrap_impl(THD *thd) } mysql_parse(thd, thd->query(), length, &parser_state); - close_thread_tables(thd); // Free tables bootstrap_error= thd->is_error(); thd->protocol->end_statement(); @@ -1139,13 +1142,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { char *beginning_of_next_stmt= (char*) parser_state.m_lip.found_semicolon; - - thd->protocol->end_statement(); - query_cache_end_of_result(thd); /* Multiple queries exits, execute them individually */ - close_thread_tables(thd); + thd->protocol->end_statement(); + query_cache_end_of_result(thd); ulong length= (ulong)(packet_end - beginning_of_next_stmt); log_slow_statement(thd); @@ -1197,38 +1198,54 @@ bool dispatch_command(enum enum_server_command command, THD *thd, char *fields, *packet_end= packet + packet_length, *arg_end; /* Locked closure of all tables */ TABLE_LIST table_list; - LEX_STRING conv_name; - - /* used as fields initializator */ - lex_start(thd); + LEX_STRING table_name; + LEX_STRING db; + /* + SHOW statements should not add the used tables to the list of tables + used in a transaction. + */ + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS]); - bzero((char*) &table_list,sizeof(table_list)); - if (thd->copy_db_to(&table_list.db, &table_list.db_length)) + if (thd->copy_db_to(&db.str, &db.length)) break; /* We have name + wildcard in packet, separated by endzero */ arg_end= strend(packet); uint arg_length= arg_end - packet; - + /* Check given table name length. */ if (arg_length >= packet_length || arg_length > NAME_LEN) { my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); break; } - thd->convert_string(&conv_name, system_charset_info, + thd->convert_string(&table_name, system_charset_info, packet, arg_length, thd->charset()); - if (check_table_name(conv_name.str, conv_name.length, FALSE)) + if (check_table_name(table_name.str, table_name.length, FALSE)) { /* this is OK due to convert_string() null-terminating the string */ - my_error(ER_WRONG_TABLE_NAME, MYF(0), conv_name.str); + my_error(ER_WRONG_TABLE_NAME, MYF(0), table_name.str); break; } - - table_list.alias= table_list.table_name= conv_name.str; packet= arg_end + 1; + mysql_reset_thd_for_next_command(thd); + lex_start(thd); + /* Must be before we init the table list. */ + if (lower_case_table_names) + table_name.length= my_casedn_str(files_charset_info, table_name.str); + table_list.init_one_table(db.str, db.length, table_name.str, + table_name.length, table_name.str, TL_READ); + /* + Init TABLE_LIST members necessary when the undelrying + table is view. + */ + table_list.select_lex= &(thd->lex->select_lex); + thd->lex-> + select_lex.table_list.link_in_list(&table_list, + &table_list.next_local); + thd->lex->add_to_query_tables(&table_list); if (is_infoschema_db(table_list.db, table_list.db_length)) { @@ -1242,32 +1259,23 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; thd->set_query(fields, query_length); general_log_print(thd, command, "%s %s", table_list.table_name, fields); - if (lower_case_table_names) - my_casedn_str(files_charset_info, table_list.table_name); - if (check_access(thd, SELECT_ACL, table_list.db, - &table_list.grant.privilege, - &table_list.grant.m_internal, - 0, 0)) - break; - if (check_grant(thd, SELECT_ACL, &table_list, TRUE, UINT_MAX, FALSE)) + if (check_table_access(thd, SELECT_ACL, &table_list, + TRUE, UINT_MAX, FALSE)) break; - /* init structures for VIEW processing */ - table_list.select_lex= &(thd->lex->select_lex); - - lex_start(thd); - mysql_reset_thd_for_next_command(thd); - - thd->lex-> - select_lex.table_list.link_in_list(&table_list, - &table_list.next_local); - thd->lex->add_to_query_tables(&table_list); - init_mdl_requests(&table_list); - - /* switch on VIEW optimisation: do not fill temporary tables */ + /* + Turn on an optimization relevant if the underlying table + is a view: do not fill derived tables. + */ thd->lex->sql_command= SQLCOM_SHOW_FIELDS; + mysqld_list_fields(thd,&table_list,fields); thd->lex->unit.cleanup(); + /* No need to rollback statement transaction, it's not started. */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); + close_thread_tables(thd); + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + thd->cleanup_after_query(); break; } @@ -1315,7 +1323,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ulong options= (ulong) (uchar) packet[0]; if (trans_commit_implicit(thd)) break; - close_thread_tables(thd); thd->mdl_context.release_transactional_locks(); if (check_global_access(thd,RELOAD_ACL)) break; @@ -1377,7 +1384,6 @@ bool dispatch_command(enum enum_server_command command, THD *thd, DBUG_PRINT("quit",("Got shutdown command for level %u", level)); general_log_print(thd, command, NullS); my_eof(thd); - close_thread_tables(thd); // Free before kill kill_mysql(); error=TRUE; break; @@ -1387,7 +1393,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { STATUS_VAR current_global_status_var; ulong uptime; - uint length; + uint length __attribute__((unused)); ulonglong queries_per_second1000; char buff[250]; uint buff_len= sizeof(buff); @@ -1400,7 +1406,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, else queries_per_second1000= thd->query_id * LL(1000) / uptime; - length= my_snprintf((char*) buff, buff_len - 1, + length= my_snprintf(buff, buff_len - 1, "Uptime: %lu Threads: %d Questions: %lu " "Slow queries: %lu Opens: %lu Flush tables: %lu " "Open tables: %u Queries per second avg: %u.%u", @@ -1480,33 +1486,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd, my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); break; } - - /* report error issued during command execution */ - if (thd->killed_errno()) - { - if (! thd->stmt_da->is_set()) - thd->send_kill_message(); - } - if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA) - { - thd->killed= THD::NOT_KILLED; - thd->mysys_var->abort= 0; - } - - /* If commit fails, we should be able to reset the OK status. */ - thd->stmt_da->can_overwrite_status= TRUE; - thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); - thd->stmt_da->can_overwrite_status= FALSE; - - thd->transaction.stmt.reset(); + DBUG_ASSERT(thd->derived_tables == NULL && + (thd->open_tables == NULL || + (thd->locked_tables_mode == LTM_LOCK_TABLES))); thd->protocol->end_statement(); query_cache_end_of_result(thd); - thd->proc_info= "closing tables"; - /* Free tables */ - close_thread_tables(thd); - if (!thd->is_error() && !thd->killed_errno()) mysql_audit_general(thd, MYSQL_AUDIT_GENERAL_RESULT, 0, 0); @@ -1525,7 +1511,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, #endif if (MYSQL_QUERY_DONE_ENABLED() || MYSQL_COMMAND_DONE_ENABLED()) { - int res; + int res __attribute__((unused)); res= (int) thd->is_error(); if (command == COM_QUERY) { @@ -1715,6 +1701,9 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, In brief: take exclusive locks, expel tables from the table cache, reopen the tables, enter the 'LOCKED TABLES' mode, downgrade the locks. + Note: the function is written to be called from + mysql_execute_command(), it is not reusable in arbitrary + execution context. Required privileges ------------------- @@ -1792,7 +1781,8 @@ static bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables) current internal MDL asserts, fix after discussing with Dmitry. */ - if (lock_table_names(thd, all_tables)) + if (lock_table_names(thd, all_tables, 0, thd->variables.lock_wait_timeout, + MYSQL_OPEN_SKIP_TEMPORARY)) goto error; for (table_list= all_tables; table_list; @@ -1815,9 +1805,9 @@ static bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables) &lock_tables_prelocking_strategy) || thd->locked_tables_list.init_locked_tables(thd)) { - close_thread_tables(thd); goto error; } + thd->variables.option_bits|= OPTION_TABLE_LOCK; /* Downgrade the exclusive locks. @@ -2040,6 +2030,7 @@ mysql_execute_command(THD *thd) thd->work_part_info= 0; #endif + DBUG_ASSERT(thd->transaction.stmt.is_empty() || thd->in_sub_stmt); /* In many cases first table of main SELECT_LEX have special meaning => check that it is first table in global list and relink it first in @@ -2221,8 +2212,7 @@ mysql_execute_command(THD *thd) /* Commit the normal transaction if one is active. */ if (trans_commit_implicit(thd)) goto error; - /* Close tables and release metadata locks. */ - close_thread_tables(thd); + /* Release metadata locks acquired in this transaction. */ thd->mdl_context.release_transactional_locks(); } @@ -3535,24 +3525,27 @@ end_with_restore_list: done FLUSH TABLES WITH READ LOCK + BEGIN. If this assumption becomes false, mysqldump will not work. */ - thd->locked_tables_list.unlock_locked_tables(thd); if (thd->variables.option_bits & OPTION_TABLE_LOCK) { - trans_commit_implicit(thd); + res= trans_commit_implicit(thd); + thd->locked_tables_list.unlock_locked_tables(thd); thd->mdl_context.release_transactional_locks(); thd->variables.option_bits&= ~(OPTION_TABLE_LOCK); } if (thd->global_read_lock.is_acquired()) thd->global_read_lock.unlock_global_read_lock(thd); + if (res) + goto error; my_ok(thd); break; case SQLCOM_LOCK_TABLES: + /* We must end the transaction first, regardless of anything */ + res= trans_commit_implicit(thd); thd->locked_tables_list.unlock_locked_tables(thd); - /* we must end the trasaction first, regardless of anything */ - if (trans_commit_implicit(thd)) - goto error; - /* release transactional metadata locks. */ + /* Release transactional metadata locks. */ thd->mdl_context.release_transactional_locks(); + if (res) + goto error; if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)) goto error; @@ -3575,17 +3568,14 @@ end_with_restore_list: if (res) { + trans_rollback_stmt(thd); /* Need to end the current transaction, so the storage engine (InnoDB) can free its locks if LOCK TABLES locked some tables before finding that it can't lock a table in its list */ - trans_rollback_stmt(thd); trans_commit_implicit(thd); - /* - Close tables and release metadata locks otherwise a later call to - close_thread_tables might not release the locks if autocommit is off. - */ + /* Close tables and release metadata locks. */ close_thread_tables(thd); DBUG_ASSERT(!thd->locked_tables_mode); thd->mdl_context.release_transactional_locks(); @@ -3633,12 +3623,6 @@ end_with_restore_list: #endif if (check_access(thd, CREATE_ACL, lex->name.str, NULL, NULL, 1, 0)) break; - if (thd->locked_tables_mode) - { - my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, - ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); - goto error; - } res= mysql_create_db(thd,(lower_case_table_names == 2 ? alias : lex->name.str), &create_info, 0); break; @@ -3668,12 +3652,6 @@ end_with_restore_list: #endif if (check_access(thd, DROP_ACL, lex->name.str, NULL, NULL, 1, 0)) break; - if (thd->locked_tables_mode) - { - my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, - ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); - goto error; - } res= mysql_rm_db(thd, lex->name.str, lex->drop_if_exists, 0); break; } @@ -3702,14 +3680,6 @@ end_with_restore_list: res= 1; break; } - if (thd->locked_tables_mode) - { - res= 1; - my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, - ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); - goto error; - } - res= mysql_upgrade_db(thd, db); if (!res) my_ok(thd); @@ -3742,12 +3712,6 @@ end_with_restore_list: #endif if (check_access(thd, ALTER_ACL, db->str, NULL, NULL, 1, 0)) break; - if (thd->locked_tables_mode) - { - my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, - ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); - goto error; - } res= mysql_alter_db(thd, db->str, &create_info); break; } @@ -4230,9 +4194,7 @@ end_with_restore_list: locks in the MDL context, so there is no risk to deadlock. */ - trans_commit_implicit(thd); - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); + close_mysql_tables(thd); /* Check if the definer exists on slave, then use definer privilege to insert routine privileges to mysql.procs_priv. @@ -4509,9 +4471,7 @@ create_sp_error: locks in the MDL context, so there is no risk to deadlock. */ - trans_commit_implicit(thd); - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); + close_mysql_tables(thd); if (sp_automatic_privileges && !opt_noacl && sp_revoke_privileges(thd, db, name, @@ -4803,17 +4763,60 @@ finish: DBUG_ASSERT(!thd->in_active_multi_stmt_transaction() || thd->in_multi_stmt_transaction_mode()); + + if (! thd->in_sub_stmt) + { + /* report error issued during command execution */ + if (thd->killed_errno()) + { + if (! thd->stmt_da->is_set()) + thd->send_kill_message(); + } + if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA) + { + thd->killed= THD::NOT_KILLED; + thd->mysys_var->abort= 0; + } + if (thd->is_error() || (thd->variables.option_bits & OPTION_MASTER_SQL_ERROR)) + trans_rollback_stmt(thd); + else + { + /* If commit fails, we should be able to reset the OK status. */ + thd->stmt_da->can_overwrite_status= TRUE; + trans_commit_stmt(thd); + thd->stmt_da->can_overwrite_status= FALSE; + } + } + + lex->unit.cleanup(); + /* Free tables */ + thd_proc_info(thd, "closing tables"); + close_thread_tables(thd); + thd_proc_info(thd, 0); + if (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END)) { + /* No transaction control allowed in sub-statements. */ + DBUG_ASSERT(! thd->in_sub_stmt); /* If commit fails, we should be able to reset the OK status. */ thd->stmt_da->can_overwrite_status= TRUE; - /* Commit or rollback the statement transaction. */ - thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd); /* Commit the normal transaction if one is active. */ trans_commit_implicit(thd); thd->stmt_da->can_overwrite_status= FALSE; - /* Close tables and release metadata locks. */ - close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); + } + else if (! thd->in_sub_stmt && ! thd->in_multi_stmt_transaction_mode()) + { + /* + - If inside a multi-statement transaction, + defer the release of metadata locks until the current + transaction is either committed or rolled back. This prevents + other statements from modifying the table for the entire + duration of this transaction. This provides commit ordering + and guarantees serializability across multiple transactions. + - If in autocommit mode, or outside a transactional context, + automatically release metadata locks of the current statement. + */ thd->mdl_context.release_transactional_locks(); } @@ -5817,16 +5820,16 @@ void mysql_init_multi_delete(LEX *lex) Parse a query. @param thd Current thread - @param inBuf Begining of the query text + @param rawbuf Begining of the query text @param length Length of the query text @param[out] found_semicolon For multi queries, position of the character of the next query in the query text. */ -void mysql_parse(THD *thd, const char *inBuf, uint length, +void mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state) { - int error; + int error __attribute__((unused)); DBUG_ENTER("mysql_parse"); DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on();); @@ -5850,7 +5853,7 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, lex_start(thd); mysql_reset_thd_for_next_command(thd); - if (query_cache_send_result_to_client(thd, (char*) inBuf, length) <= 0) + if (query_cache_send_result_to_client(thd, rawbuf, length) <= 0) { LEX *lex= thd->lex; @@ -5911,12 +5914,6 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, query_cache_abort(&thd->query_cache_tls); } - if (thd->lex->sphead) - { - delete thd->lex->sphead; - thd->lex->sphead= 0; - } - lex->unit.cleanup(); thd_proc_info(thd, "freeing items"); thd->end_statement(); thd->cleanup_after_query(); @@ -5938,14 +5935,14 @@ void mysql_parse(THD *thd, const char *inBuf, uint length, 1 can be ignored */ -bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length) +bool mysql_test_parse_for_slave(THD *thd, char *rawbuf, uint length) { LEX *lex= thd->lex; bool error= 0; DBUG_ENTER("mysql_test_parse_for_slave"); Parser_state parser_state; - if (!(error= parser_state.init(thd, inBuf, length))) + if (!(error= parser_state.init(thd, rawbuf, length))) { lex_start(thd); mysql_reset_thd_for_next_command(thd); @@ -7022,11 +7019,15 @@ uint kill_one_thread(THD *thd, ulong id, bool only_kill_query) only_kill_query Should it kill the query or the connection */ +static void sql_kill(THD *thd, ulong id, bool only_kill_query) { uint error; if (!(error= kill_one_thread(thd, id, only_kill_query))) - my_ok(thd); + { + if (! thd->killed) + my_ok(thd); + } else my_error(error, MYF(0), id); } diff --git a/sql/sql_parse.h b/sql/sql_parse.h index 475811d45b7..8b7fe8f7b83 100644 --- a/sql/sql_parse.h +++ b/sql/sql_parse.h @@ -51,7 +51,6 @@ bool parse_sql(THD *thd, Object_creation_ctx *creation_ctx); uint kill_one_thread(THD *thd, ulong id, bool only_kill_query); -void sql_kill(THD *thd, ulong id, bool only_kill_query); void free_items(Item *item); void cleanup_items(Item *item); @@ -84,7 +83,7 @@ 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); void mysql_init_select(LEX *lex); -void mysql_parse(THD *thd, const char *inBuf, uint length, +void mysql_parse(THD *thd, char *rawbuf, uint length, Parser_state *parser_state); void mysql_reset_thd_for_next_command(THD *thd); bool mysql_new_select(LEX *lex, bool move_down); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index d7ff753dfd0..fb880cce8d3 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -59,7 +59,7 @@ #include "my_md5.h" #include "transaction.h" -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // close_all_tables_for_name #include "sql_table.h" // build_table_filename, // build_table_shadow_filename, // table_to_filename @@ -1071,7 +1071,6 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, partition_info *part_info= table->part_info; bool result= TRUE; int error; - const char *save_where; LEX *old_lex= thd->lex; LEX lex; uint8 saved_full_group_by_flag; @@ -1083,7 +1082,6 @@ static bool fix_fields_part_func(THD *thd, Item* func_expr, TABLE *table, func_expr->walk(&Item::change_context_processor, 0, (uchar*) &lex.select_lex.context); - save_where= thd->where; thd->where= "partition function"; /* In execution we must avoid the use of thd->change_item_tree since @@ -4185,7 +4183,7 @@ 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, + char *part_buf, uint part_info_len, TABLE* table, bool is_create_table_ind, handlerton *default_db_type, bool *work_part_info_used) @@ -6758,7 +6756,6 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, table_list, FALSE, NULL, written_bin_log)); err: - close_thread_tables(thd); DBUG_RETURN(TRUE); } #endif diff --git a/sql/sql_partition.h b/sql/sql_partition.h index 2e0ea740555..c644e63794c 100644 --- a/sql/sql_partition.h +++ b/sql/sql_partition.h @@ -110,7 +110,7 @@ void get_full_part_id_from_key(const TABLE *table, uchar *buf, KEY *key_info, const key_range *key_spec, part_id_range *part_spec); -bool mysql_unpack_partition(THD *thd, const char *part_buf, +bool mysql_unpack_partition(THD *thd, char *part_buf, uint part_info_len, TABLE *table, bool is_create_table_ind, handlerton *default_db_type, diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 3a0945faa49..7e8c1fed999 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -21,7 +21,7 @@ #include "sql_locale.h" #include "sql_plugin.h" #include "sql_parse.h" // check_table_access -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // close_mysql_tables #include "key.h" // key_copy #include "sql_show.h" // remove_status_vars, add_status_vars #include "strfunc.h" // find_set @@ -1453,8 +1453,8 @@ static void plugin_load(MEM_ROOT *tmp_root, int *argc, char **argv) sql_print_error(ER(ER_GET_ERRNO), my_errno); end_read_record(&read_record_info); table->m_needs_reopen= TRUE; // Force close to free memory + close_mysql_tables(new_thd); end: - close_thread_tables(new_thd); /* Remember that we don't have a THD */ my_pthread_setspecific_ptr(THR_THD, 0); DBUG_VOID_RETURN; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 089e751900e..a77dbe2dab4 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -90,7 +90,7 @@ When one supplies long data for a placeholder: #include "set_var.h" #include "sql_prepare.h" #include "sql_parse.h" // insert_precheck, update_precheck, delete_precheck -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // open_normal_and_derived_tables #include "sql_cache.h" // query_cache_* #include "sql_view.h" // create_view_precheck #include "sql_delete.h" // mysql_prepare_delete @@ -152,6 +152,7 @@ public: THD *thd; Select_fetch_protocol_binary result; Item_param **param_array; + Server_side_cursor *cursor; uint param_count; uint last_errno; uint flags; @@ -352,8 +353,11 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns) &stmt->lex->param_list, Protocol::SEND_EOF); } - /* Flag that a response has already been sent */ - thd->stmt_da->disable_status(); + + if (!error) + /* Flag that a response has already been sent */ + thd->stmt_da->disable_status(); + DBUG_RETURN(error); } #else @@ -2672,7 +2676,6 @@ void mysqld_stmt_fetch(THD *thd, char *packet, uint packet_length) if (!cursor->is_open()) { stmt->close_cursor(); - thd->cursor= 0; reset_stmt_params(stmt); } @@ -2989,12 +2992,6 @@ Execute_sql_statement::execute_server_code(THD *thd) error= mysql_execute_command(thd); - if (thd->killed_errno()) - { - if (! thd->stmt_da->is_set()) - thd->send_kill_message(); - } - /* report error issued during command execution */ if (error == 0 && thd->spcont == NULL) general_log_write(thd, COM_STMT_EXECUTE, @@ -3016,6 +3013,7 @@ Prepared_statement::Prepared_statement(THD *thd_arg) thd(thd_arg), result(thd_arg), param_array(0), + cursor(0), param_count(0), last_errno(0), flags((uint) IS_IN_USE) @@ -3102,13 +3100,8 @@ void Prepared_statement::cleanup_stmt() DBUG_ENTER("Prepared_statement::cleanup_stmt"); DBUG_PRINT("enter",("stmt: 0x%lx", (long) this)); - delete lex->sphead; - lex->sphead= 0; - /* The order is important */ - lex->unit.cleanup(); cleanup_items(free_list); thd->cleanup_after_query(); - close_thread_tables(thd); thd->rollback_item_tree_changes(); DBUG_VOID_RETURN; @@ -3272,21 +3265,16 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len) to PREPARE stmt FROM "CREATE PROCEDURE ..." */ DBUG_ASSERT(lex->sphead == NULL || error != 0); - if (lex->sphead) - { - delete lex->sphead; - lex->sphead= NULL; - } + /* The order is important */ + lex->unit.cleanup(); + /* No need to commit statement transaction, it's not started. */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); + + close_thread_tables(thd); + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); lex_end(lex); cleanup_stmt(); - /* - If not inside a multi-statement transaction, the metadata - locks have already been released and our savepoint points - to ticket which has been released as well. - */ - 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; @@ -3393,11 +3381,6 @@ Prepared_statement::set_parameters(String *expanded_query, and execute of a new statement. If this happens repeatedly more than MAX_REPREPARE_ATTEMPTS times, we give up. - In future we need to be able to keep the metadata locks between - prepare and execute, but right now open_and_lock_tables(), as - well as close_thread_tables() are buried deep inside - execution code (mysql_execute_command()). - @return TRUE if an error, FALSE if success @retval TRUE either MAX_REPREPARE_ATTEMPTS has been reached, or some general error @@ -3484,11 +3467,6 @@ Prepared_statement::execute_server_runnable(Server_runnable *server_runnable) error= server_runnable->execute_server_code(thd); - delete lex->sphead; - lex->sphead= 0; - /* The order is important */ - lex->unit.cleanup(); - close_thread_tables(thd); thd->cleanup_after_query(); thd->restore_active_arena(this, &stmt_backup); @@ -3777,8 +3755,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor) /* Go! */ if (open_cursor) - error= mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR, - &result, &cursor); + error= mysql_open_cursor(thd, &result, &cursor); else { /* diff --git a/sql/sql_priv.h b/sql/sql_priv.h index 7067ca084e2..f0f6a1969f5 100644 --- a/sql/sql_priv.h +++ b/sql/sql_priv.h @@ -133,6 +133,16 @@ Type of locks to be acquired is specified directly. */ #define SELECT_HIGH_PRIORITY (1ULL << 34) // SELECT, user +/** + Is set in slave SQL thread when there was an + error on master, which, when is not reproducible + on slave (i.e. the query succeeds on slave), + is not terminal to the state of repliation, + and should be ignored. The slave SQL thread, + however, needs to rollback the effects of the + succeeded statement to keep replication consistent. +*/ +#define OPTION_MASTER_SQL_ERROR (1ULL << 35) /* The rest of the file is included in the server only */ diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 130a99a374f..301b22bd70e 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -24,10 +24,9 @@ #include "sql_table.h" // build_table_filename #include "sql_view.h" // mysql_frm_type, mysql_rename_view #include "sql_trigger.h" -#include "lock.h" // wait_if_global_read_lock, lock_table_names, - // unlock_table_names, +#include "lock.h" // wait_if_global_read_lock // start_waiting_global_read_lock -#include "sql_base.h" // tdc_remove_table +#include "sql_base.h" // tdc_remove_table, lock_table_names, #include "sql_handler.h" // mysql_ha_rm_tables #include "datadict.h" @@ -144,7 +143,8 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) } } - if (lock_table_names(thd, table_list)) + if (lock_table_names(thd, table_list, 0, thd->variables.lock_wait_timeout, + MYSQL_OPEN_SKIP_TEMPORARY)) goto err; mysql_mutex_lock(&LOCK_open); @@ -197,7 +197,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent) if (!error) query_cache_invalidate3(thd, table_list, 0); - unlock_table_names(thd); + thd->mdl_context.release_transactional_locks(); err: thd->global_read_lock.start_waiting_global_read_lock(thd); diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 5f994c09d6d..ab6c6e738b2 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -452,6 +452,7 @@ void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, #ifndef DBUG_OFF int left_events = max_binlog_dump_events; #endif + int old_max_allowed_packet= thd->variables.max_allowed_packet; DBUG_ENTER("mysql_binlog_send"); DBUG_PRINT("enter",("log_ident: '%s' pos: %ld", log_ident, (long) pos)); @@ -975,6 +976,7 @@ end: mysql_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; mysql_mutex_unlock(&LOCK_thread_count); + thd->variables.max_allowed_packet= old_max_allowed_packet; DBUG_VOID_RETURN; err: @@ -993,6 +995,7 @@ err: mysql_mutex_unlock(&LOCK_thread_count); if (file >= 0) mysql_file_close(file, MYF(MY_WME)); + thd->variables.max_allowed_packet= old_max_allowed_packet; my_message(my_errno, errmsg, MYF(0)); DBUG_VOID_RETURN; @@ -1394,12 +1397,9 @@ bool change_master(THD* thd, Master_info* mi) /* Before processing the command, save the previous state. */ - char *pos; - pos= strmake(saved_host, mi->host, HOSTNAME_LENGTH); - pos= '\0'; + strmake(saved_host, mi->host, HOSTNAME_LENGTH); saved_port= mi->port; - pos= strmake(saved_log_name, mi->master_log_name, FN_REFLEN - 1); - pos= '\0'; + strmake(saved_log_name, mi->master_log_name, FN_REFLEN - 1); saved_log_pos= mi->master_log_pos; /* @@ -1690,6 +1690,7 @@ bool mysql_show_binlog_events(THD* thd) IO_CACHE log; File file = -1; MYSQL_BIN_LOG *binary_log= NULL; + int old_max_allowed_packet= thd->variables.max_allowed_packet; DBUG_ENTER("mysql_show_binlog_events"); Log_event::init_show_field_list(&field_list); @@ -1844,6 +1845,7 @@ err: mysql_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; mysql_mutex_unlock(&LOCK_thread_count); + thd->variables.max_allowed_packet= old_max_allowed_packet; DBUG_RETURN(ret); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0c351813d4e..ccfd93a1bc8 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -33,7 +33,6 @@ #include "sql_select.h" #include "sql_cache.h" // query_cache_* #include "sql_table.h" // primary_key_name -#include "sql_cursor.h" #include "probes_mysql.h" #include "key.h" // key_copy, key_cmp, key_cmp_if_same #include "lock.h" // mysql_unlock_some_tables, @@ -2340,35 +2339,13 @@ JOIN::exec() curr_join->fields= curr_fields_list; curr_join->procedure= procedure; - if (is_top_level_join() && thd->cursor && tables != const_tables) - { - /* - We are here if this is JOIN::exec for the last select of the main unit - and the client requested to open a cursor. - We check that not all tables are constant because this case is not - handled by do_select() separately, and this case is not implemented - for cursors yet. - */ - DBUG_ASSERT(error == 0); - /* - curr_join is used only for reusable joins - that is, - to perform SELECT for each outer row (like in subselects). - This join is main, so we know for sure that curr_join == join. - */ - DBUG_ASSERT(curr_join == this); - /* Open cursor for the last join sweep */ - error= thd->cursor->open(this); - } - else - { - thd_proc_info(thd, "Sending data"); - DBUG_PRINT("info", ("%s", thd->proc_info)); - result->send_result_set_metadata((procedure ? curr_join->procedure_fields_list : - *curr_fields_list), - Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); - error= do_select(curr_join, curr_fields_list, NULL, procedure); - thd->limit_found_rows= curr_join->send_records; - } + thd_proc_info(thd, "Sending data"); + DBUG_PRINT("info", ("%s", thd->proc_info)); + result->send_result_set_metadata((procedure ? curr_join->procedure_fields_list : + *curr_fields_list), + Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); + error= do_select(curr_join, curr_fields_list, NULL, procedure); + thd->limit_found_rows= curr_join->send_records; /* Accumulate the counts from all join iterations of all join parts. */ thd->examined_row_count+= curr_join->examined_rows; @@ -2563,16 +2540,6 @@ mysql_select(THD *thd, Item ***rref_pointer_array, join->exec(); - if (thd->cursor && thd->cursor->is_open()) - { - /* - A cursor was opened for the last sweep in exec(). - We are here only if this is mysql_select for top-level SELECT_LEX_UNIT - and there were no error. - */ - free_join= 0; - } - if (thd->lex->describe & DESCRIBE_EXTENDED) { select_lex->where= join->conds_history; @@ -11642,37 +11609,23 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) enum_nested_loop_state rc; READ_RECORD *info= &join_tab->read_record; - if (join->resume_nested_loop) - { - /* If not the last table, plunge down the nested loop */ - if (join_tab < join->join_tab + join->tables - 1) - rc= (*join_tab->next_select)(join, join_tab + 1, 0); - else - { - join->resume_nested_loop= FALSE; - rc= NESTED_LOOP_OK; - } - } - else - { - join->return_tab= join_tab; - - if (join_tab->last_inner) - { - /* join_tab is the first inner table for an outer join operation. */ + join->return_tab= join_tab; - /* Set initial state of guard variables for this table.*/ - join_tab->found=0; - join_tab->not_null_compl= 1; + if (join_tab->last_inner) + { + /* join_tab is the first inner table for an outer join operation. */ - /* Set first_unmatched for the last inner table of this group */ - join_tab->last_inner->first_unmatched= join_tab; - } - join->thd->warning_info->reset_current_row_for_warning(); + /* Set initial state of guard variables for this table.*/ + join_tab->found=0; + join_tab->not_null_compl= 1; - error= (*join_tab->read_first_record)(join_tab); - rc= evaluate_join_record(join, join_tab, error); + /* Set first_unmatched for the last inner table of this group */ + join_tab->last_inner->first_unmatched= join_tab; } + join->thd->warning_info->reset_current_row_for_warning(); + + error= (*join_tab->read_first_record)(join_tab); + rc= evaluate_join_record(join, join_tab, error); while (rc == NESTED_LOOP_OK) { @@ -13244,7 +13197,7 @@ static int test_if_order_by_key(ORDER *order, TABLE *table, uint idx, DBUG_RETURN(0); } - if (key_part->field != field) + if (key_part->field != field || !field->part_of_sortkey.is_set(idx)) DBUG_RETURN(0); /* set flag to 1 if we can use read-next on key, else to -1 */ diff --git a/sql/sql_select.h b/sql/sql_select.h index 0496870bb3f..40f9e6d4054 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -309,11 +309,6 @@ public: bool sort_and_group; bool first_record,full_join,group, no_field_update; bool do_send_rows; - /** - TRUE when we want to resume nested loop iterations when - fetching data from a cursor - */ - bool resume_nested_loop; table_map const_table_map,found_const_table_map; /* Bitmap of all inner tables from outer joins @@ -479,7 +474,6 @@ public: sort_and_group= 0; first_record= 0; do_send_rows= 1; - resume_nested_loop= FALSE; send_records= 0; found_records= 0; fetch_limit= HA_POS_ERROR; diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index c7f9cf0b132..cfbf8e96719 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -36,7 +36,7 @@ #include "sql_priv.h" #include "sql_servers.h" #include "unireg.h" -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // close_mysql_tables #include "records.h" // init_read_record, end_read_record #include "hash_filo.h" #include <m_ctype.h> @@ -280,9 +280,7 @@ bool servers_reload(THD *thd) } end: - trans_commit_implicit(thd); - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); + close_mysql_tables(thd); DBUG_PRINT("info", ("unlocking servers_cache")); mysql_rwlock_unlock(&THR_LOCK_servers); DBUG_RETURN(return_val); @@ -535,6 +533,7 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server) { int error; DBUG_ENTER("insert_server_record"); + tmp_disable_binlog(table->in_use); table->use_all_columns(); empty_record(table); @@ -571,6 +570,8 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server) } else error= ER_FOREIGN_SERVER_EXISTS; + + reenable_binlog(table->in_use); DBUG_RETURN(error); } @@ -625,7 +626,7 @@ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options) error= delete_server_record(table, name.str, name.length); /* close the servers table before we call closed_cached_connection_tables */ - close_thread_tables(thd); + close_mysql_tables(thd); if (close_cached_connection_tables(thd, TRUE, &name)) { @@ -880,6 +881,7 @@ update_server_record(TABLE *table, FOREIGN_SERVER *server) { int error=0; DBUG_ENTER("update_server_record"); + tmp_disable_binlog(table->in_use); table->use_all_columns(); /* set the field that's the PK to the value we're looking for */ table->field[0]->store(server->server_name, @@ -913,6 +915,7 @@ update_server_record(TABLE *table, FOREIGN_SERVER *server) } end: + reenable_binlog(table->in_use); DBUG_RETURN(error); } @@ -938,6 +941,7 @@ delete_server_record(TABLE *table, { int error; DBUG_ENTER("delete_server_record"); + tmp_disable_binlog(table->in_use); table->use_all_columns(); /* set the field that's the PK to the value we're looking for */ @@ -959,6 +963,7 @@ delete_server_record(TABLE *table, table->file->print_error(error, MYF(0)); } + reenable_binlog(table->in_use); DBUG_RETURN(error); } @@ -1050,7 +1055,7 @@ int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options) error= update_server(thd, existing, altered); /* close the servers table before we call closed_cached_connection_tables */ - close_thread_tables(thd); + close_mysql_tables(thd); if (close_cached_connection_tables(thd, FALSE, &name)) { diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 78508df2c9e..4d58db2e36c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -460,8 +460,19 @@ find_files(THD *thd, List<LEX_STRING> *files, const char *db, continue; file_name_len= filename_to_tablename(file->name, uname, sizeof(uname)); - if (wild && wild_compare(uname, wild, 0)) - continue; + if (wild) + { + if (lower_case_table_names) + { + if (my_wildcmp(files_charset_info, + uname, uname + file_name_len, + wild, wild + wild_length, + wild_prefix, wild_one,wild_many)) + continue; + } + else if (wild_compare(uname, wild, 0)) + continue; + } if (!(file_name= thd->make_lex_string(file_name, uname, file_name_len, TRUE))) { @@ -649,22 +660,30 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) Protocol *protocol= thd->protocol; char buff[2048]; String buffer(buff, sizeof(buff), system_charset_info); + List<Item> field_list; + bool error= TRUE; DBUG_ENTER("mysqld_show_create"); DBUG_PRINT("enter",("db: %s table: %s",table_list->db, table_list->table_name)); + /* + Metadata locks taken during SHOW CREATE should be released when + the statmement completes as it is an information statement. + */ + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); + /* We want to preserve the tree for views. */ thd->lex->view_prepare_mode= TRUE; { Show_create_error_handler view_error_suppressor(thd, table_list); thd->push_internal_handler(&view_error_suppressor); - bool error= + bool open_error= open_normal_and_derived_tables(thd, table_list, MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL); thd->pop_internal_handler(); - if (error && (thd->killed || thd->is_error())) - DBUG_RETURN(TRUE); + if (open_error && (thd->killed || thd->is_error())) + goto exit; } /* TODO: add environment variables show when it become possible */ @@ -672,7 +691,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) { my_error(ER_WRONG_OBJECT, MYF(0), table_list->db, table_list->table_name, "VIEW"); - DBUG_RETURN(TRUE); + goto exit; } buffer.length(0); @@ -684,9 +703,8 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) view_store_create_info(thd, table_list, &buffer) : store_create_info(thd, table_list, &buffer, NULL, FALSE /* show_database */))) - DBUG_RETURN(TRUE); + goto exit; - List<Item> field_list; if (table_list->view) { field_list.push_back(new Item_empty_string("View",NAME_CHAR_LEN)); @@ -707,7 +725,8 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) if (protocol->send_result_set_metadata(&field_list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) - DBUG_RETURN(TRUE); + goto exit; + protocol->prepare_for_resend(); if (table_list->view) protocol->store(table_list->view_name.str, system_charset_info); @@ -735,10 +754,16 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) protocol->store(buffer.ptr(), buffer.length(), buffer.charset()); if (protocol->write()) - DBUG_RETURN(TRUE); + goto exit; + error= FALSE; my_eof(thd); - DBUG_RETURN(FALSE); + +exit: + close_thread_tables(thd); + /* Release any metadata locks taken during SHOW CREATE. */ + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + DBUG_RETURN(error); } bool mysqld_show_create_db(THD *thd, char *dbname, @@ -2922,7 +2947,7 @@ make_table_name_list(THD *thd, List<LEX_STRING> *table_names, LEX *lex, */ if (res == FIND_FILES_DIR) { - if (lex->sql_command != SQLCOM_SELECT) + if (sql_command_flags[lex->sql_command] & CF_STATUS_COMMAND) return 1; thd->clear_error(); return 2; @@ -4112,7 +4137,6 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, uchar *pos; char tmp[MAX_FIELD_WIDTH]; String type(tmp,sizeof(tmp), system_charset_info); - char *end; DEBUG_SYNC(thd, "get_schema_column"); @@ -4133,7 +4157,7 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, field->field_name) & COL_ACLS; if (!tables->schema_table && !col_access) continue; - end= tmp; + char *end= tmp; for (uint bitnr=0; col_access ; col_access>>=1,bitnr++) { if (col_access & 1) @@ -4169,7 +4193,6 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, table->field[15]->store((const char*) pos, strlen((const char*) pos), cs); - end= tmp; if (field->unireg_check == Field::NEXT_NUMBER) table->field[16]->store(STRING_WITH_LEN("auto_increment"), cs); if (timestamp_field == field && @@ -7719,6 +7742,10 @@ TABLE_LIST *get_trigger_table(THD *thd, const sp_name *trg_name) bool show_create_trigger(THD *thd, const sp_name *trg_name) { TABLE_LIST *lst= get_trigger_table(thd, trg_name); + uint num_tables; /* NOTE: unused, only to pass to open_tables(). */ + Table_triggers_list *triggers; + int trigger_idx; + bool error= TRUE; if (!lst) return TRUE; @@ -7730,35 +7757,35 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name) } /* - Open the table by name in order to load Table_triggers_list object. - - NOTE: there is race condition here -- the table can be dropped after - LOCK_open is released. It will be fixed later by acquiring shared - metadata lock on trigger or table name. + Metadata locks taken during SHOW CREATE TRIGGER should be released when + the statement completes as it is an information statement. */ + MDL_ticket *mdl_savepoint= thd->mdl_context.mdl_savepoint(); - uint num_tables; /* NOTE: unused, only to pass to open_tables(). */ - - if (open_tables(thd, &lst, &num_tables, 0)) + /* + Open the table by name in order to load Table_triggers_list object. + */ + if (open_tables(thd, &lst, &num_tables, + MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL)) { my_error(ER_TRG_CANT_OPEN_TABLE, MYF(0), (const char *) trg_name->m_db.str, (const char *) lst->table_name); - return TRUE; + goto exit; /* Perform closing actions and return error status. */ } - Table_triggers_list *triggers= lst->table->triggers; + triggers= lst->table->triggers; if (!triggers) { my_error(ER_TRG_DOES_NOT_EXIST, MYF(0)); - return TRUE; + goto exit; } - int trigger_idx= triggers->find_trigger_by_name(&trg_name->m_name); + trigger_idx= triggers->find_trigger_by_name(&trg_name->m_name); if (trigger_idx < 0) { @@ -7766,16 +7793,22 @@ bool show_create_trigger(THD *thd, const sp_name *trg_name) (const char *) trg_name->m_db.str, (const char *) lst->table_name); - return TRUE; + goto exit; } - return show_create_trigger_impl(thd, triggers, trigger_idx); + error= show_create_trigger_impl(thd, triggers, trigger_idx); /* NOTE: if show_create_trigger_impl() failed, that means we could not send data to the client. In this case we simply raise the error status and client connection will be closed. */ + +exit: + close_thread_tables(thd); + /* Release any metadata locks taken during SHOW CREATE TRIGGER. */ + thd->mdl_context.rollback_to_savepoint(mdl_savepoint); + return error; } class IS_internal_schema_access : public ACL_internal_schema_access diff --git a/sql/sql_table.cc b/sql/sql_table.cc index d28b4859ab5..02a874ce62f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -22,17 +22,17 @@ #include "sql_rename.h" // do_rename #include "sql_parse.h" // test_if_data_home_dir #include "sql_cache.h" // query_cache_* -#include "sql_base.h" // open_temporary_table -#include "lock.h" // wait_if_global_read_lock, lock_table_names, +#include "sql_base.h" // open_temporary_table, lock_table_names +#include "lock.h" // wait_if_global_read_lock // start_waiting_global_read_lock, - // unlock_table_names, mysql_unlock_tables + // mysql_unlock_tables #include "strfunc.h" // find_type2, find_set #include "sql_view.h" // view_checksum #include "sql_truncate.h" // regenerate_locked_table #include "sql_partition.h" // mem_alloc_error, // generate_partition_syntax, // partition_info -#include "sql_db.h" // load_db_opt_by_name, lock_db_cache, creating_database +#include "sql_db.h" // load_db_opt_by_name #include "sql_time.h" // make_truncated_value_warning #include "records.h" // init_read_record, end_read_record #include "filesort.h" // filesort_free_buffers @@ -58,8 +58,6 @@ #include <io.h> #endif -int creating_table= 0; // How many mysql_create_table are running - const char *primary_key_name="PRIMARY"; static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end); @@ -1954,7 +1952,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, { if (!thd->locked_tables_mode) { - if (lock_table_names(thd, tables)) + if (lock_table_names(thd, tables, NULL, thd->variables.lock_wait_timeout, + MYSQL_OPEN_SKIP_TEMPORARY)) DBUG_RETURN(1); mysql_mutex_lock(&LOCK_open); for (table= tables; table; table= table->next_local) @@ -1964,7 +1963,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, else { for (table= tables; table; table= table->next_local) - if (find_temporary_table(thd, table->db, table->table_name)) + if (table->open_type != OT_BASE_ONLY && + find_temporary_table(thd, table->db, table->table_name)) { /* A temporary table. @@ -2009,8 +2009,11 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, table->db, table->table_name, (long) table->table, table->table ? (long) table->table->s : (long) -1)); - error= drop_temporary_table(thd, table); - + if (table->open_type == OT_BASE_ONLY) + error= 1; + else + error= drop_temporary_table(thd, table); + switch (error) { case 0: // removed temporary table @@ -2282,18 +2285,13 @@ err: { /* Under LOCK TABLES we should release meta-data locks on the tables - which were dropped. Otherwise we can rely on close_thread_tables() - doing this. Unfortunately in this case we are likely to get more - false positives in try_acquire_lock() function. So - it makes sense to remove exclusive meta-data locks in all cases. + which were dropped. Leave LOCK TABLES mode if we managed to drop all tables which were locked. Additional check for 'non_temp_tables_count' is to avoid leaving LOCK TABLES mode if we have dropped only temporary tables. */ - if (! thd->locked_tables_mode) - unlock_table_names(thd); - else + if (thd->locked_tables_mode) { if (thd->lock && thd->lock->table_count == 0 && non_temp_tables_count > 0) { @@ -2302,7 +2300,8 @@ err: } for (table= tables; table; table= table->next_local) { - if (table->mdl_request.ticket) + /* Drop locks for all successfully dropped tables. */ + if (table->table == NULL && table->mdl_request.ticket) { /* Under LOCK TABLES we may have several instances of table open @@ -2313,6 +2312,10 @@ err: } } } + /* + Rely on the caller to implicitly commit the transaction + and release metadata locks. + */ } end: @@ -4211,8 +4214,14 @@ warn: } -/* - Database and name-locking aware wrapper for mysql_create_table_no_lock(), +/** + Implementation of SQLCOM_CREATE_TABLE. + + Take the metadata locks (including a shared lock on the affected + schema) and create the table. Is written to be called from + mysql_execute_command(), to which it delegates the common parts + with other commands (i.e. implicit commit before and after, + close of thread tables. */ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, @@ -4222,31 +4231,13 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, bool result; DBUG_ENTER("mysql_create_table"); - /* Wait for any database locks */ - mysql_mutex_lock(&LOCK_lock_db); - while (!thd->killed && - my_hash_search(&lock_db_cache, (uchar*)create_table->db, - create_table->db_length)) - { - wait_for_condition(thd, &LOCK_lock_db, &COND_refresh); - mysql_mutex_lock(&LOCK_lock_db); - } - - if (thd->killed) - { - mysql_mutex_unlock(&LOCK_lock_db); - DBUG_RETURN(TRUE); - } - creating_table++; - mysql_mutex_unlock(&LOCK_lock_db); - /* Open or obtain an exclusive metadata lock on table being created. */ if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0)) { result= TRUE; - goto unlock; + goto end; } /* Got lock. */ @@ -4268,20 +4259,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, !(create_info->options & HA_LEX_CREATE_TMP_TABLE)))) result= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); - if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) - { - /* - close_thread_tables() takes care about both closing open tables (which - might be still around in case of error) and releasing metadata locks. - */ - close_thread_tables(thd); - } - -unlock: - mysql_mutex_lock(&LOCK_lock_db); - if (!--creating_table && creating_database) - mysql_cond_signal(&COND_refresh); - mysql_mutex_unlock(&LOCK_lock_db); +end: DBUG_RETURN(result); } @@ -4454,8 +4432,6 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, { char key[MAX_DBKEY_LENGTH]; uint key_length; - MDL_request mdl_global_request; - MDL_request_list mdl_requests; /* If the table didn't exist, we have a shared metadata lock on it that is left from mysql_admin_table()'s attempt to @@ -4475,12 +4451,9 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, table_list->db, table_list->table_name, MDL_EXCLUSIVE); - mdl_global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE); - mdl_requests.push_front(&table_list->mdl_request); - mdl_requests.push_front(&mdl_global_request); - - if (thd->mdl_context.acquire_locks(&mdl_requests, - thd->variables.lock_wait_timeout)) + if (lock_table_names(thd, table_list, table_list->next_global, + thd->variables.lock_wait_timeout, + MYSQL_OPEN_SKIP_TEMPORARY)) DBUG_RETURN(0); has_mdl_lock= TRUE; @@ -4776,6 +4749,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, trans_rollback_stmt(thd); trans_rollback(thd); close_thread_tables(thd); + thd->mdl_context.release_transactional_locks(); DBUG_PRINT("admin", ("simple error, admin next table")); continue; case -1: // error, message could be written to net @@ -5062,11 +5036,11 @@ send_result_message: trans_commit_stmt(thd); trans_commit(thd); close_thread_tables(thd); - table->table= NULL; thd->mdl_context.release_transactional_locks(); + table->table= NULL; if (!result_code) // recreation went ok { - /* Clear the ticket released in close_thread_tables(). */ + /* Clear the ticket released above. */ table->mdl_request.ticket= NULL; DEBUG_SYNC(thd, "ha_admin_open_ltable"); table->mdl_request.set_type(MDL_SHARED_WRITE); @@ -5170,7 +5144,8 @@ send_result_message: May be something modified. Consequently, we have to invalidate the query cache. */ - query_cache_invalidate3(thd, table->table, 0); + table->table= 0; // For query cache + query_cache_invalidate3(thd, table, 0); } } /* Error path, a admin command failed. */ @@ -5178,7 +5153,6 @@ send_result_message: trans_commit_implicit(thd); close_thread_tables(thd); thd->mdl_context.release_transactional_locks(); - table->table=0; // For query cache /* If it is CHECK TABLE v1, v2, v3, and v1, v2, v3 are views, we will run @@ -6499,7 +6473,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, uint index_add_count= 0; uint *index_add_buffer= NULL; uint candidate_key_count= 0; - bool committed= 0; bool no_pk; DBUG_ENTER("mysql_alter_table"); @@ -6576,6 +6549,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, Alter_table_prelocking_strategy alter_prelocking_strategy(alter_info); + DEBUG_SYNC(thd, "alter_table_before_open_tables"); error= open_and_lock_tables(thd, table_list, FALSE, 0, &alter_prelocking_strategy); @@ -6752,13 +6726,11 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, goto err; DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000);); error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); - /* COND_refresh will be signaled in close_thread_tables() */ break; case DISABLE: if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) goto err; error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); - /* COND_refresh will be signaled in close_thread_tables() */ break; default: DBUG_ASSERT(FALSE); @@ -6844,8 +6816,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, { /* Under LOCK TABLES we should adjust meta-data locks before finishing - statement. Otherwise we can rely on close_thread_tables() releasing - them. + statement. Otherwise we can rely on them being released + along with the implicit commit. */ if (new_name != table_name || new_db != db) { @@ -7329,7 +7301,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, DBUG_PRINT("info", ("Committing before unlocking table")); if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) goto err_new_table_cleanup; - committed= 1; } /*end of if (! new_table) for add/drop index*/ @@ -7393,8 +7364,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, 5) Write statement to the binary log. 6) If we are under LOCK TABLES and do ALTER TABLE ... RENAME we remove placeholders and release metadata locks. - 7) If we are not not under LOCK TABLES we rely on close_thread_tables() - call to remove placeholders and releasing metadata locks. + 7) If we are not not under LOCK TABLES we rely on the caller + (mysql_execute_command()) to release metadata locks. */ thd_proc_info(thd, "rename result table"); @@ -8023,7 +7994,13 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, } } thd->clear_error(); + if (! thd->in_sub_stmt) + trans_rollback_stmt(thd); close_thread_tables(thd); + /* + Don't release metadata locks, this will be done at + statement end. + */ table->table=0; // For query cache } if (protocol->write()) @@ -8033,10 +8010,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, my_eof(thd); DBUG_RETURN(FALSE); - err: - close_thread_tables(thd); // Shouldn't be needed - if (table) - table->table=0; +err: DBUG_RETURN(TRUE); } diff --git a/sql/sql_table.h b/sql/sql_table.h index 40b24605bd6..dca4b706605 100644 --- a/sql/sql_table.h +++ b/sql/sql_table.h @@ -210,7 +210,6 @@ uint explain_filename(THD* thd, const char *from, char *to, uint to_length, extern MYSQL_PLUGIN_IMPORT const char *primary_key_name; -extern int creating_table; // How many mysql_create_table() are running extern mysql_mutex_t LOCK_gdl; #endif /* SQL_TABLE_INCLUDED */ diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 2f084c369b6..a5664b00287 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -540,9 +540,9 @@ end: } /* - If we are under LOCK TABLES we should restore original state of meta-data - locks. Otherwise call to close_thread_tables() will take care about both - TABLE instance created by open_n_lock_single_table() and metadata lock. + If we are under LOCK TABLES we should restore original state of + meta-data locks. Otherwise all locks will be released along + with the implicit commit. */ if (thd->locked_tables_mode && tables && lock_upgrade_done) mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE); @@ -1321,6 +1321,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, thd->reset_db((char*) db, strlen(db)); while ((trg_create_str= it++)) { + sp_head *sp; trg_sql_mode= itm++; LEX_STRING *trg_definer= it_definer++; @@ -1357,13 +1358,14 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, */ lex.set_trg_event_type_for_tables(); - lex.sphead->set_info(0, 0, &lex.sp_chistics, (ulong) *trg_sql_mode); - int event= lex.trg_chistics.event; int action_time= lex.trg_chistics.action_time; - lex.sphead->set_creation_ctx(creation_ctx); - triggers->bodies[event][action_time]= lex.sphead; + sp= triggers->bodies[event][action_time]= lex.sphead; + lex.sphead= NULL; /* Prevent double cleanup. */ + + sp->set_info(0, 0, &lex.sp_chistics, (ulong) *trg_sql_mode); + sp->set_creation_ctx(creation_ctx); if (!trg_definer->length) { @@ -1376,27 +1378,26 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER), (const char*) db, - (const char*) lex.sphead->m_name.str); + (const char*) sp->m_name.str); /* Set definer to the '' to correct displaying in the information schema. */ - lex.sphead->set_definer((char*) "", 0); + sp->set_definer((char*) "", 0); /* Triggers without definer information are executed under the authorization of the invoker. */ - lex.sphead->m_chistics->suid= SP_IS_NOT_SUID; + sp->m_chistics->suid= SP_IS_NOT_SUID; } else - lex.sphead->set_definer(trg_definer->str, trg_definer->length); + sp->set_definer(trg_definer->str, trg_definer->length); - if (triggers->names_list.push_back(&lex.sphead->m_name, - &table->mem_root)) + if (triggers->names_list.push_back(&sp->m_name, &table->mem_root)) goto err_with_lex_cleanup; if (!(on_table_name= alloc_lex_string(&table->mem_root))) diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc index c2482ef1ce0..ee5c707cd69 100644 --- a/sql/sql_truncate.cc +++ b/sql/sql_truncate.cc @@ -242,9 +242,10 @@ static bool open_and_lock_table_for_truncate(THD *thd, TABLE_LIST *table_ref, MDL_ticket **ticket_downgrade) { TABLE *table= NULL; - MDL_ticket *mdl_ticket= NULL; DBUG_ENTER("open_and_lock_table_for_truncate"); + DBUG_ASSERT(table_ref->lock_type == TL_WRITE); + DBUG_ASSERT(table_ref->mdl_request.type == MDL_SHARED_NO_READ_WRITE); /* Before doing anything else, acquire a metadata lock on the table, or ensure we have one. We don't use open_and_lock_tables() @@ -266,6 +267,7 @@ static bool open_and_lock_table_for_truncate(THD *thd, TABLE_LIST *table_ref, *hton_can_recreate= ha_check_storage_engine_flag(table->s->db_type(), HTON_CAN_RECREATE); + table_ref->mdl_request.ticket= table->mdl_ticket; } else { @@ -273,21 +275,12 @@ static bool open_and_lock_table_for_truncate(THD *thd, TABLE_LIST *table_ref, Even though we could use the previous execution branch here just as well, we must not try to open the table: */ - MDL_request mdl_global_request, mdl_request; - MDL_request_list mdl_requests; - - mdl_global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE); - mdl_request.init(MDL_key::TABLE, table_ref->db, table_ref->table_name, - MDL_SHARED_NO_READ_WRITE); - mdl_requests.push_front(&mdl_request); - mdl_requests.push_front(&mdl_global_request); - - if (thd->mdl_context.acquire_locks(&mdl_requests, - thd->variables.lock_wait_timeout)) + DBUG_ASSERT(table_ref->next_global == NULL); + if (lock_table_names(thd, table_ref, NULL, + thd->variables.lock_wait_timeout, + MYSQL_OPEN_SKIP_TEMPORARY)) DBUG_RETURN(TRUE); - mdl_ticket= mdl_request.ticket; - if (dd_check_storage_engine_flag(thd, table_ref->db, table_ref->table_name, HTON_CAN_RECREATE, hton_can_recreate)) DBUG_RETURN(TRUE); @@ -313,7 +306,9 @@ static bool open_and_lock_table_for_truncate(THD *thd, TABLE_LIST *table_ref, else { ulong timeout= thd->variables.lock_wait_timeout; - if (thd->mdl_context.upgrade_shared_lock_to_exclusive(mdl_ticket, timeout)) + if (thd->mdl_context. + upgrade_shared_lock_to_exclusive(table_ref->mdl_request.ticket, + timeout)) DBUG_RETURN(TRUE); mysql_mutex_lock(&LOCK_open); tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table_ref->db, @@ -335,15 +330,14 @@ static bool open_and_lock_table_for_truncate(THD *thd, TABLE_LIST *table_ref, table_ref->required_type= FRMTYPE_TABLE; /* We don't need to load triggers. */ DBUG_ASSERT(table_ref->trg_event_map == 0); - /* Work around partition parser rules using alter table's. */ - if (thd->lex->alter_info.flags & ALTER_ADMIN_PARTITION) - { - table_ref->lock_type= TL_WRITE; - table_ref->mdl_request.set_type(MDL_SHARED_WRITE); - } - /* Ensure proper lock types (e.g. from the parser). */ - DBUG_ASSERT(table_ref->lock_type == TL_WRITE); - DBUG_ASSERT(table_ref->mdl_request.type == MDL_SHARED_WRITE); + /* + Even though we have an MDL lock on the table here, we don't + pass MYSQL_OPEN_HAS_MDL_LOCK to open_and_lock_tables + since to truncate a MERGE table, we must open and lock + merge children, and on those we don't have an MDL lock. + Thus clear the ticket to satisfy MDL asserts. + */ + table_ref->mdl_request.ticket= NULL; /* Open the table as it will handle some required preparations. diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 3d197303fb1..ba1d0ceadeb 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -33,7 +33,7 @@ #include "sql_priv.h" #include "unireg.h" -#include "sql_base.h" // close_thread_tables +#include "sql_base.h" // close_mysql_tables #include "sql_parse.h" // check_identifier_name #include "sql_table.h" // write_bin_log #include "records.h" // init_read_record, end_read_record @@ -251,7 +251,7 @@ void udf_init() table->m_needs_reopen= TRUE; // Force close to free memory end: - close_thread_tables(new_thd); + close_mysql_tables(new_thd); delete new_thd; /* Remember that we don't have a THD */ my_pthread_setspecific_ptr(THR_THD, 0); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 9ca4556524f..acc0f704c44 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -36,8 +36,7 @@ bool mysql_union(THD *thd, LEX *lex, select_result *result, if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | setup_tables_done_option))) res= unit->exec(); - if (res || !thd->cursor || !thd->cursor->is_open()) - res|= unit->cleanup(); + res|= unit->cleanup(); DBUG_RETURN(res); } diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 69abe70e863..be13349b5a1 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -19,10 +19,10 @@ #include "sql_priv.h" #include "unireg.h" #include "sql_view.h" -#include "sql_base.h" // find_table_in_global_list +#include "sql_base.h" // find_table_in_global_list, lock_table_names #include "sql_parse.h" // sql_parse #include "sql_cache.h" // query_cache_* -#include "lock.h" // wait_if_global_read_lock, lock_table_names +#include "lock.h" // wait_if_global_read_lock #include "sql_show.h" // append_identifier #include "sql_table.h" // build_table_filename #include "sql_db.h" // mysql_opt_change_db, mysql_change_db @@ -1652,7 +1652,8 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) DBUG_RETURN(TRUE); } - if (lock_table_names(thd, views)) + if (lock_table_names(thd, views, 0, thd->variables.lock_wait_timeout, + MYSQL_OPEN_SKIP_TEMPORARY)) DBUG_RETURN(TRUE); mysql_mutex_lock(&LOCK_open); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3ba67368565..ca951897055 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6440,6 +6440,8 @@ alter_commands: lex->sql_command= SQLCOM_TRUNCATE; lex->alter_info.flags|= ALTER_ADMIN_PARTITION; lex->check_opt.init(); + lex->query_tables->mdl_request.set_type(MDL_SHARED_NO_READ_WRITE); + lex->query_tables->lock_type= TL_WRITE; } | reorg_partition_rule ; @@ -10693,7 +10695,7 @@ truncate: lex->select_lex.sql_cache= SELECT_LEX::SQL_CACHE_UNSPECIFIED; lex->select_lex.init_order(); YYPS->m_lock_type= TL_WRITE; - YYPS->m_mdl_type= MDL_SHARED_WRITE; + YYPS->m_mdl_type= MDL_SHARED_NO_READ_WRITE; } table_name {} @@ -11184,10 +11186,10 @@ flush_options: Lex->type|= REFRESH_TABLES; /* Set type of metadata and table locks for - FLUSH TABLES table_list WITH READ LOCK. + FLUSH TABLES table_list [WITH READ LOCK]. */ YYPS->m_lock_type= TL_READ_NO_INSERT; - YYPS->m_mdl_type= MDL_EXCLUSIVE; + YYPS->m_mdl_type= MDL_SHARED_HIGH_PRIO; } opt_table_list {} opt_with_read_lock {} @@ -11197,7 +11199,13 @@ flush_options: opt_with_read_lock: /* empty */ {} | WITH READ_SYM LOCK_SYM - { Lex->type|= REFRESH_READ_LOCK; } + { + TABLE_LIST *tables= Lex->query_tables; + Lex->type|= REFRESH_READ_LOCK; + /* We acquire an X lock currently and then downgrade. */ + for (; tables; tables= tables->next_global) + tables->mdl_request.set_type(MDL_EXCLUSIVE); + } ; flush_options_list: diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 6e838759e83..320e6d9253e 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2207,14 +2207,21 @@ static bool fix_autocommit(sys_var *self, THD *thd, enum_var_type type) thd->variables.option_bits & OPTION_NOT_AUTOCOMMIT) { // activating autocommit - if (trans_commit(thd)) + if (trans_commit_stmt(thd) || trans_commit(thd)) { thd->variables.option_bits&= ~OPTION_AUTOCOMMIT; return true; } - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); - + /* + Don't close thread tables or release metadata locks: if we do so, we + risk releasing locks/closing tables of expressions used to assign + other variables, as in: + set @var=my_stored_function1(), @@autocommit=1, @var2=(select max(a) + from my_table), ... + The locks will be released at statement end anyway, as SET + statement that assigns autocommit is marked to commit + transaction implicitly at the end (@sa stmt_causes_implicitcommit()). + */ thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG | OPTION_NOT_AUTOCOMMIT); thd->transaction.all.modified_non_trans_table= false; diff --git a/sql/table.cc b/sql/table.cc index c89ce90e719..bcdfd23b4c1 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -541,7 +541,7 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags) int error, table_type; bool error_given; File file; - uchar head[64], *disk_buff; + uchar head[64]; char path[FN_REFLEN]; MEM_ROOT **root_ptr, *old_root; DBUG_ENTER("open_table_def"); @@ -550,7 +550,6 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags) error= 1; error_given= 0; - disk_buff= NULL; strxmov(path, share->normalized_path.str, reg_ext, NullS); if ((file= mysql_file_open(key_file_frm, diff --git a/sql/table.h b/sql/table.h index 2bf390aee4d..7579a8a6df3 100644 --- a/sql/table.h +++ b/sql/table.h @@ -629,7 +629,7 @@ struct TABLE_SHARE #ifdef WITH_PARTITION_STORAGE_ENGINE /* filled in when reading from frm */ bool auto_partitioned; - const char *partition_info_str; + char *partition_info_str; uint partition_info_str_len; uint partition_info_buffer_size; handlerton *default_part_db_type; diff --git a/sql/transaction.cc b/sql/transaction.cc index f6786f20dcf..a28fba8805d 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -28,6 +28,12 @@ static bool trans_check(THD *thd) enum xa_states xa_state= thd->transaction.xid_state.xa_state; DBUG_ENTER("trans_check"); + /* + Always commit statement transaction before manipulating with + the normal one. + */ + DBUG_ASSERT(thd->transaction.stmt.is_empty()); + if (unlikely(thd->in_sub_stmt)) my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); if (xa_state != XA_NOTR) @@ -252,6 +258,14 @@ bool trans_commit_stmt(THD *thd) { DBUG_ENTER("trans_commit_stmt"); int res= FALSE; + /* + We currently don't invoke commit/rollback at end of + a sub-statement. In future, we perhaps should take + a savepoint for each nested statement, and release the + savepoint when statement has succeeded. + */ + DBUG_ASSERT(! thd->in_sub_stmt); + if (thd->transaction.stmt.ha_list) { res= ha_commit_trans(thd, FALSE); @@ -267,6 +281,9 @@ bool trans_commit_stmt(THD *thd) RUN_HOOK(transaction, after_rollback, (thd, FALSE)); else RUN_HOOK(transaction, after_commit, (thd, FALSE)); + + thd->transaction.stmt.reset(); + DBUG_RETURN(test(res)); } @@ -283,6 +300,14 @@ bool trans_rollback_stmt(THD *thd) { DBUG_ENTER("trans_rollback_stmt"); + /* + We currently don't invoke commit/rollback at end of + a sub-statement. In future, we perhaps should take + a savepoint for each nested statement, and release the + savepoint when statement has succeeded. + */ + DBUG_ASSERT(! thd->in_sub_stmt); + if (thd->transaction.stmt.ha_list) { ha_rollback_trans(thd, FALSE); @@ -294,6 +319,8 @@ bool trans_rollback_stmt(THD *thd) RUN_HOOK(transaction, after_rollback, (thd, FALSE)); + thd->transaction.stmt.reset(); + DBUG_RETURN(FALSE); } diff --git a/sql/tztime.cc b/sql/tztime.cc index af8574c38f1..43d43123158 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -50,13 +50,6 @@ // MYSQL_LOCK_IGNORE_TIMEOUT /* - This forward declaration is needed because including sql_base.h - causes further includes. [TODO] Eliminate this forward declaration - and include a file with the prototype instead. -*/ -extern void close_thread_tables(THD *thd); - -/* Now we don't use abbreviations in server but we will do this in future. */ #if defined(TZINFO2SQL) || defined(TESTTIME) @@ -1784,10 +1777,7 @@ end_with_setting_default_tz: end_with_close: if (time_zone_tables_exist) - { - close_thread_tables(thd); - thd->mdl_context.release_transactional_locks(); - } + close_mysql_tables(thd); end_with_cleanup: diff --git a/sql/udf_example.c b/sql/udf_example.c index 5f8e71d25fa..36828bdf94d 100644 --- a/sql/udf_example.c +++ b/sql/udf_example.c @@ -1071,7 +1071,7 @@ char *myfunc_argument_name(UDF_INIT *initid __attribute__((unused)), { if (!args->attributes[0]) { - null_value= 0; + *null_value= 1; return 0; } (*length)--; /* space for ending \0 (for debugging purposes) */ diff --git a/storage/archive/azio.c b/storage/archive/azio.c index c1dd6e6f38c..1e2753027dc 100644 --- a/storage/archive/azio.c +++ b/storage/archive/azio.c @@ -31,7 +31,7 @@ int az_open(azio_stream *s, const char *path, int Flags, File fd); int do_flush(azio_stream *file, int flush); int get_byte(azio_stream *s); void check_header(azio_stream *s); -void write_header(azio_stream *s); +int write_header(azio_stream *s); int destroy(azio_stream *s); void putLong(File file, uLong x); uLong getLong(azio_stream *s); @@ -155,7 +155,7 @@ int az_open (azio_stream *s, const char *path, int Flags, File fd) } -void write_header(azio_stream *s) +int write_header(azio_stream *s) { char buffer[AZHEADER_SIZE + AZMETA_BUFFER_SIZE]; char *ptr= buffer; @@ -191,8 +191,8 @@ void write_header(azio_stream *s) *(ptr + AZ_DIRTY_POS)= (unsigned char)s->dirty; /* Start of Data Block Index Block */ /* Always begin at the begining, and end there as well */ - my_pwrite(s->file, (uchar*) buffer, AZHEADER_SIZE + AZMETA_BUFFER_SIZE, 0, - MYF(0)); + return my_pwrite(s->file, (uchar*) buffer, AZHEADER_SIZE + AZMETA_BUFFER_SIZE, + 0, MYF(MY_NABP)) ? 1 : 0; } /* =========================================================================== @@ -838,19 +838,19 @@ int azwrite_frm(azio_stream *s, char *blob, unsigned int length) s->frm_length= length; s->start+= length; - my_pwrite(s->file, (uchar*) blob, s->frm_length, s->frm_start_pos, MYF(0)); - - write_header(s); - my_seek(s->file, 0, MY_SEEK_END, MYF(0)); + if (my_pwrite(s->file, (uchar*) blob, s->frm_length, + s->frm_start_pos, MYF(MY_NABP)) || + write_header(s) || + (my_seek(s->file, 0, MY_SEEK_END, MYF(0)) == MY_FILEPOS_ERROR)) + return 1; return 0; } int azread_frm(azio_stream *s, char *blob) { - my_pread(s->file, (uchar*) blob, s->frm_length, s->frm_start_pos, MYF(0)); - - return 0; + return my_pread(s->file, (uchar*) blob, s->frm_length, + s->frm_start_pos, MYF(MY_NABP)) ? 1 : 0; } diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc index 63848370ff1..ef907b035b5 100644 --- a/storage/archive/ha_archive.cc +++ b/storage/archive/ha_archive.cc @@ -613,6 +613,34 @@ int ha_archive::close(void) } +/** + Copy a frm blob between streams. + + @param src The source stream. + @param dst The destination stream. + + @return Zero on success, non-zero otherwise. +*/ + +int ha_archive::frm_copy(azio_stream *src, azio_stream *dst) +{ + int rc= 0; + char *frm_ptr; + + if (!(frm_ptr= (char *) my_malloc(src->frm_length, MYF(0)))) + return HA_ERR_OUT_OF_MEM; + + /* Write file offset is set to the end of the file. */ + if (azread_frm(src, frm_ptr) || + azwrite_frm(dst, frm_ptr, src->frm_length)) + rc= my_errno ? my_errno : HA_ERR_INTERNAL_ERROR; + + my_free(frm_ptr); + + return rc; +} + + /* We create our data file here. The format is pretty simple. You can read about the format of the data file above. @@ -1345,10 +1373,10 @@ int ha_archive::repair(THD* thd, HA_CHECK_OPT* check_opt) */ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt) { - DBUG_ENTER("ha_archive::optimize"); int rc= 0; azio_stream writer; char writer_filename[FN_REFLEN]; + DBUG_ENTER("ha_archive::optimize"); init_archive_reader(); @@ -1366,6 +1394,13 @@ int ha_archive::optimize(THD* thd, HA_CHECK_OPT* check_opt) if (!(azopen(&writer, writer_filename, O_CREAT|O_RDWR|O_BINARY))) DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE); + /* + Transfer the embedded FRM so that the file can be discoverable. + Write file offset is set to the end of the file. + */ + if ((rc= frm_copy(&archive, &writer))) + goto error; + /* An extended rebuild is a lot more effort. We open up each row and re-record it. Any dead rows are removed (aka rows that may have been partially recorded). diff --git a/storage/archive/ha_archive.h b/storage/archive/ha_archive.h index 94842203f16..b258b403c3c 100644 --- a/storage/archive/ha_archive.h +++ b/storage/archive/ha_archive.h @@ -75,6 +75,7 @@ class ha_archive: public handler archive_record_buffer *create_record_buffer(unsigned int length); void destroy_record_buffer(archive_record_buffer *r); + int frm_copy(azio_stream *src, azio_stream *dst); public: ha_archive(handlerton *hton, TABLE_SHARE *table_arg); diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc index 216097f0fdc..e8012a86ae6 100644 --- a/storage/csv/ha_tina.cc +++ b/storage/csv/ha_tina.cc @@ -519,7 +519,7 @@ int ha_tina::encode_quote(uchar *buf) const char *ptr; const char *end_ptr; const bool was_null= (*field)->is_null(); - + /* assistance for backwards compatibility in production builds. note: this will not work for ENUM columns. @@ -531,7 +531,7 @@ int ha_tina::encode_quote(uchar *buf) } (*field)->val_str(&attribute,&attribute); - + if (was_null) (*field)->set_null(); @@ -542,34 +542,30 @@ int ha_tina::encode_quote(uchar *buf) buffer.append('"'); - while (ptr < end_ptr) + for (; ptr < end_ptr; ptr++) { if (*ptr == '"') { buffer.append('\\'); buffer.append('"'); - *ptr++; } else if (*ptr == '\r') { buffer.append('\\'); buffer.append('r'); - *ptr++; } else if (*ptr == '\\') { buffer.append('\\'); buffer.append('\\'); - *ptr++; } else if (*ptr == '\n') { buffer.append('\\'); buffer.append('n'); - *ptr++; } else - buffer.append(*ptr++); + buffer.append(*ptr); } buffer.append('"'); } diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc index 899f55a33f7..306f8eaeccd 100644 --- a/storage/example/ha_example.cc +++ b/storage/example/ha_example.cc @@ -180,7 +180,7 @@ static int example_done_func(void *p) my_hash_free(&example_open_tables); mysql_mutex_destroy(&example_mutex); - DBUG_RETURN(0); + DBUG_RETURN(error); } diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt index b6399dcc478..218dbad2df0 100644 --- a/storage/innobase/CMakeLists.txt +++ b/storage/innobase/CMakeLists.txt @@ -40,6 +40,12 @@ IF(UNIX) ENDIF() ENDIF() +# Enable InnoDB's UNIV_DEBUG if MySQL's WITH_DEBUG[_FULL] is defined +# enable when this bug is resolved: +# Bug#54861 Additional connections not handled properly in mtr --embedded +#IF(WITH_DEBUG OR WITH_DEBUG_FULL) +# ADD_DEFINITIONS("-DUNIV_DEBUG") +#ENDIF() IF(NOT MSVC) # either define HAVE_IB_GCC_ATOMIC_BUILTINS or not @@ -182,11 +188,7 @@ IF(SIZEOF_PTHREAD_T) ENDIF() IF(MSVC) - # 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) + ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS -DHAVE_IB_PAUSE_INSTRUCTION) ENDIF() diff --git a/storage/innobase/btr/btr0btr.c b/storage/innobase/btr/btr0btr.c index 05dd094b6df..f8638af2e71 100644 --- a/storage/innobase/btr/btr0btr.c +++ b/storage/innobase/btr/btr0btr.c @@ -737,7 +737,7 @@ btr_create( ulint space, /*!< in: space where created */ ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ - dulint index_id,/*!< in: index id */ + index_id_t index_id,/*!< in: index id */ dict_index_t* index, /*!< in: index */ mtr_t* mtr) /*!< in: mini-transaction handle */ { @@ -1020,7 +1020,7 @@ btr_page_reorganize_low( /* In crash recovery, dict_index_is_sec_or_ibuf() always returns TRUE, even for clustered indexes. max_trx_id is unused in clustered index pages. */ - ut_ad(!ut_dulint_is_zero(max_trx_id) || recovery); + ut_ad(max_trx_id != 0 || recovery); } if (UNIV_LIKELY_NULL(page_zip) @@ -2883,7 +2883,7 @@ btr_discard_only_page_on_level( ibuf_reset_free_bits(block); if (page_is_leaf(buf_block_get_frame(block))) { - ut_a(!ut_dulint_is_zero(max_trx_id)); + ut_a(max_trx_id); page_set_max_trx_id(block, buf_block_get_page_zip(block), max_trx_id, mtr); diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c index 31e1a2d4b12..537d5f51184 100644 --- a/storage/innobase/btr/btr0cur.c +++ b/storage/innobase/btr/btr0cur.c @@ -660,7 +660,7 @@ retry_page_get: 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(index->id == btr_page_get_index_id(page)); if (UNIV_UNLIKELY(height == ULINT_UNDEFINED)) { /* We are in the root node */ @@ -854,8 +854,7 @@ btr_cur_open_at_index_side_func( RW_NO_LATCH, NULL, BUF_GET, file, line, mtr); page = buf_block_get_frame(block); - ut_ad(0 == ut_dulint_cmp(index->id, - btr_page_get_index_id(page))); + ut_ad(index->id == btr_page_get_index_id(page)); block->check_index_page_at_flush = TRUE; @@ -975,8 +974,7 @@ btr_cur_open_at_rnd_pos_func( RW_NO_LATCH, NULL, BUF_GET, file, line, mtr); page = buf_block_get_frame(block); - ut_ad(0 == ut_dulint_cmp(index->id, - btr_page_get_index_id(page))); + ut_ad(index->id == btr_page_get_index_id(page)); if (height == ULINT_UNDEFINED) { /* We are in the root node */ @@ -1135,7 +1133,7 @@ btr_cur_trx_report( const char* op) /*!< in: operation */ { fprintf(stderr, "Trx with id " TRX_ID_FMT " going to ", - TRX_ID_PREP_PRINTF(trx->id)); + (ullint) trx->id); fputs(op, stderr); dict_index_name_print(stderr, trx, index); putc('\n', stderr); @@ -1826,7 +1824,7 @@ btr_cur_update_in_place( page_zip_des_t* page_zip; ulint err; rec_t* rec; - roll_ptr_t roll_ptr = ut_dulint_zero; + roll_ptr_t roll_ptr = 0; trx_t* trx; ulint was_delete_marked; mem_heap_t* heap = NULL; @@ -4936,7 +4934,7 @@ btr_copy_externally_stored_field( /*******************************************************************//** Copies an externally stored field of a record to mem heap. -@return the field copied to heap */ +@return the field copied to heap, or NULL if the field is incomplete */ UNIV_INTERN byte* btr_rec_copy_externally_stored_field( @@ -4966,6 +4964,18 @@ btr_rec_copy_externally_stored_field( data = rec_get_nth_field(rec, offsets, no, &local_len); + ut_a(local_len >= BTR_EXTERN_FIELD_REF_SIZE); + + if (UNIV_UNLIKELY + (!memcmp(data + local_len - BTR_EXTERN_FIELD_REF_SIZE, + field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE))) { + /* The externally stored field was not written yet. + This record should only be seen by + recv_recovery_rollback_active() or any + TRX_ISO_READ_UNCOMMITTED transactions. */ + return(NULL); + } + return(btr_copy_externally_stored_field(len, data, zip_size, local_len, heap)); } diff --git a/storage/innobase/btr/btr0sea.c b/storage/innobase/btr/btr0sea.c index 98a321bdb80..06cc48c7c60 100644 --- a/storage/innobase/btr/btr0sea.c +++ b/storage/innobase/btr/btr0sea.c @@ -46,6 +46,7 @@ Created 2/17/1996 Heikki Tuuri /** Flag: has the search system been enabled? Protected by btr_search_latch and btr_search_enabled_mutex. */ UNIV_INTERN char btr_search_enabled = TRUE; +UNIV_INTERN ibool btr_search_fully_disabled = FALSE; /** Mutex protecting btr_search_enabled */ static mutex_t btr_search_enabled_mutex; @@ -213,12 +214,19 @@ btr_search_disable(void) mutex_enter(&btr_search_enabled_mutex); rw_lock_x_lock(&btr_search_latch); + /* Disable access to hash index, also tell ha_insert_for_fold() + stop adding new nodes to hash index, but still allow updating + existing nodes */ btr_search_enabled = FALSE; /* Clear all block->is_hashed flags and remove all entries from btr_search_sys->hash_index. */ buf_pool_drop_hash_index(); + /* hash index has been cleaned up, disallow any operation to + the hash index */ + btr_search_fully_disabled = TRUE; + /* btr_search_enabled_mutex should guarantee this. */ ut_ad(!btr_search_enabled); @@ -237,6 +245,7 @@ btr_search_enable(void) rw_lock_x_lock(&btr_search_latch); btr_search_enabled = TRUE; + btr_search_fully_disabled = FALSE; rw_lock_x_unlock(&btr_search_latch); mutex_exit(&btr_search_enabled_mutex); @@ -523,9 +532,9 @@ btr_search_update_hash_ref( buf_block_t* block, /*!< in: buffer block where cursor positioned */ btr_cur_t* cursor) /*!< in: cursor */ { - ulint fold; - rec_t* rec; - dulint index_id; + ulint fold; + rec_t* rec; + index_id_t index_id; ut_ad(cursor->flag == BTR_CUR_HASH_FAIL); #ifdef UNIV_SYNC_DEBUG @@ -830,7 +839,7 @@ btr_search_guess_on_hash( buf_block_t* block; rec_t* rec; ulint fold; - dulint index_id; + index_id_t index_id; #ifdef notdefined btr_cur_t cursor2; btr_pcur_t pcur; @@ -922,8 +931,7 @@ btr_search_guess_on_hash( is positioned on. We cannot look at the next of the previous record to determine if our guess for the cursor position is right. */ - if (UNIV_EXPECT - (ut_dulint_cmp(index_id, btr_page_get_index_id(block->frame)), 0) + if (UNIV_UNLIKELY(index_id != btr_page_get_index_id(block->frame)) || !btr_search_check_guess(cursor, has_search_latch, tuple, mode, mtr)) { @@ -1028,7 +1036,7 @@ btr_search_drop_page_hash_index( const rec_t* rec; ulint fold; ulint prev_fold; - dulint index_id; + index_id_t index_id; ulint n_cached; ulint n_recs; ulint* folds; @@ -1088,7 +1096,7 @@ retry: index_id = btr_page_get_index_id(page); - ut_a(0 == ut_dulint_cmp(index_id, index->id)); + ut_a(index_id == index->id); prev_fold = 0; @@ -1245,7 +1253,7 @@ btr_search_build_page_hash_index( rec_t* next_rec; ulint fold; ulint next_fold; - dulint index_id; + index_id_t index_id; ulint n_cached; ulint n_recs; ulint* folds; @@ -1376,7 +1384,7 @@ btr_search_build_page_hash_index( rw_lock_x_lock(&btr_search_latch); - if (UNIV_UNLIKELY(!btr_search_enabled)) { + if (UNIV_UNLIKELY(btr_search_fully_disabled)) { goto exit_func; } @@ -1498,7 +1506,7 @@ btr_search_update_hash_on_delete( buf_block_t* block; rec_t* rec; ulint fold; - dulint index_id; + index_id_t index_id; ibool found; ulint offsets_[REC_OFFS_NORMAL_SIZE]; mem_heap_t* heap = NULL; @@ -1604,7 +1612,7 @@ btr_search_update_hash_on_insert( rec_t* rec; rec_t* ins_rec; rec_t* next_rec; - dulint index_id; + index_id_t index_id; ulint fold; ulint ins_fold; ulint next_fold = 0; /* remove warning (??? bug ???) */ @@ -1784,6 +1792,7 @@ btr_search_validate(void) = buf_block_align(node->data); const buf_block_t* hash_block; buf_pool_t* buf_pool; + index_id_t page_index_id; buf_pool = buf_pool_from_bpage((buf_page_t*) block); @@ -1828,12 +1837,15 @@ btr_search_validate(void) + (block->curr_n_bytes > 0), &heap); - if (!block->is_hashed || node->fold - != rec_fold((rec_t*)(node->data), - offsets, - block->curr_n_fields, - block->curr_n_bytes, - btr_page_get_index_id(block->frame))) { + page_index_id = btr_page_get_index_id(block->frame); + + if (UNIV_UNLIKELY + (!block->is_hashed || node->fold + != rec_fold((rec_t*)(node->data), + offsets, + block->curr_n_fields, + block->curr_n_bytes, + page_index_id))) { const page_t* page = block->frame; ok = FALSE; @@ -1843,21 +1855,17 @@ btr_search_validate(void) " InnoDB: Error in an adaptive hash" " index pointer to page %lu\n" "InnoDB: ptr mem address %p" - " index id %lu %lu," + " index id %llu," " node fold %lu, rec fold %lu\n", (ulong) page_get_page_no(page), node->data, - (ulong) ut_dulint_get_high( - btr_page_get_index_id(page)), - (ulong) ut_dulint_get_low( - btr_page_get_index_id(page)), + (ullint) page_index_id, (ulong) node->fold, (ulong) rec_fold((rec_t*)(node->data), offsets, block->curr_n_fields, block->curr_n_bytes, - btr_page_get_index_id( - page))); + page_index_id)); fputs("InnoDB: Record ", stderr); rec_print_new(stderr, (rec_t*)node->data, diff --git a/storage/innobase/buf/buf0buf.c b/storage/innobase/buf/buf0buf.c index 4b6b0a82486..ab3c1abf490 100644 --- a/storage/innobase/buf/buf0buf.c +++ b/storage/innobase/buf/buf0buf.c @@ -522,7 +522,9 @@ buf_page_is_corrupted( ib_uint64_t current_lsn; if (log_peek_lsn(¤t_lsn) - && current_lsn < mach_read_ull(read_buf + FIL_PAGE_LSN)) { + && UNIV_UNLIKELY + (current_lsn + < mach_read_from_8(read_buf + FIL_PAGE_LSN))) { ut_print_timestamp(stderr); fprintf(stderr, @@ -538,7 +540,7 @@ buf_page_is_corrupted( "InnoDB: for more information.\n", (ulong) mach_read_from_4(read_buf + FIL_PAGE_OFFSET), - mach_read_ull(read_buf + FIL_PAGE_LSN), + mach_read_from_8(read_buf + FIL_PAGE_LSN), current_lsn); } } @@ -735,17 +737,15 @@ buf_page_print( #endif /* !UNIV_HOTBACKUP */ switch (fil_page_get_type(read_buf)) { + index_id_t index_id; case FIL_PAGE_INDEX: + index_id = btr_page_get_index_id(read_buf); fprintf(stderr, "InnoDB: Page may be an index page where" - " index id is %lu %lu\n", - (ulong) ut_dulint_get_high( - btr_page_get_index_id(read_buf)), - (ulong) ut_dulint_get_low( - btr_page_get_index_id(read_buf))); + " index id is %llu\n", + (ullint) index_id); #ifndef UNIV_HOTBACKUP - index = dict_index_find_on_id_low( - btr_page_get_index_id(read_buf)); + index = dict_index_find_on_id_low(index_id); if (index) { fputs("InnoDB: (", stderr); dict_index_name_print(stderr, NULL, index); @@ -4461,12 +4461,12 @@ buf_print_instance( /*===============*/ buf_pool_t* buf_pool) { - dulint* index_ids; + index_id_t* index_ids; ulint* counts; ulint size; ulint i; ulint j; - dulint id; + index_id_t id; ulint n_found; buf_chunk_t* chunk; dict_index_t* index; @@ -4475,7 +4475,7 @@ buf_print_instance( size = buf_pool->curr_size; - index_ids = mem_alloc(sizeof(dulint) * size); + index_ids = mem_alloc(size * sizeof *index_ids); counts = mem_alloc(sizeof(ulint) * size); buf_pool_mutex_enter(buf_pool); @@ -4530,8 +4530,7 @@ buf_print_instance( while (j < n_found) { - if (ut_dulint_cmp(index_ids[j], - id) == 0) { + if (index_ids[j] == id) { counts[j]++; break; @@ -4554,8 +4553,8 @@ buf_print_instance( index = dict_index_get_if_in_cache(index_ids[i]); fprintf(stderr, - "Block count for index %lu in buffer is about %lu", - (ulong) ut_dulint_get_low(index_ids[i]), + "Block count for index %llu in buffer is about %lu", + (ullint) index_ids[i], (ulong) counts[i]); if (index) { diff --git a/storage/innobase/buf/buf0flu.c b/storage/innobase/buf/buf0flu.c index 046f1ed51e8..3737627301f 100644 --- a/storage/innobase/buf/buf0flu.c +++ b/storage/innobase/buf/buf0flu.c @@ -114,7 +114,9 @@ buf_flush_insert_in_flush_rbt( p_node = rbt_prev(buf_pool->flush_rbt, c_node); if (p_node != NULL) { - prev = *rbt_value(buf_page_t*, p_node); + buf_page_t** value; + value = rbt_value(buf_page_t*, p_node); + prev = *value; ut_a(prev != NULL); } @@ -980,8 +982,8 @@ buf_flush_init_for_writing( case FIL_PAGE_TYPE_ZBLOB: case FIL_PAGE_TYPE_ZBLOB2: case FIL_PAGE_INDEX: - mach_write_ull(page_zip->data - + FIL_PAGE_LSN, newest_lsn); + mach_write_to_8(page_zip->data + + FIL_PAGE_LSN, newest_lsn); memset(page_zip->data + FIL_PAGE_FILE_FLUSH_LSN, 0, 8); mach_write_to_4(page_zip->data + FIL_PAGE_SPACE_OR_CHKSUM, @@ -1003,10 +1005,10 @@ buf_flush_init_for_writing( } /* Write the newest modification lsn to the page header and trailer */ - mach_write_ull(page + FIL_PAGE_LSN, newest_lsn); + mach_write_to_8(page + FIL_PAGE_LSN, newest_lsn); - mach_write_ull(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, - newest_lsn); + mach_write_to_8(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM, + newest_lsn); /* Store the new formula checksum */ @@ -1094,8 +1096,8 @@ buf_flush_write_block_low( ut_a(mach_read_from_4(frame + FIL_PAGE_SPACE_OR_CHKSUM) == page_zip_calc_checksum(frame, zip_size)); } - mach_write_ull(frame + FIL_PAGE_LSN, - bpage->newest_modification); + mach_write_to_8(frame + FIL_PAGE_LSN, + bpage->newest_modification); memset(frame + FIL_PAGE_FILE_FLUSH_LSN, 0, 8); break; case BUF_BLOCK_FILE_PAGE: @@ -2088,13 +2090,13 @@ buf_flush_validate_low( ut_a(om > 0); if (UNIV_LIKELY_NULL(buf_pool->flush_rbt)) { - buf_page_t* rpage; + buf_page_t** prpage; ut_a(rnode); - rpage = *rbt_value(buf_page_t*, rnode); + prpage = rbt_value(buf_page_t*, rnode); - ut_a(rpage); - ut_a(rpage == bpage); + ut_a(*prpage); + ut_a(*prpage == bpage); rnode = rbt_next(buf_pool->flush_rbt, rnode); } diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c index a539c4e894b..e1d4b5081b8 100644 --- a/storage/innobase/buf/buf0lru.c +++ b/storage/innobase/buf/buf0lru.c @@ -2278,19 +2278,17 @@ buf_LRU_print_instance( case BUF_BLOCK_FILE_PAGE: frame = buf_block_get_frame((buf_block_t*) bpage); fprintf(stderr, "\ntype %lu" - " index id %lu\n", + " index id %llu\n", (ulong) fil_page_get_type(frame), - (ulong) ut_dulint_get_low( - btr_page_get_index_id(frame))); + (ullint) btr_page_get_index_id(frame)); break; case BUF_BLOCK_ZIP_PAGE: frame = bpage->zip.data; fprintf(stderr, "\ntype %lu size %lu" - " index id %lu\n", + " index id %llu\n", (ulong) fil_page_get_type(frame), (ulong) buf_page_get_zip_size(bpage), - (ulong) ut_dulint_get_low( - btr_page_get_index_id(frame))); + (ullint) btr_page_get_index_id(frame)); break; default: diff --git a/storage/innobase/data/data0data.c b/storage/innobase/data/data0data.c index 0715b49bf9c..0ef0cfa554a 100644 --- a/storage/innobase/data/data0data.c +++ b/storage/innobase/data/data0data.c @@ -367,7 +367,7 @@ dfield_print_also_hex( prtype = dtype_get_prtype(dfield_get_type(dfield)); switch (dtype_get_mtype(dfield_get_type(dfield))) { - dulint id; + ib_id_t id; case DATA_INT: switch (len) { ulint val; @@ -417,22 +417,16 @@ dfield_print_also_hex( case 6: id = mach_read_from_6(data); - fprintf(stderr, "{%lu %lu}", - ut_dulint_get_high(id), - ut_dulint_get_low(id)); + fprintf(stderr, "%llu", (ullint) id); break; case 7: id = mach_read_from_7(data); - fprintf(stderr, "{%lu %lu}", - ut_dulint_get_high(id), - ut_dulint_get_low(id)); + fprintf(stderr, "%llu", (ullint) id); break; case 8: id = mach_read_from_8(data); - fprintf(stderr, "{%lu %lu}", - ut_dulint_get_high(id), - ut_dulint_get_low(id)); + fprintf(stderr, "%llu", (ullint) id); break; default: goto print_hex; @@ -444,29 +438,25 @@ dfield_print_also_hex( case DATA_TRX_ID: id = mach_read_from_6(data); - fprintf(stderr, "trx_id " TRX_ID_FMT, - TRX_ID_PREP_PRINTF(id)); + fprintf(stderr, "trx_id " TRX_ID_FMT, (ullint) id); break; case DATA_ROLL_PTR: id = mach_read_from_7(data); - fprintf(stderr, "roll_ptr {%lu %lu}", - ut_dulint_get_high(id), ut_dulint_get_low(id)); + fprintf(stderr, "roll_ptr " TRX_ID_FMT, (ullint) id); break; case DATA_ROW_ID: id = mach_read_from_6(data); - fprintf(stderr, "row_id {%lu %lu}", - ut_dulint_get_high(id), ut_dulint_get_low(id)); + fprintf(stderr, "row_id " TRX_ID_FMT, (ullint) id); break; default: - id = mach_dulint_read_compressed(data); + id = mach_ull_read_compressed(data); - fprintf(stderr, "mix_id {%lu %lu}", - ut_dulint_get_high(id), ut_dulint_get_low(id)); + fprintf(stderr, "mix_id " TRX_ID_FMT, (ullint) id); } break; diff --git a/storage/innobase/data/data0type.c b/storage/innobase/data/data0type.c index e834fd2ec55..20d1f5db8d3 100644 --- a/storage/innobase/data/data0type.c +++ b/storage/innobase/data/data0type.c @@ -49,10 +49,8 @@ ulint dtype_get_at_most_n_mbchars( /*========================*/ ulint prtype, /*!< in: precise type */ - ulint mbminlen, /*!< in: minimum length of a - multi-byte character */ - ulint mbmaxlen, /*!< in: maximum length of a - multi-byte character */ + ulint mbminmaxlen, /*!< in: minimum and maximum length of + a multi-byte character */ ulint prefix_len, /*!< in: length of the requested prefix, in characters, multiplied by dtype_get_mbmaxlen(dtype) */ @@ -60,6 +58,9 @@ dtype_get_at_most_n_mbchars( const char* str) /*!< in: the string whose prefix length is being determined */ { + ulint mbminlen = DATA_MBMINLEN(mbminmaxlen); + ulint mbmaxlen = DATA_MBMAXLEN(mbminmaxlen); + ut_a(data_len != UNIV_SQL_NULL); ut_ad(!mbmaxlen || !(prefix_len % mbmaxlen)); @@ -180,7 +181,7 @@ dtype_validate( } #ifndef UNIV_HOTBACKUP - ut_a(type->mbminlen <= type->mbmaxlen); + ut_a(dtype_get_mbminlen(type) <= dtype_get_mbmaxlen(type)); #endif /* !UNIV_HOTBACKUP */ return(TRUE); diff --git a/storage/innobase/dict/dict0boot.c b/storage/innobase/dict/dict0boot.c index e63c1dc94b9..20d676e6129 100644 --- a/storage/innobase/dict/dict0boot.c +++ b/storage/innobase/dict/dict0boot.c @@ -67,12 +67,15 @@ UNIV_INTERN void dict_hdr_get_new_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) */ + table_id_t* table_id, /*!< out: table id + (not assigned if NULL) */ + index_id_t* 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; + ib_id_t id; mtr_t mtr; mtr_start(&mtr); @@ -80,16 +83,16 @@ dict_hdr_get_new_id( dict_hdr = dict_hdr_get(&mtr); 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); + id = mach_read_from_8(dict_hdr + DICT_HDR_TABLE_ID); + id++; + mlog_write_ull(dict_hdr + DICT_HDR_TABLE_ID, id, &mtr); *table_id = id; } 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); + id = mach_read_from_8(dict_hdr + DICT_HDR_INDEX_ID); + id++; + mlog_write_ull(dict_hdr + DICT_HDR_INDEX_ID, id, &mtr); *index_id = id; } @@ -114,7 +117,7 @@ dict_hdr_flush_row_id(void) /*=======================*/ { dict_hdr_t* dict_hdr; - dulint id; + row_id_t id; mtr_t mtr; ut_ad(mutex_own(&(dict_sys->mutex))); @@ -125,7 +128,7 @@ dict_hdr_flush_row_id(void) dict_hdr = dict_hdr_get(&mtr); - mlog_write_dulint(dict_hdr + DICT_HDR_ROW_ID, id, &mtr); + mlog_write_ull(dict_hdr + DICT_HDR_ROW_ID, id, &mtr); mtr_commit(&mtr); } @@ -157,14 +160,14 @@ dict_hdr_create( /* Start counting row, table, index, and tree ids from DICT_HDR_FIRST_ID */ - mlog_write_dulint(dict_header + DICT_HDR_ROW_ID, - ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); + mlog_write_ull(dict_header + DICT_HDR_ROW_ID, + DICT_HDR_FIRST_ID, mtr); - mlog_write_dulint(dict_header + DICT_HDR_TABLE_ID, - ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); + mlog_write_ull(dict_header + DICT_HDR_TABLE_ID, + DICT_HDR_FIRST_ID, mtr); - mlog_write_dulint(dict_header + DICT_HDR_INDEX_ID, - ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr); + mlog_write_ull(dict_header + DICT_HDR_INDEX_ID, + DICT_HDR_FIRST_ID, mtr); mlog_write_ulint(dict_header + DICT_HDR_MAX_SPACE_ID, 0, MLOG_4BYTES, mtr); @@ -273,11 +276,9 @@ dict_boot(void) ..._MARGIN, it will immediately be updated to the disk-based header. */ - dict_sys->row_id = ut_dulint_add( - ut_dulint_align_up(mtr_read_dulint(dict_hdr + DICT_HDR_ROW_ID, - &mtr), - DICT_HDR_ROW_ID_WRITE_MARGIN), - DICT_HDR_ROW_ID_WRITE_MARGIN); + dict_sys->row_id = DICT_HDR_ROW_ID_WRITE_MARGIN + + ut_uint64_align_up(mach_read_from_8(dict_hdr + DICT_HDR_ROW_ID), + DICT_HDR_ROW_ID_WRITE_MARGIN); /* Insert into the dictionary cache the descriptions of the basic system tables */ diff --git a/storage/innobase/dict/dict0crea.c b/storage/innobase/dict/dict0crea.c index 09353c45c8c..6824d0fa9f9 100644 --- a/storage/innobase/dict/dict0crea.c +++ b/storage/innobase/dict/dict0crea.c @@ -590,7 +590,7 @@ dict_build_index_def_step( ins_node_set_new_row(node->ind_def, row); /* Note that the index was created by this transaction. */ - index->trx_id = (ib_uint64_t) ut_conv_dulint_to_longlong(trx->id); + index->trx_id = trx->id; return(DB_SUCCESS); } @@ -761,7 +761,7 @@ dict_truncate_index_tree( ibool drop = !space; ulint zip_size; ulint type; - dulint index_id; + index_id_t index_id; rec_t* rec; const byte* ptr; ulint len; @@ -854,7 +854,7 @@ create: for (index = UT_LIST_GET_FIRST(table->indexes); index; index = UT_LIST_GET_NEXT(indexes, index)) { - if (!ut_dulint_cmp(index->id, index_id)) { + if (index->id == index_id) { root_page_no = btr_create(type, space, zip_size, index_id, index, mtr); index->page = (unsigned int) root_page_no; @@ -864,10 +864,9 @@ create: ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB: Index %lu %lu of table %s is missing\n" + " InnoDB: Index %llu of table %s is missing\n" "InnoDB: from the data dictionary during TRUNCATE!\n", - ut_dulint_get_high(index_id), - ut_dulint_get_low(index_id), + (ullint) index_id, table->name); return(FIL_NULL); @@ -1119,7 +1118,7 @@ dict_create_index_step( if (node->state == INDEX_ADD_TO_CACHE) { - dulint index_id = node->index->id; + index_id_t index_id = node->index->id; err = dict_index_add_to_cache( node->table, node->index, FIL_NULL, diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c index a298d785449..802f0bd8b6f 100644 --- a/storage/innobase/dict/dict0dict.c +++ b/storage/innobase/dict/dict0dict.c @@ -256,8 +256,8 @@ dict_mutex_exit_for_mysql(void) /** 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]) + (&dict_index_stat_mutex[ut_fold_ull(index->id) \ + % DICT_INDEX_STAT_MUTEX_SIZE]) /**********************************************************************//** Lock the appropriate mutex to protect index->stat_n_diff_key_vals[]. @@ -425,14 +425,14 @@ dict_index_t* dict_index_get_on_id_low( /*=====================*/ dict_table_t* table, /*!< in: table */ - dulint id) /*!< in: index id */ + index_id_t id) /*!< in: index id */ { dict_index_t* index; index = dict_table_get_first_index(table); while (index) { - if (0 == ut_dulint_cmp(id, index->id)) { + if (id == index->id) { /* Found */ return(index); @@ -574,20 +574,18 @@ UNIV_INTERN dict_table_t* dict_table_get_on_id( /*=================*/ - dulint table_id, /*!< in: table id */ - trx_t* trx) /*!< in: transaction handle */ + table_id_t table_id, /*!< in: table id */ + trx_t* trx) /*!< in: transaction handle */ { dict_table_t* table; - if (ut_dulint_cmp(table_id, DICT_FIELDS_ID) <= 0 + if (table_id <= DICT_FIELDS_ID || trx->dict_operation_lock_mode == RW_X_LATCH) { - /* It is a system table which will always exist in the table - cache: we avoid acquiring the dictionary mutex, because - if we are doing a rollback to handle an error in TABLE - CREATE, for example, we already have the mutex! */ - ut_ad(mutex_own(&(dict_sys->mutex)) - || trx->dict_operation_lock_mode == RW_X_LATCH); + /* Note: An X latch implies that the transaction + already owns the dictionary mutex. */ + + ut_ad(mutex_own(&dict_sys->mutex)); return(dict_table_get_on_id_low(table_id)); } @@ -800,7 +798,7 @@ dict_table_add_to_cache( table->cached = TRUE; fold = ut_fold_string(table->name); - id_fold = ut_fold_dulint(table->id); + id_fold = ut_fold_ull(table->id); row_len = 0; for (i = 0; i < table->n_def; i++) { @@ -842,7 +840,7 @@ dict_table_add_to_cache( dict_table_t* table2; HASH_SEARCH(id_hash, dict_sys->table_id_hash, id_fold, dict_table_t*, table2, ut_ad(table2->cached), - ut_dulint_cmp(table2->id, table->id) == 0); + table2->id == table->id); ut_a(table2 == NULL); #ifdef UNIV_DEBUG @@ -864,7 +862,8 @@ dict_table_add_to_cache( /* Add table to LRU list of tables */ UT_LIST_ADD_FIRST(table_LRU, dict_sys->table_LRU, table); - dict_sys->size += mem_heap_get_size(table->heap); + dict_sys->size += mem_heap_get_size(table->heap) + + strlen(table->name) + 1; } /**********************************************************************//** @@ -876,7 +875,7 @@ UNIV_INTERN dict_index_t* dict_index_find_on_id_low( /*======================*/ - dulint id) /*!< in: index id */ + index_id_t id) /*!< in: index id */ { dict_table_t* table; dict_index_t* index; @@ -887,7 +886,7 @@ dict_index_find_on_id_low( index = dict_table_get_first_index(table); while (index) { - if (0 == ut_dulint_cmp(id, index->id)) { + if (id == index->id) { /* Found */ return(index); @@ -918,14 +917,21 @@ dict_table_rename_in_cache( dict_foreign_t* foreign; dict_index_t* index; ulint fold; - ulint old_size; - const char* old_name; + char old_name[MAX_TABLE_NAME_LEN + 1]; ut_ad(table); ut_ad(mutex_own(&(dict_sys->mutex))); - old_size = mem_heap_get_size(table->heap); - old_name = table->name; + /* store the old/current name to an automatic variable */ + if (strlen(table->name) + 1 <= sizeof(old_name)) { + memcpy(old_name, table->name, strlen(table->name) + 1); + } else { + ut_print_timestamp(stderr); + fprintf(stderr, "InnoDB: too long table name: '%s', " + "max length is %d\n", table->name, + MAX_TABLE_NAME_LEN); + ut_error; + } fold = ut_fold_string(new_name); @@ -971,12 +977,22 @@ dict_table_rename_in_cache( /* Remove table from the hash tables of tables */ HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash, ut_fold_string(old_name), table); - table->name = mem_heap_strdup(table->heap, new_name); + + if (strlen(new_name) > strlen(table->name)) { + /* We allocate MAX_TABLE_NAME_LEN+1 bytes here to avoid + memory fragmentation, we assume a repeated calls of + ut_realloc() with the same size do not cause fragmentation */ + ut_a(strlen(new_name) <= MAX_TABLE_NAME_LEN); + table->name = ut_realloc(table->name, MAX_TABLE_NAME_LEN + 1); + } + memcpy(table->name, new_name, strlen(new_name) + 1); /* Add table to hash table of tables */ HASH_INSERT(dict_table_t, name_hash, dict_sys->table_hash, fold, table); - dict_sys->size += (mem_heap_get_size(table->heap) - old_size); + + dict_sys->size += strlen(new_name) - strlen(old_name); + ut_a(dict_sys->size > 0); /* Update the table_name field in indexes */ index = dict_table_get_first_index(table); @@ -1126,7 +1142,7 @@ void dict_table_change_id_in_cache( /*==========================*/ dict_table_t* table, /*!< in/out: table object already in cache */ - dulint new_id) /*!< in: new id to set */ + table_id_t new_id) /*!< in: new id to set */ { ut_ad(table); ut_ad(mutex_own(&(dict_sys->mutex))); @@ -1135,12 +1151,12 @@ dict_table_change_id_in_cache( /* Remove the table from the hash table of id's */ HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash, - ut_fold_dulint(table->id), table); + ut_fold_ull(table->id), table); table->id = new_id; /* Add the table back to the hash table */ HASH_INSERT(dict_table_t, id_hash, dict_sys->table_id_hash, - ut_fold_dulint(table->id), table); + ut_fold_ull(table->id), table); } /**********************************************************************//** @@ -1196,12 +1212,12 @@ dict_table_remove_from_cache( HASH_DELETE(dict_table_t, name_hash, dict_sys->table_hash, ut_fold_string(table->name), table); HASH_DELETE(dict_table_t, id_hash, dict_sys->table_id_hash, - ut_fold_dulint(table->id), table); + ut_fold_ull(table->id), table); /* Remove table from LRU list of tables */ UT_LIST_REMOVE(table_LRU, dict_sys->table_LRU, table); - size = mem_heap_get_size(table->heap); + size = mem_heap_get_size(table->heap) + strlen(table->name) + 1; ut_ad(dict_sys->size >= size); @@ -2458,8 +2474,7 @@ dict_table_get_index_by_max_id( /* We found a matching index, select the index with the higher id*/ - if (!found - || ut_dulint_cmp(index->id, found->id) > 0) { + if (!found || index->id > found->id) { found = index; } @@ -3947,7 +3962,7 @@ UNIV_INTERN dict_index_t* dict_index_get_if_in_cache_low( /*===========================*/ - dulint index_id) /*!< in: index id */ + index_id_t index_id) /*!< in: index id */ { ut_ad(mutex_own(&(dict_sys->mutex))); @@ -3962,7 +3977,7 @@ UNIV_INTERN dict_index_t* dict_index_get_if_in_cache( /*=======================*/ - dulint index_id) /*!< in: index id */ + index_id_t index_id) /*!< in: index id */ { dict_index_t* index; @@ -4358,12 +4373,11 @@ dict_table_print_low( fprintf(stderr, "--------------------------------------\n" - "TABLE: name %s, id %lu %lu, flags %lx, columns %lu," + "TABLE: name %s, id %llu, flags %lx, columns %lu," " indexes %lu, appr.rows %lu\n" " COLUMNS: ", table->name, - (ulong) ut_dulint_get_high(table->id), - (ulong) ut_dulint_get_low(table->id), + (ullint) table->id, (ulong) table->flags, (ulong) table->n_cols, (ulong) UT_LIST_GET_LEN(table->indexes), @@ -4452,14 +4466,13 @@ dict_index_print_low( } fprintf(stderr, - " INDEX: name %s, id %lu %lu, fields %lu/%lu," + " INDEX: name %s, id %llu, fields %lu/%lu," " uniq %lu, type %lu\n" " root page %lu, appr.key vals %lu," " leaf pages %lu, size pages %lu\n" " FIELDS: ", index->name, - (ulong) ut_dulint_get_high(index->id), - (ulong) ut_dulint_get_low(index->id), + (ullint) index->id, (ulong) index->n_user_defined_cols, (ulong) index->n_fields, (ulong) index->n_uniq, @@ -4831,8 +4844,7 @@ dict_table_get_index_on_name_and_min_id( while (index != NULL) { if (ut_strcmp(index->name, name) == 0) { - if (!min_index - || ut_dulint_cmp(index->id, min_index->id) < 0) { + if (!min_index || index->id < min_index->id) { min_index = index; } diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c index 6bf2c1d9d81..20a18c72a39 100644 --- a/storage/innobase/dict/dict0load.c +++ b/storage/innobase/dict/dict0load.c @@ -364,7 +364,7 @@ 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 */ + table_id_t* table_id) /*!< out: index table id */ { const char* err_msg; byte* buf; @@ -390,7 +390,7 @@ 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 */ + table_id_t* table_id, /*!< out: table id */ const char** col_name) /*!< out: column name */ { const char* err_msg; @@ -414,8 +414,8 @@ dict_process_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 */ + index_id_t* index_id, /*!< out: current index id */ + index_id_t last_id) /*!< in: previous index id */ { byte* buf; byte* last_index_id; @@ -644,7 +644,7 @@ dict_check_tablespaces_and_store_max_id( dict_index_t* sys_index; btr_pcur_t pcur; const rec_t* rec; - ulint max_space_id = 0; + ulint max_space_id; mtr_t mtr; mutex_enter(&(dict_sys->mutex)); @@ -655,6 +655,11 @@ dict_check_tablespaces_and_store_max_id( sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); ut_a(!dict_table_is_comp(sys_tables)); + max_space_id = mtr_read_ulint(dict_hdr_get(&mtr) + + DICT_HDR_MAX_SPACE_ID, + MLOG_4BYTES, &mtr); + fil_set_max_space_id_if_bigger(max_space_id); + btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr); loop: @@ -777,13 +782,14 @@ const char* dict_load_column_low( /*=================*/ dict_table_t* table, /*!< in/out: table, could be NULL - if we just polulate a dict_column_t + 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 */ + dict_col_t* column, /*!< out: dict_column_t to fill, + or NULL if table != NULL */ + table_id_t* table_id, /*!< out: table id */ const char** col_name, /*!< out: column name */ const rec_t* rec) /*!< in: SYS_COLUMNS record */ { @@ -795,6 +801,8 @@ dict_load_column_low( ulint col_len; ulint pos; + ut_ad(table || column); + if (UNIV_UNLIKELY(rec_get_deleted_flag(rec, 0))) { return("delete-marked record in SYS_COLUMNS"); } @@ -811,8 +819,7 @@ err_len: if (table_id) { *table_id = mach_read_from_8(field); - } else if (UNIV_UNLIKELY(ut_dulint_cmp(table->id, - mach_read_from_8(field)))) { + } else if (UNIV_UNLIKELY(table->id != mach_read_from_8(field))) { return("SYS_COLUMNS.TABLE_ID mismatch"); } @@ -822,9 +829,9 @@ err_len: goto err_len; } - if (!table) { - pos = mach_read_from_4(field); - } else if (UNIV_UNLIKELY(table->n_def != mach_read_from_4(field))) { + pos = mach_read_from_4(field); + + if (UNIV_UNLIKELY(table && table->n_def != pos)) { return("SYS_COLUMNS.POS mismatch"); } @@ -1191,7 +1198,7 @@ dict_load_index_low( ulint len; ulint name_len; char* name_buf; - dulint id; + index_id_t id; ulint n_fields; ulint type; ulint space; @@ -1308,19 +1315,11 @@ dict_load_indexes( dfield_t* dfield; const rec_t* rec; byte* buf; - ibool is_sys_table; mtr_t mtr; ulint error = DB_SUCCESS; ut_ad(mutex_own(&(dict_sys->mutex))); - if ((ut_dulint_get_high(table->id) == 0) - && (ut_dulint_get_low(table->id) < DICT_HDR_FIRST_ID)) { - is_sys_table = TRUE; - } else { - is_sys_table = FALSE; - } - mtr_start(&mtr); sys_indexes = dict_table_get_low("SYS_INDEXES"); @@ -1406,7 +1405,7 @@ corrupted: " is not clustered!\n", stderr); goto corrupted; - } else if (is_sys_table + } else if (table->id < DICT_HDR_FIRST_ID && (dict_index_is_clust(index) || ((table == dict_sys->sys_tables) && !strcmp("ID_IND", index->name)))) { @@ -1766,7 +1765,7 @@ UNIV_INTERN dict_table_t* dict_load_table_on_id( /*==================*/ - dulint table_id) /*!< in: table id */ + table_id_t table_id) /*!< in: table id */ { byte id_buf[8]; btr_pcur_t pcur; @@ -1829,7 +1828,7 @@ dict_load_table_on_id( ut_ad(len == 8); /* Check if the table id in record is the one searched for */ - if (ut_dulint_cmp(table_id, mach_read_from_8(field)) != 0) { + if (table_id != mach_read_from_8(field)) { btr_pcur_close(&pcur); mtr_commit(&mtr); diff --git a/storage/innobase/dict/dict0mem.c b/storage/innobase/dict/dict0mem.c index b6e516783c7..bbb8f810f44 100644 --- a/storage/innobase/dict/dict0mem.c +++ b/storage/innobase/dict/dict0mem.c @@ -73,7 +73,8 @@ dict_mem_table_create( table->heap = heap; table->flags = (unsigned int) flags; - table->name = mem_heap_strdup(heap, name); + table->name = ut_malloc(strlen(name) + 1); + memcpy(table->name, name, strlen(name) + 1); table->space = (unsigned int) space; table->n_cols = (unsigned int) (n_cols + DATA_N_SYS_COLS); @@ -112,6 +113,7 @@ dict_mem_table_free( #ifndef UNIV_HOTBACKUP mutex_free(&(table->autoinc_mutex)); #endif /* UNIV_HOTBACKUP */ + ut_free(table->name); mem_heap_free(table->heap); } @@ -204,6 +206,37 @@ dict_mem_table_add_col( dict_mem_fill_column_struct(col, i, mtype, prtype, len); } + +/**********************************************************************//** +This function populates a dict_col_t memory structure with +supplied information. */ +UNIV_INTERN +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 length */ +{ +#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); + dict_col_set_mbminmaxlen(column, mbminlen, mbmaxlen); +#endif /* !UNIV_HOTBACKUP */ +} + /**********************************************************************//** Creates an index memory object. @return own: index object */ diff --git a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c index 0d033c37879..710f0ac8603 100644 --- a/storage/innobase/fil/fil0fil.c +++ b/storage/innobase/fil/fil0fil.c @@ -1214,7 +1214,7 @@ try_again: space->tablespace_version = fil_system->tablespace_version; space->mark = FALSE; - if (UNIV_LIKELY(purpose == FIL_TABLESPACE) + if (UNIV_LIKELY(purpose == FIL_TABLESPACE && !recv_recovery_on) && UNIV_UNLIKELY(id > fil_system->max_assigned_id)) { if (!fil_system->space_id_reuse_warned) { fil_system->space_id_reuse_warned = TRUE; @@ -1705,7 +1705,7 @@ fil_write_lsn_and_arch_no_to_file( fil_read(TRUE, 0, 0, sum_of_sizes, 0, UNIV_PAGE_SIZE, buf, NULL); - mach_write_ull(buf + FIL_PAGE_FILE_FLUSH_LSN, lsn); + mach_write_to_8(buf + FIL_PAGE_FILE_FLUSH_LSN, lsn); fil_write(TRUE, 0, 0, sum_of_sizes, 0, UNIV_PAGE_SIZE, buf, NULL); @@ -1799,7 +1799,7 @@ fil_read_flushed_lsn_and_arch_log_no( os_file_read(data_file, buf, 0, 0, UNIV_PAGE_SIZE); - flushed_lsn = mach_read_ull(buf + FIL_PAGE_FILE_FLUSH_LSN); + flushed_lsn = mach_read_from_8(buf + FIL_PAGE_FILE_FLUSH_LSN); ut_free(buf2); @@ -2850,7 +2850,7 @@ fil_reset_too_high_lsns( /* We have to read the file flush lsn from the header of the file */ - flush_lsn = mach_read_ull(page + FIL_PAGE_FILE_FLUSH_LSN); + flush_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN); if (current_lsn >= flush_lsn) { /* Ok */ @@ -2898,7 +2898,7 @@ fil_reset_too_high_lsns( goto func_exit; } - if (mach_read_ull(page + FIL_PAGE_LSN) > current_lsn) { + if (mach_read_from_8(page + FIL_PAGE_LSN) > current_lsn) { /* We have to reset the lsn */ if (zip_size) { @@ -2940,7 +2940,7 @@ fil_reset_too_high_lsns( goto func_exit; } - mach_write_ull(page + FIL_PAGE_FILE_FLUSH_LSN, current_lsn); + mach_write_to_8(page + FIL_PAGE_FILE_FLUSH_LSN, current_lsn); success = os_file_write(filepath, file, page, 0, 0, zip_size ? zip_size : UNIV_PAGE_SIZE); diff --git a/storage/innobase/fsp/fsp0fsp.c b/storage/innobase/fsp/fsp0fsp.c index 2bae8481d20..3efe147b998 100644 --- a/storage/innobase/fsp/fsp0fsp.c +++ b/storage/innobase/fsp/fsp0fsp.c @@ -127,9 +127,8 @@ typedef byte fseg_inode_t; #define FSEG_ARR_OFFSET (FSEG_PAGE_DATA + FLST_NODE_SIZE) /*-------------------------------------*/ -#define FSEG_ID 0 /* 8 bytes of segment id: if this is - ut_dulint_zero, it means that the - header is unused */ +#define FSEG_ID 0 /* 8 bytes of segment id: if this is 0, + it means that the header is unused */ #define FSEG_NOT_FULL_N_USED 8 /* number of used segment pages in the FSEG_NOT_FULL list */ @@ -999,11 +998,11 @@ fsp_header_init( flst_init(header + FSP_SEG_INODES_FULL, mtr); flst_init(header + FSP_SEG_INODES_FREE, mtr); - mlog_write_dulint(header + FSP_SEG_ID, ut_dulint_create(0, 1), mtr); + mlog_write_ull(header + FSP_SEG_ID, 1, mtr); if (space == 0) { fsp_fill_free_list(FALSE, space, header, mtr); btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, - 0, 0, ut_dulint_add(DICT_IBUF_ID_MIN, space), + 0, 0, DICT_IBUF_ID_MIN + space, dict_ind_redundant, mtr); } else { fsp_fill_free_list(TRUE, space, header, mtr); @@ -1841,7 +1840,7 @@ fsp_seg_inode_page_find_used( inode = fsp_seg_inode_page_get_nth_inode( page, i, zip_size, mtr); - if (!ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))) { + if (mach_read_from_8(inode + FSEG_ID)) { /* This is used */ ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) @@ -1872,7 +1871,7 @@ fsp_seg_inode_page_find_free( inode = fsp_seg_inode_page_get_nth_inode( page, i, zip_size, mtr); - if (ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID))) { + if (!mach_read_from_8(inode + FSEG_ID)) { /* This is unused */ return(i); @@ -1931,7 +1930,7 @@ fsp_alloc_seg_inode_page( inode = fsp_seg_inode_page_get_nth_inode(page, i, zip_size, mtr); - mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr); + mlog_write_ull(inode + FSEG_ID, 0, mtr); } flst_add_last(space_header + FSP_SEG_INODES_FREE, @@ -1998,7 +1997,7 @@ fsp_alloc_seg_inode( page + FSEG_INODE_PAGE_NODE, mtr); } - ut_ad(ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID)) + ut_ad(!mach_read_from_8(inode + FSEG_ID) || mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); return(inode); } @@ -2036,7 +2035,7 @@ fsp_free_seg_inode( page + FSEG_INODE_PAGE_NODE, mtr); } - mlog_write_dulint(inode + FSEG_ID, ut_dulint_zero, mtr); + mlog_write_ull(inode + FSEG_ID, 0, mtr); mlog_write_ulint(inode + FSEG_MAGIC_N, 0xfa051ce3, MLOG_4BYTES, mtr); if (ULINT_UNDEFINED @@ -2073,8 +2072,7 @@ fseg_inode_try_get( inode = fut_get_ptr(space, zip_size, inode_addr, RW_X_LATCH, mtr); - if (UNIV_UNLIKELY - (ut_dulint_is_zero(mach_read_from_8(inode + FSEG_ID)))) { + if (UNIV_UNLIKELY(!mach_read_from_8(inode + FSEG_ID))) { inode = NULL; } else { @@ -2249,7 +2247,7 @@ fseg_create_general( ulint zip_size; fsp_header_t* space_header; fseg_inode_t* inode; - dulint seg_id; + ib_id_t seg_id; buf_block_t* block = 0; /* remove warning */ fseg_header_t* header = 0; /* remove warning */ rw_lock_t* latch; @@ -2303,12 +2301,11 @@ fseg_create_general( /* Read the next segment id from space header and increment the value in space header */ - seg_id = mtr_read_dulint(space_header + FSP_SEG_ID, mtr); + seg_id = mach_read_from_8(space_header + FSP_SEG_ID); - mlog_write_dulint(space_header + FSP_SEG_ID, ut_dulint_add(seg_id, 1), - mtr); + mlog_write_ull(space_header + FSP_SEG_ID, seg_id + 1, mtr); - mlog_write_dulint(inode + FSEG_ID, seg_id, mtr); + mlog_write_ull(inode + FSEG_ID, seg_id, mtr); mlog_write_ulint(inode + FSEG_NOT_FULL_N_USED, 0, MLOG_4BYTES, mtr); flst_init(inode + FSEG_FREE, mtr); @@ -2460,7 +2457,7 @@ fseg_fill_free_list( { xdes_t* descr; ulint i; - dulint seg_id; + ib_id_t seg_id; ulint reserved; ulint used; @@ -2497,10 +2494,10 @@ fseg_fill_free_list( xdes_set_state(descr, XDES_FSEG, mtr); - seg_id = mtr_read_dulint(inode + FSEG_ID, mtr); + seg_id = mach_read_from_8(inode + FSEG_ID); ut_ad(mach_read_from_4(inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); - mlog_write_dulint(descr + XDES_ID, seg_id, mtr); + mlog_write_ull(descr + XDES_ID, seg_id, mtr); flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr); hint += FSP_EXTENT_SIZE; @@ -2524,7 +2521,7 @@ fseg_alloc_free_extent( mtr_t* mtr) /*!< in: mtr */ { xdes_t* descr; - dulint seg_id; + ib_id_t seg_id; fil_addr_t first; ut_ad(!((page_offset(inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE)); @@ -2545,10 +2542,10 @@ fseg_alloc_free_extent( return(NULL); } - seg_id = mtr_read_dulint(inode + FSEG_ID, mtr); + seg_id = mach_read_from_8(inode + FSEG_ID); xdes_set_state(descr, XDES_FSEG, mtr); - mlog_write_dulint(descr + XDES_ID, seg_id, mtr); + mlog_write_ull(descr + XDES_ID, seg_id, mtr); flst_add_last(inode + FSEG_FREE, descr + XDES_FLST_NODE, mtr); /* Try to fill the segment free list */ @@ -2583,7 +2580,7 @@ fseg_alloc_free_page_low( { fsp_header_t* space_header; ulint space_size; - dulint seg_id; + ib_id_t seg_id; ulint used; ulint reserved; xdes_t* descr; /*!< extent of the hinted page */ @@ -2599,9 +2596,9 @@ fseg_alloc_free_page_low( ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); ut_ad(!((page_offset(seg_inode) - FSEG_ARR_OFFSET) % FSEG_INODE_SIZE)); - seg_id = mtr_read_dulint(seg_inode + FSEG_ID, mtr); + seg_id = mach_read_from_8(seg_inode + FSEG_ID); - ut_ad(!ut_dulint_is_zero(seg_id)); + ut_ad(seg_id); reserved = fseg_n_reserved_pages_low(seg_inode, &used, mtr); @@ -2619,8 +2616,7 @@ fseg_alloc_free_page_low( /* In the big if-else below we look for ret_page and ret_descr */ /*-------------------------------------------------------------*/ if ((xdes_get_state(descr, mtr) == XDES_FSEG) - && (0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, - mtr), seg_id)) + && mach_read_from_8(descr + XDES_ID) == seg_id && (xdes_get_bit(descr, XDES_FREE_BIT, hint % FSP_EXTENT_SIZE, mtr) == TRUE)) { @@ -2642,7 +2638,7 @@ fseg_alloc_free_page_low( ut_a(ret_descr == descr); xdes_set_state(ret_descr, XDES_FSEG, mtr); - mlog_write_dulint(ret_descr + XDES_ID, seg_id, mtr); + mlog_write_ull(ret_descr + XDES_ID, seg_id, mtr); flst_add_last(seg_inode + FSEG_FREE, ret_descr + XDES_FLST_NODE, mtr); @@ -2671,8 +2667,7 @@ fseg_alloc_free_page_low( } /*-----------------------------------------------------------*/ } else if ((xdes_get_state(descr, mtr) == XDES_FSEG) - && (0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, - mtr), seg_id)) + && mach_read_from_8(descr + XDES_ID) == seg_id && (!xdes_is_full(descr, mtr))) { /* 4. We can take the page from the same extent as the @@ -3243,8 +3238,8 @@ fseg_free_page_low( xdes_t* descr; ulint not_full_n_used; ulint state; - dulint descr_id; - dulint seg_id; + ib_id_t descr_id; + ib_id_t seg_id; ulint i; ut_ad(seg_inode && mtr); @@ -3303,20 +3298,18 @@ crash: /* If we get here, the page is in some extent of the segment */ - descr_id = mtr_read_dulint(descr + XDES_ID, mtr); - seg_id = mtr_read_dulint(seg_inode + FSEG_ID, mtr); + descr_id = mach_read_from_8(descr + XDES_ID); + seg_id = mach_read_from_8(seg_inode + FSEG_ID); #if 0 fprintf(stderr, "InnoDB: InnoDB is freeing space %lu page %lu,\n" - "InnoDB: which belongs to descr seg %lu %lu\n" - "InnoDB: segment %lu %lu.\n", + "InnoDB: which belongs to descr seg %llu\n" + "InnoDB: segment %llu.\n", (ulong) space, (ulong) page, - (ulong) ut_dulint_get_high(descr_id), - (ulong) ut_dulint_get_low(descr_id), - (ulong) ut_dulint_get_high(seg_id), - (ulong) ut_dulint_get_low(seg_id)); + (ullint) descr_id, + (ullint) seg_id); #endif /* 0 */ - if (0 != ut_dulint_cmp(descr_id, seg_id)) { + if (UNIV_UNLIKELY(descr_id != seg_id)) { fputs("InnoDB: Dump of the tablespace extent descriptor: ", stderr); ut_print_buf(stderr, descr, 40); @@ -3328,13 +3321,11 @@ crash: "InnoDB: Serious error: InnoDB is trying to" " free space %lu page %lu,\n" "InnoDB: which does not belong to" - " segment %lu %lu but belongs\n" - "InnoDB: to segment %lu %lu.\n", + " segment %llu but belongs\n" + "InnoDB: to segment %llu.\n", (ulong) space, (ulong) page, - (ulong) ut_dulint_get_high(descr_id), - (ulong) ut_dulint_get_low(descr_id), - (ulong) ut_dulint_get_high(seg_id), - (ulong) ut_dulint_get_low(seg_id)); + (ullint) descr_id, + (ullint) seg_id); goto crash; } @@ -3423,8 +3414,7 @@ fseg_free_extent( descr = xdes_get_descriptor(space, zip_size, page, mtr); ut_a(xdes_get_state(descr, mtr) == XDES_FSEG); - ut_a(0 == ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, mtr), - mtr_read_dulint(seg_inode + FSEG_ID, mtr))); + ut_a(!memcmp(descr + XDES_ID, seg_inode + FSEG_ID, 8)); ut_ad(mach_read_from_4(seg_inode + FSEG_MAGIC_N) == FSEG_MAGIC_N_VALUE); @@ -3684,7 +3674,7 @@ fseg_validate_low( mtr_t* mtr2) /*!< in: mtr */ { ulint space; - dulint seg_id; + ib_id_t seg_id; mtr_t mtr; xdes_t* descr; fil_addr_t node_addr; @@ -3696,7 +3686,7 @@ fseg_validate_low( space = page_get_space_id(page_align(inode)); - seg_id = mtr_read_dulint(inode + FSEG_ID, mtr2); + seg_id = mach_read_from_8(inode + FSEG_ID); n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr2); flst_validate(inode + FSEG_FREE, mtr2); @@ -3719,8 +3709,7 @@ fseg_validate_low( ut_a(xdes_get_n_used(descr, &mtr) == 0); ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG); - ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr), - seg_id)); + ut_a(mach_read_from_8(descr + XDES_ID) == seg_id); node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr); mtr_commit(&mtr); @@ -3744,8 +3733,7 @@ fseg_validate_low( ut_a(xdes_get_n_used(descr, &mtr) > 0); ut_a(xdes_get_n_used(descr, &mtr) < FSP_EXTENT_SIZE); ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG); - ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr), - seg_id)); + ut_a(mach_read_from_8(descr + XDES_ID) == seg_id); n_used2 += xdes_get_n_used(descr, &mtr); @@ -3770,8 +3758,7 @@ fseg_validate_low( ut_a(xdes_get_n_used(descr, &mtr) == FSP_EXTENT_SIZE); ut_a(xdes_get_state(descr, &mtr) == XDES_FSEG); - ut_a(!ut_dulint_cmp(mtr_read_dulint(descr + XDES_ID, &mtr), - seg_id)); + ut_a(mach_read_from_8(descr + XDES_ID) == seg_id); node_addr = flst_get_next_addr(descr + XDES_FLST_NODE, &mtr); mtr_commit(&mtr); @@ -3822,8 +3809,6 @@ fseg_print_low( mtr_t* mtr) /*!< in: mtr */ { ulint space; - ulint seg_id_low; - ulint seg_id_high; ulint n_used; ulint n_frag; ulint n_free; @@ -3832,7 +3817,7 @@ fseg_print_low( ulint reserved; ulint used; ulint page_no; - dulint d_var; + ib_id_t seg_id; ut_ad(mtr_memo_contains_page(mtr, inode, MTR_MEMO_PAGE_X_FIX)); space = page_get_space_id(page_align(inode)); @@ -3840,10 +3825,7 @@ fseg_print_low( reserved = fseg_n_reserved_pages_low(inode, &used, mtr); - d_var = mtr_read_dulint(inode + FSEG_ID, mtr); - - seg_id_low = ut_dulint_get_low(d_var); - seg_id_high = ut_dulint_get_high(d_var); + seg_id = mach_read_from_8(inode + FSEG_ID); n_used = mtr_read_ulint(inode + FSEG_NOT_FULL_N_USED, MLOG_4BYTES, mtr); @@ -3853,11 +3835,11 @@ fseg_print_low( n_full = flst_get_len(inode + FSEG_FULL, mtr); fprintf(stderr, - "SEGMENT id %lu %lu space %lu; page %lu;" + "SEGMENT id %llu space %lu; page %lu;" " res %lu used %lu; full ext %lu\n" "fragm pages %lu; free extents %lu;" " not full extents %lu: pages %lu\n", - (ulong) seg_id_high, (ulong) seg_id_low, + (ullint) seg_id, (ulong) space, (ulong) page_no, (ulong) reserved, (ulong) used, (ulong) n_full, (ulong) n_frag, (ulong) n_free, (ulong) n_not_full, @@ -4059,8 +4041,7 @@ fsp_validate( seg_inode = fsp_seg_inode_page_get_nth_inode( seg_inode_page, n, zip_size, &mtr); - ut_a(!ut_dulint_is_zero( - mach_read_from_8(seg_inode + FSEG_ID))); + ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0); fseg_validate_low(seg_inode, &mtr); descr_count += flst_get_len(seg_inode + FSEG_FREE, @@ -4105,8 +4086,7 @@ fsp_validate( seg_inode = fsp_seg_inode_page_get_nth_inode( seg_inode_page, n, zip_size, &mtr); - if (!ut_dulint_is_zero( - mach_read_from_8(seg_inode + FSEG_ID))) { + if (mach_read_from_8(seg_inode + FSEG_ID)) { fseg_validate_low(seg_inode, &mtr); descr_count += flst_get_len( @@ -4168,11 +4148,9 @@ fsp_print( ulint n_free; ulint n_free_frag; ulint n_full_frag; - ulint seg_id_low; - ulint seg_id_high; + ib_id_t seg_id; ulint n; ulint n_segs = 0; - dulint d_var; mtr_t mtr; mtr_t mtr2; @@ -4202,21 +4180,18 @@ fsp_print( n_free_frag = flst_get_len(header + FSP_FREE_FRAG, &mtr); n_full_frag = flst_get_len(header + FSP_FULL_FRAG, &mtr); - d_var = mtr_read_dulint(header + FSP_SEG_ID, &mtr); - - seg_id_low = ut_dulint_get_low(d_var); - seg_id_high = ut_dulint_get_high(d_var); + seg_id = mach_read_from_8(header + FSP_SEG_ID); fprintf(stderr, "FILE SPACE INFO: id %lu\n" "size %lu, free limit %lu, free extents %lu\n" "not full frag extents %lu: used pages %lu," " full frag extents %lu\n" - "first seg id not used %lu %lu\n", + "first seg id not used %llu\n", (ulong) space, (ulong) size, (ulong) free_limit, (ulong) n_free, (ulong) n_free_frag, (ulong) frag_n_used, (ulong) n_full_frag, - (ulong) seg_id_high, (ulong) seg_id_low); + (ullint) seg_id); mtr_commit(&mtr); @@ -4246,8 +4221,7 @@ fsp_print( seg_inode = fsp_seg_inode_page_get_nth_inode( seg_inode_page, n, zip_size, &mtr); - ut_a(!ut_dulint_is_zero( - mach_read_from_8(seg_inode + FSEG_ID))); + ut_a(mach_read_from_8(seg_inode + FSEG_ID) != 0); fseg_print_low(seg_inode, &mtr); n_segs++; @@ -4284,8 +4258,7 @@ fsp_print( seg_inode = fsp_seg_inode_page_get_nth_inode( seg_inode_page, n, zip_size, &mtr); - if (!ut_dulint_is_zero( - mach_read_from_8(seg_inode + FSEG_ID))) { + if (mach_read_from_8(seg_inode + FSEG_ID)) { fseg_print_low(seg_inode, &mtr); n_segs++; diff --git a/storage/innobase/ha/ha0ha.c b/storage/innobase/ha/ha0ha.c index 9d9d341ad39..f9e798012f8 100644 --- a/storage/innobase/ha/ha0ha.c +++ b/storage/innobase/ha/ha0ha.c @@ -31,9 +31,7 @@ Created 8/22/1994 Heikki Tuuri #ifdef UNIV_DEBUG # include "buf0buf.h" #endif /* UNIV_DEBUG */ -#ifdef UNIV_SYNC_DEBUG -# include "btr0sea.h" -#endif /* UNIV_SYNC_DEBUG */ +#include "btr0sea.h" #include "page0page.h" /*************************************************************//** @@ -127,7 +125,8 @@ ha_clear( /*************************************************************//** Inserts an entry into a hash table. If an entry with the same fold number is found, its node is updated to point to the new data, and no new node -is inserted. +is inserted. If btr_search_enabled is set to FALSE, we will only allow +updating existing nodes, but no new node is allowed to be added. @return TRUE if succeed, FALSE if no more memory could be allocated */ UNIV_INTERN ibool @@ -174,6 +173,7 @@ ha_insert_for_fold_func( prev_block->n_pointers--; block->n_pointers++; } + ut_ad(!btr_search_fully_disabled); # endif /* !UNIV_HOTBACKUP */ prev_node->block = block; @@ -186,6 +186,13 @@ ha_insert_for_fold_func( prev_node = prev_node->next; } + /* We are in the process of disabling hash index, do not add + new chain node */ + if (!btr_search_enabled) { + ut_ad(!btr_search_fully_disabled); + return(TRUE); + } + /* We have to allocate a new chain node */ node = mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t)); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 716b7bbbd56..ab9df9a0272 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -571,7 +571,7 @@ innodb_show_status( THD* thd, /*!< in: the MySQL query thread of the caller */ stat_print_fn *stat_print); static -bool innobase_show_status(handlerton *hton, THD* thd, +bool innobase_show_status(handlerton *hton, THD* thd, stat_print_fn* stat_print, enum ha_stat_type stat_type); @@ -1032,6 +1032,8 @@ innobase_get_cset_width( if (cs) { *mbminlen = cs->mbminlen; *mbmaxlen = cs->mbmaxlen; + ut_ad(*mbminlen < DATA_MBMAX); + ut_ad(*mbmaxlen < DATA_MBMAX); } else { THD* thd = current_thd; @@ -1254,7 +1256,7 @@ innobase_mysql_tmpfile(void) my_close(). */ #ifdef _WIN32 - /* Note that on Windows, the integer returned by mysql_tmpfile + /* Note that on Windows, the integer returned by mysql_tmpfile has no relation to C runtime file descriptor. Here, we need to call my_get_osfhandle to get the HANDLE and then convert it to C runtime filedescriptor. */ @@ -2444,6 +2446,7 @@ innobase_change_buffering_inited_ok: /* Get the current high water mark format. */ innobase_file_format_max = (char*) trx_sys_file_format_max_get(); + btr_search_fully_disabled = (!btr_search_enabled); DBUG_RETURN(FALSE); error: DBUG_RETURN(TRUE); @@ -2956,9 +2959,9 @@ innobase_close_connection( global_system_variables.log_warnings) { sql_print_warning( "MySQL is closing a connection that has an active " - "InnoDB transaction. %lu row modifications will " + "InnoDB transaction. %llu row modifications will " "roll back.", - (ulong) trx->undo_no.low); + (ullint) trx->undo_no); } innobase_rollback_trx(trx); @@ -4427,15 +4430,14 @@ ha_innobase::store_key_val_for_row( memcpy(buff, src_start, true_len); buff += true_len; - /* Pad the unused space with spaces. Note that no - padding is ever needed for UCS-2 because in MySQL, - all UCS2 characters are 2 bytes, as MySQL does not - support surrogate pairs, which are needed to represent - characters in the range U+10000 to U+10FFFF. */ + /* Pad the unused space with spaces. */ if (true_len < key_len) { - ulint pad_len = key_len - true_len; - memset(buff, ' ', pad_len); + ulint pad_len = key_len - true_len; + ut_a(!(pad_len % cs->mbminlen)); + + cs->cset->fill(cs, buff, pad_len, + 0x20 /* space */); buff += pad_len; } } @@ -4544,6 +4546,7 @@ build_template( /* Note that in InnoDB, i is the column number. MySQL calls columns 'fields'. */ for (i = 0; i < n_fields; i++) { + const dict_col_t* col = &index->table->cols[i]; templ = prebuilt->mysql_template + n_requested_fields; field = table->field[i]; @@ -4592,7 +4595,7 @@ include_field: if (index == clust_index) { templ->rec_field_no = dict_col_get_clust_pos( - &index->table->cols[i], index); + col, index); } else { templ->rec_field_no = dict_index_get_nth_col_pos( index, i); @@ -4621,7 +4624,7 @@ include_field: mysql_prefix_len = templ->mysql_col_offset + templ->mysql_col_len; } - templ->type = index->table->cols[i].mtype; + templ->type = col->mtype; templ->mysql_type = (ulint)field->type(); if (templ->mysql_type == DATA_MYSQL_TRUE_VARCHAR) { @@ -4629,12 +4632,10 @@ include_field: (((Field_varstring*)field)->length_bytes); } - templ->charset = dtype_get_charset_coll( - index->table->cols[i].prtype); - templ->mbminlen = index->table->cols[i].mbminlen; - templ->mbmaxlen = index->table->cols[i].mbmaxlen; - templ->is_unsigned = index->table->cols[i].prtype - & DATA_UNSIGNED; + templ->charset = dtype_get_charset_coll(col->prtype); + templ->mbminlen = dict_col_get_mbminlen(col); + templ->mbmaxlen = dict_col_get_mbmaxlen(col); + templ->is_unsigned = col->prtype & DATA_UNSIGNED; if (templ->type == DATA_BLOB) { prebuilt->templ_contains_blob = TRUE; } @@ -5562,6 +5563,9 @@ ha_innobase::index_read( prebuilt->index_usable = FALSE; DBUG_RETURN(HA_ERR_CRASHED); } + if (UNIV_UNLIKELY(!prebuilt->index_usable)) { + DBUG_RETURN(HA_ERR_TABLE_DEF_CHANGED); + } /* Note that if the index for which the search template is built is not necessarily prebuilt->index, but can also be the clustered index */ @@ -6655,6 +6659,7 @@ ha_innobase::create( const ulint file_format = srv_file_format; const char* stmt; size_t stmt_len; + enum row_type row_type; DBUG_ENTER("ha_innobase::create"); @@ -6775,94 +6780,94 @@ ha_innobase::create( } } - if (create_info->used_fields & HA_CREATE_USED_ROW_FORMAT) { - if (flags) { - /* KEY_BLOCK_SIZE was specified. */ - if (form->s->row_type != ROW_TYPE_COMPRESSED) { - /* ROW_FORMAT other than COMPRESSED - ignores KEY_BLOCK_SIZE. It does not - make sense to reject conflicting - KEY_BLOCK_SIZE and ROW_FORMAT, because - such combinations can be obtained - with ALTER TABLE anyway. */ - push_warning_printf( - thd, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: ignoring KEY_BLOCK_SIZE=%lu" - " unless ROW_FORMAT=COMPRESSED.", - create_info->key_block_size); - flags = 0; - } - } else { - /* No KEY_BLOCK_SIZE */ - if (form->s->row_type == ROW_TYPE_COMPRESSED) { - /* ROW_FORMAT=COMPRESSED without - KEY_BLOCK_SIZE implies half the - maximum KEY_BLOCK_SIZE. */ - flags = (DICT_TF_ZSSIZE_MAX - 1) - << DICT_TF_ZSSIZE_SHIFT - | DICT_TF_COMPACT - | DICT_TF_FORMAT_ZIP - << DICT_TF_FORMAT_SHIFT; + row_type = form->s->row_type; + + if (flags) { + /* KEY_BLOCK_SIZE was specified. */ + if (!(create_info->used_fields & HA_CREATE_USED_ROW_FORMAT)) { + /* ROW_FORMAT was not specified; + default to ROW_FORMAT=COMPRESSED */ + row_type = ROW_TYPE_COMPRESSED; + } else if (row_type != ROW_TYPE_COMPRESSED) { + /* ROW_FORMAT other than COMPRESSED + ignores KEY_BLOCK_SIZE. It does not + make sense to reject conflicting + KEY_BLOCK_SIZE and ROW_FORMAT, because + such combinations can be obtained + with ALTER TABLE anyway. */ + push_warning_printf( + thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: ignoring KEY_BLOCK_SIZE=%lu" + " unless ROW_FORMAT=COMPRESSED.", + create_info->key_block_size); + flags = 0; + } + } else { + /* No KEY_BLOCK_SIZE */ + if (row_type == ROW_TYPE_COMPRESSED) { + /* ROW_FORMAT=COMPRESSED without + KEY_BLOCK_SIZE implies half the + maximum KEY_BLOCK_SIZE. */ + flags = (DICT_TF_ZSSIZE_MAX - 1) + << DICT_TF_ZSSIZE_SHIFT + | DICT_TF_COMPACT + | DICT_TF_FORMAT_ZIP + << DICT_TF_FORMAT_SHIFT; #if DICT_TF_ZSSIZE_MAX < 1 # error "DICT_TF_ZSSIZE_MAX < 1" #endif - } } + } - switch (form->s->row_type) { - const char* row_format_name; - case ROW_TYPE_REDUNDANT: - break; - case ROW_TYPE_COMPRESSED: - case ROW_TYPE_DYNAMIC: - row_format_name - = form->s->row_type == ROW_TYPE_COMPRESSED - ? "COMPRESSED" - : "DYNAMIC"; - - if (!srv_file_per_table) { - push_warning_printf( - thd, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: ROW_FORMAT=%s" - " requires innodb_file_per_table.", - row_format_name); - } else if (file_format < DICT_TF_FORMAT_ZIP) { - push_warning_printf( - thd, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: ROW_FORMAT=%s" - " requires innodb_file_format >" - " Antelope.", - row_format_name); - } else { - flags |= DICT_TF_COMPACT - | (DICT_TF_FORMAT_ZIP - << DICT_TF_FORMAT_SHIFT); - break; - } + switch (row_type) { + const char* row_format_name; + case ROW_TYPE_REDUNDANT: + break; + case ROW_TYPE_COMPRESSED: + case ROW_TYPE_DYNAMIC: + row_format_name + = row_type == ROW_TYPE_COMPRESSED + ? "COMPRESSED" + : "DYNAMIC"; - /* fall through */ - case ROW_TYPE_NOT_USED: - case ROW_TYPE_FIXED: - default: - push_warning(thd, - MYSQL_ERROR::WARN_LEVEL_WARN, - ER_ILLEGAL_HA_CREATE_OPTION, - "InnoDB: assuming ROW_FORMAT=COMPACT."); - case ROW_TYPE_DEFAULT: - case ROW_TYPE_COMPACT: - flags = DICT_TF_COMPACT; + if (!srv_file_per_table) { + push_warning_printf( + thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: ROW_FORMAT=%s" + " requires innodb_file_per_table.", + row_format_name); + } else if (file_format < DICT_TF_FORMAT_ZIP) { + push_warning_printf( + thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: ROW_FORMAT=%s" + " requires innodb_file_format >" + " Antelope.", + row_format_name); + } else { + flags |= DICT_TF_COMPACT + | (DICT_TF_FORMAT_ZIP + << DICT_TF_FORMAT_SHIFT); break; } - } else if (!flags) { - /* No KEY_BLOCK_SIZE or ROW_FORMAT specified: - use ROW_FORMAT=COMPACT by default. */ + + /* fall through */ + case ROW_TYPE_NOT_USED: + case ROW_TYPE_FIXED: + default: + push_warning(thd, + MYSQL_ERROR::WARN_LEVEL_WARN, + ER_ILLEGAL_HA_CREATE_OPTION, + "InnoDB: assuming ROW_FORMAT=COMPACT."); + case ROW_TYPE_DEFAULT: + case ROW_TYPE_COMPACT: flags = DICT_TF_COMPACT; + break; } /* Look for a primary key */ @@ -7419,6 +7424,10 @@ ha_innobase::records_in_range( n_rows = HA_POS_ERROR; goto func_exit; } + if (UNIV_UNLIKELY(!row_merge_is_index_usable(prebuilt->trx, index))) { + n_rows = HA_ERR_TABLE_DEF_CHANGED; + goto func_exit; + } heap = mem_heap_create(2 * (key->key_parts * sizeof(dfield_t) + sizeof(dtuple_t))); @@ -10826,7 +10835,7 @@ by the server. Can be set during server startup at command line or configure file, and a read only variable after server startup */ static MYSQL_SYSVAR_BOOL(file_format_check, innobase_file_format_check, - PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, "Whether to perform system file format check.", NULL, NULL, TRUE); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index ec17882590c..3744d16570c 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -99,8 +99,10 @@ innobase_col_to_mysql( #ifdef UNIV_DEBUG case DATA_MYSQL: ut_ad(flen >= len); - ut_ad(col->mbmaxlen >= col->mbminlen); - ut_ad(col->mbmaxlen > col->mbminlen || flen == len); + ut_ad(DATA_MBMAXLEN(col->mbminmaxlen) + >= DATA_MBMINLEN(col->mbminmaxlen)); + ut_ad(DATA_MBMAXLEN(col->mbminmaxlen) + > DATA_MBMINLEN(col->mbminmaxlen) || flen == len); memcpy(dest, data, len); break; diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 2c15a3b87db..0733a558080 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -401,133 +401,7 @@ static ST_FIELD_INFO innodb_trx_fields_info[] = 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_name, "trx_adaptive_hash_latched"), STRUCT_FLD(field_length, 1), STRUCT_FLD(field_type, MYSQL_TYPE_LONG), STRUCT_FLD(value, 0), @@ -674,7 +548,7 @@ fill_innodb_trx_from_cache( OK(field_store_string(fields[IDX_TRX_LAST_FOREIGN_KEY_ERROR], row->trx_foreign_key_error)); - /* trx_apative_hash_latched */ + /* trx_adaptive_hash_latched */ OK(fields[IDX_TRX_ADAPTIVE_HASH_LATCHED]->store( row->trx_has_search_latch)); @@ -1973,16 +1847,13 @@ i_s_dict_fill_sys_tables( 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(fields[SYS_TABLE_ID]->store(longlong(table->id), TRUE)); OK(field_store_string(fields[SYS_TABLE_NAME], table->name)); @@ -2238,16 +2109,13 @@ i_s_dict_fill_sys_tablestats( 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(fields[SYS_TABLESTATS_ID]->store(longlong(table->id), TRUE)); OK(field_store_string(fields[SYS_TABLESTATS_NAME], table->name)); @@ -2495,27 +2363,22 @@ int i_s_dict_fill_sys_indexes( /*======================*/ THD* thd, /*!< in: thread */ - dulint tableid, /*!< in: table id */ + table_id_t table_id, /*!< 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(fields[SYS_INDEX_ID]->store(longlong(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_TABLE_ID]->store(longlong(table_id), TRUE)); OK(fields[SYS_INDEX_TYPE]->store(index->type)); @@ -2564,7 +2427,7 @@ i_s_sys_indexes_fill_table( /* Process each record in the table */ while (rec) { const char* err_msg;; - dulint table_id; + table_id_t table_id; dict_index_t index_rec; /* Populate a dict_index_t structure with information from @@ -2737,22 +2600,19 @@ int i_s_dict_fill_sys_columns( /*======================*/ THD* thd, /*!< in: thread */ - dulint tableid, /*!< in: table ID */ + table_id_t table_id, /*!< 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(fields[SYS_COLUMN_TABLE_ID]->store(longlong(table_id), TRUE)); OK(field_store_string(fields[SYS_COLUMN_NAME], col_name)); @@ -2803,7 +2663,7 @@ i_s_sys_columns_fill_table( while (rec) { const char* err_msg; dict_col_t column_rec; - dulint table_id; + table_id_t table_id; /* populate a dict_col_t structure with information from a SYS_COLUMNS row */ @@ -2948,21 +2808,18 @@ int i_s_dict_fill_sys_fields( /*=====================*/ THD* thd, /*!< in: thread */ - dulint indexid, /*!< in: index id for the field */ + index_id_t index_id, /*!< 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(fields[SYS_FIELD_INDEX_ID]->store(longlong(index_id), TRUE)); OK(field_store_string(fields[SYS_FIELD_NAME], field->name)); @@ -2988,7 +2845,7 @@ i_s_sys_fields_fill_table( btr_pcur_t pcur; const rec_t* rec; mem_heap_t* heap; - dulint last_id; + index_id_t last_id; mtr_t mtr; DBUG_ENTER("i_s_sys_fields_fill_table"); @@ -3005,14 +2862,14 @@ i_s_sys_fields_fill_table( /* 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); + last_id = 0; rec = dict_startscan_system(&pcur, &mtr, SYS_FIELDS); while (rec) { ulint pos; const char* err_msg; - dulint index_id; + index_id_t index_id; dict_field_t field_rec; /* Populate a dict_field_t structure with information from diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c index 0397af88ff4..dc8e61e5070 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.c +++ b/storage/innobase/ibuf/ibuf0ibuf.c @@ -565,7 +565,7 @@ ibuf_init_at_db_start(void) dict_mem_table_add_col(table, heap, "DUMMY_COLUMN", DATA_BINARY, 0, 0); - table->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID); + table->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID; dict_table_add_to_cache(table, heap); mem_heap_free(heap); @@ -576,7 +576,7 @@ ibuf_init_at_db_start(void) dict_mem_index_add_field(index, "DUMMY_COLUMN", 0); - index->id = ut_dulint_add(DICT_IBUF_ID_MIN, IBUF_SPACE_ID); + index->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID; error = dict_index_add_to_cache(table, index, FSP_IBUF_TREE_ROOT_PAGE_NO, FALSE); diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index cc08cc620c5..3912f315f2a 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -130,7 +130,7 @@ btr_page_get( Gets the index id field of a page. @return index id */ UNIV_INLINE -dulint +index_id_t btr_page_get_index_id( /*==================*/ const page_t* page); /*!< in: index page */ @@ -226,7 +226,7 @@ btr_create( ulint space, /*!< in: space where created */ ulint zip_size,/*!< in: compressed page size in bytes or 0 for uncompressed pages */ - dulint index_id,/*!< in: index id */ + index_id_t index_id,/*!< in: index id */ dict_index_t* index, /*!< in: index */ mtr_t* mtr); /*!< in: mini-transaction handle */ /************************************************************//** diff --git a/storage/innobase/include/btr0btr.ic b/storage/innobase/include/btr0btr.ic index 97944cc2e26..6c580a0bd6e 100644 --- a/storage/innobase/include/btr0btr.ic +++ b/storage/innobase/include/btr0btr.ic @@ -86,7 +86,7 @@ btr_page_set_index_id( page_t* page, /*!< in: page to be created */ page_zip_des_t* page_zip,/*!< in: compressed page whose uncompressed part will be updated, or NULL */ - dulint id, /*!< in: index id */ + index_id_t id, /*!< in: index id */ mtr_t* mtr) /*!< in: mtr */ { if (UNIV_LIKELY_NULL(page_zip)) { @@ -95,8 +95,7 @@ btr_page_set_index_id( page + (PAGE_HEADER + PAGE_INDEX_ID), 8, mtr); } else { - mlog_write_dulint(page + (PAGE_HEADER + PAGE_INDEX_ID), - id, mtr); + mlog_write_ull(page + (PAGE_HEADER + PAGE_INDEX_ID), id, mtr); } } #endif /* !UNIV_HOTBACKUP */ @@ -105,7 +104,7 @@ btr_page_set_index_id( Gets the index id field of a page. @return index id */ UNIV_INLINE -dulint +index_id_t btr_page_get_index_id( /*==================*/ const page_t* page) /*!< in: index page */ diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h index 136d2d068a1..757477838ee 100644 --- a/storage/innobase/include/btr0cur.h +++ b/storage/innobase/include/btr0cur.h @@ -558,7 +558,7 @@ btr_copy_externally_stored_field_prefix( ulint local_len);/*!< in: length of data, in bytes */ /*******************************************************************//** Copies an externally stored field of a record to mem heap. -@return the field copied to heap */ +@return the field copied to heap, or NULL if the field is incomplete */ UNIV_INTERN byte* btr_rec_copy_externally_stored_field( diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h index f98ba386f9c..20a2be7f877 100644 --- a/storage/innobase/include/btr0sea.h +++ b/storage/innobase/include/btr0sea.h @@ -190,7 +190,13 @@ btr_search_validate(void); /** Flag: has the search system been enabled? Protected by btr_search_latch and btr_search_enabled_mutex. */ -extern char btr_search_enabled; +extern char btr_search_enabled; + +/** Flag: whether the search system has completed its disabling process, +It is set to TRUE right after buf_pool_drop_hash_index() in +btr_search_disable(), indicating hash index entries are cleaned up. +Protected by btr_search_latch and btr_search_enabled_mutex. */ +extern ibool btr_search_fully_disabled; /** The search info struct in an index */ struct btr_search_struct{ diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 5326ca9c14f..f33ef65ddf2 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -869,7 +869,8 @@ buf_page_set_accessed( __attribute__((nonnull)); /*********************************************************************//** Gets the buf_block_t handle of a buffered file block if an uncompressed -page frame exists, or NULL. +page frame exists, or NULL. Note: even though bpage is not declared a +const we don't update its value. It is safe to make this pure. @return control block, or NULL */ UNIV_INLINE buf_block_t* diff --git a/storage/innobase/include/data0data.h b/storage/innobase/include/data0data.h index f9fce3f3657..11e4027777a 100644 --- a/storage/innobase/include/data0data.h +++ b/storage/innobase/include/data0data.h @@ -309,7 +309,7 @@ dtuple_fold( ulint n_fields,/*!< in: number of complete fields to fold */ ulint n_bytes,/*!< in: number of bytes to fold in an incomplete last field */ - dulint tree_id)/*!< in: index tree id */ + index_id_t tree_id)/*!< in: index tree id */ __attribute__((pure)); /*******************************************************************//** Sets types of fields binary in a tuple. */ diff --git a/storage/innobase/include/data0data.ic b/storage/innobase/include/data0data.ic index da79aa33702..2e3adf4b707 100644 --- a/storage/innobase/include/data0data.ic +++ b/storage/innobase/include/data0data.ic @@ -518,7 +518,7 @@ dtuple_fold( ulint n_fields,/*!< in: number of complete fields to fold */ ulint n_bytes,/*!< in: number of bytes to fold in an incomplete last field */ - dulint tree_id)/*!< in: index tree id */ + index_id_t tree_id)/*!< in: index tree id */ { const dfield_t* field; ulint i; @@ -530,7 +530,7 @@ dtuple_fold( ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N); ut_ad(dtuple_check_typed(tuple)); - fold = ut_fold_dulint(tree_id); + fold = ut_fold_ull(tree_id); for (i = 0; i < n_fields; i++) { field = dtuple_get_nth_field(tuple, i); diff --git a/storage/innobase/include/data0type.h b/storage/innobase/include/data0type.h index a73bed3a9f5..850cf2e2975 100644 --- a/storage/innobase/include/data0type.h +++ b/storage/innobase/include/data0type.h @@ -128,7 +128,7 @@ columns, and for them the precise type is usually not used at all. /* Precise data types for system columns and the length of those columns; NOTE: the values must run from 0 up in the order given! All codes must be less than 256 */ -#define DATA_ROW_ID 0 /* row id: a dulint */ +#define DATA_ROW_ID 0 /* row id: a 48-bit integer */ #define DATA_ROW_ID_LEN 6 /* stored length for row id */ #define DATA_TRX_ID 1 /* transaction id: 6 bytes */ @@ -168,6 +168,17 @@ SQL null*/ store the charset-collation number; one byte is left unused, though */ #define DATA_NEW_ORDER_NULL_TYPE_BUF_SIZE 6 +/* Maximum multi-byte character length in bytes, plus 1 */ +#define DATA_MBMAX 5 + +/* Pack mbminlen, mbmaxlen to mbminmaxlen. */ +#define DATA_MBMINMAXLEN(mbminlen, mbmaxlen) \ + ((mbmaxlen) * DATA_MBMAX + (mbminlen)) +/* Get mbminlen from mbminmaxlen. */ +#define DATA_MBMINLEN(mbminmaxlen) UNIV_EXPECT(((mbminmaxlen) % DATA_MBMAX), 1) +/* Get mbmaxlen from mbminmaxlen. */ +#define DATA_MBMAXLEN(mbminmaxlen) ((mbminmaxlen) / DATA_MBMAX) + #ifndef UNIV_HOTBACKUP /*********************************************************************//** Gets the MySQL type code from a dtype. @@ -187,10 +198,8 @@ ulint dtype_get_at_most_n_mbchars( /*========================*/ ulint prtype, /*!< in: precise type */ - ulint mbminlen, /*!< in: minimum length of a - multi-byte character */ - ulint mbmaxlen, /*!< in: maximum length of a - multi-byte character */ + ulint mbminmaxlen, /*!< in: minimum and maximum length of + a multi-byte character */ ulint prefix_len, /*!< in: length of the requested prefix, in characters, multiplied by dtype_get_mbmaxlen(dtype) */ @@ -335,6 +344,19 @@ dtype_get_mbmaxlen( /*===============*/ const dtype_t* type); /*!< in: type */ /*********************************************************************//** +Sets the minimum and maximum length of a character, in bytes. */ +UNIV_INLINE +void +dtype_set_mbminmaxlen( +/*==================*/ + dtype_t* type, /*!< in/out: type */ + ulint mbminlen, /*!< in: minimum length of a char, + in bytes, or 0 if this is not + a character type */ + ulint mbmaxlen); /*!< in: maximum length of a char, + in bytes, or 0 if this is not + a character type */ +/*********************************************************************//** Gets the padding character code for the type. @return padding character code, or ULINT_UNDEFINED if no padding specified */ UNIV_INLINE @@ -354,8 +376,8 @@ dtype_get_fixed_size_low( ulint mtype, /*!< in: main type */ ulint prtype, /*!< in: precise type */ ulint len, /*!< in: length */ - ulint mbminlen, /*!< in: minimum length of a multibyte char */ - ulint mbmaxlen, /*!< in: maximum length of a multibyte char */ + ulint mbminmaxlen, /*!< in: minimum and maximum length of a + multibyte character, in bytes */ ulint comp); /*!< in: nonzero=ROW_FORMAT=COMPACT */ #ifndef UNIV_HOTBACKUP /***********************************************************************//** @@ -368,8 +390,8 @@ dtype_get_min_size_low( ulint mtype, /*!< in: main type */ ulint prtype, /*!< in: precise type */ ulint len, /*!< in: length */ - ulint mbminlen, /*!< in: minimum length of a multibyte char */ - ulint mbmaxlen); /*!< in: maximum length of a multibyte char */ + ulint mbminmaxlen); /*!< in: minimum and maximum length of a + multibyte character */ /***********************************************************************//** Returns the maximum size of a data type. Note: types in system tables may be incomplete and return incorrect information. @@ -472,10 +494,11 @@ struct dtype_struct{ the string, MySQL uses 1 or 2 bytes to store the string length) */ #ifndef UNIV_HOTBACKUP - unsigned mbminlen:2; /*!< minimum length of a - character, in bytes */ - unsigned mbmaxlen:3; /*!< maximum length of a - character, in bytes */ + unsigned mbminmaxlen:5; /*!< minimum and maximum length of a + character, in bytes; + DATA_MBMINMAXLEN(mbminlen,mbmaxlen); + mbminlen=DATA_MBMINLEN(mbminmaxlen); + mbmaxlen=DATA_MBMINLEN(mbminmaxlen) */ #endif /* !UNIV_HOTBACKUP */ }; diff --git a/storage/innobase/include/data0type.ic b/storage/innobase/include/data0type.ic index 2bf67a941bd..757dd815c5e 100644 --- a/storage/innobase/include/data0type.ic +++ b/storage/innobase/include/data0type.ic @@ -93,14 +93,35 @@ dtype_get_mblen( innobase_get_cset_width(dtype_get_charset_coll(prtype), mbminlen, mbmaxlen); ut_ad(*mbminlen <= *mbmaxlen); - ut_ad(*mbminlen <= 2); /* mbminlen in dtype_t is 0..3 */ - ut_ad(*mbmaxlen < 1 << 3); /* mbmaxlen in dtype_t is 0..7 */ + ut_ad(*mbminlen < DATA_MBMAX); + ut_ad(*mbmaxlen < DATA_MBMAX); } else { *mbminlen = *mbmaxlen = 0; } } /*********************************************************************//** +Sets the minimum and maximum length of a character, in bytes. */ +UNIV_INLINE +void +dtype_set_mbminmaxlen( +/*==================*/ + dtype_t* type, /*!< in/out: type */ + ulint mbminlen, /*!< in: minimum length of a char, + in bytes, or 0 if this is not + a character type */ + ulint mbmaxlen) /*!< in: maximum length of a char, + in bytes, or 0 if this is not + a character type */ +{ + ut_ad(mbminlen < DATA_MBMAX); + ut_ad(mbmaxlen < DATA_MBMAX); + ut_ad(mbminlen <= mbmaxlen); + + type->mbminmaxlen = DATA_MBMINMAXLEN(mbminlen, mbmaxlen); +} + +/*********************************************************************//** Compute the mbminlen and mbmaxlen members of a data type structure. */ UNIV_INLINE void @@ -112,8 +133,7 @@ dtype_set_mblen( ulint mbmaxlen; dtype_get_mblen(type->mtype, type->prtype, &mbminlen, &mbmaxlen); - type->mbminlen = mbminlen; - type->mbmaxlen = mbmaxlen; + dtype_set_mbminmaxlen(type, mbminlen, mbmaxlen); ut_ad(dtype_validate(type)); } @@ -210,7 +230,7 @@ dtype_get_mbminlen( const dtype_t* type) /*!< in: type */ { ut_ad(type); - return(type->mbminlen); + return(DATA_MBMINLEN(type->mbminmaxlen)); } /*********************************************************************//** Gets the maximum length of a character, in bytes. @@ -223,7 +243,7 @@ dtype_get_mbmaxlen( const dtype_t* type) /*!< in: type */ { ut_ad(type); - return(type->mbmaxlen); + return(DATA_MBMAXLEN(type->mbminmaxlen)); } /*********************************************************************//** @@ -404,8 +424,8 @@ dtype_get_fixed_size_low( ulint mtype, /*!< in: main type */ ulint prtype, /*!< in: precise type */ ulint len, /*!< in: length */ - ulint mbminlen, /*!< in: minimum length of a multibyte char */ - ulint mbmaxlen, /*!< in: maximum length of a multibyte char */ + ulint mbminmaxlen, /*!< in: minimum and maximum length of + a multibyte character, in bytes */ ulint comp) /*!< in: nonzero=ROW_FORMAT=COMPACT */ { switch (mtype) { @@ -453,8 +473,9 @@ dtype_get_fixed_size_low( dtype_get_charset_coll(prtype), &i_mbminlen, &i_mbmaxlen); - if (UNIV_UNLIKELY(mbminlen != i_mbminlen) - || UNIV_UNLIKELY(mbmaxlen != i_mbmaxlen)) { + if (UNIV_UNLIKELY + (DATA_MBMINMAXLEN(i_mbminlen, i_mbmaxlen) + != mbminmaxlen)) { ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: " @@ -464,10 +485,10 @@ dtype_get_fixed_size_low( "type->mbmaxlen=%lu\n", (ulong) i_mbminlen, (ulong) i_mbmaxlen, - (ulong) mbminlen, - (ulong) mbmaxlen); + (ulong) DATA_MBMINLEN(mbminmaxlen), + (ulong) DATA_MBMAXLEN(mbminmaxlen)); } - if (mbminlen == mbmaxlen) { + if (i_mbminlen == i_mbmaxlen) { return(len); } } @@ -499,8 +520,8 @@ dtype_get_min_size_low( ulint mtype, /*!< in: main type */ ulint prtype, /*!< in: precise type */ ulint len, /*!< in: length */ - ulint mbminlen, /*!< in: minimum length of a multibyte char */ - ulint mbmaxlen) /*!< in: maximum length of a multibyte char */ + ulint mbminmaxlen) /*!< in: minimum and maximum length of a + multi-byte character */ { switch (mtype) { case DATA_SYS: @@ -527,14 +548,22 @@ dtype_get_min_size_low( case DATA_DOUBLE: return(len); case DATA_MYSQL: - if ((prtype & DATA_BINARY_TYPE) || mbminlen == mbmaxlen) { + if (prtype & DATA_BINARY_TYPE) { return(len); + } else { + ulint mbminlen = DATA_MBMINLEN(mbminmaxlen); + ulint mbmaxlen = DATA_MBMAXLEN(mbminmaxlen); + + if (mbminlen == mbmaxlen) { + return(len); + } + + /* this is a variable-length character set */ + ut_a(mbminlen > 0); + ut_a(mbmaxlen > mbminlen); + ut_a(len % mbmaxlen == 0); + return(len * mbminlen / mbmaxlen); } - /* this is a variable-length character set */ - ut_a(mbminlen > 0); - ut_a(mbmaxlen > mbminlen); - ut_a(len % mbmaxlen == 0); - return(len * mbminlen / mbmaxlen); case DATA_VARCHAR: case DATA_BINARY: case DATA_DECIMAL: @@ -595,9 +624,9 @@ dtype_get_sql_null_size( { #ifndef UNIV_HOTBACKUP return(dtype_get_fixed_size_low(type->mtype, type->prtype, type->len, - type->mbminlen, type->mbmaxlen, comp)); + type->mbminmaxlen, comp)); #else /* !UNIV_HOTBACKUP */ return(dtype_get_fixed_size_low(type->mtype, type->prtype, type->len, - 0, 0, 0)); + 0, 0)); #endif /* !UNIV_HOTBACKUP */ } diff --git a/storage/innobase/include/dict0boot.h b/storage/innobase/include/dict0boot.h index 148b5cbe250..22df826da65 100644 --- a/storage/innobase/include/dict0boot.h +++ b/storage/innobase/include/dict0boot.h @@ -51,32 +51,35 @@ UNIV_INTERN void dict_hdr_get_new_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) */ + table_id_t* table_id, /*!< out: table id + (not assigned if NULL) */ + index_id_t* 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 */ UNIV_INLINE -dulint +row_id_t dict_sys_get_new_row_id(void); /*=========================*/ /**********************************************************************//** Reads a row id from a record or other 6-byte stored form. @return row id */ UNIV_INLINE -dulint +row_id_t dict_sys_read_row_id( /*=================*/ - byte* field); /*!< in: record field */ + const byte* field); /*!< in: record field */ /**********************************************************************//** Writes a row id to a record or other 6-byte stored form. */ UNIV_INLINE void dict_sys_write_row_id( /*==================*/ - byte* field, /*!< in: record field */ - dulint row_id);/*!< in: row id */ + byte* field, /*!< in: record field */ + row_id_t row_id);/*!< in: row id */ /*****************************************************************//** Initializes the data dictionary memory structures when the database is started. This function is also called when the data dictionary is created. */ @@ -97,12 +100,12 @@ dict_create(void); #define DICT_HDR_PAGE_NO FSP_DICT_HDR_PAGE_NO /* The ids for the basic system tables and their indexes */ -#define DICT_TABLES_ID ut_dulint_create(0, 1) -#define DICT_COLUMNS_ID ut_dulint_create(0, 2) -#define DICT_INDEXES_ID ut_dulint_create(0, 3) -#define DICT_FIELDS_ID ut_dulint_create(0, 4) +#define DICT_TABLES_ID 1 +#define DICT_COLUMNS_ID 2 +#define DICT_INDEXES_ID 3 +#define DICT_FIELDS_ID 4 /* The following is a secondary index on SYS_TABLES */ -#define DICT_TABLE_IDS_ID ut_dulint_create(0, 5) +#define DICT_TABLE_IDS_ID 5 #define DICT_HDR_FIRST_ID 10 /* the ids for tables etc. start from this number, except for basic @@ -110,7 +113,7 @@ dict_create(void); indexes; ibuf tables and indexes are assigned as the id the number DICT_IBUF_ID_MIN plus the space id */ -#define DICT_IBUF_ID_MIN ut_dulint_create(0xFFFFFFFFUL, 0) +#define DICT_IBUF_ID_MIN 0xFFFFFFFF00000000ULL /* The offset of the dictionary header on the page */ #define DICT_HDR FSEG_PAGE_DATA diff --git a/storage/innobase/include/dict0boot.ic b/storage/innobase/include/dict0boot.ic index d5f372e38c4..d3ba9eee78f 100644 --- a/storage/innobase/include/dict0boot.ic +++ b/storage/innobase/include/dict0boot.ic @@ -36,22 +36,22 @@ dict_hdr_flush_row_id(void); Returns a new row id. @return the new id */ UNIV_INLINE -dulint +row_id_t dict_sys_get_new_row_id(void) /*=========================*/ { - dulint id; + row_id_t id; mutex_enter(&(dict_sys->mutex)); id = dict_sys->row_id; - if (0 == (ut_dulint_get_low(id) % DICT_HDR_ROW_ID_WRITE_MARGIN)) { + if (0 == (id % DICT_HDR_ROW_ID_WRITE_MARGIN)) { dict_hdr_flush_row_id(); } - UT_DULINT_INC(dict_sys->row_id); + dict_sys->row_id++; mutex_exit(&(dict_sys->mutex)); @@ -62,10 +62,10 @@ dict_sys_get_new_row_id(void) Reads a row id from a record or other 6-byte stored form. @return row id */ UNIV_INLINE -dulint +row_id_t dict_sys_read_row_id( /*=================*/ - byte* field) /*!< in: record field */ + const byte* field) /*!< in: record field */ { #if DATA_ROW_ID_LEN != 6 # error "DATA_ROW_ID_LEN != 6" @@ -80,8 +80,8 @@ UNIV_INLINE void dict_sys_write_row_id( /*==================*/ - byte* field, /*!< in: record field */ - dulint row_id) /*!< in: row id */ + byte* field, /*!< in: record field */ + row_id_t row_id) /*!< in: row id */ { #if DATA_ROW_ID_LEN != 6 # error "DATA_ROW_ID_LEN != 6" diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 3a1bee4cd89..971173a65a5 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -75,8 +75,8 @@ UNIV_INTERN dict_table_t* dict_table_get_on_id( /*=================*/ - dulint table_id, /*!< in: table id */ - trx_t* trx); /*!< in: transaction handle */ + table_id_t table_id, /*!< in: table id */ + trx_t* trx); /*!< in: transaction handle */ /********************************************************************//** Decrements the count of open MySQL handles to a table. */ UNIV_INTERN @@ -102,6 +102,33 @@ void dict_load_space_id_list(void); /*=========================*/ /*********************************************************************//** +Gets the minimum number of bytes per character. +@return minimum multi-byte char size, in bytes */ +UNIV_INLINE +ulint +dict_col_get_mbminlen( +/*==================*/ + const dict_col_t* col); /*!< in: column */ +/*********************************************************************//** +Gets the maximum number of bytes per character. +@return maximum multi-byte char size, in bytes */ +UNIV_INLINE +ulint +dict_col_get_mbmaxlen( +/*==================*/ + const dict_col_t* col); /*!< in: column */ +/*********************************************************************//** +Sets the minimum and maximum number of bytes per character. */ +UNIV_INLINE +void +dict_col_set_mbminmaxlen( +/*=====================*/ + dict_col_t* col, /*!< in/out: column */ + ulint mbminlen, /*!< in: minimum multi-byte + character size, in bytes */ + ulint mbmaxlen); /*!< in: minimum multi-byte + character size, in bytes */ +/*********************************************************************//** Gets the column data type. */ UNIV_INLINE void @@ -277,7 +304,7 @@ void dict_table_change_id_in_cache( /*==========================*/ dict_table_t* table, /*!< in/out: table object already in cache */ - dulint new_id);/*!< in: new id to set */ + table_id_t new_id);/*!< in: new id to set */ /**********************************************************************//** Adds a foreign key constraint object to the dictionary cache. May free the object if there already is an object with the same identifier in. @@ -397,7 +424,7 @@ dict_index_t* dict_index_get_on_id_low( /*=====================*/ dict_table_t* table, /*!< in: table */ - dulint index_id); /*!< in: index id */ + index_id_t index_id); /*!< in: index id */ /**********************************************************************//** Checks if a table is in the dictionary cache. @return table, NULL if not found */ @@ -423,7 +450,7 @@ UNIV_INLINE dict_table_t* dict_table_get_on_id_low( /*=====================*/ - dulint table_id); /*!< in: table id */ + table_id_t table_id); /*!< in: table id */ /**********************************************************************//** Find an index that is equivalent to the one passed in and is not marked for deletion. @@ -710,7 +737,7 @@ UNIV_INTERN dict_index_t* dict_index_find_on_id_low( /*======================*/ - dulint id); /*!< in: index id */ + index_id_t id); /*!< in: index id */ /**********************************************************************//** Adds an index to the dictionary cache. @return DB_SUCCESS, DB_TOO_BIG_RECORD, or DB_CORRUPTION */ @@ -901,7 +928,7 @@ UNIV_INTERN dict_index_t* dict_index_get_if_in_cache_low( /*===========================*/ - dulint index_id); /*!< in: index id */ + index_id_t index_id); /*!< in: index id */ #if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG /**********************************************************************//** Returns an index object if it is found in the dictionary cache. @@ -910,7 +937,7 @@ UNIV_INTERN dict_index_t* dict_index_get_if_in_cache( /*=======================*/ - dulint index_id); /*!< in: index id */ + index_id_t index_id); /*!< in: index id */ #endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */ #ifdef UNIV_DEBUG /**********************************************************************//** @@ -1135,7 +1162,7 @@ struct dict_sys_struct{ and DROP TABLE, as well as reading the dictionary data for a table from system tables */ - dulint row_id; /*!< the next row id to assign; + row_id_t row_id; /*!< the next row id to assign; NOTE that at a checkpoint this must be written to the dict system header and flushed to a file; in diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index 93c3f8d4733..09f967aa74a 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -29,6 +29,46 @@ Created 1/8/1996 Heikki Tuuri #include "rem0types.h" /*********************************************************************//** +Gets the minimum number of bytes per character. +@return minimum multi-byte char size, in bytes */ +UNIV_INLINE +ulint +dict_col_get_mbminlen( +/*==================*/ + const dict_col_t* col) /*!< in: column */ +{ + return(DATA_MBMINLEN(col->mbminmaxlen)); +} +/*********************************************************************//** +Gets the maximum number of bytes per character. +@return maximum multi-byte char size, in bytes */ +UNIV_INLINE +ulint +dict_col_get_mbmaxlen( +/*==================*/ + const dict_col_t* col) /*!< in: column */ +{ + return(DATA_MBMAXLEN(col->mbminmaxlen)); +} +/*********************************************************************//** +Sets the minimum and maximum number of bytes per character. */ +UNIV_INLINE +void +dict_col_set_mbminmaxlen( +/*=====================*/ + dict_col_t* col, /*!< in/out: column */ + ulint mbminlen, /*!< in: minimum multi-byte + character size, in bytes */ + ulint mbmaxlen) /*!< in: minimum multi-byte + character size, in bytes */ +{ + ut_ad(mbminlen < DATA_MBMAX); + ut_ad(mbmaxlen < DATA_MBMAX); + ut_ad(mbminlen <= mbmaxlen); + + col->mbminmaxlen = DATA_MBMINMAXLEN(mbminlen, mbmaxlen); +} +/*********************************************************************//** Gets the column data type. */ UNIV_INLINE void @@ -42,8 +82,7 @@ dict_col_copy_type( type->mtype = col->mtype; type->prtype = col->prtype; type->len = col->len; - type->mbminlen = col->mbminlen; - type->mbmaxlen = col->mbmaxlen; + type->mbminmaxlen = col->mbminmaxlen; } #endif /* !UNIV_HOTBACKUP */ @@ -65,8 +104,7 @@ dict_col_type_assert_equal( ut_ad(col->prtype == type->prtype); ut_ad(col->len == type->len); # ifndef UNIV_HOTBACKUP - ut_ad(col->mbminlen == type->mbminlen); - ut_ad(col->mbmaxlen == type->mbmaxlen); + ut_ad(col->mbminmaxlen == type->mbminmaxlen); # endif /* !UNIV_HOTBACKUP */ return(TRUE); @@ -84,7 +122,7 @@ dict_col_get_min_size( const dict_col_t* col) /*!< in: column */ { return(dtype_get_min_size_low(col->mtype, col->prtype, col->len, - col->mbminlen, col->mbmaxlen)); + col->mbminmaxlen)); } /***********************************************************************//** Returns the maximum size of the column. @@ -109,7 +147,7 @@ dict_col_get_fixed_size( ulint comp) /*!< in: nonzero=ROW_FORMAT=COMPACT */ { return(dtype_get_fixed_size_low(col->mtype, col->prtype, col->len, - col->mbminlen, col->mbmaxlen, comp)); + col->mbminmaxlen, comp)); } /***********************************************************************//** Returns the ROW_FORMAT=REDUNDANT stored SQL NULL size of a column. @@ -780,7 +818,7 @@ UNIV_INLINE dict_table_t* dict_table_get_on_id_low( /*=====================*/ - dulint table_id) /*!< in: table id */ + table_id_t table_id) /*!< in: table id */ { dict_table_t* table; ulint fold; @@ -788,11 +826,11 @@ dict_table_get_on_id_low( ut_ad(mutex_own(&(dict_sys->mutex))); /* Look for the table name in the hash table */ - fold = ut_fold_dulint(table_id); + fold = ut_fold_ull(table_id); HASH_SEARCH(id_hash, dict_sys->table_id_hash, fold, dict_table_t*, table, ut_ad(table->cached), - !ut_dulint_cmp(table->id, table_id)); + table->id == table_id); if (table == NULL) { table = dict_load_table_on_id(table_id); } diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h index d85f8f7fc3e..6a718a464ab 100644 --- a/storage/innobase/include/dict0load.h +++ b/storage/innobase/include/dict0load.h @@ -109,8 +109,9 @@ dict_load_column_low( 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 */ + dict_col_t* column, /*!< out: dict_column_t to fill, + or NULL if table != NULL */ + table_id_t* table_id, /*!< out: table id */ const char** col_name, /*!< out: column name */ const rec_t* rec); /*!< in: SYS_COLUMNS record */ /********************************************************************//** @@ -173,7 +174,7 @@ UNIV_INTERN dict_table_t* dict_load_table_on_id( /*==================*/ - dulint table_id); /*!< in: table id */ + table_id_t table_id); /*!< in: table id */ /********************************************************************//** This function is called when the database is booted. Loads system table index definitions except for the clustered index which @@ -255,7 +256,7 @@ dict_process_sys_indexes_rec( 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 */ + table_id_t* 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. @@ -267,7 +268,7 @@ 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 */ + table_id_t* 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 @@ -282,8 +283,8 @@ dict_process_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 */ + index_id_t* index_id, /*!< out: current index id */ + index_id_t 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 diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 57e5b5394ee..75f9acd6b26 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -151,9 +151,9 @@ dict_mem_table_add_col( ulint prtype, /*!< in: precise type */ ulint len); /*!< in: precision */ /**********************************************************************//** -This function poplulates a dict_col_t memory structure with +This function populates a dict_col_t memory structure with supplied information. */ -UNIV_INLINE +UNIV_INTERN void dict_mem_fill_column_struct( /*========================*/ @@ -162,7 +162,7 @@ dict_mem_fill_column_struct( ulint col_pos, /*!< in: column position */ ulint mtype, /*!< in: main data type */ ulint prtype, /*!< in: precise type */ - ulint col_len); /*!< in: column lenght */ + ulint col_len); /*!< in: column length */ /**********************************************************************//** This function poplulates a dict_index_t index memory structure with supplied information. */ @@ -249,10 +249,11 @@ struct dict_col_struct{ the string, MySQL uses 1 or 2 bytes to store the string length) */ - unsigned mbminlen:2; /*!< minimum length of a - character, in bytes */ - unsigned mbmaxlen:3; /*!< maximum length of a - character, in bytes */ + unsigned mbminmaxlen:5; /*!< minimum and maximum length of a + character, in bytes; + DATA_MBMINMAXLEN(mbminlen,mbmaxlen); + mbminlen=DATA_MBMINLEN(mbminmaxlen); + mbmaxlen=DATA_MBMINLEN(mbminmaxlen) */ /*----------------------*/ /* End of definitions copied from dtype_t */ /* @} */ @@ -293,7 +294,7 @@ struct dict_field_struct{ /** Data structure for an index. Most fields will be initialized to 0, NULL or FALSE in dict_mem_index_create(). */ struct dict_index_struct{ - dulint id; /*!< id of the index */ + index_id_t id; /*!< id of the index */ mem_heap_t* heap; /*!< memory heap */ const char* name; /*!< index name */ const char* table_name;/*!< table name */ @@ -349,7 +350,7 @@ struct dict_index_struct{ /* @} */ rw_lock_t lock; /*!< read-write lock protecting the upper levels of the index tree */ - ib_uint64_t trx_id; /*!< id of the transaction that created this + trx_id_t trx_id; /*!< id of the transaction that created this index, or 0 if the index existed when InnoDB was started up */ #endif /* !UNIV_HOTBACKUP */ @@ -414,9 +415,9 @@ a foreign key constraint is enforced, therefore RESTRICT just means no flag */ /** Data structure for a database table. Most fields will be initialized to 0, NULL or FALSE in dict_mem_table_create(). */ struct dict_table_struct{ - dulint id; /*!< id of the table */ + table_id_t id; /*!< id of the table */ mem_heap_t* heap; /*!< memory heap */ - const char* name; /*!< table name */ + char* name; /*!< table name */ const char* dir_path_of_temp_table;/*!< NULL or the directory path where a TEMPORARY table that was explicitly created by a user should be placed if diff --git a/storage/innobase/include/dict0mem.ic b/storage/innobase/include/dict0mem.ic index 5a851da5640..1d80ffc9b94 100644 --- a/storage/innobase/include/dict0mem.ic +++ b/storage/innobase/include/dict0mem.ic @@ -70,35 +70,3 @@ dict_mem_fill_index_struct( 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/dict0types.h b/storage/innobase/include/dict0types.h index 7ad69193cc9..0a9edfbfe70 100644 --- a/storage/innobase/include/dict0types.h +++ b/storage/innobase/include/dict0types.h @@ -45,4 +45,7 @@ typedef struct tab_node_struct tab_node_t; #define DICT_HDR_SPACE 0 /* the SYSTEM tablespace */ #define DICT_HDR_PAGE_NO FSP_DICT_HDR_PAGE_NO +typedef ib_id_t table_id_t; +typedef ib_id_t index_id_t; + #endif diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index c746915844b..d7d98787bcf 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -26,6 +26,7 @@ Created 10/25/1995 Heikki Tuuri #ifndef fil0fil_h #define fil0fil_h +#include "univ.i" #include "dict0types.h" #include "ut0byte.h" #include "os0file.h" diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index 0319c0e9261..3eca80beda4 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -670,7 +670,7 @@ lock_get_type( Gets the id of the transaction owning a lock. @return transaction id */ UNIV_INTERN -ullint +trx_id_t lock_get_trx_id( /*============*/ const lock_t* lock); /*!< in: lock */ @@ -699,7 +699,7 @@ lock_get_type_str( Gets the id of the table on which the lock is. @return id of the table */ UNIV_INTERN -ullint +table_id_t lock_get_table_id( /*==============*/ const lock_t* lock); /*!< in: lock */ diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic index 139f4041a36..1ce00fd7313 100644 --- a/storage/innobase/include/log0log.ic +++ b/storage/innobase/include/log0log.ic @@ -433,7 +433,10 @@ void log_free_check(void) /*================*/ { - /* ut_ad(sync_thread_levels_empty()); */ + +#ifdef UNIV_SYNC_DEBUG + ut_ad(sync_thread_levels_empty_gen(TRUE)); +#endif /* UNIV_SYNC_DEBUG */ if (log_sys->check_flush_or_checkpoint) { diff --git a/storage/innobase/include/mach0data.h b/storage/innobase/include/mach0data.h index 44ee3df22ce..8434bc73586 100644 --- a/storage/innobase/include/mach0data.h +++ b/storage/innobase/include/mach0data.h @@ -166,14 +166,14 @@ UNIV_INLINE void mach_write_to_6( /*============*/ - byte* b, /*!< in: pointer to 6 bytes where to store */ - dulint n); /*!< in: dulint integer to be stored */ + byte* b, /*!< in: pointer to 6 bytes where to store */ + ib_uint64_t id); /*!< in: 48-bit integer */ /********************************************************//** The following function is used to fetch data from 6 consecutive bytes. The most significant byte is at the lowest address. -@return dulint integer */ +@return 48-bit integer */ UNIV_INLINE -dulint +ib_uint64_t mach_read_from_6( /*=============*/ const byte* b) /*!< in: pointer to 6 bytes */ @@ -185,14 +185,14 @@ UNIV_INLINE void mach_write_to_7( /*============*/ - byte* b, /*!< in: pointer to 7 bytes where to store */ - dulint n); /*!< in: dulint integer to be stored */ + byte* b, /*!< in: pointer to 7 bytes where to store */ + ib_uint64_t n); /*!< in: 56-bit integer */ /********************************************************//** The following function is used to fetch data from 7 consecutive bytes. The most significant byte is at the lowest address. -@return dulint integer */ +@return 56-bit integer */ UNIV_INLINE -dulint +ib_uint64_t mach_read_from_7( /*=============*/ const byte* b) /*!< in: pointer to 7 bytes */ @@ -204,88 +204,69 @@ UNIV_INLINE void mach_write_to_8( /*============*/ - byte* b, /*!< in: pointer to 8 bytes where to store */ - dulint n); /*!< in: dulint integer to be stored */ -/*******************************************************//** -The following function is used to store data in 8 consecutive -bytes. We store the most significant byte to the lowest address. */ -UNIV_INLINE -void -mach_write_ull( -/*===========*/ byte* b, /*!< in: pointer to 8 bytes where to store */ ib_uint64_t n); /*!< in: 64-bit integer to be stored */ /********************************************************//** The following function is used to fetch data from 8 consecutive bytes. The most significant byte is at the lowest address. -@return dulint integer */ -UNIV_INLINE -dulint -mach_read_from_8( -/*=============*/ - const byte* b) /*!< in: pointer to 8 bytes */ - __attribute__((nonnull, pure)); -/********************************************************//** -The following function is used to fetch data from 8 consecutive -bytes. The most significant byte is at the lowest address. @return 64-bit integer */ UNIV_INLINE ib_uint64_t -mach_read_ull( -/*==========*/ +mach_read_from_8( +/*=============*/ const byte* b) /*!< in: pointer to 8 bytes */ __attribute__((nonnull, pure)); /*********************************************************//** -Writes a dulint in a compressed form (5..9 bytes). +Writes a 64-bit integer in a compressed form (5..9 bytes). @return size in bytes */ UNIV_INLINE ulint -mach_dulint_write_compressed( -/*=========================*/ - byte* b, /*!< in: pointer to memory where to store */ - dulint n); /*!< in: dulint integer to be stored */ +mach_ull_write_compressed( +/*======================*/ + byte* b, /*!< in: pointer to memory where to store */ + ib_uint64_t n); /*!< in: 64-bit integer to be stored */ /*********************************************************//** -Returns the size of a dulint when written in the compressed form. +Returns the size of a 64-bit integer when written in the compressed form. @return compressed size in bytes */ UNIV_INLINE ulint -mach_dulint_get_compressed_size( -/*============================*/ - dulint n); /*!< in: dulint integer to be stored */ +mach_ull_get_compressed_size( +/*=========================*/ + ib_uint64_t n); /*!< in: 64-bit integer to be stored */ /*********************************************************//** -Reads a dulint in a compressed form. -@return read dulint */ +Reads a 64-bit integer in a compressed form. +@return the value read */ UNIV_INLINE -dulint -mach_dulint_read_compressed( -/*========================*/ +ib_uint64_t +mach_ull_read_compressed( +/*=====================*/ const byte* b) /*!< in: pointer to memory from where to read */ __attribute__((nonnull, pure)); /*********************************************************//** -Writes a dulint in a compressed form (1..11 bytes). +Writes a 64-bit integer in a compressed form (1..11 bytes). @return size in bytes */ UNIV_INLINE ulint -mach_dulint_write_much_compressed( -/*==============================*/ - byte* b, /*!< in: pointer to memory where to store */ - dulint n); /*!< in: dulint integer to be stored */ +mach_ull_write_much_compressed( +/*===========================*/ + byte* b, /*!< in: pointer to memory where to store */ + ib_uint64_t n); /*!< in: 64-bit integer to be stored */ /*********************************************************//** -Returns the size of a dulint when written in the compressed form. +Returns the size of a 64-bit integer when written in the compressed form. @return compressed size in bytes */ UNIV_INLINE ulint -mach_dulint_get_much_compressed_size( -/*=================================*/ - dulint n) /*!< in: dulint integer to be stored */ +mach_ull_get_much_compressed_size( +/*==============================*/ + ib_uint64_t n) /*!< in: 64-bit integer to be stored */ __attribute__((const)); /*********************************************************//** -Reads a dulint in a compressed form. -@return read dulint */ +Reads a 64-bit integer in a compressed form. +@return the value read */ UNIV_INLINE -dulint -mach_dulint_read_much_compressed( -/*=============================*/ +ib_uint64_t +mach_ull_read_much_compressed( +/*==========================*/ const byte* b) /*!< in: pointer to memory from where to read */ __attribute__((nonnull, pure)); /*********************************************************//** @@ -299,15 +280,16 @@ mach_parse_compressed( byte* end_ptr,/*!< in: pointer to end of the buffer */ ulint* val); /*!< out: read value */ /*********************************************************//** -Reads a dulint in a compressed form if the log record fully contains it. -@return pointer to end of the stored field, NULL if not complete */ -UNIV_INTERN +Reads a 64-bit integer in a compressed form +if the log record fully contains it. +@return pointer to end of the stored field, NULL if not complete */ +UNIV_INLINE byte* -mach_dulint_parse_compressed( -/*=========================*/ - byte* ptr, /*!< in: pointer to buffer from where to read */ - byte* end_ptr,/*!< in: pointer to end of the buffer */ - dulint* val); /*!< out: read value */ +mach_ull_parse_compressed( +/*======================*/ + byte* ptr, /*!< in: pointer to buffer from where to read */ + byte* end_ptr,/*!< in: pointer to end of the buffer */ + ib_uint64_t* val); /*!< out: read value */ #ifndef UNIV_HOTBACKUP /*********************************************************//** Reads a double. It is stored in a little-endian format. diff --git a/storage/innobase/include/mach0data.ic b/storage/innobase/include/mach0data.ic index 96d2417ac81..b1e5991d39e 100644 --- a/storage/innobase/include/mach0data.ic +++ b/storage/innobase/include/mach0data.ic @@ -280,22 +280,6 @@ UNIV_INLINE void mach_write_to_8( /*============*/ - byte* b, /*!< in: pointer to 8 bytes where to store */ - dulint n) /*!< in: dulint integer to be stored */ -{ - ut_ad(b); - - mach_write_to_4(b, ut_dulint_get_high(n)); - mach_write_to_4(b + 4, ut_dulint_get_low(n)); -} - -/*******************************************************//** -The following function is used to store data in 8 consecutive -bytes. We store the most significant byte to the lowest address. */ -UNIV_INLINE -void -mach_write_ull( -/*===========*/ byte* b, /*!< in: pointer to 8 bytes where to store */ ib_uint64_t n) /*!< in: 64-bit integer to be stored */ { @@ -308,32 +292,11 @@ mach_write_ull( /********************************************************//** The following function is used to fetch data from 8 consecutive bytes. The most significant byte is at the lowest address. -@return dulint integer */ -UNIV_INLINE -dulint -mach_read_from_8( -/*=============*/ - const byte* b) /*!< in: pointer to 8 bytes */ -{ - ulint high; - ulint low; - - ut_ad(b); - - high = mach_read_from_4(b); - low = mach_read_from_4(b + 4); - - return(ut_dulint_create(high, low)); -} - -/********************************************************//** -The following function is used to fetch data from 8 consecutive -bytes. The most significant byte is at the lowest address. @return 64-bit integer */ UNIV_INLINE ib_uint64_t -mach_read_ull( -/*==========*/ +mach_read_from_8( +/*=============*/ const byte* b) /*!< in: pointer to 8 bytes */ { ib_uint64_t ull; @@ -351,34 +314,28 @@ UNIV_INLINE void mach_write_to_7( /*============*/ - byte* b, /*!< in: pointer to 7 bytes where to store */ - dulint n) /*!< in: dulint integer to be stored */ + byte* b, /*!< in: pointer to 7 bytes where to store */ + ib_uint64_t n) /*!< in: 56-bit integer */ { ut_ad(b); - mach_write_to_3(b, ut_dulint_get_high(n)); - mach_write_to_4(b + 3, ut_dulint_get_low(n)); + mach_write_to_3(b, (ulint) (n >> 32)); + mach_write_to_4(b + 3, (ulint) n); } /********************************************************//** The following function is used to fetch data from 7 consecutive bytes. The most significant byte is at the lowest address. -@return dulint integer */ +@return 56-bit integer */ UNIV_INLINE -dulint +ib_uint64_t mach_read_from_7( /*=============*/ const byte* b) /*!< in: pointer to 7 bytes */ { - ulint high; - ulint low; - ut_ad(b); - high = mach_read_from_3(b); - low = mach_read_from_4(b + 3); - - return(ut_dulint_create(high, low)); + return(ut_ull_create(mach_read_from_3(b), mach_read_from_4(b + 3))); } /*******************************************************//** @@ -388,162 +345,196 @@ UNIV_INLINE void mach_write_to_6( /*============*/ - byte* b, /*!< in: pointer to 6 bytes where to store */ - dulint n) /*!< in: dulint integer to be stored */ + byte* b, /*!< in: pointer to 6 bytes where to store */ + ib_uint64_t n) /*!< in: 48-bit integer */ { ut_ad(b); - mach_write_to_2(b, ut_dulint_get_high(n)); - mach_write_to_4(b + 2, ut_dulint_get_low(n)); + mach_write_to_2(b, (ulint) (n >> 32)); + mach_write_to_4(b + 2, (ulint) n); } /********************************************************//** The following function is used to fetch data from 6 consecutive bytes. The most significant byte is at the lowest address. -@return dulint integer */ +@return 48-bit integer */ UNIV_INLINE -dulint +ib_uint64_t mach_read_from_6( /*=============*/ const byte* b) /*!< in: pointer to 6 bytes */ { - ulint high; - ulint low; - ut_ad(b); - high = mach_read_from_2(b); - low = mach_read_from_4(b + 2); - - return(ut_dulint_create(high, low)); + return(ut_ull_create(mach_read_from_2(b), mach_read_from_4(b + 2))); } /*********************************************************//** -Writes a dulint in a compressed form (5..9 bytes). +Writes a 64-bit integer in a compressed form (5..9 bytes). @return size in bytes */ UNIV_INLINE ulint -mach_dulint_write_compressed( -/*=========================*/ - byte* b, /*!< in: pointer to memory where to store */ - dulint n) /*!< in: dulint integer to be stored */ +mach_ull_write_compressed( +/*======================*/ + byte* b, /*!< in: pointer to memory where to store */ + ib_uint64_t n) /*!< in: 64-bit integer to be stored */ { ulint size; ut_ad(b); - size = mach_write_compressed(b, ut_dulint_get_high(n)); - mach_write_to_4(b + size, ut_dulint_get_low(n)); + size = mach_write_compressed(b, (ulint) (n >> 32)); + mach_write_to_4(b + size, (ulint) n); return(size + 4); } /*********************************************************//** -Returns the size of a dulint when written in the compressed form. +Returns the size of a 64-bit integer when written in the compressed form. @return compressed size in bytes */ UNIV_INLINE ulint -mach_dulint_get_compressed_size( -/*============================*/ - dulint n) /*!< in: dulint integer to be stored */ +mach_ull_get_compressed_size( +/*=========================*/ + ib_uint64_t n) /*!< in: 64-bit integer to be stored */ { - return(4 + mach_get_compressed_size(ut_dulint_get_high(n))); + return(4 + mach_get_compressed_size((ulint) (n >> 32))); } /*********************************************************//** -Reads a dulint in a compressed form. -@return read dulint */ +Reads a 64-bit integer in a compressed form. +@return the value read */ UNIV_INLINE -dulint -mach_dulint_read_compressed( -/*========================*/ +ib_uint64_t +mach_ull_read_compressed( +/*=====================*/ const byte* b) /*!< in: pointer to memory from where to read */ { - ulint high; - ulint low; - ulint size; + ib_uint64_t n; + ulint size; ut_ad(b); - high = mach_read_compressed(b); + n = (ib_uint64_t) mach_read_compressed(b); - size = mach_get_compressed_size(high); + size = mach_get_compressed_size((ulint) n); - low = mach_read_from_4(b + size); + n <<= 32; + n |= (ib_uint64_t) mach_read_from_4(b + size); - return(ut_dulint_create(high, low)); + return(n); } /*********************************************************//** -Writes a dulint in a compressed form (1..11 bytes). +Writes a 64-bit integer in a compressed form (1..11 bytes). @return size in bytes */ UNIV_INLINE ulint -mach_dulint_write_much_compressed( -/*==============================*/ - byte* b, /*!< in: pointer to memory where to store */ - dulint n) /*!< in: dulint integer to be stored */ +mach_ull_write_much_compressed( +/*===========================*/ + byte* b, /*!< in: pointer to memory where to store */ + ib_uint64_t n) /*!< in: 64-bit integer to be stored */ { ulint size; ut_ad(b); - if (ut_dulint_get_high(n) == 0) { - return(mach_write_compressed(b, ut_dulint_get_low(n))); + if (!(n >> 32)) { + return(mach_write_compressed(b, (ulint) n)); } *b = (byte)0xFF; - size = 1 + mach_write_compressed(b + 1, ut_dulint_get_high(n)); + size = 1 + mach_write_compressed(b + 1, (ulint) (n >> 32)); - size += mach_write_compressed(b + size, ut_dulint_get_low(n)); + size += mach_write_compressed(b + size, (ulint) n & 0xFFFFFFFF); return(size); } /*********************************************************//** -Returns the size of a dulint when written in the compressed form. +Returns the size of a 64-bit integer when written in the compressed form. @return compressed size in bytes */ UNIV_INLINE ulint -mach_dulint_get_much_compressed_size( -/*=================================*/ - dulint n) /*!< in: dulint integer to be stored */ +mach_ull_get_much_compressed_size( +/*==============================*/ + ib_uint64_t n) /*!< in: 64-bit integer to be stored */ { - if (0 == ut_dulint_get_high(n)) { - return(mach_get_compressed_size(ut_dulint_get_low(n))); + if (!(n >> 32)) { + return(mach_get_compressed_size((ulint) n)); } - return(1 + mach_get_compressed_size(ut_dulint_get_high(n)) - + mach_get_compressed_size(ut_dulint_get_low(n))); + return(1 + mach_get_compressed_size((ulint) (n >> 32)) + + mach_get_compressed_size((ulint) n & ULINT32_MASK)); } /*********************************************************//** -Reads a dulint in a compressed form. -@return read dulint */ +Reads a 64-bit integer in a compressed form. +@return the value read */ UNIV_INLINE -dulint -mach_dulint_read_much_compressed( -/*=============================*/ +ib_uint64_t +mach_ull_read_much_compressed( +/*==========================*/ const byte* b) /*!< in: pointer to memory from where to read */ { - ulint high; - ulint low; - ulint size; + ib_uint64_t n; + ulint size; ut_ad(b); if (*b != (byte)0xFF) { - high = 0; + n = 0; size = 0; } else { - high = mach_read_compressed(b + 1); + n = (ib_uint64_t) mach_read_compressed(b + 1); + + size = 1 + mach_get_compressed_size((ulint) n); + n <<= 32; + } + + n |= mach_read_compressed(b + size); + + return(n); +} + +/*********************************************************//** +Reads a 64-bit integer in a compressed form +if the log record fully contains it. +@return pointer to end of the stored field, NULL if not complete */ +UNIV_INLINE +byte* +mach_ull_parse_compressed( +/*======================*/ + byte* ptr, /* in: pointer to buffer from where to read */ + byte* end_ptr,/* in: pointer to end of the buffer */ + ib_uint64_t* val) /* out: read value */ +{ + ulint size; + + ut_ad(ptr); + ut_ad(end_ptr); + ut_ad(val); + + if (end_ptr < ptr + 5) { + + return(NULL); + } + + *val = mach_read_compressed(ptr); + + size = mach_get_compressed_size((ulint) *val); + + ptr += size; + + if (end_ptr < ptr + 4) { - size = 1 + mach_get_compressed_size(high); + return(NULL); } - low = mach_read_compressed(b + size); + *val <<= 32; + *val |= mach_read_from_4(ptr); - return(ut_dulint_create(high, low)); + return(ptr + 4); } #ifndef UNIV_HOTBACKUP /*********************************************************//** diff --git a/storage/innobase/include/mtr0log.h b/storage/innobase/include/mtr0log.h index 6322af2a569..d271002a5fe 100644 --- a/storage/innobase/include/mtr0log.h +++ b/storage/innobase/include/mtr0log.h @@ -47,11 +47,11 @@ Writes 8 bytes to a file page buffered in the buffer pool. Writes the corresponding log record to the mini-transaction log. */ UNIV_INTERN void -mlog_write_dulint( -/*==============*/ - byte* ptr, /*!< in: pointer where to write */ - dulint val, /*!< in: value to write */ - mtr_t* mtr); /*!< in: mini-transaction handle */ +mlog_write_ull( +/*===========*/ + byte* ptr, /*!< in: pointer where to write */ + ib_uint64_t val, /*!< in: value to write */ + mtr_t* mtr); /*!< in: mini-transaction handle */ /********************************************************//** Writes a string to a file page buffered in the buffer pool. Writes the corresponding log record to the mini-transaction log. */ @@ -125,13 +125,13 @@ mlog_catenate_ulint_compressed( mtr_t* mtr, /*!< in: mtr */ ulint val); /*!< in: value to write */ /********************************************************//** -Catenates a compressed dulint to mlog. */ +Catenates a compressed 64-bit integer to mlog. */ UNIV_INLINE void -mlog_catenate_dulint_compressed( -/*============================*/ - mtr_t* mtr, /*!< in: mtr */ - dulint val); /*!< in: value to write */ +mlog_catenate_ull_compressed( +/*=========================*/ + mtr_t* mtr, /*!< in: mtr */ + ib_uint64_t val); /*!< in: value to write */ /********************************************************//** Opens a buffer to mlog. It must be closed with mlog_close. @return buffer, NULL if log mode MTR_LOG_NONE */ @@ -183,7 +183,7 @@ mlog_parse_initial_log_record( ulint* space, /*!< out: space id */ ulint* page_no);/*!< out: page number */ /********************************************************//** -Parses a log record written by mlog_write_ulint or mlog_write_dulint. +Parses a log record written by mlog_write_ulint or mlog_write_ull. @return parsed record end, NULL if not a complete record */ UNIV_INTERN byte* diff --git a/storage/innobase/include/mtr0log.ic b/storage/innobase/include/mtr0log.ic index 5c24c38b337..c670a0a8c82 100644 --- a/storage/innobase/include/mtr0log.ic +++ b/storage/innobase/include/mtr0log.ic @@ -142,13 +142,13 @@ mlog_catenate_ulint_compressed( } /********************************************************//** -Catenates a compressed dulint to mlog. */ +Catenates a compressed 64-bit integer to mlog. */ UNIV_INLINE void -mlog_catenate_dulint_compressed( -/*============================*/ - mtr_t* mtr, /*!< in: mtr */ - dulint val) /*!< in: value to write */ +mlog_catenate_ull_compressed( +/*=========================*/ + mtr_t* mtr, /*!< in: mtr */ + ib_uint64_t val) /*!< in: value to write */ { byte* log_ptr; @@ -160,7 +160,7 @@ mlog_catenate_dulint_compressed( return; } - log_ptr += mach_dulint_write_compressed(log_ptr, val); + log_ptr += mach_ull_write_compressed(log_ptr, val); mlog_close(mtr, log_ptr); } diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h index bc3f1951be9..8abca093548 100644 --- a/storage/innobase/include/mtr0mtr.h +++ b/storage/innobase/include/mtr0mtr.h @@ -264,15 +264,6 @@ mtr_read_ulint( const byte* ptr, /*!< in: pointer from where to read */ ulint type, /*!< in: MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES */ mtr_t* mtr); /*!< in: mini-transaction handle */ -/********************************************************//** -Reads 8 bytes from a file page buffered in the buffer pool. -@return value read */ -UNIV_INTERN -dulint -mtr_read_dulint( -/*============*/ - const byte* ptr, /*!< in: pointer from where to read */ - mtr_t* mtr); /*!< in: mini-transaction handle */ #ifndef UNIV_HOTBACKUP /*********************************************************************//** This macro locks an rw-lock in s-mode. */ diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index 197e361b2b1..6d95b280330 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -177,6 +177,13 @@ log. */ #define OS_WIN95 2 /*!< Microsoft Windows 95 */ #define OS_WINNT 3 /*!< Microsoft Windows NT 3.x */ #define OS_WIN2000 4 /*!< Microsoft Windows 2000 */ +#define OS_WINXP 5 /*!< Microsoft Windows XP + or Windows Server 2003 */ +#define OS_WINVISTA 6 /*!< Microsoft Windows Vista + or Windows Server 2008 */ +#define OS_WIN7 7 /*!< Microsoft Windows 7 + or Windows Server 2008 R2 */ + extern ulint os_n_file_reads; extern ulint os_n_file_writes; @@ -368,7 +375,8 @@ typedef DIR* os_file_dir_t; /*!< directory stream */ /***********************************************************************//** Gets the operating system version. Currently works only on Windows. -@return OS_WIN95, OS_WIN31, OS_WINNT, or OS_WIN2000 */ +@return OS_WIN95, OS_WIN31, OS_WINNT, OS_WIN2000, OS_WINXP, OS_WINVISTA, +OS_WIN7. */ UNIV_INTERN ulint os_get_os_version(void); diff --git a/storage/innobase/include/os0sync.h b/storage/innobase/include/os0sync.h index 0c22162b900..0b600c80ce3 100644 --- a/storage/innobase/include/os0sync.h +++ b/storage/innobase/include/os0sync.h @@ -38,28 +38,18 @@ Created 9/6/1995 Heikki Tuuri #include "ut0lst.h" #ifdef __WIN__ - +/** Native event (slow)*/ +typedef HANDLE os_native_event_t; /** Native mutex */ -#define os_fast_mutex_t CRITICAL_SECTION - -/** Native event */ -typedef HANDLE os_native_event_t; - -/** Operating system event */ -typedef struct os_event_struct os_event_struct_t; -/** Operating system event handle */ -typedef os_event_struct_t* os_event_t; - -/** An asynchronous signal sent between threads */ -struct os_event_struct { - os_native_event_t handle; - /*!< Windows event */ - UT_LIST_NODE_T(os_event_struct_t) os_event_list; - /*!< list of all created events */ -}; +typedef CRITICAL_SECTION os_fast_mutex_t; +/** Native condition variable. */ +typedef CONDITION_VARIABLE os_cond_t; #else /** Native mutex */ -typedef pthread_mutex_t os_fast_mutex_t; +typedef pthread_mutex_t os_fast_mutex_t; +/** Native condition variable */ +typedef pthread_cond_t os_cond_t; +#endif /** Operating system event */ typedef struct os_event_struct os_event_struct_t; @@ -68,6 +58,10 @@ typedef os_event_struct_t* os_event_t; /** An asynchronous signal sent between threads */ struct os_event_struct { +#ifdef __WIN__ + HANDLE handle; /*!< kernel event object, slow, + used on older Windows */ +#endif os_fast_mutex_t os_mutex; /*!< this mutex protects the next fields */ ibool is_set; /*!< this is TRUE when the event is @@ -76,24 +70,17 @@ struct os_event_struct { this event */ ib_int64_t signal_count; /*!< this is incremented each time the event becomes signaled */ - pthread_cond_t cond_var; /*!< condition variable is used in + os_cond_t cond_var; /*!< condition variable is used in waiting for the event */ UT_LIST_NODE_T(os_event_struct_t) os_event_list; /*!< list of all created events */ }; -#endif /** Operating system mutex */ typedef struct os_mutex_struct os_mutex_str_t; /** Operating system mutex handle */ typedef os_mutex_str_t* os_mutex_t; -/** Denotes an infinite delay for os_event_wait_time() */ -#define OS_SYNC_INFINITE_TIME ((ulint)(-1)) - -/** Return value of os_event_wait_time() when the time is exceeded */ -#define OS_SYNC_TIME_EXCEEDED 1 - /** Mutex protecting counts and the event and OS 'slow' mutex lists */ extern os_mutex_t os_sync_mutex; @@ -187,42 +174,14 @@ os_event_wait_low( #define os_event_wait(event) os_event_wait_low(event, 0) -/**********************************************************//** -Waits for an event object until it is in the signaled state or -a timeout is exceeded. In Unix the timeout is always infinite. -@return 0 if success, OS_SYNC_TIME_EXCEEDED if timeout was exceeded */ -UNIV_INTERN -ulint -os_event_wait_time( -/*===============*/ - os_event_t event, /*!< in: event to wait */ - ulint time); /*!< in: timeout in microseconds, or - OS_SYNC_INFINITE_TIME */ -#ifdef __WIN__ -/**********************************************************//** -Waits for any event in an OS native event array. Returns if even a single -one is signaled or becomes signaled. -@return index of the event which was signaled */ -UNIV_INTERN -ulint -os_event_wait_multiple( -/*===================*/ - ulint n, /*!< in: number of events in the - array */ - os_native_event_t* native_event_array); - /*!< in: pointer to an array of event - handles */ -#endif /*********************************************************//** Creates an operating system mutex semaphore. Because these are slow, the mutex semaphore of InnoDB itself (mutex_t) should be used where possible. @return the mutex handle */ UNIV_INTERN os_mutex_t -os_mutex_create( -/*============*/ - const char* name); /*!< in: the name of the mutex, if NULL - the mutex is created without a name */ +os_mutex_create(void); +/*=================*/ /**********************************************************//** Acquires ownership of a mutex semaphore. */ UNIV_INTERN diff --git a/storage/innobase/include/os0sync.ic b/storage/innobase/include/os0sync.ic index 1f3ce38fa65..c33f13aaad6 100644 --- a/storage/innobase/include/os0sync.ic +++ b/storage/innobase/include/os0sync.ic @@ -28,8 +28,7 @@ Created 9/6/1995 Heikki Tuuri #endif /**********************************************************//** -Acquires ownership of a fast mutex. Currently in Windows this is the same -as os_fast_mutex_lock! +Acquires ownership of a fast mutex. @return 0 if success, != 0 if was reserved by another thread */ UNIV_INLINE ulint @@ -38,9 +37,13 @@ os_fast_mutex_trylock( os_fast_mutex_t* fast_mutex) /*!< in: mutex to acquire */ { #ifdef __WIN__ - EnterCriticalSection(fast_mutex); + if (TryEnterCriticalSection(fast_mutex)) { - return(0); + return(0); + } else { + + return(1); + } #else /* NOTE that the MySQL my_pthread.h redefines pthread_mutex_trylock so that it returns 0 on success. In the operating system diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index 3899499fb6a..826fd13125d 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -66,7 +66,7 @@ typedef byte page_header_t; direction */ #define PAGE_N_RECS 16 /* number of user records on the page */ #define PAGE_MAX_TRX_ID 18 /* highest id of a trx which may have modified - a record on the page; a dulint; defined only + a record on the page; trx_id_t; defined only in secondary indexes and in the insert buffer tree; NOTE: this may be modified only when the thread has an x-latch to the page, diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic index 8f794410f20..e9624c2360f 100644 --- a/storage/innobase/include/page0page.ic +++ b/storage/innobase/include/page0page.ic @@ -94,11 +94,10 @@ page_update_max_trx_id( TRUE for the dummy indexes constructed during redo log application). In that case, PAGE_MAX_TRX_ID is unused, and trx_id is usually zero. */ - ut_ad(!ut_dulint_is_zero(trx_id) || recv_recovery_is_on()); + ut_ad(trx_id || recv_recovery_is_on()); ut_ad(page_is_leaf(buf_block_get_frame(block))); - if (ut_dulint_cmp(page_get_max_trx_id(buf_block_get_frame(block)), - trx_id) < 0) { + if (page_get_max_trx_id(buf_block_get_frame(block)) < trx_id) { page_set_max_trx_id(block, page_zip, trx_id, mtr); } diff --git a/storage/innobase/include/pars0pars.h b/storage/innobase/include/pars0pars.h index 524fe4ac3e7..141b2706d7d 100644 --- a/storage/innobase/include/pars0pars.h +++ b/storage/innobase/include/pars0pars.h @@ -520,35 +520,18 @@ 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); +pars_info_add_literal(info, name, buf, 8, DATA_FIXBINARY, 0); except that the buffer is dynamically allocated from the info struct's heap. */ UNIV_INTERN void -pars_info_add_dulint_literal( -/*=========================*/ +pars_info_add_ull_literal( +/*======================*/ pars_info_t* info, /*!< in: info struct */ const char* name, /*!< in: name */ - dulint val); /*!< in: value */ + ib_uint64_t val); /*!< in: value */ /****************************************************************//** Add user function. */ UNIV_INTERN diff --git a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h index 39f8d07af89..09734bbb197 100644 --- a/storage/innobase/include/que0que.h +++ b/storage/innobase/include/que0que.h @@ -421,9 +421,6 @@ struct que_fork_struct{ ibool cur_on_row; /*!< TRUE if cursor is on a row, i.e., it is not before the first row or after the last row */ - dulint n_inserts; /*!< number of rows inserted */ - dulint n_updates; /*!< number of rows updated */ - dulint n_deletes; /*!< number of rows deleted */ sel_node_t* last_sel_node; /*!< last executed select node, or NULL if none */ UT_LIST_NODE_T(que_fork_t) diff --git a/storage/innobase/include/read0read.h b/storage/innobase/include/read0read.h index 4d9a9fade36..73ea66f4da2 100644 --- a/storage/innobase/include/read0read.h +++ b/storage/innobase/include/read0read.h @@ -43,8 +43,7 @@ read_view_t* read_view_open_now( /*===============*/ trx_id_t cr_trx_id, /*!< in: trx_id of creating - transaction, or ut_dulint_zero - used in purge */ + transaction, or 0 used in purge */ mem_heap_t* heap); /*!< in: memory heap from which allocated */ /*********************************************************************//** @@ -56,8 +55,7 @@ read_view_t* read_view_oldest_copy_or_open_new( /*==============================*/ trx_id_t cr_trx_id, /*!< in: trx_id of creating - transaction, or ut_dulint_zero - used in purge */ + transaction, or 0 used in purge */ mem_heap_t* heap); /*!< in: memory heap from which allocated */ /*********************************************************************//** @@ -125,7 +123,7 @@ read should not see the modifications to the database. */ struct read_view_struct{ ulint type; /*!< VIEW_NORMAL, VIEW_HIGH_GRANULARITY */ - undo_no_t undo_no;/*!< ut_dulint_zero or if type is + undo_no_t undo_no;/*!< 0 or if type is VIEW_HIGH_GRANULARITY transaction undo_no when this high-granularity consistent read view was created */ @@ -156,7 +154,7 @@ struct read_view_struct{ that is, up_limit_id and low_limit_id. */ trx_id_t creator_trx_id; /*!< trx id of creating transaction, or - ut_dulint_zero used in purge */ + 0 used in purge */ UT_LIST_NODE_T(read_view_t) view_list; /*!< List of read views in trx_sys */ }; diff --git a/storage/innobase/include/read0read.ic b/storage/innobase/include/read0read.ic index 9924967cc2d..5bb5249b591 100644 --- a/storage/innobase/include/read0read.ic +++ b/storage/innobase/include/read0read.ic @@ -64,15 +64,14 @@ read_view_sees_trx_id( trx_id_t trx_id) /*!< in: trx id */ { ulint n_ids; - int cmp; ulint i; - if (ut_dulint_cmp(trx_id, view->up_limit_id) < 0) { + if (trx_id < view->up_limit_id) { return(TRUE); } - if (ut_dulint_cmp(trx_id, view->low_limit_id) >= 0) { + if (trx_id >= view->low_limit_id) { return(FALSE); } @@ -85,12 +84,11 @@ read_view_sees_trx_id( n_ids = view->n_trx_ids; for (i = 0; i < n_ids; i++) { + trx_id_t view_trx_id + = read_view_get_nth_trx_id(view, n_ids - i - 1); - cmp = ut_dulint_cmp( - trx_id, - read_view_get_nth_trx_id(view, n_ids - i - 1)); - if (cmp <= 0) { - return(cmp < 0); + if (trx_id <= view_trx_id) { + return(trx_id != view_trx_id); } } diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h index 17d08afabb9..53402e8d3a9 100644 --- a/storage/innobase/include/rem0rec.h +++ b/storage/innobase/include/rem0rec.h @@ -659,7 +659,7 @@ rec_fold( fields to fold */ ulint n_bytes, /*!< in: number of bytes to fold in an incomplete last field */ - dulint tree_id) /*!< in: index tree id */ + index_id_t tree_id) /*!< in: index tree id */ __attribute__((pure)); #endif /* !UNIV_HOTBACKUP */ /*********************************************************//** diff --git a/storage/innobase/include/rem0rec.ic b/storage/innobase/include/rem0rec.ic index 8e5bd9a7fcd..ba306eaf27f 100644 --- a/storage/innobase/include/rem0rec.ic +++ b/storage/innobase/include/rem0rec.ic @@ -1594,7 +1594,7 @@ rec_fold( fields to fold */ ulint n_bytes, /*!< in: number of bytes to fold in an incomplete last field */ - dulint tree_id) /*!< in: index tree id */ + index_id_t tree_id) /*!< in: index tree id */ { ulint i; const byte* data; @@ -1618,7 +1618,7 @@ rec_fold( n_bytes = 0; } - fold = ut_fold_dulint(tree_id); + fold = ut_fold_ull(tree_id); for (i = 0; i < n_fields; i++) { data = rec_get_nth_field(rec, offsets, i, &len); diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 39ea240772c..d9c26a2ee3b 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -103,6 +103,17 @@ row_mysql_read_blob_ref( ulint col_len); /*!< in: BLOB reference length (not BLOB length) */ /**************************************************************//** +Pad a column with spaces. */ +UNIV_INTERN +void +row_mysql_pad_col( +/*==============*/ + ulint mbminlen, /*!< in: minimum size of a character, + in bytes */ + byte* pad, /*!< out: padded buffer */ + ulint len); /*!< in: number of bytes to pad */ + +/**************************************************************//** Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format. The counterpart of this function is row_sel_field_store_in_mysql_format() in row0sel.c. @@ -622,7 +633,11 @@ struct row_prebuilt_struct { the secondary index, then this is set to TRUE */ unsigned templ_contains_blob:1;/*!< TRUE if the template contains - BLOB column(s) */ + a column with DATA_BLOB == + get_innobase_type_from_mysql_type(); + not to be confused with InnoDB + externally stored columns + (VARCHAR can be off-page too) */ mysql_row_templ_t* mysql_template;/*!< template used to transform rows fast between MySQL and Innobase formats; memory for this template diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h index 635d746d5a1..f7bec6f7561 100644 --- a/storage/innobase/include/row0upd.h +++ b/storage/innobase/include/row0upd.h @@ -132,7 +132,7 @@ row_upd_index_entry_sys_field( them */ dict_index_t* index, /*!< in: clustered index */ ulint type, /*!< in: DATA_TRX_ID or DATA_ROLL_PTR */ - dulint val); /*!< in: value to write */ + ib_uint64_t val); /*!< in: value to write */ /*********************************************************************//** Creates an update node for a query graph. @return own: update node */ diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 18f7c07c3c6..d78c8113aee 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -112,6 +112,9 @@ 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; +#ifdef __WIN__ +extern ibool srv_use_native_conditions; +#endif extern ulint srv_n_data_files; extern char** srv_data_file_names; extern ulint* srv_data_file_sizes; @@ -161,9 +164,9 @@ is 5% of the max where max is srv_io_capacity. */ #define PCT_IO(p) ((ulong) (srv_io_capacity * ((double) p / 100.0))) #ifdef UNIV_LOG_ARCHIVE -extern ibool srv_log_archive_on; -extern ibool srv_archive_recovery; -extern dulint srv_archive_recovery_limit_lsn; +extern ibool srv_log_archive_on; +extern ibool srv_archive_recovery; +extern ib_uint64_t srv_archive_recovery_limit_lsn; #endif /* UNIV_LOG_ARCHIVE */ extern char* srv_file_flush_method_str; diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index 4e73bee9108..940e583350a 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -621,7 +621,7 @@ or row lock! */ #define SYNC_FILE_FORMAT_TAG 1200 /* Used to serialize access to the file format tag */ #define SYNC_DICT_OPERATION 1001 /* table create, drop, etc. reserve - this in X-mode, implicit or backround + this in X-mode; implicit or backround operations purge, rollback, foreign key checks reserve this in S-mode */ #define SYNC_DICT 1000 diff --git a/storage/innobase/include/trx0i_s.h b/storage/innobase/include/trx0i_s.h index c610782c229..8f8b7367fb0 100644 --- a/storage/innobase/include/trx0i_s.h +++ b/storage/innobase/include/trx0i_s.h @@ -30,6 +30,7 @@ Created July 17, 2007 Vasil Dimov #include "univ.i" #include "trx0types.h" +#include "dict0types.h" #include "ut0ut.h" /** The maximum amount of memory that can be consumed by innodb_trx, @@ -95,7 +96,7 @@ struct i_s_hash_chain_struct { /** This structure represents INFORMATION_SCHEMA.innodb_locks row */ struct i_s_locks_row_struct { - ullint lock_trx_id; /*!< transaction identifier */ + trx_id_t lock_trx_id; /*!< transaction identifier */ const char* lock_mode; /*!< lock mode from lock_get_mode_str() */ const char* lock_type; /*!< lock type from @@ -116,7 +117,7 @@ struct i_s_locks_row_struct { /** The following are auxiliary and not included in the table */ /* @{ */ - ullint lock_table_id; + table_id_t lock_table_id; /*!< table identifier from lock_get_table_id */ i_s_hash_chain_t hash_chain; /*!< hash table chain node for @@ -126,10 +127,10 @@ 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 */ + trx_id_t 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 diff --git a/storage/innobase/include/trx0rec.h b/storage/innobase/include/trx0rec.h index a6e56e963c6..477748f6f89 100644 --- a/storage/innobase/include/trx0rec.h +++ b/storage/innobase/include/trx0rec.h @@ -108,7 +108,7 @@ trx_undo_rec_get_pars( ibool* updated_extern, /*!< out: TRUE if we updated an externally stored fild */ undo_no_t* undo_no, /*!< out: undo log record number */ - dulint* table_id); /*!< out: table id */ + table_id_t* table_id); /*!< out: table id */ /*******************************************************************//** Builds a row reference from an undo log record. @return pointer to remaining part of undo record */ @@ -227,7 +227,7 @@ trx_undo_report_row_operation( index, otherwise NULL */ roll_ptr_t* roll_ptr); /*!< out: rollback pointer to the inserted undo log record, - ut_dulint_zero if BTR_NO_UNDO_LOG + 0 if BTR_NO_UNDO_LOG flag was specified */ /******************************************************************//** Copies an undo record to heap. This function can be called if we know that diff --git a/storage/innobase/include/trx0rec.ic b/storage/innobase/include/trx0rec.ic index e7e41d6d9f6..f0b3276ed44 100644 --- a/storage/innobase/include/trx0rec.ic +++ b/storage/innobase/include/trx0rec.ic @@ -78,7 +78,7 @@ trx_undo_rec_get_undo_no( ptr = undo_rec + 3; - return(mach_dulint_read_much_compressed(ptr)); + return(mach_ull_read_much_compressed(ptr)); } /**********************************************************************//** @@ -90,7 +90,7 @@ trx_undo_rec_get_offset( /*====================*/ undo_no_t undo_no) /*!< in: undo no read from node */ { - return (3 + mach_dulint_get_much_compressed_size(undo_no)); + return (3 + mach_ull_get_much_compressed_size(undo_no)); } /***********************************************************************//** diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h index fc92b4317d5..63e3f6be934 100644 --- a/storage/innobase/include/trx0sys.h +++ b/storage/innobase/include/trx0sys.h @@ -568,11 +568,16 @@ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_NO. */ (TRX_SYS_PAGE_NO of TRX_SYS_SPACE) */ #define TRX_SYS_FILE_FORMAT_TAG (UNIV_PAGE_SIZE - 16) -/** Contents of TRX_SYS_FILE_FORMAT_TAG when valid. The file format +/** Contents of TRX_SYS_FILE_FORMAT_TAG when valid. The file format identifier is added to this constant. */ #define TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW 3645922177UL /** Contents of TRX_SYS_FILE_FORMAT_TAG+4 when valid */ #define TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH 2745987765UL +/** Contents of TRX_SYS_FILE_FORMAT_TAG when valid. The file format +identifier is added to this 64-bit constant. */ +#define TRX_SYS_FILE_FORMAT_TAG_MAGIC_N \ + ((ib_uint64_t) TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH << 32 \ + | TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW) /* @} */ /** Doublewrite control struct */ diff --git a/storage/innobase/include/trx0sys.ic b/storage/innobase/include/trx0sys.ic index 820d31d0692..385c7f4f0cc 100644 --- a/storage/innobase/include/trx0sys.ic +++ b/storage/innobase/include/trx0sys.ic @@ -266,7 +266,7 @@ trx_get_on_id( trx = UT_LIST_GET_FIRST(trx_sys->trx_list); while (trx != NULL) { - if (0 == ut_dulint_cmp(trx_id, trx->id)) { + if (trx_id == trx->id) { return(trx); } @@ -315,12 +315,12 @@ trx_is_active( ut_ad(mutex_own(&(kernel_mutex))); - if (ut_dulint_cmp(trx_id, trx_list_get_min_trx_id()) < 0) { + if (trx_id < trx_list_get_min_trx_id()) { return(FALSE); } - if (ut_dulint_cmp(trx_id, trx_sys->max_trx_id) >= 0) { + if (UNIV_UNLIKELY(trx_id >= trx_sys->max_trx_id)) { /* There must be corruption: we return TRUE because this function is only called by lock_clust_rec_some_has_impl() @@ -359,15 +359,12 @@ trx_sys_get_new_trx_id(void) Thus trx id values will not overlap when the database is repeatedly started! */ - if (ut_dulint_get_low(trx_sys->max_trx_id) - % TRX_SYS_TRX_ID_WRITE_MARGIN == 0) { + if ((ulint) trx_sys->max_trx_id % TRX_SYS_TRX_ID_WRITE_MARGIN == 0) { trx_sys_flush_max_trx_id(); } - id = trx_sys->max_trx_id; - - UT_DULINT_INC(trx_sys->max_trx_id); + id = trx_sys->max_trx_id++; return(id); } diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index abd175d365b..6a817ccdc8e 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -408,30 +408,20 @@ Calculates the "weight" of a transaction. The weight of one transaction is estimated as the number of altered rows + the number of locked rows. @param t transaction @return transaction weight */ -#define TRX_WEIGHT(t) \ - ut_dulint_add((t)->undo_no, UT_LIST_GET_LEN((t)->trx_locks)) +#define TRX_WEIGHT(t) ((t)->undo_no + UT_LIST_GET_LEN((t)->trx_locks)) /*******************************************************************//** Compares the "weight" (or size) of two transactions. Transactions that have edited non-transactional tables are considered heavier than ones that have not. -@return <0, 0 or >0; similar to strcmp(3) */ +@return TRUE if weight(a) >= weight(b) */ UNIV_INTERN -int -trx_weight_cmp( -/*===========*/ +ibool +trx_weight_ge( +/*==========*/ const trx_t* a, /*!< in: the first transaction to be compared */ const trx_t* b); /*!< in: the second transaction to be compared */ -/*******************************************************************//** -Retrieves transacion's id, represented as unsigned long long. -@return transaction's id */ -UNIV_INLINE -ullint -trx_get_id( -/*=======*/ - const trx_t* trx); /*!< in: transaction */ - /* Maximum length of a string that can be returned by trx_get_que_state_str(). */ #define TRX_QUE_STATE_STR_MAX_LEN 12 /* "ROLLING BACK" */ @@ -555,8 +545,8 @@ struct trx_struct{ max trx id when the transaction is moved to COMMITTED_IN_MEMORY state */ ib_uint64_t commit_lsn; /*!< lsn at the time of the commit */ - trx_id_t table_id; /*!< Table to drop iff dict_operation - is TRUE, or ut_dulint_zero. */ + table_id_t table_id; /*!< Table to drop iff dict_operation + is TRUE, or 0. */ /*------------------------------*/ void* mysql_thd; /*!< MySQL thread handle corresponding to this trx, or NULL */ diff --git a/storage/innobase/include/trx0trx.ic b/storage/innobase/include/trx0trx.ic index 7332eeece85..4a1d3bcde0b 100644 --- a/storage/innobase/include/trx0trx.ic +++ b/storage/innobase/include/trx0trx.ic @@ -69,18 +69,6 @@ trx_get_error_info( } /*******************************************************************//** -Retrieves transacion's id, represented as unsigned long long. -@return transaction's id */ -UNIV_INLINE -ullint -trx_get_id( -/*=======*/ - const trx_t* trx) /*!< in: transaction */ -{ - return((ullint)ut_conv_dulint_to_longlong(trx->id)); -} - -/*******************************************************************//** Retrieves transaction's que state in a human readable string. The string should not be free()'d or modified. @return string in the data segment */ diff --git a/storage/innobase/include/trx0types.h b/storage/innobase/include/trx0types.h index 40a7256cbfd..a4115b5aca7 100644 --- a/storage/innobase/include/trx0types.h +++ b/storage/innobase/include/trx0types.h @@ -28,10 +28,7 @@ Created 3/26/1996 Heikki Tuuri #include "ut0byte.h" -/** prepare trx_t::id for being printed via printf(3) */ -#define TRX_ID_PREP_PRINTF(id) (ullint) ut_conv_dulint_to_longlong(id) - -/** printf(3) format used for printing TRX_ID_PRINTF_PREP() */ +/** printf(3) format used for printing DB_TRX_ID and other system fields */ #define TRX_ID_FMT "%llX" /** maximum length that a formatted trx_t::id could take, not including @@ -81,12 +78,14 @@ enum trx_rb_ctx { in crash recovery */ }; +/** Row identifier (DB_ROW_ID, DATA_ROW_ID) */ +typedef ib_id_t row_id_t; /** Transaction identifier (DB_TRX_ID, DATA_TRX_ID) */ -typedef dulint trx_id_t; +typedef ib_id_t trx_id_t; /** Rollback pointer (DB_ROLL_PTR, DATA_ROLL_PTR) */ -typedef dulint roll_ptr_t; +typedef ib_id_t roll_ptr_t; /** Undo number */ -typedef dulint undo_no_t; +typedef ib_id_t undo_no_t; /** Transaction savepoint */ typedef struct trx_savept_struct trx_savept_t; diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h index a084f2394b5..54809f9c2d5 100644 --- a/storage/innobase/include/trx0undo.h +++ b/storage/innobase/include/trx0undo.h @@ -383,7 +383,7 @@ struct trx_undo_struct{ XID xid; /*!< X/Open XA transaction identification */ ibool dict_operation; /*!< TRUE if a dict operation trx */ - dulint table_id; /*!< if a dict operation, then the table + table_id_t table_id; /*!< if a dict operation, then the table id */ trx_rseg_t* rseg; /*!< rseg where the undo log belongs */ /*-----------------------------*/ diff --git a/storage/innobase/include/trx0undo.ic b/storage/innobase/include/trx0undo.ic index 6502ee826e5..b81330f7f8b 100644 --- a/storage/innobase/include/trx0undo.ic +++ b/storage/innobase/include/trx0undo.ic @@ -39,16 +39,19 @@ trx_undo_build_roll_ptr( ulint page_no, /*!< in: page number */ ulint offset) /*!< in: offset of the undo entry within page */ { + roll_ptr_t roll_ptr; #if DATA_ROLL_PTR_LEN != 7 # error "DATA_ROLL_PTR_LEN != 7" #endif + ut_ad(is_insert == 0 || is_insert == 1); ut_ad(rseg_id < TRX_SYS_N_RSEGS); + ut_ad(offset < 65536); - return(ut_dulint_create(is_insert * 128 * 256 * 256 - + rseg_id * 256 * 256 - + (page_no / 256) / 256, - (page_no % (256 * 256)) * 256 * 256 - + offset)); + roll_ptr = (roll_ptr_t) is_insert << 55 + | (roll_ptr_t) rseg_id << 48 + | (roll_ptr_t) page_no << 16 + | offset; + return(roll_ptr); } /***********************************************************************//** @@ -64,24 +67,20 @@ trx_undo_decode_roll_ptr( ulint* offset) /*!< out: offset of the undo entry within page */ { - ulint low; - ulint high; #if DATA_ROLL_PTR_LEN != 7 # error "DATA_ROLL_PTR_LEN != 7" #endif #if TRUE != 1 # error "TRUE != 1" #endif - high = ut_dulint_get_high(roll_ptr); - low = ut_dulint_get_low(roll_ptr); - - *offset = low % (256 * 256); - - *is_insert = high / (256 * 256 * 128); /* TRUE == 1 */ - *rseg_id = (high / (256 * 256)) % 128; - - *page_no = (high % (256 * 256)) * 256 * 256 - + (low / 256) / 256; + ut_ad(roll_ptr < (1ULL << 56)); + *offset = (ulint) roll_ptr & 0xFFFF; + roll_ptr >>= 16; + *page_no = (ulint) roll_ptr & 0xFFFFFFFF; + roll_ptr >>= 32; + *rseg_id = (ulint) roll_ptr & 0x7F; + roll_ptr >>= 7; + *is_insert = (ibool) roll_ptr; /* TRUE==1 */ } /***********************************************************************//** @@ -93,16 +92,14 @@ trx_undo_roll_ptr_is_insert( /*========================*/ roll_ptr_t roll_ptr) /*!< in: roll pointer */ { - ulint high; #if DATA_ROLL_PTR_LEN != 7 # error "DATA_ROLL_PTR_LEN != 7" #endif #if TRUE != 1 # error "TRUE != 1" #endif - high = ut_dulint_get_high(roll_ptr); - - return(high / (256 * 256 * 128)); + ut_ad(roll_ptr < (1ULL << 56)); + return((ibool) (roll_ptr >> 55)); } #endif /* !UNIV_HOTBACKUP */ diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index ea213486445..ac87942f255 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -46,7 +46,7 @@ Created 1/20/1994 Heikki Tuuri #define INNODB_VERSION_MAJOR 1 #define INNODB_VERSION_MINOR 1 -#define INNODB_VERSION_BUGFIX 1 +#define INNODB_VERSION_BUGFIX 2 /* The following is the InnoDB version as shown in SELECT plugin_version FROM information_schema.plugins; @@ -310,6 +310,12 @@ management to ensure correct alignment for doubles etc. */ /* Maximum number of parallel threads in a parallelized operation */ #define UNIV_MAX_PARALLELISM 32 +/* The maximum length of a table name. This is the MySQL limit and is +defined in mysql_com.h like NAME_CHAR_LEN*SYSTEM_CHARSET_MBMAXLEN, the +number does not include a terminating '\0'. InnoDB probably can handle +longer names internally */ +#define MAX_TABLE_NAME_LEN 192 + /* UNIVERSAL TYPE DEFINITIONS ========================== @@ -365,8 +371,10 @@ typedef unsigned long long int ullint; /* The 'undefined' value for a ulint */ #define ULINT_UNDEFINED ((ulint)(-1)) +/** The bitmask of 32-bit unsigned integer */ +#define ULINT32_MASK 0xFFFFFFFF /* The undefined 32-bit unsigned integer */ -#define ULINT32_UNDEFINED 0xFFFFFFFF +#define ULINT32_UNDEFINED ULINT32_MASK /* Maximum value for a ulint */ #define ULINT_MAX ((ulint)(-2)) @@ -374,6 +382,9 @@ typedef unsigned long long int ullint; /* Maximum value for ib_uint64_t */ #define IB_ULONGLONG_MAX ((ib_uint64_t) (~0ULL)) +/** The generic InnoDB system object identifier data type */ +typedef ib_uint64_t ib_id_t; + /* This 'ibool' type is used within Innobase. Remember that different included headers may define 'bool' differently. Do not assume that 'bool' is a ulint! */ #define ibool ulint diff --git a/storage/innobase/include/ut0byte.h b/storage/innobase/include/ut0byte.h index f55e2888c60..b99d7175b94 100644 --- a/storage/innobase/include/ut0byte.h +++ b/storage/innobase/include/ut0byte.h @@ -27,145 +27,22 @@ Created 1/20/1994 Heikki Tuuri #define ut0byte_h -#include "univ.i" - -/** Pair of ulint integers. */ -typedef struct dulint_struct dulint; -/** Type definition for a 64-bit unsigned integer, which works also -in 32-bit machines. NOTE! Access the fields only with the accessor -functions. This definition appears here only for the compiler to -know the size of a dulint. */ -struct dulint_struct{ - ulint high; /*!< most significant 32 bits */ - ulint low; /*!< least significant 32 bits */ -}; - -/** Zero value for a dulint */ -extern const dulint ut_dulint_zero; -/** Maximum value for a dulint */ -extern const dulint ut_dulint_max; +#include "univ.i" /*******************************************************//** -Creates a 64-bit dulint out of two ulints. +Creates a 64-bit integer out of two 32-bit integers. @return created dulint */ UNIV_INLINE -dulint -ut_dulint_create( -/*=============*/ - ulint high, /*!< in: high-order 32 bits */ - ulint low); /*!< in: low-order 32 bits */ -/*******************************************************//** -Gets the high-order 32 bits of a dulint. -@return 32 bits in ulint */ -UNIV_INLINE -ulint -ut_dulint_get_high( -/*===============*/ - dulint d); /*!< in: dulint */ -/*******************************************************//** -Gets the low-order 32 bits of a dulint. -@return 32 bits in ulint */ -UNIV_INLINE -ulint -ut_dulint_get_low( -/*==============*/ - dulint d); /*!< in: dulint */ -/*******************************************************//** -Converts a dulint (a struct of 2 ulints) to ib_int64_t, which is a 64-bit -integer type. -@return value in ib_int64_t type */ -UNIV_INLINE -ib_int64_t -ut_conv_dulint_to_longlong( -/*=======================*/ - dulint d); /*!< in: dulint */ -/*******************************************************//** -Tests if a dulint is zero. -@return TRUE if zero */ -UNIV_INLINE -ibool -ut_dulint_is_zero( -/*==============*/ - dulint a); /*!< in: dulint */ -/*******************************************************//** -Compares two dulints. -@return -1 if a < b, 0 if a == b, 1 if a > b */ -UNIV_INLINE -int -ut_dulint_cmp( -/*==========*/ - dulint a, /*!< in: dulint */ - dulint b); /*!< in: dulint */ -/*******************************************************//** -Calculates the max of two dulints. -@return max(a, b) */ -UNIV_INLINE -dulint -ut_dulint_get_max( -/*==============*/ - dulint a, /*!< in: dulint */ - dulint b); /*!< in: dulint */ -/*******************************************************//** -Calculates the min of two dulints. -@return min(a, b) */ -UNIV_INLINE -dulint -ut_dulint_get_min( -/*==============*/ - dulint a, /*!< in: dulint */ - dulint b); /*!< in: dulint */ -/*******************************************************//** -Adds a ulint to a dulint. -@return sum a + b */ -UNIV_INLINE -dulint -ut_dulint_add( +ib_uint64_t +ut_ull_create( /*==========*/ - dulint a, /*!< in: dulint */ - ulint b); /*!< in: ulint */ -/*******************************************************//** -Subtracts a ulint from a dulint. -@return a - b */ -UNIV_INLINE -dulint -ut_dulint_subtract( -/*===============*/ - dulint a, /*!< in: dulint */ - ulint b); /*!< in: ulint, b <= a */ -/*******************************************************//** -Subtracts a dulint from another. NOTE that the difference must be positive -and smaller that 4G. -@return a - b */ -UNIV_INLINE -ulint -ut_dulint_minus( -/*============*/ - dulint a, /*!< in: dulint; NOTE a must be >= b and at most - 2 to power 32 - 1 greater */ - dulint b); /*!< in: dulint */ -/********************************************************//** -Rounds a dulint downward to a multiple of a power of 2. -@return rounded value */ -UNIV_INLINE -dulint -ut_dulint_align_down( -/*=================*/ - dulint n, /*!< in: number to be rounded */ - ulint align_no); /*!< in: align by this number which must be a - power of 2 */ -/********************************************************//** -Rounds a dulint upward to a multiple of a power of 2. -@return rounded value */ -UNIV_INLINE -dulint -ut_dulint_align_up( -/*===============*/ - dulint n, /*!< in: number to be rounded */ - ulint align_no); /*!< in: align by this number which must be a - power of 2 */ + ulint high, /*!< in: high-order 32 bits */ + ulint low) /*!< in: low-order 32 bits */ + __attribute__((const)); + /********************************************************//** -Rounds a dulint downward to a multiple of a power of 2. +Rounds a 64-bit integer downward to a multiple of a power of 2. @return rounded value */ UNIV_INLINE ib_uint64_t @@ -184,34 +61,6 @@ ut_uint64_align_up( ib_uint64_t n, /*!< in: number to be rounded */ ulint align_no); /*!< in: align by this number which must be a power of 2 */ -/*******************************************************//** -Increments a dulint variable by 1. */ -#define UT_DULINT_INC(D)\ -{\ - if ((D).low == 0xFFFFFFFFUL) {\ - (D).high = (D).high + 1;\ - (D).low = 0;\ - } else {\ - (D).low = (D).low + 1;\ - }\ -} -/*******************************************************//** -Tests if two dulints are equal. */ -#define UT_DULINT_EQ(D1, D2) (((D1).low == (D2).low)\ - && ((D1).high == (D2).high)) -#ifdef notdefined -/************************************************************//** -Sort function for dulint arrays. */ -UNIV_INTERN -void -ut_dulint_sort( -/*===========*/ - dulint* arr, /*!< in/out: array to be sorted */ - dulint* aux_arr,/*!< in/out: auxiliary array (same size as arr) */ - ulint low, /*!< in: low bound of sort interval, inclusive */ - ulint high); /*!< in: high bound of sort interval, noninclusive */ -#endif /* notdefined */ - /*********************************************************//** The following function rounds up a pointer to the nearest aligned address. @return aligned pointer */ diff --git a/storage/innobase/include/ut0byte.ic b/storage/innobase/include/ut0byte.ic index 3dd51890cb4..e7908efa41a 100644 --- a/storage/innobase/include/ut0byte.ic +++ b/storage/innobase/include/ut0byte.ic @@ -24,260 +24,22 @@ Created 5/30/1994 Heikki Tuuri *******************************************************************/ /*******************************************************//** -Creates a 64-bit dulint out of two ulints. +Creates a 64-bit integer out of two 32-bit integers. @return created dulint */ UNIV_INLINE -dulint -ut_dulint_create( -/*=============*/ +ib_uint64_t +ut_ull_create( +/*==========*/ ulint high, /*!< in: high-order 32 bits */ ulint low) /*!< in: low-order 32 bits */ { - dulint res; - - ut_ad(high <= 0xFFFFFFFF); - ut_ad(low <= 0xFFFFFFFF); - - res.high = high; - res.low = low; - - return(res); -} - -/*******************************************************//** -Gets the high-order 32 bits of a dulint. -@return 32 bits in ulint */ -UNIV_INLINE -ulint -ut_dulint_get_high( -/*===============*/ - dulint d) /*!< in: dulint */ -{ - return(d.high); -} - -/*******************************************************//** -Gets the low-order 32 bits of a dulint. -@return 32 bits in ulint */ -UNIV_INLINE -ulint -ut_dulint_get_low( -/*==============*/ - dulint d) /*!< in: dulint */ -{ - return(d.low); -} - -/*******************************************************//** -Converts a dulint (a struct of 2 ulints) to ib_int64_t, which is a 64-bit -integer type. -@return value in ib_int64_t type */ -UNIV_INLINE -ib_int64_t -ut_conv_dulint_to_longlong( -/*=======================*/ - dulint d) /*!< in: dulint */ -{ - return((ib_int64_t)d.low - + (((ib_int64_t)d.high) << 32)); -} - -/*******************************************************//** -Tests if a dulint is zero. -@return TRUE if zero */ -UNIV_INLINE -ibool -ut_dulint_is_zero( -/*==============*/ - dulint a) /*!< in: dulint */ -{ - if ((a.low == 0) && (a.high == 0)) { - - return(TRUE); - } - - return(FALSE); -} - -/*******************************************************//** -Compares two dulints. -@return -1 if a < b, 0 if a == b, 1 if a > b */ -UNIV_INLINE -int -ut_dulint_cmp( -/*==========*/ - dulint a, /*!< in: dulint */ - dulint b) /*!< in: dulint */ -{ - if (a.high > b.high) { - return(1); - } else if (a.high < b.high) { - return(-1); - } else if (a.low > b.low) { - return(1); - } else if (a.low < b.low) { - return(-1); - } else { - return(0); - } -} - -/*******************************************************//** -Calculates the max of two dulints. -@return max(a, b) */ -UNIV_INLINE -dulint -ut_dulint_get_max( -/*==============*/ - dulint a, /*!< in: dulint */ - dulint b) /*!< in: dulint */ -{ - if (ut_dulint_cmp(a, b) > 0) { - - return(a); - } - - return(b); -} - -/*******************************************************//** -Calculates the min of two dulints. -@return min(a, b) */ -UNIV_INLINE -dulint -ut_dulint_get_min( -/*==============*/ - dulint a, /*!< in: dulint */ - dulint b) /*!< in: dulint */ -{ - if (ut_dulint_cmp(a, b) > 0) { - - return(b); - } - - return(a); -} - -/*******************************************************//** -Adds a ulint to a dulint. -@return sum a + b */ -UNIV_INLINE -dulint -ut_dulint_add( -/*==========*/ - dulint a, /*!< in: dulint */ - ulint b) /*!< in: ulint */ -{ - if (0xFFFFFFFFUL - b >= a.low) { - a.low += b; - - return(a); - } - - a.low = a.low - (0xFFFFFFFFUL - b) - 1; - - a.high++; - - return(a); -} - -/*******************************************************//** -Subtracts a ulint from a dulint. -@return a - b */ -UNIV_INLINE -dulint -ut_dulint_subtract( -/*===============*/ - dulint a, /*!< in: dulint */ - ulint b) /*!< in: ulint, b <= a */ -{ - if (a.low >= b) { - a.low -= b; - - return(a); - } - - b -= a.low + 1; - - a.low = 0xFFFFFFFFUL - b; - - ut_ad(a.high > 0); - - a.high--; - - return(a); -} - -/*******************************************************//** -Subtracts a dulint from another. NOTE that the difference must be positive -and smaller that 4G. -@return a - b */ -UNIV_INLINE -ulint -ut_dulint_minus( -/*============*/ - dulint a, /*!< in: dulint; NOTE a must be >= b and at most - 2 to power 32 - 1 greater */ - dulint b) /*!< in: dulint */ -{ - ulint diff; - - if (a.high == b.high) { - ut_ad(a.low >= b.low); - - return(a.low - b.low); - } - - ut_ad(a.high == b.high + 1); - - diff = (ulint)(0xFFFFFFFFUL - b.low); - diff += 1 + a.low; - - ut_ad(diff > a.low); - - return(diff); -} - -/********************************************************//** -Rounds a dulint downward to a multiple of a power of 2. -@return rounded value */ -UNIV_INLINE -dulint -ut_dulint_align_down( -/*=================*/ - dulint n, /*!< in: number to be rounded */ - ulint align_no) /*!< in: align by this number which must be a - power of 2 */ -{ - ulint low, high; - - ut_ad(align_no > 0); - ut_ad(((align_no - 1) & align_no) == 0); - - low = ut_dulint_get_low(n); - high = ut_dulint_get_high(n); - - low = low & ~(align_no - 1); - - return(ut_dulint_create(high, low)); -} - -/********************************************************//** -Rounds a dulint upward to a multiple of a power of 2. -@return rounded value */ -UNIV_INLINE -dulint -ut_dulint_align_up( -/*===============*/ - dulint n, /*!< in: number to be rounded */ - ulint align_no) /*!< in: align by this number which must be a - power of 2 */ -{ - return(ut_dulint_align_down(ut_dulint_add(n, align_no - 1), align_no)); + ut_ad(high <= ULINT32_MASK); + ut_ad(low <= ULINT32_MASK); + return(((ib_uint64_t) high) << 32 | low); } /********************************************************//** -Rounds ib_uint64_t downward to a multiple of a power of 2. +Rounds a 64-bit integer downward to a multiple of a power of 2. @return rounded value */ UNIV_INLINE ib_uint64_t diff --git a/storage/innobase/include/ut0rnd.h b/storage/innobase/include/ut0rnd.h index ce5152e942f..946b1117af7 100644 --- a/storage/innobase/include/ut0rnd.h +++ b/storage/innobase/include/ut0rnd.h @@ -97,13 +97,13 @@ ut_fold_ulint_pair( ulint n2) /*!< in: ulint */ __attribute__((const)); /*************************************************************//** -Folds a dulint. +Folds a 64-bit integer. @return folded value */ UNIV_INLINE ulint -ut_fold_dulint( -/*===========*/ - dulint d) /*!< in: dulint */ +ut_fold_ull( +/*========*/ + ib_uint64_t d) /*!< in: 64-bit integer */ __attribute__((const)); /*************************************************************//** Folds a character string ending in the null character. diff --git a/storage/innobase/include/ut0rnd.ic b/storage/innobase/include/ut0rnd.ic index c3dbd86923c..a6ba4ec2ba2 100644 --- a/storage/innobase/include/ut0rnd.ic +++ b/storage/innobase/include/ut0rnd.ic @@ -173,16 +173,16 @@ ut_fold_ulint_pair( } /*************************************************************//** -Folds a dulint. +Folds a 64-bit integer. @return folded value */ UNIV_INLINE ulint -ut_fold_dulint( -/*===========*/ - dulint d) /*!< in: dulint */ +ut_fold_ull( +/*========*/ + ib_uint64_t d) /*!< in: 64-bit integer */ { - return(ut_fold_ulint_pair(ut_dulint_get_low(d), - ut_dulint_get_high(d))); + return(ut_fold_ulint_pair((ulint) d & ULINT32_MASK, + (ulint) (d >> 32))); } /*************************************************************//** diff --git a/storage/innobase/lock/lock0lock.c b/storage/innobase/lock/lock0lock.c index 0e57a52666e..dcfca1b6315 100644 --- a/storage/innobase/lock/lock0lock.c +++ b/storage/innobase/lock/lock0lock.c @@ -468,7 +468,7 @@ lock_check_trx_id_sanity( /* A sanity check: the trx_id in rec must be smaller than the global trx id counter */ - if (ut_dulint_cmp(trx_id, trx_sys->max_trx_id) >= 0) { + if (UNIV_UNLIKELY(trx_id >= trx_sys->max_trx_id)) { ut_print_timestamp(stderr); fputs(" InnoDB: Error: transaction id associated" " with record\n", @@ -481,8 +481,7 @@ lock_check_trx_id_sanity( " global trx id counter " TRX_ID_FMT "!\n" "InnoDB: The table is corrupt. You have to do" " dump + drop + reimport.\n", - TRX_ID_PREP_PRINTF(trx_id), - TRX_ID_PREP_PRINTF(trx_sys->max_trx_id)); + (ullint) trx_id, (ullint) trx_sys->max_trx_id); is_ok = FALSE; } @@ -556,9 +555,9 @@ lock_sec_rec_cons_read_sees( } max_trx_id = page_get_max_trx_id(page_align(rec)); - ut_ad(!ut_dulint_is_zero(max_trx_id)); + ut_ad(max_trx_id); - return(ut_dulint_cmp(max_trx_id, view->up_limit_id) < 0); + return(max_trx_id < view->up_limit_id); } /*********************************************************************//** @@ -1594,8 +1593,7 @@ lock_sec_rec_some_has_impl_off_kernel( max trx id to the log, and therefore during recovery, this value for a page may be incorrect. */ - if (!(ut_dulint_cmp(page_get_max_trx_id(page), - trx_list_get_min_trx_id()) >= 0) + if (page_get_max_trx_id(page) < trx_list_get_min_trx_id() && !recv_recovery_is_on()) { return(NULL); @@ -1820,8 +1818,8 @@ lock_rec_enqueue_waiting( #ifdef UNIV_DEBUG if (lock_print_waits) { - fprintf(stderr, "Lock wait for trx %lu in index ", - (ulong) ut_dulint_get_low(trx->id)); + fprintf(stderr, "Lock wait for trx " TRX_ID_FMT " in index ", + (ullint) trx->id); ut_print_name(stderr, trx, FALSE, index->name); } #endif /* UNIV_DEBUG */ @@ -2193,8 +2191,8 @@ lock_grant( #ifdef UNIV_DEBUG if (lock_print_waits) { - fprintf(stderr, "Lock wait for trx %lu ends\n", - (ulong) ut_dulint_get_low(lock->trx->id)); + fprintf(stderr, "Lock wait for trx " TRX_ID_FMT " ends\n", + (ullint) lock->trx->id); } #endif /* UNIV_DEBUG */ @@ -3486,8 +3484,7 @@ lock_deadlock_recursive( } #endif /* UNIV_DEBUG */ - if (trx_weight_cmp(wait_lock->trx, - start) >= 0) { + if (trx_weight_ge(wait_lock->trx, start)) { /* Our recursion starting point transaction is 'smaller', let us choose 'start' as the victim and roll @@ -4023,7 +4020,7 @@ lock_release_off_kernel( ut_ad(lock_get_type_low(lock) & LOCK_TABLE); if (lock_get_mode(lock) != LOCK_IS - && !ut_dulint_is_zero(trx->undo_no)) { + && trx->undo_no != 0) { /* The trx may have modified the table. We block the use of the MySQL query cache for @@ -4222,8 +4219,7 @@ lock_table_print( fputs("TABLE LOCK table ", file); ut_print_name(file, lock->trx, TRUE, lock->un_member.tab_lock.table->name); - fprintf(file, " trx id " TRX_ID_FMT, - TRX_ID_PREP_PRINTF(lock->trx->id)); + fprintf(file, " trx id " TRX_ID_FMT, (ullint) lock->trx->id); if (lock_get_mode(lock) == LOCK_S) { fputs(" lock mode S", file); @@ -4276,8 +4272,7 @@ lock_rec_print( (ulong) space, (ulong) page_no, (ulong) lock_rec_get_n_bits(lock)); dict_index_name_print(file, lock->trx, lock->index); - fprintf(file, " trx id " TRX_ID_FMT, - TRX_ID_PREP_PRINTF(lock->trx->id)); + fprintf(file, " trx id " TRX_ID_FMT, (ullint) lock->trx->id); if (lock_get_mode(lock) == LOCK_S) { fputs(" lock mode S", file); @@ -4412,13 +4407,13 @@ lock_print_info_summary( "------------\n", file); fprintf(file, "Trx id counter " TRX_ID_FMT "\n", - TRX_ID_PREP_PRINTF(trx_sys->max_trx_id)); + (ullint) trx_sys->max_trx_id); fprintf(file, "Purge done for trx's n:o < " TRX_ID_FMT " undo n:o < " TRX_ID_FMT "\n", - TRX_ID_PREP_PRINTF(purge_sys->purge_trx_no), - TRX_ID_PREP_PRINTF(purge_sys->purge_undo_no)); + (ullint) purge_sys->purge_trx_no, + (ullint) purge_sys->purge_undo_no); fprintf(file, "History list length %lu\n", @@ -4495,10 +4490,8 @@ loop: "Trx read view will not see trx with" " id >= " TRX_ID_FMT ", sees < " TRX_ID_FMT "\n", - TRX_ID_PREP_PRINTF( - trx->read_view->low_limit_id), - TRX_ID_PREP_PRINTF( - trx->read_view->up_limit_id)); + (ullint) trx->read_view->low_limit_id, + (ullint) trx->read_view->up_limit_id); } if (trx->que_state == TRX_QUE_LOCK_WAIT) { @@ -4912,12 +4905,12 @@ ibool lock_validate(void) /*===============*/ { - lock_t* lock; - trx_t* trx; - dulint limit; - ulint space; - ulint page_no; - ulint i; + lock_t* lock; + trx_t* trx; + ib_uint64_t limit; + ulint space; + ulint page_no; + ulint i; lock_mutex_enter_kernel(); @@ -4941,20 +4934,21 @@ lock_validate(void) for (i = 0; i < hash_get_n_cells(lock_sys->rec_hash); i++) { - limit = ut_dulint_zero; + limit = 0; for (;;) { lock = HASH_GET_FIRST(lock_sys->rec_hash, i); while (lock) { + ib_uint64_t space_page; ut_a(trx_in_trx_list(lock->trx)); space = lock->un_member.rec_lock.space; page_no = lock->un_member.rec_lock.page_no; - if (ut_dulint_cmp( - ut_dulint_create(space, page_no), - limit) >= 0) { + space_page = ut_ull_create(space, page_no); + + if (space_page >= limit) { break; } @@ -4974,7 +4968,7 @@ lock_validate(void) lock_mutex_enter_kernel(); - limit = ut_dulint_create(space, page_no + 1); + limit = ut_ull_create(space, page_no + 1); } } @@ -5348,8 +5342,7 @@ lock_sec_rec_read_check_and_lock( if the max trx id for the page >= min trx id for the trx list or a database recovery is running. */ - if (((ut_dulint_cmp(page_get_max_trx_id(block->frame), - trx_list_get_min_trx_id()) >= 0) + if ((page_get_max_trx_id(block->frame) >= trx_list_get_min_trx_id() || recv_recovery_is_on()) && !page_rec_is_supremum(rec)) { @@ -5572,12 +5565,12 @@ lock_get_type( Gets the id of the transaction owning a lock. @return transaction id */ UNIV_INTERN -ullint +trx_id_t lock_get_trx_id( /*============*/ const lock_t* lock) /*!< in: lock */ { - return(trx_get_id(lock->trx)); + return(lock->trx->id); } /*******************************************************************//** @@ -5671,7 +5664,7 @@ lock_get_table( Gets the id of the table on which the lock is. @return id of the table */ UNIV_INTERN -ullint +table_id_t lock_get_table_id( /*==============*/ const lock_t* lock) /*!< in: lock */ @@ -5680,7 +5673,7 @@ lock_get_table_id( table = lock_get_table(lock); - return((ullint)ut_conv_dulint_to_longlong(table->id)); + return(table->id); } /*******************************************************************//** diff --git a/storage/innobase/log/log0log.c b/storage/innobase/log/log0log.c index 386f9630baa..401cede1d8f 100644 --- a/storage/innobase/log/log0log.c +++ b/storage/innobase/log/log0log.c @@ -1166,7 +1166,7 @@ log_group_file_header_flush( buf = *(group->file_header_bufs + nth_file); mach_write_to_4(buf + LOG_GROUP_ID, group->id); - mach_write_ull(buf + LOG_FILE_START_LSN, start_lsn); + mach_write_to_8(buf + LOG_FILE_START_LSN, start_lsn); /* Wipe over possible label of ibbackup --restore */ memcpy(buf + LOG_FILE_WAS_CREATED_BY_HOT_BACKUP, " ", 4); @@ -1769,8 +1769,8 @@ log_group_checkpoint( buf = group->checkpoint_buf; - mach_write_ull(buf + LOG_CHECKPOINT_NO, log_sys->next_checkpoint_no); - mach_write_ull(buf + LOG_CHECKPOINT_LSN, log_sys->next_checkpoint_lsn); + mach_write_to_8(buf + LOG_CHECKPOINT_NO, log_sys->next_checkpoint_no); + mach_write_to_8(buf + LOG_CHECKPOINT_LSN, log_sys->next_checkpoint_lsn); mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET, log_group_calc_lsn_offset( @@ -1790,9 +1790,9 @@ log_group_checkpoint( } } - mach_write_ull(buf + LOG_CHECKPOINT_ARCHIVED_LSN, archived_lsn); + mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN, archived_lsn); #else /* UNIV_LOG_ARCHIVE */ - mach_write_ull(buf + LOG_CHECKPOINT_ARCHIVED_LSN, IB_ULONGLONG_MAX); + mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN, IB_ULONGLONG_MAX); #endif /* UNIV_LOG_ARCHIVE */ for (i = 0; i < LOG_MAX_N_GROUPS; i++) { @@ -1884,7 +1884,7 @@ log_reset_first_header_and_checkpoint( ib_uint64_t lsn; mach_write_to_4(hdr_buf + LOG_GROUP_ID, 0); - mach_write_ull(hdr_buf + LOG_FILE_START_LSN, start); + mach_write_to_8(hdr_buf + LOG_FILE_START_LSN, start); lsn = start + LOG_BLOCK_HDR_SIZE; @@ -1896,15 +1896,15 @@ log_reset_first_header_and_checkpoint( + (sizeof "ibbackup ") - 1)); buf = hdr_buf + LOG_CHECKPOINT_1; - mach_write_ull(buf + LOG_CHECKPOINT_NO, 0); - mach_write_ull(buf + LOG_CHECKPOINT_LSN, lsn); + mach_write_to_8(buf + LOG_CHECKPOINT_NO, 0); + mach_write_to_8(buf + LOG_CHECKPOINT_LSN, lsn); mach_write_to_4(buf + LOG_CHECKPOINT_OFFSET, LOG_FILE_HDR_SIZE + LOG_BLOCK_HDR_SIZE); mach_write_to_4(buf + LOG_CHECKPOINT_LOG_BUF_SIZE, 2 * 1024 * 1024); - mach_write_ull(buf + LOG_CHECKPOINT_ARCHIVED_LSN, IB_ULONGLONG_MAX); + mach_write_to_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN, IB_ULONGLONG_MAX); fold = ut_fold_binary(buf, LOG_CHECKPOINT_CHECKSUM_1); mach_write_to_4(buf + LOG_CHECKPOINT_CHECKSUM_1, fold); @@ -2272,7 +2272,7 @@ log_group_archive_file_header_write( buf = *(group->archive_file_header_bufs + nth_file); mach_write_to_4(buf + LOG_GROUP_ID, group->id); - mach_write_ull(buf + LOG_FILE_START_LSN, start_lsn); + mach_write_to_8(buf + LOG_FILE_START_LSN, start_lsn); mach_write_to_4(buf + LOG_FILE_NO, file_no); mach_write_to_4(buf + LOG_FILE_ARCH_COMPLETED, FALSE); @@ -2308,7 +2308,7 @@ log_group_archive_completed_header_write( buf = *(group->archive_file_header_bufs + nth_file); mach_write_to_4(buf + LOG_FILE_ARCH_COMPLETED, TRUE); - mach_write_ull(buf + LOG_FILE_END_LSN, end_lsn); + mach_write_to_8(buf + LOG_FILE_END_LSN, end_lsn); dest_offset = nth_file * group->file_size + LOG_FILE_ARCH_COMPLETED; diff --git a/storage/innobase/log/log0recv.c b/storage/innobase/log/log0recv.c index f47f47e6a68..f983c4fb974 100644 --- a/storage/innobase/log/log0recv.c +++ b/storage/innobase/log/log0recv.c @@ -704,11 +704,11 @@ recv_find_max_checkpoint( group->state = LOG_GROUP_OK; - group->lsn = mach_read_ull( + group->lsn = mach_read_from_8( buf + LOG_CHECKPOINT_LSN); group->lsn_offset = mach_read_from_4( buf + LOG_CHECKPOINT_OFFSET); - checkpoint_no = mach_read_ull( + checkpoint_no = mach_read_from_8( buf + LOG_CHECKPOINT_NO); #ifdef UNIV_DEBUG @@ -778,14 +778,14 @@ recv_read_cp_info_for_backup( cp_buf = hdr + LOG_CHECKPOINT_1; if (recv_check_cp_is_consistent(cp_buf)) { - max_cp_no = mach_read_ull(cp_buf + LOG_CHECKPOINT_NO); + max_cp_no = mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO); max_cp = LOG_CHECKPOINT_1; } cp_buf = hdr + LOG_CHECKPOINT_2; if (recv_check_cp_is_consistent(cp_buf)) { - if (mach_read_ull(cp_buf + LOG_CHECKPOINT_NO) > max_cp_no) { + if (mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO) > max_cp_no) { max_cp = LOG_CHECKPOINT_2; } } @@ -796,7 +796,7 @@ recv_read_cp_info_for_backup( cp_buf = hdr + max_cp; - *lsn = mach_read_ull(cp_buf + LOG_CHECKPOINT_LSN); + *lsn = mach_read_from_8(cp_buf + LOG_CHECKPOINT_LSN); *offset = mach_read_from_4(cp_buf + LOG_CHECKPOINT_OFFSET); /* If the user is running a pre-3.23.50 version of InnoDB, its @@ -816,9 +816,9 @@ recv_read_cp_info_for_backup( /* fprintf(stderr, "fsp limit %lu MB\n", *fsp_limit); */ - *cp_no = mach_read_ull(cp_buf + LOG_CHECKPOINT_NO); + *cp_no = mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO); - *first_header_lsn = mach_read_ull(hdr + LOG_FILE_START_LSN); + *first_header_lsn = mach_read_from_8(hdr + LOG_FILE_START_LSN); return(TRUE); } @@ -1541,7 +1541,7 @@ recv_recover_page_func( #endif /* !UNIV_HOTBACKUP */ /* Read the newest modification lsn from the page */ - page_lsn = mach_read_ull(page + FIL_PAGE_LSN); + page_lsn = mach_read_from_8(page + FIL_PAGE_LSN); #ifndef UNIV_HOTBACKUP /* It may be that the page has been modified in the buffer @@ -1616,14 +1616,14 @@ recv_recover_page_func( block, &mtr); end_lsn = recv->start_lsn + recv->len; - mach_write_ull(FIL_PAGE_LSN + page, end_lsn); - mach_write_ull(UNIV_PAGE_SIZE - - FIL_PAGE_END_LSN_OLD_CHKSUM - + page, end_lsn); + mach_write_to_8(FIL_PAGE_LSN + page, end_lsn); + mach_write_to_8(UNIV_PAGE_SIZE + - FIL_PAGE_END_LSN_OLD_CHKSUM + + page, end_lsn); if (page_zip) { - mach_write_ull(FIL_PAGE_LSN - + page_zip->data, end_lsn); + mach_write_to_8(FIL_PAGE_LSN + + page_zip->data, end_lsn); } } @@ -1995,7 +1995,7 @@ recv_apply_log_recs_for_backup(void) buf_flush_init_for_writing( block->frame, buf_block_get_page_zip(block), - mach_read_ull(block->frame + FIL_PAGE_LSN)); + mach_read_from_8(block->frame + FIL_PAGE_LSN)); if (zip_size) { error = fil_io(OS_FILE_WRITE, TRUE, @@ -2961,9 +2961,9 @@ recv_recovery_from_checkpoint_start_func( buf = log_sys->checkpoint_buf; - checkpoint_lsn = mach_read_ull(buf + LOG_CHECKPOINT_LSN); - checkpoint_no = mach_read_ull(buf + LOG_CHECKPOINT_NO); - archived_lsn = mach_read_ull(buf + LOG_CHECKPOINT_ARCHIVED_LSN); + checkpoint_lsn = mach_read_from_8(buf + LOG_CHECKPOINT_LSN); + checkpoint_no = mach_read_from_8(buf + LOG_CHECKPOINT_NO); + archived_lsn = mach_read_from_8(buf + LOG_CHECKPOINT_ARCHIVED_LSN); /* Read the first log file header to print a note if this is a recovery from a restored InnoDB Hot Backup */ @@ -3613,8 +3613,8 @@ ask_again: return(TRUE); } - start_lsn = mach_read_ull(buf + LOG_FILE_START_LSN); - file_end_lsn = mach_read_ull(buf + LOG_FILE_END_LSN); + start_lsn = mach_read_from_8(buf + LOG_FILE_START_LSN); + file_end_lsn = mach_read_from_8(buf + LOG_FILE_END_LSN); if (!recv_sys->scanned_lsn) { diff --git a/storage/innobase/mach/mach0data.c b/storage/innobase/mach/mach0data.c index e030ce9aadf..647d9e57384 100644 --- a/storage/innobase/mach/mach0data.c +++ b/storage/innobase/mach/mach0data.c @@ -92,43 +92,3 @@ mach_parse_compressed( return(ptr + 5); } } - -/*********************************************************//** -Reads a dulint in a compressed form if the log record fully contains it. -@return pointer to end of the stored field, NULL if not complete */ -UNIV_INTERN -byte* -mach_dulint_parse_compressed( -/*=========================*/ - byte* ptr, /*!< in: pointer to buffer from where to read */ - byte* end_ptr,/*!< in: pointer to end of the buffer */ - dulint* val) /*!< out: read value */ -{ - ulint high; - ulint low; - ulint size; - - ut_ad(ptr && end_ptr && val); - - if (end_ptr < ptr + 5) { - - return(NULL); - } - - high = mach_read_compressed(ptr); - - size = mach_get_compressed_size(high); - - ptr += size; - - if (end_ptr < ptr + 4) { - - return(NULL); - } - - low = mach_read_from_4(ptr); - - *val = ut_dulint_create(high, low); - - return(ptr + 4); -} diff --git a/storage/innobase/mtr/mtr0log.c b/storage/innobase/mtr/mtr0log.c index 3f3dab36b76..04eeb4391cd 100644 --- a/storage/innobase/mtr/mtr0log.c +++ b/storage/innobase/mtr/mtr0log.c @@ -133,7 +133,7 @@ mlog_parse_initial_log_record( } /********************************************************//** -Parses a log record written by mlog_write_ulint or mlog_write_dulint. +Parses a log record written by mlog_write_ulint or mlog_write_ull. @return parsed record end, NULL if not a complete record or a corrupt record */ UNIV_INTERN byte* @@ -145,9 +145,9 @@ mlog_parse_nbytes( byte* page, /*!< in: page where to apply the log record, or NULL */ void* page_zip)/*!< in/out: compressed page, or NULL */ { - ulint offset; - ulint val; - dulint dval; + ulint offset; + ulint val; + ib_uint64_t dval; ut_a(type <= MLOG_8BYTES); ut_a(!page || !page_zip || fil_page_get_type(page) != FIL_PAGE_INDEX); @@ -167,7 +167,7 @@ mlog_parse_nbytes( } if (type == MLOG_8BYTES) { - ptr = mach_dulint_parse_compressed(ptr, end_ptr, &dval); + ptr = mach_ull_parse_compressed(ptr, end_ptr, &dval); if (ptr == NULL) { @@ -290,11 +290,11 @@ Writes 8 bytes to a file page buffered in the buffer pool. Writes the corresponding log record to the mini-transaction log. */ UNIV_INTERN void -mlog_write_dulint( -/*==============*/ - byte* ptr, /*!< in: pointer where to write */ - dulint val, /*!< in: value to write */ - mtr_t* mtr) /*!< in: mini-transaction handle */ +mlog_write_ull( +/*===========*/ + byte* ptr, /*!< in: pointer where to write */ + ib_uint64_t val, /*!< in: value to write */ + mtr_t* mtr) /*!< in: mini-transaction handle */ { byte* log_ptr; @@ -316,7 +316,7 @@ mlog_write_dulint( mach_write_to_2(log_ptr, page_offset(ptr)); log_ptr += 2; - log_ptr += mach_dulint_write_compressed(log_ptr, val); + log_ptr += mach_ull_write_compressed(log_ptr, val); mlog_close(mtr, log_ptr); } diff --git a/storage/innobase/mtr/mtr0mtr.c b/storage/innobase/mtr/mtr0mtr.c index b01462f6b9b..74d04a22b86 100644 --- a/storage/innobase/mtr/mtr0mtr.c +++ b/storage/innobase/mtr/mtr0mtr.c @@ -337,9 +337,12 @@ mtr_memo_release( slot = dyn_array_get_element(memo, offset); if (object == slot->object && type == slot->type) { - if (mtr->modifications) { - mtr_memo_slot_note_modification(mtr, slot); - } + + /* We cannot release a page that has been written + to in the middle of a mini-transaction. */ + + ut_ad(!(mtr->modifications + && slot->type == MTR_MEMO_PAGE_X_FIX)); mtr_memo_slot_release(mtr, slot); @@ -375,23 +378,6 @@ mtr_read_ulint( } } -/********************************************************//** -Reads 8 bytes from a file page buffered in the buffer pool. -@return value read */ -UNIV_INTERN -dulint -mtr_read_dulint( -/*============*/ - const byte* ptr, /*!< in: pointer from where to read */ - mtr_t* mtr __attribute__((unused))) - /*!< in: mini-transaction handle */ -{ - ut_ad(mtr->state == MTR_ACTIVE); - ut_ad(mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_S_FIX) - || mtr_memo_contains_page(mtr, ptr, MTR_MEMO_PAGE_X_FIX)); - return(mach_read_from_8(ptr)); -} - #ifdef UNIV_DEBUG # ifndef UNIV_HOTBACKUP /**********************************************************//** diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c index a7117386608..65c5d65f860 100644 --- a/storage/innobase/os/os0file.c +++ b/storage/innobase/os/os0file.c @@ -183,7 +183,7 @@ struct os_aio_slot_struct{ which pending aio operation was completed */ #ifdef WIN_ASYNC_IO - os_event_t event; /*!< event object we need in the + HANDLE handle; /*!< handle object we need in the OVERLAPPED struct */ OVERLAPPED control; /*!< Windows control block for the aio request */ @@ -225,7 +225,7 @@ struct os_aio_array_struct{ aio array outside the ibuf segment */ os_aio_slot_t* slots; /*!< Pointer to the slots in the array */ #ifdef __WIN__ - os_native_event_t* native_events; + HANDLE* handles; /*!< Pointer to an array of OS native event handles where we copied the handles from slots, in the same @@ -304,7 +304,8 @@ UNIV_INTERN ulint os_n_pending_reads = 0; /***********************************************************************//** Gets the operating system version. Currently works only on Windows. -@return OS_WIN95, OS_WIN31, OS_WINNT, OS_WIN2000 */ +@return OS_WIN95, OS_WIN31, OS_WINNT, OS_WIN2000, OS_WINXP, OS_WINVISTA, +OS_WIN7. */ UNIV_INTERN ulint os_get_os_version(void) @@ -322,10 +323,18 @@ os_get_os_version(void) } else if (os_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { return(OS_WIN95); } else if (os_info.dwPlatformId == VER_PLATFORM_WIN32_NT) { - if (os_info.dwMajorVersion <= 4) { - return(OS_WINNT); - } else { - return(OS_WIN2000); + switch (os_info.dwMajorVersion) { + case 3: + case 4: + return OS_WINNT; + case 5: + return (os_info.dwMinorVersion == 0) ? OS_WIN2000 + : OS_WINXP; + case 6: + return (os_info.dwMinorVersion == 0) ? OS_WINVISTA + : OS_WIN7; + default: + return OS_WIN7; } } else { ut_error; @@ -673,10 +682,10 @@ os_io_init_simple(void) { ulint i; - os_file_count_mutex = os_mutex_create(NULL); + os_file_count_mutex = os_mutex_create(); for (i = 0; i < OS_FILE_N_SEEK_MUTEXES; i++) { - os_file_seek_mutexes[i] = os_mutex_create(NULL); + os_file_seek_mutexes[i] = os_mutex_create(); } } @@ -3217,7 +3226,7 @@ os_aio_array_create( array = ut_malloc(sizeof(os_aio_array_t)); - array->mutex = os_mutex_create(NULL); + array->mutex = os_mutex_create(); array->not_full = os_event_create(NULL); array->is_empty = os_event_create(NULL); @@ -3229,10 +3238,13 @@ os_aio_array_create( 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)); + array->handles = ut_malloc(n * sizeof(HANDLE)); #endif #if defined(LINUX_NATIVE_AIO) + array->aio_ctx = NULL; + array->aio_events = NULL; + /* If we are not using native aio interface then skip this part of initialization. */ if (!srv_use_native_aio) { @@ -3270,13 +3282,13 @@ skip_native_aio: slot->pos = i; slot->reserved = FALSE; #ifdef WIN_ASYNC_IO - slot->event = os_event_create(NULL); + slot->handle = CreateEvent(NULL,TRUE, FALSE, NULL); over = &(slot->control); - over->hEvent = slot->event->handle; + over->hEvent = slot->handle; - *((array->native_events) + i) = over->hEvent; + *((array->handles) + i) = over->hEvent; #elif defined(LINUX_NATIVE_AIO) @@ -3302,17 +3314,24 @@ os_aio_array_free( for (i = 0; i < array->n_slots; i++) { os_aio_slot_t* slot = os_aio_array_get_nth_slot(array, i); - os_event_free(slot->event); + CloseHandle(slot->handle); } #endif /* WIN_ASYNC_IO */ #ifdef __WIN__ - ut_free(array->native_events); + ut_free(array->handles); #endif /* __WIN__ */ os_mutex_free(array->mutex); os_event_free(array->not_full); os_event_free(array->is_empty); +#if defined(LINUX_NATIVE_AIO) + if (srv_use_native_aio) { + ut_free(array->aio_events); + ut_free(array->aio_ctx); + } +#endif /* LINUX_NATIVE_AIO */ + ut_free(array->slots); ut_free(array); } @@ -3453,7 +3472,7 @@ os_aio_array_wake_win_aio_at_shutdown( for (i = 0; i < array->n_slots; i++) { - os_event_set((array->slots + i)->event); + SetEvent((array->slots + i)->handle); } } #endif @@ -3692,7 +3711,7 @@ found: control = &(slot->control); control->Offset = (DWORD)offset; control->OffsetHigh = (DWORD)offset_high; - os_event_reset(slot->event); + ResetEvent(slot->handle); #elif defined(LINUX_NATIVE_AIO) @@ -3764,7 +3783,7 @@ os_aio_array_free_slot( #ifdef WIN_ASYNC_IO - os_event_reset(slot->event); + ResetEvent(slot->handle); #elif defined(LINUX_NATIVE_AIO) @@ -4198,13 +4217,20 @@ os_aio_windows_handle( n = array->n_slots / array->n_segments; if (array == os_aio_sync_array) { - os_event_wait(os_aio_array_get_nth_slot(array, pos)->event); + WaitForSingleObject( + os_aio_array_get_nth_slot(array, pos)->handle, + INFINITE); i = pos; } else { srv_set_io_thread_op_info(orig_seg, "wait Windows aio"); - i = os_event_wait_multiple(n, - (array->native_events) - + segment * n); + i = WaitForMultipleObjects((DWORD) n, + array->handles + segment * n, + FALSE, + INFINITE); + } + + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + os_thread_exit(NULL); } os_mutex_enter(array->mutex); diff --git a/storage/innobase/os/os0sync.c b/storage/innobase/os/os0sync.c index 60467242e14..3c70e93aae0 100644 --- a/storage/innobase/os/os0sync.c +++ b/storage/innobase/os/os0sync.c @@ -35,6 +35,7 @@ Created 9/6/1995 Heikki Tuuri #include "ut0mem.h" #include "srv0start.h" +#include "srv0srv.h" /* Type definition for an operating system mutex struct */ struct os_mutex_struct{ @@ -76,6 +77,155 @@ event embedded inside a mutex, on free, this generates a recursive call. This version of the free event function doesn't acquire the global lock */ static void os_event_free_internal(os_event_t event); +/* On Windows (Vista and later), load function pointers for condition +variable handling. Those functions are not available in prior versions, +so we have to use them via runtime loading, as long as we support XP. */ +static void os_cond_module_init(void); + +#ifdef __WIN__ +/* Prototypes and function pointers for condition variable functions */ +typedef VOID (WINAPI* InitializeConditionVariableProc) + (PCONDITION_VARIABLE ConditionVariable); +static InitializeConditionVariableProc initialize_condition_variable; + +typedef BOOL (WINAPI* SleepConditionVariableCSProc) + (PCONDITION_VARIABLE ConditionVariable, + PCRITICAL_SECTION CriticalSection, + DWORD dwMilliseconds); +static SleepConditionVariableCSProc sleep_condition_variable; + +typedef VOID (WINAPI* WakeAllConditionVariableProc) + (PCONDITION_VARIABLE ConditionVariable); +static WakeAllConditionVariableProc wake_all_condition_variable; + +typedef VOID (WINAPI* WakeConditionVariableProc) + (PCONDITION_VARIABLE ConditionVariable); +static WakeConditionVariableProc wake_condition_variable; +#endif + +/*********************************************************//** +Initialitze condition variable */ +UNIV_INLINE +void +os_cond_init( +/*=========*/ + os_cond_t* cond) /*!< in: condition variable. */ +{ + ut_a(cond); + +#ifdef __WIN__ + ut_a(initialize_condition_variable != NULL); + initialize_condition_variable(cond); +#else + ut_a(pthread_cond_init(cond, NULL) == 0); +#endif +} + +/*********************************************************//** +Wait on condition variable */ +UNIV_INLINE +void +os_cond_wait( +/*=========*/ + os_cond_t* cond, /*!< in: condition variable. */ + os_fast_mutex_t* mutex) /*!< in: fast mutex */ +{ + ut_a(cond); + ut_a(mutex); + +#ifdef __WIN__ + ut_a(sleep_condition_variable != NULL); + ut_a(sleep_condition_variable(cond, mutex, INFINITE)); +#else + ut_a(pthread_cond_wait(cond, mutex) == 0); +#endif +} + +/*********************************************************//** +Wakes all threads waiting for condition variable */ +UNIV_INLINE +void +os_cond_broadcast( +/*==============*/ + os_cond_t* cond) /*!< in: condition variable. */ +{ + ut_a(cond); + +#ifdef __WIN__ + ut_a(wake_all_condition_variable != NULL); + wake_all_condition_variable(cond); +#else + ut_a(pthread_cond_broadcast(cond) == 0); +#endif +} + +/*********************************************************//** +Wakes one thread waiting for condition variable */ +UNIV_INLINE +void +os_cond_signal( +/*==========*/ + os_cond_t* cond) /*!< in: condition variable. */ +{ + ut_a(cond); + +#ifdef __WIN__ + ut_a(wake_condition_variable != NULL); + wake_condition_variable(cond); +#else + ut_a(pthread_cond_signal(cond) == 0); +#endif +} + +/*********************************************************//** +Destroys condition variable */ +UNIV_INLINE +void +os_cond_destroy( +/*============*/ + os_cond_t* cond) /*!< in: condition variable. */ +{ +#ifdef __WIN__ + /* Do nothing */ +#else + ut_a(pthread_cond_destroy(cond) == 0); +#endif +} + +/*********************************************************//** +On Windows (Vista and later), load function pointers for condition variable +handling. Those functions are not available in prior versions, so we have to +use them via runtime loading, as long as we support XP. */ +static +void +os_cond_module_init(void) +/*=====================*/ +{ +#ifdef __WIN__ + HMODULE h_dll; + + if (!srv_use_native_conditions) + return; + + h_dll = GetModuleHandle("kernel32"); + + initialize_condition_variable = (InitializeConditionVariableProc) + GetProcAddress(h_dll, "InitializeConditionVariable"); + sleep_condition_variable = (SleepConditionVariableCSProc) + GetProcAddress(h_dll, "SleepConditionVariableCS"); + wake_all_condition_variable = (WakeAllConditionVariableProc) + GetProcAddress(h_dll, "WakeAllConditionVariable"); + wake_condition_variable = (WakeConditionVariableProc) + GetProcAddress(h_dll, "WakeConditionVariable"); + + /* When using native condition variables, check function pointers */ + ut_a(initialize_condition_variable); + ut_a(sleep_condition_variable); + ut_a(wake_all_condition_variable); + ut_a(wake_condition_variable); +#endif +} + /*********************************************************//** Initializes global event and OS 'slow' mutex lists. */ UNIV_INTERN @@ -89,7 +239,10 @@ os_sync_init(void) os_sync_mutex = NULL; os_sync_mutex_inited = FALSE; - os_sync_mutex = os_mutex_create(NULL); + /* Now for Windows only */ + os_cond_module_init(); + + os_sync_mutex = os_mutex_create(); os_sync_mutex_inited = TRUE; } @@ -143,42 +296,45 @@ os_event_create( const char* name) /*!< in: the name of the event, if NULL the event is created without a name */ { -#ifdef __WIN__ - os_event_t event; - - event = ut_malloc(sizeof(struct os_event_struct)); - - event->handle = CreateEvent(NULL, /* No security attributes */ - TRUE, /* Manual reset */ - FALSE, /* Initial state nonsignaled */ - (LPCTSTR) name); - if (!event->handle) { - fprintf(stderr, - "InnoDB: Could not create a Windows event semaphore;" - " Windows error %lu\n", - (ulong) GetLastError()); - } -#else /* Unix */ os_event_t event; - UT_NOT_USED(name); +#ifdef __WIN__ + if(!srv_use_native_conditions) { + + event = ut_malloc(sizeof(struct os_event_struct)); + + event->handle = CreateEvent(NULL, + TRUE, + FALSE, + (LPCTSTR) name); + if (!event->handle) { + fprintf(stderr, + "InnoDB: Could not create a Windows event" + " semaphore; Windows error %lu\n", + (ulong) GetLastError()); + } + } else /* Windows with condition variables */ +#endif - event = ut_malloc(sizeof(struct os_event_struct)); + { + UT_NOT_USED(name); - os_fast_mutex_init(&(event->os_mutex)); + event = ut_malloc(sizeof(struct os_event_struct)); - ut_a(0 == pthread_cond_init(&(event->cond_var), NULL)); + os_fast_mutex_init(&(event->os_mutex)); - event->is_set = FALSE; + os_cond_init(&(event->cond_var)); - /* We return this value in os_event_reset(), which can then be - be used to pass to the os_event_wait_low(). The value of zero - is reserved in os_event_wait_low() for the case when the - caller does not want to pass any signal_count value. To - distinguish between the two cases we initialize signal_count - to 1 here. */ - event->signal_count = 1; -#endif /* __WIN__ */ + event->is_set = FALSE; + + /* We return this value in os_event_reset(), which can then be + be used to pass to the os_event_wait_low(). The value of zero + is reserved in os_event_wait_low() for the case when the + caller does not want to pass any signal_count value. To + distinguish between the two cases we initialize signal_count + to 1 here. */ + event->signal_count = 1; + } /* The os_sync_mutex can be NULL because during startup an event can be created [ because it's embedded in the mutex/rwlock ] before @@ -208,10 +364,15 @@ os_event_set( /*=========*/ os_event_t event) /*!< in: event to set */ { -#ifdef __WIN__ ut_a(event); - ut_a(SetEvent(event->handle)); -#else + +#ifdef __WIN__ + if (!srv_use_native_conditions) { + ut_a(SetEvent(event->handle)); + return; + } +#endif + ut_a(event); os_fast_mutex_lock(&(event->os_mutex)); @@ -221,11 +382,10 @@ os_event_set( } else { event->is_set = TRUE; event->signal_count += 1; - ut_a(0 == pthread_cond_broadcast(&(event->cond_var))); + os_cond_broadcast(&(event->cond_var)); } os_fast_mutex_unlock(&(event->os_mutex)); -#endif } /**********************************************************//** @@ -244,12 +404,14 @@ os_event_reset( { ib_int64_t ret = 0; -#ifdef __WIN__ ut_a(event); - ut_a(ResetEvent(event->handle)); -#else - ut_a(event); +#ifdef __WIN__ + if(!srv_use_native_conditions) { + ut_a(ResetEvent(event->handle)); + return(0); + } +#endif os_fast_mutex_lock(&(event->os_mutex)); @@ -261,7 +423,6 @@ os_event_reset( ret = event->signal_count; os_fast_mutex_unlock(&(event->os_mutex)); -#endif return(ret); } @@ -274,19 +435,21 @@ os_event_free_internal( os_event_t event) /*!< in: event to free */ { #ifdef __WIN__ - ut_a(event); + if(!srv_use_native_conditions) { + ut_a(event); + ut_a(CloseHandle(event->handle)); + } else +#endif + { + ut_a(event); - ut_a(CloseHandle(event->handle)); -#else - ut_a(event); + /* This is to avoid freeing the mutex twice */ + os_fast_mutex_free(&(event->os_mutex)); - /* This is to avoid freeing the mutex twice */ - os_fast_mutex_free(&(event->os_mutex)); + os_cond_destroy(&(event->cond_var)); + } - ut_a(0 == pthread_cond_destroy(&(event->cond_var))); -#endif /* Remove from the list of events */ - UT_LIST_REMOVE(os_event_list, os_event_list, event); os_event_count--; @@ -303,18 +466,19 @@ os_event_free( os_event_t event) /*!< in: event to free */ { -#ifdef __WIN__ ut_a(event); +#ifdef __WIN__ + if(!srv_use_native_conditions){ + ut_a(CloseHandle(event->handle)); + } else /*Windows with condition variables */ +#endif + { + os_fast_mutex_free(&(event->os_mutex)); - ut_a(CloseHandle(event->handle)); -#else - ut_a(event); + os_cond_destroy(&(event->cond_var)); + } - os_fast_mutex_free(&(event->os_mutex)); - ut_a(0 == pthread_cond_destroy(&(event->cond_var))); -#endif /* Remove from the list of events */ - os_mutex_enter(os_sync_mutex); UT_LIST_REMOVE(os_event_list, os_event_list, event); @@ -355,23 +519,27 @@ os_event_wait_low( returned by previous call of os_event_reset(). */ { + ib_int64_t old_signal_count; + #ifdef __WIN__ - DWORD err; + if(!srv_use_native_conditions) { + DWORD err; - ut_a(event); + ut_a(event); - UT_NOT_USED(reset_sig_count); + UT_NOT_USED(reset_sig_count); - /* Specify an infinite time limit for waiting */ - err = WaitForSingleObject(event->handle, INFINITE); + /* Specify an infinite wait */ + err = WaitForSingleObject(event->handle, INFINITE); - ut_a(err == WAIT_OBJECT_0); + ut_a(err == WAIT_OBJECT_0); - if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { - os_thread_exit(NULL); + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + os_thread_exit(NULL); + } + return; } -#else - ib_int64_t old_signal_count; +#endif os_fast_mutex_lock(&(event->os_mutex)); @@ -396,93 +564,13 @@ os_event_wait_low( return; } - pthread_cond_wait(&(event->cond_var), &(event->os_mutex)); + os_cond_wait(&(event->cond_var), &(event->os_mutex)); /* Solaris manual said that spurious wakeups may occur: we have to check if the event really has been signaled after we came here to wait */ } -#endif -} - -/**********************************************************//** -Waits for an event object until it is in the signaled state or -a timeout is exceeded. In Unix the timeout is always infinite. -@return 0 if success, OS_SYNC_TIME_EXCEEDED if timeout was exceeded */ -UNIV_INTERN -ulint -os_event_wait_time( -/*===============*/ - os_event_t event, /*!< in: event to wait */ - ulint time) /*!< in: timeout in microseconds, or - OS_SYNC_INFINITE_TIME */ -{ -#ifdef __WIN__ - DWORD err; - - ut_a(event); - - if (time != OS_SYNC_INFINITE_TIME) { - err = WaitForSingleObject(event->handle, (DWORD) time / 1000); - } else { - err = WaitForSingleObject(event->handle, INFINITE); - } - - if (err == WAIT_OBJECT_0) { - - return(0); - } else if (err == WAIT_TIMEOUT) { - - return(OS_SYNC_TIME_EXCEEDED); - } else { - ut_error; - return(1000000); /* dummy value to eliminate compiler warn. */ - } -#else - UT_NOT_USED(time); - - /* In Posix this is just an ordinary, infinite wait */ - - os_event_wait(event); - - return(0); -#endif -} - -#ifdef __WIN__ -/**********************************************************//** -Waits for any event in an OS native event array. Returns if even a single -one is signaled or becomes signaled. -@return index of the event which was signaled */ -UNIV_INTERN -ulint -os_event_wait_multiple( -/*===================*/ - ulint n, /*!< in: number of events in the - array */ - os_native_event_t* native_event_array) - /*!< in: pointer to an array of event - handles */ -{ - DWORD index; - - ut_a(native_event_array); - ut_a(n > 0); - - index = WaitForMultipleObjects((DWORD) n, native_event_array, - FALSE, /* Wait for any 1 event */ - INFINITE); /* Infinite wait time - limit */ - ut_a(index >= WAIT_OBJECT_0); /* NOTE: Pointless comparison */ - ut_a(index < WAIT_OBJECT_0 + n); - - if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { - os_thread_exit(NULL); - } - - return(index - WAIT_OBJECT_0); } -#endif /*********************************************************//** Creates an operating system mutex semaphore. Because these are slow, the @@ -490,29 +578,15 @@ mutex semaphore of InnoDB itself (mutex_t) should be used where possible. @return the mutex handle */ UNIV_INTERN os_mutex_t -os_mutex_create( -/*============*/ - const char* name) /*!< in: the name of the mutex, if NULL - the mutex is created without a name */ +os_mutex_create(void) +/*=================*/ { -#ifdef __WIN__ - HANDLE mutex; - os_mutex_t mutex_str; - - mutex = CreateMutex(NULL, /* No security attributes */ - FALSE, /* Initial state: no owner */ - (LPCTSTR) name); - ut_a(mutex); -#else os_fast_mutex_t* mutex; os_mutex_t mutex_str; - UT_NOT_USED(name); - mutex = ut_malloc(sizeof(os_fast_mutex_t)); os_fast_mutex_init(mutex); -#endif mutex_str = ut_malloc(sizeof(os_mutex_str_t)); mutex_str->handle = mutex; @@ -543,25 +617,11 @@ os_mutex_enter( /*===========*/ os_mutex_t mutex) /*!< in: mutex to acquire */ { -#ifdef __WIN__ - DWORD err; - - ut_a(mutex); - - /* Specify infinite time limit for waiting */ - err = WaitForSingleObject(mutex->handle, INFINITE); - - ut_a(err == WAIT_OBJECT_0); - - (mutex->count)++; - ut_a(mutex->count == 1); -#else os_fast_mutex_lock(mutex->handle); (mutex->count)++; ut_a(mutex->count == 1); -#endif } /**********************************************************//** @@ -577,11 +637,7 @@ os_mutex_exit( ut_a(mutex->count == 1); (mutex->count)--; -#ifdef __WIN__ - ut_a(ReleaseMutex(mutex->handle)); -#else os_fast_mutex_unlock(mutex->handle); -#endif } /**********************************************************//** @@ -610,15 +666,9 @@ os_mutex_free( os_mutex_exit(os_sync_mutex); } -#ifdef __WIN__ - ut_a(CloseHandle(mutex->handle)); - - ut_free(mutex); -#else os_fast_mutex_free(mutex->handle); ut_free(mutex->handle); ut_free(mutex); -#endif } /*********************************************************//** diff --git a/storage/innobase/os/os0thread.c b/storage/innobase/os/os0thread.c index 632199b56bc..adc876be5d5 100644 --- a/storage/innobase/os/os0thread.c +++ b/storage/innobase/os/os0thread.c @@ -242,7 +242,7 @@ os_thread_yield(void) /*=================*/ { #if defined(__WIN__) - Sleep(0); + SwitchToThread(); #elif (defined(HAVE_SCHED_YIELD) && defined(HAVE_SCHED_H)) sched_yield(); #elif defined(HAVE_PTHREAD_YIELD_ZERO_ARG) diff --git a/storage/innobase/page/page0page.c b/storage/innobase/page/page0page.c index 10008f9ac25..2e785412ac9 100644 --- a/storage/innobase/page/page0page.c +++ b/storage/innobase/page/page0page.c @@ -235,8 +235,8 @@ page_set_max_trx_id( 8, mtr); #ifndef UNIV_HOTBACKUP } else if (mtr) { - mlog_write_dulint(page + (PAGE_HEADER + PAGE_MAX_TRX_ID), - trx_id, mtr); + mlog_write_ull(page + (PAGE_HEADER + PAGE_MAX_TRX_ID), + trx_id, mtr); #endif /* !UNIV_HOTBACKUP */ } else { mach_write_to_8(page + (PAGE_HEADER + PAGE_MAX_TRX_ID), trx_id); @@ -457,7 +457,7 @@ page_create_low( page_header_set_field(page, NULL, PAGE_DIRECTION, PAGE_NO_DIRECTION); page_header_set_field(page, NULL, PAGE_N_DIRECTION, 0); page_header_set_field(page, NULL, PAGE_N_RECS, 0); - page_set_max_trx_id(block, NULL, ut_dulint_zero, NULL); + page_set_max_trx_id(block, NULL, 0, NULL); memset(heap_top, 0, UNIV_PAGE_SIZE - PAGE_EMPTY_DIR_START - page_offset(heap_top)); diff --git a/storage/innobase/page/page0zip.c b/storage/innobase/page/page0zip.c index 14ec3e7a94f..98640a8e6fb 100644 --- a/storage/innobase/page/page0zip.c +++ b/storage/innobase/page/page0zip.c @@ -1464,6 +1464,7 @@ page_zip_fields_free( dict_table_t* table = index->table; mem_heap_free(index->heap); mutex_free(&(table->autoinc_mutex)); + ut_free(table->name); mem_heap_free(table->heap); } } @@ -4467,7 +4468,7 @@ page_zip_reorganize( /* Copy max trx id to recreated page */ trx_id_t max_trx_id = page_get_max_trx_id(temp_page); page_set_max_trx_id(block, NULL, max_trx_id, NULL); - ut_ad(!ut_dulint_is_zero(max_trx_id)); + ut_ad(max_trx_id != 0); } /* Restore logging. */ @@ -4527,7 +4528,7 @@ page_zip_copy_recs( /* The PAGE_MAX_TRX_ID must be set on leaf pages of secondary indexes. It does not matter on other pages. */ ut_a(dict_index_is_clust(index) || !page_is_leaf(src) - || !ut_dulint_is_zero(page_get_max_trx_id(src))); + || page_get_max_trx_id(src)); UNIV_MEM_ASSERT_W(page, UNIV_PAGE_SIZE); UNIV_MEM_ASSERT_W(page_zip->data, page_zip_get_size(page_zip)); diff --git a/storage/innobase/pars/pars0pars.c b/storage/innobase/pars/pars0pars.c index 613e7962f0e..ef107f2896f 100644 --- a/storage/innobase/pars/pars0pars.c +++ b/storage/innobase/pars/pars0pars.c @@ -2031,29 +2031,6 @@ 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); @@ -2061,11 +2038,11 @@ except that the buffer is dynamically allocated from the info struct's heap. */ UNIV_INTERN void -pars_info_add_dulint_literal( -/*=========================*/ +pars_info_add_ull_literal( +/*======================*/ pars_info_t* info, /*!< in: info struct */ const char* name, /*!< in: name */ - dulint val) /*!< in: value */ + ib_uint64_t val) /*!< in: value */ { byte* buf = mem_heap_alloc(info->heap, 8); diff --git a/storage/innobase/read/read0read.c b/storage/innobase/read/read0read.c index 85adae4ddff..9975b8c2c57 100644 --- a/storage/innobase/read/read0read.c +++ b/storage/innobase/read/read0read.c @@ -168,8 +168,7 @@ read_view_t* read_view_oldest_copy_or_open_new( /*==============================*/ trx_id_t cr_trx_id, /*!< in: trx_id of creating - transaction, or ut_dulint_zero - used in purge */ + transaction, or 0 used in purge */ mem_heap_t* heap) /*!< in: memory heap from which allocated */ { @@ -191,7 +190,7 @@ read_view_oldest_copy_or_open_new( n = old_view->n_trx_ids; - if (!ut_dulint_is_zero(old_view->creator_trx_id)) { + if (old_view->creator_trx_id) { n++; } else { needs_insert = FALSE; @@ -206,9 +205,8 @@ read_view_oldest_copy_or_open_new( while (i < n) { if (needs_insert && (i >= old_view->n_trx_ids - || ut_dulint_cmp(old_view->creator_trx_id, - read_view_get_nth_trx_id(old_view, i)) - > 0)) { + || old_view->creator_trx_id + > read_view_get_nth_trx_id(old_view, i))) { read_view_set_nth_trx_id(view_copy, i, old_view->creator_trx_id); @@ -252,8 +250,7 @@ read_view_t* read_view_open_now( /*===============*/ trx_id_t cr_trx_id, /*!< in: trx_id of creating - transaction, or ut_dulint_zero - used in purge */ + transaction, or 0 used in purge */ mem_heap_t* heap) /*!< in: memory heap from which allocated */ { @@ -267,7 +264,7 @@ read_view_open_now( view->creator_trx_id = cr_trx_id; view->type = VIEW_NORMAL; - view->undo_no = ut_dulint_zero; + view->undo_no = 0; /* No future transactions should be visible in the view */ @@ -280,7 +277,7 @@ read_view_open_now( /* No active transaction should be visible, except cr_trx */ while (trx) { - if (ut_dulint_cmp(trx->id, cr_trx_id) != 0 + if (trx->id != cr_trx_id && (trx->conc_state == TRX_ACTIVE || trx->conc_state == TRX_PREPARED)) { @@ -292,9 +289,9 @@ read_view_open_now( trx_sys->max_trx_id can still be active, if it is in the middle of its commit! Note that when a transaction starts, we initialize trx->no to - ut_dulint_max. */ + IB_ULONGLONG_MAX. */ - if (ut_dulint_cmp(view->low_limit_no, trx->no) > 0) { + if (view->low_limit_no > trx->no) { view->low_limit_no = trx->no; } @@ -367,22 +364,20 @@ read_view_print( if (view->type == VIEW_HIGH_GRANULARITY) { fprintf(stderr, - "High-granularity read view undo_n:o %lu %lu\n", - (ulong) ut_dulint_get_high(view->undo_no), - (ulong) ut_dulint_get_low(view->undo_no)); + "High-granularity read view undo_n:o %llu\n", + (ullint) view->undo_no); } else { fprintf(stderr, "Normal read view\n"); } - fprintf(stderr, "Read view low limit trx n:o %lu %lu\n", - (ulong) ut_dulint_get_high(view->low_limit_no), - (ulong) ut_dulint_get_low(view->low_limit_no)); + fprintf(stderr, "Read view low limit trx n:o " TRX_ID_FMT "\n", + (ullint) view->low_limit_no); fprintf(stderr, "Read view up limit trx id " TRX_ID_FMT "\n", - TRX_ID_PREP_PRINTF(view->up_limit_id)); + (ullint) view->up_limit_id); fprintf(stderr, "Read view low limit trx id " TRX_ID_FMT "\n", - TRX_ID_PREP_PRINTF(view->low_limit_id)); + (ullint) view->low_limit_id); fprintf(stderr, "Read view individually stored trx ids:\n"); @@ -390,8 +385,7 @@ read_view_print( for (i = 0; i < n_ids; i++) { fprintf(stderr, "Read view trx id " TRX_ID_FMT "\n", - TRX_ID_PREP_PRINTF( - read_view_get_nth_trx_id(view, i))); + (ullint) read_view_get_nth_trx_id(view, i)); } } @@ -460,9 +454,9 @@ read_cursor_view_create_for_mysql( trx_sys->max_trx_id can still be active, if it is in the middle of its commit! Note that when a transaction starts, we initialize trx->no to - ut_dulint_max. */ + IB_ULONGLONG_MAX. */ - if (ut_dulint_cmp(view->low_limit_no, trx->no) > 0) { + if (view->low_limit_no > trx->no) { view->low_limit_no = trx->no; } diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index c882a065cd1..8fd8c4f8532 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -51,6 +51,15 @@ Created 4/20/1996 Heikki Tuuri #define ROW_INS_PREV 1 #define ROW_INS_NEXT 2 +/************************************************************************* +IMPORTANT NOTE: Any operation that generates redo MUST check that there +is enough space in the redo log before for that operation. This is +done by calling log_free_check(). The reason for checking the +availability of the redo log space before the start of the operation is +that we MUST not hold any synchonization objects when performing the +check. +If you make a change in this module make sure that no codepath is +introduced where a call to log_free_check() is bypassed. */ /*********************************************************************//** Creates an insert node struct. @@ -78,7 +87,7 @@ ins_node_create( node->select = NULL; - node->trx_id = ut_dulint_zero; + node->trx_id = 0; node->entry_sys_heap = mem_heap_create(128); @@ -198,7 +207,7 @@ ins_node_set_new_row( /* As we allocated a new trx id buf, the trx id should be written there again: */ - node->trx_id = ut_dulint_zero; + node->trx_id = 0; } /*******************************************************************//** @@ -506,8 +515,7 @@ row_ins_cascade_calc_update_vec( if (!dfield_is_null(&ufield->new_val) && dtype_get_at_most_n_mbchars( - col->prtype, - col->mbminlen, col->mbmaxlen, + col->prtype, col->mbminmaxlen, col->len, ufield_len, dfield_get_data(&ufield->new_val)) @@ -530,49 +538,37 @@ row_ins_cascade_calc_update_vec( if (min_size > ufield_len) { - char* pad_start; - const char* pad_end; - char* padded_data - = mem_heap_alloc( - heap, min_size); - pad_start = padded_data + ufield_len; - pad_end = padded_data + min_size; + byte* pad; + ulint pad_len; + byte* padded_data; + ulint mbminlen; + + padded_data = mem_heap_alloc( + heap, min_size); + + pad = padded_data + ufield_len; + pad_len = min_size - ufield_len; memcpy(padded_data, dfield_get_data(&ufield ->new_val), - dfield_get_len(&ufield - ->new_val)); + ufield_len); - switch (UNIV_EXPECT(col->mbminlen,1)) { - default: - ut_error; - return(ULINT_UNDEFINED); - case 1: - if (UNIV_UNLIKELY - (dtype_get_charset_coll( - col->prtype) - == DATA_MYSQL_BINARY_CHARSET_COLL)) { - /* Do not pad BINARY - columns. */ - return(ULINT_UNDEFINED); - } + mbminlen = dict_col_get_mbminlen(col); + + ut_ad(!(ufield_len % mbminlen)); + ut_ad(!(min_size % mbminlen)); - /* space=0x20 */ - memset(pad_start, 0x20, - pad_end - pad_start); - break; - case 2: - /* space=0x0020 */ - ut_a(!(ufield_len % 2)); - ut_a(!(min_size % 2)); - do { - *pad_start++ = 0x00; - *pad_start++ = 0x20; - } while (pad_start < pad_end); - break; + if (mbminlen == 1 + && dtype_get_charset_coll( + col->prtype) + == DATA_MYSQL_BINARY_CHARSET_COLL) { + /* Do not pad BINARY columns */ + return(ULINT_UNDEFINED); } + row_mysql_pad_col(mbminlen, + pad, pad_len); dfield_set_data(&ufield->new_val, padded_data, min_size); } @@ -2223,7 +2219,7 @@ row_ins_index_entry_set_vals( = dict_field_get_col(ind_field); len = dtype_get_at_most_n_mbchars( - col->prtype, col->mbminlen, col->mbmaxlen, + col->prtype, col->mbminmaxlen, ind_field->prefix_len, len, dfield_get_data(row_field)); @@ -2270,7 +2266,7 @@ row_ins_alloc_row_id_step( /*======================*/ ins_node_t* node) /*!< in: row insert node */ { - dulint row_id; + row_id_t row_id; ut_ad(node->state == INS_NODE_ALLOC_ROW_ID); @@ -2457,7 +2453,7 @@ row_ins_step( /* It may be that the current session has not yet started its transaction, or it has been committed: */ - if (UT_DULINT_EQ(trx->id, node->trx_id)) { + if (trx->id == node->trx_id) { /* No need to do IX-locking */ goto same_trx; diff --git a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c index eac2f9fb377..38ec4bff08f 100644 --- a/storage/innobase/row/row0merge.c +++ b/storage/innobase/row/row0merge.c @@ -338,7 +338,7 @@ row_merge_buf_add( if (ifield->prefix_len) { len = dtype_get_at_most_n_mbchars( col->prtype, - col->mbminlen, col->mbmaxlen, + col->mbminmaxlen, ifield->prefix_len, len, dfield_get_data(field)); dfield_set_len(field, len); @@ -1779,6 +1779,11 @@ row_merge_copy_blobs( (below). */ data = btr_rec_copy_externally_stored_field( mrec, offsets, zip_size, i, &len, heap); + /* Because we have locked the table, any records + written by incomplete transactions must have been + rolled back already. There must not be any incomplete + BLOB columns. */ + ut_a(data); dfield_set_data(field, data, len); } @@ -2023,7 +2028,7 @@ row_merge_drop_index( ut_ad(index && table && trx); - pars_info_add_dulint_literal(info, "indexid", index->id); + pars_info_add_ull_literal(info, "indexid", index->id); trx_start_if_not_started(trx); trx->op_info = "dropping index"; @@ -2093,7 +2098,7 @@ row_merge_drop_temp_indexes(void) const rec_t* rec; const byte* field; ulint len; - dulint table_id; + table_id_t table_id; dict_table_t* table; btr_pcur_move_to_next_user_rec(&pcur, &mtr); @@ -2322,7 +2327,7 @@ row_merge_rename_indexes( trx->op_info = "renaming indexes"; - pars_info_add_dulint_literal(info, "tableid", table->id); + pars_info_add_ull_literal(info, "tableid", table->id); err = que_eval_sql(info, rename_indexes, FALSE, trx); @@ -2359,7 +2364,7 @@ row_merge_rename_tables( { ulint err = DB_ERROR; pars_info_t* info; - const char* old_name= old_table->name; + char old_name[MAX_TABLE_NAME_LEN + 1]; ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(old_table != new_table); @@ -2367,6 +2372,17 @@ row_merge_rename_tables( ut_a(trx->dict_operation_lock_mode == RW_X_LATCH); + /* store the old/current name to an automatic variable */ + if (strlen(old_table->name) + 1 <= sizeof(old_name)) { + memcpy(old_name, old_table->name, strlen(old_table->name) + 1); + } else { + ut_print_timestamp(stderr); + fprintf(stderr, "InnoDB: too long table name: '%s', " + "max length is %d\n", old_table->name, + MAX_TABLE_NAME_LEN); + ut_error; + } + trx->op_info = "renaming tables"; /* We use the private SQL parser of Innobase to generate the query @@ -2499,8 +2515,7 @@ row_merge_create_index( /* Note the id of the transaction that created this index, we use it to restrict readers from accessing this index, to ensure read consistency. */ - index->trx_id = (ib_uint64_t) - ut_conv_dulint_to_longlong(trx->id); + index->trx_id = trx->id; } else { index = NULL; } @@ -2517,10 +2532,8 @@ row_merge_is_index_usable( const trx_t* trx, /*!< in: transaction */ const dict_index_t* index) /*!< in: index to check */ { - return(!trx->read_view || read_view_sees_trx_id( - trx->read_view, - ut_dulint_create((ulint) (index->trx_id >> 32), - (ulint) index->trx_id & 0xFFFFFFFF))); + return(!trx->read_view + || read_view_sees_trx_id(trx->read_view, index->trx_id)); } /*********************************************************************//** diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 1f7f98a59a2..1262ac71e98 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -266,6 +266,49 @@ row_mysql_read_blob_ref( } /**************************************************************//** +Pad a column with spaces. */ +UNIV_INTERN +void +row_mysql_pad_col( +/*==============*/ + ulint mbminlen, /*!< in: minimum size of a character, + in bytes */ + byte* pad, /*!< out: padded buffer */ + ulint len) /*!< in: number of bytes to pad */ +{ + const byte* pad_end; + + switch (UNIV_EXPECT(mbminlen, 1)) { + default: + ut_error; + case 1: + /* space=0x20 */ + memset(pad, 0x20, len); + break; + case 2: + /* space=0x0020 */ + pad_end = pad + len; + ut_a(!(len % 2)); + do { + *pad++ = 0x00; + *pad++ = 0x20; + } while (pad < pad_end); + break; + case 4: + /* space=0x00000020 */ + pad_end = pad + len; + ut_a(!(len % 4)); + do { + *pad++ = 0x00; + *pad++ = 0x00; + *pad++ = 0x00; + *pad++ = 0x20; + } while (pad < pad_end); + break; + } +} + +/**************************************************************//** Stores a non-SQL-NULL field given in the MySQL format in the InnoDB format. The counterpart of this function is row_sel_field_store_in_mysql_format() in row0sel.c. @@ -357,12 +400,28 @@ row_mysql_store_col_in_innobase_format( /* Remove trailing spaces from old style VARCHAR columns. */ - /* Handle UCS2 strings differently. */ + /* Handle Unicode strings differently. */ ulint mbminlen = dtype_get_mbminlen(dtype); ptr = mysql_data; - if (mbminlen == 2) { + switch (mbminlen) { + default: + ut_error; + case 4: + /* space=0x00000020 */ + /* Trim "half-chars", just in case. */ + col_len &= ~3; + + while (col_len >= 4 + && ptr[col_len - 4] == 0x00 + && ptr[col_len - 3] == 0x00 + && ptr[col_len - 2] == 0x00 + && ptr[col_len - 1] == 0x20) { + col_len -= 4; + } + break; + case 2: /* space=0x0020 */ /* Trim "half-chars", just in case. */ col_len &= ~1; @@ -371,8 +430,8 @@ row_mysql_store_col_in_innobase_format( && ptr[col_len - 1] == 0x20) { col_len -= 2; } - } else { - ut_a(mbminlen == 1); + break; + case 1: /* space=0x20 */ while (col_len > 0 && ptr[col_len - 1] == 0x20) { @@ -1532,7 +1591,7 @@ row_unlock_for_mysql( } } - if (ut_dulint_cmp(rec_trx_id, trx->id) != 0) { + if (rec_trx_id != trx->id) { /* We did not update the record: unlock it */ rec = btr_pcur_get_rec(pcur); @@ -2283,7 +2342,7 @@ row_discard_tablespace_for_mysql( trx_t* trx) /*!< in: transaction handle */ { dict_foreign_t* foreign; - dulint new_id; + table_id_t new_id; dict_table_t* table; ibool success; ulint err; @@ -2405,7 +2464,7 @@ row_discard_tablespace_for_mysql( info = pars_info_create(); pars_info_add_str_literal(info, "table_name", name); - pars_info_add_dulint_literal(info, "new_id", new_id); + pars_info_add_ull_literal(info, "new_id", new_id); err = que_eval_sql(info, "PROCEDURE DISCARD_TABLESPACE_PROC () IS\n" @@ -2619,7 +2678,7 @@ row_truncate_table_for_mysql( dict_index_t* sys_index; btr_pcur_t pcur; mtr_t mtr; - dulint new_id; + table_id_t new_id; ulint recreate_space = 0; pars_info_t* info = NULL; @@ -2873,8 +2932,8 @@ next_rec: info = pars_info_create(); pars_info_add_int4_literal(info, "space", (lint) table->space); - pars_info_add_dulint_literal(info, "old_id", table->id); - pars_info_add_dulint_literal(info, "new_id", new_id); + pars_info_add_ull_literal(info, "old_id", table->id); + pars_info_add_ull_literal(info, "new_id", new_id); err = que_eval_sql(info, "PROCEDURE RENUMBER_TABLESPACE_PROC () IS\n" diff --git a/storage/innobase/row/row0purge.c b/storage/innobase/row/row0purge.c index da9d31f333f..fe7a3e0236e 100644 --- a/storage/innobase/row/row0purge.c +++ b/storage/innobase/row/row0purge.c @@ -44,6 +44,16 @@ Created 3/14/1997 Heikki Tuuri #include "row0mysql.h" #include "log0log.h" +/************************************************************************* +IMPORTANT NOTE: Any operation that generates redo MUST check that there +is enough space in the redo log before for that operation. This is +done by calling log_free_check(). The reason for checking the +availability of the redo log space before the start of the operation is +that we MUST not hold any synchonization objects when performing the +check. +If you make a change in this module make sure that no codepath is +introduced where a call to log_free_check() is bypassed. */ + /********************************************************************//** Creates a purge node to a query graph. @return own: purge node */ @@ -126,6 +136,7 @@ row_purge_remove_clust_if_poss_low( pcur = &(node->pcur); btr_cur = btr_pcur_get_btr_cur(pcur); + log_free_check(); mtr_start(&mtr); success = row_purge_reposition_pcur(mode, node, &mtr); @@ -140,10 +151,9 @@ row_purge_remove_clust_if_poss_low( rec = btr_pcur_get_rec(pcur); - if (0 != ut_dulint_cmp(node->roll_ptr, row_get_rec_roll_ptr( - rec, index, rec_get_offsets( - rec, index, offsets_, - ULINT_UNDEFINED, &heap)))) { + if (node->roll_ptr != row_get_rec_roll_ptr( + rec, index, rec_get_offsets(rec, index, offsets_, + ULINT_UNDEFINED, &heap))) { if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } @@ -606,7 +616,7 @@ row_purge_parse_undo_rec( byte* ptr; trx_t* trx; undo_no_t undo_no; - dulint table_id; + table_id_t table_id; trx_id_t trx_id; roll_ptr_t roll_ptr; ulint info_bits; diff --git a/storage/innobase/row/row0row.c b/storage/innobase/row/row0row.c index 6cdfa410c15..050b8522fa3 100644 --- a/storage/innobase/row/row0row.c +++ b/storage/innobase/row/row0row.c @@ -156,7 +156,7 @@ row_build_index_entry( } len = dtype_get_at_most_n_mbchars( - col->prtype, col->mbminlen, col->mbmaxlen, + col->prtype, col->mbminmaxlen, ind_field->prefix_len, len, dfield_get_data(dfield)); dfield_set_len(dfield, len); } @@ -294,7 +294,13 @@ row_build( ut_ad(dtuple_check_typed(row)); - if (j) { + if (!ext) { + /* REDUNDANT and COMPACT formats store a local + 768-byte prefix of each externally stored + column. No cache is needed. */ + ut_ad(dict_table_get_format(index->table) + < DICT_TF_FORMAT_ZIP); + } else if (j) { *ext = row_ext_create(j, ext_cols, row, dict_table_zip_size(index->table), heap); @@ -514,8 +520,7 @@ row_build_row_ref( dfield_set_len(dfield, dtype_get_at_most_n_mbchars( dtype->prtype, - dtype->mbminlen, - dtype->mbmaxlen, + dtype->mbminmaxlen, clust_col_prefix_len, len, (char*) field)); } @@ -629,8 +634,7 @@ notfound: dfield_set_len(dfield, dtype_get_at_most_n_mbchars( dtype->prtype, - dtype->mbminlen, - dtype->mbmaxlen, + dtype->mbminmaxlen, clust_col_prefix_len, len, (char*) field)); } diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c index 2861235a995..39ab2179740 100644 --- a/storage/innobase/row/row0sel.c +++ b/storage/innobase/row/row0sel.c @@ -88,10 +88,8 @@ row_sel_sec_rec_is_for_blob( /*========================*/ ulint mtype, /*!< in: main type */ ulint prtype, /*!< in: precise type */ - ulint mbminlen, /*!< in: minimum length of a - multi-byte character */ - ulint mbmaxlen, /*!< in: maximum length of a - multi-byte character */ + ulint mbminmaxlen, /*!< in: minimum and maximum length of + a multi-byte character */ const byte* clust_field, /*!< in: the locally stored part of the clustered index column, including the BLOB pointer; the clustered @@ -119,7 +117,7 @@ row_sel_sec_rec_is_for_blob( return(FALSE); } - len = dtype_get_at_most_n_mbchars(prtype, mbminlen, mbmaxlen, + len = dtype_get_at_most_n_mbchars(prtype, mbminmaxlen, sec_len, len, (const char*) buf); return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len)); @@ -202,14 +200,14 @@ row_sel_sec_rec_is_for_clust_rec( } len = dtype_get_at_most_n_mbchars( - col->prtype, col->mbminlen, col->mbmaxlen, + col->prtype, col->mbminmaxlen, ifield->prefix_len, len, (char*) clust_field); if (rec_offs_nth_extern(clust_offs, clust_pos) && len < sec_len) { if (!row_sel_sec_rec_is_for_blob( col->mtype, col->prtype, - col->mbminlen, col->mbmaxlen, + col->mbminmaxlen, clust_field, clust_len, sec_field, sec_len, dict_table_zip_size( @@ -416,7 +414,7 @@ row_sel_fetch_columns( field_no))) { /* Copy an externally stored field to the - temporary heap */ + temporary heap, if possible. */ heap = mem_heap_create(1); @@ -425,6 +423,17 @@ row_sel_fetch_columns( dict_table_zip_size(index->table), field_no, &len, heap); + /* data == NULL means that the + externally stored field was not + written yet. This record + should only be seen by + recv_recovery_rollback_active() or any + TRX_ISO_READ_UNCOMMITTED + transactions. The InnoDB SQL parser + (the sole caller of this function) + does not implement READ UNCOMMITTED, + and it is not involved during rollback. */ + ut_a(data); ut_a(len != UNIV_SQL_NULL); needs_copy = TRUE; @@ -926,6 +935,7 @@ row_sel_get_clust_rec( when plan->clust_pcur was positioned. The latch will not be released until mtr_commit(mtr). */ + ut_ad(!rec_get_deleted_flag(clust_rec, rec_offs_comp(offsets))); row_sel_fetch_columns(index, clust_rec, offsets, UT_LIST_GET_FIRST(plan->columns)); *out_rec = clust_rec; @@ -1628,6 +1638,13 @@ skip_lock: } if (old_vers == NULL) { + /* The record does not exist + in our read view. Skip it, but + first attempt to determine + whether the index segment we + are searching through has been + exhausted. */ + offsets = rec_get_offsets( rec, index, offsets, ULINT_UNDEFINED, &heap); @@ -2508,13 +2525,13 @@ row_sel_field_store_in_mysql_format( ulint len) /*!< in: length of the data */ { byte* ptr; - byte* field_end; - byte* pad_ptr; ut_ad(len != UNIV_SQL_NULL); UNIV_MEM_ASSERT_RW(data, len); switch (templ->type) { + const byte* field_end; + byte* pad; case DATA_INT: /* Convert integer data from Innobase to a little-endian format, sign bit restored to normal */ @@ -2558,38 +2575,32 @@ row_sel_field_store_in_mysql_format( unused end of a >= 5.0.3 true VARCHAR column, just in case MySQL expects its contents to be deterministic. */ - pad_ptr = dest + len; + pad = dest + len; ut_ad(templ->mbminlen <= templ->mbmaxlen); - /* We handle UCS2 charset strings differently. */ - if (templ->mbminlen == 2) { - /* A space char is two bytes, 0x0020 in UCS2 */ + /* We treat some Unicode charset strings specially. */ + switch (templ->mbminlen) { + case 4: + /* InnoDB should never have stripped partial + UTF-32 characters. */ + ut_a(!(len & 3)); + break; + case 2: + /* A space char is two bytes, + 0x0020 in UCS2 and UTF-16 */ - if (len & 1) { + if (UNIV_UNLIKELY(len & 1)) { /* A 0x20 has been stripped from the column. Pad it back. */ - if (pad_ptr < field_end) { - *pad_ptr = 0x20; - pad_ptr++; + if (pad < field_end) { + *pad++ = 0x20; } } - - /* Pad the rest of the string with 0x0020 */ - - while (pad_ptr < field_end) { - *pad_ptr = 0x00; - pad_ptr++; - *pad_ptr = 0x20; - pad_ptr++; - } - } else { - ut_ad(templ->mbminlen == 1); - /* space=0x20 */ - - memset(pad_ptr, 0x20, field_end - pad_ptr); } + + row_mysql_pad_col(templ->mbminlen, pad, field_end - pad); break; case DATA_BLOB: @@ -2614,9 +2625,9 @@ row_sel_field_store_in_mysql_format( || !(templ->mysql_col_len % templ->mbmaxlen)); ut_ad(len * templ->mbmaxlen >= templ->mysql_col_len); - if (templ->mbminlen != templ->mbmaxlen) { + if (templ->mbminlen == 1 && templ->mbmaxlen != 1) { /* Pad with spaces. This undoes the stripping - done in row0mysql.ic, function + done in row0mysql.c, function row_mysql_store_col_in_innobase_format(). */ memset(dest + len, 0x20, templ->mysql_col_len - len); @@ -2647,9 +2658,8 @@ Convert a row in the Innobase format to a row in the MySQL format. Note that the template in prebuilt may advise us to copy only a few columns to mysql_rec, other columns are left blank. All columns may not be needed in the query. -@return TRUE if success, FALSE if could not allocate memory for a BLOB -(though we may also assert in that case) */ -static +@return TRUE on success, FALSE if not all columns could be retrieved */ +static __attribute__((warn_unused_result)) ibool row_sel_store_mysql_rec( /*====================*/ @@ -2672,6 +2682,7 @@ row_sel_store_mysql_rec( ut_ad(prebuilt->mysql_template); ut_ad(prebuilt->default_rec); ut_ad(rec_offs_validate(rec, NULL, offsets)); + ut_ad(!rec_get_deleted_flag(rec, rec_offs_comp(offsets))); if (UNIV_LIKELY_NULL(prebuilt->blob_heap)) { mem_heap_free(prebuilt->blob_heap); @@ -2719,6 +2730,21 @@ row_sel_store_mysql_rec( dict_table_zip_size(prebuilt->table), templ->rec_field_no, &len, heap); + if (UNIV_UNLIKELY(!data)) { + /* The externally stored field + was not written yet. This + record should only be seen by + recv_recovery_rollback_active() + or any TRX_ISO_READ_UNCOMMITTED + transactions. */ + + if (extern_field_heap) { + mem_heap_free(extern_field_heap); + } + + return(FALSE); + } + ut_a(len != UNIV_SQL_NULL); } else { /* Field is stored in the row. */ @@ -3136,9 +3162,10 @@ row_sel_pop_cached_row_for_mysql( } /********************************************************************//** -Pushes a row for MySQL to the fetch cache. */ -UNIV_INLINE -void +Pushes a row for MySQL to the fetch cache. +@return TRUE on success, FALSE if the record contains incomplete BLOBs */ +UNIV_INLINE __attribute__((warn_unused_result)) +ibool row_sel_push_cache_row_for_mysql( /*=============================*/ row_prebuilt_t* prebuilt, /*!< in: prebuilt struct */ @@ -3180,10 +3207,11 @@ row_sel_push_cache_row_for_mysql( prebuilt->fetch_cache[ prebuilt->n_fetch_cached], prebuilt, rec, offsets))) { - ut_error; + return(FALSE); } prebuilt->n_fetch_cached++; + return(TRUE); } /*********************************************************************//** @@ -3578,11 +3606,21 @@ row_search_for_mysql( if (!row_sel_store_mysql_rec(buf, prebuilt, rec, offsets)) { - err = DB_TOO_BIG_RECORD; - - /* We let the main loop to do the - error handling */ - goto shortcut_fails_too_big_rec; + /* Only fresh inserts may contain + incomplete externally stored + columns. Pretend that such + records do not exist. Such + records may only be accessed + at the READ UNCOMMITTED + isolation level or when + rolling back a recovered + transaction. Rollback happens + at a lower level, not here. */ + ut_a(trx->isolation_level + == TRX_ISO_READ_UNCOMMITTED); + + /* Proceed as in case SEL_RETRY. */ + break; } mtr_commit(&mtr); @@ -3622,7 +3660,7 @@ release_search_latch_if_needed: default: ut_ad(0); } -shortcut_fails_too_big_rec: + mtr_commit(&mtr); mtr_start(&mtr); } @@ -4357,9 +4395,18 @@ requires_clust_rec: not cache rows because there the cursor is a scrollable cursor. */ - row_sel_push_cache_row_for_mysql(prebuilt, result_rec, - offsets); - if (prebuilt->n_fetch_cached == MYSQL_FETCH_CACHE_SIZE) { + if (!row_sel_push_cache_row_for_mysql(prebuilt, result_rec, + offsets)) { + /* Only fresh inserts may contain incomplete + externally stored columns. Pretend that such + records do not exist. Such records may only be + accessed at the READ UNCOMMITTED isolation + level or when rolling back a recovered + transaction. Rollback happens at a lower + level, not here. */ + ut_a(trx->isolation_level == TRX_ISO_READ_UNCOMMITTED); + } else if (prebuilt->n_fetch_cached + == MYSQL_FETCH_CACHE_SIZE) { goto got_row; } @@ -4375,9 +4422,17 @@ requires_clust_rec: } else { if (!row_sel_store_mysql_rec(buf, prebuilt, result_rec, offsets)) { - err = DB_TOO_BIG_RECORD; - - goto lock_wait_or_error; + /* Only fresh inserts may contain + incomplete externally stored + columns. Pretend that such records do + not exist. Such records may only be + accessed at the READ UNCOMMITTED + isolation level or when rolling back a + recovered transaction. Rollback + happens at a lower level, not here. */ + ut_a(trx->isolation_level + == TRX_ISO_READ_UNCOMMITTED); + goto next_rec; } } @@ -4622,8 +4677,7 @@ row_search_check_if_query_cache_permitted( IX type locks actually would require ret = FALSE. */ if (UT_LIST_GET_LEN(table->locks) == 0 - && ut_dulint_cmp(trx->id, - table->query_cache_inv_trx_id) >= 0) { + && trx->id >= table->query_cache_inv_trx_id) { ret = TRUE; diff --git a/storage/innobase/row/row0uins.c b/storage/innobase/row/row0uins.c index c35f1ef7a44..d25afed3840 100644 --- a/storage/innobase/row/row0uins.c +++ b/storage/innobase/row/row0uins.c @@ -46,6 +46,16 @@ Created 2/25/1997 Heikki Tuuri #include "ibuf0ibuf.h" #include "log0log.h" +/************************************************************************* +IMPORTANT NOTE: Any operation that generates redo MUST check that there +is enough space in the redo log before for that operation. This is +done by calling log_free_check(). The reason for checking the +availability of the redo log space before the start of the operation is +that we MUST not hold any synchonization objects when performing the +check. +If you make a change in this module make sure that no codepath is +introduced where a call to log_free_check() is bypassed. */ + /***************************************************************//** Removes a clustered index record. The pcur in node was positioned on the record, now it is detached. @@ -68,7 +78,7 @@ row_undo_ins_remove_clust_rec( &mtr); ut_a(success); - if (ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) { + if (node->table->id == DICT_INDEXES_ID) { ut_ad(node->trx->dict_operation_lock_mode == RW_X_LATCH); /* Drop the index tree associated with the row in @@ -151,7 +161,6 @@ row_undo_ins_remove_sec_low( mtr_t mtr; enum row_search_result search_result; - log_free_check(); mtr_start(&mtr); btr_cur = btr_pcur_get_btr_cur(&pcur); @@ -251,7 +260,7 @@ row_undo_ins_parse_undo_rec( dict_index_t* clust_index; byte* ptr; undo_no_t undo_no; - dulint table_id; + table_id_t table_id; ulint type; ulint dummy; ibool dummy_extern; @@ -337,6 +346,7 @@ row_undo_ins( transactions. */ ut_a(trx_is_recv(node->trx)); } else { + log_free_check(); err = row_undo_ins_remove_sec(node->index, entry); if (err != DB_SUCCESS) { @@ -348,5 +358,6 @@ row_undo_ins( node->index = dict_table_get_next_index(node->index); } + log_free_check(); return(row_undo_ins_remove_clust_rec(node)); } diff --git a/storage/innobase/row/row0umod.c b/storage/innobase/row/row0umod.c index 75de18a0b7d..aebff0764c8 100644 --- a/storage/innobase/row/row0umod.c +++ b/storage/innobase/row/row0umod.c @@ -58,12 +58,22 @@ delete marked clustered index record was delete unmarked and possibly also some of its fields were changed. Now, it is possible that the delete marked version has become obsolete at the time the undo is started. */ +/************************************************************************* +IMPORTANT NOTE: Any operation that generates redo MUST check that there +is enough space in the redo log before for that operation. This is +done by calling log_free_check(). The reason for checking the +availability of the redo log space before the start of the operation is +that we MUST not hold any synchonization objects when performing the +check. +If you make a change in this module make sure that no codepath is +introduced where a call to log_free_check() is bypassed. */ + /***********************************************************//** Checks if also the previous version of the clustered index record was modified or inserted by the same transaction, and its undo number is such that it should be undone in the same rollback. @return TRUE if also previous modify or insert of this row should be undone */ -UNIV_INLINE +static ibool row_undo_mod_undo_also_prev_vers( /*=============================*/ @@ -75,9 +85,9 @@ row_undo_mod_undo_also_prev_vers( trx = node->trx; - if (0 != ut_dulint_cmp(node->new_trx_id, trx->id)) { + if (node->new_trx_id != trx->id) { - *undo_no = ut_dulint_zero; + *undo_no = 0; return(FALSE); } @@ -85,7 +95,7 @@ row_undo_mod_undo_also_prev_vers( *undo_no = trx_undo_rec_get_undo_no(undo_rec); - return(ut_dulint_cmp(trx->roll_limit, *undo_no) <= 0); + return(trx->roll_limit <= *undo_no); } /***********************************************************//** @@ -231,6 +241,8 @@ row_undo_mod_clust( ut_ad(node && thr); + log_free_check(); + /* Check if also the previous version of the clustered index record should be undone in this same rollback operation */ @@ -778,7 +790,7 @@ row_undo_mod_parse_undo_rec( dict_index_t* clust_index; byte* ptr; undo_no_t undo_no; - dulint table_id; + table_id_t table_id; trx_id_t trx_id; roll_ptr_t roll_ptr; ulint info_bits; diff --git a/storage/innobase/row/row0undo.c b/storage/innobase/row/row0undo.c index 3d739c9689a..09970b7fe21 100644 --- a/storage/innobase/row/row0undo.c +++ b/storage/innobase/row/row0undo.c @@ -185,9 +185,8 @@ row_undo_search_clust_to_pcur( offsets = rec_get_offsets(rec, clust_index, offsets, ULINT_UNDEFINED, &heap); - if (!found || 0 != ut_dulint_cmp(node->roll_ptr, - row_get_rec_roll_ptr(rec, clust_index, - offsets))) { + if (!found || node->roll_ptr + != row_get_rec_roll_ptr(rec, clust_index, offsets)) { /* We must remove the reservation on the undo log record BEFORE releasing the latch on the clustered index page: this @@ -199,8 +198,24 @@ row_undo_search_clust_to_pcur( ret = FALSE; } else { + row_ext_t** ext; + + if (dict_table_get_format(node->table) >= DICT_TF_FORMAT_ZIP) { + /* In DYNAMIC or COMPRESSED format, there is + no prefix of externally stored columns in the + clustered index record. Build a cache of + column prefixes. */ + ext = &node->ext; + } else { + /* REDUNDANT and COMPACT formats store a local + 768-byte prefix of each externally stored + column. No cache is needed. */ + ext = NULL; + node->ext = NULL; + } + node->row = row_build(ROW_COPY_DATA, clust_index, rec, - offsets, NULL, &node->ext, node->heap); + offsets, NULL, ext, node->heap); if (node->update) { node->undo_row = dtuple_copy(node->row, node->heap); row_upd_replace(node->undo_row, &node->undo_ext, @@ -297,7 +312,7 @@ row_undo( if (locked_data_dict) { - row_mysql_lock_data_dictionary(trx); + row_mysql_freeze_data_dictionary(trx); } if (node->state == UNDO_NODE_INSERT) { @@ -312,7 +327,7 @@ row_undo( if (locked_data_dict) { - row_mysql_unlock_data_dictionary(trx); + row_mysql_unfreeze_data_dictionary(trx); } /* Do some cleanup */ diff --git a/storage/innobase/row/row0upd.c b/storage/innobase/row/row0upd.c index f1a90a3bf1c..588ee352ba0 100644 --- a/storage/innobase/row/row0upd.c +++ b/storage/innobase/row/row0upd.c @@ -92,6 +92,16 @@ the x-latch freed? The most efficient way for performing a searched delete is obviously to keep the x-latch for several steps of query graph execution. */ +/************************************************************************* +IMPORTANT NOTE: Any operation that generates redo MUST check that there +is enough space in the redo log before for that operation. This is +done by calling log_free_check(). The reason for checking the +availability of the redo log space before the start of the operation is +that we MUST not hold any synchonization objects when performing the +check. +If you make a change in this module make sure that no codepath is +introduced where a call to log_free_check() is bypassed. */ + /***********************************************************//** Checks if an update vector changes some of the first ordering fields of an index record. This is only used in foreign key checks and we can assume @@ -367,7 +377,7 @@ row_upd_index_entry_sys_field( them */ dict_index_t* index, /*!< in: clustered index */ ulint type, /*!< in: DATA_TRX_ID or DATA_ROLL_PTR */ - dulint val) /*!< in: value to write */ + ib_uint64_t val) /*!< in: value to write */ { dfield_t* dfield; byte* field; @@ -526,7 +536,7 @@ row_upd_write_sys_vals_to_log( trx_write_roll_ptr(log_ptr, roll_ptr); log_ptr += DATA_ROLL_PTR_LEN; - log_ptr += mach_dulint_write_compressed(log_ptr, trx->id); + log_ptr += mach_ull_write_compressed(log_ptr, trx->id); return(log_ptr); } @@ -560,7 +570,7 @@ row_upd_parse_sys_vals( *roll_ptr = trx_read_roll_ptr(ptr); ptr += DATA_ROLL_PTR_LEN; - ptr = mach_dulint_parse_compressed(ptr, end_ptr, trx_id); + ptr = mach_ull_parse_compressed(ptr, end_ptr, trx_id); return(ptr); } @@ -939,7 +949,7 @@ row_upd_index_replace_new_col_val( } len = dtype_get_at_most_n_mbchars(col->prtype, - col->mbminlen, col->mbmaxlen, + col->mbminmaxlen, field->prefix_len, len, (const char*) data); @@ -1388,6 +1398,7 @@ row_upd_store_row( dict_index_t* clust_index; rec_t* rec; mem_heap_t* heap = NULL; + row_ext_t** ext; ulint offsets_[REC_OFFS_NORMAL_SIZE]; const ulint* offsets; rec_offs_init(offsets_); @@ -1404,8 +1415,22 @@ row_upd_store_row( offsets = rec_get_offsets(rec, clust_index, offsets_, ULINT_UNDEFINED, &heap); + + if (dict_table_get_format(node->table) >= DICT_TF_FORMAT_ZIP) { + /* In DYNAMIC or COMPRESSED format, there is no prefix + of externally stored columns in the clustered index + record. Build a cache of column prefixes. */ + ext = &node->ext; + } else { + /* REDUNDANT and COMPACT formats store a local + 768-byte prefix of each externally stored column. + No cache is needed. */ + ext = NULL; + node->ext = NULL; + } + node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets, - NULL, &node->ext, node->heap); + NULL, ext, node->heap); if (node->is_delete) { node->upd_row = NULL; node->upd_ext = NULL; @@ -1454,7 +1479,6 @@ row_upd_sec_index_entry( entry = row_build_index_entry(node->row, node->ext, index, heap); ut_a(entry); - log_free_check(); mtr_start(&mtr); /* Set the query thread, so that ibuf_insert_low() will be @@ -1557,7 +1581,7 @@ Updates the secondary index record if it is changed in the row update or deletes it if this is a delete. @return DB_SUCCESS if operation successfully completed, else error code or DB_LOCK_WAIT */ -UNIV_INLINE +static ulint row_upd_sec_step( /*=============*/ @@ -1903,8 +1927,7 @@ row_upd_clust_step( then we have to free the file segments of the index tree associated with the index */ - if (node->is_delete - && ut_dulint_cmp(node->table->id, DICT_INDEXES_ID) == 0) { + if (node->is_delete && node->table->id == DICT_INDEXES_ID) { dict_drop_index_tree(btr_pcur_get_rec(pcur), mtr); @@ -2049,6 +2072,7 @@ row_upd( if (node->state == UPD_NODE_UPDATE_CLUSTERED || node->state == UPD_NODE_INSERT_CLUSTERED) { + log_free_check(); err = row_upd_clust_step(node, thr); if (err != DB_SUCCESS) { @@ -2063,6 +2087,8 @@ row_upd( } while (node->index != NULL) { + + log_free_check(); err = row_upd_sec_step(node, thr); if (err != DB_SUCCESS) { diff --git a/storage/innobase/row/row0vers.c b/storage/innobase/row/row0vers.c index a4fbb5289aa..3e6fc3f18b6 100644 --- a/storage/innobase/row/row0vers.c +++ b/storage/innobase/row/row0vers.c @@ -209,7 +209,7 @@ row_vers_impl_x_locked_off_kernel( prev_trx_id must have already committed for the trx_id to be able to modify the row. Therefore, prev_trx_id cannot hold any implicit lock. */ - if (vers_del && 0 != ut_dulint_cmp(trx_id, prev_trx_id)) { + if (vers_del && trx_id != prev_trx_id) { mutex_enter(&kernel_mutex); break; @@ -280,7 +280,7 @@ row_vers_impl_x_locked_off_kernel( break; } - if (0 != ut_dulint_cmp(trx_id, prev_trx_id)) { + if (trx_id != prev_trx_id) { /* The versions modified by the trx_id transaction end to prev_version: no implicit x-lock */ @@ -533,7 +533,7 @@ row_vers_build_for_consistent_read( undo_no of the record is < undo_no in the view. */ if (view->type == VIEW_HIGH_GRANULARITY - && ut_dulint_cmp(view->creator_trx_id, trx_id) == 0) { + && view->creator_trx_id == trx_id) { roll_ptr = row_get_rec_roll_ptr(version, index, *offsets); @@ -541,7 +541,7 @@ row_vers_build_for_consistent_read( undo_no = trx_undo_rec_get_undo_no(undo_rec); mem_heap_empty(heap); - if (ut_dulint_cmp(view->undo_no, undo_no) > 0) { + if (view->undo_no > undo_no) { /* The view already sees this version: we can copy it to in_heap and return */ @@ -632,7 +632,7 @@ row_vers_build_for_semi_consistent_read( mem_heap_t* heap = NULL; byte* buf; ulint err; - trx_id_t rec_trx_id = ut_dulint_zero; + trx_id_t rec_trx_id = 0; ut_ad(dict_index_is_clust(index)); ut_ad(mtr_memo_contains_page(mtr, rec, MTR_MEMO_PAGE_X_FIX) @@ -684,7 +684,7 @@ row_vers_build_for_semi_consistent_read( rolled back and the transaction is removed from the global list of transactions. */ - if (!ut_dulint_cmp(rec_trx_id, version_trx_id)) { + if (rec_trx_id == version_trx_id) { /* The transaction was committed while we searched for earlier versions. Return the current version as a diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c index 6354689105a..97d699dde99 100644 --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -142,6 +142,21 @@ 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; +#ifdef __WIN__ +/* Windows native condition variables. We use runtime loading / function +pointers, because they are not available on Windows Server 2003 and +Windows XP/2000. + +We use condition for events on Windows if possible, even if os_event +resembles Windows kernel event object well API-wise. The reason is +performance, kernel objects are heavyweights and WaitForSingleObject() is a +performance killer causing calling thread to context switch. Besides, Innodb +is preallocating large number (often millions) of os_events. With kernel event +objects it takes a big chunk out of non-paged pool, which is better suited +for tasks like IO than for storing idle event objects. */ +UNIV_INTERN ibool srv_use_native_conditions = FALSE; +#endif /* __WIN__ */ + UNIV_INTERN ulint srv_n_data_files = 0; UNIV_INTERN char** srv_data_file_names = NULL; /* size in database pages */ @@ -3007,6 +3022,8 @@ srv_purge_thread( slot_no = srv_table_reserve_slot(SRV_WORKER); + slot = srv_table_get_nth_slot(slot_no); + ++srv_n_threads_active[SRV_WORKER]; mutex_exit(&kernel_mutex); @@ -3058,20 +3075,16 @@ srv_purge_thread( mutex_enter(&kernel_mutex); + ut_ad(srv_table_get_nth_slot(slot_no) == slot); + /* Decrement the active count. */ srv_suspend_thread(); - mutex_exit(&kernel_mutex); + slot->in_use = FALSE; /* 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 diff --git a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c index 686ee6a4198..4da836672ec 100644 --- a/storage/innobase/srv/srv0start.c +++ b/storage/innobase/srv/srv0start.c @@ -1160,9 +1160,17 @@ innobase_start_or_create_for_mysql(void) srv_use_native_aio = FALSE; break; + + case OS_WIN2000: + case OS_WINXP: + /* On 2000 and XP, async IO is available. */ + srv_use_native_aio = TRUE; + break; + default: - /* On Win 2000 and XP use async i/o */ + /* Vista and later have both async IO and condition variables */ srv_use_native_aio = TRUE; + srv_use_native_conditions = TRUE; break; } @@ -1695,20 +1703,6 @@ 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 */ - 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) { /* Create the doublewrite buffer to a new tablespace */ @@ -1721,8 +1715,29 @@ innobase_start_or_create_for_mysql(void) We create the new segments only if it's a new database or the database was shutdown cleanly. */ + /* Note: When creating the extra rollback segments during an upgrade + we violate the latching order, even if the change buffer is empty. + We make an exception in sync0sync.c and check srv_is_being_started + for that violation. It cannot create a deadlock because we are still + running in single threaded mode essentially. Only the IO threads + should be running at this stage. */ + trx_sys_create_rsegs(TRX_SYS_N_RSEGS - 1); + /* 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; + err = dict_create_or_check_foreign_constraint_tables(); if (err != DB_SUCCESS) { diff --git a/storage/innobase/sync/sync0arr.c b/storage/innobase/sync/sync0arr.c index 248bd2cd25d..753ebd958ac 100644 --- a/storage/innobase/sync/sync0arr.c +++ b/storage/innobase/sync/sync0arr.c @@ -250,7 +250,7 @@ sync_array_create( /* Then create the mutex to protect the wait array complex */ if (protection == SYNC_ARRAY_OS_MUTEX) { - arr->os_mutex = os_mutex_create(NULL); + arr->os_mutex = os_mutex_create(); } else if (protection == SYNC_ARRAY_MUTEX) { mutex_create(syn_arr_mutex_key, &arr->mutex, SYNC_NO_ORDER_CHECK); diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c index 235f733382d..8062d9e902e 100644 --- a/storage/innobase/sync/sync0sync.c +++ b/storage/innobase/sync/sync0sync.c @@ -40,6 +40,9 @@ Created 9/5/1995 Heikki Tuuri #include "srv0srv.h" #include "buf0types.h" #include "os0sync.h" /* for HAVE_ATOMIC_BUILTINS */ +#ifdef UNIV_SYNC_DEBUG +# include "srv0start.h" /* srv_is_being_started */ +#endif /* UNIV_SYNC_DEBUG */ /* REASONS FOR IMPLEMENTING THE SPIN LOCK MUTEX @@ -1152,6 +1155,13 @@ sync_thread_add_level( case SYNC_TREE_NODE_FROM_HASH: /* Do no order checking */ break; + case SYNC_TRX_SYS_HEADER: + if (srv_is_being_started) { + /* This is violated during trx_sys_create_rsegs() + when creating additional rollback segments when + upgrading in innobase_start_or_create_for_mysql(). */ + break; + } case SYNC_MEM_POOL: case SYNC_MEM_HASH: case SYNC_RECV: @@ -1160,7 +1170,6 @@ sync_thread_add_level( 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_SEARCH_SYS: @@ -1222,8 +1231,12 @@ sync_thread_add_level( ut_a(sync_thread_levels_g(array, SYNC_IBUF_BITMAP - 1, TRUE)); } else { - ut_a(sync_thread_levels_g(array, SYNC_IBUF_BITMAP, - TRUE)); + /* This is violated during trx_sys_create_rsegs() + when creating additional rollback segments when + upgrading in innobase_start_or_create_for_mysql(). */ + ut_a(srv_is_being_started + || sync_thread_levels_g(array, SYNC_IBUF_BITMAP, + TRUE)); } break; case SYNC_FSP_PAGE: @@ -1492,14 +1505,16 @@ sync_print_wait_info( fprintf(file, "Mutex spin waits %llu, rounds %llu, OS waits %llu\n" - "RW-shared spins %llu, OS waits %llu;" - " RW-excl spins %llu, OS waits %llu\n", + "RW-shared spins %llu, rounds %llu, OS waits %llu\n" + "RW-excl spins %llu, rounds %llu, OS waits %llu\n", mutex_spin_wait_count, mutex_spin_round_count, mutex_os_wait_count, rw_s_spin_wait_count, + rw_s_spin_round_count, rw_s_os_wait_count, rw_x_spin_wait_count, + rw_x_spin_round_count, rw_x_os_wait_count); fprintf(file, diff --git a/storage/innobase/trx/trx0i_s.c b/storage/innobase/trx/trx0i_s.c index 8b719646023..1ad074769c7 100644 --- a/storage/innobase/trx/trx0i_s.c +++ b/storage/innobase/trx/trx0i_s.c @@ -444,7 +444,7 @@ fill_trx_row( ut_ad(mutex_own(&kernel_mutex)); - row->trx_id = trx_get_id(trx); + row->trx_id = trx->id; row->trx_started = (ib_time_t) trx->start_time; row->trx_state = trx_get_que_state_str(trx); @@ -462,7 +462,7 @@ fill_trx_row( row->trx_wait_started = 0; } - row->trx_weight = (ullint) ut_conv_dulint_to_longlong(TRX_WEIGHT(trx)); + row->trx_weight = (ullint) TRX_WEIGHT(trx); if (trx->mysql_thd == NULL) { /* For internal transactions e.g., purge and transactions @@ -527,7 +527,7 @@ thd_done: row->trx_rows_locked = lock_number_of_rows_locked(trx); - row->trx_rows_modified = ut_conv_dulint_to_longlong(trx->undo_no); + row->trx_rows_modified = trx->undo_no; row->trx_concurrency_tickets = trx->n_tickets_to_enter_innodb; diff --git a/storage/innobase/trx/trx0purge.c b/storage/innobase/trx/trx0purge.c index 550a8c9c4b3..e17ed547050 100644 --- a/storage/innobase/trx/trx0purge.c +++ b/storage/innobase/trx/trx0purge.c @@ -145,47 +145,44 @@ void trx_purge_arr_get_biggest( /*======================*/ trx_undo_arr_t* arr, /*!< in: purge array */ - trx_id_t* trx_no, /*!< out: transaction number: ut_dulint_zero + trx_id_t* trx_no, /*!< out: transaction number: 0 if array is empty */ undo_no_t* undo_no)/*!< out: undo number */ { trx_undo_inf_t* cell; trx_id_t pair_trx_no; undo_no_t pair_undo_no; - int trx_cmp; - ulint n_used; ulint i; ulint n; - n = 0; - n_used = arr->n_used; - pair_trx_no = ut_dulint_zero; - pair_undo_no = ut_dulint_zero; + n = arr->n_used; + pair_trx_no = 0; + pair_undo_no = 0; - for (i = 0;; i++) { - cell = trx_undo_arr_get_nth_info(arr, i); + if (n) { + for (i = 0;; i++) { + cell = trx_undo_arr_get_nth_info(arr, i); - if (cell->in_use) { - n++; - trx_cmp = ut_dulint_cmp(cell->trx_no, pair_trx_no); + if (!cell->in_use) { + continue; + } - if ((trx_cmp > 0) - || ((trx_cmp == 0) - && (ut_dulint_cmp(cell->undo_no, - pair_undo_no) >= 0))) { + if ((cell->trx_no > pair_trx_no) + || ((cell->trx_no == pair_trx_no) + && cell->undo_no >= pair_undo_no)) { pair_trx_no = cell->trx_no; pair_undo_no = cell->undo_no; } - } - - if (n == n_used) { - *trx_no = pair_trx_no; - *undo_no = pair_undo_no; - return; + if (!--n) { + break; + } } } + + *trx_no = pair_trx_no; + *undo_no = pair_undo_no; } /****************************************************************//** @@ -233,8 +230,8 @@ trx_purge_sys_create(void) purge_sys->n_pages_handled = 0; - purge_sys->purge_trx_no = ut_dulint_zero; - purge_sys->purge_undo_no = ut_dulint_zero; + purge_sys->purge_trx_no = 0; + purge_sys->purge_undo_no = 0; purge_sys->next_stored = FALSE; rw_lock_create(trx_purge_latch_key, @@ -257,7 +254,7 @@ trx_purge_sys_create(void) purge_sys->query = trx_purge_graph_build(); - purge_sys->view = read_view_oldest_copy_or_open_new(ut_dulint_zero, + purge_sys->view = read_view_oldest_copy_or_open_new(0, purge_sys->heap); } @@ -370,7 +367,7 @@ trx_purge_add_update_undo_to_history( } /* Write the trx number to the undo log header */ - mlog_write_dulint(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr); + mlog_write_ull(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr); /* Write information about delete markings to the undo log header */ if (!undo->del_marks) { @@ -512,9 +509,9 @@ trx_purge_truncate_rseg_history( page_t* undo_page; trx_ulogf_t* log_hdr; trx_usegf_t* seg_hdr; - int cmp; ulint n_removed_logs = 0; mtr_t mtr; + trx_id_t undo_trx_no; ut_ad(mutex_own(&(purge_sys->mutex))); @@ -540,15 +537,16 @@ loop: hdr_addr.page, &mtr); log_hdr = undo_page + hdr_addr.boffset; + undo_trx_no = mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO); - cmp = ut_dulint_cmp(mach_read_from_8(log_hdr + TRX_UNDO_TRX_NO), - limit_trx_no); - if (cmp == 0) { - trx_undo_truncate_start(rseg, rseg->space, hdr_addr.page, - hdr_addr.boffset, limit_undo_no); - } + if (undo_trx_no >= limit_trx_no) { + if (undo_trx_no == limit_trx_no) { + trx_undo_truncate_start(rseg, rseg->space, + hdr_addr.page, + hdr_addr.boffset, + limit_undo_no); + } - if (cmp >= 0) { mutex_enter(&kernel_mutex); ut_a(trx_sys->rseg_history_len >= n_removed_logs); trx_sys->rseg_history_len -= n_removed_logs; @@ -614,7 +612,7 @@ trx_purge_truncate_history(void) trx_purge_arr_get_biggest(purge_sys->arr, &limit_trx_no, &limit_undo_no); - if (ut_dulint_is_zero(limit_trx_no)) { + if (limit_trx_no == 0) { limit_trx_no = purge_sys->purge_trx_no; limit_undo_no = purge_sys->purge_undo_no; @@ -623,13 +621,12 @@ trx_purge_truncate_history(void) /* We play safe and set the truncate limit at most to the purge view low_limit number, though this is not necessary */ - if (ut_dulint_cmp(limit_trx_no, purge_sys->view->low_limit_no) >= 0) { + if (limit_trx_no >= purge_sys->view->low_limit_no) { limit_trx_no = purge_sys->view->low_limit_no; - limit_undo_no = ut_dulint_zero; + limit_undo_no = 0; } - ut_ad((ut_dulint_cmp(limit_trx_no, - purge_sys->view->low_limit_no) <= 0)); + ut_ad(limit_trx_no <= purge_sys->view->low_limit_no); rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list); @@ -684,8 +681,8 @@ trx_purge_rseg_get_next_history_log( ut_a(rseg->last_page_no != FIL_NULL); - purge_sys->purge_trx_no = ut_dulint_add(rseg->last_trx_no, 1); - purge_sys->purge_undo_no = ut_dulint_zero; + purge_sys->purge_trx_no = rseg->last_trx_no + 1; + purge_sys->purge_undo_no = 0; purge_sys->next_stored = FALSE; mtr_start(&mtr); @@ -787,7 +784,7 @@ trx_purge_choose_next_log(void) rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list); - min_trx_no = ut_dulint_max; + min_trx_no = IB_ULONGLONG_MAX; min_rseg = NULL; @@ -796,9 +793,8 @@ trx_purge_choose_next_log(void) if (rseg->last_page_no != FIL_NULL) { - if ((min_rseg == NULL) - || (ut_dulint_cmp(min_trx_no, - rseg->last_trx_no) > 0)) { + if (min_rseg == NULL + || min_trx_no > rseg->last_trx_no) { min_rseg = rseg; min_trx_no = rseg->last_trx_no; @@ -848,7 +844,7 @@ trx_purge_choose_next_log(void) if (rec == &trx_purge_dummy_rec) { - purge_sys->purge_undo_no = ut_dulint_zero; + purge_sys->purge_undo_no = 0; purge_sys->page_no = page_no; purge_sys->offset = 0; } else { @@ -1041,8 +1037,7 @@ trx_purge_fetch_next_rec( return(NULL); } - if (ut_dulint_cmp(purge_sys->purge_trx_no, - purge_sys->view->low_limit_no) >= 0) { + if (purge_sys->purge_trx_no >= purge_sys->view->low_limit_no) { purge_sys->state = TRX_STOP_PURGE; trx_purge_truncate_if_arr_empty(); @@ -1052,10 +1047,10 @@ trx_purge_fetch_next_rec( return(NULL); } - /* fprintf(stderr, "Thread %lu purging trx %lu undo record %lu\n", + /* fprintf(stderr, "Thread %lu purging trx %llu undo record %llu\n", os_thread_get_curr_id(), - ut_dulint_get_low(purge_sys->purge_trx_no), - ut_dulint_get_low(purge_sys->purge_undo_no)); */ + (ullint) purge_sys->purge_trx_no, + (ullint) purge_sys->purge_undo_no); */ *roll_ptr = trx_undo_build_roll_ptr(FALSE, (purge_sys->rseg)->id, purge_sys->page_no, @@ -1064,8 +1059,7 @@ trx_purge_fetch_next_rec( *cell = trx_purge_arr_store_info(purge_sys->purge_trx_no, purge_sys->purge_undo_no); - ut_ad(ut_dulint_cmp(purge_sys->purge_trx_no, - (purge_sys->view)->low_limit_no) < 0); + ut_ad(purge_sys->purge_trx_no < purge_sys->view->low_limit_no); /* The following call will advance the stored values of purge_trx_no and purge_undo_no, therefore we had to store them first */ @@ -1157,7 +1151,7 @@ trx_purge( } } - purge_sys->view = read_view_oldest_copy_or_open_new(ut_dulint_zero, + purge_sys->view = read_view_oldest_copy_or_open_new(0, purge_sys->heap); mutex_exit(&kernel_mutex); @@ -1215,8 +1209,8 @@ trx_purge_sys_print(void) fprintf(stderr, "InnoDB: Purge trx n:o " TRX_ID_FMT ", undo n:o " TRX_ID_FMT "\n", - TRX_ID_PREP_PRINTF(purge_sys->purge_trx_no), - TRX_ID_PREP_PRINTF(purge_sys->purge_undo_no)); + (ullint) purge_sys->purge_trx_no, + (ullint) purge_sys->purge_undo_no); fprintf(stderr, "InnoDB: Purge next stored %lu, page_no %lu, offset %lu,\n" "InnoDB: Purge hdr_page_no %lu, hdr_offset %lu\n", diff --git a/storage/innobase/trx/trx0rec.c b/storage/innobase/trx/trx0rec.c index f50e10ed756..e7e9a008db4 100644 --- a/storage/innobase/trx/trx0rec.c +++ b/storage/innobase/trx/trx0rec.c @@ -242,8 +242,8 @@ trx_undo_page_report_insert( /* Store first some general parameters to the undo log */ *ptr++ = TRX_UNDO_INSERT_REC; - ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no); - ptr += mach_dulint_write_much_compressed(ptr, index->table->id); + ptr += mach_ull_write_much_compressed(ptr, trx->undo_no); + ptr += mach_ull_write_much_compressed(ptr, index->table->id); /*----------------------------------------*/ /* Store then the fields required to uniquely determine the record to be inserted in the clustered index */ @@ -289,7 +289,7 @@ trx_undo_rec_get_pars( ibool* updated_extern, /*!< out: TRUE if we updated an externally stored fild */ undo_no_t* undo_no, /*!< out: undo log record number */ - dulint* table_id) /*!< out: table id */ + table_id_t* table_id) /*!< out: table id */ { byte* ptr; ulint type_cmpl; @@ -309,11 +309,11 @@ trx_undo_rec_get_pars( *type = type_cmpl & (TRX_UNDO_CMPL_INFO_MULT - 1); *cmpl_info = type_cmpl / TRX_UNDO_CMPL_INFO_MULT; - *undo_no = mach_dulint_read_much_compressed(ptr); - ptr += mach_dulint_get_much_compressed_size(*undo_no); + *undo_no = mach_ull_read_much_compressed(ptr); + ptr += mach_ull_get_much_compressed_size(*undo_no); - *table_id = mach_dulint_read_much_compressed(ptr); - ptr += mach_dulint_get_much_compressed_size(*table_id); + *table_id = mach_ull_read_much_compressed(ptr); + ptr += mach_ull_get_much_compressed_size(*table_id); return(ptr); } @@ -598,9 +598,9 @@ trx_undo_page_report_modify( type_cmpl_ptr = ptr; *ptr++ = (byte) type_cmpl; - ptr += mach_dulint_write_much_compressed(ptr, trx->undo_no); + ptr += mach_ull_write_much_compressed(ptr, trx->undo_no); - ptr += mach_dulint_write_much_compressed(ptr, table->id); + ptr += mach_ull_write_much_compressed(ptr, table->id); /*----------------------------------------*/ /* Store the state of the info bits */ @@ -620,16 +620,16 @@ trx_undo_page_report_modify( by some other trx as it must have committed by now for us to allow an over-write. */ if (ignore_prefix) { - ignore_prefix = ut_dulint_cmp(trx_id, trx->id) != 0; + ignore_prefix = (trx_id != trx->id); } - ptr += mach_dulint_write_compressed(ptr, trx_id); + ptr += mach_ull_write_compressed(ptr, trx_id); field = rec_get_nth_field(rec, offsets, dict_index_get_sys_col_pos( index, DATA_ROLL_PTR), &flen); ut_ad(flen == DATA_ROLL_PTR_LEN); - ptr += mach_dulint_write_compressed(ptr, trx_read_roll_ptr(field)); + ptr += mach_ull_write_compressed(ptr, trx_read_roll_ptr(field)); /*----------------------------------------*/ /* Store then the fields required to uniquely determine the @@ -848,11 +848,11 @@ trx_undo_update_rec_get_sys_cols( /* Read the values of the system columns */ - *trx_id = mach_dulint_read_compressed(ptr); - ptr += mach_dulint_get_compressed_size(*trx_id); + *trx_id = mach_ull_read_compressed(ptr); + ptr += mach_ull_get_compressed_size(*trx_id); - *roll_ptr = mach_dulint_read_compressed(ptr); - ptr += mach_dulint_get_compressed_size(*roll_ptr); + *roll_ptr = mach_ull_read_compressed(ptr); + ptr += mach_ull_get_compressed_size(*roll_ptr); return(ptr); } @@ -1168,7 +1168,7 @@ trx_undo_report_row_operation( index, otherwise NULL */ roll_ptr_t* roll_ptr) /*!< out: rollback pointer to the inserted undo log record, - ut_dulint_zero if BTR_NO_UNDO_LOG + 0 if BTR_NO_UNDO_LOG flag was specified */ { trx_t* trx; @@ -1186,7 +1186,7 @@ trx_undo_report_row_operation( if (flags & BTR_NO_UNDO_LOG_FLAG) { - *roll_ptr = ut_dulint_zero; + *roll_ptr = 0; return(DB_SUCCESS); } @@ -1284,7 +1284,7 @@ trx_undo_report_row_operation( undo->top_undo_no = trx->undo_no; undo->guess_block = undo_block; - UT_DULINT_INC(trx->undo_no); + trx->undo_no++; mutex_exit(&trx->undo_mutex); @@ -1433,7 +1433,7 @@ trx_undo_prev_version_build( trx_id_t rec_trx_id; ulint type; undo_no_t undo_no; - dulint table_id; + table_id_t table_id; trx_id_t trx_id; roll_ptr_t roll_ptr; roll_ptr_t old_roll_ptr; @@ -1523,7 +1523,7 @@ trx_undo_prev_version_build( roll_ptr, info_bits, NULL, heap, &update); - if (ut_dulint_cmp(table_id, index->table->id) != 0) { + if (UNIV_UNLIKELY(table_id != index->table->id)) { ptr = NULL; fprintf(stderr, @@ -1544,16 +1544,14 @@ trx_undo_prev_version_build( fprintf(stderr, "InnoDB: table %s, index %s, n_uniq %lu\n" "InnoDB: undo rec address %p, type %lu cmpl_info %lu\n" - "InnoDB: undo rec table id %lu %lu," - " index table id %lu %lu\n" + "InnoDB: undo rec table id %llu," + " index table id %llu\n" "InnoDB: dump of 150 bytes in undo rec: ", index->table_name, index->name, (ulong) dict_index_get_n_unique(index), undo_rec, (ulong) type, (ulong) cmpl_info, - (ulong) ut_dulint_get_high(table_id), - (ulong) ut_dulint_get_low(table_id), - (ulong) ut_dulint_get_high(index->table->id), - (ulong) ut_dulint_get_low(index->table->id)); + (ullint) table_id, + (ullint) index->table->id); ut_print_buf(stderr, undo_rec, 150); fputs("\n" "InnoDB: index record ", stderr); @@ -1564,14 +1562,10 @@ trx_undo_prev_version_build( fprintf(stderr, "\n" "InnoDB: Record trx id " TRX_ID_FMT ", update rec trx id " TRX_ID_FMT "\n" - "InnoDB: Roll ptr in rec %lu %lu, in update rec" - " %lu %lu\n", - TRX_ID_PREP_PRINTF(rec_trx_id), - TRX_ID_PREP_PRINTF(trx_id), - (ulong) ut_dulint_get_high(old_roll_ptr), - (ulong) ut_dulint_get_low(old_roll_ptr), - (ulong) ut_dulint_get_high(roll_ptr), - (ulong) ut_dulint_get_low(roll_ptr)); + "InnoDB: Roll ptr in rec " TRX_ID_FMT + ", in update rec" TRX_ID_FMT "\n", + (ullint) rec_trx_id, (ullint) trx_id, + (ullint) old_roll_ptr, (ullint) roll_ptr); trx_purge_sys_print(); return(DB_ERROR); diff --git a/storage/innobase/trx/trx0roll.c b/storage/innobase/trx/trx0roll.c index 4f1a71a5531..42b8a8685ad 100644 --- a/storage/innobase/trx/trx0roll.c +++ b/storage/innobase/trx/trx0roll.c @@ -52,7 +52,7 @@ static trx_t* trx_roll_crash_recv_trx = NULL; /** In crash recovery we set this to the undo n:o of the current trx to be rolled back. Then we can print how many % the rollback has progressed. */ -static ib_int64_t trx_roll_max_undo_no; +static undo_no_t trx_roll_max_undo_no; /** Auxiliary variable which tells the previous progress % we printed */ static ulint trx_roll_progress_printed_pct; @@ -443,7 +443,7 @@ trx_rollback_active( ut_a(thr == que_fork_start_command(fork)); trx_roll_crash_recv_trx = trx; - trx_roll_max_undo_no = ut_conv_dulint_to_longlong(trx->undo_no); + trx_roll_max_undo_no = trx->undo_no; trx_roll_progress_printed_pct = 0; rows_to_undo = trx_roll_max_undo_no; @@ -456,7 +456,7 @@ trx_rollback_active( fprintf(stderr, " InnoDB: Rolling back trx with id " TRX_ID_FMT ", %lu%s" " rows to undo\n", - TRX_ID_PREP_PRINTF(trx->id), + (ullint) trx->id, (ulong) rows_to_undo, unit); mutex_exit(&kernel_mutex); @@ -478,8 +478,9 @@ trx_rollback_active( mutex_exit(&kernel_mutex); fprintf(stderr, - "InnoDB: Waiting for rollback of trx id %lu to end\n", - (ulong) ut_dulint_get_low(trx->id)); + "InnoDB: Waiting for rollback of trx id " + TRX_ID_FMT " to end\n", + (ullint) trx->id); os_thread_sleep(100000); mutex_enter(&kernel_mutex); @@ -488,16 +489,15 @@ trx_rollback_active( mutex_exit(&kernel_mutex); if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE - && !ut_dulint_is_zero(trx->table_id)) { + && trx->table_id != 0) { /* If the transaction was for a dictionary operation, we drop the relevant table, if it still exists */ fprintf(stderr, - "InnoDB: Dropping table with id %lu %lu" + "InnoDB: Dropping table with id %llu" " in recovery if it exists\n", - (ulong) ut_dulint_get_high(trx->table_id), - (ulong) ut_dulint_get_low(trx->table_id)); + (ullint) trx->table_id); table = dict_table_get_on_id_low(trx->table_id); @@ -521,7 +521,7 @@ trx_rollback_active( fprintf(stderr, "\nInnoDB: Rolling back of trx id " TRX_ID_FMT " completed\n", - TRX_ID_PREP_PRINTF(trx->id)); + (ullint) trx->id); mem_heap_free(heap); trx_roll_crash_recv_trx = NULL; @@ -574,7 +574,7 @@ loop: fprintf(stderr, "InnoDB: Cleaning up trx with id " TRX_ID_FMT "\n", - TRX_ID_PREP_PRINTF(trx->id)); + (ullint) trx->id); trx_cleanup_at_db_startup(trx); goto loop; @@ -710,7 +710,7 @@ trx_undo_arr_store_info( } else { n++; - if (0 == ut_dulint_cmp(cell->undo_no, undo_no)) { + if (cell->undo_no == undo_no) { if (stored_here) { stored_here->in_use = FALSE; @@ -754,7 +754,7 @@ trx_undo_arr_remove_info( cell = trx_undo_arr_get_nth_info(arr, i); if (cell->in_use - && 0 == ut_dulint_cmp(cell->undo_no, undo_no)) { + && cell->undo_no == undo_no) { cell->in_use = FALSE; @@ -769,7 +769,7 @@ trx_undo_arr_remove_info( /*******************************************************************//** Gets the biggest undo number in an array. -@return biggest value, ut_dulint_zero if the array is empty */ +@return biggest value, 0 if the array is empty */ static undo_no_t trx_undo_arr_get_biggest( @@ -784,14 +784,14 @@ trx_undo_arr_get_biggest( n = 0; n_used = arr->n_used; - biggest = ut_dulint_zero; + biggest = 0; for (i = 0;; i++) { cell = trx_undo_arr_get_nth_info(arr, i); if (cell->in_use) { n++; - if (ut_dulint_cmp(cell->undo_no, biggest) > 0) { + if (cell->undo_no > biggest) { biggest = cell->undo_no; } @@ -827,9 +827,9 @@ trx_roll_try_truncate( if (arr->n_used > 0) { biggest = trx_undo_arr_get_biggest(arr); - if (ut_dulint_cmp(biggest, limit) >= 0) { + if (biggest >= limit) { - limit = ut_dulint_add(biggest, 1); + limit = biggest + 1; } } @@ -865,9 +865,9 @@ trx_roll_pop_top_rec( undo->top_page_no, mtr); offset = undo->top_offset; - /* fprintf(stderr, "Thread %lu undoing trx %lu undo record %lu\n", - os_thread_get_curr_id(), ut_dulint_get_low(trx->id), - ut_dulint_get_low(undo->top_undo_no)); */ + /* fprintf(stderr, "Thread %lu undoing trx " TRX_ID_FMT + " undo record " TRX_ID_FMT "\n", + os_thread_get_curr_id(), trx->id, undo->top_undo_no); */ prev_rec = trx_undo_get_prev_rec(undo_page + offset, undo->hdr_page_no, undo->hdr_offset, @@ -938,15 +938,14 @@ try_again: undo = upd_undo; } else if (!upd_undo || upd_undo->empty) { undo = ins_undo; - } else if (ut_dulint_cmp(upd_undo->top_undo_no, - ins_undo->top_undo_no) > 0) { + } else if (upd_undo->top_undo_no > ins_undo->top_undo_no) { undo = upd_undo; } else { undo = ins_undo; } if (!undo || undo->empty - || (ut_dulint_cmp(limit, undo->top_undo_no) > 0)) { + || limit > undo->top_undo_no) { if ((trx->undo_no_arr)->n_used == 0) { /* Rollback is ending */ @@ -978,7 +977,7 @@ try_again: undo_no = trx_undo_rec_get_undo_no(undo_rec); - ut_ad(ut_dulint_cmp(ut_dulint_add(undo_no, 1), trx->undo_no) == 0); + ut_ad(undo_no + 1 == trx->undo_no); /* We print rollback progress info if we are in a crash recovery and the transaction has at least 1000 row operations to undo. */ @@ -986,8 +985,7 @@ try_again: if (trx == trx_roll_crash_recv_trx && trx_roll_max_undo_no > 1000) { progress_pct = 100 - (ulint) - ((ut_conv_dulint_to_longlong(undo_no) * 100) - / trx_roll_max_undo_no); + ((undo_no * 100) / trx_roll_max_undo_no); if (progress_pct != trx_roll_progress_printed_pct) { if (trx_roll_progress_printed_pct == 0) { fprintf(stderr, @@ -1090,22 +1088,21 @@ trx_rollback( /* Initialize the rollback field in the transaction */ - if (sig->type == TRX_SIG_TOTAL_ROLLBACK) { - - trx->roll_limit = ut_dulint_zero; - - } else if (sig->type == TRX_SIG_ROLLBACK_TO_SAVEPT) { - + switch (sig->type) { + case TRX_SIG_TOTAL_ROLLBACK: + trx->roll_limit = 0; + break; + case TRX_SIG_ROLLBACK_TO_SAVEPT: trx->roll_limit = (sig->savept).least_undo_no; - - } else if (sig->type == TRX_SIG_ERROR_OCCURRED) { - + break; + case TRX_SIG_ERROR_OCCURRED: trx->roll_limit = trx->last_sql_stat_start.least_undo_no; - } else { + break; + default: ut_error; } - ut_a(ut_dulint_cmp(trx->roll_limit, trx->undo_no) <= 0); + ut_a(trx->roll_limit <= trx->undo_no); trx->pages_undone = 0; @@ -1269,8 +1266,8 @@ trx_finish_rollback_off_kernel( #ifdef UNIV_DEBUG if (lock_print_waits) { - fprintf(stderr, "Trx %lu rollback finished\n", - (ulong) ut_dulint_get_low(trx->id)); + fprintf(stderr, "Trx " TRX_ID_FMT " rollback finished\n", + (ullint) trx->id); } #endif /* UNIV_DEBUG */ diff --git a/storage/innobase/trx/trx0rseg.c b/storage/innobase/trx/trx0rseg.c index b458364b05d..740320f68c1 100644 --- a/storage/innobase/trx/trx0rseg.c +++ b/storage/innobase/trx/trx0rseg.c @@ -236,8 +236,8 @@ trx_rseg_mem_create( node_addr.page, mtr) + node_addr.boffset; - rseg->last_trx_no = mtr_read_dulint( - undo_log_hdr + TRX_UNDO_TRX_NO, mtr); + rseg->last_trx_no = mach_read_from_8( + undo_log_hdr + TRX_UNDO_TRX_NO); rseg->last_del_marks = mtr_read_ulint( undo_log_hdr + TRX_UNDO_DEL_MARKS, MLOG_2BYTES, mtr); } else { diff --git a/storage/innobase/trx/trx0sys.c b/storage/innobase/trx/trx0sys.c index e2f0ff6d532..640412c4572 100644 --- a/storage/innobase/trx/trx0sys.c +++ b/storage/innobase/trx/trx0sys.c @@ -664,8 +664,8 @@ trx_sys_flush_max_trx_id(void) sys_header = trx_sysf_get(&mtr); - mlog_write_dulint(sys_header + TRX_SYS_TRX_ID_STORE, - trx_sys->max_trx_id, &mtr); + mlog_write_ull(sys_header + TRX_SYS_TRX_ID_STORE, + trx_sys->max_trx_id, &mtr); mtr_commit(&mtr); } @@ -912,8 +912,7 @@ trx_sysf_create( sys_header = trx_sysf_get(mtr); /* Start counting transaction ids from number 1 up */ - mach_write_to_8(sys_header + TRX_SYS_TRX_ID_STORE, - ut_dulint_create(0, 1)); + mach_write_to_8(sys_header + TRX_SYS_TRX_ID_STORE, 1); /* Reset the rollback segment slots. Old versions of InnoDB define TRX_SYS_N_RSEGS as 256 (TRX_SYS_OLD_N_RSEGS) and expect @@ -950,7 +949,7 @@ trx_sys_init_at_db_start(void) /*==========================*/ { trx_sysf_t* sys_header; - ib_int64_t rows_to_undo = 0; + ib_uint64_t rows_to_undo = 0; const char* unit = ""; trx_t* trx; mtr_t mtr; @@ -976,12 +975,10 @@ trx_sys_init_at_db_start(void) to the disk-based header! Thus trx id values will not overlap when the database is repeatedly started! */ - trx_sys->max_trx_id = ut_dulint_add( - ut_dulint_align_up(mtr_read_dulint( - sys_header - + TRX_SYS_TRX_ID_STORE, &mtr), - TRX_SYS_TRX_ID_WRITE_MARGIN), - 2 * TRX_SYS_TRX_ID_WRITE_MARGIN); + trx_sys->max_trx_id = 2 * TRX_SYS_TRX_ID_WRITE_MARGIN + + ut_uint64_align_up(mach_read_from_8(sys_header + + TRX_SYS_TRX_ID_STORE), + TRX_SYS_TRX_ID_WRITE_MARGIN); UT_LIST_INIT(trx_sys->mysql_trx_list); trx_dummy_sess = sess_open(); @@ -992,9 +989,8 @@ trx_sys_init_at_db_start(void) for (;;) { - if ( trx->conc_state != TRX_PREPARED) { - rows_to_undo += ut_conv_dulint_to_longlong( - trx->undo_no); + if (trx->conc_state != TRX_PREPARED) { + rows_to_undo += trx->undo_no; } trx = UT_LIST_GET_NEXT(trx_list, trx); @@ -1017,7 +1013,7 @@ trx_sys_init_at_db_start(void) (ulong) rows_to_undo, unit); fprintf(stderr, "InnoDB: Trx id counter is " TRX_ID_FMT "\n", - TRX_ID_PREP_PRINTF(trx_sys->max_trx_id)); + (ullint) trx_sys->max_trx_id); } UT_LIST_INIT(trx_sys->view_list); @@ -1061,7 +1057,7 @@ trx_sys_file_format_max_write( mtr_t mtr; byte* ptr; buf_block_t* block; - ulint tag_value_low; + ib_uint64_t tag_value; mtr_start(&mtr); @@ -1072,17 +1068,13 @@ trx_sys_file_format_max_write( file_format_max.name = trx_sys_file_format_id_to_name(format_id); ptr = buf_block_get_frame(block) + TRX_SYS_FILE_FORMAT_TAG; - tag_value_low = format_id + TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW; + tag_value = format_id + TRX_SYS_FILE_FORMAT_TAG_MAGIC_N; if (name) { *name = file_format_max.name; } - mlog_write_dulint( - ptr, - ut_dulint_create(TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH, - tag_value_low), - &mtr); + mlog_write_ull(ptr, tag_value, &mtr); mtr_commit(&mtr); @@ -1100,8 +1092,7 @@ trx_sys_file_format_max_read(void) mtr_t mtr; const byte* ptr; const buf_block_t* block; - ulint format_id; - dulint file_format_id; + ib_id_t file_format_id; /* Since this is called during the startup phase it's safe to read the value without a covering mutex. */ @@ -1115,16 +1106,15 @@ trx_sys_file_format_max_read(void) mtr_commit(&mtr); - format_id = file_format_id.low - TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW; + file_format_id -= TRX_SYS_FILE_FORMAT_TAG_MAGIC_N; - if (file_format_id.high != TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH - || format_id >= FILE_FORMAT_NAME_N) { + if (file_format_id >= FILE_FORMAT_NAME_N) { /* Either it has never been tagged, or garbage in it. */ return(ULINT_UNDEFINED); } - return(format_id); + return((ulint) file_format_id); } /*****************************************************************//** @@ -1416,7 +1406,7 @@ trx_sys_read_file_format_id( byte buf[UNIV_PAGE_SIZE * 2]; page_t* page = ut_align(buf, UNIV_PAGE_SIZE); const byte* ptr; - dulint file_format_id; + ib_id_t file_format_id; *format_id = ULINT_UNDEFINED; @@ -1430,9 +1420,9 @@ trx_sys_read_file_format_id( if (!success) { /* The following call prints an error message */ os_file_get_last_error(TRUE); - + ut_print_timestamp(stderr); - + fprintf(stderr, " ibbackup: Error: trying to read system tablespace file format,\n" " ibbackup: but could not open the tablespace file %s!\n", @@ -1449,9 +1439,9 @@ trx_sys_read_file_format_id( if (!success) { /* The following call prints an error message */ os_file_get_last_error(TRUE); - + ut_print_timestamp(stderr); - + fprintf(stderr, " ibbackup: Error: trying to read system table space file format,\n" " ibbackup: but failed to read the tablespace file %s!\n", @@ -1465,17 +1455,16 @@ trx_sys_read_file_format_id( /* get the file format from the page */ ptr = page + TRX_SYS_FILE_FORMAT_TAG; file_format_id = mach_read_from_8(ptr); + file_format_id -= TRX_SYS_FILE_FORMAT_TAG_MAGIC_N; - *format_id = file_format_id.low - TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_LOW; - - if (file_format_id.high != TRX_SYS_FILE_FORMAT_TAG_MAGIC_N_HIGH - || *format_id >= FILE_FORMAT_NAME_N) { + if (file_format_id >= FILE_FORMAT_NAME_N) { /* Either it has never been tagged, or garbage in it. */ - *format_id = ULINT_UNDEFINED; return(TRUE); } - + + *format_id = (ulint) file_format_id; + return(TRUE); } diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c index c794671f7be..19e3eb26421 100644 --- a/storage/innobase/trx/trx0trx.c +++ b/storage/innobase/trx/trx0trx.c @@ -109,8 +109,8 @@ trx_create( trx->isolation_level = TRX_ISO_REPEATABLE_READ; - trx->id = ut_dulint_zero; - trx->no = ut_dulint_max; + trx->id = 0; + trx->no = IB_ULONGLONG_MAX; trx->support_xa = TRUE; @@ -121,7 +121,7 @@ trx_create( trx->must_flush_log_later = FALSE; trx->dict_operation = TRX_DICT_OP_NONE; - trx->table_id = ut_dulint_zero; + trx->table_id = 0; trx->mysql_thd = NULL; trx->active_trans = 0; @@ -137,8 +137,8 @@ trx_create( trx->rseg = NULL; - trx->undo_no = ut_dulint_zero; - trx->last_sql_stat_start.least_undo_no = ut_dulint_zero; + trx->undo_no = 0; + trx->last_sql_stat_start.least_undo_no = 0; trx->insert_undo = NULL; trx->update_undo = NULL; trx->undo_no_arr = NULL; @@ -392,9 +392,9 @@ trx_list_insert_ordered( trx2 = UT_LIST_GET_FIRST(trx_sys->trx_list); while (trx2 != NULL) { - if (ut_dulint_cmp(trx->id, trx2->id) >= 0) { + if (trx->id >= trx2->id) { - ut_ad(ut_dulint_cmp(trx->id, trx2->id) == 1); + ut_ad(trx->id > trx2->id); break; } trx2 = UT_LIST_GET_NEXT(trx_list, trx2); @@ -463,7 +463,7 @@ trx_lists_init_at_db_start(void) TRX_ID_FMT " was in the" " XA prepared state.\n", - TRX_ID_PREP_PRINTF(trx->id)); + (ullint) trx->id); if (srv_force_recovery == 0) { @@ -495,9 +495,9 @@ trx_lists_init_at_db_start(void) trx->conc_state = TRX_ACTIVE; /* A running transaction always has the number - field inited to ut_dulint_max */ + field inited to IB_ULONGLONG_MAX */ - trx->no = ut_dulint_max; + trx->no = IB_ULONGLONG_MAX; } if (undo->dict_operation) { @@ -507,8 +507,7 @@ trx_lists_init_at_db_start(void) } if (!undo->empty) { - trx->undo_no = ut_dulint_add(undo->top_undo_no, - 1); + trx->undo_no = undo->top_undo_no + 1; } trx_list_insert_ordered(trx); @@ -539,8 +538,7 @@ trx_lists_init_at_db_start(void) "InnoDB: Transaction " TRX_ID_FMT " was in the" " XA prepared state.\n", - TRX_ID_PREP_PRINTF( - trx->id)); + (ullint) trx->id); if (srv_force_recovery == 0) { @@ -571,9 +569,9 @@ trx_lists_init_at_db_start(void) /* A running transaction always has the number field inited to - ut_dulint_max */ + IB_ULONGLONG_MAX */ - trx->no = ut_dulint_max; + trx->no = IB_ULONGLONG_MAX; } trx->rseg = rseg; @@ -589,11 +587,9 @@ trx_lists_init_at_db_start(void) trx->update_undo = undo; if ((!undo->empty) - && (ut_dulint_cmp(undo->top_undo_no, - trx->undo_no) >= 0)) { + && undo->top_undo_no >= trx->undo_no) { - trx->undo_no = ut_dulint_add(undo->top_undo_no, - 1); + trx->undo_no = undo->top_undo_no + 1; } undo = UT_LIST_GET_NEXT(undo_list, undo); @@ -655,7 +651,7 @@ trx_start_low( ut_ad(trx->rseg == NULL); if (trx->is_purge) { - trx->id = ut_dulint_zero; + trx->id = 0; trx->conc_state = TRX_ACTIVE; trx->start_time = time(NULL); @@ -673,10 +669,10 @@ trx_start_low( trx->id = trx_sys_get_new_trx_id(); - /* The initial value for trx->no: ut_dulint_max is used in + /* The initial value for trx->no: IB_ULONGLONG_MAX is used in read_view_open_now: */ - trx->no = ut_dulint_max; + trx->no = IB_ULONGLONG_MAX; trx->rseg = rseg; @@ -941,8 +937,8 @@ trx_commit_off_kernel( trx->conc_state = TRX_NOT_STARTED; trx->rseg = NULL; - trx->undo_no = ut_dulint_zero; - trx->last_sql_stat_start.least_undo_no = ut_dulint_zero; + trx->undo_no = 0; + trx->last_sql_stat_start.least_undo_no = 0; ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0); ut_ad(UT_LIST_GET_LEN(trx->trx_locks) == 0); @@ -967,8 +963,8 @@ trx_cleanup_at_db_startup( trx->conc_state = TRX_NOT_STARTED; trx->rseg = NULL; - trx->undo_no = ut_dulint_zero; - trx->last_sql_stat_start.least_undo_no = ut_dulint_zero; + trx->undo_no = 0; + trx->last_sql_stat_start.least_undo_no = 0; UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx); } @@ -1631,7 +1627,7 @@ trx_mark_sql_stat_end( ut_a(trx); if (trx->conc_state == TRX_NOT_STARTED) { - trx->undo_no = ut_dulint_zero; + trx->undo_no = 0; } trx->last_sql_stat_start.least_undo_no = trx->undo_no; @@ -1651,7 +1647,7 @@ trx_print( { ibool newline; - fprintf(f, "TRANSACTION " TRX_ID_FMT, TRX_ID_PREP_PRINTF(trx->id)); + fprintf(f, "TRANSACTION " TRX_ID_FMT, (ullint) trx->id); switch (trx->conc_state) { case TRX_NOT_STARTED: @@ -1735,10 +1731,10 @@ trx_print( fputs(", holds adaptive hash latch", f); } - if (!ut_dulint_is_zero(trx->undo_no)) { + if (trx->undo_no != 0) { newline = TRUE; - fprintf(f, ", undo log entries %lu", - (ulong) ut_dulint_get_low(trx->undo_no)); + fprintf(f, ", undo log entries %llu", + (ullint) trx->undo_no); } if (newline) { @@ -1754,11 +1750,11 @@ trx_print( Compares the "weight" (or size) of two transactions. Transactions that have edited non-transactional tables are considered heavier than ones that have not. -@return <0, 0 or >0; similar to strcmp(3) */ +@return TRUE if weight(a) >= weight(b) */ UNIV_INTERN -int -trx_weight_cmp( -/*===========*/ +ibool +trx_weight_ge( +/*==========*/ const trx_t* a, /*!< in: the first transaction to be compared */ const trx_t* b) /*!< in: the second transaction to be compared */ { @@ -1769,19 +1765,14 @@ trx_weight_cmp( not edited non-transactional tables. */ a_notrans_edit = a->mysql_thd != NULL - && thd_has_edited_nontrans_tables(a->mysql_thd); + && thd_has_edited_nontrans_tables(a->mysql_thd); b_notrans_edit = b->mysql_thd != NULL - && thd_has_edited_nontrans_tables(b->mysql_thd); - - if (a_notrans_edit && !b_notrans_edit) { - - return(1); - } + && thd_has_edited_nontrans_tables(b->mysql_thd); - if (!a_notrans_edit && b_notrans_edit) { + if (a_notrans_edit != b_notrans_edit) { - return(-1); + return(a_notrans_edit); } /* Either both had edited non-transactional tables or both had @@ -1792,13 +1783,11 @@ trx_weight_cmp( fprintf(stderr, "%s TRX_WEIGHT(a): %lld+%lu, TRX_WEIGHT(b): %lld+%lu\n", __func__, - ut_conv_dulint_to_longlong(a->undo_no), - UT_LIST_GET_LEN(a->trx_locks), - ut_conv_dulint_to_longlong(b->undo_no), - UT_LIST_GET_LEN(b->trx_locks)); + a->undo_no, UT_LIST_GET_LEN(a->trx_locks), + b->undo_no, UT_LIST_GET_LEN(b->trx_locks)); #endif - return(ut_dulint_cmp(TRX_WEIGHT(a), TRX_WEIGHT(b))); + return(TRX_WEIGHT(a) >= TRX_WEIGHT(b)); } /****************************************************************//** @@ -1980,14 +1969,13 @@ trx_recover_for_mysql( fprintf(stderr, " InnoDB: Transaction " TRX_ID_FMT " in" " prepared state after recovery\n", - TRX_ID_PREP_PRINTF(trx->id)); + (ullint) trx->id); ut_print_timestamp(stderr); fprintf(stderr, " InnoDB: Transaction contains changes" - " to %lu rows\n", - (ulong) ut_conv_dulint_to_longlong( - trx->undo_no)); + " to %llu rows\n", + (ullint) trx->undo_no); count++; @@ -2036,7 +2024,7 @@ trx_get_trx_by_xid( while (trx) { /* Compare two X/Open XA transaction id's: their length should be the same and binary comparison - of gtrid_lenght+bqual_length bytes should be + of gtrid_length+bqual_length bytes should be the same */ if (xid->gtrid_length == trx->xid.gtrid_length diff --git a/storage/innobase/trx/trx0undo.c b/storage/innobase/trx/trx0undo.c index eb5112c4d31..90fc98f419d 100644 --- a/storage/innobase/trx/trx0undo.c +++ b/storage/innobase/trx/trx0undo.c @@ -515,7 +515,7 @@ trx_undo_header_create_log( { mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_CREATE, mtr); - mlog_catenate_dulint_compressed(mtr, trx_id); + mlog_catenate_ull_compressed(mtr, trx_id); } #else /* !UNIV_HOTBACKUP */ # define trx_undo_header_create_log(undo_page,trx_id,mtr) ((void) 0) @@ -687,7 +687,7 @@ trx_undo_insert_header_reuse_log( { mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_REUSE, mtr); - mlog_catenate_dulint_compressed(mtr, trx_id); + mlog_catenate_ull_compressed(mtr, trx_id); } #else /* !UNIV_HOTBACKUP */ # define trx_undo_insert_header_reuse_log(undo_page,trx_id,mtr) ((void) 0) @@ -707,8 +707,14 @@ trx_undo_parse_page_header( mtr_t* mtr) /*!< in: mtr or NULL */ { trx_id_t trx_id; + /* Silence a GCC warning about possibly uninitialized variable + when mach_ull_parse_compressed() is not inlined. */ + ut_d(trx_id = 0); + /* Declare the variable uninitialized in Valgrind, so that the + above initialization will not mask any bugs. */ + UNIV_MEM_INVALID(&trx_id, sizeof trx_id); - ptr = mach_dulint_parse_compressed(ptr, end_ptr, &trx_id); + ptr = mach_ull_parse_compressed(ptr, end_ptr, &trx_id); if (ptr == NULL) { @@ -1098,8 +1104,7 @@ trx_undo_truncate_end( break; } - if (ut_dulint_cmp(trx_undo_rec_get_undo_no(rec), limit) - >= 0) { + if (trx_undo_rec_get_undo_no(rec) >= limit) { /* Truncate at least this record off, maybe more */ trunc_here = rec; @@ -1152,7 +1157,7 @@ trx_undo_truncate_start( ut_ad(mutex_own(&(rseg->mutex))); - if (ut_dulint_is_zero(limit)) { + if (!limit) { return; } @@ -1174,7 +1179,7 @@ loop: last_rec = trx_undo_page_get_last_rec(undo_page, hdr_page_no, hdr_offset); - if (ut_dulint_cmp(trx_undo_rec_get_undo_no(last_rec), limit) >= 0) { + if (trx_undo_rec_get_undo_no(last_rec) >= limit) { mtr_commit(&mtr); @@ -1296,7 +1301,7 @@ trx_undo_mem_create_at_db_start( undo_header = undo_page + offset; - trx_id = mtr_read_dulint(undo_header + TRX_UNDO_TRX_ID, mtr); + trx_id = mach_read_from_8(undo_header + TRX_UNDO_TRX_ID); xid_exists = mtr_read_ulint(undo_header + TRX_UNDO_XID_EXISTS, MLOG_1BYTE, mtr); @@ -1320,7 +1325,7 @@ trx_undo_mem_create_at_db_start( undo->dict_operation = mtr_read_ulint( undo_header + TRX_UNDO_DICT_TRANS, MLOG_1BYTE, mtr); - undo->table_id = mtr_read_dulint(undo_header + TRX_UNDO_TABLE_ID, mtr); + undo->table_id = mach_read_from_8(undo_header + TRX_UNDO_TABLE_ID); undo->state = state; undo->size = flst_get_len(seg_header + TRX_UNDO_PAGE_LIST, mtr); @@ -1709,7 +1714,7 @@ trx_undo_mark_as_dict_operation( ut_error; case TRX_DICT_OP_INDEX: /* Do not discard the table on recovery. */ - undo->table_id = ut_dulint_zero; + undo->table_id = 0; break; case TRX_DICT_OP_TABLE: undo->table_id = trx->table_id; @@ -1720,8 +1725,8 @@ trx_undo_mark_as_dict_operation( + TRX_UNDO_DICT_TRANS, TRUE, MLOG_1BYTE, mtr); - mlog_write_dulint(hdr_page + undo->hdr_offset + TRX_UNDO_TABLE_ID, - undo->table_id, mtr); + mlog_write_ull(hdr_page + undo->hdr_offset + TRX_UNDO_TABLE_ID, + undo->table_id, mtr); undo->dict_operation = TRUE; } diff --git a/storage/innobase/ut/ut0byte.c b/storage/innobase/ut/ut0byte.c index 4e093f72ce2..535f74b8907 100644 --- a/storage/innobase/ut/ut0byte.c +++ b/storage/innobase/ut/ut0byte.c @@ -28,28 +28,3 @@ Created 5/11/1994 Heikki Tuuri #ifdef UNIV_NONINL #include "ut0byte.ic" #endif - -/** Zero value for a dulint */ -UNIV_INTERN const dulint ut_dulint_zero = {0, 0}; - -/** Maximum value for a dulint */ -UNIV_INTERN const dulint ut_dulint_max = {0xFFFFFFFFUL, 0xFFFFFFFFUL}; - -#ifdef notdefined /* unused code */ -#include "ut0sort.h" - -/************************************************************//** -Sort function for dulint arrays. */ -UNIV_INTERN -void -ut_dulint_sort( -/*===========*/ - dulint* arr, /*!< in/out: array to be sorted */ - dulint* aux_arr,/*!< in/out: auxiliary array (same size as arr) */ - ulint low, /*!< in: low bound of sort interval, inclusive */ - ulint high) /*!< in: high bound of sort interval, noninclusive */ -{ - UT_SORT_FUNCTION_BODY(ut_dulint_sort, arr, aux_arr, low, high, - ut_dulint_cmp); -} -#endif /* notdefined */ diff --git a/storage/myisam/mi_locking.c b/storage/myisam/mi_locking.c index 065f18965d1..6134b4f46df 100644 --- a/storage/myisam/mi_locking.c +++ b/storage/myisam/mi_locking.c @@ -29,7 +29,6 @@ int mi_lock_database(MI_INFO *info, int lock_type) int error; uint count; MYISAM_SHARE *share=info->s; - uint flag; DBUG_ENTER("mi_lock_database"); DBUG_PRINT("enter",("lock_type: %d old lock %d r_locks: %u w_locks: %u " "global_changed: %d open_count: %u name: '%s'", @@ -49,7 +48,7 @@ int mi_lock_database(MI_INFO *info, int lock_type) DBUG_RETURN(0); } - flag=error=0; + error= 0; mysql_mutex_lock(&share->intern_lock); if (share->kfile >= 0) /* May only be false on windows */ { @@ -121,14 +120,12 @@ int mi_lock_database(MI_INFO *info, int lock_type) { if (share->r_locks) { /* Only read locks left */ - flag=1; if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF, MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error) error=my_errno; } else if (!share->w_locks) { /* No more locks */ - flag=1; if (my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF, MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error) error=my_errno; @@ -150,7 +147,6 @@ int mi_lock_database(MI_INFO *info, int lock_type) */ if (share->w_locks == 1) { - flag=1; if (my_lock(share->kfile,lock_type,0L,F_TO_EOF, MYF(MY_SEEK_NOT_DONE))) { @@ -165,7 +161,6 @@ int mi_lock_database(MI_INFO *info, int lock_type) } if (!share->r_locks && !share->w_locks) { - flag=1; if (my_lock(share->kfile,lock_type,0L,F_TO_EOF, info->lock_wait | MY_SEEK_NOT_DONE)) { @@ -191,7 +186,6 @@ int mi_lock_database(MI_INFO *info, int lock_type) { /* Change READONLY to RW */ if (share->r_locks == 1) { - flag=1; if (my_lock(share->kfile,lock_type,0L,F_TO_EOF, MYF(info->lock_wait | MY_SEEK_NOT_DONE))) { @@ -208,7 +202,6 @@ int mi_lock_database(MI_INFO *info, int lock_type) { if (!share->w_locks) { - flag=1; if (my_lock(share->kfile,lock_type,0L,F_TO_EOF, info->lock_wait | MY_SEEK_NOT_DONE)) { @@ -256,11 +249,6 @@ int mi_lock_database(MI_INFO *info, int lock_type) } #endif mysql_mutex_unlock(&share->intern_lock); -#if defined(FULL_LOG) || defined(_lint) - lock_type|=(int) (flag << 8); /* Set bit to set if real lock */ - myisam_log_command(MI_LOG_LOCK,info,(uchar*) &lock_type,sizeof(lock_type), - error); -#endif DBUG_RETURN(error); } /* mi_lock_database */ diff --git a/storage/myisam/mi_statrec.c b/storage/myisam/mi_statrec.c index 74fca5902f5..f83afa3c886 100644 --- a/storage/myisam/mi_statrec.c +++ b/storage/myisam/mi_statrec.c @@ -273,7 +273,12 @@ int _mi_read_rnd_static_record(MI_INFO *info, uchar *buf, DBUG_RETURN(error); } - /* Read record with cacheing */ + /* + Read record with caching. If my_b_read() returns TRUE, less than the + requested bytes have been read. In this case rec_cache.error is + either -1 for a read error, or contains the number of bytes copied + into the buffer. + */ error=my_b_read(&info->rec_cache,(uchar*) buf,share->base.reclength); if (info->s->base.pack_reclength != info->s->base.reclength && !error) { @@ -293,8 +298,17 @@ int _mi_read_rnd_static_record(MI_INFO *info, uchar *buf, info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED; DBUG_RETURN(0); } - /* my_errno should be set if rec_cache.error == -1 */ + /* error is TRUE. my_errno should be set if rec_cache.error == -1 */ if (info->rec_cache.error != -1 || my_errno == 0) - my_errno=HA_ERR_WRONG_IN_RECORD; + { + /* + If we could not get a full record, we either have a broken record, + or are at end of file. + */ + if (info->rec_cache.error == 0) + my_errno= HA_ERR_END_OF_FILE; + else + my_errno= HA_ERR_WRONG_IN_RECORD; + } DBUG_RETURN(my_errno); /* Something wrong (EOF?) */ } diff --git a/storage/myisam/rt_split.c b/storage/myisam/rt_split.c index 88cf643faf9..03d22de68fa 100644 --- a/storage/myisam/rt_split.c +++ b/storage/myisam/rt_split.c @@ -255,7 +255,6 @@ int rtree_split_page(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key, SplitStruct *stop; double *coord_buf; double *next_coord; - double *old_coord; int n_dim; uchar *source_cur, *cur1, *cur2; uchar *new_page= info->buff; @@ -293,8 +292,6 @@ int rtree_split_page(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key, rtree_d_mbr(keyinfo->seg, key, key_length, cur->coords); cur->key = key; - old_coord = next_coord; - if (split_rtree_node(task, max_keys + 1, mi_getint(page) + full_length + 2, full_length, rt_PAGE_MIN_SIZE(keyinfo->block_length), diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc index eb43e141f27..f62aff4e383 100644 --- a/storage/myisammrg/ha_myisammrg.cc +++ b/storage/myisammrg/ha_myisammrg.cc @@ -475,10 +475,7 @@ int ha_myisammrg::add_children_list(void) child_l->parent_l= parent_l; /* Copy select_lex. Used in unique_table() at least. */ child_l->select_lex= parent_l->select_lex; - /* - Set the expected table version, to not cause spurious re-prepare. - @todo: revise after the fix for Bug#36171 - */ + /* Set the expected table version, to not cause spurious re-prepare. */ child_l->set_table_ref_id(mrg_child_def->get_child_table_ref_type(), mrg_child_def->get_child_def_version()); /* Link TABLE_LIST object into the children list. */ @@ -617,15 +614,17 @@ extern "C" MI_INFO *myisammrg_attach_children_callback(void *callback_param) param->need_compat_check= TRUE; /* - If parent is temporary, children must be temporary too and vice - versa. This check must be done for every child on every open because - the table def version can overlap between temporary and - non-temporary tables. We need to detect the case where a - non-temporary table has been replaced with a temporary table of the - same version. Or vice versa. A very unlikely case, but it could - happen. + If child is temporary, parent must be temporary as well. Other + parent/child combinations are allowed. This check must be done for + every child on every open because the table def version can overlap + between temporary and non-temporary tables. We need to detect the + case where a non-temporary table has been replaced with a temporary + table of the same version. Or vice versa. A very unlikely case, but + it could happen. (Note that the condition was different from + 5.1.23/6.0.4(Bug#19627) to 5.5.6 (Bug#36171): child->s->tmp_table != + parent->s->tmp_table. Tables were required to have the same status.) */ - if (child->s->tmp_table != parent->s->tmp_table) + if (child->s->tmp_table && !parent->s->tmp_table) { DBUG_PRINT("error", ("temporary table mismatch parent: %d child: %d", parent->s->tmp_table, child->s->tmp_table)); @@ -1321,6 +1320,8 @@ int ha_myisammrg::extra(enum ha_extra_function operation) if (operation == HA_EXTRA_FORCE_REOPEN || operation == HA_EXTRA_PREPARE_FOR_DROP) return 0; + if (operation == HA_EXTRA_MMAP && !opt_myisam_use_mmap) + return 0; return myrg_extra(file,operation,0); } diff --git a/storage/myisammrg/myrg_open.c b/storage/myisammrg/myrg_open.c index c9e19d32e96..b8e86b89181 100644 --- a/storage/myisammrg/myrg_open.c +++ b/storage/myisammrg/myrg_open.c @@ -226,9 +226,7 @@ MYRG_INFO *myrg_parent_open(const char *parent_name, int save_errno; int insert_method; uint length; - uint dir_length; uint child_count; - size_t name_buff_length; File fd; IO_CACHE file_cache; char parent_name_buff[FN_REFLEN * 2]; @@ -300,7 +298,6 @@ MYRG_INFO *myrg_parent_open(const char *parent_name, } /* Call callback for each child. */ - dir_length= dirname_part(parent_name_buff, parent_name, &name_buff_length); my_b_seek(&file_cache, 0); while ((length= my_b_gets(&file_cache, child_name_buff, FN_REFLEN - 1))) { @@ -381,7 +378,6 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking, { ulonglong file_offset; MI_INFO *myisam; - int rc; int errpos; int save_errno; uint idx; @@ -400,7 +396,6 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking, here and in ha_myisammrg::store_lock() forces consistent data. */ mysql_mutex_lock(&m_info->mutex); - rc= 1; errpos= 0; file_offset= 0; min_keys= 0; diff --git a/strings/ctype-big5.c b/strings/ctype-big5.c index f5221bb3a21..3007d76a5a4 100644 --- a/strings/ctype-big5.c +++ b/strings/ctype-big5.c @@ -994,86 +994,6 @@ static int my_strxfrm_big5(uchar *dest, const uchar *src, int len) #endif -/* -** Calculate min_str and max_str that ranges a LIKE string. -** Arguments: -** ptr Pointer to LIKE string. -** ptr_length Length of LIKE string. -** escape Escape character in LIKE. (Normally '\'). -** All escape characters should be removed from min_str and max_str -** res_length Length of min_str and max_str. -** min_str Smallest case sensitive string that ranges LIKE. -** Should be space padded to res_length. -** max_str Largest case sensitive string that ranges LIKE. -** Normally padded with the biggest character sort value. -** -** The function should return 0 if ok and 1 if the LIKE string can't be -** optimized ! -*/ - -#define max_sort_char ((char) 255) - -static my_bool my_like_range_big5(CHARSET_INFO *cs __attribute__((unused)), - const char *ptr,size_t ptr_length, - pbool escape, pbool w_one, pbool w_many, - size_t res_length, - char *min_str, char *max_str, - size_t *min_length, size_t *max_length) -{ - const char *end= ptr + ptr_length; - char *min_org=min_str; - char *min_end=min_str+res_length; - size_t charlen= res_length / cs->mbmaxlen; - - for (; ptr != end && min_str != min_end && charlen > 0; ptr++, charlen--) - { - if (ptr+1 != end && isbig5code(ptr[0],ptr[1])) - { - *min_str++= *max_str++ = *ptr++; - *min_str++= *max_str++ = *ptr; - continue; - } - if (*ptr == escape && ptr+1 != end) - { - ptr++; /* Skip escape */ - if (isbig5code(ptr[0], ptr[1])) - *min_str++= *max_str++ = *ptr++; - if (min_str < min_end) - *min_str++= *max_str++= *ptr; - continue; - } - if (*ptr == w_one) /* '_' in SQL */ - { - *min_str++='\0'; /* This should be min char */ - *max_str++=max_sort_char; - continue; - } - if (*ptr == w_many) /* '%' in SQL */ - { - /* - Calculate length of keys: - 'a\0\0... is the smallest possible string when we have space expand - a\ff\ff... is the biggest possible string - */ - *min_length= ((cs->state & MY_CS_BINSORT) ? (size_t) (min_str - min_org) : - res_length); - *max_length= res_length; - do { - *min_str++ = 0; - *max_str++ = max_sort_char; - } while (min_str != min_end); - return 0; - } - *min_str++= *max_str++ = *ptr; - } - - *min_length= *max_length= (size_t) (min_str-min_org); - while (min_str != min_end) - *min_str++= *max_str++= ' '; - return 0; -} - - static uint ismbchar_big5(CHARSET_INFO *cs __attribute__((unused)), const char* p, const char *e) { @@ -6955,7 +6875,7 @@ static MY_COLLATION_HANDLER my_collation_big5_chinese_ci_handler = my_strnncollsp_big5, my_strnxfrm_big5, my_strnxfrmlen_simple, - my_like_range_big5, + my_like_range_mb, my_wildcmp_mb, my_strcasecmp_mb, my_instr_mb, @@ -7019,7 +6939,7 @@ CHARSET_INFO my_charset_big5_chinese_ci= 1, /* mbminlen */ 2, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xF9D5, /* max_sort_char */ ' ', /* pad char */ 1, /* escape_with_backslash_is_dangerous */ &my_charset_big5_handler, @@ -7052,7 +6972,7 @@ CHARSET_INFO my_charset_big5_bin= 1, /* mbminlen */ 2, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xF9FE, /* max_sort_char */ ' ', /* pad char */ 1, /* escape_with_backslash_is_dangerous */ &my_charset_big5_handler, diff --git a/strings/ctype-cp932.c b/strings/ctype-cp932.c index 67555ac4384..df4083c9f8d 100644 --- a/strings/ctype-cp932.c +++ b/strings/ctype-cp932.c @@ -1812,77 +1812,6 @@ static size_t my_strnxfrm_cp932(CHARSET_INFO *cs __attribute__((unused)), } -/* -** Calculate min_str and max_str that ranges a LIKE string. -** Arguments: -** ptr Pointer to LIKE string. -** ptr_length Length of LIKE string. -** escape Escape character in LIKE. (Normally '\'). -** All escape characters should be removed from min_str and max_str -** res_length Length of min_str and max_str. -** min_str Smallest case sensitive string that ranges LIKE. -** Should be space padded to res_length. -** max_str Largest case sensitive string that ranges LIKE. -** Normally padded with the biggest character sort value. -** -** The function should return 0 if ok and 1 if the LIKE string can't be -** optimized ! -*/ - -#define max_sort_char ((char) 255) - -static my_bool my_like_range_cp932(CHARSET_INFO *cs __attribute__((unused)), - const char *ptr,size_t ptr_length, - pbool escape, pbool w_one, pbool w_many, - size_t res_length, - char *min_str,char *max_str, - size_t *min_length, size_t *max_length) -{ - const char *end=ptr+ptr_length; - char *min_org=min_str; - char *min_end=min_str+res_length; - - while (ptr < end && min_str < min_end) { - if (ismbchar_cp932(cs, ptr, end)) { - *min_str++ = *max_str++ = *ptr++; - if (min_str < min_end) - *min_str++ = *max_str++ = *ptr++; - continue; - } - if (*ptr == escape && ptr+1 < end) { - ptr++; /* Skip escape */ - if (ismbchar_cp932(cs, ptr, end)) - *min_str++ = *max_str++ = *ptr++; - if (min_str < min_end) - *min_str++ = *max_str++ = *ptr++; - continue; - } - if (*ptr == w_one) { /* '_' in SQL */ - *min_str++ = '\0'; /* This should be min char */ - *max_str++ = max_sort_char; - ptr++; - continue; - } - if (*ptr == w_many) - { /* '%' in SQL */ - *min_length = (size_t)(min_str - min_org); - *max_length = res_length; - do - { - *min_str++= 0; - *max_str++= max_sort_char; - } while (min_str < min_end); - return 0; - } - *min_str++ = *max_str++ = *ptr++; - } - *min_length = *max_length = (size_t) (min_str - min_org); - while (min_str < min_end) - *min_str++ = *max_str++ = ' '; /* Because if key compression */ - return 0; -} - - static uint16 cp932_to_unicode[65536]= { 0x0000, 0x0001, 0x0002, 0x0003, /* 0000 */ @@ -34852,7 +34781,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler = my_strnncollsp_cp932, my_strnxfrm_cp932, my_strnxfrmlen_simple, - my_like_range_cp932, + my_like_range_mb, my_wildcmp_mb, /* wildcmp */ my_strcasecmp_8bit, my_instr_mb, @@ -34918,7 +34847,7 @@ CHARSET_INFO my_charset_cp932_japanese_ci= 1, /* mbminlen */ 2, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xFCFC, /* max_sort_char */ ' ', /* pad char */ 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, @@ -34950,7 +34879,7 @@ CHARSET_INFO my_charset_cp932_bin= 1, /* mbminlen */ 2, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xFCFC, /* max_sort_char */ ' ', /* pad char */ 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, diff --git a/strings/ctype-euc_kr.c b/strings/ctype-euc_kr.c index c2067ac6f6b..7329f9ec09a 100644 --- a/strings/ctype-euc_kr.c +++ b/strings/ctype-euc_kr.c @@ -10029,7 +10029,7 @@ CHARSET_INFO my_charset_euckr_korean_ci= 1, /* mbminlen */ 2, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xFEFE, /* max_sort_char */ ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, @@ -10062,7 +10062,7 @@ CHARSET_INFO my_charset_euckr_bin= 1, /* mbminlen */ 2, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xFEFE, /* max_sort_char */ ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, diff --git a/strings/ctype-eucjpms.c b/strings/ctype-eucjpms.c index 25c15a08d4e..6180e0e1a7a 100644 --- a/strings/ctype-eucjpms.c +++ b/strings/ctype-eucjpms.c @@ -67573,7 +67573,7 @@ CHARSET_INFO my_charset_eucjpms_japanese_ci= 1, /* mbminlen */ 3, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xFEFE, /* max_sort_char */ ' ', /* pad_char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, @@ -67606,7 +67606,7 @@ CHARSET_INFO my_charset_eucjpms_bin= 1, /* mbminlen */ 3, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xFEFE, /* max_sort_char */ ' ', /* pad_char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, diff --git a/strings/ctype-gb2312.c b/strings/ctype-gb2312.c index 46f3e9c6da5..b1acd643df3 100644 --- a/strings/ctype-gb2312.c +++ b/strings/ctype-gb2312.c @@ -6432,7 +6432,7 @@ CHARSET_INFO my_charset_gb2312_chinese_ci= 1, /* mbminlen */ 2, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xF7FE, /* max_sort_char */ ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, @@ -6464,7 +6464,7 @@ CHARSET_INFO my_charset_gb2312_bin= 1, /* mbminlen */ 2, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xF7FE, /* max_sort_char */ ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, diff --git a/strings/ctype-gbk.c b/strings/ctype-gbk.c index 609bc2ecd27..547c8821229 100644 --- a/strings/ctype-gbk.c +++ b/strings/ctype-gbk.c @@ -3548,86 +3548,6 @@ static size_t my_strnxfrm_gbk(CHARSET_INFO *cs __attribute__((unused)), } -/* -** Calculate min_str and max_str that ranges a LIKE string. -** Arguments: -** ptr Pointer to LIKE string. -** ptr_length Length of LIKE string. -** escape Escape character in LIKE. (Normally '\'). -** All escape characters should be removed from min_str and max_str -** res_length Length of min_str and max_str. -** min_str Smallest case sensitive string that ranges LIKE. -** Should be space padded to res_length. -** max_str Largest case sensitive string that ranges LIKE. -** Normally padded with the biggest character sort value. -** -** The function should return 0 if ok and 1 if the LIKE string can't be -** optimized ! -*/ - -#define max_sort_char ((uchar) 255) - -static my_bool my_like_range_gbk(CHARSET_INFO *cs __attribute__((unused)), - const char *ptr,size_t ptr_length, - pbool escape, pbool w_one, pbool w_many, - size_t res_length, - char *min_str,char *max_str, - size_t *min_length,size_t *max_length) -{ - const char *end= ptr + ptr_length; - char *min_org=min_str; - char *min_end=min_str+res_length; - size_t charlen= res_length / cs->mbmaxlen; - - for (; ptr != end && min_str != min_end && charlen > 0; ptr++, charlen--) - { - if (ptr+1 != end && isgbkcode(ptr[0],ptr[1])) - { - *min_str++= *max_str++ = *ptr++; - *min_str++= *max_str++ = *ptr; - continue; - } - if (*ptr == escape && ptr+1 != end) - { - ptr++; /* Skip escape */ - if (isgbkcode(ptr[0], ptr[1])) - *min_str++= *max_str++ = *ptr; - if (min_str < min_end) - *min_str++= *max_str++= *ptr; - continue; - } - if (*ptr == w_one) /* '_' in SQL */ - { - *min_str++='\0'; /* This should be min char */ - *max_str++=max_sort_char; - continue; - } - if (*ptr == w_many) /* '%' in SQL */ - { - /* - Calculate length of keys: - 'a\0\0... is the smallest possible string when we have space expand - a\ff\ff... is the biggest possible string - */ - *min_length= ((cs->state & MY_CS_BINSORT) ? (size_t) (min_str - min_org) : - res_length); - *max_length= res_length; - do { - *min_str++= 0; - *max_str++= max_sort_char; - } while (min_str != min_end); - return 0; - } - *min_str++= *max_str++ = *ptr; - } - - *min_length= *max_length = (size_t) (min_str - min_org); - while (min_str != min_end) - *min_str++= *max_str++= ' '; /* Because if key compression */ - return 0; -} - - static uint ismbchar_gbk(CHARSET_INFO *cs __attribute__((unused)), const char* p, const char *e) { @@ -10841,7 +10761,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler = my_strnncollsp_gbk, my_strnxfrm_gbk, my_strnxfrmlen_simple, - my_like_range_gbk, + my_like_range_mb, my_wildcmp_mb, my_strcasecmp_mb, my_instr_mb, @@ -10906,7 +10826,7 @@ CHARSET_INFO my_charset_gbk_chinese_ci= 1, /* mbminlen */ 2, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xA967, /* max_sort_char */ ' ', /* pad char */ 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, @@ -10938,7 +10858,7 @@ CHARSET_INFO my_charset_gbk_bin= 1, /* mbminlen */ 2, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xFEFE, /* max_sort_char */ ' ', /* pad char */ 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, diff --git a/strings/ctype-mb.c b/strings/ctype-mb.c index b1b381da59e..b2f2e3cd22e 100644 --- a/strings/ctype-mb.c +++ b/strings/ctype-mb.c @@ -604,7 +604,9 @@ my_hash_sort_mb_bin(CHARSET_INFO *cs __attribute__((unused)), DESCRIPTION Write max key: - for non-Unicode character sets: - just set to 255. + just bfill using max_sort_char if max_sort_char is one byte. + In case when max_sort_char is two bytes, fill with double-byte pairs + and optionally pad with a single space character. - for Unicode character set (utf-8): create a buffer with multibyte representation of the max_sort_char character, and copy it into max_str in a loop. @@ -616,12 +618,20 @@ static void pad_max_char(CHARSET_INFO *cs, char *str, char *end) if (!(cs->state & MY_CS_UNICODE)) { - bfill(str, end - str, 255); - return; + if (cs->max_sort_char <= 255) + { + bfill(str, end - str, cs->max_sort_char); + return; + } + buf[0]= cs->max_sort_char >> 8; + buf[1]= cs->max_sort_char & 0xFF; + buflen= 2; + } + else + { + buflen= cs->cset->wc_mb(cs, cs->max_sort_char, (uchar*) buf, + (uchar*) buf + sizeof(buf)); } - - buflen= cs->cset->wc_mb(cs, cs->max_sort_char, (uchar*) buf, - (uchar*) buf + sizeof(buf)); DBUG_ASSERT(buflen > 0); do diff --git a/strings/ctype-sjis.c b/strings/ctype-sjis.c index 90c76dc3c79..91adf4ebddf 100644 --- a/strings/ctype-sjis.c +++ b/strings/ctype-sjis.c @@ -1179,86 +1179,6 @@ static size_t my_strnxfrm_sjis(CHARSET_INFO *cs __attribute__((unused)), } -/* -** Calculate min_str and max_str that ranges a LIKE string. -** Arguments: -** ptr Pointer to LIKE string. -** ptr_length Length of LIKE string. -** escape Escape character in LIKE. (Normally '\'). -** All escape characters should be removed from min_str and max_str -** res_length Length of min_str and max_str. -** min_str Smallest case sensitive string that ranges LIKE. -** Should be space padded to res_length. -** max_str Largest case sensitive string that ranges LIKE. -** Normally padded with the biggest character sort value. -** -** The function should return 0 if ok and 1 if the LIKE string can't be -** optimized ! -*/ - -#define max_sort_char ((char) 255) - -static my_bool my_like_range_sjis(CHARSET_INFO *cs __attribute__((unused)), - const char *ptr,size_t ptr_length, - pbool escape, pbool w_one, pbool w_many, - size_t res_length, - char *min_str,char *max_str, - size_t *min_length,size_t *max_length) -{ - const char *end= ptr + ptr_length; - char *min_org=min_str; - char *min_end=min_str+res_length; - size_t charlen= res_length / cs->mbmaxlen; - - for ( ; ptr < end && min_str < min_end && charlen > 0 ; charlen--) - { - if (ismbchar_sjis(cs, ptr, end)) { - *min_str++ = *max_str++ = *ptr++; - if (min_str < min_end) - *min_str++ = *max_str++ = *ptr++; - continue; - } - if (*ptr == escape && ptr+1 < end) { - ptr++; /* Skip escape */ - if (ismbchar_sjis(cs, ptr, end)) - *min_str++ = *max_str++ = *ptr++; - if (min_str < min_end) - *min_str++ = *max_str++ = *ptr++; - continue; - } - if (*ptr == w_one) { /* '_' in SQL */ - *min_str++ = '\0'; /* This should be min char */ - *max_str++ = max_sort_char; - ptr++; - continue; - } - if (*ptr == w_many) - { /* '%' in SQL */ - /* - Calculate length of keys: - 'a\0\0... is the smallest possible string when we have space expand - a\ff\ff... is the biggest possible string - */ - *min_length= ((cs->state & MY_CS_BINSORT) ? (size_t) (min_str - min_org) : - res_length); - *max_length= res_length; - do - { - *min_str++= 0; - *max_str++= max_sort_char; - } while (min_str < min_end); - return 0; - } - *min_str++ = *max_str++ = *ptr++; - } - - *min_length= *max_length= (size_t) (min_str - min_org); - while (min_str != min_end) - *min_str++= *max_str++= ' '; /* Because if key compression */ - return 0; -} - - /* SJIS->Unicode conversion table */ static uint16 sjis_to_unicode[65536]= { @@ -34231,7 +34151,7 @@ static MY_COLLATION_HANDLER my_collation_ci_handler = my_strnncollsp_sjis, my_strnxfrm_sjis, my_strnxfrmlen_simple, - my_like_range_sjis, + my_like_range_mb, my_wildcmp_mb, /* wildcmp */ my_strcasecmp_8bit, my_instr_mb, @@ -34297,7 +34217,7 @@ CHARSET_INFO my_charset_sjis_japanese_ci= 1, /* mbminlen */ 2, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xFCFC, /* max_sort_char */ ' ', /* pad char */ 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, @@ -34329,7 +34249,7 @@ CHARSET_INFO my_charset_sjis_bin= 1, /* mbminlen */ 2, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xFCFC, /* max_sort_char */ ' ', /* pad char */ 1, /* escape_with_backslash_is_dangerous */ &my_charset_handler, diff --git a/strings/ctype-ujis.c b/strings/ctype-ujis.c index 4fabbdbaeb3..9f4d032ffe0 100644 --- a/strings/ctype-ujis.c +++ b/strings/ctype-ujis.c @@ -67316,7 +67316,7 @@ CHARSET_INFO my_charset_ujis_japanese_ci= 1, /* mbminlen */ 3, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xFEFE, /* max_sort_char */ ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, @@ -67349,7 +67349,7 @@ CHARSET_INFO my_charset_ujis_bin= 1, /* mbminlen */ 3, /* mbmaxlen */ 0, /* min_sort_char */ - 255, /* max_sort_char */ + 0xFEFE, /* max_sort_char */ ' ', /* pad char */ 0, /* escape_with_backslash_is_dangerous */ &my_charset_handler, diff --git a/strings/decimal.c b/strings/decimal.c index 99b7ccd3249..7625ed80ec3 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -1917,8 +1917,7 @@ static int do_sub(decimal_t *from1, decimal_t *from2, decimal_t *to) int decimal_intg(decimal_t *from) { int res; - dec1 *tmp_res; - tmp_res= remove_leading_zeroes(from, &res); + remove_leading_zeroes(from, &res); return res; } diff --git a/unittest/Makefile.am b/unittest/Makefile.am index 6197586b008..da655d1844e 100644 --- a/unittest/Makefile.am +++ b/unittest/Makefile.am @@ -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 -SUBDIRS = mytap . mysys examples +SUBDIRS = mytap . mysys examples strings EXTRA_DIST = unit.pl CLEANFILES = unit -unittests = mytap mysys @mysql_se_unittest_dirs@ @mysql_pg_unittest_dirs@ +unittests = mytap mysys strings @mysql_se_unittest_dirs@ @mysql_pg_unittest_dirs@ test: perl unit.pl run $(unittests) diff --git a/unittest/strings/Makefile.am b/unittest/strings/Makefile.am new file mode 100644 index 00000000000..5b18d89f58e --- /dev/null +++ b/unittest/strings/Makefile.am @@ -0,0 +1,27 @@ +# Copyright 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 +# 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 + +AM_CPPFLAGS = @ZLIB_INCLUDES@ -I$(top_builddir)/include +AM_CPPFLAGS += -I$(top_srcdir)/include -I$(top_srcdir)/unittest/mytap + +LDADD = $(top_builddir)/unittest/mytap/libmytap.a \ + $(top_builddir)/mysys/libmysys.a \ + $(top_builddir)/dbug/libdbug.a \ + $(top_builddir)/strings/libmystrings.a + +noinst_PROGRAMS = strings-t + +# Don't update the files from bitkeeper +%::SCCS/s.% diff --git a/unittest/strings/strings-t.c b/unittest/strings/strings-t.c new file mode 100644 index 00000000000..278f42e56a5 --- /dev/null +++ b/unittest/strings/strings-t.c @@ -0,0 +1,114 @@ +/* Copyright 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 + 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 */ + +#include <tap.h> +#include <my_global.h> +#include <my_sys.h> + + +/* + Test that like_range() returns well-formed results. +*/ +static int +test_like_range_for_charset(CHARSET_INFO *cs, const char *src, size_t src_len) +{ + char min_str[32], max_str[32]; + size_t min_len, max_len, min_well_formed_len, max_well_formed_len; + int error= 0; + + cs->coll->like_range(cs, src, src_len, '\\', '_', '%', + sizeof(min_str), min_str, max_str, &min_len, &max_len); + diag("min_len=%d\tmax_len=%d\t%s", (int) min_len, (int) max_len, cs->name); + min_well_formed_len= cs->cset->well_formed_len(cs, + min_str, min_str + min_len, + 10000, &error); + max_well_formed_len= cs->cset->well_formed_len(cs, + max_str, max_str + max_len, + 10000, &error); + if (min_len != min_well_formed_len) + diag("Bad min_str: min_well_formed_len=%d min_str[%d]=0x%02X", + (int) min_well_formed_len, (int) min_well_formed_len, + (uchar) min_str[min_well_formed_len]); + if (max_len != max_well_formed_len) + diag("Bad max_str: max_well_formed_len=%d max_str[%d]=0x%02X", + (int) max_well_formed_len, (int) max_well_formed_len, + (uchar) max_str[max_well_formed_len]); + return + min_len == min_well_formed_len && + max_len == max_well_formed_len ? 0 : 1; +} + + +static CHARSET_INFO *charset_list[]= +{ +#ifdef HAVE_CHARSET_big5 + &my_charset_big5_chinese_ci, + &my_charset_big5_bin, +#endif +#ifdef HAVE_CHARSET_euckr + &my_charset_euckr_korean_ci, + &my_charset_euckr_bin, +#endif +#ifdef HAVE_CHARSET_gb2312 + &my_charset_gb2312_chinese_ci, + &my_charset_gb2312_bin, +#endif +#ifdef HAVE_CHARSET_gbk + &my_charset_gbk_chinese_ci, + &my_charset_gbk_bin, +#endif +#ifdef HAVE_CHARSET_latin1 + &my_charset_latin1, + &my_charset_latin1_bin, +#endif +#ifdef HAVE_CHARSET_sjis + &my_charset_sjis_japanese_ci, + &my_charset_sjis_bin, +#endif +#ifdef HAVE_CHARSET_tis620 + &my_charset_tis620_thai_ci, + &my_charset_tis620_bin, +#endif +#ifdef HAVE_CHARSET_ujis + &my_charset_ujis_japanese_ci, + &my_charset_ujis_bin, +#endif +#ifdef HAVE_CHARSET_utf8 + &my_charset_utf8_general_ci, + &my_charset_utf8_unicode_ci, + &my_charset_utf8_bin, +#endif +}; + + +int main() +{ + size_t i, failed= 0; + + plan(1); + diag("Testing my_like_range_xxx() functions"); + + for (i= 0; i < array_elements(charset_list); i++) + { + CHARSET_INFO *cs= charset_list[i]; + if (test_like_range_for_charset(cs, "abc%", 4)) + { + ++failed; + diag("Failed for %s", cs->name); + } + } + ok(failed == 0, "Testing my_like_range_xxx() functions"); + return exit_status(); +} |