summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore9
-rwxr-xr-xBUILD/SETUP.sh10
-rw-r--r--client/mysqlbinlog.cc3
-rw-r--r--client/mysqltest.cc16
-rw-r--r--cmake/abi_check.cmake12
-rw-r--r--cmake/maintainer.cmake2
-rw-r--r--cmake/os/Windows.cmake3
-rw-r--r--cmake/os/WindowsCache.cmake7
-rw-r--r--cmd-line-utils/libedit/el.c21
-rw-r--r--cmd-line-utils/libedit/vi.c12
-rw-r--r--config.h.cmake9
-rw-r--r--configure.cmake44
-rw-r--r--extra/replace.c18
-rw-r--r--include/m_ctype.h2
-rw-r--r--include/my_global.h3
-rw-r--r--include/mysql.h4
-rw-r--r--include/mysql.h.pp3
-rw-r--r--include/mysql/client_plugin.h5
-rw-r--r--include/mysql/client_plugin.h.pp5
-rw-r--r--libmysql/CMakeLists.txt12
-rw-r--r--libmysql/authentication_win/CMakeLists.txt33
-rw-r--r--libmysql/authentication_win/common.cc492
-rw-r--r--libmysql/authentication_win/common.h324
-rw-r--r--libmysql/authentication_win/handshake.cc289
-rw-r--r--libmysql/authentication_win/handshake.h181
-rw-r--r--libmysql/authentication_win/handshake_client.cc378
-rw-r--r--libmysql/authentication_win/log_client.cc55
-rw-r--r--libmysql/authentication_win/plugin_client.cc58
-rw-r--r--libmysql/libmysql.c75
-rw-r--r--libmysql/libmysql.def1
-rw-r--r--mysql-test/collections/default.experimental11
-rw-r--r--mysql-test/extra/rpl_tests/rpl_extra_col_slave.test13
-rw-r--r--mysql-test/lib/My/ConfigFactory.pm8
-rw-r--r--mysql-test/lib/My/Find.pm5
-rw-r--r--mysql-test/lib/My/SafeProcess/safe_process.pl4
-rw-r--r--mysql-test/lib/mtr_gcov.pl24
-rwxr-xr-xmysql-test/mysql-test-run.pl74
-rw-r--r--mysql-test/r/alter_table.result13
-rw-r--r--mysql-test/r/events_1.result106
-rw-r--r--mysql-test/r/events_restart.result3
-rw-r--r--mysql-test/r/func_analyse.result13
-rw-r--r--mysql-test/r/func_group.result11
-rw-r--r--mysql-test/r/func_in.result6
-rw-r--r--mysql-test/r/func_math.result22
-rw-r--r--mysql-test/r/func_time.result12
-rw-r--r--mysql-test/r/having.result22
-rw-r--r--mysql-test/r/loaddata.result16
-rw-r--r--mysql-test/r/mysqlbinlog_base64.result10
-rw-r--r--mysql-test/r/partition_myisam.result9
-rw-r--r--mysql-test/r/subselect.result18
-rw-r--r--mysql-test/r/trigger.result20
-rw-r--r--mysql-test/r/type_timestamp.result63
-rw-r--r--mysql-test/r/warnings.result22
-rw-r--r--mysql-test/r/xa.result63
-rw-r--r--mysql-test/suite/binlog/r/binlog_bug23533.result15
-rw-r--r--mysql-test/suite/binlog/r/binlog_bug36391.result10
-rw-r--r--mysql-test/suite/binlog/t/binlog_bug23533.test (renamed from mysql-test/suite/bugs/t/rpl_bug23533.test)30
-rw-r--r--mysql-test/suite/binlog/t/binlog_bug36391-master.opt (renamed from mysql-test/suite/bugs/t/rpl_bug36391-master.opt)0
-rw-r--r--mysql-test/suite/binlog/t/binlog_bug36391.test (renamed from mysql-test/suite/bugs/t/rpl_bug36391.test)23
-rw-r--r--mysql-test/suite/bugs/combinations8
-rw-r--r--mysql-test/suite/bugs/data/rpl_bug12691.dat3
-rw-r--r--mysql-test/suite/bugs/r/bug57108.result5
-rw-r--r--mysql-test/suite/bugs/r/rpl_bug12691.result33
-rw-r--r--mysql-test/suite/bugs/r/rpl_bug23533.result23
-rw-r--r--mysql-test/suite/bugs/r/rpl_bug31582.result16
-rw-r--r--mysql-test/suite/bugs/r/rpl_bug31583.result16
-rw-r--r--mysql-test/suite/bugs/r/rpl_bug33029.result15
-rw-r--r--mysql-test/suite/bugs/r/rpl_bug36391.result18
-rw-r--r--mysql-test/suite/bugs/r/rpl_bug37426.result17
-rw-r--r--mysql-test/suite/bugs/r/rpl_bug38205.result56
-rw-r--r--mysql-test/suite/bugs/t/bug57108-master.opt2
-rw-r--r--mysql-test/suite/bugs/t/bug57108.test12
-rw-r--r--mysql-test/suite/bugs/t/rpl_bug12691.test48
-rw-r--r--mysql-test/suite/bugs/t/rpl_bug31582.test25
-rw-r--r--mysql-test/suite/bugs/t/rpl_bug31583.test25
-rw-r--r--mysql-test/suite/bugs/t/rpl_bug33029.test26
-rw-r--r--mysql-test/suite/bugs/t/rpl_bug38205.test166
-rw-r--r--mysql-test/suite/innodb/r/innodb_bug59410.result17
-rw-r--r--mysql-test/suite/innodb/r/innodb_bug59641.result57
-rwxr-xr-xmysql-test/suite/innodb/r/innodb_bug60196.result44
-rw-r--r--mysql-test/suite/innodb/t/innodb_bug59410.test24
-rw-r--r--mysql-test/suite/innodb/t/innodb_bug59641.test68
-rwxr-xr-xmysql-test/suite/innodb/t/innodb_bug60196.test70
-rw-r--r--mysql-test/suite/parts/inc/partition_check_drop.inc2
-rw-r--r--mysql-test/suite/parts/inc/partition_fail.inc2
-rw-r--r--mysql-test/suite/parts/inc/partition_layout_check1.inc3
-rw-r--r--mysql-test/suite/parts/inc/partition_layout_check2.inc3
-rw-r--r--mysql-test/suite/rpl/r/rpl_bug37426.result12
-rw-r--r--mysql-test/suite/rpl/r/rpl_server_id2.result2
-rw-r--r--mysql-test/suite/rpl/t/rpl_bug37426.test (renamed from mysql-test/suite/bugs/t/rpl_bug37426.test)11
-rw-r--r--mysql-test/suite/rpl/t/rpl_row_until.test12
-rw-r--r--mysql-test/suite/rpl/t/rpl_server_id2.test2
-rw-r--r--mysql-test/t/alter_table.test17
-rw-r--r--mysql-test/t/events_1.test109
-rw-r--r--mysql-test/t/events_restart.test2
-rw-r--r--mysql-test/t/func_analyse.test12
-rw-r--r--mysql-test/t/func_group.test12
-rw-r--r--mysql-test/t/func_in.test6
-rw-r--r--mysql-test/t/func_math.test16
-rw-r--r--mysql-test/t/func_time.test8
-rw-r--r--mysql-test/t/having.test26
-rw-r--r--mysql-test/t/loaddata.test28
-rw-r--r--mysql-test/t/mysqlbinlog_base64.test29
-rw-r--r--mysql-test/t/partition_myisam.test13
-rw-r--r--mysql-test/t/subselect.test22
-rw-r--r--mysql-test/t/trigger.test30
-rw-r--r--mysql-test/t/type_timestamp.test47
-rw-r--r--mysql-test/t/warnings.test40
-rw-r--r--mysql-test/t/xa.test94
-rw-r--r--mysys/my_init.c7
-rw-r--r--mysys/my_thr_init.c10
-rw-r--r--mysys/mysys_priv.h4
-rw-r--r--plugin/semisync/semisync_slave_plugin.cc4
-rw-r--r--sql-common/client.c7
-rw-r--r--sql-common/client_plugin.c2
-rw-r--r--sql-common/my_time.c3
-rw-r--r--sql/event_db_repository.cc22
-rw-r--r--sql/field.cc2
-rw-r--r--sql/ha_partition.cc429
-rw-r--r--sql/ha_partition.h35
-rw-r--r--sql/handler.cc27
-rw-r--r--sql/handler.h16
-rw-r--r--sql/item.cc35
-rw-r--r--sql/item_cmpfunc.cc16
-rw-r--r--sql/item_func.cc5
-rw-r--r--sql/item_row.cc2
-rw-r--r--sql/item_strfunc.cc2
-rw-r--r--sql/item_sum.cc6
-rw-r--r--sql/item_timefunc.cc6
-rw-r--r--sql/mdl.h15
-rw-r--r--sql/mysqld.cc4
-rw-r--r--sql/mysqld.h11
-rw-r--r--sql/opt_range.cc2
-rw-r--r--sql/opt_sum.cc43
-rw-r--r--sql/rpl_handler.h3
-rw-r--r--sql/slave.cc6
-rw-r--r--sql/sp_head.cc7
-rw-r--r--sql/sql_admin.cc45
-rw-r--r--sql/sql_base.cc8
-rw-r--r--sql/sql_class.cc14
-rw-r--r--sql/sql_class.h22
-rw-r--r--sql/sql_error.cc23
-rw-r--r--sql/sql_error.h28
-rw-r--r--sql/sql_load.cc11
-rw-r--r--sql/sql_parse.cc16
-rw-r--r--sql/sql_partition.cc2
-rw-r--r--sql/sql_plist.h16
-rw-r--r--sql/sql_prepare.cc7
-rw-r--r--sql/sql_select.cc56
-rw-r--r--sql/sql_select.h3
-rw-r--r--sql/sql_show.cc153
-rw-r--r--sql/sql_table.cc27
-rw-r--r--sql/sql_trigger.cc25
-rw-r--r--sql/transaction.cc54
-rw-r--r--storage/archive/ha_archive.cc26
-rw-r--r--storage/heap/ha_heap.cc4
-rw-r--r--storage/heap/ha_heap.h2
-rw-r--r--storage/innobase/btr/btr0cur.c4
-rw-r--r--storage/innobase/buf/buf0flu.c2
-rw-r--r--storage/innobase/dict/dict0dict.c5
-rw-r--r--storage/innobase/dict/dict0load.c2
-rw-r--r--storage/innobase/dict/dict0mem.c17
-rw-r--r--storage/innobase/fil/fil0fil.c6
-rw-r--r--storage/innobase/handler/ha_innodb.cc97
-rw-r--r--storage/innobase/handler/ha_innodb.h11
-rw-r--r--storage/innobase/handler/handler0alter.cc43
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.c13
-rw-r--r--storage/innobase/include/dict0mem.h10
-rw-r--r--storage/innobase/include/ha_prototypes.h11
-rw-r--r--storage/innobase/include/log0log.ic2
-rw-r--r--storage/innobase/include/os0sync.h5
-rw-r--r--storage/innobase/include/os0thread.h33
-rw-r--r--storage/innobase/include/srv0srv.h3
-rw-r--r--storage/innobase/include/sync0sync.h35
-rw-r--r--storage/innobase/include/trx0trx.h16
-rw-r--r--storage/innobase/include/trx0undo.h9
-rw-r--r--storage/innobase/include/univ.i15
-rw-r--r--storage/innobase/include/ut0dbg.h7
-rw-r--r--storage/innobase/include/ut0ut.h3
-rw-r--r--storage/innobase/log/log0log.c108
-rw-r--r--storage/innobase/os/os0file.c205
-rw-r--r--storage/innobase/os/os0sync.c52
-rw-r--r--storage/innobase/os/os0thread.c93
-rw-r--r--storage/innobase/row/row0merge.c2
-rw-r--r--storage/innobase/row/row0mysql.c14
-rw-r--r--storage/innobase/row/row0sel.c17
-rw-r--r--storage/innobase/srv/srv0srv.c85
-rw-r--r--storage/innobase/srv/srv0start.c23
-rw-r--r--storage/innobase/sync/sync0sync.c67
-rw-r--r--storage/innobase/trx/trx0roll.c4
-rw-r--r--storage/innobase/trx/trx0sys.c10
-rw-r--r--storage/innobase/trx/trx0trx.c78
-rw-r--r--storage/innobase/trx/trx0undo.c28
-rw-r--r--storage/myisam/ha_myisam.cc5
-rw-r--r--storage/myisam/ha_myisam.h2
-rw-r--r--storage/myisammrg/ha_myisammrg.cc6
-rw-r--r--storage/myisammrg/ha_myisammrg.h2
-rw-r--r--storage/ndb/src/kernel/blocks/lgman.cpp16
-rw-r--r--vio/viosocket.c36
199 files changed, 4834 insertions, 1727 deletions
diff --git a/.bzrignore b/.bzrignore
index 45cd7f2dc78..05597220950 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -43,6 +43,10 @@
*.vcxproj
*.vcxproj.filters
*/*.dir/*
+*.dir
+Debug
+MySql.sdf
+Win32
*/*_pure_*warnings
*/.deps
*/.libs/*
@@ -615,6 +619,7 @@ include/mysql_h.ic
include/mysql_version.h
include/mysqld_ername.h
include/mysqld_error.h
+include/mysqld_error.h.rule
include/openssl
include/probes_mysql_dtrace.h
include/readline
@@ -1897,7 +1902,9 @@ scripts/mysql_find_rows
scripts/mysql_fix_extensions
scripts/mysql_fix_privilege_tables
scripts/mysql_fix_privilege_tables.sql
+scripts/mysql_fix_privilege_tables.sql.rule
scripts/mysql_fix_privilege_tables_sql.c
+scripts/mysql_fix_privilege_tables_sql.c.rule
scripts/mysql_install_db
scripts/mysql_secure_installation
scripts/mysql_setpermission
@@ -2137,6 +2144,7 @@ sql/handlerton.cc
sql/html
sql/latex
sql/lex_hash.h
+sql/lex_hash.h.rule
sql/link_sources
sql/max/*
sql/message.h
@@ -2168,6 +2176,7 @@ sql/sql_builtin.cc
sql/sql_select.cc.orig
sql/sql_yacc.cc
sql/sql_yacc.h
+sql/sql_yacc.h.rule
sql/sql_yacc.output
sql/sql_yacc.yy.orig
sql/test_time
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh
index 2642788e360..c7f434d1bb3 100755
--- a/BUILD/SETUP.sh
+++ b/BUILD/SETUP.sh
@@ -31,6 +31,7 @@ Usage: $0 [-h|-n] [configure-options]
-h, --help Show this help message.
-n, --just-print Don't actually run any commands; just print them.
-c, --just-configure Stop after running configure.
+ --with-debug=full Build with full debug(no optimizations, keep call stack).
--warning-mode=[old|pedantic|maintainer]
Influences the debug flags. Old is default.
--prefix=path Build with prefix 'path'.
@@ -46,6 +47,8 @@ parse_options()
case "$1" in
--prefix=*)
prefix=`get_key_value "$1"`;;
+ --with-debug=full)
+ full_debug="=full";;
--warning-mode=*)
warning_mode=`get_key_value "$1"`;;
-c | --just-configure)
@@ -76,6 +79,7 @@ just_print=
just_configure=
warning_mode=
maintainer_mode=
+full_debug=
parse_options "$@"
@@ -154,7 +158,11 @@ base_cxxflags="-felide-constructors -fno-exceptions -fno-rtti"
fast_cflags="-O3 -fno-omit-frame-pointer"
debug_configs="--with-debug"
-debug_cflags="$debug_cflags $debug_extra_cflags"
+if [ -z "$full_debug" ]
+then
+ debug_cflags="$debug_cflags $debug_extra_cflags"
+fi
+
#
# Configuration options.
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index e8a37ecfe5f..b374fa748b9 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -966,7 +966,8 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
passed --short-form, because --short-form disables printing
row events.
*/
- if (!print_event_info->printed_fd_event && !short_form)
+ if (!print_event_info->printed_fd_event && !short_form &&
+ opt_base64_output_mode != BASE64_OUTPUT_DECODE_ROWS)
{
const char* type_str= ev->get_type_str();
if (opt_base64_output_mode == BASE64_OUTPUT_NEVER)
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index 4f067c54429..a6bd80059c1 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -4598,13 +4598,14 @@ static int my_kill(int pid, int sig)
command called command
DESCRIPTION
- shutdown [<timeout>]
+ shutdown_server [<timeout>]
*/
void do_shutdown_server(struct st_command *command)
{
- int timeout=60, pid;
+ long timeout=60;
+ int pid;
DYNAMIC_STRING ds_pidfile_name;
MYSQL* mysql = &cur_con->mysql;
static DYNAMIC_STRING ds_timeout;
@@ -4619,8 +4620,9 @@ void do_shutdown_server(struct st_command *command)
if (ds_timeout.length)
{
- timeout= atoi(ds_timeout.str);
- if (timeout == 0)
+ char* endptr;
+ timeout= strtol(ds_timeout.str, &endptr, 10);
+ if (*endptr != '\0')
die("Illegal argument for timeout: '%s'", ds_timeout.str);
}
dynstr_free(&ds_timeout);
@@ -4662,7 +4664,7 @@ void do_shutdown_server(struct st_command *command)
DBUG_PRINT("info", ("Process %d does not exist anymore", pid));
DBUG_VOID_RETURN;
}
- DBUG_PRINT("info", ("Sleeping, timeout: %d", timeout));
+ DBUG_PRINT("info", ("Sleeping, timeout: %ld", timeout));
my_sleep(1000000L);
}
@@ -10069,7 +10071,7 @@ int find_set(REP_SETS *sets,REP_SET *find)
return i;
}
}
- return i; /* return new postion */
+ return i; /* return new position */
}
/* find if there is a found_set with same table_offset & found_offset
@@ -10089,7 +10091,7 @@ int find_found(FOUND_SET *found_set,uint table_offset, int found_offset)
found_set[i].table_offset=table_offset;
found_set[i].found_offset=found_offset;
found_sets++;
- return -i-2; /* return new postion */
+ return -i-2; /* return new position */
}
/* Return 1 if regexp starts with \b or ends with \b*/
diff --git a/cmake/abi_check.cmake b/cmake/abi_check.cmake
index 2488bcefe33..a671aeff342 100644
--- a/cmake/abi_check.cmake
+++ b/cmake/abi_check.cmake
@@ -19,8 +19,16 @@
# plugin_audit.h and plugin_ftparser.h.
#
# We use gcc specific preprocessing command and sed/diff, so it will
-# only be run on Unix and only if gcc is used.
-IF(CMAKE_COMPILER_IS_GNUCC AND CMAKE_SYSTEM_NAME MATCHES "Linux")
+# only be run on Unix and only if gcc is used. On some Unixes,
+# (Solaris) sed or diff might act differently from GNU, so we run only
+# on systems we can trust.
+IF(APPLE OR CMAKE_SYSTEM_NAME MATCHES "Linux")
+ SET(RUN_ABI_CHECK 1)
+ELSE()
+ SET(RUN_ABI_CHECK 0)
+ENDIF()
+
+IF(CMAKE_COMPILER_IS_GNUCC AND RUN_ABI_CHECK)
IF(CMAKE_C_COMPILER MATCHES "ccache$")
SET(COMPILER ${CMAKE_C_COMPILER_ARG1})
STRING(REGEX REPLACE "^ " "" COMPILER ${COMPILER})
diff --git a/cmake/maintainer.cmake b/cmake/maintainer.cmake
index 468b2f40084..d24211a6ff8 100644
--- a/cmake/maintainer.cmake
+++ b/cmake/maintainer.cmake
@@ -35,7 +35,7 @@ ENDMACRO()
# Setup G++ (GNU C++ compiler) warning options.
MACRO(SET_MYSQL_MAINTAINER_GNU_CXX_OPTIONS)
SET(MY_MAINTAINER_CXX_WARNINGS
- "${MY_MAINTAINER_WARNINGS} -Wno-unused-parameter"
+ "${MY_MAINTAINER_WARNINGS} -Wno-unused-parameter -Woverloaded-virtual"
CACHE STRING "C++ warning options used in maintainer builds.")
ENDMACRO()
diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake
index 0dbfde5294c..b51f3a2dc52 100644
--- a/cmake/os/Windows.cmake
+++ b/cmake/os/Windows.cmake
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 Sun Microsystems, Inc
+# Copyright (C) 2010, 2011, 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
@@ -192,3 +192,4 @@ IF(NOT HAVE_SIZE_OF_SSIZE_T)
ENDIF()
SET(FN_NO_CASE_SENSE 1)
+SET(USE_SYMDIR 1)
diff --git a/cmake/os/WindowsCache.cmake b/cmake/os/WindowsCache.cmake
index ff068bfeaf6..477fd1d2b88 100644
--- a/cmake/os/WindowsCache.cmake
+++ b/cmake/os/WindowsCache.cmake
@@ -76,9 +76,6 @@ SET(HAVE_FTRUNCATE CACHE INTERNAL "")
SET(HAVE_GETADDRINFO 1 CACHE INTERNAL "")
SET(HAVE_GETCWD 1 CACHE INTERNAL "")
SET(HAVE_GETHOSTBYADDR_R CACHE INTERNAL "")
-SET(HAVE_GETHOSTBYNAME_R CACHE INTERNAL "")
-SET(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE CACHE INTERNAL "")
-SET(HAVE_GETHOSTBYNAME_R_RETURN_INT CACHE INTERNAL "")
SET(HAVE_GETHRTIME CACHE INTERNAL "")
SET(HAVE_GETLINE CACHE INTERNAL "")
SET(HAVE_GETNAMEINFO CACHE INTERNAL "")
@@ -104,6 +101,10 @@ SET(HAVE_IPV6_V6ONLY 1 CACHE INTERNAL "")
SET(HAVE_ISINF CACHE INTERNAL "")
SET(HAVE_ISNAN CACHE INTERNAL "")
SET(HAVE_ISSETUGID CACHE INTERNAL "")
+SET(HAVE_GETUID CACHE INTERNAL "")
+SET(HAVE_GETEUID CACHE INTERNAL "")
+SET(HAVE_GETGID CACHE INTERNAL "")
+SET(HAVE_GETEGID CACHE INTERNAL "")
SET(HAVE_LANGINFO_H CACHE INTERNAL "")
SET(HAVE_LDIV 1 CACHE INTERNAL "")
SET(HAVE_LIMITS_H 1 CACHE INTERNAL "")
diff --git a/cmd-line-utils/libedit/el.c b/cmd-line-utils/libedit/el.c
index d99946eb68f..c7f8386773d 100644
--- a/cmd-line-utils/libedit/el.c
+++ b/cmd-line-utils/libedit/el.c
@@ -478,7 +478,13 @@ el_source(EditLine *el, const char *fname)
fp = NULL;
if (fname == NULL) {
-#ifdef HAVE_ISSETUGID
+/* XXXMYSQL: Bug#49967 */
+#if defined(HAVE_GETUID) && defined(HAVE_GETEUID) && \
+ defined(HAVE_GETGID) && defined(HAVE_GETEGID)
+#define HAVE_IDENTITY_FUNCS 1
+#endif
+
+#if (defined(HAVE_ISSETUGID) || defined(HAVE_IDENTITY_FUNCS))
static const char elpath[] = "/.editrc";
/* XXXMYSQL: Portability fix (for which platforms?) */
#ifdef MAXPATHLEN
@@ -486,9 +492,13 @@ el_source(EditLine *el, const char *fname)
#else
char path[4096];
#endif
-
+#ifdef HAVE_ISSETUGID
if (issetugid())
return (-1);
+#elif defined(HAVE_IDENTITY_FUNCS)
+ if (getuid() != geteuid() || getgid() != getegid())
+ return (-1);
+#endif
if ((ptr = getenv("HOME")) == NULL)
return (-1);
if (strlcpy(path, ptr, sizeof(path)) >= sizeof(path))
@@ -498,9 +508,10 @@ el_source(EditLine *el, const char *fname)
fname = path;
#else
/*
- * If issetugid() is missing, always return an error, in order
- * to keep from inadvertently opening up the user to a security
- * hole.
+ * If issetugid() or the above mentioned get[e][u|g]id()
+ * functions are missing, always return an error, in order
+ * to keep from inadvertently opening up the user to a
+ * security hole.
*/
return (-1);
#endif
diff --git a/cmd-line-utils/libedit/vi.c b/cmd-line-utils/libedit/vi.c
index d628f076a1d..beffc7b40b5 100644
--- a/cmd-line-utils/libedit/vi.c
+++ b/cmd-line-utils/libedit/vi.c
@@ -1012,8 +1012,10 @@ vi_histedit(EditLine *el, int c __attribute__((__unused__)))
if (fd < 0)
return CC_ERROR;
cp = el->el_line.buffer;
- write(fd, cp, el->el_line.lastchar - cp +0u);
- write(fd, "\n", 1);
+ if (write(fd, cp, el->el_line.lastchar - cp +0u) == -1)
+ goto error;
+ if (write(fd, "\n", 1) == -1)
+ goto error;
pid = fork();
switch (pid) {
case -1:
@@ -1041,6 +1043,12 @@ vi_histedit(EditLine *el, int c __attribute__((__unused__)))
unlink(tempfile);
/* return CC_REFRESH; */
return ed_newline(el, 0);
+
+/* XXXMYSQL: Avoid compiler warnings. */
+error:
+ close(fd);
+ unlink(tempfile);
+ return CC_ERROR;
}
/* vi_history_word():
diff --git a/config.h.cmake b/config.h.cmake
index 7de8f716e77..3247093c613 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -125,6 +125,7 @@
#cmakedefine FIONREAD_IN_SYS_IOCTL 1
#cmakedefine GWINSZ_IN_SYS_IOCTL 1
#cmakedefine TIOCSTAT_IN_SYS_IOCTL 1
+#cmakedefine FIONREAD_IN_SYS_FILIO 1
/* Functions we may want to use. */
#cmakedefine HAVE_AIOWAIT 1
@@ -157,7 +158,6 @@
#cmakedefine HAVE_GETADDRINFO 1
#cmakedefine HAVE_GETCWD 1
#cmakedefine HAVE_GETHOSTBYADDR_R 1
-#cmakedefine HAVE_GETHOSTBYNAME_R 1
#cmakedefine HAVE_GETHRTIME 1
#cmakedefine HAVE_GETLINE 1
#cmakedefine HAVE_GETNAMEINFO 1
@@ -174,6 +174,10 @@
#cmakedefine gmtime_r @gmtime_r@
#cmakedefine HAVE_INITGROUPS 1
#cmakedefine HAVE_ISSETUGID 1
+#cmakedefine HAVE_GETUID 1
+#cmakedefine HAVE_GETEUID 1
+#cmakedefine HAVE_GETGID 1
+#cmakedefine HAVE_GETEGID 1
#cmakedefine HAVE_ISNAN 1
#cmakedefine HAVE_ISINF 1
#cmakedefine HAVE_LARGE_PAGE_OPTION 1
@@ -448,8 +452,6 @@
#cmakedefine HAVE_SOLARIS_STYLE_GETHOST 1
-#cmakedefine HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE 1
-#cmakedefine HAVE_GETHOSTBYNAME_R_RETURN_INT 1
#cmakedefine MY_ATOMIC_MODE_DUMMY 1
#cmakedefine MY_ATOMIC_MODE_RWLOCKS 1
@@ -513,6 +515,7 @@
#cmakedefine EXTRA_DEBUG 1
#cmakedefine BACKUP_TEST 1
#cmakedefine CYBOZU 1
+#cmakedefine USE_SYMDIR 1
/* Character sets and collations */
#cmakedefine MYSQL_DEFAULT_CHARSET_NAME "@MYSQL_DEFAULT_CHARSET_NAME@"
diff --git a/configure.cmake b/configure.cmake
index 90a01ff913c..77d8b9e1faa 100644
--- a/configure.cmake
+++ b/configure.cmake
@@ -350,7 +350,6 @@ CHECK_FUNCTION_EXISTS (fseeko HAVE_FSEEKO)
CHECK_FUNCTION_EXISTS (fsync HAVE_FSYNC)
CHECK_FUNCTION_EXISTS (getcwd HAVE_GETCWD)
CHECK_FUNCTION_EXISTS (gethostbyaddr_r HAVE_GETHOSTBYADDR_R)
-CHECK_FUNCTION_EXISTS (gethostbyname_r HAVE_GETHOSTBYNAME_R)
CHECK_FUNCTION_EXISTS (gethrtime HAVE_GETHRTIME)
CHECK_FUNCTION_EXISTS (getnameinfo HAVE_GETNAMEINFO)
CHECK_FUNCTION_EXISTS (getpass HAVE_GETPASS)
@@ -363,6 +362,10 @@ CHECK_FUNCTION_EXISTS (getwd HAVE_GETWD)
CHECK_FUNCTION_EXISTS (gmtime_r HAVE_GMTIME_R)
CHECK_FUNCTION_EXISTS (initgroups HAVE_INITGROUPS)
CHECK_FUNCTION_EXISTS (issetugid HAVE_ISSETUGID)
+CHECK_FUNCTION_EXISTS (getuid HAVE_GETUID)
+CHECK_FUNCTION_EXISTS (geteuid HAVE_GETEUID)
+CHECK_FUNCTION_EXISTS (getgid HAVE_GETGID)
+CHECK_FUNCTION_EXISTS (getegid HAVE_GETEGID)
CHECK_FUNCTION_EXISTS (ldiv HAVE_LDIV)
CHECK_FUNCTION_EXISTS (localtime_r HAVE_LOCALTIME_R)
CHECK_FUNCTION_EXISTS (longjmp HAVE_LONGJMP)
@@ -488,6 +491,7 @@ CHECK_SYMBOL_EXISTS(getpagesize "unistd.h" HAVE_GETPAGESIZE)
CHECK_SYMBOL_EXISTS(TIOCGWINSZ "sys/ioctl.h" GWINSZ_IN_SYS_IOCTL)
CHECK_SYMBOL_EXISTS(FIONREAD "sys/ioctl.h" FIONREAD_IN_SYS_IOCTL)
CHECK_SYMBOL_EXISTS(TIOCSTAT "sys/ioctl.h" TIOCSTAT_IN_SYS_IOCTL)
+CHECK_SYMBOL_EXISTS(FIONREAD "sys/filio.h" FIONREAD_IN_SYS_FILIO)
CHECK_SYMBOL_EXISTS(gettimeofday "sys/time.h" HAVE_GETTIMEOFDAY)
CHECK_SYMBOL_EXISTS(finite "math.h" HAVE_FINITE_IN_MATH_H)
@@ -921,44 +925,6 @@ CHECK_CXX_SOURCE_COMPILES("
"
HAVE_SOLARIS_STYLE_GETHOST)
-CHECK_CXX_SOURCE_COMPILES("
- #undef inline
- #if !defined(SCO) && !defined(__osf__) && !defined(_REENTRANT)
- #define _REENTRANT
- #endif
- #include <pthread.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- int main()
- {
- int ret = gethostbyname_r((const char *) 0,
- (struct hostent*) 0, (char*) 0, 0, (struct hostent **) 0, (int *) 0);
- return 0;
- }"
- HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE)
-
-CHECK_CXX_SOURCE_COMPILES("
- #undef inline
- #if !defined(SCO) && !defined(__osf__) && !defined(_REENTRANT)
- #define _REENTRANT
- #endif
- #include <pthread.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- int main()
- {
- int ret = gethostbyname_r((const char *) 0, (struct hostent*) 0, (struct hostent_data*) 0);
- return 0;
- }"
- HAVE_GETHOSTBYNAME_R_RETURN_INT)
-
-
# Use of ALARMs to wakeup on timeout on sockets
#
# This feature makes use of a mutex and is a scalability hog we
diff --git a/extra/replace.c b/extra/replace.c
index 2ce374726eb..21b9acb6f0c 100644
--- a/extra/replace.c
+++ b/extra/replace.c
@@ -1,17 +1,19 @@
-/* Copyright (C) 2000 MySQL AB
+/* Copyright (c) 2000, 2011, 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 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
+ 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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ 02110-1301 USA */
/*
Replace strings in textfile
@@ -818,7 +820,7 @@ static short find_set(REP_SETS *sets,REP_SET *find)
return (short) i;
}
}
- return (short) i; /* return new postion */
+ return (short) i; /* return new position */
}
@@ -841,7 +843,7 @@ static short find_found(FOUND_SET *found_set,uint table_offset,
found_set[i].table_offset=table_offset;
found_set[i].found_offset=found_offset;
found_sets++;
- return (short) (-i-2); /* return new postion */
+ return (short) (-i-2); /* return new position */
}
/* Return 1 if regexp starts with \b or ends with \b*/
diff --git a/include/m_ctype.h b/include/m_ctype.h
index bb7f5ddfb3d..a35aea31a71 100644
--- a/include/m_ctype.h
+++ b/include/m_ctype.h
@@ -346,7 +346,7 @@ extern CHARSET_INFO my_charset_utf32_bin;
extern CHARSET_INFO my_charset_utf32_general_ci;
extern CHARSET_INFO my_charset_utf32_unicode_ci;
-extern CHARSET_INFO my_charset_utf8_general_ci;
+extern MYSQL_PLUGIN_IMPORT CHARSET_INFO my_charset_utf8_general_ci;
extern CHARSET_INFO my_charset_utf8_unicode_ci;
extern CHARSET_INFO my_charset_utf8_bin;
extern CHARSET_INFO my_charset_utf8mb4_bin;
diff --git a/include/my_global.h b/include/my_global.h
index 9ae70b3bcc7..0ff4ea5484b 100644
--- a/include/my_global.h
+++ b/include/my_global.h
@@ -301,9 +301,6 @@ C_MODE_END
#undef HAVE_PWRITE
#endif
-#ifdef UNDEF_HAVE_GETHOSTBYNAME_R /* For OSF4.x */
-#undef HAVE_GETHOSTBYNAME_R
-#endif
#ifdef UNDEF_HAVE_INITGROUPS /* For AIX 4.3 */
#undef HAVE_INITGROUPS
#endif
diff --git a/include/mysql.h b/include/mysql.h
index d3b24f0198a..1966caefdc1 100644
--- a/include/mysql.h
+++ b/include/mysql.h
@@ -573,6 +573,8 @@ typedef struct st_mysql_bind
} MYSQL_BIND;
+struct st_mysql_stmt_extension;
+
/* statement handler */
typedef struct st_mysql_stmt
{
@@ -618,7 +620,7 @@ typedef struct st_mysql_stmt
metadata fields when doing mysql_stmt_store_result.
*/
my_bool update_max_length;
- void *extension;
+ struct st_mysql_stmt_extension *extension;
} MYSQL_STMT;
enum enum_stmt_attr_type
diff --git a/include/mysql.h.pp b/include/mysql.h.pp
index 169a8b30e2b..15ec563dfc2 100644
--- a/include/mysql.h.pp
+++ b/include/mysql.h.pp
@@ -512,6 +512,7 @@ typedef struct st_mysql_bind
my_bool is_null_value;
void *extension;
} MYSQL_BIND;
+struct st_mysql_stmt_extension;
typedef struct st_mysql_stmt
{
MEM_ROOT mem_root;
@@ -541,7 +542,7 @@ typedef struct st_mysql_stmt
unsigned char bind_result_done;
my_bool unbuffered_fetch_cancelled;
my_bool update_max_length;
- void *extension;
+ struct st_mysql_stmt_extension *extension;
} MYSQL_STMT;
enum enum_stmt_attr_type
{
diff --git a/include/mysql/client_plugin.h b/include/mysql/client_plugin.h
index cc3f468040f..6b37170aeab 100644
--- a/include/mysql/client_plugin.h
+++ b/include/mysql/client_plugin.h
@@ -156,8 +156,7 @@ mysql_client_register_plugin(struct st_mysql *mysql,
@retval 0 on success, 1 in case of failure
**/
-int STDCALL mysql_plugin_options(struct st_mysql_client_plugin *plugin,
- const char *option,
- const void *value);
+int mysql_plugin_options(struct st_mysql_client_plugin *plugin,
+ const char *option, const void *value);
#endif
diff --git a/include/mysql/client_plugin.h.pp b/include/mysql/client_plugin.h.pp
index e508f821aad..93eaff7501e 100644
--- a/include/mysql/client_plugin.h.pp
+++ b/include/mysql/client_plugin.h.pp
@@ -35,6 +35,5 @@ mysql_client_find_plugin(struct st_mysql *mysql, const char *name, int type);
struct st_mysql_client_plugin *
mysql_client_register_plugin(struct st_mysql *mysql,
struct st_mysql_client_plugin *plugin);
-int STDCALL mysql_plugin_options(struct st_mysql_client_plugin *plugin,
- const char *option,
- const void *value);
+int mysql_plugin_options(struct st_mysql_client_plugin *plugin,
+ const char *option, const void *value);
diff --git a/libmysql/CMakeLists.txt b/libmysql/CMakeLists.txt
index d7426c465d8..d0e383c6640 100644
--- a/libmysql/CMakeLists.txt
+++ b/libmysql/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2011, 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
@@ -134,6 +134,12 @@ CACHE INTERNAL "Functions exported by client API"
)
+IF(WIN32)
+ ADD_SUBDIRECTORY(authentication_win)
+ SET(WITH_AUTHENTICATION_WIN 1)
+ ADD_DEFINITIONS(-DAUTHENTICATION_WIN)
+ENDIF(WIN32)
+
SET(CLIENT_SOURCES
get_password.c
libmysql.c
@@ -151,6 +157,10 @@ ADD_DEPENDENCIES(clientlib GenError)
SET(LIBS clientlib dbug strings vio mysys ${ZLIB_LIBRARY} ${SSL_LIBRARIES} ${LIBDL})
+IF(WITH_AUTHENTICATION_WIN)
+ LIST(APPEND LIBS auth_win_client)
+ENDIF(WITH_AUTHENTICATION_WIN)
+
# Merge several convenience libraries into one big mysqlclient
# and link them together into shared library.
MERGE_LIBRARIES(mysqlclient STATIC ${LIBS} COMPONENT Development)
diff --git a/libmysql/authentication_win/CMakeLists.txt b/libmysql/authentication_win/CMakeLists.txt
new file mode 100644
index 00000000000..80cd14780e6
--- /dev/null
+++ b/libmysql/authentication_win/CMakeLists.txt
@@ -0,0 +1,33 @@
+# Copyright (c) 2011, 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
+
+#
+# Configuration for building Windows Authentication Plugin (client-side)
+#
+
+ADD_DEFINITIONS(-DSECURITY_WIN32)
+ADD_DEFINITIONS(-DDEBUG_ERRROR_LOG) # no error logging in production builds
+ADD_DEFINITIONS(-DWINAUTH_USE_DBUG_LIB) # it is OK to use dbug library in statically
+ # linked plugin
+
+SET(HEADERS common.h handshake.h)
+SET(PLUGIN_SOURCES plugin_client.cc handshake_client.cc log_client.cc common.cc handshake.cc)
+
+ADD_CONVENIENCE_LIBRARY(auth_win_client ${PLUGIN_SOURCES} ${HEADERS})
+TARGET_LINK_LIBRARIES(auth_win_client Secur32)
+
+# In IDE, group headers in a separate folder.
+
+SOURCE_GROUP(Headers REGULAR_EXPRESSION ".*h$")
diff --git a/libmysql/authentication_win/common.cc b/libmysql/authentication_win/common.cc
new file mode 100644
index 00000000000..1d1f2938969
--- /dev/null
+++ b/libmysql/authentication_win/common.cc
@@ -0,0 +1,492 @@
+/* Copyright (c) 2011, 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 "common.h"
+#include <sddl.h> // for ConvertSidToStringSid()
+#include <secext.h> // for GetUserNameEx()
+
+
+template <> void error_log_print<error_log_level::INFO>(const char *fmt, ...);
+template <> void error_log_print<error_log_level::WARNING>(const char *fmt, ...);
+template <> void error_log_print<error_log_level::ERROR>(const char *fmt, ...);
+
+
+/** Connection class **************************************************/
+
+/**
+ Create connection out of an active MYSQL_PLUGIN_VIO object.
+
+ @param[in] vio pointer to a @c MYSQL_PLUGIN_VIO object used for
+ connection - it can not be NULL
+*/
+
+Connection::Connection(MYSQL_PLUGIN_VIO *vio): m_vio(vio), m_error(0)
+{
+ DBUG_ASSERT(vio);
+}
+
+
+/**
+ Write data to the connection.
+
+ @param[in] blob data to be written
+
+ @return 0 on success, VIO error code on failure.
+
+ @note In case of error, VIO error code is stored in the connection object
+ and can be obtained with @c error() method.
+*/
+
+int Connection::write(const Blob &blob)
+{
+ m_error= m_vio->write_packet(m_vio, blob.ptr(), blob.len());
+
+#ifndef DBUG_OFF
+ if (m_error)
+ DBUG_PRINT("error", ("vio write error %d", m_error));
+#endif
+
+ return m_error;
+}
+
+
+/**
+ Read data from connection.
+
+ @return A Blob containing read packet or null Blob in case of error.
+
+ @note In case of error, VIO error code is stored in the connection object
+ and can be obtained with @c error() method.
+*/
+
+Blob Connection::read()
+{
+ unsigned char *ptr;
+ int len= m_vio->read_packet(m_vio, &ptr);
+
+ if (len < 0)
+ {
+ m_error= true;
+ return Blob();
+ }
+
+ return Blob(ptr, len);
+}
+
+
+/** Sid class *****************************************************/
+
+
+/**
+ Create Sid object corresponding to a given account name.
+
+ @param[in] account_name name of a Windows account
+
+ The account name can be in any form accepted by @c LookupAccountName()
+ function.
+
+ @note In case of errors created object is invalid and its @c is_valid()
+ method returns @c false.
+*/
+
+Sid::Sid(const wchar_t *account_name): m_data(NULL)
+#ifndef DBUG_OFF
+, m_as_string(NULL)
+#endif
+{
+ DWORD sid_size= 0, domain_size= 0;
+ bool success;
+
+ // Determine required buffer sizes
+
+ success= LookupAccountNameW(NULL, account_name, NULL, &sid_size,
+ NULL, &domain_size, &m_type);
+
+ if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not determine SID buffer size, "
+ "LookupAccountName() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+ return;
+ }
+
+ // Query for SID (domain is ignored)
+
+ wchar_t *domain= new wchar_t[domain_size];
+ m_data= (TOKEN_USER*) new BYTE[sid_size + sizeof(TOKEN_USER)];
+ m_data->User.Sid= (BYTE*)m_data + sizeof(TOKEN_USER);
+
+ success= LookupAccountNameW(NULL, account_name,
+ m_data->User.Sid, &sid_size,
+ domain, &domain_size,
+ &m_type);
+
+ if (!success || !is_valid())
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not determine SID of '%S', "
+ "LookupAccountName() failed with error %X (%s)",
+ account_name, GetLastError(),
+ get_last_error_message(error_buf)));
+#endif
+ goto fail;
+ }
+
+ goto end;
+
+fail:
+ if (m_data)
+ delete [] m_data;
+ m_data= NULL;
+
+end:
+ if (domain)
+ delete [] domain;
+}
+
+
+/**
+ Create Sid object corresponding to a given security token.
+
+ @param[in] token security token of a Windows account
+
+ @note In case of errors created object is invalid and its @c is_valid()
+ method returns @c false.
+*/
+
+Sid::Sid(HANDLE token): m_data(NULL)
+#ifndef DBUG_OFF
+, m_as_string(NULL)
+#endif
+{
+ DWORD req_size= 0;
+ bool success;
+
+ // Determine required buffer size
+
+ success= GetTokenInformation(token, TokenUser, NULL, 0, &req_size);
+ if (!success && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not determine SID buffer size, "
+ "GetTokenInformation() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+ return;
+ }
+
+ m_data= (TOKEN_USER*) new BYTE[req_size];
+ success= GetTokenInformation(token, TokenUser, m_data, req_size, &req_size);
+
+ if (!success || !is_valid())
+ {
+ delete [] m_data;
+ m_data= NULL;
+#ifndef DBUG_OFF
+ if (!success)
+ {
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not read SID from security token, "
+ "GetTokenInformation() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+ }
+#endif
+ }
+}
+
+
+Sid::~Sid()
+{
+ if (m_data)
+ delete [] m_data;
+#ifndef DBUG_OFF
+ if (m_as_string)
+ LocalFree(m_as_string);
+#endif
+}
+
+/// Check if Sid object is valid.
+bool Sid::is_valid(void) const
+{
+ return m_data && m_data->User.Sid && IsValidSid(m_data->User.Sid);
+}
+
+
+#ifndef DBUG_OFF
+
+/**
+ Produces string representation of the SID.
+
+ @return String representation of the SID or NULL in case of errors.
+
+ @note Memory allocated for the string is automatically freed in Sid's
+ destructor.
+*/
+
+const char* Sid::as_string()
+{
+ if (!m_data)
+ return NULL;
+
+ if (!m_as_string)
+ {
+ bool success= ConvertSidToStringSid(m_data->User.Sid, &m_as_string);
+
+ if (!success)
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not get textual representation of a SID, "
+ "ConvertSidToStringSid() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+ m_as_string= NULL;
+ return NULL;
+ }
+ }
+
+ return m_as_string;
+}
+
+#endif
+
+
+bool Sid::operator ==(const Sid &other)
+{
+ if (!is_valid() || !other.is_valid())
+ return false;
+
+ return EqualSid(m_data->User.Sid, other.m_data->User.Sid);
+}
+
+
+/** Generating User Principal Name *************************/
+
+/**
+ Call Windows API functions to get UPN of the current user and store it
+ in internal buffer.
+*/
+
+UPN::UPN(): m_buf(NULL)
+{
+ wchar_t buf1[MAX_SERVICE_NAME_LENGTH];
+
+ // First we try to use GetUserNameEx.
+
+ m_len= sizeof(buf1)/sizeof(wchar_t);
+
+ if (!GetUserNameExW(NameUserPrincipal, buf1, (PULONG)&m_len))
+ {
+ if (GetLastError())
+ {
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("note", ("When determining UPN"
+ ", GetUserNameEx() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+ if (ERROR_MORE_DATA == GetLastError())
+ ERROR_LOG(INFO, ("Buffer overrun when determining UPN:"
+ " need %ul characters but have %ul",
+ m_len, sizeof(buf1)/sizeof(WCHAR)));
+ }
+
+ m_len= 0; // m_len == 0 indicates invalid UPN
+ return;
+ }
+
+ /*
+ UPN is stored in buf1 in wide-char format - convert it to utf8
+ for sending over network.
+ */
+
+ m_buf= wchar_to_utf8(buf1, &m_len);
+
+ if(!m_buf)
+ ERROR_LOG(ERROR, ("Failed to convert UPN to utf8"));
+
+ // Note: possible error would be indicated by the fact that m_buf is NULL.
+ return;
+}
+
+
+UPN::~UPN()
+{
+ if (m_buf)
+ free(m_buf);
+}
+
+
+/**
+ Convert a wide-char string to utf8 representation.
+
+ @param[in] string null-terminated wide-char string to be converted
+ @param[in,out] len length of the string to be converted or 0; on
+ return length (in bytes, excluding terminating
+ null character) of the converted string
+
+ If len is 0 then the length of the string will be computed by this function.
+
+ @return Pointer to a buffer containing utf8 representation or NULL in
+ case of error.
+
+ @note The returned buffer must be freed with @c free() call.
+*/
+
+char* wchar_to_utf8(const wchar_t *string, size_t *len)
+{
+ char *buf= NULL;
+ size_t str_len= len && *len ? *len : wcslen(string);
+
+ /*
+ A conversion from utf8 to wchar_t will never take more than 3 bytes per
+ character, so a buffer of length 3 * str_len schould be sufficient.
+ We check that assumption with an assertion later.
+ */
+
+ size_t buf_len= 3 * str_len;
+
+ buf= (char*)malloc(buf_len + 1);
+ if (!buf)
+ {
+ DBUG_PRINT("error",("Out of memory when converting string '%S' to utf8",
+ string));
+ return NULL;
+ }
+
+ int res= WideCharToMultiByte(CP_UTF8, // convert to UTF-8
+ 0, // conversion flags
+ string, // input buffer
+ str_len, // its length
+ buf, buf_len, // output buffer and its size
+ NULL, NULL); // default character (not used)
+
+ if (res)
+ {
+ buf[res]= '\0';
+ if (len)
+ *len= res;
+ return buf;
+ }
+
+ // res is 0 which indicates error
+
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not convert string '%S' to utf8"
+ ", WideCharToMultiByte() failed with error %X (%s)",
+ string, GetLastError(),
+ get_last_error_message(error_buf)));
+#endif
+
+ // Let's check our assumption about sufficient buffer size
+ DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
+
+ return NULL;
+}
+
+
+/**
+ Convert an utf8 string to a wide-char string.
+
+ @param[in] string null-terminated utf8 string to be converted
+ @param[in,out] len length of the string to be converted or 0; on
+ return length (in chars) of the converted string
+
+ If len is 0 then the length of the string will be computed by this function.
+
+ @return Pointer to a buffer containing wide-char representation or NULL in
+ case of error.
+
+ @note The returned buffer must be freed with @c free() call.
+*/
+
+wchar_t* utf8_to_wchar(const char *string, size_t *len)
+{
+ size_t buf_len;
+
+ /*
+ Note: length (in bytes) of an utf8 string is always bigger than the
+ number of characters in this string. Hence a buffer of size len will
+ be sufficient. We add 1 for the terminating null character.
+ */
+
+ buf_len= len && *len ? *len : strlen(string);
+ wchar_t *buf= (wchar_t*)malloc((buf_len+1)*sizeof(wchar_t));
+
+ if (!buf)
+ {
+ DBUG_PRINT("error",("Out of memory when converting utf8 string '%s'"
+ " to wide-char representation", string));
+ return NULL;
+ }
+
+ size_t res;
+ res= MultiByteToWideChar(CP_UTF8, // convert from UTF-8
+ 0, // conversion flags
+ string, // input buffer
+ buf_len, // its size
+ buf, buf_len); // output buffer and its size
+ if (res)
+ {
+ buf[res]= '\0';
+ if (len)
+ *len= res;
+ return buf;
+ }
+
+ // error in MultiByteToWideChar()
+
+#ifndef DBUG_OFF
+ Error_message_buf error_buf;
+ DBUG_PRINT("error", ("Could not convert UPN from UTF-8"
+ ", MultiByteToWideChar() failed with error %X (%s)",
+ GetLastError(), get_last_error_message(error_buf)));
+#endif
+
+ // Let's check our assumption about sufficient buffer size
+ DBUG_ASSERT(ERROR_INSUFFICIENT_BUFFER != GetLastError());
+
+ return NULL;
+}
+
+
+/** Error handling ****************************************************/
+
+
+/**
+ Returns error message corresponding to the last Windows error given
+ by GetLastError().
+
+ @note Error message is overwritten by next call to
+ @c get_last_error_message().
+*/
+
+const char* get_last_error_message(Error_message_buf buf)
+{
+ int error= GetLastError();
+
+ buf[0]= '\0';
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR)buf, sizeof(buf), NULL );
+
+ return buf;
+}
diff --git a/libmysql/authentication_win/common.h b/libmysql/authentication_win/common.h
new file mode 100644
index 00000000000..ff0f7153664
--- /dev/null
+++ b/libmysql/authentication_win/common.h
@@ -0,0 +1,324 @@
+/* Copyright (c) 2011, 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 */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <my_global.h>
+#include <windows.h>
+#include <sspi.h> // for CtxtHandle
+#include <mysql/plugin_auth.h> // for MYSQL_PLUGIN_VIO
+
+/// Maximum length of the target service name.
+#define MAX_SERVICE_NAME_LENGTH 1024
+
+
+/** Debugging and error reporting infrastructure ***************************/
+
+/*
+ Note: We use plugin local logging and error reporting mechanisms until
+ WL#2940 (plugin service: error reporting) is available.
+*/
+
+#undef INFO
+#undef WARNING
+#undef ERROR
+
+struct error_log_level
+{
+ typedef enum {INFO, WARNING, ERROR} type;
+};
+
+
+/*
+ If DEBUG_ERROR_LOG is defined then error logging happens only
+ in debug-copiled code. Otherwise ERROR_LOG() expands to
+ error_log_print() even in production code. Note that in client
+ plugin, error_log_print() will print nothing if opt_auth_win_clinet_log
+ is 0.
+
+ Note: Macro ERROR_LOG() can use printf-like format string like this:
+
+ ERROR_LOG(Level, ("format string", args));
+
+ The implementation should handle it correctly. Currently it is passed
+ to fprintf() (see error_log_vprint() function).
+*/
+
+extern "C" int opt_auth_win_client_log;
+
+#if defined(DEBUG_ERROR_LOG) && defined(DBUG_OFF)
+#define ERROR_LOG(Level, Msg) do {} while (0)
+#else
+#define ERROR_LOG(Level, Msg) error_log_print< error_log_level::Level > Msg
+#endif
+
+
+void error_log_vprint(error_log_level::type level,
+ const char *fmt, va_list args);
+
+template <error_log_level::type Level>
+void error_log_print(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ error_log_vprint(Level, fmt, args);
+ va_end(args);
+}
+
+typedef char Error_message_buf[1024];
+const char* get_last_error_message(Error_message_buf);
+
+
+/*
+ Internal implementation of debug message printing which does not use
+ dbug library. This is invoked via macro:
+
+ DBUG_PRINT_DO(Keyword, ("format string", args));
+
+ This is supposed to be used as an implementation of DBUG_PRINT() macro,
+ unless the dbug library implementation is used or debug messages are disabled.
+*/
+
+#ifndef DBUG_OFF
+
+#define DBUG_PRINT_DO(Keyword, Msg) \
+ do { \
+ if (2 > opt_auth_win_client_log) break; \
+ fprintf(stderr, "winauth: %s: ", Keyword); \
+ debug_msg Msg; \
+ } while (0)
+
+inline
+void debug_msg(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ fputc('\n', stderr);
+ fflush(stderr);
+ va_end(args);
+}
+
+#else
+#define DBUG_PRINT_DO(K, M) do {} while (0)
+#endif
+
+
+#ifndef WINAUTH_USE_DBUG_LIB
+
+#undef DBUG_PRINT
+#define DBUG_PRINT(Keyword, Msg) DBUG_PRINT_DO(Keyword, Msg)
+
+/*
+ Redefine few more debug macros to make sure that no symbols from
+ dbug library are used.
+*/
+
+#undef DBUG_ENTER
+#define DBUG_ENTER(X) do {} while (0)
+
+#undef DBUG_RETURN
+#define DBUG_RETURN(X) return (X)
+
+#undef DBUG_ASSERT
+#ifndef DBUG_OFF
+#define DBUG_ASSERT(X) assert (X)
+#else
+#define DBUG_ASSERT(X) do {} while (0)
+#endif
+
+#undef DBUG_DUMP
+#define DBUG_DUMP(A,B,C) do {} while (0)
+
+#endif
+
+
+/** Blob class *************************************************************/
+
+typedef unsigned char byte;
+
+/**
+ Class representing a region of memory (e.g., a string or binary buffer).
+
+ @note This class does not allocate memory. It merely describes a region
+ of memory which must be allocated externally (if it is dynamic memory).
+*/
+
+class Blob
+{
+ byte *m_ptr; ///< Pointer to the first byte of the memory region.
+ size_t m_len; ///< Length of the memory region.
+
+public:
+
+ Blob(): m_ptr(NULL), m_len(0)
+ {}
+
+ Blob(const byte *ptr, const size_t len)
+ : m_ptr(const_cast<byte*>(ptr)), m_len(len)
+ {}
+
+ Blob(const char *str): m_ptr((byte*)str)
+ {
+ m_len= strlen(str);
+ }
+
+ byte* ptr() const
+ {
+ return m_ptr;
+ }
+
+ size_t len() const
+ {
+ return m_len;
+ }
+
+ byte& operator[](unsigned pos) const
+ {
+ static byte out_of_range= 0; // alas, no exceptions...
+ return pos < len() ? m_ptr[pos] : out_of_range;
+ }
+
+ bool is_null() const
+ {
+ return m_ptr == NULL;
+ }
+
+ void trim(size_t l)
+ {
+ m_len= l;
+ }
+};
+
+
+/** Connection class *******************************************************/
+
+/**
+ Convenience wrapper around MYSQL_PLUGIN_VIO object providing basic
+ read/write operations.
+*/
+
+class Connection
+{
+ MYSQL_PLUGIN_VIO *m_vio; ///< Pointer to @c MYSQL_PLUGIN_VIO structure.
+
+ /**
+ If non-zero, indicates that connection is broken. If this has happened
+ because of failed operation, stores non-zero error code from that failure.
+ */
+ int m_error;
+
+public:
+
+ Connection(MYSQL_PLUGIN_VIO *vio);
+ int write(const Blob&);
+ Blob read();
+
+ int error() const
+ {
+ return m_error;
+ }
+};
+
+
+/** Sid class **************************************************************/
+
+/**
+ Class for storing and manipulating Windows security identifiers (SIDs).
+*/
+
+class Sid
+{
+ TOKEN_USER *m_data; ///< Pointer to structure holding identifier's data.
+ SID_NAME_USE m_type; ///< Type of identified entity.
+
+public:
+
+ Sid(const wchar_t*);
+ Sid(HANDLE sec_token);
+ ~Sid();
+
+ bool is_valid(void) const;
+
+ bool is_group(void) const
+ {
+ return m_type == SidTypeGroup
+ || m_type == SidTypeWellKnownGroup
+ || m_type == SidTypeAlias;
+ }
+
+ bool is_user(void) const
+ {
+ return m_type == SidTypeUser;
+ }
+
+ bool operator==(const Sid&);
+
+ operator PSID() const
+ {
+ return (PSID)m_data->User.Sid;
+ }
+
+#ifndef DBUG_OFF
+
+private:
+ char *m_as_string; ///< Cached string representation of the SID.
+public:
+ const char* as_string();
+
+#endif
+};
+
+
+/** UPN class **************************************************************/
+
+/**
+ An object of this class obtains and stores User Principal Name of the
+ account under which current process is running.
+*/
+
+class UPN
+{
+ char *m_buf; ///< Pointer to UPN in utf8 representation.
+ size_t m_len; ///< Length of the name.
+
+public:
+
+ UPN();
+ ~UPN();
+
+ bool is_valid() const
+ {
+ return m_len > 0;
+ }
+
+ const Blob as_blob() const
+ {
+ return m_len ? Blob((byte*)m_buf, m_len) : Blob();
+ }
+
+ const char* as_string() const
+ {
+ return (const char*)m_buf;
+ }
+
+};
+
+
+char* wchar_to_utf8(const wchar_t*, size_t*);
+wchar_t* utf8_to_wchar(const char*, size_t*);
+
+#endif
diff --git a/libmysql/authentication_win/handshake.cc b/libmysql/authentication_win/handshake.cc
new file mode 100644
index 00000000000..ec665af9ef9
--- /dev/null
+++ b/libmysql/authentication_win/handshake.cc
@@ -0,0 +1,289 @@
+/* Copyright (c) 2011, 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 "handshake.h"
+
+
+/** Handshake class implementation **********************************/
+
+/**
+ Create common part of handshake context.
+
+ @param[in] ssp name of the SSP (Security Service Provider) to
+ be used for authentication
+ @param[in] side is this handshake object used for server- or
+ client-side handshake
+
+ Prepare for handshake using the @c ssp security module. We use
+ "Negotiate" which picks best available module. Parameter @c side
+ tells if this is preparing for server or client side authentication
+ and is used to prepare appropriate credentials.
+*/
+
+Handshake::Handshake(const char *ssp, side_t side)
+: m_atts(0L), m_error(0), m_complete(FALSE),
+ m_have_credentials(false), m_have_sec_context(false)
+#ifndef DBUG_OFF
+ , m_ssp_info(NULL)
+#endif
+{
+ SECURITY_STATUS ret;
+
+ // Obtain credentials for the authentication handshake.
+
+ ret= AcquireCredentialsHandle(NULL, (SEC_CHAR*)ssp,
+ side == SERVER ? SECPKG_CRED_INBOUND : SECPKG_CRED_OUTBOUND,
+ NULL, NULL, NULL, NULL, &m_cred, &m_expire);
+
+ if (ret != SEC_E_OK)
+ {
+ DBUG_PRINT("error", ("AcqireCredentialsHandle() failed"
+ " with error %X", ret));
+ ERROR_LOG(ERROR, ("Could not obtain local credentials"
+ " required for authentication"));
+ m_error= ret;
+ }
+
+ m_have_credentials= true;
+}
+
+
+Handshake::~Handshake()
+{
+ if (m_have_credentials)
+ FreeCredentialsHandle(&m_cred);
+ if (m_have_sec_context)
+ DeleteSecurityContext(&m_sctx);
+ m_output.free();
+
+#ifndef DBUG_OFF
+ if (m_ssp_info)
+ FreeContextBuffer(m_ssp_info);
+#endif
+}
+
+
+/**
+ Read and process data packets from the other end of a connection.
+
+ @param[IN] con a connection to read packets from
+
+ Packets are read and processed until authentication handshake is
+ complete. It is assumed that the peer will send at least one packet.
+ Packets are processed with @c process_data() method. If new data is
+ generated during packet processing, this data is sent to the peer and
+ another round of packet exchange starts.
+
+ @return 0 on success.
+
+ @note In case of error, appropriate error message is logged.
+*/
+int Handshake::packet_processing_loop()
+{
+ m_round= 0;
+
+ do {
+ ++m_round;
+ // Read packet send by the peer
+
+ DBUG_PRINT("info", ("Waiting for packet"));
+ Blob packet= read_packet();
+ if (error())
+ {
+ ERROR_LOG(ERROR, ("Error reading packet in round %d", m_round));
+ return 1;
+ }
+ DBUG_PRINT("info", ("Got packet of length %d", packet.len()));
+
+ /*
+ Process received data, possibly generating new data to be sent.
+ */
+
+ Blob new_data= process_data(packet);
+
+ if (error())
+ {
+ ERROR_LOG(ERROR, ("Error processing packet in round %d", m_round));
+ return 1;
+ }
+
+ /*
+ If new data has been generated, send it to the peer. Otherwise
+ handshake must be completed.
+ */
+
+ if (!new_data.is_null())
+ {
+ DBUG_PRINT("info", ("Round %d started", m_round));
+
+ DBUG_PRINT("info", ("Sending packet of length %d", new_data.len()));
+ int ret= write_packet(new_data);
+ if (ret)
+ {
+ ERROR_LOG(ERROR, ("Error writing packet in round %d", m_round));
+ return 1;
+ }
+ DBUG_PRINT("info", ("Data sent"));
+ }
+ else if (!is_complete())
+ {
+ ERROR_LOG(ERROR, ("No data to send in round %d"
+ " but handshake is not complete", m_round));
+ return 1;
+ }
+
+ /*
+ To protect against malicious clients, break handshake exchange if
+ too many rounds.
+ */
+
+ if (m_round > MAX_HANDSHAKE_ROUNDS)
+ {
+ ERROR_LOG(ERROR, ("Authentication handshake could not be completed"
+ " after %d rounds", m_round));
+ return 1;
+ }
+
+ } while(!is_complete());
+
+ ERROR_LOG(INFO, ("Handshake completed after %d rounds", m_round));
+ return 0;
+}
+
+
+#ifndef DBUG_OFF
+
+/**
+ Get name of the security package which was used in authentication.
+
+ This method should be called only after handshake was completed. It is
+ available only in debug builds.
+
+ @return Name of security package or NULL if it can not be obtained.
+*/
+
+const char* Handshake::ssp_name()
+{
+ if (!m_ssp_info && m_complete)
+ {
+ SecPkgContext_PackageInfo pinfo;
+
+ int ret= QueryContextAttributes(&m_sctx, SECPKG_ATTR_PACKAGE_INFO, &pinfo);
+
+ if (SEC_E_OK == ret)
+ {
+ m_ssp_info= pinfo.PackageInfo;
+ }
+ else
+ DBUG_PRINT("error",
+ ("Could not obtain SSP info from authentication context"
+ ", QueryContextAttributes() failed with error %X", ret));
+ }
+
+ return m_ssp_info ? m_ssp_info->Name : NULL;
+}
+
+#endif
+
+
+/**
+ Process result of @c {Initialize,Accept}SecurityContext() function.
+
+ @param[in] ret return code from @c {Initialize,Accept}SecurityContext()
+ function
+
+ This function analyses return value of Windows
+ @c {Initialize,Accept}SecurityContext() function. A call to
+ @c CompleteAuthToken() is done if requested. If authentication is complete,
+ this fact is marked in the internal state of the Handshake object.
+ If errors are detected the object is moved to error state.
+
+ @return True if error has been detected.
+*/
+
+bool Handshake::process_result(int ret)
+{
+ /*
+ First check for errors and set the m_complete flag if the result
+ indicates that handshake is complete.
+ */
+
+ switch (ret)
+ {
+ case SEC_E_OK:
+ case SEC_I_COMPLETE_NEEDED:
+ // Handshake completed
+ m_complete= true;
+ break;
+
+ case SEC_I_CONTINUE_NEEDED:
+ case SEC_I_COMPLETE_AND_CONTINUE:
+ break;
+
+ default:
+ m_error= ret;
+ return true;
+ }
+
+ m_have_sec_context= true;
+
+ /*
+ If the result indicates a need for this, complete the authentication
+ token.
+ */
+
+ switch (ret)
+ {
+ case SEC_I_COMPLETE_NEEDED:
+ case SEC_I_COMPLETE_AND_CONTINUE:
+ ret= CompleteAuthToken(&m_sctx, &m_output);
+ if (ret != 0)
+ {
+ DBUG_PRINT("error", ("CompleteAuthToken() failed with error %X", ret));
+ m_error= ret;
+ return true;
+ }
+ default:
+ break;
+ }
+
+ return false;
+}
+
+
+/** Security_buffer class implementation **********************************/
+
+
+Security_buffer::Security_buffer(const Blob &blob): m_allocated(false)
+{
+ init(blob.ptr(), blob.len());
+}
+
+
+Security_buffer::Security_buffer(): m_allocated(true)
+{
+ init(NULL, 0);
+}
+
+
+void Security_buffer::free(void)
+{
+ if (!m_allocated)
+ return;
+ if (!ptr())
+ return;
+ FreeContextBuffer(ptr());
+ m_allocated= false;
+}
diff --git a/libmysql/authentication_win/handshake.h b/libmysql/authentication_win/handshake.h
new file mode 100644
index 00000000000..5292948b583
--- /dev/null
+++ b/libmysql/authentication_win/handshake.h
@@ -0,0 +1,181 @@
+/* Copyright (c) 2011, 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 */
+
+#ifndef HANDSHAKE_H
+#define HANDSHAKE_H
+
+#include "common.h"
+
+/**
+ Name of the SSP (Security Support Provider) to be used for authentication.
+
+ We use "Negotiate" which will find the most secure SSP which can be used
+ and redirect to that SSP.
+*/
+#define SSP_NAME "Negotiate"
+
+/**
+ Maximal number of rounds in authentication handshake.
+
+ Server will interrupt authentication handshake with error if client's
+ identity can not be determined within this many rounds.
+*/
+#define MAX_HANDSHAKE_ROUNDS 50
+
+
+/// Convenience wrapper around @c SecBufferDesc.
+
+class Security_buffer: public SecBufferDesc
+{
+ SecBuffer m_buf; ///< A @c SecBuffer instance.
+
+ void init(byte *ptr, size_t len)
+ {
+ ulVersion= 0;
+ cBuffers= 1;
+ pBuffers= &m_buf;
+
+ m_buf.BufferType= SECBUFFER_TOKEN;
+ m_buf.pvBuffer= ptr;
+ m_buf.cbBuffer= len;
+ }
+
+ /// If @c false, no deallocation will be done in the destructor.
+ bool m_allocated;
+
+ public:
+
+ Security_buffer(const Blob&);
+ Security_buffer();
+
+ ~Security_buffer()
+ {
+ free();
+ }
+
+ byte* ptr() const
+ {
+ return (byte*)m_buf.pvBuffer;
+ }
+
+ size_t len() const
+ {
+ return m_buf.cbBuffer;
+ }
+
+ bool is_valid() const
+ {
+ return ptr() != NULL;
+ }
+
+ const Blob as_blob() const
+ {
+ return Blob(ptr(), len());
+ }
+
+ void free(void);
+};
+
+
+/// Common base for Handshake_{server,client}.
+
+class Handshake
+{
+public:
+
+ typedef enum {CLIENT, SERVER} side_t;
+
+ Handshake(const char *ssp, side_t side);
+ virtual ~Handshake();
+
+ int Handshake::packet_processing_loop();
+
+ bool virtual is_complete() const
+ {
+ return m_complete;
+ }
+
+ int error() const
+ {
+ return m_error;
+ }
+
+protected:
+
+ /// Security context object created during the handshake.
+ CtxtHandle m_sctx;
+
+ /// Credentials of the principal performing this handshake.
+ CredHandle m_cred;
+
+ /// Stores expiry date of the created security context.
+ TimeStamp m_expire;
+
+ /// Stores attributes of the created security context.
+ ULONG m_atts;
+
+ /**
+ Round of the handshake (starting from round 1). One round
+ consist of reading packet from the other side, processing it and
+ optionally sending a reply (see @c packet_processing_loop()).
+ */
+ unsigned int m_round;
+
+ /// If non-zero, stores error code of the last failed operation.
+ int m_error;
+
+ /// @c true when handshake is complete.
+ bool m_complete;
+
+ /// @c true when the principal credentials has been determined.
+ bool m_have_credentials;
+
+ /// @c true when the security context has been created.
+ bool m_have_sec_context;
+
+ /// Buffer for data to be send to the other side.
+ Security_buffer m_output;
+
+ bool process_result(int);
+
+ /**
+ This method is used inside @c packet_processing_loop to process
+ data packets received from the other end.
+
+ @param[IN] data data to be processed
+
+ @return A blob with data to be sent to the other end or null blob if
+ no more data needs to be exchanged.
+ */
+ virtual Blob process_data(const Blob &data) =0;
+
+ /// Read packet from the other end.
+ virtual Blob read_packet() =0;
+
+ /// Write packet to the other end.
+ virtual int write_packet(Blob &data) =0;
+
+#ifndef DBUG_OFF
+
+private:
+ SecPkgInfo *m_ssp_info;
+public:
+ const char* ssp_name();
+
+#endif
+};
+
+
+#endif
diff --git a/libmysql/authentication_win/handshake_client.cc b/libmysql/authentication_win/handshake_client.cc
new file mode 100644
index 00000000000..7e89fc92ae7
--- /dev/null
+++ b/libmysql/authentication_win/handshake_client.cc
@@ -0,0 +1,378 @@
+/* Copyright (c) 2011, 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 "handshake.h"
+
+#include <mysql.h> // for MYSQL structure
+
+
+/// Client-side context for authentication handshake
+
+class Handshake_client: public Handshake
+{
+ /**
+ Name of the server's service for which we authenticate.
+
+ The service name is sent by server in the initial packet. If no
+ service name is used, this member is @c NULL.
+ */
+ SEC_WCHAR *m_service_name;
+
+ /// Buffer for storing service name obtained from server.
+ SEC_WCHAR m_service_name_buf[MAX_SERVICE_NAME_LENGTH];
+
+ Connection &m_con;
+
+public:
+
+ Handshake_client(Connection &con, const char *target, size_t len);
+ ~Handshake_client();
+
+ Blob first_packet();
+ Blob process_data(const Blob&);
+
+ Blob read_packet();
+ int write_packet(Blob &data);
+};
+
+
+/**
+ Create authentication handshake context for client.
+
+ @param con connection for communication with the peer
+ @param target name of the target service with which we will authenticate
+ (can be NULL if not used)
+
+ Some security packages (like Kerberos) require providing explicit name
+ of the service with which a client wants to authenticate. The server-side
+ authentication plugin sends this name in the greeting packet
+ (see @c win_auth_handshake_{server,client}() functions).
+*/
+
+Handshake_client::Handshake_client(Connection &con,
+ const char *target, size_t len)
+: Handshake(SSP_NAME, CLIENT), m_service_name(NULL), m_con(con)
+{
+ if (!target || 0 == len)
+ return;
+
+ // Convert received UPN to internal WCHAR representation.
+
+ m_service_name= utf8_to_wchar(target, &len);
+
+ if (m_service_name)
+ DBUG_PRINT("info", ("Using target service: %S\n", m_service_name));
+ else
+ {
+ /*
+ Note: we ignore errors here - m_target will be NULL, the target name
+ will not be used and system will fall-back to NTLM authentication. But
+ we leave trace in error log.
+ */
+ ERROR_LOG(WARNING, ("Could not decode UPN sent by the server"
+ "; target service name will not be used"
+ " and Kerberos authentication will not work"));
+ }
+}
+
+
+Handshake_client::~Handshake_client()
+{
+ if (m_service_name)
+ free(m_service_name);
+}
+
+
+Blob Handshake_client::read_packet()
+{
+ /*
+ We do a fake read in the first round because first
+ packet from the server containing UPN must be read
+ before the handshake context is created and the packet
+ processing loop starts. We return an empty blob here
+ and process_data() function will ignore it.
+ */
+ if (m_round == 1)
+ return Blob();
+
+ // Otherwise we read packet from the connection.
+
+ Blob packet= m_con.read();
+ m_error= m_con.error();
+ if (!m_error && packet.is_null())
+ m_error= true; // (no specific error code assigned)
+
+ if (m_error)
+ return Blob();
+
+ DBUG_PRINT("dump", ("Got the following bytes"));
+ DBUG_DUMP("dump", packet.ptr(), packet.len());
+ return packet;
+}
+
+
+
+int Handshake_client::write_packet(Blob &data)
+{
+ /*
+ Length of the first data payload send by client authentication plugin is
+ limited to 255 bytes (because it is wrapped inside client authentication
+ packet and is length-encoded with 1 byte for the length).
+
+ If the data payload is longer than 254 bytes, then it is sent in two parts:
+ first part of length 255 will be embedded in the authentication packet,
+ second part will be sent in the following packet. Byte 255 of the first
+ part contains information about the total length of the payload. It is a
+ number of blocks of size 512 bytes which is sufficient to store the
+ combined packets.
+
+ Server's logic for reading first client's payload is as follows
+ (see Handshake_server::read_packet()):
+ 1. Read data from the authentication packet, if it is shorter than 255 bytes
+ then that is all data sent by client.
+ 2. If there is 255 bytes of data in the authentication packet, read another
+ packet and append it to the data, skipping byte 255 of the first packet
+ which can be used to allocate buffer of appropriate size.
+ */
+
+ size_t len2= 0; // length of the second part of first data payload
+ byte saved_byte; // for saving byte 255 in which data length is stored
+
+ if (m_round == 1 && data.len() > 254)
+ {
+ len2= data.len() - 254;
+ DBUG_PRINT("info", ("Splitting first packet of length %lu"
+ ", %lu bytes will be sent in a second part",
+ data.len(), len2));
+ /*
+ Store in byte 255 the number of 512b blocks that are needed to
+ keep all the data.
+ */
+ unsigned block_count= data.len()/512 + ((data.len() % 512) ? 1 : 0);
+ DBUG_ASSERT(block_count < (unsigned)0x100);
+ saved_byte= data[254];
+ data[254] = block_count;
+
+ data.trim(255);
+ }
+
+ DBUG_PRINT("dump", ("Sending the following data"));
+ DBUG_DUMP("dump", data.ptr(), data.len());
+ int ret= m_con.write(data);
+
+ if (ret)
+ return ret;
+
+ // Write second part if it is present.
+ if (len2)
+ {
+ data[254]= saved_byte;
+ Blob data2(data.ptr() + 254, len2);
+ DBUG_PRINT("info", ("Sending second part of data"));
+ DBUG_DUMP("info", data2.ptr(), data2.len());
+ ret= m_con.write(data2);
+ }
+
+ return ret;
+}
+
+
+/**
+ Process data sent by server.
+
+ @param[in] data blob with data from server
+
+ This method analyses data sent by server during authentication handshake.
+ If client should continue packet exchange, this method returns data to
+ be sent to the server next. If no more data needs to be exchanged, an
+ empty blob is returned and @c is_complete() is @c true. In case of error
+ an empty blob is returned and @c error() gives non-zero error code.
+
+ When invoked for the first time (in the first round of the handshake)
+ there is no data from the server (data blob is null) and the intial
+ packet is generated without an input.
+
+ @return Data to be sent to the server next or null blob if no more data
+ needs to be exchanged or in case of error.
+*/
+
+Blob Handshake_client::process_data(const Blob &data)
+{
+#if !defined(DBUG_OFF) && defined(WINAUTH_USE_DBUG_LIB)
+ /*
+ Code for testing the logic for sending the first client payload.
+
+ A fake data of length given by environment variable TEST_PACKET_LENGTH
+ (or default 255 bytes) is sent to the server. First 2 bytes of the
+ payload contain its total length (LSB first). The length of test data
+ is limited to 2048 bytes.
+
+ Upon receiving test data, server will check that data is correct and
+ refuse connection. If server detects data errors it will crash on
+ assertion.
+
+ This code is executed if debug flag "winauth_first_packet_test" is
+ set, e.g. using client option:
+
+ --debug="d,winauth_first_packet_test"
+
+ The same debug flag must be enabled in the server, e.g. using
+ statement:
+
+ SET GLOBAL debug= '+d,winauth_first_packet_test';
+ */
+
+ static byte test_buf[2048];
+
+ if (m_round == 1
+ && DBUG_EVALUATE_IF("winauth_first_packet_test", true, false))
+ {
+ const char *env= getenv("TEST_PACKET_LENGTH");
+ size_t len= env ? atoi(env) : 0;
+ if (!len)
+ len= 255;
+ if (len > sizeof(test_buf))
+ len= sizeof(test_buf);
+
+ // Store data length in first 2 bytes.
+ byte *ptr= test_buf;
+ *ptr++= len & 0xFF;
+ *ptr++= len >> 8;
+
+ // Fill remaining bytes with known values.
+ for (byte b= 0; ptr < test_buf + len; ++ptr, ++b)
+ *ptr= b;
+
+ return Blob(test_buf, len);
+ };
+
+#endif
+
+ Security_buffer input(data);
+ SECURITY_STATUS ret;
+
+ m_output.free();
+
+ ret= InitializeSecurityContextW(
+ &m_cred,
+ m_round == 1 ? NULL : &m_sctx, // partial context
+ m_service_name, // service name
+ ASC_REQ_ALLOCATE_MEMORY, // requested attributes
+ 0, // reserved
+ SECURITY_NETWORK_DREP, // data representation
+ m_round == 1 ? NULL : &input, // input data
+ 0, // reserved
+ &m_sctx, // context
+ &m_output, // output data
+ &m_atts, // attributes
+ &m_expire); // expire date
+
+ if (process_result(ret))
+ {
+ DBUG_PRINT("error",
+ ("InitializeSecurityContext() failed with error %X", ret));
+ return Blob();
+ }
+
+ return m_output.as_blob();
+}
+
+
+/**********************************************************************/
+
+
+/**
+ Perform authentication handshake from client side.
+
+ @param[in] vio pointer to @c MYSQL_PLUGIN_VIO instance to be used
+ for communication with the server
+ @param[in] mysql pointer to a MySQL connection for which we authenticate
+
+ After reading the initial packet from server, containing its UPN to be
+ used as service name, client starts packet exchange by sending the first
+ packet in this exchange. While handshake is not yet completed, client
+ reads packets sent by the server and process them, possibly generating new
+ data to be sent to the server.
+
+ This function reports errors.
+
+ @return 0 on success.
+*/
+
+int win_auth_handshake_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
+{
+ DBUG_ENTER("win_auth_handshake_client");
+
+ /*
+ Check if we should enable logging.
+ */
+ {
+ const char *opt= getenv("AUTHENTICATION_WIN_LOG");
+ int opt_val= opt ? atoi(opt) : 0;
+ if (opt && !opt_val)
+ {
+ if (!strncasecmp("on", opt, 2)) opt_val= 1;
+ if (!strncasecmp("yes", opt, 3)) opt_val= 1;
+ if (!strncasecmp("true", opt, 4)) opt_val= 1;
+ if (!strncasecmp("debug", opt, 5)) opt_val= 2;
+ if (!strncasecmp("dbug", opt, 4)) opt_val= 2;
+ }
+ opt_auth_win_client_log= opt_val;
+ }
+
+ ERROR_LOG(INFO, ("Authentication handshake for account %s", mysql->user));
+
+ // Create connection object.
+
+ Connection con(vio);
+ DBUG_ASSERT(!con.error());
+
+ // Read initial packet from server containing service name.
+
+ Blob service_name= con.read();
+
+ if (con.error() || service_name.is_null())
+ {
+ ERROR_LOG(ERROR, ("Error reading initial packet"));
+ DBUG_RETURN(CR_ERROR);
+ }
+ DBUG_PRINT("info", ("Got initial packet of length %d", service_name.len()));
+
+ // Create authentication handshake context using the given service name.
+
+ Handshake_client hndshk(con,
+ service_name[0] ? (char *)service_name.ptr() : NULL,
+ service_name.len());
+ if (hndshk.error())
+ {
+ ERROR_LOG(ERROR, ("Could not create authentication handshake context"));
+ DBUG_RETURN(CR_ERROR);
+ }
+
+ DBUG_ASSERT(!hndshk.error());
+
+ /*
+ Read and process packets from server until handshake is complete.
+ Note that the first read from server is dummy
+ (see Handshake_client::read_packet()) as we already have read the
+ first packet to establish service name.
+ */
+ if (hndshk.packet_processing_loop())
+ DBUG_RETURN(CR_ERROR);
+
+ DBUG_ASSERT(!hndshk.error() && hndshk.is_complete());
+
+ DBUG_RETURN(CR_OK);
+}
diff --git a/libmysql/authentication_win/log_client.cc b/libmysql/authentication_win/log_client.cc
new file mode 100644
index 00000000000..df4ce4f9c2a
--- /dev/null
+++ b/libmysql/authentication_win/log_client.cc
@@ -0,0 +1,55 @@
+/* Copyright (c) 2011, 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 "common.h"
+
+/**
+ This option is set in win_auth_handshake_client() function
+ in handshake_client.cc.
+
+ Values:
+ 0 - no logging
+ 1 - log error/warning/info messages
+ 2 - also log debug messages
+
+ Note: No error or debug messages are logged in production code
+ (see logging macros in common.h).
+*/
+int opt_auth_win_client_log= 0;
+
+
+// Client-side logging function
+
+void error_log_vprint(error_log_level::type level,
+ const char *fmt, va_list args)
+{
+ if (0 == opt_auth_win_client_log)
+ return;
+
+ const char *level_string= "";
+
+ switch (level)
+ {
+ case error_log_level::INFO: level_string= "Note"; break;
+ case error_log_level::WARNING: level_string= "Warning"; break;
+ case error_log_level::ERROR: level_string= "ERROR"; break;
+ }
+
+ fprintf(stderr, "Windows Authentication Plugin %s: ", level_string);
+ vfprintf(stderr, fmt, args);
+ fputc('\n', stderr);
+ fflush(stderr);
+}
diff --git a/libmysql/authentication_win/plugin_client.cc b/libmysql/authentication_win/plugin_client.cc
new file mode 100644
index 00000000000..72769ada8f6
--- /dev/null
+++ b/libmysql/authentication_win/plugin_client.cc
@@ -0,0 +1,58 @@
+/* Copyright (c) 2011, 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 <mysql.h>
+#include <mysql/plugin_auth.h>
+#include <mysql/client_plugin.h>
+
+#include "common.h"
+
+static int win_auth_client_plugin_init(char*, size_t, int, va_list)
+{
+ return 0;
+}
+
+
+static int win_auth_client_plugin_deinit()
+{
+ return 0;
+}
+
+
+int win_auth_handshake_client(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql);
+
+
+/*
+ Client plugin declaration. This is added to mysql_client_builtins[]
+ in sql-common/client.c
+*/
+
+extern "C"
+st_mysql_client_plugin_AUTHENTICATION win_auth_client_plugin=
+{
+ MYSQL_CLIENT_AUTHENTICATION_PLUGIN,
+ MYSQL_CLIENT_AUTHENTICATION_PLUGIN_INTERFACE_VERSION,
+ "authentication_windows_client",
+ "Rafal Somla",
+ "Windows Authentication Plugin - client side",
+ {0,1,0},
+ "GPL",
+ NULL,
+ win_auth_client_plugin_init,
+ win_auth_client_plugin_deinit,
+ NULL, // option handling
+ win_auth_handshake_client
+};
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index f802387cf9a..ec48720a2f5 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -94,6 +94,11 @@ sig_handler my_pipe_sig_handler(int sig);
static my_bool mysql_client_init= 0;
static my_bool org_my_init_done= 0;
+typedef struct st_mysql_stmt_extension
+{
+ MEM_ROOT fields_mem_root;
+} MYSQL_STMT_EXT;
+
/*
Initialize the MySQL client library
@@ -1480,11 +1485,16 @@ mysql_stmt_init(MYSQL *mysql)
MYSQL_STMT *stmt;
DBUG_ENTER("mysql_stmt_init");
- if (!(stmt= (MYSQL_STMT *) my_malloc(sizeof(MYSQL_STMT),
+ if (!(stmt=
+ (MYSQL_STMT *) my_malloc(sizeof (MYSQL_STMT),
+ MYF(MY_WME | MY_ZEROFILL))) ||
+ !(stmt->extension=
+ (MYSQL_STMT_EXT *) my_malloc(sizeof (MYSQL_STMT_EXT),
MYF(MY_WME | MY_ZEROFILL))))
{
set_mysql_error(mysql, CR_OUT_OF_MEMORY, unknown_sqlstate);
- DBUG_RETURN(0);
+ my_free(stmt);
+ DBUG_RETURN(NULL);
}
init_alloc_root(&stmt->mem_root, 2048, 2048);
@@ -1499,6 +1509,8 @@ mysql_stmt_init(MYSQL *mysql)
strmov(stmt->sqlstate, not_error_sqlstate);
/* The rest of statement members was bzeroed inside malloc */
+ init_alloc_root(&stmt->extension->fields_mem_root, 2048, 0);
+
DBUG_RETURN(stmt);
}
@@ -1571,6 +1583,7 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
stmt->bind_param_done= stmt->bind_result_done= FALSE;
stmt->param_count= stmt->field_count= 0;
free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC));
+ free_root(&stmt->extension->fields_mem_root, MYF(0));
int4store(buff, stmt->stmt_id);
@@ -1631,21 +1644,21 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length)
static void alloc_stmt_fields(MYSQL_STMT *stmt)
{
MYSQL_FIELD *fields, *field, *end;
- MEM_ROOT *alloc= &stmt->mem_root;
+ MEM_ROOT *fields_mem_root= &stmt->extension->fields_mem_root;
MYSQL *mysql= stmt->mysql;
- DBUG_ASSERT(mysql->field_count);
+ DBUG_ASSERT(stmt->field_count);
- stmt->field_count= mysql->field_count;
+ free_root(fields_mem_root, MYF(0));
/*
Get the field information for non-select statements
like SHOW and DESCRIBE commands
*/
- if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(alloc,
+ if (!(stmt->fields= (MYSQL_FIELD *) alloc_root(fields_mem_root,
sizeof(MYSQL_FIELD) *
stmt->field_count)) ||
- !(stmt->bind= (MYSQL_BIND *) alloc_root(alloc,
+ !(stmt->bind= (MYSQL_BIND *) alloc_root(fields_mem_root,
sizeof(MYSQL_BIND) *
stmt->field_count)))
{
@@ -1658,18 +1671,36 @@ static void alloc_stmt_fields(MYSQL_STMT *stmt)
field && fields < end; fields++, field++)
{
*field= *fields; /* To copy all numeric parts. */
- field->catalog= strmake_root(alloc, fields->catalog,
+ field->catalog= strmake_root(fields_mem_root,
+ fields->catalog,
fields->catalog_length);
- field->db= strmake_root(alloc, fields->db, fields->db_length);
- field->table= strmake_root(alloc, fields->table, fields->table_length);
- field->org_table= strmake_root(alloc, fields->org_table,
+ field->db= strmake_root(fields_mem_root,
+ fields->db,
+ fields->db_length);
+ field->table= strmake_root(fields_mem_root,
+ fields->table,
+ fields->table_length);
+ field->org_table= strmake_root(fields_mem_root,
+ fields->org_table,
fields->org_table_length);
- field->name= strmake_root(alloc, fields->name, fields->name_length);
- field->org_name= strmake_root(alloc, fields->org_name,
+ field->name= strmake_root(fields_mem_root,
+ fields->name,
+ fields->name_length);
+ field->org_name= strmake_root(fields_mem_root,
+ fields->org_name,
fields->org_name_length);
- field->def= fields->def ? strmake_root(alloc, fields->def,
- fields->def_length) : 0;
- field->def_length= field->def ? fields->def_length : 0;
+ if (fields->def)
+ {
+ field->def= strmake_root(fields_mem_root,
+ fields->def,
+ fields->def_length);
+ field->def_length= fields->def_length;
+ }
+ else
+ {
+ field->def= NULL;
+ field->def_length= 0;
+ }
field->extension= 0; /* Avoid dangling links. */
field->max_length= 0; /* max_length is set in mysql_stmt_store_result() */
}
@@ -2387,6 +2418,9 @@ static void reinit_result_set_metadata(MYSQL_STMT *stmt)
prepared statements can't send result set metadata for these queries
on prepare stage. Read it now.
*/
+
+ stmt->field_count= stmt->mysql->field_count;
+
alloc_stmt_fields(stmt);
}
else
@@ -2404,7 +2438,7 @@ static void reinit_result_set_metadata(MYSQL_STMT *stmt)
previous branch always works.
TODO: send metadata only when it's really necessary and add a warning
'Metadata changed' when it's sent twice.
- */
+ */
update_stmt_fields(stmt);
}
}
@@ -4605,6 +4639,7 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
free_root(&stmt->result.alloc, MYF(0));
free_root(&stmt->mem_root, MYF(0));
+ free_root(&stmt->extension->fields_mem_root, MYF(0));
if (mysql)
{
@@ -4639,6 +4674,7 @@ my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt)
}
}
+ my_free(stmt->extension);
my_free(stmt);
DBUG_RETURN(test(rc));
@@ -4805,16 +4841,13 @@ int STDCALL mysql_stmt_next_result(MYSQL_STMT *stmt)
stmt->state= MYSQL_STMT_EXECUTE_DONE;
stmt->bind_result_done= FALSE;
+ stmt->field_count= mysql->field_count;
if (mysql->field_count)
{
alloc_stmt_fields(stmt);
prepare_to_fetch_result(stmt);
}
- else
- {
- stmt->field_count= mysql->field_count;
- }
DBUG_RETURN(0);
}
diff --git a/libmysql/libmysql.def b/libmysql/libmysql.def
index fc15fcf0884..ce85d2a4086 100644
--- a/libmysql/libmysql.def
+++ b/libmysql/libmysql.def
@@ -104,4 +104,3 @@ EXPORTS
mysql_server_end
mysql_set_character_set
mysql_get_character_set_info
- mysql_plugin_options
diff --git a/mysql-test/collections/default.experimental b/mysql-test/collections/default.experimental
index d7d30f9c151..5ecc8ef8c64 100644
--- a/mysql-test/collections/default.experimental
+++ b/mysql-test/collections/default.experimental
@@ -2,6 +2,7 @@
# in alphabetical order. This also helps with merge conflict resolution.
binlog.binlog_multi_engine # joro : NDB tests marked as experimental as agreed with bochklin
+binlog.binlog_bug23533 # skozlov: BUG#12371924
funcs_1.charset_collation_1 # depends on compile-time decisions
@@ -14,19 +15,13 @@ main.sp @solaris # Bug#47791 2010-01-20 alik Several tes
main.type_float @freebsd # Bug#38965 2010-05-04 alik test cases gis-rtree, type_float, type_newdecimal fail in embedded server
main.wait_timeout @solaris # Bug#51244 2010-04-26 alik wait_timeout fails on OpenSolaris
+rpl.rpl_heartbeat_basic # BUG#12403008 2011-04-27 sven fails sporadically
rpl.rpl_innodb_bug28430 # Bug#46029
+rpl.rpl_show_slave_hosts # BUG#12416700 2011-05-02 sven fails sporadically
sys_vars.max_sp_recursion_depth_func @solaris # Bug#47791 2010-01-20 alik Several test cases fail on Solaris with error Thread stack overrun
sys_vars.plugin_dir_basic # Bug#52223 2010-11-24 alik Test "plugin_dir_basic" does not support RPM build (test) directory structure
-sys_vars.slow_query_log_func @solaris # Bug#54819 2010-06-26 alik sys_vars.slow_query_log_func fails sporadically on Solaris 10
sys_vars.wait_timeout_func # Bug#41255 2010-04-26 alik wait_timeout_func fails
-sys_vars.sys_vars # Bug #59148 2011-01-10 joro 'INSTALL PLUGIN rpl_semi_sync_master' fails in release build with debug binaries
-sys_vars.rpl_semi_sync_master_enabled_basic # Bug #59148 2011-01-10 joro 'INSTALL PLUGIN rpl_semi_sync_master' fails in release build with debug binaries
-sys_vars.rpl_semi_sync_master_timeout_basic # Bug #59148 2011-01-10 joro 'INSTALL PLUGIN rpl_semi_sync_master' fails in release build with debug binaries
-sys_vars.rpl_semi_sync_master_trace_level_basic # Bug #59148 2011-01-10 joro 'INSTALL PLUGIN rpl_semi_sync_master' fails in release build with debug binaries
-sys_vars.rpl_semi_sync_master_wait_no_slave_basic # Bug #59148 2011-01-10 joro 'INSTALL PLUGIN rpl_semi_sync_master' fails in release build with debug binaries
-rpl.rpl_semi_sync_event # Bug #59148 2011-02-02 svoj 'INSTALL PLUGIN rpl_semi_sync_master' fails in release build with debug binaries
-rpl.rpl_semi_sync # Bug #59148 2011-02-02 svoj 'INSTALL PLUGIN rpl_semi_sync_master' fails in release build with debug binaries
# BUG #59055 : All ndb tests should be removed from the repository
# Leaving the sys_vars tests for now. sys_vars.all_vars.test fails on removing ndb tests
diff --git a/mysql-test/extra/rpl_tests/rpl_extra_col_slave.test b/mysql-test/extra/rpl_tests/rpl_extra_col_slave.test
index 482c7e44922..119e081878c 100644
--- a/mysql-test/extra/rpl_tests/rpl_extra_col_slave.test
+++ b/mysql-test/extra/rpl_tests/rpl_extra_col_slave.test
@@ -396,7 +396,7 @@ sync_slave_with_master;
# Error reaction is up to sql_mode of the slave sql (bug#38173)
#--echo *** Create t9 on slave ***
# Please, check BUG#47741 to see why you are not testing NDB.
-if ($engine_type != NDB)
+if (`SELECT UPPER(LEFT($engine_type, 3)) != 'NDB'`)
{
STOP SLAVE;
RESET SLAVE;
@@ -440,12 +440,13 @@ if ($engine_type != NDB)
#--let $slave_skip_counter= 2
#--let $show_slave_sql_error= 1
#--source include/wait_for_slave_sql_error_and_skip.inc
-}
-#--echo *** Drop t9 ***
-connection master;
-DROP TABLE t9;
-sync_slave_with_master;
+ #--echo *** Drop t9 ***
+ connection master;
+ DROP TABLE t9;
+ sync_slave_with_master;
+
+}
############################################
# More columns in slave at middle of table #
diff --git a/mysql-test/lib/My/ConfigFactory.pm b/mysql-test/lib/My/ConfigFactory.pm
index 6ba23754890..cca4fa2497e 100644
--- a/mysql-test/lib/My/ConfigFactory.pm
+++ b/mysql-test/lib/My/ConfigFactory.pm
@@ -1,5 +1,5 @@
# -*- cperl -*-
-# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2008, 2011, 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 Library General Public
@@ -150,7 +150,11 @@ sub fix_tmpdir {
sub fix_log_error {
my ($self, $config, $group_name, $group)= @_;
my $dir= $self->{ARGS}->{vardir};
- return "$dir/log/$group_name.err";
+ if ( $::opt_valgrind and $::opt_debug ) {
+ return "$dir/log/$group_name.trace";
+ } else {
+ return "$dir/log/$group_name.err";
+ }
}
sub fix_log {
diff --git a/mysql-test/lib/My/Find.pm b/mysql-test/lib/My/Find.pm
index 521adecfd13..9d1d2915012 100644
--- a/mysql-test/lib/My/Find.pm
+++ b/mysql-test/lib/My/Find.pm
@@ -1,5 +1,5 @@
# -*- cperl -*-
-# Copyright (C) 2008 MySQL AB
+# Copyright (c) 2004, 2011, 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
@@ -156,8 +156,7 @@ sub my_find_paths {
# User can select to look in a special build dir
# which is a subdirectory of any of the paths
my @extra_dirs;
- my $build_dir= $::opt_config_dir || $ENV{MTR_VS_CONFIG}
- || $ENV{MTR_BUILD_DIR};
+ my $build_dir= $::opt_vs_config || $ENV{MTR_VS_CONFIG} || $ENV{MTR_BUILD_DIR};
push(@extra_dirs, $build_dir) if defined $build_dir;
if (defined $extension){
diff --git a/mysql-test/lib/My/SafeProcess/safe_process.pl b/mysql-test/lib/My/SafeProcess/safe_process.pl
index e3114a749d3..54b0073f8df 100644
--- a/mysql-test/lib/My/SafeProcess/safe_process.pl
+++ b/mysql-test/lib/My/SafeProcess/safe_process.pl
@@ -94,7 +94,7 @@ eval {
local $SIG{INT}= \&handle_signal;
local $SIG{CHLD}= sub {
message("Got signal @_");
- kill(9, -$child_pid);
+ kill('KILL', -$child_pid);
my $ret= waitpid($child_pid, 0);
if ($? & 127){
exit(65); # Killed by signal
@@ -134,7 +134,7 @@ if ( $@ ) {
# Use negative pid in order to kill the whole
# process group
#
-my $ret= kill(9, -$child_pid);
+my $ret= kill('KILL', -$child_pid);
message("Killed child: $child_pid, ret: $ret");
if ($ret > 0) {
message("Killed child: $child_pid");
diff --git a/mysql-test/lib/mtr_gcov.pl b/mysql-test/lib/mtr_gcov.pl
index d8fb1c0a07d..6f9e744a548 100644
--- a/mysql-test/lib/mtr_gcov.pl
+++ b/mysql-test/lib/mtr_gcov.pl
@@ -1,5 +1,5 @@
# -*- cperl -*-
-# Copyright (C) 2004, 2006 MySQL AB, 2009 Sun Microsystems, Inc.
+# Copyright (c) 2004, 2011, 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
@@ -31,7 +31,7 @@ sub gcov_prepare ($) {
#
# Collect gcov statistics.
# Arguments:
-# $dir basedir, normally source directory
+# $dir basedir, normally build directory
# $gcov gcov utility program [path] name
# $gcov_msg message file name
# $gcov_err error file name
@@ -43,29 +43,25 @@ sub gcov_collect ($$$) {
my $start_dir= cwd();
print "Collecting source coverage info using '$gcov'...\n";
- -f "$start_dir/$gcov_msg" and unlink("$start_dir/$gcov_msg");
- -f "$start_dir/$gcov_err" and unlink("$start_dir/$gcov_err");
+ -f "$dir/$gcov_msg" and unlink("$dir/$gcov_msg");
+ -f "$dir/$gcov_err" and unlink("$dir/$gcov_err");
my @dirs= `find "$dir" -type d -print | sort`;
#print "List of directories:\n@dirs\n";
foreach my $d ( @dirs ) {
- my $dir_reported= 0;
chomp($d);
chdir($d) or next;
- foreach my $f ( (glob("*.h"), glob("*.cc"), glob("*.c")) ) {
- $f =~ /(.*)\.[ch]c?/;
- -f "$1.gcno" or next;
- if (!$dir_reported) {
- print "Collecting in '$d'...\n";
- $dir_reported= 1;
- }
- system("$gcov $f 2>>$start_dir/$gcov_err >>$start_dir/$gcov_msg");
+ my @flist= glob("*.*.gcno");
+ print ("Collecting in '$d'...\n") if @flist;
+
+ foreach my $f (@flist) {
+ system("$gcov $f 2>>$dir/$gcov_err >>$dir/$gcov_msg");
}
chdir($start_dir);
}
- print "gcov info in $gcov_msg, errors in $gcov_err\n";
+ print "gcov info in $dir/$gcov_msg, errors in $dir/$gcov_err\n";
}
diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl
index 0d227170476..f3f1181562b 100755
--- a/mysql-test/mysql-test-run.pl
+++ b/mysql-test/mysql-test-run.pl
@@ -210,8 +210,8 @@ our $opt_clean_vardir= $ENV{'MTR_CLEAN_VARDIR'};
our $opt_gcov;
our $opt_gcov_exe= "gcov";
-our $opt_gcov_err= "mysql-test-gcov.msg";
-our $opt_gcov_msg= "mysql-test-gcov.err";
+our $opt_gcov_err= "mysql-test-gcov.err";
+our $opt_gcov_msg= "mysql-test-gcov.msg";
our $opt_gprof;
our %gprof_dirs;
@@ -274,12 +274,13 @@ my $opt_strace_client;
our $opt_user = "root";
-my $opt_valgrind= 0;
+our $opt_valgrind= 0;
my $opt_valgrind_mysqld= 0;
my $opt_valgrind_mysqltest= 0;
my @default_valgrind_args= ("--show-reachable=yes");
my @valgrind_args;
my $opt_valgrind_path;
+my $valgrind_reports= 0;
my $opt_callgrind;
my %mysqld_logs;
my $opt_debug_sync_timeout= 300; # Default timeout for WAIT_FOR actions.
@@ -504,10 +505,29 @@ sub main {
push @$completed, run_ctest() if $opt_ctest;
+ if ($opt_valgrind) {
+ # Create minimalistic "test" for the reporting
+ my $tinfo = My::Test->new
+ (
+ name => 'valgrind_report',
+ );
+ # Set dummy worker id to align report with normal tests
+ $tinfo->{worker} = 0 if $opt_parallel > 1;
+ if ($valgrind_reports) {
+ $tinfo->{result}= 'MTR_RES_FAILED';
+ $tinfo->{comment}= "Valgrind reported failures at shutdown, see above";
+ $tinfo->{failures}= 1;
+ } else {
+ $tinfo->{result}= 'MTR_RES_PASSED';
+ }
+ mtr_report_test($tinfo);
+ push @$completed, $tinfo;
+ }
+
mtr_print_line();
if ( $opt_gcov ) {
- gcov_collect($basedir, $opt_gcov_exe,
+ gcov_collect($bindir, $opt_gcov_exe,
$opt_gcov_msg, $opt_gcov_err);
}
@@ -704,6 +724,9 @@ sub run_test_server ($$$) {
elsif ($line =~ /^SPENT/) {
add_total_times($line);
}
+ elsif ($line eq 'VALGREP' && $opt_valgrind) {
+ $valgrind_reports= 1;
+ }
else {
mtr_error("Unknown response: '$line' from client");
}
@@ -889,6 +912,7 @@ sub run_worker ($) {
my $valgrind_reports= 0;
if ($opt_valgrind_mysqld) {
$valgrind_reports= valgrind_exit_reports();
+ print $server "VALGREP\n" if $valgrind_reports;
}
if ( $opt_gprof ) {
gprof_collect (find_mysqld($basedir), keys %gprof_dirs);
@@ -1198,7 +1222,7 @@ sub command_line_setup {
chomp;
# remove comments (# foo) at the beginning of the line, or after a
# blank at the end of the line
- s/( +|^)#.*$//;
+ s/(\s+|^)#.*$//;
# If @ platform specifier given, use this entry only if it contains
# @<platform> or @!<xxx> where xxx != platform
if (/\@.*/)
@@ -1209,8 +1233,8 @@ sub command_line_setup {
s/\@.*$//;
}
# remove whitespace
- s/^ +//;
- s/ +$//;
+ s/^\s+//;
+ s/\s+$//;
# if nothing left, don't need to remember this line
if ( $_ eq "" ) {
next;
@@ -2196,7 +2220,12 @@ sub environment_setup {
$ENV{'DEFAULT_MASTER_PORT'}= $mysqld_variables{'port'};
$ENV{'MYSQL_TMP_DIR'}= $opt_tmpdir;
$ENV{'MYSQLTEST_VARDIR'}= $opt_vardir;
+ # Used for guessing default plugin dir, we can't really know for sure
$ENV{'MYSQL_LIBDIR'}= "$basedir/lib";
+ # Override if this does not exist, but lib64 does (best effort)
+ if (! -d "$basedir/lib" && -d "$basedir/lib64") {
+ $ENV{'MYSQL_LIBDIR'}= "$basedir/lib64";
+ }
$ENV{'MYSQL_BINDIR'}= "$bindir";
$ENV{'MYSQL_SHAREDIR'}= $path_language;
$ENV{'MYSQL_CHARSETSDIR'}= $path_charsetsdir;
@@ -4092,6 +4121,9 @@ sub extract_warning_lines ($$) {
);
my $skip_valgrind= 0;
+ my $last_pat= "";
+ my $num_rep= 0;
+
foreach my $line ( @lines )
{
if ($opt_valgrind_mysqld) {
@@ -4106,11 +4138,29 @@ sub extract_warning_lines ($$) {
{
if ( $line =~ /$pat/ )
{
- print $Fwarn $line;
+ # Remove initial timestamp and look for consecutive identical lines
+ my $line_pat= $line;
+ $line_pat =~ s/^[0-9: ]*//;
+ if ($line_pat eq $last_pat) {
+ $num_rep++;
+ } else {
+ # Previous line had been repeated, report that first
+ if ($num_rep) {
+ print $Fwarn ".... repeated $num_rep times: $last_pat";
+ $num_rep= 0;
+ }
+ $last_pat= $line_pat;
+ print $Fwarn $line;
+ }
last;
}
}
}
+ # Catch the case of last warning being repeated
+ if ($num_rep) {
+ print $Fwarn ".... repeated $num_rep times: $last_pat";
+ }
+
$Fwarn = undef; # Close file
}
@@ -4747,13 +4797,6 @@ sub mysqld_start ($$) {
unlink($mysqld->value('pid-file'));
my $output= $mysqld->value('#log-error');
- if ( $opt_valgrind and $opt_debug )
- {
- # When both --valgrind and --debug is selected, send
- # all output to the trace file, making it possible to
- # see the exact location where valgrind complains
- $output= "$opt_vardir/log/".$mysqld->name().".trace";
- }
# Remember this log file for valgrind error report search
$mysqld_logs{$output}= 1 if $opt_valgrind;
# Remember data dir for gmon.out files if using gprof
@@ -5660,6 +5703,7 @@ sub valgrind_exit_reports() {
@culprits);
mtr_print_line();
print ("$valgrind_rep\n");
+ $found_err= 1;
$err_in_report= 0;
}
# Make ready to collect new report
diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result
index 69b93555ec0..eba9562a8c3 100644
--- a/mysql-test/r/alter_table.result
+++ b/mysql-test/r/alter_table.result
@@ -1391,3 +1391,16 @@ CREATE DATABASE db1 CHARACTER SET utf8;
CREATE TABLE db1.t1 (bar TINYTEXT, KEY (bar(100)));
ALTER TABLE db1.t1 ADD baz INT;
DROP DATABASE db1;
+#
+# Bug#11938039 RE-EXECUTION OF FRM-ONLY ALTER TABLE WITH RENAME
+# CLAUSE FAILS OR ABORTS SERVER.
+#
+drop table if exists t1;
+create table t1 (a int);
+prepare stmt1 from 'alter table t1 alter column a set default 1, rename to t2';
+execute stmt1;
+rename table t2 to t1;
+# The below statement should succeed and not emit error or abort server.
+execute stmt1;
+deallocate prepare stmt1;
+drop table t2;
diff --git a/mysql-test/r/events_1.result b/mysql-test/r/events_1.result
index e068158e6ce..29e81975c87 100644
--- a/mysql-test/r/events_1.result
+++ b/mysql-test/r/events_1.result
@@ -1,3 +1,4 @@
+call mtr.add_suppression("Column count of mysql.event is wrong. Expected .*, found .*\. The table is probably corrupted");
drop database if exists events_test;
drop database if exists db_x;
drop database if exists mysqltest_db2;
@@ -259,33 +260,36 @@ events_test intact_check root@localhost SYSTEM RECURRING NULL 10 # # NULL ENABLE
Try to alter mysql.event: the server should fail to load
event information after mysql.event was tampered with.
-First, let's add a column to the end and make sure everything
-works as before
+First, let's add a column to the end and check the error is emitted.
ALTER TABLE mysql.event ADD dummy INT;
SHOW EVENTS;
-Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
-events_test intact_check root@localhost SYSTEM RECURRING NULL 10 # # NULL ENABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci
+ERROR HY000: Failed to open mysql.event
SELECT event_name FROM INFORMATION_SCHEMA.events;
-event_name
-intact_check
+ERROR HY000: Failed to open mysql.event
SHOW CREATE EVENT intact_check;
-Event sql_mode time_zone Create Event character_set_client collation_connection Database Collation
-intact_check SYSTEM CREATE DEFINER=`root`@`localhost` EVENT `intact_check` ON SCHEDULE EVERY 10 HOUR STARTS '#' ON COMPLETION NOT PRESERVE ENABLE DO SELECT "nothing" latin1 latin1_swedish_ci latin1_swedish_ci
+ERROR HY000: Failed to open mysql.event
DROP EVENT no_such_event;
-ERROR HY000: Unknown event 'no_such_event'
+ERROR HY000: Failed to open mysql.event
CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
+ERROR HY000: Failed to open mysql.event
ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
+ERROR HY000: Failed to open mysql.event
ALTER EVENT intact_check_1 RENAME TO intact_check_2;
+ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check_1;
-ERROR HY000: Unknown event 'intact_check_1'
+ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check_2;
+ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check;
+ERROR HY000: Failed to open mysql.event
DROP DATABASE IF EXISTS mysqltest_no_such_database;
Warnings:
Note 1008 Can't drop database 'mysqltest_no_such_database'; database doesn't exist
CREATE DATABASE mysqltest_db2;
DROP DATABASE mysqltest_db2;
+Warnings:
+Error 1545 Failed to open mysql.event
SELECT @@event_scheduler;
@@event_scheduler
OFF
@@ -294,6 +298,7 @@ Variable_name Value
event_scheduler OFF
SET GLOBAL event_scheduler=OFF;
ALTER TABLE mysql.event DROP dummy;
+DROP EVENT intact_check;
CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing";
Now let's add a column to the first position: the server
@@ -301,30 +306,32 @@ expects to see event schema name there
ALTER TABLE mysql.event ADD dummy INT FIRST;
SHOW EVENTS;
-ERROR HY000: Cannot load from mysql.event. The table is probably corrupted
+ERROR HY000: Failed to open mysql.event
SELECT event_name FROM INFORMATION_SCHEMA.events;
-ERROR HY000: Cannot load from mysql.event. The table is probably corrupted
+ERROR HY000: Failed to open mysql.event
SHOW CREATE EVENT intact_check;
-ERROR HY000: Unknown event 'intact_check'
+ERROR HY000: Failed to open mysql.event
DROP EVENT no_such_event;
-ERROR HY000: Unknown event 'no_such_event'
+ERROR HY000: Failed to open mysql.event
CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
-ERROR HY000: Failed to store event name. Error code 2 from storage engine.
+ERROR HY000: Failed to open mysql.event
ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
-ERROR HY000: Unknown event 'intact_check_1'
+ERROR HY000: Failed to open mysql.event
ALTER EVENT intact_check_1 RENAME TO intact_check_2;
-ERROR HY000: Unknown event 'intact_check_1'
+ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check_1;
-ERROR HY000: Unknown event 'intact_check_1'
+ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check_2;
-ERROR HY000: Unknown event 'intact_check_2'
+ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check;
-ERROR HY000: Unknown event 'intact_check'
+ERROR HY000: Failed to open mysql.event
DROP DATABASE IF EXISTS mysqltest_no_such_database;
Warnings:
Note 1008 Can't drop database 'mysqltest_no_such_database'; database doesn't exist
CREATE DATABASE mysqltest_db2;
DROP DATABASE mysqltest_db2;
+Warnings:
+Error 1545 Failed to open mysql.event
SELECT @@event_scheduler;
@@event_scheduler
OFF
@@ -345,29 +352,32 @@ Drop some columns and try more checks.
ALTER TABLE mysql.event DROP comment, DROP starts;
SHOW EVENTS;
-ERROR HY000: Cannot load from mysql.event. The table is probably corrupted
+ERROR HY000: Failed to open mysql.event
SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
-ERROR HY000: Cannot load from mysql.event. The table is probably corrupted
+ERROR HY000: Failed to open mysql.event
SHOW CREATE EVENT intact_check;
-ERROR HY000: Cannot load from mysql.event. The table is probably corrupted
+ERROR HY000: Failed to open mysql.event
DROP EVENT no_such_event;
-ERROR HY000: Unknown event 'no_such_event'
+ERROR HY000: Failed to open mysql.event
CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
-ERROR HY000: Column count of mysql.event is wrong. Expected 22, found 20. The table is probably corrupted
+ERROR HY000: Failed to open mysql.event
ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
-ERROR HY000: Unknown event 'intact_check_1'
+ERROR HY000: Failed to open mysql.event
ALTER EVENT intact_check_1 RENAME TO intact_check_2;
-ERROR HY000: Unknown event 'intact_check_1'
+ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check_1;
-ERROR HY000: Unknown event 'intact_check_1'
+ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check_2;
-ERROR HY000: Unknown event 'intact_check_2'
+ERROR HY000: Failed to open mysql.event
DROP EVENT intact_check;
+ERROR HY000: Failed to open mysql.event
DROP DATABASE IF EXISTS mysqltest_no_such_database;
Warnings:
Note 1008 Can't drop database 'mysqltest_no_such_database'; database doesn't exist
CREATE DATABASE mysqltest_db2;
DROP DATABASE mysqltest_db2;
+Warnings:
+Error 1545 Failed to open mysql.event
SELECT @@event_scheduler;
@@event_scheduler
OFF
@@ -425,4 +435,42 @@ CREATE TABLE mysql.event like event_like;
DROP TABLE event_like;
SHOW EVENTS;
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
+
+#
+# Bug#12394306: the sever may crash if mysql.event is corrupted
+#
+
+CREATE EVENT ev1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
+ALTER EVENT ev1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
+
+CREATE TABLE event_original LIKE mysql.event;
+INSERT INTO event_original SELECT * FROM mysql.event;
+
+ALTER TABLE mysql.event MODIFY modified CHAR(1);
+Warnings:
+Warning 1265 Data truncated for column 'modified' at row 1
+
+SHOW EVENTS;
+ERROR HY000: Failed to open mysql.event
+
+SELECT event_name, created, last_altered FROM information_schema.events;
+ERROR HY000: Failed to open mysql.event
+
+CREATE EVENT ev2 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
+ERROR HY000: Failed to open mysql.event
+
+ALTER EVENT ev1 ON SCHEDULE EVERY 9 HOUR DO SELECT 9;
+ERROR HY000: Failed to open mysql.event
+
+DROP TABLE mysql.event;
+RENAME TABLE event_original TO mysql.event;
+
+DROP EVENT ev1;
+
+SHOW EVENTS;
+Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
+
+#
+# End of tests
+#
drop database events_test;
diff --git a/mysql-test/r/events_restart.result b/mysql-test/r/events_restart.result
index 4db61d357ce..6a751fa29f8 100644
--- a/mysql-test/r/events_restart.result
+++ b/mysql-test/r/events_restart.result
@@ -1,3 +1,4 @@
+call mtr.add_suppression("Column count of mysql.event is wrong. Expected .*, found .*\. The table is probably corrupted");
set global event_scheduler=off;
drop database if exists events_test;
create database events_test;
@@ -52,6 +53,8 @@ Warnings:
Note 1008 Can't drop database 'mysqltest_database_not_exists'; database doesn't exist
create database mysqltest_db1;
drop database mysqltest_db1;
+Warnings:
+Error 1545 Failed to open mysql.event
Restore the original mysql.event table
drop table mysql.event;
rename table event_like to mysql.event;
diff --git a/mysql-test/r/func_analyse.result b/mysql-test/r/func_analyse.result
index 92fc26e7ba3..f82439090f6 100644
--- a/mysql-test/r/func_analyse.result
+++ b/mysql-test/r/func_analyse.result
@@ -135,4 +135,17 @@ SELECT * FROM t1 PROCEDURE ANALYSE();
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
test.t1.a e e- 1 2 0 0 1.3333 NULL ENUM('e','e-') NOT NULL
DROP TABLE t1;
+#
+# Bug#11756242 48137: PROCEDURE ANALYSE() LEAKS MEMORY WHEN RETURNING NULL
+#
+CREATE TABLE t1(f1 INT) ENGINE=MYISAM;
+CREATE TABLE t2(f2 INT) ENGINE=INNODB;
+INSERT INTO t2 VALUES (1);
+SELECT DISTINCTROW f1 FROM t1 NATURAL RIGHT OUTER JOIN t2 PROCEDURE ANALYSE();
+Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
+test.t1.f1 NULL NULL 0 0 0 1 0.0 0.0 CHAR(0)
+SELECT * FROM t2 LIMIT 1 PROCEDURE ANALYSE();
+Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
+test.t2.f2 1 1 1 1 0 0 1.0000 0.0000 ENUM('1') NOT NULL
+DROP TABLE t1, t2;
End of 5.1 tests
diff --git a/mysql-test/r/func_group.result b/mysql-test/r/func_group.result
index 5454446984a..b299ba69a91 100644
--- a/mysql-test/r/func_group.result
+++ b/mysql-test/r/func_group.result
@@ -1746,6 +1746,17 @@ MAX(LENGTH(a)) LENGTH(MAX(a)) MIN(a) MAX(a) CONCAT(MIN(a)) CONCAT(MAX(a))
20 20 18446668621106209655 18446668621106209655 18446668621106209655 18446668621106209655
DROP TABLE t1;
#
+# Bug #11766270 59343: YEAR(4): INCORRECT RESULT AND VALGRIND WARNINGS WITH MIN/MAX, UNION
+#
+CREATE TABLE t1(f1 YEAR(4));
+INSERT INTO t1 VALUES (0000),(2001);
+(SELECT MAX(f1) FROM t1) UNION (SELECT MAX(f1) FROM t1);
+Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
+def MAX(f1) MAX(f1) 13 4 4 Y 32864 0 63
+MAX(f1)
+2001
+DROP TABLE t1;
+#
End of 5.1 tests
#
# Bug#52123 Assertion failed: aggregator == aggr->Aggrtype(),
diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result
index fdeec2755ca..0b6117581f3 100644
--- a/mysql-test/r/func_in.result
+++ b/mysql-test/r/func_in.result
@@ -770,4 +770,10 @@ CASE a WHEN a THEN a END
NULL
DROP TABLE t1;
#
+# Bug #11766212 59270: NOT IN (YEAR( ... ), ... ) PRODUCES MANY VALGRIND WARNINGS
+#
+SELECT 1 IN (YEAR(FROM_UNIXTIME(NULL)) ,1);
+1 IN (YEAR(FROM_UNIXTIME(NULL)) ,1)
+1
+#
End of 5.1 tests
diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result
index 525ee0dc506..ac24ef4dea9 100644
--- a/mysql-test/r/func_math.result
+++ b/mysql-test/r/func_math.result
@@ -521,6 +521,28 @@ CREATE TABLE t1 SELECT CEIL(LINESTRINGFROMWKB(1) DIV NULL);
DROP TABLE t1;
CREATE TABLE t1 SELECT FLOOR(LINESTRINGFROMWKB(1) DIV NULL);
DROP TABLE t1;
+#
+# Bug#11765923 58937: MANY VALGRIND ERRORS AFTER GROUPING BY RESULT OF DECIMAL COLUMN FUNCTION
+#
+CREATE TABLE t1(f1 DECIMAL(22,1));
+INSERT INTO t1 VALUES (0),(1);
+SELECT ROUND(f1, f1) FROM t1;
+ROUND(f1, f1)
+0.0
+1.0
+SELECT ROUND(f1, f1) FROM t1 GROUP BY 1;
+ROUND(f1, f1)
+0.0
+1.0
+DROP TABLE t1;
+#
+# Bug#11764671 57533: UNINITIALISED VALUES IN COPY_AND_CONVERT (SQL_STRING.CC) WITH CERTAIN CHA
+#
+SELECT ROUND(LEAST(15, -4939092, 0.2704), STDDEV('a'));
+ROUND(LEAST(15, -4939092, 0.2704), STDDEV('a'))
+-4939092.0000
+Warnings:
+Warning 1292 Truncated incorrect DOUBLE value: 'a'
End of 5.1 tests
#
# Bug #8433: Overflow must be an error
diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result
index 43e37dab9d5..b1bf0a6a830 100644
--- a/mysql-test/r/func_time.result
+++ b/mysql-test/r/func_time.result
@@ -1377,6 +1377,18 @@ NULL
SELECT ADDDATE(MONTH(FROM_UNIXTIME(NULL)),INTERVAL 1 HOUR);
ADDDATE(MONTH(FROM_UNIXTIME(NULL)),INTERVAL 1 HOUR)
NULL
+#
+# Bug#11889186 60503: CRASH IN MAKE_DATE_TIME WITH DATE_FORMAT / STR_TO_DATE COMBINATION
+#
+SELECT DATE_FORMAT('0000-00-11', '%W');
+DATE_FORMAT('0000-00-11', '%W')
+NULL
+SELECT DATE_FORMAT('0000-00-11', '%a');
+DATE_FORMAT('0000-00-11', '%a')
+NULL
+SELECT DATE_FORMAT('0000-00-11', '%w');
+DATE_FORMAT('0000-00-11', '%w')
+NULL
End of 5.1 tests
#
# Bug#57039: constant subtime expression returns incorrect result.
diff --git a/mysql-test/r/having.result b/mysql-test/r/having.result
index daf043860a4..1bbdd5011c4 100644
--- a/mysql-test/r/having.result
+++ b/mysql-test/r/having.result
@@ -547,4 +547,26 @@ FROM t1 JOIN t2 ON t2.f2 LIKE 'x'
HAVING field1 < 7;
field1
DROP TABLE t1,t2;
+#
+# Bug#48916 Server incorrectly processing HAVING clauses with an ORDER BY clause
+#
+CREATE TABLE t1 (f1 INT, f2 INT);
+INSERT INTO t1 VALUES (1, 0), (2, 1), (3, 2);
+CREATE TABLE t2 (f1 INT, f2 INT);
+SELECT t1.f1
+FROM t1
+HAVING (3, 2) IN (SELECT f1, f2 FROM t2) AND t1.f1 >= 0
+ORDER BY t1.f1;
+f1
+SELECT t1.f1
+FROM t1
+HAVING (3, 2) IN (SELECT 4, 2) AND t1.f1 >= 0
+ORDER BY t1.f1;
+f1
+SELECT t1.f1
+FROM t1
+HAVING 2 IN (SELECT f2 FROM t2) AND t1.f1 >= 0
+ORDER BY t1.f1;
+f1
+DROP TABLE t1,t2;
End of 5.1 tests
diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result
index 1c59f41cfc0..c4c8216c14a 100644
--- a/mysql-test/r/loaddata.result
+++ b/mysql-test/r/loaddata.result
@@ -532,4 +532,20 @@ a
0
1
DROP TABLE t1;
+#
+# Bug#11765139 58069: LOAD DATA INFILE: VALGRIND REPORTS INVALID MEMORY READS AND WRITES WITH U
+#
+CREATE TABLE t1(f1 INT);
+SELECT 0xE1BB30 INTO OUTFILE 't1.dat';
+LOAD DATA INFILE 't1.dat' IGNORE INTO TABLE t1 CHARACTER SET utf8;
+DROP TABLE t1;
+#
+# Bug#11765141 - 58072: LOAD DATA INFILE: LEAKS IO CACHE MEMORY
+# WHEN ERROR OCCURS
+#
+SELECT '1\n' INTO DUMPFILE 'MYSQLTEST_VARDIR/tmp/bug11735141.txt';
+create table t1(a point);
+LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug11735141.txt' INTO TABLE t1;
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+drop table t1;
End of 5.1 tests
diff --git a/mysql-test/r/mysqlbinlog_base64.result b/mysql-test/r/mysqlbinlog_base64.result
index c5e1e2f8ca1..72d49c16cc8 100644
--- a/mysql-test/r/mysqlbinlog_base64.result
+++ b/mysql-test/r/mysqlbinlog_base64.result
@@ -109,3 +109,13 @@ count(*)
35840
drop table t1;
drop table t2;
+RESET MASTER;
+USE test;
+SET @old_binlog_format= @@binlog_format;
+SET SESSION binlog_format=ROW;
+CREATE TABLE t1(c1 INT);
+INSERT INTO t1 VALUES (1);
+FLUSH LOGS;
+DROP TABLE t1;
+SET SESSION binlog_format= @old_binlog_format;
+RESET MASTER;
diff --git a/mysql-test/r/partition_myisam.result b/mysql-test/r/partition_myisam.result
index 57228c8d9a0..97bcc11495c 100644
--- a/mysql-test/r/partition_myisam.result
+++ b/mysql-test/r/partition_myisam.result
@@ -239,3 +239,12 @@ a
DROP TABLE t1;
# Should not be any files left here
# End of bug#30102 test.
+# Test of post-push fix for bug#11766249/59316
+CREATE TABLE t1 (a INT, b VARCHAR(255), PRIMARY KEY (a))
+ENGINE = MyISAM
+PARTITION BY RANGE (a)
+(PARTITION p0 VALUES LESS THAN (0) MAX_ROWS=100,
+PARTITION p1 VALUES LESS THAN (100) MAX_ROWS=100,
+PARTITION pMax VALUES LESS THAN MAXVALUE);
+INSERT INTO t1 VALUES (1, "Partition p1, first row");
+DROP TABLE t1;
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index 3abc02358b8..37741b79695 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -5084,6 +5084,24 @@ i
DROP TABLE t1,t1s,t2s;
End of 5.1 tests
#
+# Bug #11765713 58705:
+# OPTIMIZER LET ENGINE DEPEND ON UNINITIALIZED VALUES
+# CREATED BY OPT_SUM_QUERY
+#
+CREATE TABLE t1(a INT NOT NULL, KEY (a));
+INSERT INTO t1 VALUES (0), (1);
+SELECT 1 as foo FROM t1 WHERE a < SOME
+(SELECT a FROM t1 WHERE a <=>
+(SELECT a FROM t1)
+);
+ERROR 21000: Subquery returns more than 1 row
+SELECT 1 as foo FROM t1 WHERE a < SOME
+(SELECT a FROM t1 WHERE a <=>
+(SELECT a FROM t1 where a is null)
+);
+foo
+DROP TABLE t1;
+#
# Bug #57704: Cleanup code dies with void TABLE::set_keyread(bool):
# Assertion `file' failed.
#
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
index 11e0d7313b7..e759153eaaf 100644
--- a/mysql-test/r/trigger.result
+++ b/mysql-test/r/trigger.result
@@ -2208,4 +2208,22 @@ trigger_name
# Clean-up.
drop temporary table t1;
drop table t1;
-End of 6.0 tests.
+
+#
+# Bug #12362125: SP INOUT HANDLING IS BROKEN FOR TEXT TYPE.
+#
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1(c TEXT);
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+DECLARE v TEXT;
+SET v = 'aaa';
+SET NEW.c = v;
+END|
+INSERT INTO t1 VALUES('qazwsxedc');
+SELECT c FROM t1;
+c
+aaa
+DROP TABLE t1;
+
+End of 5.5 tests.
diff --git a/mysql-test/r/type_timestamp.result b/mysql-test/r/type_timestamp.result
index d5769bfd59a..55f8b0753a8 100644
--- a/mysql-test/r/type_timestamp.result
+++ b/mysql-test/r/type_timestamp.result
@@ -523,6 +523,69 @@ a
2000-01-01 00:00:01
2000-01-01 00:00:01
DROP TABLE t1;
+#
+# Bug#50774: failed to get the correct resultset when timestamp values
+# are appended with .0
+#
+CREATE TABLE t1 ( a TIMESTAMP, KEY ( a ) );
+INSERT INTO t1 VALUES( '2010-02-01 09:31:01' );
+INSERT INTO t1 VALUES( '2010-02-01 09:31:02' );
+INSERT INTO t1 VALUES( '2010-02-01 09:31:03' );
+INSERT INTO t1 VALUES( '2010-02-01 09:31:04' );
+SELECT * FROM t1 WHERE a >= '2010-02-01 09:31:02.0';
+a
+2010-02-01 09:31:02
+2010-02-01 09:31:03
+2010-02-01 09:31:04
+SELECT * FROM t1 WHERE '2010-02-01 09:31:02.0' <= a;
+a
+2010-02-01 09:31:02
+2010-02-01 09:31:03
+2010-02-01 09:31:04
+SELECT * FROM t1 WHERE a <= '2010-02-01 09:31:02.0';
+a
+2010-02-01 09:31:01
+2010-02-01 09:31:02
+SELECT * FROM t1 WHERE '2010-02-01 09:31:02.0' >= a;
+a
+2010-02-01 09:31:01
+2010-02-01 09:31:02
+EXPLAIN
+SELECT * FROM t1 WHERE a >= '2010-02-01 09:31:02.0';
+id select_type table type possible_keys key key_len ref rows Extra
+x x x range x x x x x x
+SELECT * FROM t1 WHERE a >= '2010-02-01 09:31:02.0';
+a
+2010-02-01 09:31:02
+2010-02-01 09:31:03
+2010-02-01 09:31:04
+CREATE TABLE t2 ( a TIMESTAMP, KEY ( a DESC ) );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:01' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:02' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:03' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:04' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:05' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:06' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:07' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:08' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:09' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:10' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:11' );
+# The bug would cause the range optimizer's comparison to use an open
+# interval here. This reveals itself only in the number of reads
+# performed.
+FLUSH STATUS;
+EXPLAIN
+SELECT * FROM t2 WHERE a < '2010-02-01 09:31:02.0';
+id select_type table type possible_keys key key_len ref rows Extra
+x x x range x x x x x x
+SELECT * FROM t2 WHERE a < '2010-02-01 09:31:02.0';
+a
+2010-02-01 09:31:01
+SHOW STATUS LIKE 'Handler_read_next';
+Variable_name Value
+Handler_read_next 1
+DROP TABLE t1, t2;
End of 5.1 tests
Bug#50888 valgrind warnings in Field_timestamp::val_str
diff --git a/mysql-test/r/warnings.result b/mysql-test/r/warnings.result
index 70b54ffceaf..4e706de382b 100644
--- a/mysql-test/r/warnings.result
+++ b/mysql-test/r/warnings.result
@@ -316,3 +316,25 @@ SHOW ERRORS;
Level Code Message
Error 1051 Unknown table 't1'
End of 5.0 tests
+
+-- Bug#55847
+
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS f1;
+CREATE TABLE t1(a INT UNIQUE);
+CREATE FUNCTION f1(x INT) RETURNS INT
+BEGIN
+INSERT INTO t1 VALUES(x);
+INSERT INTO t1 VALUES(x);
+RETURN x;
+END|
+
+SHOW TABLES WHERE f1(11) = 11;
+ERROR 23000: Duplicate entry '11' for key 'a'
+
+SHOW WARNINGS;
+Level Code Message
+Error 1062 Duplicate entry '11' for key 'a'
+
+DROP TABLE t1;
+DROP FUNCTION f1;
diff --git a/mysql-test/r/xa.result b/mysql-test/r/xa.result
index ad0d103c1e0..7b580abb19f 100644
--- a/mysql-test/r/xa.result
+++ b/mysql-test/r/xa.result
@@ -166,3 +166,66 @@ ERROR XA102: XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was det
XA END 'b';
XA ROLLBACK 'b';
DROP TABLE t1;
+#
+# Bug#11766752 59936: multiple xa assertions - transactional
+# statement fuzzer
+#
+CREATE TABLE t1 (a INT) engine=InnoDB;
+XA START 'a';
+INSERT INTO t1 VALUES (1);
+SAVEPOINT savep;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state
+XA END 'a';
+SELECT * FROM t1;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state
+INSERT INTO t1 VALUES (2);
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state
+SAVEPOINT savep;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state
+SET @a=(SELECT * FROM t1);
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the IDLE state
+XA PREPARE 'a';
+SELECT * FROM t1;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state
+INSERT INTO t1 VALUES (2);
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state
+SAVEPOINT savep;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state
+SET @a=(SELECT * FROM t1);
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state
+UPDATE t1 SET a=1 WHERE a=2;
+ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the PREPARED state
+XA COMMIT 'a';
+SELECT * FROM t1;
+a
+1
+DROP TABLE t1;
+#
+# Bug#12352846 - TRANS_XA_START(THD*):
+# ASSERTION THD->TRANSACTION.XID_STATE.XID.IS_NULL()
+# FAILED
+#
+DROP TABLE IF EXISTS t1, t2;
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (a INT);
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+# Connection con2
+XA START 'xid1';
+# Sending:
+INSERT INTO t2 SELECT a FROM t1;
+# Connection default
+# Waiting until INSERT ... is blocked
+DELETE FROM t1;
+COMMIT;
+# Connection con2
+# Reaping: INSERT INTO t2 SELECT a FROM t1
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+XA COMMIT 'xid1';
+ERROR XA102: XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected
+XA START 'xid1';
+XA END 'xid1';
+XA PREPARE 'xid1';
+XA ROLLBACK 'xid1';
+# Connection default
+DROP TABLE t1, t2;
diff --git a/mysql-test/suite/binlog/r/binlog_bug23533.result b/mysql-test/suite/binlog/r/binlog_bug23533.result
new file mode 100644
index 00000000000..d5cd93284a2
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_bug23533.result
@@ -0,0 +1,15 @@
+SET AUTOCOMMIT=0;
+CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT, b TEXT, PRIMARY KEY(a)) ENGINE=InnoDB;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+1000
+SET GLOBAL binlog_cache_size=4096;
+SET GLOBAL max_binlog_cache_size=4096;
+START TRANSACTION;
+CREATE TABLE t2 SELECT * FROM t1;
+ERROR HY000: Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again
+COMMIT;
+SHOW TABLES LIKE 't%';
+Tables_in_test (t%)
+t1
+DROP TABLE t1;
diff --git a/mysql-test/suite/binlog/r/binlog_bug36391.result b/mysql-test/suite/binlog/r/binlog_bug36391.result
new file mode 100644
index 00000000000..551bfb9924d
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_bug36391.result
@@ -0,0 +1,10 @@
+CREATE TABLE t1(id INT);
+SHOW TABLES;
+Tables_in_test
+t1
+FLUSH LOGS;
+DROP TABLE t1;
+SHOW TABLES;
+Tables_in_test
+t1
+DROP TABLE t1;
diff --git a/mysql-test/suite/bugs/t/rpl_bug23533.test b/mysql-test/suite/binlog/t/binlog_bug23533.test
index 337dddcef3d..ca610e399e4 100644
--- a/mysql-test/suite/bugs/t/rpl_bug23533.test
+++ b/mysql-test/suite/binlog/t/binlog_bug23533.test
@@ -4,33 +4,47 @@
#############################################################
--source include/have_innodb.inc
+--source include/have_log_bin.inc
--source include/have_binlog_format_row.inc
---source include/master-slave.inc
SET AUTOCOMMIT=0;
-SET GLOBAL max_binlog_cache_size=4096;
-SHOW VARIABLES LIKE 'max_binlog_cache_size';
+# Create 1st table
CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT, b TEXT, PRIMARY KEY(a)) ENGINE=InnoDB;
-
--disable_query_log
let $i= 1000;
while ($i)
{
+ BEGIN;
eval INSERT INTO t1 VALUES($i, REPEAT('x', 4096));
+ COMMIT;
dec $i;
}
--enable_query_log
-
SELECT COUNT(*) FROM t1;
+# Set small value for max_binlog_cache_size
+let $saved_binlog_cache_size= query_get_value(SELECT @@binlog_cache_size AS Value, Value, 1);
+let $saved_max_binlog_cache_size= query_get_value(SELECT @@max_binlog_cache_size AS Value, Value, 1);
+SET GLOBAL binlog_cache_size=4096;
+SET GLOBAL max_binlog_cache_size=4096;
+
+# New value of max_binlog_cache_size will apply to new session
+disconnect default;
+connect(default,localhost,root,,test);
+
# Copied data from t1 into t2 large than max_binlog_cache_size
START TRANSACTION;
---error 1534
+--error ER_TRANS_CACHE_FULL
CREATE TABLE t2 SELECT * FROM t1;
COMMIT;
SHOW TABLES LIKE 't%';
-
# 5.1 End of Test
---source include/rpl_end.inc
+--disable_query_log
+eval SET GLOBAL max_binlog_cache_size=$saved_max_binlog_cache_size;
+eval SET GLOBAL binlog_cache_size=$saved_binlog_cache_size;
+--enable_query_log
+DROP TABLE t1;
+disconnect default;
+connect(default,localhost,root,,test);
diff --git a/mysql-test/suite/bugs/t/rpl_bug36391-master.opt b/mysql-test/suite/binlog/t/binlog_bug36391-master.opt
index 56273241f14..56273241f14 100644
--- a/mysql-test/suite/bugs/t/rpl_bug36391-master.opt
+++ b/mysql-test/suite/binlog/t/binlog_bug36391-master.opt
diff --git a/mysql-test/suite/bugs/t/rpl_bug36391.test b/mysql-test/suite/binlog/t/binlog_bug36391.test
index 3961082273d..64d91dfafd9 100644
--- a/mysql-test/suite/bugs/t/rpl_bug36391.test
+++ b/mysql-test/suite/binlog/t/binlog_bug36391.test
@@ -13,17 +13,18 @@
#
#
---source include/master-slave.inc
+--source include/have_log_bin.inc
+--source include/have_binlog_format_mixed.inc
-create table t1(id int);
+CREATE TABLE t1(id INT);
+let $binlog= query_get_value(SHOW MASTER STATUS, File, 1);
+let $binlog_path= `SELECT CONCAT(@@DATADIR, '$binlog')`;
+SHOW TABLES;
+FLUSH LOGS;
+DROP TABLE t1;
-show tables;
+--exec $MYSQL_BINLOG $binlog_path | $MYSQL test
+SHOW TABLES;
---source include/show_master_status.inc
-
-flush logs;
-
---exec $MYSQL_BINLOG $MYSQL_TEST_DIR/var/log/master-bin.000001 | $MYSQL test
-
-drop table t1;
---source include/rpl_end.inc
+# Clean up
+DROP TABLE t1;
diff --git a/mysql-test/suite/bugs/combinations b/mysql-test/suite/bugs/combinations
deleted file mode 100644
index 07042c2cbec..00000000000
--- a/mysql-test/suite/bugs/combinations
+++ /dev/null
@@ -1,8 +0,0 @@
-[row]
-binlog-format=row
-
-[stmt]
-binlog-format=statement
-
-[mix]
-binlog-format=mixed
diff --git a/mysql-test/suite/bugs/data/rpl_bug12691.dat b/mysql-test/suite/bugs/data/rpl_bug12691.dat
deleted file mode 100644
index de980441c3a..00000000000
--- a/mysql-test/suite/bugs/data/rpl_bug12691.dat
+++ /dev/null
@@ -1,3 +0,0 @@
-a
-b
-c
diff --git a/mysql-test/suite/bugs/r/bug57108.result b/mysql-test/suite/bugs/r/bug57108.result
deleted file mode 100644
index ad60b07a1e3..00000000000
--- a/mysql-test/suite/bugs/r/bug57108.result
+++ /dev/null
@@ -1,5 +0,0 @@
-INSTALL PLUGIN example SONAME 'ha_example.so';
-SELECT @@global.connect_timeout AS connect_timeout, @@global.local_infile AS local_infile;
-connect_timeout 4711
-local_infile 1
-UNINSTALL PLUGIN example;
diff --git a/mysql-test/suite/bugs/r/rpl_bug12691.result b/mysql-test/suite/bugs/r/rpl_bug12691.result
deleted file mode 100644
index 8feeb0effc3..00000000000
--- a/mysql-test/suite/bugs/r/rpl_bug12691.result
+++ /dev/null
@@ -1,33 +0,0 @@
-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;
-
-**** On Master ****
-CREATE TABLE t1 (b CHAR(10));
-
-**** On Slave ****
-STOP SLAVE;
-
-**** On Master ****
-LOAD DATA INFILE FILENAME
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-3
-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 (b CHAR(10))
-master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=#
-master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/rpl_bug12691.dat' INTO TABLE `t1` FIELDS TERMINATED BY '|' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`b`) ;file_id=#
-
-**** On Slave ****
-SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
-START SLAVE;
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-0
-
-**** On Master ****
-DROP TABLE t1;
diff --git a/mysql-test/suite/bugs/r/rpl_bug23533.result b/mysql-test/suite/bugs/r/rpl_bug23533.result
deleted file mode 100644
index 1dda75a69b0..00000000000
--- a/mysql-test/suite/bugs/r/rpl_bug23533.result
+++ /dev/null
@@ -1,23 +0,0 @@
-stop slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-reset master;
-reset slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-start slave;
-DROP TABLE IF EXISTS t1,t2;
-SET AUTOCOMMIT=0;
-SET GLOBAL max_binlog_cache_size=4096;
-SHOW VARIABLES LIKE 'max_binlog_cache_size';
-Variable_name Value
-max_binlog_cache_size 4096
-CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT, b TEXT, PRIMARY KEY(a)) ENGINE=InnoDB;
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-1000
-START TRANSACTION;
-CREATE TABLE t2 SELECT * FROM t1;
-ERROR HY000: Writing one row to the row-based binary log failed
-COMMIT;
-SHOW TABLES LIKE 't%';
-Tables_in_test (t%)
-t1
diff --git a/mysql-test/suite/bugs/r/rpl_bug31582.result b/mysql-test/suite/bugs/r/rpl_bug31582.result
deleted file mode 100644
index 1f71fbf8fe7..00000000000
--- a/mysql-test/suite/bugs/r/rpl_bug31582.result
+++ /dev/null
@@ -1,16 +0,0 @@
-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 (a VARCHAR(10) PRIMARY KEY) ENGINE=MyISAM;
-INSERT INTO t1 VALUES ('a');
-UPDATE t1 SET a = 'MyISAM';
-SELECT * FROM t1 ORDER BY a;
-a
-MyISAM
-SELECT * FROM t1 ORDER BY a;
-a
-MyISAM
-DROP TABLE t1;
diff --git a/mysql-test/suite/bugs/r/rpl_bug31583.result b/mysql-test/suite/bugs/r/rpl_bug31583.result
deleted file mode 100644
index 74846607313..00000000000
--- a/mysql-test/suite/bugs/r/rpl_bug31583.result
+++ /dev/null
@@ -1,16 +0,0 @@
-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 ( a INT, b INT DEFAULT -3 );
-INSERT INTO t1 VALUES (1, DEFAULT);
-UPDATE t1 SET a = 3;
-SELECT * FROM t1 ORDER BY a;
-a b
-3 -3
-SELECT * FROM t1 ORDER BY a;
-a b
-3 -3
-DROP TABLE t1;
diff --git a/mysql-test/suite/bugs/r/rpl_bug33029.result b/mysql-test/suite/bugs/r/rpl_bug33029.result
deleted file mode 100644
index d11ae1cc0be..00000000000
--- a/mysql-test/suite/bugs/r/rpl_bug33029.result
+++ /dev/null
@@ -1,15 +0,0 @@
-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` (`id` int not null auto_increment primary key);
-create trigger `trg` before insert on `t1` for each row begin end;
-set @@global.debug="+d,simulate_bug33029";
-stop slave;
-start slave;
-insert into `t1` values ();
-select * from t1;
-id
-1
diff --git a/mysql-test/suite/bugs/r/rpl_bug36391.result b/mysql-test/suite/bugs/r/rpl_bug36391.result
deleted file mode 100644
index 33175d89d30..00000000000
--- a/mysql-test/suite/bugs/r/rpl_bug36391.result
+++ /dev/null
@@ -1,18 +0,0 @@
-stop slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-reset master;
-reset slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-start slave;
-drop table if exists t1;
-Warnings:
-Note 1051 Unknown table 't1'
-create table t1(id int);
-show tables;
-Tables_in_test
-t1
-show master status;
-File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000001 # <Binlog_Do_DB> <Binlog_Ignore_DB>
-flush logs;
-drop table t1;
diff --git a/mysql-test/suite/bugs/r/rpl_bug37426.result b/mysql-test/suite/bugs/r/rpl_bug37426.result
deleted file mode 100644
index 24dfd27ca01..00000000000
--- a/mysql-test/suite/bugs/r/rpl_bug37426.result
+++ /dev/null
@@ -1,17 +0,0 @@
-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 char128_utf8 (
-i1 INT NOT NULL,
-c CHAR(128) CHARACTER SET utf8 NOT NULL,
-i2 INT NOT NULL);
-INSERT INTO char128_utf8 VALUES ( 1, "123", 1 );
-SELECT * FROM char128_utf8;
-i1 c i2
-1 123 1
-SELECT * FROM char128_utf8;
-i1 c i2
-1 123 1
diff --git a/mysql-test/suite/bugs/r/rpl_bug38205.result b/mysql-test/suite/bugs/r/rpl_bug38205.result
deleted file mode 100644
index 8f1dee344fa..00000000000
--- a/mysql-test/suite/bugs/r/rpl_bug38205.result
+++ /dev/null
@@ -1,56 +0,0 @@
-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 t1i(n int primary key) engine=innodb;
-create table t2m(n int primary key) engine=myisam;
-begin;
-insert into t1i values (1);
-insert into t1i values (2);
-insert into t1i values (3);
-commit;
-begin;
-insert into t1i values (5);
-begin;
-insert into t1i values (4);
-insert into t2m values (1);
-update t1i set n = 5 where n = 4;
-commit;
-zero
-0
-*** kill sql thread ***
-rollback;
-*** sql thread is *not* running: No ***
-*** the prove: the killed slave has not finished the current transaction ***
-three
-3
-one
-1
-zero
-0
-delete from t2m;
-start slave sql_thread;
-delete from t1i;
-delete from t2m;
-begin;
-insert into t1i values (5);
-begin;
-insert into t1i values (4);
-update t1i set n = 5 where n = 4;
-commit;
-zero
-0
-stop slave sql_thread;
-rollback;
-*** sql thread is *not* running: No ***
-*** the prove: the stopped slave has rolled back the current transaction ***
-zero
-0
-zero
-0
-one
-1
-start slave sql_thread;
-drop table t1i, t2m;
diff --git a/mysql-test/suite/bugs/t/bug57108-master.opt b/mysql-test/suite/bugs/t/bug57108-master.opt
deleted file mode 100644
index c2ab1c2ead6..00000000000
--- a/mysql-test/suite/bugs/t/bug57108-master.opt
+++ /dev/null
@@ -1,2 +0,0 @@
---defaults-file=std_data/bug57108.cnf
-$EXAMPLE_PLUGIN_OPT
diff --git a/mysql-test/suite/bugs/t/bug57108.test b/mysql-test/suite/bugs/t/bug57108.test
deleted file mode 100644
index 56acd7fe7bd..00000000000
--- a/mysql-test/suite/bugs/t/bug57108.test
+++ /dev/null
@@ -1,12 +0,0 @@
---source include/not_windows_embedded.inc
---source include/have_example_plugin.inc
-
-# Test that we can install a plugin despite the fact that we have
-# switched directory after starting the server and am using a relative
-# --defaults-file.
---replace_regex /\.dll/.so/
-eval INSTALL PLUGIN example SONAME '$EXAMPLE_PLUGIN';
-
---query_vertical SELECT @@global.connect_timeout AS connect_timeout, @@global.local_infile AS local_infile
-
-UNINSTALL PLUGIN example;
diff --git a/mysql-test/suite/bugs/t/rpl_bug12691.test b/mysql-test/suite/bugs/t/rpl_bug12691.test
deleted file mode 100644
index 791cf126bfa..00000000000
--- a/mysql-test/suite/bugs/t/rpl_bug12691.test
+++ /dev/null
@@ -1,48 +0,0 @@
-# Bug#12691: Exec_master_log_pos corrupted with SQL_SLAVE_SKIP_COUNTER
-
---source include/master-slave.inc
---source include/have_binlog_format_mixed_or_statement.inc
-
---echo
---echo **** On Master ****
-CREATE TABLE t1 (b CHAR(10));
---echo
---echo **** On Slave ****
---sync_slave_with_master
-STOP SLAVE;
---source include/wait_for_slave_to_stop.inc
-
---connection master
-
---echo
---echo **** On Master ****
---exec cp $MYSQL_TEST_DIR/suite/bugs/data/rpl_bug12691.dat $MYSQLTEST_VARDIR/tmp/
---echo LOAD DATA INFILE FILENAME
---disable_query_log
---eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/rpl_bug12691.dat' INTO TABLE t1 FIELDS TERMINATED BY '|'
---enable_query_log
---remove_file $MYSQLTEST_VARDIR/tmp/rpl_bug12691.dat
-
-SELECT COUNT(*) FROM t1;
-
-source include/show_binlog_events.inc;
-
---save_master_pos
-
---connection slave
---echo
---echo **** On Slave ****
-SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
-START SLAVE;
---source include/wait_for_slave_to_start.inc
---sync_with_master
-
-SELECT COUNT(*) FROM t1;
-
-# Clean up
---connection master
---echo
---echo **** On Master ****
-DROP TABLE t1;
-
---source include/rpl_end.inc
diff --git a/mysql-test/suite/bugs/t/rpl_bug31582.test b/mysql-test/suite/bugs/t/rpl_bug31582.test
deleted file mode 100644
index 6bff8ef4172..00000000000
--- a/mysql-test/suite/bugs/t/rpl_bug31582.test
+++ /dev/null
@@ -1,25 +0,0 @@
-
-# BUG#31582: 5.1-telco-6.1 -> 5.1.22. Slave crashes when reading
-# UPDATE for VARCHAR
-
-# This is a problem for any update statement replicating from an old
-# server to a new server. The bug consisted of a new slave trying to
-# read two column bitmaps, but there is only one available in the old
-# format.
-
-# This test case should be executed replicating from an old server to
-# a new server, so make sure you have one handy.
-
-source include/master-slave.inc;
-
-CREATE TABLE t1 (a VARCHAR(10) PRIMARY KEY) ENGINE=MyISAM;
-INSERT INTO t1 VALUES ('a');
-UPDATE t1 SET a = 'MyISAM';
-SELECT * FROM t1 ORDER BY a;
-sync_slave_with_master;
-SELECT * FROM t1 ORDER BY a;
-
-connection master;
-DROP TABLE t1;
-
---source include/rpl_end.inc
diff --git a/mysql-test/suite/bugs/t/rpl_bug31583.test b/mysql-test/suite/bugs/t/rpl_bug31583.test
deleted file mode 100644
index ee5b7698016..00000000000
--- a/mysql-test/suite/bugs/t/rpl_bug31583.test
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# BUG#31583: 5.1-telco-6.1 -> 5.1.22. Slave returns Error in unknown event
-
-# This is a problem for any update statement replicating from an old
-# server to a new server. The bug consisted of a new slave trying to
-# read two column bitmaps, but there is only one available in the old
-# format.
-
-# This test case should be executed replicating from an old server to
-# a new server, so make sure you have one handy.
-
-source include/master-slave.inc;
-
-CREATE TABLE t1 ( a INT, b INT DEFAULT -3 );
-
-INSERT INTO t1 VALUES (1, DEFAULT);
-UPDATE t1 SET a = 3;
-SELECT * FROM t1 ORDER BY a;
-sync_slave_with_master;
-SELECT * FROM t1 ORDER BY a;
-
-connection master;
-DROP TABLE t1;
-
---source include/rpl_end.inc
diff --git a/mysql-test/suite/bugs/t/rpl_bug33029.test b/mysql-test/suite/bugs/t/rpl_bug33029.test
deleted file mode 100644
index f5aad4de8df..00000000000
--- a/mysql-test/suite/bugs/t/rpl_bug33029.test
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# Bug #36443 Server crashes when executing insert when insert trigger on table
-#
-# Emulating the former bug#33029 situation to see that there is no crash anymore.
-#
-
-
-source include/master-slave.inc;
-
-create table `t1` (`id` int not null auto_increment primary key);
-create trigger `trg` before insert on `t1` for each row begin end;
-
-sync_slave_with_master;
-set @@global.debug="+d,simulate_bug33029";
-
-stop slave;
-start slave;
-
-connection master;
-
-insert into `t1` values ();
-
-sync_slave_with_master;
-select * from t1;
-
---source include/rpl_end.inc
diff --git a/mysql-test/suite/bugs/t/rpl_bug38205.test b/mysql-test/suite/bugs/t/rpl_bug38205.test
deleted file mode 100644
index 550746719f4..00000000000
--- a/mysql-test/suite/bugs/t/rpl_bug38205.test
+++ /dev/null
@@ -1,166 +0,0 @@
-#
-# Bug #38205 Row-based Replication (RBR) causes inconsistencies: HA_ERR_FOUND_DUPP_KEY
-# Bug#319 if while a non-transactional slave is replicating a transaction possible problem
-#
-# Verifying the fact that STOP SLAVE in the middle of a group execution waits
-# for the end of the group before the slave sql thread will stop.
-# The patch refines STOP SLAVE to not interrupt a transaction or other type of
-# the replication events group (the part I).
-# Killing the sql thread continues to provide a "hard" stop (the part II).
-#
-# Non-deterministic tests
-#
-
-source include/master-slave.inc;
-source include/have_innodb.inc;
-
-
-#
-# Part II, killed sql slave leaves instantly
-#
-
-# A. multi-statement transaction as the replication group
-
-connection master;
-
-create table t1i(n int primary key) engine=innodb;
-create table t2m(n int primary key) engine=myisam;
-
-sync_slave_with_master;
-
-connection master;
-
-begin;
-insert into t1i values (1);
-insert into t1i values (2);
-insert into t1i values (3);
-commit;
-
-sync_slave_with_master;
-
-#
-# todo: first challenge is to find out the SQL thread id
-# the following is not fully reliable
-#
-
-let $id=`SELECT id from information_schema.processlist where user like 'system user' and state like '%Has read all relay log%' or user like 'system user' and state like '%Reading event from the relay log%'`;
-connection slave;
-begin;
-insert into t1i values (5);
-
-connection master;
-let $pos0_master= query_get_value(SHOW MASTER STATUS, Position, 1);
-begin;
-insert into t1i values (4);
-insert into t2m values (1); # non-ta update
-update t1i set n = 5 where n = 4; # to block at. can't be played with killed
-commit;
-let $pos1_master= query_get_value(SHOW MASTER STATUS, Position, 1);
-
-connection slave;
-# slave sql thread must be locked out by the conn `slave' explicit lock
-let $pos0_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
---disable_query_log
-eval select $pos0_master - $pos0_slave as zero;
---enable_query_log
-
-connection slave1;
-
-let $count= 1;
-let $table= t2m;
-source include/wait_until_rows_count.inc;
-#
-# todo: may fail as said above
-#
---echo *** kill sql thread ***
---disable_query_log
-eval kill connection $id;
---enable_query_log
-
-connection slave;
-rollback; # release the sql thread
-
-connection slave1;
-
-source include/wait_for_slave_sql_to_stop.inc;
-let $sql_status= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1);
---echo *** sql thread is *not* running: $sql_status ***
-let $pos1_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
-
-connection slave;
---echo *** the prove: the killed slave has not finished the current transaction ***
-
---disable_query_log
-select count(*) as three from t1i;
-eval select $pos1_master > $pos1_slave as one;
-eval select $pos1_slave - $pos0_slave as zero;
---enable_query_log
-
-delete from t2m; # remove the row to be able to replay
-start slave sql_thread;
-
-#
-# Part I: B The homogenous transaction remains interuptable in between
-#
-
-connection master;
-delete from t1i;
-delete from t2m;
-
-sync_slave_with_master;
-begin;
-insert into t1i values (5);
-
-connection master;
-let $pos0_master= query_get_value(SHOW MASTER STATUS, Position, 1);
-begin;
-insert into t1i values (4);
-update t1i set n = 5 where n = 4; # to block at. not to be played
-commit;
-let $pos1_master= query_get_value(SHOW MASTER STATUS, Position, 1);
-
-
-connection slave1;
-# slave sql can't advance as must be locked by the conn `slave' trans
-let $pos0_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
---disable_query_log
-eval select $pos0_master - $pos0_slave as zero;
---enable_query_log
-
-#
-# the replicated trans is blocked by the slave's local.
-# However, it's not easy to catch the exact moment when it happens.
-# The test issues sleep which makes the test either non-deterministic or
-# wasting too much time.
-#
---sleep 3
-
-send stop slave sql_thread;
-
-connection slave;
-rollback; # release the sql thread
-
-connection slave1;
-reap;
-source include/wait_for_slave_sql_to_stop.inc;
-let $sql_status= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1);
---echo *** sql thread is *not* running: $sql_status ***
-
-let $pos1_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
-
---echo *** the prove: the stopped slave has rolled back the current transaction ***
-
---disable_query_log
-select count(*) as zero from t1i;
-eval select $pos0_master - $pos0_slave as zero;
-eval select $pos1_master > $pos0_slave as one;
---enable_query_log
-
-start slave sql_thread;
-
-# clean-up
-
-connection master;
-drop table t1i, t2m;
-
---source include/rpl_end.inc
diff --git a/mysql-test/suite/innodb/r/innodb_bug59410.result b/mysql-test/suite/innodb/r/innodb_bug59410.result
new file mode 100644
index 00000000000..494d601ba4f
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb_bug59410.result
@@ -0,0 +1,17 @@
+create table `bug59410_1`(`a` int)engine=innodb;
+insert into `bug59410_1` values (1),(2),(3);
+select 1 from `bug59410_1` where `a` <> any (
+select 1 from `bug59410_1` where `a` <> 1 for update)
+for update;
+1
+1
+1
+drop table bug59410_1;
+create table bug59410_2(`a` char(1),`b` int)engine=innodb;
+insert into bug59410_2 values('0',0);
+set transaction isolation level read uncommitted;
+start transaction;
+set @a=(select b from bug59410_2 where
+(select 1 from bug59410_2 where a group by @a=b)
+group by @a:=b);
+drop table bug59410_2;
diff --git a/mysql-test/suite/innodb/r/innodb_bug59641.result b/mysql-test/suite/innodb/r/innodb_bug59641.result
new file mode 100644
index 00000000000..361172aa82b
--- /dev/null
+++ b/mysql-test/suite/innodb/r/innodb_bug59641.result
@@ -0,0 +1,57 @@
+CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB;
+INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32);
+COMMIT;
+XA START '123';
+INSERT INTO t VALUES(1,1);
+XA END '123';
+XA PREPARE '123';
+XA START '456';
+INSERT INTO t VALUES(3,47),(5,67);
+UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8;
+XA END '456';
+XA PREPARE '456';
+XA START '789';
+UPDATE t SET b=4*a WHERE a=32;
+XA END '789';
+XA PREPARE '789';
+call mtr.add_suppression("Found 3 prepared XA transactions");
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT * FROM t;
+a b
+1 1
+2 2
+3 47
+4 4
+5 134
+8 16
+16 16
+32 128
+COMMIT;
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT * FROM t;
+a b
+1 1
+2 2
+3 47
+4 4
+5 134
+8 16
+16 16
+32 128
+COMMIT;
+XA RECOVER;
+formatID gtrid_length bqual_length data
+1 3 0 789
+1 3 0 456
+1 3 0 123
+XA ROLLBACK '123';
+XA ROLLBACK '456';
+XA COMMIT '789';
+SELECT * FROM t;
+a b
+2 2
+4 4
+8 8
+16 16
+32 128
+DROP TABLE t;
diff --git a/mysql-test/suite/innodb/r/innodb_bug60196.result b/mysql-test/suite/innodb/r/innodb_bug60196.result
index 85707f81a28..411950b49dd 100755
--- a/mysql-test/suite/innodb/r/innodb_bug60196.result
+++ b/mysql-test/suite/innodb/r/innodb_bug60196.result
@@ -71,3 +71,47 @@ FK1_Key FK2_Key
DROP TABLE Bug_60196;
DROP TABLE Bug_60196_FK1;
DROP TABLE Bug_60196_FK2;
+CREATE TABLE Bug_60309_FK (
+ID INT PRIMARY KEY,
+ID2 INT,
+KEY K2(ID2)
+) ENGINE=InnoDB;
+CREATE TABLE Bug_60309 (
+ID INT PRIMARY KEY,
+FK_ID INT,
+KEY (FK_ID),
+CONSTRAINT FK FOREIGN KEY (FK_ID) REFERENCES Bug_60309_FK (ID)
+) ENGINE=InnoDB;
+INSERT INTO Bug_60309_FK (ID, ID2) VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO Bug_60309 VALUES (1, 1);
+INSERT INTO Bug_60309 VALUES (2, 99);
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`bug_60309`, CONSTRAINT `FK` FOREIGN KEY (`FK_ID`) REFERENCES `Bug_60309_FK` (`ID`))
+SELECT * FROM Bug_60309_FK;
+ID ID2
+1 1
+2 2
+3 3
+SELECT * FROM Bug_60309;
+ID FK_ID
+1 1
+# Stop server
+# Restart server.
+#
+# Try to insert more to the example table with foreign keys.
+# Bug60309 causes the foreign key file not to be found after
+# the resstart above.
+#
+SELECT * FROM Bug_60309;
+ID FK_ID
+1 1
+INSERT INTO Bug_60309 VALUES (2, 2);
+INSERT INTO Bug_60309 VALUES (3, 3);
+SELECT * FROM Bug_60309;
+ID FK_ID
+1 1
+2 2
+3 3
+
+# Clean up.
+DROP TABLE Bug_60309;
+DROP TABLE Bug_60309_FK;
diff --git a/mysql-test/suite/innodb/t/innodb_bug59410.test b/mysql-test/suite/innodb/t/innodb_bug59410.test
new file mode 100644
index 00000000000..30bb0642679
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb_bug59410.test
@@ -0,0 +1,24 @@
+#
+# Bug#59410 read uncommitted: unlock row could not find a 3 mode lock on the record
+#
+-- source include/have_innodb.inc
+
+# only interested that the following do not produce something like
+# InnoDB: Error: unlock row could not find a 2 mode lock on the record
+# in the error log
+
+create table `bug59410_1`(`a` int)engine=innodb;
+insert into `bug59410_1` values (1),(2),(3);
+select 1 from `bug59410_1` where `a` <> any (
+select 1 from `bug59410_1` where `a` <> 1 for update)
+for update;
+drop table bug59410_1;
+
+create table bug59410_2(`a` char(1),`b` int)engine=innodb;
+insert into bug59410_2 values('0',0);
+set transaction isolation level read uncommitted;
+start transaction;
+set @a=(select b from bug59410_2 where
+(select 1 from bug59410_2 where a group by @a=b)
+group by @a:=b);
+drop table bug59410_2;
diff --git a/mysql-test/suite/innodb/t/innodb_bug59641.test b/mysql-test/suite/innodb/t/innodb_bug59641.test
new file mode 100644
index 00000000000..b933abd1d14
--- /dev/null
+++ b/mysql-test/suite/innodb/t/innodb_bug59641.test
@@ -0,0 +1,68 @@
+# Bug #59641 Prepared XA transaction causes shutdown hang after a crash
+
+-- source include/not_embedded.inc
+-- source include/have_innodb.inc
+
+CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB;
+INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32);
+COMMIT;
+XA START '123';
+INSERT INTO t VALUES(1,1);
+XA END '123';
+XA PREPARE '123';
+
+CONNECT (con1,localhost,root,,);
+CONNECTION con1;
+
+XA START '456';
+INSERT INTO t VALUES(3,47),(5,67);
+UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8;
+XA END '456';
+XA PREPARE '456';
+
+CONNECT (con2,localhost,root,,);
+CONNECTION con2;
+
+XA START '789';
+UPDATE t SET b=4*a WHERE a=32;
+XA END '789';
+XA PREPARE '789';
+
+CONNECT (con3,localhost,root,,);
+CONNECTION con3;
+# The server would issue this warning on restart.
+call mtr.add_suppression("Found 3 prepared XA transactions");
+
+# Kill the server without sending a shutdown command
+-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- shutdown_server 0
+-- source include/wait_until_disconnected.inc
+
+# Restart the server.
+-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- enable_reconnect
+-- source include/wait_until_connected_again.inc
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT * FROM t;
+COMMIT;
+
+# Shut down the server. This would hang because of the bug.
+-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- shutdown_server
+-- source include/wait_until_disconnected.inc
+
+# Restart the server.
+-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+-- enable_reconnect
+-- source include/wait_until_connected_again.inc
+
+SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
+SELECT * FROM t;
+COMMIT;
+XA RECOVER;
+XA ROLLBACK '123';
+XA ROLLBACK '456';
+XA COMMIT '789';
+SELECT * FROM t;
+
+DROP TABLE t;
diff --git a/mysql-test/suite/innodb/t/innodb_bug60196.test b/mysql-test/suite/innodb/t/innodb_bug60196.test
index 47c646a5a75..ea85653f1af 100755
--- a/mysql-test/suite/innodb/t/innodb_bug60196.test
+++ b/mysql-test/suite/innodb/t/innodb_bug60196.test
@@ -85,3 +85,73 @@ DROP TABLE Bug_60196;
DROP TABLE Bug_60196_FK1;
DROP TABLE Bug_60196_FK2;
+
+# Bug#60309/12356829
+# MYSQL 5.5.9 FOR MAC OSX HAS BUG WITH FOREIGN KEY CONSTRAINTS
+# This testcase is different from that for Bug#60196 in that the
+# referenced table contains a secondary key. When the engine is
+# restarted, the referenced table is opened by the purge thread,
+# which does not notice that lower_case_table_names == 2.
+
+#
+# Create test data.
+#
+CREATE TABLE Bug_60309_FK (
+ ID INT PRIMARY KEY,
+ ID2 INT,
+ KEY K2(ID2)
+) ENGINE=InnoDB;
+CREATE TABLE Bug_60309 (
+ ID INT PRIMARY KEY,
+ FK_ID INT,
+ KEY (FK_ID),
+ CONSTRAINT FK FOREIGN KEY (FK_ID) REFERENCES Bug_60309_FK (ID)
+) ENGINE=InnoDB;
+
+INSERT INTO Bug_60309_FK (ID, ID2) VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO Bug_60309 VALUES (1, 1);
+--error ER_NO_REFERENCED_ROW_2
+INSERT INTO Bug_60309 VALUES (2, 99);
+
+SELECT * FROM Bug_60309_FK;
+SELECT * FROM Bug_60309;
+
+--echo # Stop server
+
+# Write file to make mysql-test-run.pl wait for the server to stop
+-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+
+# Send a shutdown request to the server
+-- shutdown_server 10
+
+# Call script that will poll the server waiting for it to disapear
+-- source include/wait_until_disconnected.inc
+
+--echo # Restart server.
+
+# Write file to make mysql-test-run.pl start up the server again
+--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
+
+# Turn on reconnect
+--enable_reconnect
+
+# Call script that will poll the server waiting for it to be back online again
+--source include/wait_until_connected_again.inc
+
+# Turn off reconnect again
+--disable_reconnect
+
+--echo #
+--echo # Try to insert more to the example table with foreign keys.
+--echo # Bug60309 causes the foreign key file not to be found after
+--echo # the resstart above.
+--echo #
+SELECT * FROM Bug_60309;
+INSERT INTO Bug_60309 VALUES (2, 2);
+INSERT INTO Bug_60309 VALUES (3, 3);
+SELECT * FROM Bug_60309;
+
+--echo
+--echo # Clean up.
+DROP TABLE Bug_60309;
+DROP TABLE Bug_60309_FK;
diff --git a/mysql-test/suite/parts/inc/partition_check_drop.inc b/mysql-test/suite/parts/inc/partition_check_drop.inc
index 0941cd9703b..7f8b5b7929b 100644
--- a/mysql-test/suite/parts/inc/partition_check_drop.inc
+++ b/mysql-test/suite/parts/inc/partition_check_drop.inc
@@ -37,7 +37,7 @@ if ($do_file_tests)
eval SET @aux = load_file('$ls_file');
# clean up
- remove_file $ls_file;
+ --remove_file $ls_file
}
if (!$do_file_tests)
{
diff --git a/mysql-test/suite/parts/inc/partition_fail.inc b/mysql-test/suite/parts/inc/partition_fail.inc
index f433712e284..dd79cdf1dc8 100644
--- a/mysql-test/suite/parts/inc/partition_fail.inc
+++ b/mysql-test/suite/parts/inc/partition_fail.inc
@@ -23,6 +23,7 @@ DROP TABLE t1;
--eval $create_statement
--eval $insert_statement
--echo # State before failure
+--replace_result #p# #P# #sp# #SP#
--list_files $DATADIR/test
SHOW CREATE TABLE t1;
--sorted_result
@@ -32,6 +33,7 @@ LOCK TABLE t1 WRITE;
--eval $fail_statement
--enable_abort_on_error
--echo # State after failure
+--replace_result #p# #P# #sp# #SP#
--list_files $DATADIR/test
SHOW CREATE TABLE t1;
--sorted_result
diff --git a/mysql-test/suite/parts/inc/partition_layout_check1.inc b/mysql-test/suite/parts/inc/partition_layout_check1.inc
index de35d3f2cad..76df4c1a250 100644
--- a/mysql-test/suite/parts/inc/partition_layout_check1.inc
+++ b/mysql-test/suite/parts/inc/partition_layout_check1.inc
@@ -45,6 +45,9 @@ if ($do_file_tests)
--list_files_append_file $ls_file $MYSQLTEST_VARDIR/mysql-test-idx-dir t1*
}
eval SET @aux = load_file('$ls_file');
+
+ # clean up
+ --remove_file $ls_file
}
if (!$do_file_tests)
{
diff --git a/mysql-test/suite/parts/inc/partition_layout_check2.inc b/mysql-test/suite/parts/inc/partition_layout_check2.inc
index 028b1242e90..23e4a9e1e95 100644
--- a/mysql-test/suite/parts/inc/partition_layout_check2.inc
+++ b/mysql-test/suite/parts/inc/partition_layout_check2.inc
@@ -43,6 +43,9 @@ if ($do_file_tests)
--list_files_append_file $ls_file $MYSQLTEST_VARDIR/mysql-test-idx-dir t1*
}
eval SET @aux = load_file('$ls_file');
+
+ # clean up
+ --remove_file $ls_file
}
if (!$do_file_tests)
{
diff --git a/mysql-test/suite/rpl/r/rpl_bug37426.result b/mysql-test/suite/rpl/r/rpl_bug37426.result
new file mode 100644
index 00000000000..bf96255c7b4
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_bug37426.result
@@ -0,0 +1,12 @@
+include/master-slave.inc
+[connection master]
+CREATE TABLE char128_utf8 (i1 INT NOT NULL, c CHAR(128) CHARACTER SET utf8 NOT NULL, i2 INT NOT NULL);
+INSERT INTO char128_utf8 VALUES ( 1, "123", 1 );
+SELECT * FROM char128_utf8;
+i1 c i2
+1 123 1
+SELECT * FROM char128_utf8;
+i1 c i2
+1 123 1
+DROP TABLE char128_utf8;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/r/rpl_server_id2.result b/mysql-test/suite/rpl/r/rpl_server_id2.result
index ce1f54dbf85..69c0e1f7d9b 100644
--- a/mysql-test/suite/rpl/r/rpl_server_id2.result
+++ b/mysql-test/suite/rpl/r/rpl_server_id2.result
@@ -22,7 +22,7 @@ change master to master_port=MASTER_PORT;
start slave until master_log_file='master-bin.000001', master_log_pos=UNTIL_POS;
include/wait_for_slave_io_to_start.inc
include/wait_for_slave_sql_to_stop.inc
-*** checking until postion execution: must be only t1 in the list ***
+*** checking until position execution: must be only t1 in the list ***
show tables;
Tables_in_test
t1
diff --git a/mysql-test/suite/bugs/t/rpl_bug37426.test b/mysql-test/suite/rpl/t/rpl_bug37426.test
index 4c7729ab837..d0a60524fef 100644
--- a/mysql-test/suite/bugs/t/rpl_bug37426.test
+++ b/mysql-test/suite/rpl/t/rpl_bug37426.test
@@ -7,15 +7,16 @@ source include/master-slave.inc;
source include/have_binlog_format_row.inc;
connection master;
-CREATE TABLE char128_utf8 (
- i1 INT NOT NULL,
- c CHAR(128) CHARACTER SET utf8 NOT NULL,
- i2 INT NOT NULL);
-
+CREATE TABLE char128_utf8 (i1 INT NOT NULL, c CHAR(128) CHARACTER SET utf8 NOT NULL, i2 INT NOT NULL);
INSERT INTO char128_utf8 VALUES ( 1, "123", 1 );
SELECT * FROM char128_utf8;
sync_slave_with_master;
SELECT * FROM char128_utf8;
+
+# Clean up
+connection master;
+DROP TABLE char128_utf8;
+sync_slave_with_master;
--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_row_until.test b/mysql-test/suite/rpl/t/rpl_row_until.test
index 0a70fb441c1..b861bb8c8ec 100644
--- a/mysql-test/suite/rpl/t/rpl_row_until.test
+++ b/mysql-test/suite/rpl/t/rpl_row_until.test
@@ -8,32 +8,32 @@
connection master;
CREATE TABLE t1(n INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
INSERT INTO t1 VALUES (1),(2),(3),(4);
-# Save master log postion for query DROP TABLE t1
+# Save master log position for query DROP TABLE t1
let $master_pos_drop_t1= query_get_value(SHOW MASTER STATUS, Position, 1);
DROP TABLE t1;
-# Save master log postion for query DROP TABLE t1
+# Save master log position for query DROP TABLE t1
save_master_pos;
let $master_pos_drop_t1= query_get_value(SHOW BINLOG EVENTS, Pos, 7);
let $master_log_file= query_get_value(SHOW BINLOG EVENTS, Log_name, 7);
-# Save master log postion for query CREATE TABLE t2
+# Save master log position for query CREATE TABLE t2
let $master_pos_create_t2= query_get_value(SHOW MASTER STATUS, Position, 1);
CREATE TABLE t2(n INT NOT NULL AUTO_INCREMENT PRIMARY KEY);
#show binlog events;
INSERT INTO t2 VALUES (1),(2);
-# Save master log postion for query INSERT INTO t2 VALUES (1),(2);
+# Save master log position for query INSERT INTO t2 VALUES (1),(2);
let $master_pos_insert1_t2= query_get_value(SHOW MASTER STATUS, Position, 1);
sync_slave_with_master;
#show binlog events;
-# Save relay log postion for query INSERT INTO t2 VALUES (1),(2);
+# Save relay log position for query INSERT INTO t2 VALUES (1),(2);
let $relay_pos_insert1_t2= query_get_value(SHOW SLAVE STATUS, Relay_Log_Pos, 1);
connection master;
INSERT INTO t2 VALUES (3),(4);
DROP TABLE t2;
-# Save master log postion for query DROP TABLE t2;
+# Save master log position for query DROP TABLE t2;
let $master_pos_drop_t2= query_get_value(SHOW MASTER STATUS, Position, 1);
sync_slave_with_master;
#show binlog events;
diff --git a/mysql-test/suite/rpl/t/rpl_server_id2.test b/mysql-test/suite/rpl/t/rpl_server_id2.test
index aa2ad5c3a8a..21e197866cf 100644
--- a/mysql-test/suite/rpl/t/rpl_server_id2.test
+++ b/mysql-test/suite/rpl/t/rpl_server_id2.test
@@ -50,7 +50,7 @@ eval start slave until master_log_file='master-bin.000001', master_log_pos=$unti
--source include/wait_for_slave_io_to_start.inc
--source include/wait_for_slave_sql_to_stop.inc
---echo *** checking until postion execution: must be only t1 in the list ***
+--echo *** checking until position execution: must be only t1 in the list ***
show tables;
# cleanup
diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test
index 5d71eead642..38d0d08808a 100644
--- a/mysql-test/t/alter_table.test
+++ b/mysql-test/t/alter_table.test
@@ -1159,3 +1159,20 @@ CREATE TABLE db1.t1 (bar TINYTEXT, KEY (bar(100)));
ALTER TABLE db1.t1 ADD baz INT;
DROP DATABASE db1;
+
+
+--echo #
+--echo # Bug#11938039 RE-EXECUTION OF FRM-ONLY ALTER TABLE WITH RENAME
+--echo # CLAUSE FAILS OR ABORTS SERVER.
+--echo #
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (a int);
+prepare stmt1 from 'alter table t1 alter column a set default 1, rename to t2';
+execute stmt1;
+rename table t2 to t1;
+--echo # The below statement should succeed and not emit error or abort server.
+execute stmt1;
+deallocate prepare stmt1;
+drop table t2;
diff --git a/mysql-test/t/events_1.test b/mysql-test/t/events_1.test
index ccdeb70d291..7f31e3fc881 100644
--- a/mysql-test/t/events_1.test
+++ b/mysql-test/t/events_1.test
@@ -4,6 +4,8 @@
# Can't test with embedded server that doesn't support grants
-- source include/not_embedded.inc
+call mtr.add_suppression("Column count of mysql.event is wrong. Expected .*, found .*\. The table is probably corrupted");
+
--disable_warnings
drop database if exists events_test;
drop database if exists db_x;
@@ -270,23 +272,28 @@ SHOW EVENTS;
--echo Try to alter mysql.event: the server should fail to load
--echo event information after mysql.event was tampered with.
--echo
---echo First, let's add a column to the end and make sure everything
---echo works as before
+--echo First, let's add a column to the end and check the error is emitted.
--echo
ALTER TABLE mysql.event ADD dummy INT;
---replace_column 8 # 9 #
+--error ER_EVENT_OPEN_TABLE_FAILED
SHOW EVENTS;
+--error ER_EVENT_OPEN_TABLE_FAILED
SELECT event_name FROM INFORMATION_SCHEMA.events;
---replace_regex /STARTS '[^']+'/STARTS '#'/
+--error ER_EVENT_OPEN_TABLE_FAILED
SHOW CREATE EVENT intact_check;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT no_such_event;
+--error ER_EVENT_OPEN_TABLE_FAILED
CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
+--error ER_EVENT_OPEN_TABLE_FAILED
ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
+--error ER_EVENT_OPEN_TABLE_FAILED
ALTER EVENT intact_check_1 RENAME TO intact_check_2;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check_1;
+--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check_2;
+--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check;
DROP DATABASE IF EXISTS mysqltest_no_such_database;
CREATE DATABASE mysqltest_db2;
@@ -296,6 +303,7 @@ SHOW VARIABLES LIKE 'event_scheduler';
SET GLOBAL event_scheduler=OFF;
# Clean up
ALTER TABLE mysql.event DROP dummy;
+DROP EVENT intact_check;
CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing";
--echo
--echo Now let's add a column to the first position: the server
@@ -303,24 +311,26 @@ CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing";
--echo
ALTER TABLE mysql.event ADD dummy INT FIRST;
--error ER_CANNOT_LOAD_FROM_TABLE
+--error ER_EVENT_OPEN_TABLE_FAILED
SHOW EVENTS;
--error ER_CANNOT_LOAD_FROM_TABLE
+--error ER_EVENT_OPEN_TABLE_FAILED
SELECT event_name FROM INFORMATION_SCHEMA.events;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
SHOW CREATE EVENT intact_check;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT no_such_event;
---error ER_EVENT_STORE_FAILED
+--error ER_EVENT_OPEN_TABLE_FAILED
CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
ALTER EVENT intact_check_1 RENAME TO intact_check_2;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check_1;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check_2;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check;
# Should work OK
DROP DATABASE IF EXISTS mysqltest_no_such_database;
@@ -341,25 +351,25 @@ INSERT INTO event_like SELECT * FROM mysql.event;
--echo
--echo
ALTER TABLE mysql.event DROP comment, DROP starts;
---error ER_CANNOT_LOAD_FROM_TABLE
+--error ER_EVENT_OPEN_TABLE_FAILED
SHOW EVENTS;
---error ER_CANNOT_LOAD_FROM_TABLE
+--error ER_EVENT_OPEN_TABLE_FAILED
SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
---error ER_CANNOT_LOAD_FROM_TABLE
+--error ER_EVENT_OPEN_TABLE_FAILED
SHOW CREATE EVENT intact_check;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT no_such_event;
---error ER_COL_COUNT_DOESNT_MATCH_CORRUPTED
+--error ER_EVENT_OPEN_TABLE_FAILED
CREATE EVENT intact_check_1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
ALTER EVENT intact_check_1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
ALTER EVENT intact_check_1 RENAME TO intact_check_2;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check_1;
---error ER_EVENT_DOES_NOT_EXIST
+--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check_2;
-# Should succeed
+--error ER_EVENT_OPEN_TABLE_FAILED
DROP EVENT intact_check;
DROP DATABASE IF EXISTS mysqltest_no_such_database;
CREATE DATABASE mysqltest_db2;
@@ -407,9 +417,54 @@ CREATE TABLE mysql.event like event_like;
DROP TABLE event_like;
--replace_column 8 # 9 #
SHOW EVENTS;
-#
-# End of tests
-#
+
+--echo
+--echo #
+--echo # Bug#12394306: the sever may crash if mysql.event is corrupted
+--echo #
+
+--echo
+CREATE EVENT ev1 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
+ALTER EVENT ev1 ON SCHEDULE EVERY 8 HOUR DO SELECT 8;
+
+--echo
+CREATE TABLE event_original LIKE mysql.event;
+INSERT INTO event_original SELECT * FROM mysql.event;
+
+--echo
+ALTER TABLE mysql.event MODIFY modified CHAR(1);
+
+--echo
+--error ER_EVENT_OPEN_TABLE_FAILED
+SHOW EVENTS;
+
+--echo
+--error ER_EVENT_OPEN_TABLE_FAILED
+SELECT event_name, created, last_altered FROM information_schema.events;
+
+--echo
+--error ER_EVENT_OPEN_TABLE_FAILED
+CREATE EVENT ev2 ON SCHEDULE EVERY 5 HOUR DO SELECT 5;
+
+--echo
+--error ER_EVENT_OPEN_TABLE_FAILED
+ALTER EVENT ev1 ON SCHEDULE EVERY 9 HOUR DO SELECT 9;
+
+--echo
+DROP TABLE mysql.event;
+RENAME TABLE event_original TO mysql.event;
+
+--echo
+DROP EVENT ev1;
+
+--echo
+SHOW EVENTS;
+
+
+--echo
+--echo #
+--echo # End of tests
+--echo #
let $wait_condition=
select count(*) = 0 from information_schema.processlist
diff --git a/mysql-test/t/events_restart.test b/mysql-test/t/events_restart.test
index e155fe2ea16..facf2912087 100644
--- a/mysql-test/t/events_restart.test
+++ b/mysql-test/t/events_restart.test
@@ -1,6 +1,8 @@
# Can't test with embedded server that doesn't support grants
-- source include/not_embedded.inc
+call mtr.add_suppression("Column count of mysql.event is wrong. Expected .*, found .*\. The table is probably corrupted");
+
#
# Test that when the server is restarted, it checks mysql.event table,
# and disables the scheduler if it's not up to date.
diff --git a/mysql-test/t/func_analyse.test b/mysql-test/t/func_analyse.test
index 63929d8766b..c77967a0cc9 100644
--- a/mysql-test/t/func_analyse.test
+++ b/mysql-test/t/func_analyse.test
@@ -1,6 +1,7 @@
#
# Test of procedure analyse
#
+-- source include/have_innodb.inc
--disable_warnings
drop table if exists t1,t2;
@@ -144,4 +145,15 @@ INSERT INTO t1 VALUES ('e'),('e'),('e-');
SELECT * FROM t1 PROCEDURE ANALYSE();
DROP TABLE t1;
+--echo #
+--echo # Bug#11756242 48137: PROCEDURE ANALYSE() LEAKS MEMORY WHEN RETURNING NULL
+--echo #
+
+CREATE TABLE t1(f1 INT) ENGINE=MYISAM;
+CREATE TABLE t2(f2 INT) ENGINE=INNODB;
+INSERT INTO t2 VALUES (1);
+SELECT DISTINCTROW f1 FROM t1 NATURAL RIGHT OUTER JOIN t2 PROCEDURE ANALYSE();
+SELECT * FROM t2 LIMIT 1 PROCEDURE ANALYSE();
+DROP TABLE t1, t2;
+
--echo End of 5.1 tests
diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test
index 1c25a5bf8c7..e8309d68830 100644
--- a/mysql-test/t/func_group.test
+++ b/mysql-test/t/func_group.test
@@ -1128,6 +1128,18 @@ SELECT MAX(LENGTH(a)), LENGTH(MAX(a)), MIN(a), MAX(a), CONCAT(MIN(a)), CONCAT(MA
DROP TABLE t1;
--echo #
+--echo # Bug #11766270 59343: YEAR(4): INCORRECT RESULT AND VALGRIND WARNINGS WITH MIN/MAX, UNION
+--echo #
+
+CREATE TABLE t1(f1 YEAR(4));
+INSERT INTO t1 VALUES (0000),(2001);
+--enable_metadata
+(SELECT MAX(f1) FROM t1) UNION (SELECT MAX(f1) FROM t1);
+--disable_metadata
+DROP TABLE t1;
+
+
+--echo #
--echo End of 5.1 tests
###
diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test
index 6efeb2866e6..08469b37967 100644
--- a/mysql-test/t/func_in.test
+++ b/mysql-test/t/func_in.test
@@ -555,5 +555,11 @@ SELECT CASE a WHEN a THEN a END FROM t1 GROUP BY a WITH ROLLUP;
DROP TABLE t1;
--echo #
+--echo # Bug #11766212 59270: NOT IN (YEAR( ... ), ... ) PRODUCES MANY VALGRIND WARNINGS
+--echo #
+
+SELECT 1 IN (YEAR(FROM_UNIXTIME(NULL)) ,1);
+
+--echo #
--echo End of 5.1 tests
diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test
index 687d96f8804..0e704fecf57 100644
--- a/mysql-test/t/func_math.test
+++ b/mysql-test/t/func_math.test
@@ -354,6 +354,22 @@ DROP TABLE t1;
CREATE TABLE t1 SELECT FLOOR(LINESTRINGFROMWKB(1) DIV NULL);
DROP TABLE t1;
+--echo #
+--echo # Bug#11765923 58937: MANY VALGRIND ERRORS AFTER GROUPING BY RESULT OF DECIMAL COLUMN FUNCTION
+--echo #
+
+CREATE TABLE t1(f1 DECIMAL(22,1));
+INSERT INTO t1 VALUES (0),(1);
+SELECT ROUND(f1, f1) FROM t1;
+SELECT ROUND(f1, f1) FROM t1 GROUP BY 1;
+DROP TABLE t1;
+
+--echo #
+--echo # Bug#11764671 57533: UNINITIALISED VALUES IN COPY_AND_CONVERT (SQL_STRING.CC) WITH CERTAIN CHA
+--echo #
+
+SELECT ROUND(LEAST(15, -4939092, 0.2704), STDDEV('a'));
+
--echo End of 5.1 tests
--echo #
diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test
index 96a73a454c3..add741e12a7 100644
--- a/mysql-test/t/func_time.test
+++ b/mysql-test/t/func_time.test
@@ -894,6 +894,14 @@ SELECT CAST((MONTH(FROM_UNIXTIME(@@GLOBAL.SQL_MODE))) AS BINARY(1025));
SELECT ADDDATE(MONTH(FROM_UNIXTIME(NULL)),INTERVAL 1 HOUR);
+--echo #
+--echo # Bug#11889186 60503: CRASH IN MAKE_DATE_TIME WITH DATE_FORMAT / STR_TO_DATE COMBINATION
+--echo #
+
+SELECT DATE_FORMAT('0000-00-11', '%W');
+SELECT DATE_FORMAT('0000-00-11', '%a');
+SELECT DATE_FORMAT('0000-00-11', '%w');
+
--echo End of 5.1 tests
--echo #
diff --git a/mysql-test/t/having.test b/mysql-test/t/having.test
index c808e747523..2ed8b40b858 100644
--- a/mysql-test/t/having.test
+++ b/mysql-test/t/having.test
@@ -564,4 +564,30 @@ HAVING field1 < 7;
DROP TABLE t1,t2;
+--echo #
+--echo # Bug#48916 Server incorrectly processing HAVING clauses with an ORDER BY clause
+--echo #
+
+CREATE TABLE t1 (f1 INT, f2 INT);
+INSERT INTO t1 VALUES (1, 0), (2, 1), (3, 2);
+CREATE TABLE t2 (f1 INT, f2 INT);
+
+SELECT t1.f1
+FROM t1
+HAVING (3, 2) IN (SELECT f1, f2 FROM t2) AND t1.f1 >= 0
+ORDER BY t1.f1;
+
+SELECT t1.f1
+FROM t1
+HAVING (3, 2) IN (SELECT 4, 2) AND t1.f1 >= 0
+ORDER BY t1.f1;
+
+SELECT t1.f1
+FROM t1
+HAVING 2 IN (SELECT f2 FROM t2) AND t1.f1 >= 0
+ORDER BY t1.f1;
+
+DROP TABLE t1,t2;
+
+
--echo End of 5.1 tests
diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test
index 06054d1990d..0bb3cf64444 100644
--- a/mysql-test/t/loaddata.test
+++ b/mysql-test/t/loaddata.test
@@ -601,5 +601,33 @@ DROP TABLE t1;
let $MYSQLD_DATADIR= `select @@datadir`;
remove_file $MYSQLD_DATADIR/test/tmpp2.txt;
+--echo #
+--echo # Bug#11765139 58069: LOAD DATA INFILE: VALGRIND REPORTS INVALID MEMORY READS AND WRITES WITH U
+--echo #
+
+CREATE TABLE t1(f1 INT);
+EVAL SELECT 0xE1BB30 INTO OUTFILE 't1.dat';
+--disable_warnings
+LOAD DATA INFILE 't1.dat' IGNORE INTO TABLE t1 CHARACTER SET utf8;
+--enable_warnings
+
+DROP TABLE t1;
+let $MYSQLD_DATADIR= `select @@datadir`;
+remove_file $MYSQLD_DATADIR/test/t1.dat;
+
+--echo #
+--echo # Bug#11765141 - 58072: LOAD DATA INFILE: LEAKS IO CACHE MEMORY
+--echo # WHEN ERROR OCCURS
+--echo #
+
+--let $file=$MYSQLTEST_VARDIR/tmp/bug11735141.txt
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--eval SELECT '1\n' INTO DUMPFILE '$file'
+
+create table t1(a point);
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--error ER_CANT_CREATE_GEOMETRY_OBJECT
+--eval LOAD DATA INFILE '$file' INTO TABLE t1
+drop table t1;
--echo End of 5.1 tests
diff --git a/mysql-test/t/mysqlbinlog_base64.test b/mysql-test/t/mysqlbinlog_base64.test
index fb21e28fdcb..3d3444cea1c 100644
--- a/mysql-test/t/mysqlbinlog_base64.test
+++ b/mysql-test/t/mysqlbinlog_base64.test
@@ -71,3 +71,32 @@ select count(*) from t2;
--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_base64.sql
drop table t1;
drop table t2;
+
+#
+# BUG#12354268
+#
+# This test verifies that using --start-position with DECODE-ROWS
+# does not make mysqlbinlog to output an error stating that it
+# does not contain any FD event.
+#
+
+RESET MASTER;
+USE test;
+SET @old_binlog_format= @@binlog_format;
+SET SESSION binlog_format=ROW;
+CREATE TABLE t1(c1 INT);
+--let $master_binlog= query_get_value(SHOW MASTER STATUS, File, 1)
+--let $master_pos= query_get_value(SHOW MASTER STATUS, Position, 1)
+--let $MYSQLD_DATADIR= `SELECT @@datadir`
+
+INSERT INTO t1 VALUES (1);
+
+FLUSH LOGS;
+
+--disable_result_log
+--exec $MYSQL_BINLOG --base64-output=DECODE-ROWS --start-position=$master_pos -v $MYSQLD_DATADIR/$master_binlog
+--enable_result_log
+
+DROP TABLE t1;
+SET SESSION binlog_format= @old_binlog_format;
+RESET MASTER;
diff --git a/mysql-test/t/partition_myisam.test b/mysql-test/t/partition_myisam.test
index 37d4a071fb9..c3766430275 100644
--- a/mysql-test/t/partition_myisam.test
+++ b/mysql-test/t/partition_myisam.test
@@ -1,5 +1,4 @@
--- source include/have_partition.inc
-
+--source include/have_partition.inc
--disable_warnings
DROP TABLE IF EXISTS t1, t2;
--enable_warnings
@@ -171,3 +170,13 @@ DROP TABLE t1;
--list_files $MYSQLD_DATADIR/test t1*
--list_files $MYSQLD_DATADIR/test t2*
--echo # End of bug#30102 test.
+
+--echo # Test of post-push fix for bug#11766249/59316
+CREATE TABLE t1 (a INT, b VARCHAR(255), PRIMARY KEY (a))
+ENGINE = MyISAM
+PARTITION BY RANGE (a)
+(PARTITION p0 VALUES LESS THAN (0) MAX_ROWS=100,
+ PARTITION p1 VALUES LESS THAN (100) MAX_ROWS=100,
+ PARTITION pMax VALUES LESS THAN MAXVALUE);
+INSERT INTO t1 VALUES (1, "Partition p1, first row");
+DROP TABLE t1;
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 5230dd5ddc4..f3be94ebb94 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -4030,6 +4030,28 @@ DROP TABLE t1,t1s,t2s;
--echo End of 5.1 tests
--echo #
+--echo # Bug #11765713 58705:
+--echo # OPTIMIZER LET ENGINE DEPEND ON UNINITIALIZED VALUES
+--echo # CREATED BY OPT_SUM_QUERY
+--echo #
+
+CREATE TABLE t1(a INT NOT NULL, KEY (a));
+INSERT INTO t1 VALUES (0), (1);
+
+--error ER_SUBQUERY_NO_1_ROW
+SELECT 1 as foo FROM t1 WHERE a < SOME
+ (SELECT a FROM t1 WHERE a <=>
+ (SELECT a FROM t1)
+ );
+
+SELECT 1 as foo FROM t1 WHERE a < SOME
+ (SELECT a FROM t1 WHERE a <=>
+ (SELECT a FROM t1 where a is null)
+ );
+
+DROP TABLE t1;
+
+--echo #
--echo # Bug #57704: Cleanup code dies with void TABLE::set_keyread(bool):
--echo # Assertion `file' failed.
--echo #
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
index e5039c3ea23..80dbcceb448 100644
--- a/mysql-test/t/trigger.test
+++ b/mysql-test/t/trigger.test
@@ -2583,4 +2583,32 @@ select trigger_name from information_schema.triggers
drop temporary table t1;
drop table t1;
---echo End of 6.0 tests.
+
+--echo
+--echo #
+--echo # Bug #12362125: SP INOUT HANDLING IS BROKEN FOR TEXT TYPE.
+--echo #
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1(c TEXT);
+
+delimiter |;
+CREATE TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW
+BEGIN
+ DECLARE v TEXT;
+ SET v = 'aaa';
+ SET NEW.c = v;
+END|
+delimiter ;|
+
+INSERT INTO t1 VALUES('qazwsxedc');
+
+SELECT c FROM t1;
+
+DROP TABLE t1;
+
+--echo
+--echo End of 5.5 tests.
diff --git a/mysql-test/t/type_timestamp.test b/mysql-test/t/type_timestamp.test
index 76423b11b99..cd4ba18455b 100644
--- a/mysql-test/t/type_timestamp.test
+++ b/mysql-test/t/type_timestamp.test
@@ -362,6 +362,53 @@ SELECT a FROM t1 WHERE a >= '20000101000000';
DROP TABLE t1;
+--echo #
+--echo # Bug#50774: failed to get the correct resultset when timestamp values
+--echo # are appended with .0
+--echo #
+CREATE TABLE t1 ( a TIMESTAMP, KEY ( a ) );
+
+INSERT INTO t1 VALUES( '2010-02-01 09:31:01' );
+INSERT INTO t1 VALUES( '2010-02-01 09:31:02' );
+INSERT INTO t1 VALUES( '2010-02-01 09:31:03' );
+INSERT INTO t1 VALUES( '2010-02-01 09:31:04' );
+
+SELECT * FROM t1 WHERE a >= '2010-02-01 09:31:02.0';
+SELECT * FROM t1 WHERE '2010-02-01 09:31:02.0' <= a;
+SELECT * FROM t1 WHERE a <= '2010-02-01 09:31:02.0';
+SELECT * FROM t1 WHERE '2010-02-01 09:31:02.0' >= a;
+
+--replace_column 1 x 2 x 3 x 5 x 6 x 7 x 8 x 9 x 10 x
+EXPLAIN
+SELECT * FROM t1 WHERE a >= '2010-02-01 09:31:02.0';
+SELECT * FROM t1 WHERE a >= '2010-02-01 09:31:02.0';
+
+CREATE TABLE t2 ( a TIMESTAMP, KEY ( a DESC ) );
+
+INSERT INTO t2 VALUES( '2010-02-01 09:31:01' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:02' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:03' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:04' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:05' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:06' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:07' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:08' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:09' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:10' );
+INSERT INTO t2 VALUES( '2010-02-01 09:31:11' );
+
+--echo # The bug would cause the range optimizer's comparison to use an open
+--echo # interval here. This reveals itself only in the number of reads
+--echo # performed.
+FLUSH STATUS;
+--replace_column 1 x 2 x 3 x 5 x 6 x 7 x 8 x 9 x 10 x
+EXPLAIN
+SELECT * FROM t2 WHERE a < '2010-02-01 09:31:02.0';
+SELECT * FROM t2 WHERE a < '2010-02-01 09:31:02.0';
+SHOW STATUS LIKE 'Handler_read_next';
+
+DROP TABLE t1, t2;
+
--echo End of 5.1 tests
--echo
diff --git a/mysql-test/t/warnings.test b/mysql-test/t/warnings.test
index 98e1db62d84..5569776904f 100644
--- a/mysql-test/t/warnings.test
+++ b/mysql-test/t/warnings.test
@@ -228,3 +228,43 @@ DROP TABLE t1;
SHOW ERRORS;
--echo End of 5.0 tests
+
+#
+# Bug#55847: SHOW WARNINGS returns empty result set when SQLEXCEPTION is active
+#
+
+--echo
+--echo -- Bug#55847
+--echo
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS f1;
+--enable_warnings
+
+CREATE TABLE t1(a INT UNIQUE);
+
+delimiter |;
+
+CREATE FUNCTION f1(x INT) RETURNS INT
+BEGIN
+ INSERT INTO t1 VALUES(x);
+ INSERT INTO t1 VALUES(x);
+ RETURN x;
+END|
+
+delimiter ;|
+
+--echo
+
+--error ER_DUP_ENTRY
+SHOW TABLES WHERE f1(11) = 11;
+
+--echo
+
+SHOW WARNINGS;
+
+--echo
+
+DROP TABLE t1;
+DROP FUNCTION f1;
diff --git a/mysql-test/t/xa.test b/mysql-test/t/xa.test
index 47ea4981314..8ce9ce52960 100644
--- a/mysql-test/t/xa.test
+++ b/mysql-test/t/xa.test
@@ -3,6 +3,8 @@
#
-- source include/have_innodb.inc
+--source include/not_embedded.inc
+
# Save the initial number of concurrent sessions
--source include/count_sessions.inc
@@ -287,6 +289,98 @@ DROP TABLE t1;
disconnect con1;
+--echo #
+--echo # Bug#11766752 59936: multiple xa assertions - transactional
+--echo # statement fuzzer
+--echo #
+
+CREATE TABLE t1 (a INT) engine=InnoDB;
+XA START 'a';
+INSERT INTO t1 VALUES (1);
+
+--error ER_XAER_RMFAIL
+SAVEPOINT savep;
+
+XA END 'a';
+--error ER_XAER_RMFAIL
+SELECT * FROM t1;
+--error ER_XAER_RMFAIL
+INSERT INTO t1 VALUES (2);
+--error ER_XAER_RMFAIL
+SAVEPOINT savep;
+--error ER_XAER_RMFAIL
+SET @a=(SELECT * FROM t1);
+
+XA PREPARE 'a';
+--error ER_XAER_RMFAIL
+SELECT * FROM t1; # used to cause InnoDB assert
+--error ER_XAER_RMFAIL
+INSERT INTO t1 VALUES (2); # used to cause InnoDB assert
+--error ER_XAER_RMFAIL
+SAVEPOINT savep;
+--error ER_XAER_RMFAIL
+SET @a=(SELECT * FROM t1); # used to cause InnoDB assert
+--error ER_XAER_RMFAIL
+UPDATE t1 SET a=1 WHERE a=2;
+
+XA COMMIT 'a';
+SELECT * FROM t1;
+DROP TABLE t1;
+
+
+--echo #
+--echo # Bug#12352846 - TRANS_XA_START(THD*):
+--echo # ASSERTION THD->TRANSACTION.XID_STATE.XID.IS_NULL()
+--echo # FAILED
+--echo #
+
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2;
+--enable_warnings
+
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (a INT);
+
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+
+--echo # Connection con2
+--connect (con2,localhost,root)
+XA START 'xid1';
+--echo # Sending:
+--send INSERT INTO t2 SELECT a FROM t1
+
+--echo # Connection default
+--connection default
+let $wait_condition=
+ SELECT COUNT(*) = 1 FROM information_schema.processlist
+ WHERE state = "Sending data"
+ AND info = "INSERT INTO t2 SELECT a FROM t1";
+--echo # Waiting until INSERT ... is blocked
+--source include/wait_condition.inc
+DELETE FROM t1;
+COMMIT;
+
+--echo # Connection con2
+--connection con2
+--echo # Reaping: INSERT INTO t2 SELECT a FROM t1
+--error ER_LOCK_DEADLOCK
+--reap
+--error ER_XA_RBDEADLOCK
+XA COMMIT 'xid1';
+# This caused the assert to be triggered
+XA START 'xid1';
+
+XA END 'xid1';
+XA PREPARE 'xid1';
+XA ROLLBACK 'xid1';
+
+--echo # Connection default
+connection default;
+DROP TABLE t1, t2;
+disconnect con2;
+
+
# Wait till all disconnects are completed
--source include/wait_until_count_sessions.inc
diff --git a/mysys/my_init.c b/mysys/my_init.c
index 4963ce9b577..4056464b6fb 100644
--- a/mysys/my_init.c
+++ b/mysys/my_init.c
@@ -467,10 +467,6 @@ PSI_mutex_key key_my_file_info_mutex;
PSI_mutex_key key_LOCK_localtime_r;
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
-#ifndef HAVE_GETHOSTBYNAME_R
-PSI_mutex_key key_LOCK_gethostbyname_r;
-#endif /* HAVE_GETHOSTBYNAME_R */
-
PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock,
key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock, key_LOCK_alarm,
key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
@@ -487,9 +483,6 @@ static PSI_mutex_info all_mysys_mutexes[]=
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
{ &key_LOCK_localtime_r, "LOCK_localtime_r", PSI_FLAG_GLOBAL},
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
-#ifndef HAVE_GETHOSTBYNAME_R
- { &key_LOCK_gethostbyname_r, "LOCK_gethostbyname_r", PSI_FLAG_GLOBAL},
-#endif /* HAVE_GETHOSTBYNAME_R */
{ &key_BITMAP_mutex, "BITMAP::mutex", 0},
{ &key_IO_CACHE_append_buffer_lock, "IO_CACHE::append_buffer_lock", 0},
{ &key_IO_CACHE_SHARE_mutex, "IO_CACHE::SHARE_mutex", 0},
diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c
index 28f6412ed5b..b30d99565fa 100644
--- a/mysys/my_thr_init.c
+++ b/mysys/my_thr_init.c
@@ -34,9 +34,6 @@ uint my_thread_end_wait_time= 5;
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
mysql_mutex_t LOCK_localtime_r;
#endif
-#ifndef HAVE_GETHOSTBYNAME_R
-mysql_mutex_t LOCK_gethostbyname_r;
-#endif
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
pthread_mutexattr_t my_fast_mutexattr;
#endif
@@ -222,10 +219,6 @@ my_bool my_thread_global_init(void)
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
mysql_mutex_init(key_LOCK_localtime_r, &LOCK_localtime_r, MY_MUTEX_INIT_SLOW);
#endif
-#ifndef HAVE_GETHOSTBYNAME_R
- mysql_mutex_init(key_LOCK_gethostbyname_r,
- &LOCK_gethostbyname_r, MY_MUTEX_INIT_SLOW);
-#endif
#ifdef _MSC_VER
install_sigabrt_handler();
@@ -289,9 +282,6 @@ void my_thread_global_end(void)
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
mysql_mutex_destroy(&LOCK_localtime_r);
#endif
-#ifndef HAVE_GETHOSTBYNAME_R
- mysql_mutex_destroy(&LOCK_gethostbyname_r);
-#endif
my_thread_global_init_done= 0;
}
diff --git a/mysys/mysys_priv.h b/mysys/mysys_priv.h
index e760ea808b7..5188b909863 100644
--- a/mysys/mysys_priv.h
+++ b/mysys/mysys_priv.h
@@ -36,10 +36,6 @@ extern PSI_mutex_key key_my_file_info_mutex;
extern PSI_mutex_key key_LOCK_localtime_r;
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
-#ifndef HAVE_GETHOSTBYNAME_R
-extern PSI_mutex_key key_LOCK_gethostbyname_r;
-#endif /* HAVE_GETHOSTBYNAME_R */
-
extern PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock,
key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock, key_LOCK_alarm,
key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
diff --git a/plugin/semisync/semisync_slave_plugin.cc b/plugin/semisync/semisync_slave_plugin.cc
index 5aa32cdfd5f..cfb04bdd276 100644
--- a/plugin/semisync/semisync_slave_plugin.cc
+++ b/plugin/semisync/semisync_slave_plugin.cc
@@ -53,7 +53,6 @@ int repl_semi_slave_request_dump(Binlog_relay_IO_param *param,
if (mysql_real_query(mysql, query, strlen(query)) ||
!(res= mysql_store_result(mysql)))
{
- mysql_free_result(mysql_store_result(mysql));
sql_print_error("Execution failed on master: %s", query);
return 1;
}
@@ -65,8 +64,10 @@ int repl_semi_slave_request_dump(Binlog_relay_IO_param *param,
sql_print_warning("Master server does not support semi-sync, "
"fallback to asynchronous replication");
rpl_semi_sync_slave_status= 0;
+ mysql_free_result(res);
return 0;
}
+ mysql_free_result(res);
/*
Tell master dump thread that we want to do semi-sync
@@ -76,7 +77,6 @@ int repl_semi_slave_request_dump(Binlog_relay_IO_param *param,
if (mysql_real_query(mysql, query, strlen(query)))
{
sql_print_error("Set 'rpl_semi_sync_slave=1' on master failed");
- mysql_free_result(mysql_store_result(mysql));
return 1;
}
mysql_free_result(mysql_store_result(mysql));
diff --git a/sql-common/client.c b/sql-common/client.c
index 90d07f3e409..abaea310aae 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -2314,11 +2314,18 @@ static auth_plugin_t clear_password_client_plugin=
clear_password_auth_client
};
+#ifdef AUTHENTICATION_WIN
+extern auth_plugin_t win_auth_client_plugin;
+#endif
+
struct st_mysql_client_plugin *mysql_client_builtins[]=
{
(struct st_mysql_client_plugin *)&native_password_client_plugin,
(struct st_mysql_client_plugin *)&old_password_client_plugin,
(struct st_mysql_client_plugin *)&clear_password_client_plugin,
+#ifdef AUTHENTICATION_WIN
+ (struct st_mysql_client_plugin *)&win_auth_client_plugin,
+#endif
0
};
diff --git a/sql-common/client_plugin.c b/sql-common/client_plugin.c
index 47409e34d9a..382f14c6b3d 100644
--- a/sql-common/client_plugin.c
+++ b/sql-common/client_plugin.c
@@ -460,7 +460,7 @@ mysql_client_find_plugin(MYSQL *mysql, const char *name, int type)
/* see <mysql/client_plugin.h> for a full description */
-int STDCALL mysql_plugin_options(struct st_mysql_client_plugin *plugin,
+int mysql_plugin_options(struct st_mysql_client_plugin *plugin,
const char *option,
const void *value)
{
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index 39eee57a1c0..de88e8756b5 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -772,7 +772,7 @@ long calc_daynr(uint year,uint month,uint day)
int y= year; /* may be < 0 temporarily */
DBUG_ENTER("calc_daynr");
- if (y == 0 && month == 0 && day == 0)
+ if (y == 0 && month == 0)
DBUG_RETURN(0); /* Skip errors */
/* Cast to int to be able to handle month == 0 */
delsum= (long) (365 * y + 31 *((int) month - 1) + (int) day);
@@ -783,6 +783,7 @@ long calc_daynr(uint year,uint month,uint day)
temp=(int) ((y/100+1)*3)/4;
DBUG_PRINT("exit",("year: %d month: %d day: %d -> daynr: %ld",
y+(month <= 2),month,day,delsum+y/4-temp));
+ DBUG_ASSERT(delsum+(int) y/4-temp > 0);
DBUG_RETURN(delsum+(int) y/4-temp);
} /* calc_daynr */
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index 3a25324db52..75d1c8ef8e8 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -534,6 +534,13 @@ Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *i_s_table,
if (open_system_tables_for_read(thd, &event_table, &open_tables_backup))
DBUG_RETURN(TRUE);
+ if (table_intact.check(event_table.table, &event_table_def))
+ {
+ close_system_tables(thd, &open_tables_backup);
+ my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
/*
1. SELECT I_S => use table scan. I_S.EVENTS does not guarantee order
thus we won't order it. OTOH, SHOW EVENTS will be
@@ -591,6 +598,14 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
*table= tables.table;
tables.table->use_all_columns();
+
+ if (table_intact.check(*table, &event_table_def))
+ {
+ close_thread_tables(thd);
+ my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
DBUG_RETURN(FALSE);
}
@@ -1035,6 +1050,13 @@ Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
*/
if (!(ret= open_system_tables_for_read(thd, &event_table, &open_tables_backup)))
{
+ if (table_intact.check(event_table.table, &event_table_def))
+ {
+ close_system_tables(thd, &open_tables_backup);
+ my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
if ((ret= find_named_event(dbname, name, event_table.table)))
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
else if ((ret= etn->load_from_row(thd, event_table.table)))
diff --git a/sql/field.cc b/sql/field.cc
index 01c4459c06c..7ffc399718c 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -5382,6 +5382,7 @@ double Field_year::val_real(void)
longlong Field_year::val_int(void)
{
ASSERT_COLUMN_MARKED_FOR_READ;
+ DBUG_ASSERT(field_length == 2 || field_length == 4);
int tmp= (int) ptr[0];
if (field_length != 4)
tmp%=100; // Return last 2 char
@@ -5394,6 +5395,7 @@ longlong Field_year::val_int(void)
String *Field_year::val_str(String *val_buffer,
String *val_ptr __attribute__((unused)))
{
+ DBUG_ASSERT(field_length < 5);
val_buffer->alloc(5);
val_buffer->length(field_length);
char *to=(char*) val_buffer->ptr();
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 59b904aceac..754d5dc99cf 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -162,8 +162,7 @@ const uint ha_partition::NO_CURRENT_PART_ID= 0xFFFFFFFF;
*/
ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share)
- :handler(hton, share), m_part_info(NULL), m_create_handler(FALSE),
- m_is_sub_partitioned(0)
+ :handler(hton, share)
{
DBUG_ENTER("ha_partition::ha_partition(table)");
init_handler_variables();
@@ -183,15 +182,44 @@ ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share)
*/
ha_partition::ha_partition(handlerton *hton, partition_info *part_info)
- :handler(hton, NULL), m_part_info(part_info), m_create_handler(TRUE),
- m_is_sub_partitioned(m_part_info->is_sub_partitioned())
+ :handler(hton, NULL)
{
DBUG_ENTER("ha_partition::ha_partition(part_info)");
+ DBUG_ASSERT(part_info);
init_handler_variables();
- DBUG_ASSERT(m_part_info);
+ m_part_info= part_info;
+ m_create_handler= TRUE;
+ m_is_sub_partitioned= m_part_info->is_sub_partitioned();
DBUG_VOID_RETURN;
}
+/**
+ ha_partition constructor method used by ha_partition::clone()
+
+ @param hton Handlerton (partition_hton)
+ @param share Table share object
+ @param part_info_arg partition_info to use
+ @param clone_arg ha_partition to clone
+ @param clme_mem_root_arg MEM_ROOT to use
+
+ @return New partition handler
+*/
+
+ha_partition::ha_partition(handlerton *hton, TABLE_SHARE *share,
+ partition_info *part_info_arg,
+ ha_partition *clone_arg,
+ MEM_ROOT *clone_mem_root_arg)
+ :handler(hton, share)
+{
+ DBUG_ENTER("ha_partition::ha_partition(clone)");
+ init_handler_variables();
+ m_part_info= part_info_arg;
+ m_create_handler= TRUE;
+ m_is_sub_partitioned= m_part_info->is_sub_partitioned();
+ m_is_clone_of= clone_arg;
+ m_clone_mem_root= clone_mem_root_arg;
+ DBUG_VOID_RETURN;
+}
/*
Initialize handler object
@@ -243,7 +271,6 @@ void ha_partition::init_handler_variables()
m_rec0= 0;
m_curr_key_info[0]= NULL;
m_curr_key_info[1]= NULL;
- is_clone= FALSE,
m_part_func_monotonicity_info= NON_MONOTONIC;
auto_increment_lock= FALSE;
auto_increment_safe_stmt_log_lock= FALSE;
@@ -251,6 +278,11 @@ void ha_partition::init_handler_variables()
this allows blackhole to work properly
*/
m_num_locks= 0;
+ m_part_info= NULL;
+ m_create_handler= FALSE;
+ m_is_sub_partitioned= 0;
+ m_is_clone_of= NULL;
+ m_clone_mem_root= NULL;
#ifdef DONT_HAVE_TO_BE_INITALIZED
m_start_key.flag= 0;
@@ -358,7 +390,8 @@ bool ha_partition::initialize_partition(MEM_ROOT *mem_root)
*/
DBUG_RETURN(0);
}
- else if (get_from_handler_file(table_share->normalized_path.str, mem_root))
+ else if (get_from_handler_file(table_share->normalized_path.str,
+ mem_root, false))
{
my_error(ER_FAILED_READ_FROM_PAR_FILE, MYF(0));
DBUG_RETURN(1);
@@ -1890,7 +1923,7 @@ uint ha_partition::del_ren_cre_table(const char *from,
DBUG_RETURN(TRUE);
}
- if (get_from_handler_file(from, ha_thd()->mem_root))
+ if (get_from_handler_file(from, ha_thd()->mem_root, false))
DBUG_RETURN(TRUE);
DBUG_ASSERT(m_file_buffer);
DBUG_PRINT("enter", ("from: (%s) to: (%s)", from, to ? to : "(nil)"));
@@ -2105,18 +2138,16 @@ static uint name_add(char *dest, const char *first_name, const char *sec_name)
}
-/*
+/**
Create the special .par file
- SYNOPSIS
- create_handler_file()
- name Full path of table name
+ @param name Full path of table name
- RETURN VALUE
- >0 Error code
- 0 Success
+ @return Operation status
+ @retval FALSE Error code
+ @retval TRUE Success
- DESCRIPTION
+ @note
Method used to create handler file with names of partitions, their
engine types and the number of partitions.
*/
@@ -2180,19 +2211,22 @@ bool ha_partition::create_handler_file(const char *name)
Array of engine types n * 4 bytes where
n = (m_tot_parts + 3)/4
Length of name part in bytes 4 bytes
+ (Names in filename format)
Name part m * 4 bytes where
m = ((length_name_part + 3)/4)*4
All padding bytes are zeroed
*/
- tot_partition_words= (tot_parts + 3) / 4;
- tot_name_words= (tot_name_len + 3) / 4;
+ tot_partition_words= (tot_parts + PAR_WORD_SIZE - 1) / PAR_WORD_SIZE;
+ tot_name_words= (tot_name_len + PAR_WORD_SIZE - 1) / PAR_WORD_SIZE;
+ /* 4 static words (tot words, checksum, tot partitions, name length) */
tot_len_words= 4 + tot_partition_words + tot_name_words;
- tot_len_byte= 4 * tot_len_words;
+ tot_len_byte= PAR_WORD_SIZE * tot_len_words;
if (!(file_buffer= (uchar *) my_malloc(tot_len_byte, MYF(MY_ZEROFILL))))
DBUG_RETURN(TRUE);
- engine_array= (file_buffer + 12);
- name_buffer_ptr= (char*) (file_buffer + ((4 + tot_partition_words) * 4));
+ engine_array= (file_buffer + PAR_ENGINES_OFFSET);
+ name_buffer_ptr= (char*) (engine_array + tot_partition_words * PAR_WORD_SIZE
+ + PAR_WORD_SIZE);
part_it.rewind();
for (i= 0; i < num_parts; i++)
{
@@ -2230,13 +2264,15 @@ bool ha_partition::create_handler_file(const char *name)
}
chksum= 0;
int4store(file_buffer, tot_len_words);
- int4store(file_buffer + 8, tot_parts);
- int4store(file_buffer + 12 + (tot_partition_words * 4), tot_name_len);
+ int4store(file_buffer + PAR_NUM_PARTS_OFFSET, tot_parts);
+ int4store(file_buffer + PAR_ENGINES_OFFSET +
+ (tot_partition_words * PAR_WORD_SIZE),
+ tot_name_len);
for (i= 0; i < tot_len_words; i++)
- chksum^= uint4korr(file_buffer + 4 * i);
- int4store(file_buffer + 4, chksum);
+ chksum^= uint4korr(file_buffer + PAR_WORD_SIZE * i);
+ int4store(file_buffer + PAR_CHECKSUM_OFFSET, chksum);
/*
- Remove .frm extension and replace with .par
+ Add .par extension to the file name.
Create and write and close file
to be used at open, delete_table and rename_table
*/
@@ -2255,14 +2291,9 @@ bool ha_partition::create_handler_file(const char *name)
DBUG_RETURN(result);
}
-/*
- Clear handler variables and free some memory
- SYNOPSIS
- clear_handler_file()
-
- RETURN VALUE
- NONE
+/**
+ Clear handler variables and free some memory
*/
void ha_partition::clear_handler_file()
@@ -2275,16 +2306,15 @@ void ha_partition::clear_handler_file()
m_engine_array= NULL;
}
-/*
+
+/**
Create underlying handler objects
- SYNOPSIS
- create_handlers()
- mem_root Allocate memory through this
+ @param mem_root Allocate memory through this
- RETURN VALUE
- TRUE Error
- FALSE Success
+ @return Operation status
+ @retval TRUE Error
+ @retval FALSE Success
*/
bool ha_partition::create_handlers(MEM_ROOT *mem_root)
@@ -2322,6 +2352,7 @@ bool ha_partition::create_handlers(MEM_ROOT *mem_root)
DBUG_RETURN(FALSE);
}
+
/*
Create underlying handler objects from partition info
@@ -2393,101 +2424,165 @@ error_end:
}
-/*
- Get info about partition engines and their names from the .par file
+/**
+ Read the .par file to get the partitions engines and names
- SYNOPSIS
- get_from_handler_file()
- name Full path of table name
- mem_root Allocate memory through this
+ @param name Name of table file (without extention)
- RETURN VALUE
- TRUE Error
- FALSE Success
+ @return Operation status
+ @retval true Failure
+ @retval false Success
- DESCRIPTION
- Open handler file to get partition names, engine types and number of
- partitions.
+ @note On success, m_file_buffer is allocated and must be
+ freed by the caller. m_name_buffer_ptr and m_tot_parts is also set.
*/
-bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root)
+bool ha_partition::read_par_file(const char *name)
{
- char buff[FN_REFLEN], *address_tot_name_len;
+ char buff[FN_REFLEN], *tot_name_len_offset;
File file;
- char *file_buffer, *name_buffer_ptr;
- handlerton **engine_array;
+ char *file_buffer;
uint i, len_bytes, len_words, tot_partition_words, tot_name_words, chksum;
- DBUG_ENTER("ha_partition::get_from_handler_file");
+ DBUG_ENTER("ha_partition::read_par_file");
DBUG_PRINT("enter", ("table name: '%s'", name));
if (m_file_buffer)
- DBUG_RETURN(FALSE);
+ DBUG_RETURN(false);
fn_format(buff, name, "", ha_par_ext, MY_APPEND_EXT);
/* Following could be done with mysql_file_stat to read in whole file */
if ((file= mysql_file_open(key_file_partition,
buff, O_RDONLY | O_SHARE, MYF(0))) < 0)
DBUG_RETURN(TRUE);
- if (mysql_file_read(file, (uchar *) &buff[0], 8, MYF(MY_NABP)))
+ if (mysql_file_read(file, (uchar *) &buff[0], PAR_WORD_SIZE, MYF(MY_NABP)))
goto err1;
len_words= uint4korr(buff);
- len_bytes= 4 * len_words;
+ len_bytes= PAR_WORD_SIZE * len_words;
+ if (mysql_file_seek(file, 0, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR)
+ goto err1;
if (!(file_buffer= (char*) my_malloc(len_bytes, MYF(0))))
goto err1;
- mysql_file_seek(file, 0, MY_SEEK_SET, MYF(0));
if (mysql_file_read(file, (uchar *) file_buffer, len_bytes, MYF(MY_NABP)))
goto err2;
chksum= 0;
for (i= 0; i < len_words; i++)
- chksum ^= uint4korr((file_buffer) + 4 * i);
+ chksum ^= uint4korr((file_buffer) + PAR_WORD_SIZE * i);
if (chksum)
goto err2;
- m_tot_parts= uint4korr((file_buffer) + 8);
+ m_tot_parts= uint4korr((file_buffer) + PAR_NUM_PARTS_OFFSET);
DBUG_PRINT("info", ("No of parts = %u", m_tot_parts));
- tot_partition_words= (m_tot_parts + 3) / 4;
+ tot_partition_words= (m_tot_parts + PAR_WORD_SIZE - 1) / PAR_WORD_SIZE;
+
+ tot_name_len_offset= file_buffer + PAR_ENGINES_OFFSET +
+ PAR_WORD_SIZE * tot_partition_words;
+ tot_name_words= (uint4korr(tot_name_len_offset) + PAR_WORD_SIZE - 1) /
+ PAR_WORD_SIZE;
+ /*
+ Verify the total length = tot size word, checksum word, num parts word +
+ engines array + name length word + name array.
+ */
+ if (len_words != (tot_partition_words + tot_name_words + 4))
+ goto err2;
+ (void) mysql_file_close(file, MYF(0));
+ m_file_buffer= file_buffer; // Will be freed in clear_handler_file()
+ m_name_buffer_ptr= tot_name_len_offset + PAR_WORD_SIZE;
+
+ DBUG_RETURN(false);
+
+err2:
+ my_free(file_buffer);
+err1:
+ (void) mysql_file_close(file, MYF(0));
+ DBUG_RETURN(true);
+}
+
+
+/**
+ Setup m_engine_array
+
+ @param mem_root MEM_ROOT to use for allocating new handlers
+
+ @return Operation status
+ @retval false Success
+ @retval true Failure
+*/
+
+bool ha_partition::setup_engine_array(MEM_ROOT *mem_root)
+{
+ uint i;
+ uchar *buff;
+ handlerton **engine_array;
+
+ DBUG_ASSERT(!m_file);
+ DBUG_ENTER("ha_partition::setup_engine_array");
engine_array= (handlerton **) my_alloca(m_tot_parts * sizeof(handlerton*));
+ if (!engine_array)
+ DBUG_RETURN(true);
+
+ buff= (uchar *) (m_file_buffer + PAR_ENGINES_OFFSET);
for (i= 0; i < m_tot_parts; i++)
{
engine_array[i]= ha_resolve_by_legacy_type(ha_thd(),
(enum legacy_db_type)
- *(uchar *) ((file_buffer) +
- 12 + i));
+ *(buff + i));
if (!engine_array[i])
- goto err3;
+ goto err;
}
- address_tot_name_len= file_buffer + 12 + 4 * tot_partition_words;
- tot_name_words= (uint4korr(address_tot_name_len) + 3) / 4;
- if (len_words != (tot_partition_words + tot_name_words + 4))
- goto err3;
- name_buffer_ptr= file_buffer + 16 + 4 * tot_partition_words;
- (void) mysql_file_close(file, MYF(0));
- m_file_buffer= file_buffer; // Will be freed in clear_handler_file()
- m_name_buffer_ptr= name_buffer_ptr;
-
if (!(m_engine_array= (plugin_ref*)
my_malloc(m_tot_parts * sizeof(plugin_ref), MYF(MY_WME))))
- goto err3;
+ goto err;
for (i= 0; i < m_tot_parts; i++)
m_engine_array[i]= ha_lock_engine(NULL, engine_array[i]);
my_afree((gptr) engine_array);
- if (!m_file && create_handlers(mem_root))
+ if (create_handlers(mem_root))
{
clear_handler_file();
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(true);
}
- DBUG_RETURN(FALSE);
-err3:
+ DBUG_RETURN(false);
+
+err:
my_afree((gptr) engine_array);
-err2:
- my_free(file_buffer);
-err1:
- (void) mysql_file_close(file, MYF(0));
- DBUG_RETURN(TRUE);
+ DBUG_RETURN(true);
+}
+
+
+/**
+ Get info about partition engines and their names from the .par file
+
+ @param name Full path of table name
+ @param mem_root Allocate memory through this
+ @param is_clone If it is a clone, don't create new handlers
+
+ @return Operation status
+ @retval true Error
+ @retval false Success
+
+ @note Open handler file to get partition names, engine types and number of
+ partitions.
+*/
+
+bool ha_partition::get_from_handler_file(const char *name, MEM_ROOT *mem_root,
+ bool is_clone)
+{
+ DBUG_ENTER("ha_partition::get_from_handler_file");
+ DBUG_PRINT("enter", ("table name: '%s'", name));
+
+ if (m_file_buffer)
+ DBUG_RETURN(false);
+
+ if (read_par_file(name))
+ DBUG_RETURN(true);
+
+ if (!is_clone && setup_engine_array(mem_root))
+ DBUG_RETURN(true);
+
+ DBUG_RETURN(false);
}
@@ -2533,13 +2628,13 @@ void ha_data_partition_destroy(HA_DATA_PARTITION* ha_part_data)
int ha_partition::open(const char *name, int mode, uint test_if_locked)
{
- char *name_buffer_ptr= m_name_buffer_ptr;
- int error;
+ char *name_buffer_ptr;
+ int error= HA_ERR_INITIALIZATION;
uint alloc_len;
handler **file;
char name_buff[FN_REFLEN];
bool is_not_tmp_table= (table_share->tmp_table == NO_TMP_TABLE);
- ulonglong check_table_flags= 0;
+ ulonglong check_table_flags;
DBUG_ENTER("ha_partition::open");
DBUG_ASSERT(table->s == table_share);
@@ -2547,8 +2642,9 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
m_mode= mode;
m_open_test_lock= test_if_locked;
m_part_field_array= m_part_info->full_part_field_array;
- if (get_from_handler_file(name, &table->mem_root))
- DBUG_RETURN(1);
+ if (get_from_handler_file(name, &table->mem_root, test(m_is_clone_of)))
+ DBUG_RETURN(error);
+ name_buffer_ptr= m_name_buffer_ptr;
m_start_key.length= 0;
m_rec0= table->record[0];
m_rec_length= table_share->reclength;
@@ -2558,7 +2654,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
{
if (!(m_ordered_rec_buffer= (uchar*)my_malloc(alloc_len, MYF(MY_WME))))
{
- DBUG_RETURN(1);
+ DBUG_RETURN(error);
}
{
/*
@@ -2581,48 +2677,84 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
/* Initialize the bitmap we use to minimize ha_start_bulk_insert calls */
if (bitmap_init(&m_bulk_insert_started, NULL, m_tot_parts + 1, FALSE))
- DBUG_RETURN(1);
+ DBUG_RETURN(error);
bitmap_clear_all(&m_bulk_insert_started);
/* Initialize the bitmap we use to determine what partitions are used */
- if (!is_clone)
+ if (!m_is_clone_of)
{
+ DBUG_ASSERT(!m_clone_mem_root);
if (bitmap_init(&(m_part_info->used_partitions), NULL, m_tot_parts, TRUE))
{
bitmap_free(&m_bulk_insert_started);
- DBUG_RETURN(1);
+ DBUG_RETURN(error);
}
bitmap_set_all(&(m_part_info->used_partitions));
}
+ if (m_is_clone_of)
+ {
+ uint i;
+ DBUG_ASSERT(m_clone_mem_root);
+ /* Allocate an array of handler pointers for the partitions handlers. */
+ alloc_len= (m_tot_parts + 1) * sizeof(handler*);
+ if (!(m_file= (handler **) alloc_root(m_clone_mem_root, alloc_len)))
+ goto err_alloc;
+ memset(m_file, 0, alloc_len);
+ /*
+ Populate them by cloning the original partitions. This also opens them.
+ Note that file->ref is allocated too.
+ */
+ file= m_is_clone_of->m_file;
+ for (i= 0; i < m_tot_parts; i++)
+ {
+ create_partition_name(name_buff, name, name_buffer_ptr, NORMAL_PART_NAME,
+ FALSE);
+ if (!(m_file[i]= file[i]->clone(name_buff, m_clone_mem_root)))
+ {
+ error= HA_ERR_INITIALIZATION;
+ file= &m_file[i];
+ goto err_handler;
+ }
+ name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
+ }
+ }
+ else
+ {
+ file= m_file;
+ do
+ {
+ create_partition_name(name_buff, name, name_buffer_ptr, NORMAL_PART_NAME,
+ FALSE);
+ if ((error= (*file)->ha_open(table, name_buff, mode, test_if_locked)))
+ goto err_handler;
+ m_num_locks+= (*file)->lock_count();
+ name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
+ } while (*(++file));
+ }
+
file= m_file;
- do
+ ref_length= (*file)->ref_length;
+ check_table_flags= (((*file)->ha_table_flags() &
+ ~(PARTITION_DISABLED_TABLE_FLAGS)) |
+ (PARTITION_ENABLED_TABLE_FLAGS));
+ while (*(++file))
{
- create_partition_name(name_buff, name, name_buffer_ptr, NORMAL_PART_NAME,
- FALSE);
- if ((error= (*file)->ha_open(table, (const char*) name_buff, mode,
- test_if_locked)))
- goto err_handler;
- m_num_locks+= (*file)->lock_count();
- name_buffer_ptr+= strlen(name_buffer_ptr) + 1;
+ /* MyISAM can have smaller ref_length for partitions with MAX_ROWS set */
set_if_bigger(ref_length, ((*file)->ref_length));
/*
Verify that all partitions have the same set of table flags.
Mask all flags that partitioning enables/disables.
*/
- if (!check_table_flags)
- {
- check_table_flags= (((*file)->ha_table_flags() &
- ~(PARTITION_DISABLED_TABLE_FLAGS)) |
- (PARTITION_ENABLED_TABLE_FLAGS));
- }
- else if (check_table_flags != (((*file)->ha_table_flags() &
- ~(PARTITION_DISABLED_TABLE_FLAGS)) |
- (PARTITION_ENABLED_TABLE_FLAGS)))
+ if (check_table_flags != (((*file)->ha_table_flags() &
+ ~(PARTITION_DISABLED_TABLE_FLAGS)) |
+ (PARTITION_ENABLED_TABLE_FLAGS)))
{
error= HA_ERR_INITIALIZATION;
+ /* set file to last handler, so all of them is closed */
+ file = &m_file[m_tot_parts - 1];
goto err_handler;
}
- } while (*(++file));
+ }
key_used_on_scan= m_file[0]->key_used_on_scan;
implicit_emptied= m_file[0]->implicit_emptied;
/*
@@ -2631,6 +2763,7 @@ int ha_partition::open(const char *name, int mode, uint test_if_locked)
*/
ref_length+= PARTITION_BYTES_IN_POS;
m_ref_length= ref_length;
+
/*
Release buffer read from .par file. It will not be reused again after
being opened once.
@@ -2690,25 +2823,54 @@ err_handler:
DEBUG_SYNC(ha_thd(), "partition_open_error");
while (file-- != m_file)
(*file)->close();
+err_alloc:
bitmap_free(&m_bulk_insert_started);
- if (!is_clone)
+ if (!m_is_clone_of)
bitmap_free(&(m_part_info->used_partitions));
DBUG_RETURN(error);
}
-handler *ha_partition::clone(MEM_ROOT *mem_root)
+
+/**
+ Clone the open and locked partitioning handler.
+
+ @param mem_root MEM_ROOT to use.
+
+ @return Pointer to the successfully created clone or NULL
+
+ @details
+ This function creates a new ha_partition handler as a clone/copy. The
+ original (this) must already be opened and locked. The clone will use
+ the originals m_part_info.
+ It also allocates memory for ref + ref_dup.
+ In ha_partition::open() it will clone its original handlers partitions
+ which will allocate then on the correct MEM_ROOT and also open them.
+*/
+
+handler *ha_partition::clone(const char *name, MEM_ROOT *mem_root)
{
- handler *new_handler= get_new_handler(table->s, mem_root,
- table->s->db_type());
- ((ha_partition*)new_handler)->m_part_info= m_part_info;
- ((ha_partition*)new_handler)->is_clone= TRUE;
- if (new_handler && !new_handler->ha_open(table,
- table->s->normalized_path.str,
- table->db_stat,
- HA_OPEN_IGNORE_IF_LOCKED))
- return new_handler;
- return NULL;
+ ha_partition *new_handler;
+
+ DBUG_ENTER("ha_partition::clone");
+ new_handler= new (mem_root) ha_partition(ht, table_share, m_part_info,
+ this, mem_root);
+ /*
+ Allocate new_handler->ref here because otherwise ha_open will allocate it
+ on this->table->mem_root and we will not be able to reclaim that memory
+ when the clone handler object is destroyed.
+ */
+ if (new_handler &&
+ !(new_handler->ref= (uchar*) alloc_root(mem_root,
+ ALIGN_SIZE(m_ref_length)*2)))
+ new_handler= NULL;
+
+ if (new_handler &&
+ new_handler->ha_open(table, name,
+ table->db_stat, HA_OPEN_IGNORE_IF_LOCKED))
+ new_handler= NULL;
+
+ DBUG_RETURN((handler*) new_handler);
}
@@ -2739,7 +2901,7 @@ int ha_partition::close(void)
DBUG_ASSERT(table->s == table_share);
delete_queue(&m_queue);
bitmap_free(&m_bulk_insert_started);
- if (!is_clone)
+ if (!m_is_clone_of)
bitmap_free(&(m_part_info->used_partitions));
file= m_file;
@@ -3927,19 +4089,16 @@ end_dont_reset_start_part:
void ha_partition::position(const uchar *record)
{
handler *file= m_file[m_last_part];
+ uint pad_length;
DBUG_ENTER("ha_partition::position");
file->position(record);
int2store(ref, m_last_part);
- memcpy((ref + PARTITION_BYTES_IN_POS), file->ref,
- (ref_length - PARTITION_BYTES_IN_POS));
-
-#ifdef SUPPORTING_PARTITION_OVER_DIFFERENT_ENGINES
-#ifdef HAVE_purify
- bzero(ref + PARTITION_BYTES_IN_POS + ref_length,
- max_ref_length-ref_length);
-#endif /* HAVE_purify */
-#endif
+ memcpy((ref + PARTITION_BYTES_IN_POS), file->ref, file->ref_length);
+ pad_length= m_ref_length - PARTITION_BYTES_IN_POS - file->ref_length;
+ if (pad_length)
+ memset((ref + PARTITION_BYTES_IN_POS + file->ref_length), 0, pad_length);
+
DBUG_VOID_RETURN;
}
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 57456ddf8ae..b0b11da823f 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -37,6 +37,16 @@ enum partition_keywords
HA_DUPLICATE_POS | \
HA_CAN_SQL_HANDLER | \
HA_CAN_INSERT_DELAYED)
+
+/* First 4 bytes in the .par file is the number of 32-bit words in the file */
+#define PAR_WORD_SIZE 4
+/* offset to the .par file checksum */
+#define PAR_CHECKSUM_OFFSET 4
+/* offset to the total number of partitions */
+#define PAR_NUM_PARTS_OFFSET 8
+/* offset to the engines array */
+#define PAR_ENGINES_OFFSET 12
+
class ha_partition :public handler
{
private:
@@ -53,7 +63,7 @@ private:
/* Data for the partition handler */
int m_mode; // Open mode
uint m_open_test_lock; // Open test_if_locked
- char *m_file_buffer; // Buffer with names
+ char *m_file_buffer; // Content of the .par file
char *m_name_buffer_ptr; // Pointer to first partition name
plugin_ref *m_engine_array; // Array of types of the handlers
handler **m_file; // Array of references to handler inst.
@@ -115,6 +125,13 @@ private:
bool m_is_sub_partitioned; // Is subpartitioned
bool m_ordered_scan_ongoing;
+ /*
+ If set, this object was created with ha_partition::clone and doesn't
+ "own" the m_part_info structure.
+ */
+ ha_partition *m_is_clone_of;
+ MEM_ROOT *m_clone_mem_root;
+
/*
We keep track if all underlying handlers are MyISAM since MyISAM has a
great number of extra flags not needed by other handlers.
@@ -148,11 +165,6 @@ private:
*/
THR_LOCK_DATA lock; /* MySQL lock */
- /*
- TRUE <=> this object was created with ha_partition::clone and doesn't
- "own" the m_part_info structure.
- */
- bool is_clone;
bool auto_increment_lock; /**< lock reading/updating auto_inc */
/**
Flag to keep the auto_increment lock through out the statement.
@@ -165,7 +177,7 @@ private:
/** used for prediction of start_bulk_insert rows */
enum_monotonicity_info m_part_func_monotonicity_info;
public:
- handler *clone(MEM_ROOT *mem_root);
+ handler *clone(const char *name, MEM_ROOT *mem_root);
virtual void set_part_info(partition_info *part_info)
{
m_part_info= part_info;
@@ -184,6 +196,10 @@ public:
*/
ha_partition(handlerton *hton, TABLE_SHARE * table);
ha_partition(handlerton *hton, partition_info * part_info);
+ ha_partition(handlerton *hton, TABLE_SHARE *share,
+ partition_info *part_info_arg,
+ ha_partition *clone_arg,
+ MEM_ROOT *clone_mem_root_arg);
~ha_partition();
/*
A partition handler has no characteristics in itself. It only inherits
@@ -254,7 +270,10 @@ private:
And one method to read it in.
*/
bool create_handler_file(const char *name);
- bool get_from_handler_file(const char *name, MEM_ROOT *mem_root);
+ bool setup_engine_array(MEM_ROOT *mem_root);
+ bool read_par_file(const char *name);
+ bool get_from_handler_file(const char *name, MEM_ROOT *mem_root,
+ bool is_clone);
bool new_handlers_from_part_info(MEM_ROOT *mem_root);
bool create_handlers(MEM_ROOT *mem_root);
void clear_handler_file();
diff --git a/sql/handler.cc b/sql/handler.cc
index fefc0553c88..445e1ec5a3c 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -2076,22 +2076,29 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path,
/****************************************************************************
** General handler functions
****************************************************************************/
-handler *handler::clone(MEM_ROOT *mem_root)
+handler *handler::clone(const char *name, MEM_ROOT *mem_root)
{
- handler *new_handler= get_new_handler(table->s, mem_root, table->s->db_type());
+ handler *new_handler= get_new_handler(table->s, mem_root, ht);
/*
Allocate handler->ref here because otherwise ha_open will allocate it
on this->table->mem_root and we will not be able to reclaim that memory
when the clone handler object is destroyed.
*/
- if (!(new_handler->ref= (uchar*) alloc_root(mem_root, ALIGN_SIZE(ref_length)*2)))
- return NULL;
- if (new_handler && !new_handler->ha_open(table,
- table->s->normalized_path.str,
- table->db_stat,
- HA_OPEN_IGNORE_IF_LOCKED))
- return new_handler;
- return NULL;
+ if (new_handler &&
+ !(new_handler->ref= (uchar*) alloc_root(mem_root,
+ ALIGN_SIZE(ref_length)*2)))
+ new_handler= NULL;
+ /*
+ TODO: Implement a more efficient way to have more than one index open for
+ the same table instance. The ha_open call is not cachable for clone.
+ */
+ if (new_handler && new_handler->ha_open(table,
+ name,
+ table->db_stat,
+ HA_OPEN_IGNORE_IF_LOCKED))
+ new_handler= NULL;
+
+ return new_handler;
}
diff --git a/sql/handler.h b/sql/handler.h
index 911f7516e98..fbc52170297 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -3,18 +3,20 @@
/* Copyright (c) 2000, 2011, 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 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
+ 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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ 02110-1301 USA */
/* Definitions for parameters to do with handler-routines */
@@ -60,7 +62,7 @@
a table with rnd_next()
- We will see all rows (including deleted ones)
- Row positions are 'table->s->db_record_offset' apart
- If this flag is not set, filesort will do a postion() call for each matched
+ If this flag is not set, filesort will do a position() call for each matched
row to be able to find the row later.
*/
#define HA_REC_NOT_IN_SEQ (1 << 3)
@@ -1262,7 +1264,7 @@ public:
DBUG_ASSERT(locked == FALSE);
DBUG_ASSERT(inited == NONE);
}
- virtual handler *clone(MEM_ROOT *mem_root);
+ virtual handler *clone(const char *name, MEM_ROOT *mem_root);
/** This is called after create to allow us to set up cached variables */
void init()
{
diff --git a/sql/item.cc b/sql/item.cc
index 639a3a81b78..0aac941740f 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -581,7 +581,7 @@ void Item::rename(char *new_name)
Item* Item::transform(Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
return (this->*transformer)(arg);
}
@@ -1781,14 +1781,17 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
}
THD *thd= current_thd;
- Query_arena *arena, backup;
bool res= FALSE;
uint i;
+
/*
In case we're in statement prepare, create conversion item
in its memory: it will be reused on each execute.
*/
- arena= thd->activate_stmt_arena_if_needed(&backup);
+ Query_arena backup;
+ Query_arena *arena= thd->stmt_arena->is_stmt_prepare() ?
+ thd->activate_stmt_arena_if_needed(&backup) :
+ NULL;
for (i= 0, arg= args; i < nargs; i++, arg+= item_sep)
{
@@ -1845,7 +1848,7 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
been created in prepare. In this case register the change for
rollback.
*/
- if (thd->is_stmt_prepare())
+ if (thd->stmt_arena->is_stmt_prepare())
*arg= conv;
else
thd->change_item_tree(arg, conv);
@@ -6965,7 +6968,7 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
Item *Item_default_value::transform(Item_transformer transformer, uchar *args)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
/*
If the value of arg is NULL, then this object represents a constant,
@@ -7131,8 +7134,26 @@ bool Item_trigger_field::set_value(THD *thd, sp_rcontext * /*ctx*/, Item **it)
{
Item *item= sp_prepare_func_item(thd, it);
- return (!item || (!fixed && fix_fields(thd, 0)) ||
- (item->save_in_field(field, 0) < 0));
+ if (!item)
+ return true;
+
+ if (!fixed)
+ {
+ if (fix_fields(thd, NULL))
+ return true;
+ }
+
+ // NOTE: field->table->copy_blobs should be false here, but let's
+ // remember the value at runtime to avoid subtle bugs.
+ bool copy_blobs_saved= field->table->copy_blobs;
+
+ field->table->copy_blobs= true;
+
+ int err_code= item->save_in_field(field, 0);
+
+ field->table->copy_blobs= copy_blobs_saved;
+
+ return err_code < 0;
}
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 68c63285693..e0057d1550b 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -4069,13 +4069,11 @@ void Item_func_in::fix_length_and_dec()
uint j=0;
for (uint i=1 ; i < arg_count ; i++)
{
- if (!args[i]->null_value) // Skip NULL values
- {
- array->set(j,args[i]);
- j++;
- }
- else
- have_null= 1;
+ array->set(j,args[i]);
+ if (!args[i]->null_value) // Skip NULL values
+ j++;
+ else
+ have_null= 1;
}
if ((array->used_count= j))
array->sort();
@@ -4347,7 +4345,7 @@ bool Item_cond::walk(Item_processor processor, bool walk_subquery, uchar *arg)
Item *Item_cond::transform(Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
List_iterator<Item> li(list);
Item *item;
@@ -5720,7 +5718,7 @@ bool Item_equal::walk(Item_processor processor, bool walk_subquery, uchar *arg)
Item *Item_equal::transform(Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
List_iterator<Item_field> it(fields);
Item *item;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 82310365d27..24d0d94c6c5 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -293,7 +293,7 @@ void Item_func::traverse_cond(Cond_traverser traverser,
Item *Item_func::transform(Item_transformer transformer, uchar *argument)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
if (arg_count)
{
@@ -2407,10 +2407,7 @@ my_decimal *Item_func_round::decimal_op(my_decimal *decimal_value)
if (!(null_value= (args[0]->null_value || args[1]->null_value ||
my_decimal_round(E_DEC_FATAL_ERROR, value, (int) dec,
truncate, decimal_value) > 1)))
- {
- decimal_value->frac= decimals;
return decimal_value;
- }
return 0;
}
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 94515640625..0f5d6f27823 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -170,7 +170,7 @@ bool Item_row::walk(Item_processor processor, bool walk_subquery, uchar *arg)
Item *Item_row::transform(Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
for (uint i= 0; i < arg_count; i++)
{
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index e5c47c110f4..e1a4fcc8def 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -2536,7 +2536,7 @@ String *Item_func_make_set::val_str(String *str)
Item *Item_func_make_set::transform(Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
Item *new_item= item->transform(transformer, arg);
if (!new_item)
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 42088616f4a..b0ab436ea4a 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -1145,17 +1145,13 @@ Item_sum_hybrid::fix_fields(THD *thd, Item **ref)
switch (hybrid_type= item->result_type()) {
case INT_RESULT:
- max_length= 20;
- break;
case DECIMAL_RESULT:
+ case STRING_RESULT:
max_length= item->max_length;
break;
case REAL_RESULT:
max_length= float_length(decimals);
break;
- case STRING_RESULT:
- max_length= item->max_length;
- break;
case ROW_RESULT:
default:
DBUG_ASSERT(0);
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 36b85f2411f..5f30787f015 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -669,7 +669,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
system_charset_info);
break;
case 'W':
- if (type == MYSQL_TIMESTAMP_TIME)
+ if (type == MYSQL_TIMESTAMP_TIME || !(l_time->month || l_time->year))
return 1;
weekday= calc_weekday(calc_daynr(l_time->year,l_time->month,
l_time->day),0);
@@ -678,7 +678,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
system_charset_info);
break;
case 'a':
- if (type == MYSQL_TIMESTAMP_TIME)
+ if (type == MYSQL_TIMESTAMP_TIME || !(l_time->month || l_time->year))
return 1;
weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
l_time->day),0);
@@ -837,7 +837,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
}
break;
case 'w':
- if (type == MYSQL_TIMESTAMP_TIME)
+ if (type == MYSQL_TIMESTAMP_TIME || !(l_time->month || l_time->year))
return 1;
weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
l_time->day),1);
diff --git a/sql/mdl.h b/sql/mdl.h
index 4a9397fe215..e0934cb732b 100644
--- a/sql/mdl.h
+++ b/sql/mdl.h
@@ -286,21 +286,6 @@ private:
};
-
-/**
- Hook class which via its methods specifies which members
- of T should be used for participating in MDL lists.
-*/
-
-template <typename T, T* T::*next, T** T::*prev>
-struct I_P_List_adapter
-{
- static inline T **next_ptr(T *el) { return &(el->*next); }
-
- static inline T ***prev_ptr(T *el) { return &(el->*prev); }
-};
-
-
/**
A pending metadata lock request.
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index a31896bd022..b349c5f91b1 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -245,11 +245,7 @@ inline void setup_fpu()
#define MYSQL_KILL_SIGNAL SIGTERM
-#ifdef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R
-#include <sys/types.h>
-#else
#include <my_pthread.h> // For thr_setconcurency()
-#endif
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 13ca52596ce..303ee5bec0f 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -73,7 +73,7 @@ void flush_thread_cache();
void refresh_status(THD *thd);
bool is_secure_file_path(char *path);
-extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info;
+extern "C" MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info;
extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *files_charset_info ;
extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *national_charset_info;
extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *table_alias_charset;
@@ -182,7 +182,8 @@ extern ulong opt_binlog_rows_event_max_size;
extern ulong rpl_recovery_rank, thread_cache_size;
extern ulong back_log;
extern char language[FN_REFLEN];
-extern ulong server_id, concurrency;
+extern "C" MYSQL_PLUGIN_IMPORT ulong server_id;
+extern ulong concurrency;
extern time_t server_start_time, flush_status_time;
extern char *opt_mysql_tmpdir, mysql_charsets_dir[];
extern int mysql_unpacked_real_data_home_len;
@@ -203,8 +204,8 @@ extern handlerton *heap_hton;
extern const char *load_default_groups[];
extern struct my_option my_long_options[];
extern int mysqld_server_started;
-extern int orig_argc;
-extern char **orig_argv;
+extern "C" MYSQL_PLUGIN_IMPORT int orig_argc;
+extern "C" MYSQL_PLUGIN_IMPORT char **orig_argv;
extern pthread_attr_t connection_attrib;
extern MYSQL_FILE *bootstrap_file;
extern my_bool old_mode;
@@ -310,7 +311,7 @@ extern uint mysql_real_data_home_len;
extern const char *mysql_real_data_home_ptr;
extern ulong thread_handling;
extern MYSQL_PLUGIN_IMPORT char *mysql_data_home;
-extern char server_version[SERVER_VERSION_LENGTH];
+extern "C" MYSQL_PLUGIN_IMPORT char server_version[SERVER_VERSION_LENGTH];
extern MYSQL_PLUGIN_IMPORT char mysql_real_data_home[];
extern char mysql_unpacked_real_data_home[];
extern MYSQL_PLUGIN_IMPORT struct system_variables global_system_variables;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 4cdabab31ae..6e106010968 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -1368,7 +1368,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler)
}
thd= head->in_use;
- if (!(file= head->file->clone(thd->mem_root)))
+ if (!(file= head->file->clone(head->s->normalized_path.str, thd->mem_root)))
{
/*
Manually set the error flag. Note: there seems to be quite a few
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index a2f8b9c4447..6b8cdfaca60 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -212,6 +212,7 @@ static int get_index_max_value(TABLE *table, TABLE_REF *ref, uint range_fl)
/**
Substitutes constants for some COUNT(), MIN() and MAX() functions.
+ @param thd thread handler
@param tables list of leaves of join table tree
@param all_fields All fields to be returned
@param conds WHERE clause
@@ -229,9 +230,12 @@ static int get_index_max_value(TABLE *table, TABLE_REF *ref, uint range_fl)
HA_ERR_KEY_NOT_FOUND on impossible conditions
@retval
HA_ERR_... if a deadlock or a lock wait timeout happens, for example
+ @retval
+ ER_... e.g. ER_SUBQUERY_NO_1_ROW
*/
-int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
+int opt_sum_query(THD *thd,
+ TABLE_LIST *tables, List<Item> &all_fields, COND *conds)
{
List_iterator_fast<Item> it(all_fields);
int const_result= 1;
@@ -243,6 +247,8 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
Item *item;
int error;
+ DBUG_ENTER("opt_sum_query");
+
if (conds)
where_tables= conds->used_tables();
@@ -270,7 +276,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
WHERE t2.field IS NULL;
*/
if (tl->table->map & where_tables)
- return 0;
+ DBUG_RETURN(0);
}
else
used_tables|= tl->table->map;
@@ -297,7 +303,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
if(error)
{
tl->table->file->print_error(error, MYF(ME_FATALERROR));
- return error;
+ DBUG_RETURN(error);
}
count*= tl->table->file->stats.records;
}
@@ -390,10 +396,10 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
if (error)
{
if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE)
- return HA_ERR_KEY_NOT_FOUND; // No rows matching WHERE
+ DBUG_RETURN(HA_ERR_KEY_NOT_FOUND); // No rows matching WHERE
/* HA_ERR_LOCK_DEADLOCK or some other error */
table->file->print_error(error, MYF(0));
- return(error);
+ DBUG_RETURN(error);
}
removed_tables|= table->map;
}
@@ -442,6 +448,10 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
const_result= 0;
}
}
+
+ if (thd->is_error())
+ DBUG_RETURN(thd->stmt_da->sql_errno());
+
/*
If we have a where clause, we can only ignore searching in the
tables if MIN/MAX optimisation replaced all used tables
@@ -451,7 +461,7 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
*/
if (removed_tables && used_tables != removed_tables)
const_result= 0; // We didn't remove all tables
- return const_result;
+ DBUG_RETURN(const_result);
}
@@ -737,6 +747,12 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
if (is_null || (is_null_safe_eq && args[1]->is_null()))
{
+ /*
+ If we have a non-nullable index, we cannot use it,
+ since set_null will be ignored, and we will compare uninitialized data.
+ */
+ if (!part->field->real_maybe_null())
+ DBUG_RETURN(false);
part->field->set_null();
*key_ptr= (uchar) 1;
}
@@ -807,8 +823,9 @@ static bool matching_cond(bool max_fl, TABLE_REF *ref, KEY *keyinfo,
@param[out] prefix_len Length of prefix for the search range
@note
- This function may set table->key_read to 1, which must be reset after
- index is used! (This can only happen when function returns 1)
+ This function may set field->table->key_read to true,
+ which must be reset after index is used!
+ (This can only happen when function returns 1)
@retval
0 Index can not be used to optimize MIN(field)/MAX(field)
@@ -823,7 +840,9 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
uint *range_fl, uint *prefix_len)
{
if (!(field->flags & PART_KEY_FLAG))
- return 0; // Not key field
+ return false; // Not key field
+
+ DBUG_ENTER("find_key_for_maxmin");
TABLE *table= field->table;
uint idx= 0;
@@ -848,7 +867,7 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
part++, jdx++, key_part_to_use= (key_part_to_use << 1) | 1)
{
if (!(table->file->index_flags(idx, jdx, 0) & HA_READ_ORDER))
- return 0;
+ DBUG_RETURN(false);
/* Check whether the index component is partial */
Field *part_field= table->field[part->fieldnr-1];
@@ -897,12 +916,12 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref,
*/
if (field->part_of_key.is_set(idx))
table->set_keyread(TRUE);
- return 1;
+ DBUG_RETURN(true);
}
}
}
}
- return 0;
+ DBUG_RETURN(false);
}
diff --git a/sql/rpl_handler.h b/sql/rpl_handler.h
index bf207e53e2d..9a181250efc 100644
--- a/sql/rpl_handler.h
+++ b/sql/rpl_handler.h
@@ -73,7 +73,10 @@ public:
while (info && info->observer != observer)
info= iter++;
if (info)
+ {
iter.remove();
+ delete info;
+ }
else
ret= TRUE;
unlock();
diff --git a/sql/slave.cc b/sql/slave.cc
index c676c89b369..223ea21851a 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -113,7 +113,7 @@ static const char *reconnect_messages[SLAVE_RECON_ACT_MAX][SLAVE_RECON_MSG_MAX]=
registration on master",
"Reconnecting after a failed registration on master",
"failed registering on master, reconnecting to try again, \
-log '%s' at postion %s",
+log '%s' at position %s",
"COM_REGISTER_SLAVE",
"Slave I/O thread killed during or after reconnect"
},
@@ -121,7 +121,7 @@ log '%s' at postion %s",
"Waiting to reconnect after a failed binlog dump request",
"Slave I/O thread killed while retrying master dump",
"Reconnecting after a failed binlog dump request",
- "failed dump request, reconnecting to try again, log '%s' at postion %s",
+ "failed dump request, reconnecting to try again, log '%s' at position %s",
"COM_BINLOG_DUMP",
"Slave I/O thread killed during or after reconnect"
},
@@ -130,7 +130,7 @@ log '%s' at postion %s",
"Slave I/O thread killed while waiting to reconnect after a failed read",
"Reconnecting after a failed master event read",
"Slave I/O thread: Failed reading log event, reconnecting to retry, \
-log '%s' at postion %s",
+log '%s' at position %s",
"",
"Slave I/O thread killed during or after a reconnect done to recover from \
failed read"
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index f568a2d3e68..c8368be953b 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -1,4 +1,4 @@
-/* Copyright 2002-2008 MySQL AB, 2008-2010 Sun Microsystems, Inc.
+/* Copyright (c) 2002, 2011, 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
@@ -11,7 +11,7 @@
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 */
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
#include "sql_priv.h"
@@ -1217,7 +1217,8 @@ sp_head::execute(THD *thd, bool merge_da_on_success)
String old_packet;
Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer;
Object_creation_ctx *saved_creation_ctx;
- Warning_info *saved_warning_info, warning_info(thd->warning_info->warn_id());
+ Warning_info *saved_warning_info;
+ Warning_info warning_info(thd->warning_info->warn_id(), false);
/*
Just reporting a stack overrun error
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index dea8d38938c..575991211e6 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -263,7 +263,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
const char *operator_name,
thr_lock_type lock_type,
bool open_for_modify,
- bool no_warnings_for_error,
+ bool repair_table_use_frm,
uint extra_open_options,
int (*prepare_func)(THD *, TABLE_LIST *,
HA_CHECK_OPT *),
@@ -331,18 +331,43 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
lex->query_tables= table;
lex->query_tables_last= &table->next_global;
lex->query_tables_own_last= 0;
- /*
- Under locked tables, we know that the table can be opened,
- so any errors opening the table are logical errors.
- In these cases it makes sense to report them.
- */
- if (!thd->locked_tables_mode)
- thd->no_warnings_for_error= no_warnings_for_error;
+
if (view_operator_func == NULL)
table->required_type=FRMTYPE_TABLE;
- open_error= open_and_lock_tables(thd, table, TRUE, 0);
- thd->no_warnings_for_error= 0;
+ if (!thd->locked_tables_mode && repair_table_use_frm)
+ {
+ /*
+ If we're not under LOCK TABLES and we're executing REPAIR TABLE
+ USE_FRM, we need to ignore errors from open_and_lock_tables().
+ REPAIR TABLE USE_FRM is a heavy weapon used when a table is
+ critically damaged, so open_and_lock_tables() will most likely
+ report errors. Those errors are not interesting for the user
+ because it's already known that the table is badly damaged.
+ */
+
+ Warning_info wi(thd->query_id, false);
+ Warning_info *wi_saved= thd->warning_info;
+
+ thd->warning_info= &wi;
+
+ open_error= open_and_lock_tables(thd, table, TRUE, 0);
+
+ thd->warning_info= wi_saved;
+ }
+ else
+ {
+ /*
+ It's assumed that even if it is REPAIR TABLE USE_FRM, the table
+ can be opened if we're under LOCK TABLES (otherwise LOCK TABLES
+ would fail). Thus, the only errors we could have from
+ open_and_lock_tables() are logical ones, like incorrect locking
+ mode. It does make sense for the user to see such errors.
+ */
+
+ open_error= open_and_lock_tables(thd, table, TRUE, 0);
+ }
+
table->next_global= save_next_global;
table->next_local= save_next_local;
thd->open_options&= ~extra_open_options;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index f37f800d091..f9d85b1e024 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -4724,6 +4724,14 @@ bool open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags,
bool has_prelocking_list;
DBUG_ENTER("open_tables");
+ /* Accessing data in XA_IDLE or XA_PREPARED is not allowed. */
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ if (*start && (xa_state == XA_IDLE || xa_state == XA_PREPARED))
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ DBUG_RETURN(true);
+ }
+
/*
temporary mem_root for new .frm parsing.
TODO: variables for size
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index bc6086eaf19..4af038bb4e0 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+/* Copyright (c) 2000, 2011, 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
@@ -11,8 +11,7 @@
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 */
-
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*****************************************************************************
**
@@ -522,7 +521,7 @@ THD::THD()
#if defined(ENABLED_DEBUG_SYNC)
debug_sync_control(0),
#endif /* defined(ENABLED_DEBUG_SYNC) */
- main_warning_info(0)
+ main_warning_info(0, false)
{
ulong tmp;
@@ -581,7 +580,7 @@ THD::THD()
client_capabilities= 0; // minimalistic client
ull=0;
system_thread= NON_SYSTEM_THREAD;
- cleanup_done= abort_on_warning= no_warnings_for_error= 0;
+ cleanup_done= abort_on_warning= 0;
peer_port= 0; // For SHOW PROCESSLIST
transaction.m_pending_rows_event= 0;
transaction.on= 1;
@@ -854,10 +853,6 @@ MYSQL_ERROR* THD::raise_condition(uint sql_errno,
query_cache_abort(&query_cache_tls);
- /* FIXME: broken special case */
- if (no_warnings_for_error && (level == MYSQL_ERROR::WARN_LEVEL_ERROR))
- DBUG_RETURN(NULL);
-
/* When simulating OOM, skip writing to error log to avoid mtr errors */
DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_RETURN(NULL););
@@ -3675,6 +3670,7 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state)
xs->xa_state=xa_state;
xs->xid.set(xid);
xs->in_thd=0;
+ xs->rm_error=0;
res=my_hash_insert(&xid_cache, (uchar*)xs);
}
mysql_mutex_unlock(&LOCK_xid_cache);
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 137a0c48ead..56d85e7cb6d 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, 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
@@ -655,15 +655,10 @@ public:
virtual ~Query_arena() {};
inline bool is_stmt_prepare() const { return state == INITIALIZED; }
- inline bool is_first_sp_execute() const
- { return state == INITIALIZED_FOR_SP; }
inline bool is_stmt_prepare_or_first_sp_execute() const
{ return (int)state < (int)PREPARED; }
inline bool is_stmt_prepare_or_first_stmt_execute() const
{ return (int)state <= (int)PREPARED; }
- inline bool is_first_stmt_execute() const { return state == PREPARED; }
- inline bool is_stmt_execute() const
- { return state == PREPARED || state == EXECUTED; }
inline bool is_conventional() const
{ return state == CONVENTIONAL_EXECUTION; }
@@ -1434,6 +1429,19 @@ extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
class THD :public Statement,
public Open_tables_state
{
+private:
+ inline bool is_stmt_prepare() const
+ { DBUG_ASSERT(0); return Statement::is_stmt_prepare(); }
+
+ inline bool is_stmt_prepare_or_first_sp_execute() const
+ { DBUG_ASSERT(0); return Statement::is_stmt_prepare_or_first_sp_execute(); }
+
+ inline bool is_stmt_prepare_or_first_stmt_execute() const
+ { DBUG_ASSERT(0); return Statement::is_stmt_prepare_or_first_stmt_execute(); }
+
+ inline bool is_conventional() const
+ { DBUG_ASSERT(0); return Statement::is_conventional(); }
+
public:
MDL_context mdl_context;
@@ -2089,7 +2097,6 @@ public:
bool enable_slow_log; /* enable slow log for current statement */
bool abort_on_warning;
bool got_warning; /* Set on call to push_warning() */
- bool no_warnings_for_error; /* no warnings on call to my_error() */
/* set during loop of derived table processing */
bool derived_tables_processing;
my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */
@@ -2807,6 +2814,7 @@ private:
/** The current internal error handler for this thread, or NULL. */
Internal_error_handler *m_internal_handler;
+
/**
The lex to hold the parsed tree of conventional (non-prepared) queries.
Whereas for prepared and stored procedure statements we use an own lex
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index d0982b879e7..24516f03bee 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -1,5 +1,4 @@
-/* Copyright (C) 1995-2002 MySQL AB,
- Copyright (C) 2008-2009 Sun Microsystems, Inc
+/* Copyright (c) 1995, 2011, 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
@@ -458,10 +457,11 @@ Diagnostics_area::disable_status()
m_status= DA_DISABLED;
}
-Warning_info::Warning_info(ulonglong warn_id_arg)
+Warning_info::Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings)
:m_statement_warn_count(0),
m_current_row_for_warning(1),
m_warn_id(warn_id_arg),
+ m_allow_unlimited_warnings(allow_unlimited_warnings),
m_read_only(FALSE)
{
/* Initialize sub structures */
@@ -543,7 +543,8 @@ MYSQL_ERROR *Warning_info::push_warning(THD *thd,
if (! m_read_only)
{
- if (m_warn_list.elements < thd->variables.max_error_count)
+ if (m_allow_unlimited_warnings ||
+ m_warn_list.elements < thd->variables.max_error_count)
{
cond= new (& m_warn_root) MYSQL_ERROR(& m_warn_root);
if (cond)
@@ -559,6 +560,20 @@ MYSQL_ERROR *Warning_info::push_warning(THD *thd,
return cond;
}
+MYSQL_ERROR *Warning_info::push_warning(THD *thd, const MYSQL_ERROR *sql_condition)
+{
+ MYSQL_ERROR *new_condition= push_warning(thd,
+ sql_condition->get_sql_errno(),
+ sql_condition->get_sqlstate(),
+ sql_condition->get_level(),
+ sql_condition->get_message_text());
+
+ if (new_condition)
+ new_condition->copy_opt_attributes(sql_condition);
+
+ return new_condition;
+}
+
/*
Push the warning to error list if there is still room in the list
diff --git a/sql/sql_error.h b/sql/sql_error.h
index 14dc5e6d12c..955b3767847 100644
--- a/sql/sql_error.h
+++ b/sql/sql_error.h
@@ -1,5 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB,
- Copyright (C) 2008-2009 Sun Microsystems, Inc
+/* Copyright (c) 2000, 2011, 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
@@ -12,7 +11,7 @@
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 */
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef SQL_ERROR_H
#define SQL_ERROR_H
@@ -323,10 +322,13 @@ class Warning_info
{
/** A memory root to allocate warnings and errors */
MEM_ROOT m_warn_root;
+
/** List of warnings of all severities (levels). */
List <MYSQL_ERROR> m_warn_list;
+
/** A break down of the number of warnings per severity (level). */
uint m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
+
/**
The number of warnings of the current statement. Warning_info
life cycle differs from statement life cycle -- it may span
@@ -334,20 +336,25 @@ class Warning_info
m_statement_warn_count 0, whereas m_warn_list is not empty.
*/
uint m_statement_warn_count;
+
/*
Row counter, to print in errors and warnings. Not increased in
create_sort_index(); may differ from examined_row_count.
*/
ulong m_current_row_for_warning;
- /** Used to optionally clear warnings only once per statement. */
+
+ /** Used to optionally clear warnings only once per statement. */
ulonglong m_warn_id;
+ /** Indicates if push_warning() allows unlimited number of warnings. */
+ bool m_allow_unlimited_warnings;
+
private:
Warning_info(const Warning_info &rhs); /* Not implemented */
Warning_info& operator=(const Warning_info &rhs); /* Not implemented */
public:
- Warning_info(ulonglong warn_id_arg);
+ Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings);
~Warning_info();
/**
@@ -384,19 +391,13 @@ public:
void append_warnings(THD *thd, List<MYSQL_ERROR> *src)
{
MYSQL_ERROR *err;
- MYSQL_ERROR *copy;
List_iterator_fast<MYSQL_ERROR> it(*src);
/*
Don't use ::push_warning() to avoid invocation of condition
handlers or escalation of warnings to errors.
*/
while ((err= it++))
- {
- copy= Warning_info::push_warning(thd, err->get_sql_errno(), err->get_sqlstate(),
- err->get_level(), err->get_message_text());
- if (copy)
- copy->copy_opt_attributes(err);
- }
+ Warning_info::push_warning(thd, err);
}
/**
@@ -462,6 +463,9 @@ public:
MYSQL_ERROR::enum_warning_level level,
const char* msg);
+ /** Add a new condition to the current list. */
+ MYSQL_ERROR *push_warning(THD *thd, const MYSQL_ERROR *sql_condition);
+
/**
Set the read only status for this statement area.
This is a privileged operation, reserved for the implementation of
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index 0805a1b9f50..f82e0948b54 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -1302,9 +1302,10 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
String &field_term, String &line_start, String &line_term,
String &enclosed_par, int escape, bool get_it_from_net,
bool is_fifo)
- :file(file_par),escape_char(escape)
+ :file(file_par), buff_length(tot_length), escape_char(escape),
+ found_end_of_line(false), eof(false), need_end_io_cache(false),
+ error(false), line_cuted(false), found_null(false), read_charset(cs)
{
- read_charset= cs;
field_term_ptr=(char*) field_term.ptr();
field_term_length= field_term.length();
line_term_ptr=(char*) line_term.ptr();
@@ -1332,12 +1333,10 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
(uchar) enclosed_par[0] : INT_MAX;
field_term_char= field_term_length ? (uchar) field_term_ptr[0] : INT_MAX;
line_term_char= line_term_length ? (uchar) line_term_ptr[0] : INT_MAX;
- error=eof=found_end_of_line=found_null=line_cuted=0;
- buff_length=tot_length;
/* Set of a stack for unget if long terminators */
- uint length=max(field_term_length,line_term_length)+1;
+ uint length= max(cs->mbmaxlen, max(field_term_length, line_term_length)) + 1;
set_if_bigger(length,line_start.length());
stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
@@ -1379,7 +1378,7 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, CHARSET_INFO *cs,
READ_INFO::~READ_INFO()
{
- if (!error && need_end_io_cache)
+ if (need_end_io_cache)
::end_io_cache(&cache);
if (buffer != NULL)
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 7d0186c0752..24f7fdb8e61 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, 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
@@ -7227,10 +7227,20 @@ bool parse_sql(THD *thd,
bool mysql_parse_status= MYSQLparse(thd) != 0;
- /* Check that if MYSQLparse() failed, thd->is_error() is set. */
+ /*
+ Check that if MYSQLparse() failed either thd->is_error() is set, or an
+ internal error handler is set.
+
+ The assert will not catch a situation where parsing fails without an
+ error reported if an error handler exists. The problem is that the
+ error handler might have intercepted the error, so thd->is_error() is
+ not set. However, there is no way to be 100% sure here (the error
+ handler might be for other errors than parsing one).
+ */
DBUG_ASSERT(!mysql_parse_status ||
- (mysql_parse_status && thd->is_error()));
+ (mysql_parse_status && thd->is_error()) ||
+ (mysql_parse_status && thd->get_internal_handler()));
/* Reset parser state. */
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index b9bbec63e7d..52d6757b03a 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -3980,7 +3980,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
part_spec->start_part= 0;
part_spec->end_part= num_parts - 1;
if ((index < MAX_KEY) &&
- key_spec->flag == (uint)HA_READ_KEY_EXACT &&
+ key_spec && key_spec->flag == (uint)HA_READ_KEY_EXACT &&
part_info->some_fields_in_PF.is_set(index))
{
key_info= table->key_info+index;
diff --git a/sql/sql_plist.h b/sql/sql_plist.h
index db85266be15..b71136cd9ab 100644
--- a/sql/sql_plist.h
+++ b/sql/sql_plist.h
@@ -95,6 +95,7 @@ public:
*last= a;
*B::prev_ptr(a)= last;
I::set_last(B::next_ptr(a));
+ C::inc();
}
inline void insert_after(T *pos, T *a)
{
@@ -112,6 +113,7 @@ public:
}
else
I::set_last(B::next_ptr(a));
+ C::inc();
}
}
inline void remove(T *a)
@@ -188,6 +190,20 @@ public:
/**
+ Hook class which via its methods specifies which members
+ of T should be used for participating in a intrusive list.
+*/
+
+template <typename T, T* T::*next, T** T::*prev>
+struct I_P_List_adapter
+{
+ static inline T **next_ptr(T *el) { return &(el->*next); }
+
+ static inline T ***prev_ptr(T *el) { return &(el->*prev); }
+};
+
+
+/**
Element counting policy class for I_P_List to be used in
cases when no element counting should be done.
*/
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 9085d018dfd..779569b10fb 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2002, 2011, 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
@@ -2842,7 +2842,8 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
param= stmt->param_array[param_number];
Diagnostics_area new_stmt_da, *save_stmt_da= thd->stmt_da;
- Warning_info new_warnning_info(thd->query_id), *save_warinig_info= thd->warning_info;
+ Warning_info new_warnning_info(thd->query_id, false);
+ Warning_info *save_warinig_info= thd->warning_info;
thd->stmt_da= &new_stmt_da;
thd->warning_info= &new_warnning_info;
@@ -3900,7 +3901,7 @@ Ed_result_set::Ed_result_set(List<Ed_row> *rows_arg,
*/
Ed_connection::Ed_connection(THD *thd)
- :m_warning_info(thd->query_id),
+ :m_warning_info(thd->query_id, false),
m_thd(thd),
m_rsets(0),
m_current_rset(0)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 28981e719b8..7620d7c5f47 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -991,7 +991,7 @@ JOIN::optimize()
If all items were resolved by opt_sum_query, there is no need to
open any tables.
*/
- if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds)))
+ if ((res=opt_sum_query(thd, select_lex->leaf_tables, all_fields, conds)))
{
if (res == HA_ERR_KEY_NOT_FOUND)
{
@@ -1972,7 +1972,11 @@ JOIN::exec()
if (!curr_join->sort_and_group &&
curr_join->const_tables != curr_join->tables)
curr_join->join_tab[curr_join->const_tables].sorted= 0;
- if ((tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, 0)))
+
+ Procedure *save_proc= curr_join->procedure;
+ tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, 0);
+ curr_join->procedure= save_proc;
+ if (tmp_error)
{
error= tmp_error;
DBUG_VOID_RETURN;
@@ -2259,7 +2263,7 @@ JOIN::exec()
Item* sort_table_cond= make_cond_for_table(curr_join->tmp_having,
used_tables,
- used_tables);
+ (table_map) 0);
if (sort_table_cond)
{
if (!curr_table->select)
@@ -12620,10 +12624,14 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
if (join->having && join->having->val_int() == 0)
DBUG_RETURN(NESTED_LOOP_OK); // Didn't match having
- error=0;
if (join->procedure)
- error=join->procedure->send_row(join->procedure_fields_list);
- else if (join->do_send_rows)
+ {
+ if (join->procedure->send_row(join->procedure_fields_list))
+ DBUG_RETURN(NESTED_LOOP_ERROR);
+ DBUG_RETURN(NESTED_LOOP_OK);
+ }
+ error=0;
+ if (join->do_send_rows)
error=join->result->send_data(*join->fields);
if (error)
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
@@ -13094,6 +13102,42 @@ static bool test_if_ref(Item_field *left_item,Item *right_item)
return 0; // keep test
}
+/**
+ Extract a condition that can be checked after reading given table
+
+ @param cond Condition to analyze
+ @param tables Tables for which "current field values" are available
+ @param used_table Table that we're extracting the condition for (may
+ also include PSEUDO_TABLE_BITS, and may be zero)
+ @param exclude_expensive_cond Do not push expensive conditions
+
+ @retval <>NULL Generated condition
+ @retval =NULL Already checked, OR error
+
+ @details
+ Extract the condition that can be checked after reading the table
+ specified in 'used_table', given that current-field values for tables
+ specified in 'tables' bitmap are available.
+ If 'used_table' is 0
+ - extract conditions for all tables in 'tables'.
+ - extract conditions are unrelated to any tables
+ in the same query block/level(i.e. conditions
+ which have used_tables == 0).
+
+ The function assumes that
+ - Constant parts of the condition has already been checked.
+ - Condition that could be checked for tables in 'tables' has already
+ been checked.
+
+ The function takes into account that some parts of the condition are
+ guaranteed to be true by employed 'ref' access methods (the code that
+ does this is located at the end, search down for "EQ_FUNC").
+
+ @note
+ Make sure to keep the implementations of make_cond_for_table() and
+ make_cond_after_sjm() synchronized.
+ make_cond_for_info_schema() uses similar algorithm as well.
+*/
static COND *
make_cond_for_table(COND *cond, table_map tables, table_map used_table)
diff --git a/sql/sql_select.h b/sql/sql_select.h
index bdb9d1a315c..ea4a22527d3 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -619,7 +619,8 @@ bool is_indexed_agg_distinct(JOIN *join, List<Item_field> *out_args);
/* functions from opt_sum.cc */
bool simple_pred(Item_func *func_item, Item **args, bool *inv_order);
-int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
+int opt_sum_query(THD* thd,
+ TABLE_LIST *tables, List<Item> &all_fields, COND *conds);
/* from sql_delete.cc, used by opt_range.cc */
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 464b966e4be..9e9de5e3524 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -3416,6 +3416,45 @@ end:
/**
+ Trigger_error_handler is intended to intercept and silence SQL conditions
+ that might happen during trigger loading for SHOW statements.
+ The potential SQL conditions are:
+
+ - ER_PARSE_ERROR -- this error is thrown if a trigger definition file
+ is damaged or contains invalid CREATE TRIGGER statement. That should
+ not happen in normal life.
+
+ - ER_TRG_NO_DEFINER -- this warning is thrown when we're loading a
+ trigger created/imported in/from the version of MySQL, which does not
+ support trigger definers.
+
+ - ER_TRG_NO_CREATION_CTX -- this warning is thrown when we're loading a
+ trigger created/imported in/from the version of MySQL, which does not
+ support trigger creation contexts.
+*/
+
+class Trigger_error_handler : public Internal_error_handler
+{
+public:
+ bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl)
+ {
+ if (sql_errno == ER_PARSE_ERROR ||
+ sql_errno == ER_TRG_NO_DEFINER ||
+ sql_errno == ER_TRG_NO_CREATION_CTX)
+ return true;
+
+ return false;
+ }
+};
+
+
+
+/**
@brief Fill I_S tables whose data are retrieved
from frm files and storage engine
@@ -3570,7 +3609,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0))
#endif
{
- thd->no_warnings_for_error= 1;
List<LEX_STRING> table_names;
int res= make_table_name_list(thd, &table_names, lex,
&lookup_field_vals,
@@ -3619,9 +3657,24 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
if (!(table_open_method & ~OPEN_FRM_ONLY) &&
!with_i_schema)
{
- if (!fill_schema_table_from_frm(thd, tables, schema_table, db_name,
- table_name, schema_table_idx,
- can_deadlock))
+ /*
+ Here we need to filter out warnings, which can happen
+ during loading of triggers in fill_schema_table_from_frm(),
+ because we don't need those warnings to pollute output of
+ SELECT from I_S / SHOW-statements.
+ */
+
+ Trigger_error_handler err_handler;
+ thd->push_internal_handler(&err_handler);
+
+ int res= fill_schema_table_from_frm(thd, tables, schema_table,
+ db_name, table_name,
+ schema_table_idx,
+ can_deadlock);
+
+ thd->pop_internal_handler();
+
+ if (!res)
continue;
}
@@ -3631,7 +3684,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
Set the parent lex of 'sel' because it is needed by
sel.init_query() which is called inside make_table_list.
*/
- thd->no_warnings_for_error= 1;
sel.parent_lex= lex;
if (make_table_list(thd, &sel, db_name, table_name))
goto err;
@@ -6675,6 +6727,92 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
}
+/**
+ Fill INFORMATION_SCHEMA-table, leave correct Diagnostics_area /
+ Warning_info state after itself.
+
+ This function is a wrapper around ST_SCHEMA_TABLE::fill_table(), which
+ may "partially silence" some errors. The thing is that during
+ fill_table() many errors might be emitted. These errors stem from the
+ nature of fill_table().
+
+ For example, SELECT ... FROM INFORMATION_SCHEMA.xxx WHERE TABLE_NAME = 'xxx'
+ results in a number of 'Table <db name>.xxx does not exist' errors,
+ because fill_table() tries to open the 'xxx' table in every possible
+ database.
+
+ Those errors are cleared (the error status is cleared from
+ Diagnostics_area) inside fill_table(), but they remain in Warning_info
+ (Warning_info is not cleared because it may contain useful warnings).
+
+ This function is responsible for making sure that Warning_info does not
+ contain warnings corresponding to the cleared errors.
+
+ @note: THD::no_warnings_for_error used to be set before calling
+ fill_table(), thus those errors didn't go to Warning_info. This is not
+ the case now (THD::no_warnings_for_error was eliminated as a hack), so we
+ need to take care of those warnings here.
+
+ @param thd Thread context.
+ @param table_list I_S table.
+ @param join_table JOIN/SELECT table.
+
+ @return Error status.
+ @retval TRUE Error.
+ @retval FALSE Success.
+*/
+static bool do_fill_table(THD *thd,
+ TABLE_LIST *table_list,
+ JOIN_TAB *join_table)
+{
+ // NOTE: fill_table() may generate many "useless" warnings, which will be
+ // ignored afterwards. On the other hand, there might be "useful"
+ // warnings, which should be presented to the user. Warning_info usually
+ // stores no more than THD::variables.max_error_count warnings.
+ // The problem is that "useless warnings" may occupy all the slots in the
+ // Warning_info, so "useful warnings" get rejected. In order to avoid
+ // that problem we create a Warning_info instance, which is capable of
+ // storing "unlimited" number of warnings.
+ Warning_info wi(thd->query_id, true);
+ Warning_info *wi_saved= thd->warning_info;
+
+ thd->warning_info= &wi;
+
+ bool res= table_list->schema_table->fill_table(
+ thd, table_list, join_table->select_cond);
+
+ thd->warning_info= wi_saved;
+
+ // Pass an error if any.
+
+ if (thd->stmt_da->is_error())
+ {
+ thd->warning_info->push_warning(thd,
+ thd->stmt_da->sql_errno(),
+ thd->stmt_da->get_sqlstate(),
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ thd->stmt_da->message());
+ }
+
+ // Pass warnings (if any).
+ //
+ // Filter out warnings with WARN_LEVEL_ERROR level, because they
+ // correspond to the errors which were filtered out in fill_table().
+
+
+ List_iterator_fast<MYSQL_ERROR> it(wi.warn_list());
+ MYSQL_ERROR *err;
+
+ while ((err= it++))
+ {
+ if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_ERROR)
+ thd->warning_info->push_warning(thd, err);
+ }
+
+ return res;
+}
+
+
/*
Fill temporary schema tables before SELECT
@@ -6697,7 +6835,6 @@ bool get_schema_tables_result(JOIN *join,
bool result= 0;
DBUG_ENTER("get_schema_tables_result");
- thd->no_warnings_for_error= 1;
for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++)
{
if (!tab->table || !tab->table->pos_in_table_list)
@@ -6748,8 +6885,7 @@ bool get_schema_tables_result(JOIN *join,
else
table_list->table->file->stats.records= 0;
- if (table_list->schema_table->fill_table(thd, table_list,
- tab->select_cond))
+ if (do_fill_table(thd, table_list, tab))
{
result= 1;
join->error= 1;
@@ -6761,7 +6897,6 @@ bool get_schema_tables_result(JOIN *join,
table_list->schema_table_state= executed_place;
}
}
- thd->no_warnings_for_error= 0;
DBUG_RETURN(result);
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index ce4218869ff..f98ac676525 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -6660,15 +6660,15 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
NO need to tamper with MERGE tables. The real open is done later.
*/
Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
- TABLE *t_table;
+ TABLE_LIST temp_table_list;
+ TABLE_LIST *t_table_list;
if (new_name != table_name || new_db != db)
{
- table_list->alias= new_name;
- table_list->table_name= new_name;
- table_list->table_name_length= strlen(new_name);
- table_list->db= new_db;
- table_list->db_length= strlen(new_db);
- table_list->mdl_request.ticket= target_mdl_request.ticket;
+ temp_table_list.init_one_table(new_db, strlen(new_db),
+ new_name, strlen(new_name),
+ new_name, TL_READ_NO_INSERT);
+ temp_table_list.mdl_request.ticket= target_mdl_request.ticket;
+ t_table_list= &temp_table_list;
}
else
{
@@ -6678,20 +6678,21 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
to request the lock.
*/
table_list->mdl_request.ticket= mdl_ticket;
+ t_table_list= table_list;
}
- if (open_table(thd, table_list, thd->mem_root, &ot_ctx))
+ if (open_table(thd, t_table_list, thd->mem_root, &ot_ctx))
{
goto err_with_mdl;
}
- t_table= table_list->table;
/* Tell the handler that a new frm file is in place. */
- error= t_table->file->ha_create_handler_files(path, NULL, CHF_INDEX_FLAG,
- create_info);
+ error= t_table_list->table->file->ha_create_handler_files(path, NULL,
+ CHF_INDEX_FLAG,
+ create_info);
- DBUG_ASSERT(thd->open_tables == t_table);
+ DBUG_ASSERT(thd->open_tables == t_table_list->table);
close_thread_table(thd, &thd->open_tables);
- table_list->table= 0;
+ t_table_list->table= NULL;
if (error)
goto err_with_mdl;
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 4908fce5950..d026714c007 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -1225,13 +1225,12 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
DBUG_RETURN(1); // EOM
}
-
- if (!thd->no_warnings_for_error)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRG_NO_CREATION_CTX,
- ER(ER_TRG_NO_CREATION_CTX),
- (const char*) db,
- (const char*) table_name);
+
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRG_NO_CREATION_CTX,
+ ER(ER_TRG_NO_CREATION_CTX),
+ (const char*) db,
+ (const char*) table_name);
if (!(trg_client_cs_name= alloc_lex_string(&table->mem_root)) ||
!(trg_connection_cl_name= alloc_lex_string(&table->mem_root)) ||
@@ -1362,12 +1361,12 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
MySQL, which does not support triggers definers. We should emit
warning here.
*/
- if (!thd->no_warnings_for_error)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER),
- (const char*) db,
- (const char*) sp->m_name.str);
-
+
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER),
+ (const char*) db,
+ (const char*) sp->m_name.str);
+
/*
Set definer to the '' to correct displaying in the information
schema.
diff --git a/sql/transaction.cc b/sql/transaction.cc
index 85686810893..94a32200274 100644
--- a/sql/transaction.cc
+++ b/sql/transaction.cc
@@ -79,6 +79,33 @@ static bool xa_trans_rolled_back(XID_STATE *xid_state)
/**
+ Rollback the active XA transaction.
+
+ @note Resets rm_error before calling ha_rollback(), so
+ the thd->transaction.xid structure gets reset
+ by ha_rollback() / THD::transaction::cleanup().
+
+ @return TRUE if the rollback failed, FALSE otherwise.
+*/
+
+static bool xa_trans_force_rollback(THD *thd)
+{
+ /*
+ We must reset rm_error before calling ha_rollback(),
+ so thd->transaction.xid structure gets reset
+ by ha_rollback()/THD::transaction::cleanup().
+ */
+ thd->transaction.xid_state.rm_error= 0;
+ if (ha_rollback_trans(thd, true))
+ {
+ my_error(ER_XAER_RMERR, MYF(0));
+ return true;
+ }
+ return false;
+}
+
+
+/**
Begin a new transaction.
@note Beginning a transaction implicitly commits any current
@@ -362,6 +389,13 @@ bool trans_savepoint(THD *thd, LEX_STRING name)
!opt_using_transactions)
DBUG_RETURN(FALSE);
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ if (xa_state != XA_NOTR)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ DBUG_RETURN(TRUE);
+ }
+
sv= find_savepoint(thd, name);
if (*sv) /* old savepoint of the same name exists */
@@ -435,6 +469,13 @@ bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name)
DBUG_RETURN(TRUE);
}
+ enum xa_states xa_state= thd->transaction.xid_state.xa_state;
+ if (xa_state != XA_NOTR)
+ {
+ my_error(ER_XAER_RMFAIL, MYF(0), xa_state_names[xa_state]);
+ DBUG_RETURN(TRUE);
+ }
+
if (ha_rollback_to_savepoint(thd, sv))
res= TRUE;
else if (((thd->variables.option_bits & OPTION_KEEP_LOG) ||
@@ -635,8 +676,7 @@ bool trans_xa_commit(THD *thd)
if (xa_trans_rolled_back(&thd->transaction.xid_state))
{
- if (ha_rollback_trans(thd, TRUE))
- my_error(ER_XAER_RMERR, MYF(0));
+ xa_trans_force_rollback(thd);
res= thd->is_error();
}
else if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
@@ -725,15 +765,7 @@ bool trans_xa_rollback(THD *thd)
DBUG_RETURN(TRUE);
}
- /*
- Resource Manager error is meaningless at this point, as we perform
- explicit rollback request by user. We must reset rm_error before
- calling ha_rollback(), so thd->transaction.xid structure gets reset
- by ha_rollback()/THD::transaction::cleanup().
- */
- thd->transaction.xid_state.rm_error= 0;
- if ((res= test(ha_rollback_trans(thd, TRUE))))
- my_error(ER_XAER_RMERR, MYF(0));
+ res= xa_trans_force_rollback(thd);
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.modified_non_trans_table= FALSE;
diff --git a/storage/archive/ha_archive.cc b/storage/archive/ha_archive.cc
index eb9705ea5aa..df556a0721c 100644
--- a/storage/archive/ha_archive.cc
+++ b/storage/archive/ha_archive.cc
@@ -1,17 +1,19 @@
-/* Copyright (C) 2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
+/* Copyright (c) 2003, 2011, 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 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.
+ 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 */
+ 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 */
#ifdef USE_PRAGMA_IMPLEMENTATION
#pragma implementation // gcc: Class implementation
@@ -923,7 +925,7 @@ int ha_archive::write_row(uchar *buf)
*/
azflush(&(share->archive_write), Z_SYNC_FLUSH);
/*
- Set the position of the local read thread to the beginning postion.
+ Set the position of the local read thread to the beginning position.
*/
if (read_data_header(&archive))
{
diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc
index fc870d33fb2..1b1dfdc003e 100644
--- a/storage/heap/ha_heap.cc
+++ b/storage/heap/ha_heap.cc
@@ -157,11 +157,11 @@ int ha_heap::close(void)
DESCRIPTION
Do same as default implementation but use file->s->name instead of
table->s->path. This is needed by Windows where the clone() call sees
- '/'-delimited path in table->s->path, while ha_peap::open() was called
+ '/'-delimited path in table->s->path, while ha_heap::open() was called
with '\'-delimited path.
*/
-handler *ha_heap::clone(MEM_ROOT *mem_root)
+handler *ha_heap::clone(const char *name, MEM_ROOT *mem_root)
{
handler *new_handler= get_new_handler(table->s, mem_root, table->s->db_type());
if (new_handler && !new_handler->ha_open(table, file->s->name, table->db_stat,
diff --git a/storage/heap/ha_heap.h b/storage/heap/ha_heap.h
index 5f3d66cd53c..cc335870f06 100644
--- a/storage/heap/ha_heap.h
+++ b/storage/heap/ha_heap.h
@@ -35,7 +35,7 @@ class ha_heap: public handler
public:
ha_heap(handlerton *hton, TABLE_SHARE *table);
~ha_heap() {}
- handler *clone(MEM_ROOT *mem_root);
+ handler *clone(const char *name, MEM_ROOT *mem_root);
const char *table_type() const
{
return (table->in_use->variables.sql_mode & MODE_MYSQL323) ?
diff --git a/storage/innobase/btr/btr0cur.c b/storage/innobase/btr/btr0cur.c
index c4034d0896a..9fa8fc663c9 100644
--- a/storage/innobase/btr/btr0cur.c
+++ b/storage/innobase/btr/btr0cur.c
@@ -2429,8 +2429,8 @@ make_external:
record on its page? */
was_first = page_cur_is_before_first(page_cursor);
- /* The first parameter means that no lock checking and undo logging
- is made in the insert */
+ /* Lock checks and undo logging were already performed by
+ btr_cur_upd_lock_and_undo(). */
err = btr_cur_pessimistic_insert(BTR_NO_UNDO_LOG_FLAG
| BTR_NO_LOCKING_FLAG
diff --git a/storage/innobase/buf/buf0flu.c b/storage/innobase/buf/buf0flu.c
index 07a32e55f97..ebe96a82a10 100644
--- a/storage/innobase/buf/buf0flu.c
+++ b/storage/innobase/buf/buf0flu.c
@@ -1716,7 +1716,7 @@ buf_flush_batch(
ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST);
#ifdef UNIV_SYNC_DEBUG
ut_ad((flush_type != BUF_FLUSH_LIST)
- || sync_thread_levels_empty_gen(TRUE));
+ || sync_thread_levels_empty_except_dict());
#endif /* UNIV_SYNC_DEBUG */
buf_pool_mutex_enter(buf_pool);
diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c
index ebc7747640e..df9db4d7428 100644
--- a/storage/innobase/dict/dict0dict.c
+++ b/storage/innobase/dict/dict0dict.c
@@ -52,7 +52,6 @@ UNIV_INTERN dict_index_t* dict_ind_compact;
#include "que0que.h"
#include "rem0cmp.h"
#include "row0merge.h"
-#include "srv0srv.h" /* srv_lower_case_table_names */
#include "m_ctype.h" /* my_isspace() */
#include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str()*/
@@ -3029,14 +3028,14 @@ dict_scan_table_name(
/* Values; 0 = Store and compare as given; case sensitive
1 = Store and compare in lower; case insensitive
2 = Store as given, compare in lower; case semi-sensitive */
- if (srv_lower_case_table_names == 2) {
+ if (innobase_get_lower_case_table_names() == 2) {
innobase_casedn_str(ref);
*table = dict_table_get_low(ref);
memcpy(ref, database_name, database_name_len);
ref[database_name_len] = '/';
memcpy(ref + database_name_len + 1, table_name, table_name_len + 1);
} else {
- if (srv_lower_case_table_names == 1) {
+ if (innobase_get_lower_case_table_names() == 1) {
innobase_casedn_str(ref);
}
*table = dict_table_get_low(ref);
diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c
index 37bf4a1ad59..aad3145f7a4 100644
--- a/storage/innobase/dict/dict0load.c
+++ b/storage/innobase/dict/dict0load.c
@@ -2262,7 +2262,7 @@ loop:
may not be the same case, but the previous comparison showed that they
match with no-case. */
- if ((srv_lower_case_table_names != 2)
+ if ((innobase_get_lower_case_table_names() != 2)
&& (0 != ut_memcmp(field, table_name, len))) {
goto next_rec;
}
diff --git a/storage/innobase/dict/dict0mem.c b/storage/innobase/dict/dict0mem.c
index a442a3811d8..8785dfb57ed 100644
--- a/storage/innobase/dict/dict0mem.c
+++ b/storage/innobase/dict/dict0mem.c
@@ -33,7 +33,6 @@ Created 1/8/1996 Heikki Tuuri
#include "data0type.h"
#include "mach0data.h"
#include "dict0dict.h"
-#include "srv0srv.h" /* srv_lower_case_table_names */
#include "ha_prototypes.h" /* innobase_casedn_str()*/
#ifndef UNIV_HOTBACKUP
# include "lock0lock.h"
@@ -294,9 +293,9 @@ dict_mem_foreign_create(void)
/**********************************************************************//**
Sets the foreign_table_name_lookup pointer based on the value of
-srv_lower_case_table_names. If that is 0 or 1, foreign_table_name_lookup
-will point to foreign_table_name. If 2, then another string is allocated
-of the heap and set to lower case. */
+lower_case_table_names. If that is 0 or 1, foreign_table_name_lookup
+will point to foreign_table_name. If 2, then another string is
+allocated from foreign->heap and set to lower case. */
UNIV_INTERN
void
dict_mem_foreign_table_name_lookup_set(
@@ -304,7 +303,7 @@ dict_mem_foreign_table_name_lookup_set(
dict_foreign_t* foreign, /*!< in/out: foreign struct */
ibool do_alloc) /*!< in: is an alloc needed */
{
- if (srv_lower_case_table_names == 2) {
+ if (innobase_get_lower_case_table_names() == 2) {
if (do_alloc) {
foreign->foreign_table_name_lookup = mem_heap_alloc(
foreign->heap,
@@ -321,9 +320,9 @@ dict_mem_foreign_table_name_lookup_set(
/**********************************************************************//**
Sets the referenced_table_name_lookup pointer based on the value of
-srv_lower_case_table_names. If that is 0 or 1,
-referenced_table_name_lookup will point to referenced_table_name. If 2,
-then another string is allocated of the heap and set to lower case. */
+lower_case_table_names. If that is 0 or 1, referenced_table_name_lookup
+will point to referenced_table_name. If 2, then another string is
+allocated from foreign->heap and set to lower case. */
UNIV_INTERN
void
dict_mem_referenced_table_name_lookup_set(
@@ -331,7 +330,7 @@ dict_mem_referenced_table_name_lookup_set(
dict_foreign_t* foreign, /*!< in/out: foreign struct */
ibool do_alloc) /*!< in: is an alloc needed */
{
- if (srv_lower_case_table_names == 2) {
+ if (innobase_get_lower_case_table_names() == 2) {
if (do_alloc) {
foreign->referenced_table_name_lookup = mem_heap_alloc(
foreign->heap,
diff --git a/storage/innobase/fil/fil0fil.c b/storage/innobase/fil/fil0fil.c
index 6c50b853187..0d9846fdbf8 100644
--- a/storage/innobase/fil/fil0fil.c
+++ b/storage/innobase/fil/fil0fil.c
@@ -4527,8 +4527,8 @@ fil_aio_wait(
ret = os_aio_linux_handle(segment, &fil_node,
&message, &type);
#else
- ret = 0; /* Eliminate compiler warning */
ut_error;
+ ret = 0; /* Eliminate compiler warning */
#endif
} else {
srv_set_io_thread_op_info(segment, "simulated aio handle");
@@ -4538,6 +4538,10 @@ fil_aio_wait(
}
ut_a(ret);
+ if (UNIV_UNLIKELY(fil_node == NULL)) {
+ ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
+ return;
+ }
srv_set_io_thread_op_info(segment, "complete io for fil node");
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 74a33d05760..8efa0523927 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -1199,6 +1199,20 @@ innobase_get_stmt(
return(stmt->str);
}
+/**********************************************************************//**
+Get the current setting of the lower_case_table_names global parameter from
+mysqld.cc. We do a dirty read because for one there is no synchronization
+object and secondly there is little harm in doing so even if we get a torn
+read.
+@return value of lower_case_table_names */
+extern "C" UNIV_INTERN
+ulint
+innobase_get_lower_case_table_names(void)
+/*=====================================*/
+{
+ return(lower_case_table_names);
+}
+
#if defined (__WIN__) && defined (MYSQL_DYNAMIC_PLUGIN)
extern MYSQL_PLUGIN_IMPORT MY_TMPDIR mysql_tmpdir_list;
/*******************************************************************//**
@@ -3671,7 +3685,6 @@ ha_innobase::open(
UT_NOT_USED(test_if_locked);
thd = ha_thd();
- srv_lower_case_table_names = lower_case_table_names;
/* Under some cases MySQL seems to call this function while
holding btr_search_latch. This breaks the latching order as
@@ -6242,10 +6255,6 @@ create_table_def(
DBUG_PRINT("enter", ("table_name: %s", table_name));
ut_a(trx->mysql_thd != NULL);
- if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name,
- (THD*) trx->mysql_thd)) {
- DBUG_RETURN(HA_ERR_GENERIC);
- }
/* MySQL does the name length check. But we do additional check
on the name length here */
@@ -6782,38 +6791,17 @@ ha_innobase::create(
DBUG_RETURN(HA_ERR_TO_BIG_ROW);
}
- /* Get the transaction associated with the current thd, or create one
- if not yet created */
-
- parent_trx = check_trx_exists(thd);
-
- /* In case MySQL calls this in the middle of a SELECT query, release
- possible adaptive hash latch to avoid deadlocks of threads */
-
- trx_search_latch_release_if_reserved(parent_trx);
-
- trx = innobase_trx_allocate(thd);
-
- srv_lower_case_table_names = lower_case_table_names;
-
strcpy(name2, name);
normalize_table_name(norm_name, name2);
- /* Latch the InnoDB data dictionary exclusively so that no deadlocks
- or lock waits can happen in it during a table create operation.
- Drop table etc. do this latching in row0mysql.c. */
-
- row_mysql_lock_data_dictionary(trx);
-
/* Create the table definition in InnoDB */
flags = 0;
/* Validate create options if innodb_strict_mode is set. */
if (!create_options_are_valid(thd, form, create_info)) {
- error = ER_ILLEGAL_HA_CREATE_OPTION;
- goto cleanup;
+ DBUG_RETURN(ER_ILLEGAL_HA_CREATE_OPTION);
}
if (create_info->key_block_size) {
@@ -6955,16 +6943,37 @@ ha_innobase::create(
/* Check for name conflicts (with reserved name) for
any user indices to be created. */
- if (innobase_index_name_is_reserved(trx, form->key_info,
+ if (innobase_index_name_is_reserved(thd, form->key_info,
form->s->keys)) {
- error = -1;
- goto cleanup;
+ DBUG_RETURN(-1);
+ }
+
+ if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) {
+ DBUG_RETURN(HA_ERR_GENERIC);
}
if (create_info->options & HA_LEX_CREATE_TMP_TABLE) {
flags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT;
}
+ /* Get the transaction associated with the current thd, or create one
+ if not yet created */
+
+ parent_trx = check_trx_exists(thd);
+
+ /* In case MySQL calls this in the middle of a SELECT query, release
+ possible adaptive hash latch to avoid deadlocks of threads */
+
+ trx_search_latch_release_if_reserved(parent_trx);
+
+ trx = innobase_trx_allocate(thd);
+
+ /* Latch the InnoDB data dictionary exclusively so that no deadlocks
+ or lock waits can happen in it during a table create operation.
+ Drop table etc. do this latching in row0mysql.c. */
+
+ row_mysql_lock_data_dictionary(trx);
+
error = create_table_def(trx, form, norm_name,
create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL,
flags);
@@ -7219,8 +7228,6 @@ ha_innobase::delete_table(
trx = innobase_trx_allocate(thd);
- srv_lower_case_table_names = lower_case_table_names;
-
name_len = strlen(name);
ut_a(name_len < 1000);
@@ -7342,8 +7349,6 @@ innobase_rename_table(
char* norm_to;
char* norm_from;
- srv_lower_case_table_names = lower_case_table_names;
-
// Magic number 64 arbitrary
norm_to = (char*) my_malloc(strlen(to) + 64, MYF(0));
norm_from = (char*) my_malloc(strlen(from) + 64, MYF(0));
@@ -10263,7 +10268,7 @@ innobase_commit_by_xid(
if (trx) {
innobase_commit_low(trx);
-
+ trx_free_for_background(trx);
return(XA_OK);
} else {
return(XAER_NOTA);
@@ -10289,7 +10294,9 @@ innobase_rollback_by_xid(
trx = trx_get_trx_by_xid(xid);
if (trx) {
- return(innobase_rollback_trx(trx));
+ int ret = innobase_rollback_trx(trx);
+ trx_free_for_background(trx);
+ return(ret);
} else {
return(XAER_NOTA);
}
@@ -10922,19 +10929,19 @@ static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff)
return 0;
}
-/***********************************************************************
+/*********************************************************************//**
This function checks each index name for a table against reserved
-system default primary index name 'GEN_CLUST_INDEX'. If a name matches,
-this function pushes an warning message to the client, and returns true. */
+system default primary index name 'GEN_CLUST_INDEX'. If a name
+matches, this function pushes an warning message to the client,
+and returns true.
+@return true if the index name matches the reserved name */
extern "C" UNIV_INTERN
bool
innobase_index_name_is_reserved(
/*============================*/
- /* out: true if an index name
- matches the reserved name */
- const trx_t* trx, /* in: InnoDB transaction handle */
- const KEY* key_info, /* in: Indexes to be created */
- ulint num_of_keys) /* in: Number of indexes to
+ THD* thd, /*!< in/out: MySQL connection */
+ const KEY* key_info, /*!< in: Indexes to be created */
+ ulint num_of_keys) /*!< in: Number of indexes to
be created. */
{
const KEY* key;
@@ -10946,7 +10953,7 @@ innobase_index_name_is_reserved(
if (innobase_strcasecmp(key->name,
innobase_index_reserve_name) == 0) {
/* Push warning to mysql */
- push_warning_printf((THD*) trx->mysql_thd,
+ push_warning_printf(thd,
MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WRONG_NAME_FOR_INDEX,
"Cannot Create Index with name "
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index f05ea8801f0..0c0af8dd887 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -321,15 +321,14 @@ innobase_trx_allocate(
This function checks each index name for a table against reserved
system default primary index name 'GEN_CLUST_INDEX'. If a name
matches, this function pushes an warning message to the client,
-and returns true. */
+and returns true.
+@return true if the index name matches the reserved name */
extern "C"
bool
innobase_index_name_is_reserved(
/*============================*/
- /* out: true if the index name
- matches the reserved name */
- const trx_t* trx, /* in: InnoDB transaction handle */
- const KEY* key_info, /* in: Indexes to be created */
- ulint num_of_keys); /* in: Number of indexes to
+ THD* thd, /*!< in/out: MySQL connection */
+ const KEY* key_info, /*!< in: Indexes to be created */
+ ulint num_of_keys); /*!< in: Number of indexes to
be created. */
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index e0279c13de2..cc7e48ebd44 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -653,44 +653,37 @@ ha_innobase::add_index(
update_thd();
- heap = mem_heap_create(1024);
-
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads. */
trx_search_latch_release_if_reserved(prebuilt->trx);
- trx_start_if_not_started(prebuilt->trx);
- /* Create a background transaction for the operations on
- the data dictionary tables. */
- trx = innobase_trx_allocate(user_thd);
- trx_start_if_not_started(trx);
+ /* Check if the index name is reserved. */
+ if (innobase_index_name_is_reserved(user_thd, key_info, num_of_keys)) {
+ DBUG_RETURN(-1);
+ }
innodb_table = indexed_table
= dict_table_get(prebuilt->table->name, FALSE);
if (UNIV_UNLIKELY(!innodb_table)) {
- error = HA_ERR_NO_SUCH_TABLE;
- goto err_exit;
+ DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
- /* Check if the index name is reserved. */
- if (innobase_index_name_is_reserved(trx, key_info, num_of_keys)) {
- error = -1;
- } else {
- /* Check that index keys are sensible */
- error = innobase_check_index_keys(key_info, num_of_keys,
- innodb_table);
- }
+ /* Check that index keys are sensible */
+ error = innobase_check_index_keys(key_info, num_of_keys, innodb_table);
if (UNIV_UNLIKELY(error)) {
-err_exit:
- mem_heap_free(heap);
- trx_general_rollback_for_mysql(trx, NULL);
- trx_free_for_mysql(trx);
- trx_commit_for_mysql(prebuilt->trx);
DBUG_RETURN(error);
}
+ heap = mem_heap_create(1024);
+ trx_start_if_not_started(prebuilt->trx);
+
+ /* Create a background transaction for the operations on
+ the data dictionary tables. */
+ trx = innobase_trx_allocate(user_thd);
+ trx_start_if_not_started(trx);
+
/* Create table containing all indexes to be built in this
alter table add index so that they are in the correct order
in the table. */
@@ -762,8 +755,12 @@ err_exit:
ut_d(dict_table_check_for_dup_indexes(innodb_table,
FALSE));
+ mem_heap_free(heap);
+ trx_general_rollback_for_mysql(trx, NULL);
row_mysql_unlock_data_dictionary(trx);
- goto err_exit;
+ trx_free_for_mysql(trx);
+ trx_commit_for_mysql(prebuilt->trx);
+ DBUG_RETURN(error);
}
trx->table_id = indexed_table->id;
diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c
index 8110bccc162..7d94ebc6438 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.c
+++ b/storage/innobase/ibuf/ibuf0ibuf.c
@@ -1179,18 +1179,7 @@ ibuf_page_low(
ibuf_bitmap_page_no_calc(zip_size, page_no),
RW_NO_LATCH, NULL, BUF_GET_NO_LATCH,
file, line, &local_mtr));
-# ifdef UNIV_SYNC_DEBUG
- /* This is for tracking Bug #58212. This check and message can
- be removed once it has been established that our assumptions
- about this condition are correct. The bug was only a one-time
- occurrence, unable to repeat since then. */
- void* latch = sync_thread_levels_contains(SYNC_IBUF_BITMAP);
- if (latch) {
- fprintf(stderr, "Bug#58212 UNIV_SYNC_DEBUG"
- " levels %p (%u,%u)\n",
- latch, (unsigned) space, (unsigned) page_no);
- }
-# endif /* UNIV_SYNC_DEBUG */
+
ret = ibuf_bitmap_page_get_bits_low(
bitmap_page, page_no, zip_size,
MTR_MEMO_BUF_FIX, &local_mtr, IBUF_BITMAP_IBUF);
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 75d3b2c3302..51c9c2d1797 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -240,7 +240,9 @@ dict_mem_foreign_create(void);
/**********************************************************************//**
Sets the foreign_table_name_lookup pointer based on the value of
-srv_lower_case_table_names. */
+lower_case_table_names. If that is 0 or 1, foreign_table_name_lookup
+will point to foreign_table_name. If 2, then another string is
+allocated from the heap and set to lower case. */
UNIV_INTERN
void
dict_mem_foreign_table_name_lookup_set(
@@ -249,8 +251,10 @@ dict_mem_foreign_table_name_lookup_set(
ibool do_alloc); /*!< in: is an alloc needed */
/**********************************************************************//**
-Sets the reference_table_name_lookup pointer based on the value of
-srv_lower_case_table_names. */
+Sets the referenced_table_name_lookup pointer based on the value of
+lower_case_table_names. If that is 0 or 1, referenced_table_name_lookup
+will point to referenced_table_name. If 2, then another string is
+allocated from the heap and set to lower case. */
UNIV_INTERN
void
dict_mem_referenced_table_name_lookup_set(
diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h
index dd9e8db82ee..edf7a1a28c1 100644
--- a/storage/innobase/include/ha_prototypes.h
+++ b/storage/innobase/include/ha_prototypes.h
@@ -285,4 +285,15 @@ thd_set_lock_wait_time(
void* thd, /*!< in: thread handle (THD*) */
ulint value); /*!< in: time waited for the lock */
+/**********************************************************************//**
+Get the current setting of the lower_case_table_names global parameter from
+mysqld.cc. We do a dirty read because for one there is no synchronization
+object and secondly there is little harm in doing so even if we get a torn
+read.
+@return value of lower_case_table_names */
+UNIV_INTERN
+ulint
+innobase_get_lower_case_table_names(void);
+/*=====================================*/
+
#endif
diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic
index 1ce00fd7313..67db6695cab 100644
--- a/storage/innobase/include/log0log.ic
+++ b/storage/innobase/include/log0log.ic
@@ -435,7 +435,7 @@ log_free_check(void)
{
#ifdef UNIV_SYNC_DEBUG
- ut_ad(sync_thread_levels_empty_gen(TRUE));
+ ut_ad(sync_thread_levels_empty_except_dict());
#endif /* UNIV_SYNC_DEBUG */
if (log_sys->check_flush_or_checkpoint) {
diff --git a/storage/innobase/include/os0sync.h b/storage/innobase/include/os0sync.h
index b294d7421c8..1b98f94f641 100644
--- a/storage/innobase/include/os0sync.h
+++ b/storage/innobase/include/os0sync.h
@@ -150,10 +150,7 @@ os_event_free(
os_event_t event); /*!< in: event to free */
/**********************************************************//**
-Waits for an event object until it is in the signaled state. If
-srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the
-waiting thread when the event becomes signaled (or immediately if the
-event is already in the signaled state).
+Waits for an event object until it is in the signaled state.
Typically, if the event has been signalled after the os_event_reset()
we'll return immediately because event->is_set == TRUE.
diff --git a/storage/innobase/include/os0thread.h b/storage/innobase/include/os0thread.h
index cc56e2158ee..df3cdb7728e 100644
--- a/storage/innobase/include/os0thread.h
+++ b/storage/innobase/include/os0thread.h
@@ -107,8 +107,9 @@ UNIV_INTERN
void
os_thread_exit(
/*===========*/
- void* exit_value); /*!< in: exit value; in Windows this void*
+ void* exit_value) /*!< in: exit value; in Windows this void*
is cast as a DWORD */
+ UNIV_COLD __attribute__((noreturn));
/*****************************************************************//**
Returns the thread identifier of current thread.
@return current thread identifier */
@@ -117,13 +118,6 @@ os_thread_id_t
os_thread_get_curr_id(void);
/*========================*/
/*****************************************************************//**
-Returns handle to the current thread.
-@return current thread handle */
-UNIV_INTERN
-os_thread_t
-os_thread_get_curr(void);
-/*====================*/
-/*****************************************************************//**
Advises the os to give up remainder of the thread's time slice. */
UNIV_INTERN
void
@@ -136,29 +130,6 @@ void
os_thread_sleep(
/*============*/
ulint tm); /*!< in: time in microseconds */
-/******************************************************************//**
-Gets a thread priority.
-@return priority */
-UNIV_INTERN
-ulint
-os_thread_get_priority(
-/*===================*/
- os_thread_t handle);/*!< in: OS handle to the thread */
-/******************************************************************//**
-Sets a thread priority. */
-UNIV_INTERN
-void
-os_thread_set_priority(
-/*===================*/
- os_thread_t handle, /*!< in: OS handle to the thread */
- ulint pri); /*!< in: priority: one of OS_PRIORITY_... */
-/******************************************************************//**
-Gets the last operating system error code for the calling thread.
-@return last error on Windows, 0 otherwise */
-UNIV_INTERN
-ulint
-os_thread_get_last_error(void);
-/*==========================*/
#ifndef UNIV_NONINL
#include "os0thread.ic"
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index fb5bc56920a..fc9401a12f5 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -71,9 +71,6 @@ at a time */
#define SRV_AUTO_EXTEND_INCREMENT \
(srv_auto_extend_increment * ((1024 * 1024) / UNIV_PAGE_SIZE))
-/* This is set to the MySQL server value for this variable. */
-extern uint srv_lower_case_table_names;
-
/* Mutex for locking srv_monitor_file */
extern mutex_t srv_monitor_file_mutex;
/* Temporary file for innodb monitor output */
diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h
index a24c2106033..b823c9d5259 100644
--- a/storage/innobase/include/sync0sync.h
+++ b/storage/innobase/include/sync0sync.h
@@ -413,13 +413,6 @@ sync_thread_reset_level(
/*====================*/
void* latch); /*!< in: pointer to a mutex or an rw-lock */
/******************************************************************//**
-Checks that the level array for the current thread is empty.
-@return TRUE if empty */
-UNIV_INTERN
-ibool
-sync_thread_levels_empty(void);
-/*==========================*/
-/******************************************************************//**
Checks if the level array for the current thread contains a
mutex or rw-latch at the specified level.
@return a matching latch, or NULL if not found */
@@ -430,17 +423,33 @@ sync_thread_levels_contains(
ulint level); /*!< in: latching order level
(SYNC_DICT, ...)*/
/******************************************************************//**
-Checks if the level array for the current thread is empty.
+Checks that the level array for the current thread is empty.
@return a latch, or NULL if empty except the exceptions specified below */
UNIV_INTERN
void*
sync_thread_levels_nonempty_gen(
/*============================*/
- ibool dict_mutex_allowed); /*!< in: TRUE if dictionary mutex is
- allowed to be owned by the thread,
- also purge_is_running mutex is
- allowed */
-#define sync_thread_levels_empty_gen(d) (!sync_thread_levels_nonempty_gen(d))
+ ibool dict_mutex_allowed) /*!< in: TRUE if dictionary mutex is
+ allowed to be owned by the thread */
+ __attribute__((warn_unused_result));
+/******************************************************************//**
+Checks if the level array for the current thread is empty,
+except for data dictionary latches. */
+#define sync_thread_levels_empty_except_dict() \
+ (!sync_thread_levels_nonempty_gen(TRUE))
+/******************************************************************//**
+Checks if the level array for the current thread is empty,
+except for the btr_search_latch.
+@return a latch, or NULL if empty except the exceptions specified below */
+UNIV_INTERN
+void*
+sync_thread_levels_nonempty_trx(
+/*============================*/
+ ibool has_search_latch)
+ /*!< in: TRUE if and only if the thread
+ is supposed to hold btr_search_latch */
+ __attribute__((warn_unused_result));
+
/******************************************************************//**
Gets the debug information for a reserved mutex. */
UNIV_INTERN
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index 83f6182c347..588ddd65e88 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -44,6 +44,9 @@ extern sess_t* trx_dummy_sess;
/** Number of transactions currently allocated for MySQL: protected by
the kernel mutex */
extern ulint trx_n_mysql_transactions;
+/** Number of transactions currently in the XA PREPARED state: protected by
+the kernel mutex */
+extern ulint trx_n_prepared;
/********************************************************************//**
Releases the search latch if trx has reserved it. */
@@ -108,6 +111,14 @@ trx_free(
/*=====*/
trx_t* trx); /*!< in, own: trx object */
/********************************************************************//**
+At shutdown, frees a transaction object that is in the PREPARED state. */
+UNIV_INTERN
+void
+trx_free_prepared(
+/*==============*/
+ trx_t* trx) /*!< in, own: trx object */
+ UNIV_COLD __attribute__((nonnull));
+/********************************************************************//**
Frees a transaction object for MySQL. */
UNIV_INTERN
void
@@ -569,11 +580,6 @@ struct trx_struct{
ib_int64_t mysql_log_offset;/* if MySQL binlog is used, this field
contains the end offset of the binlog
entry */
- os_thread_id_t mysql_thread_id;/* id of the MySQL thread associated
- with this transaction object */
- ulint mysql_process_no;/* since in Linux, 'top' reports
- process id's and not thread id's, we
- store the process number too */
/*------------------------------*/
ulint n_mysql_tables_in_use; /* number of Innobase tables
used in the processing of the current
diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h
index 937e9d7ef79..df16c939070 100644
--- a/storage/innobase/include/trx0undo.h
+++ b/storage/innobase/include/trx0undo.h
@@ -296,6 +296,15 @@ void
trx_undo_insert_cleanup(
/*====================*/
trx_t* trx); /*!< in: transaction handle */
+
+/********************************************************************//**
+At shutdown, frees the undo logs of a PREPARED transaction. */
+UNIV_INTERN
+void
+trx_undo_free_prepared(
+/*===================*/
+ trx_t* trx) /*!< in/out: PREPARED transaction */
+ UNIV_COLD __attribute__((nonnull));
#endif /* !UNIV_HOTBACKUP */
/***********************************************************//**
Parses the redo log entry of an undo log page initialization.
diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i
index f561226a2de..9816edc2eaa 100644
--- a/storage/innobase/include/univ.i
+++ b/storage/innobase/include/univ.i
@@ -51,7 +51,7 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_MAJOR 1
#define INNODB_VERSION_MINOR 1
-#define INNODB_VERSION_BUGFIX 6
+#define INNODB_VERSION_BUGFIX 7
/* The following is the InnoDB version as shown in
SELECT plugin_version FROM information_schema.plugins;
@@ -255,6 +255,19 @@ easy way to get it to work. See http://bugs.mysql.com/bug.php?id=52263. */
#else
# define UNIV_INTERN
#endif
+#if defined __GNUC__ && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 3)
+/** Starting with GCC 4.3, the "cold" attribute is used to inform the
+compiler that a function is unlikely executed. The function is
+optimized for size rather than speed and on many targets it is placed
+into special subsection of the text section so all cold functions
+appears close together improving code locality of non-cold parts of
+program. The paths leading to call of cold functions within code are
+marked as unlikely by the branch prediction mechanism. optimize a
+rarely invoked function for size instead for speed. */
+# define UNIV_COLD __attribute__((cold))
+#else
+# define UNIV_COLD /* empty */
+#endif
#ifndef UNIV_MUST_NOT_INLINE
/* Definition for inline version */
diff --git a/storage/innobase/include/ut0dbg.h b/storage/innobase/include/ut0dbg.h
index d7ec90db0fb..07730176d81 100644
--- a/storage/innobase/include/ut0dbg.h
+++ b/storage/innobase/include/ut0dbg.h
@@ -50,9 +50,10 @@ UNIV_INTERN
void
ut_dbg_assertion_failed(
/*====================*/
- const char* expr, /*!< in: the failed assertion */
- const char* file, /*!< in: source file containing the assertion */
- ulint line); /*!< in: line number of the assertion */
+ const char* expr, /*!< in: the failed assertion */
+ const char* file, /*!< in: source file containing the assertion */
+ ulint line) /*!< in: line number of the assertion */
+ UNIV_COLD __attribute__((nonnull(2)));
#if defined(__WIN__) || defined(__INTEL_COMPILER)
# undef UT_DBG_USE_ABORT
diff --git a/storage/innobase/include/ut0ut.h b/storage/innobase/include/ut0ut.h
index cd5c7ca99f1..cad39e9a34f 100644
--- a/storage/innobase/include/ut0ut.h
+++ b/storage/innobase/include/ut0ut.h
@@ -275,7 +275,8 @@ UNIV_INTERN
void
ut_print_timestamp(
/*===============*/
- FILE* file); /*!< in: file where to print */
+ FILE* file) /*!< in: file where to print */
+ UNIV_COLD __attribute__((nonnull));
/**********************************************************//**
Sprintfs a timestamp to a buffer, 13..14 chars plus terminating NUL. */
UNIV_INTERN
diff --git a/storage/innobase/log/log0log.c b/storage/innobase/log/log0log.c
index 3fef4ee4fc5..fd2258945b6 100644
--- a/storage/innobase/log/log0log.c
+++ b/storage/innobase/log/log0log.c
@@ -3078,6 +3078,7 @@ logs_empty_and_mark_files_at_shutdown(void)
{
ib_uint64_t lsn;
ulint arch_log_no;
+ ibool server_busy;
if (srv_print_verbose_log) {
ut_print_timestamp(stderr);
@@ -3092,14 +3093,12 @@ loop:
mutex_enter(&kernel_mutex);
- /* We need the monitor threads to stop before we proceed with a
- normal shutdown. In case of very fast shutdown, however, we can
- proceed without waiting for monitor threads. */
+ /* We need the monitor threads to stop before we proceed with
+ a shutdown. */
- if (srv_fast_shutdown < 2
- && (srv_error_monitor_active
- || srv_lock_timeout_active
- || srv_monitor_active)) {
+ if (srv_error_monitor_active
+ || srv_lock_timeout_active
+ || srv_monitor_active) {
mutex_exit(&kernel_mutex);
@@ -3110,69 +3109,70 @@ loop:
goto loop;
}
- /* Check that there are no longer transactions. We need this wait even
- for the 'very fast' shutdown, because the InnoDB layer may have
- committed or prepared transactions and we don't want to lose them. */
-
- if (trx_n_mysql_transactions > 0
- || UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
-
- mutex_exit(&kernel_mutex);
-
- goto loop;
- }
-
- if (srv_fast_shutdown == 2) {
- /* In this fastest shutdown we do not flush the buffer pool:
- it is essentially a 'crash' of the InnoDB server. Make sure
- that the log is all flushed to disk, so that we can recover
- all committed transactions in a crash recovery. We must not
- write the lsn stamps to the data files, since at a startup
- InnoDB deduces from the stamps if the previous shutdown was
- clean. */
-
- log_buffer_flush_to_disk();
-
- mutex_exit(&kernel_mutex);
-
- return; /* We SKIP ALL THE REST !! */
- }
+ /* Check that there are no longer transactions, except for
+ PREPARED ones. We need this wait even for the 'very fast'
+ shutdown, because the InnoDB layer may have committed or
+ prepared transactions and we don't want to lose them. */
+ server_busy = trx_n_mysql_transactions > 0
+ || UT_LIST_GET_LEN(trx_sys->trx_list) > trx_n_prepared;
mutex_exit(&kernel_mutex);
- /* Check that the background threads are suspended */
-
- if (srv_is_any_background_thread_active()) {
+ if (server_busy || srv_is_any_background_thread_active()) {
goto loop;
}
- mutex_enter(&(log_sys->mutex));
-
- if (log_sys->n_pending_checkpoint_writes
+ mutex_enter(&log_sys->mutex);
+ server_busy = log_sys->n_pending_checkpoint_writes
#ifdef UNIV_LOG_ARCHIVE
- || log_sys->n_pending_archive_ios
+ || log_sys->n_pending_archive_ios
#endif /* UNIV_LOG_ARCHIVE */
- || log_sys->n_pending_writes) {
-
- mutex_exit(&(log_sys->mutex));
-
- goto loop;
- }
-
- mutex_exit(&(log_sys->mutex));
-
- if (!buf_pool_check_no_pending_io()) {
+ || log_sys->n_pending_writes;
+ mutex_exit(&log_sys->mutex);
+ if (server_busy || !buf_pool_check_no_pending_io()) {
goto loop;
}
#ifdef UNIV_LOG_ARCHIVE
log_archive_all();
#endif /* UNIV_LOG_ARCHIVE */
+ if (srv_fast_shutdown == 2) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: MySQL has requested a very fast shutdown"
+ " without flushing "
+ "the InnoDB buffer pool to data files."
+ " At the next mysqld startup "
+ "InnoDB will do a crash recovery!\n");
+
+ /* In this fastest shutdown we do not flush the buffer
+ pool: it is essentially a 'crash' of the InnoDB
+ server. Make sure that the log is all flushed to disk,
+ so that we can recover all committed transactions in a
+ crash recovery. We must not write the lsn stamps to
+ the data files, since at a startup InnoDB deduces from
+ the stamps if the previous shutdown was clean. */
+
+ log_buffer_flush_to_disk();
+
+ /* Check that the background threads stay suspended */
+ if (srv_is_any_background_thread_active()) {
+ fprintf(stderr,
+ "InnoDB: Warning: some background thread"
+ " woke up during shutdown\n");
+ goto loop;
+ }
+
+ srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE;
+ fil_close_all_files();
+ ut_a(!srv_is_any_background_thread_active());
+ return;
+ }
log_make_checkpoint_at(IB_ULONGLONG_MAX, TRUE);
- mutex_enter(&(log_sys->mutex));
+ mutex_enter(&log_sys->mutex);
lsn = log_sys->lsn;
@@ -3183,7 +3183,7 @@ loop:
#endif /* UNIV_LOG_ARCHIVE */
) {
- mutex_exit(&(log_sys->mutex));
+ mutex_exit(&log_sys->mutex);
goto loop;
}
@@ -3201,7 +3201,7 @@ loop:
log_archive_close_groups(TRUE);
#endif /* UNIV_LOG_ARCHIVE */
- mutex_exit(&(log_sys->mutex));
+ mutex_exit(&log_sys->mutex);
/* Check that the background threads stay suspended */
if (srv_is_any_background_thread_active()) {
diff --git a/storage/innobase/os/os0file.c b/storage/innobase/os/os0file.c
index 74dbac3bc96..50607e07076 100644
--- a/storage/innobase/os/os0file.c
+++ b/storage/innobase/os/os0file.c
@@ -4064,13 +4064,13 @@ os_aio_func(
}
try_again:
- if (mode == OS_AIO_NORMAL) {
- if (type == OS_FILE_READ) {
- array = os_aio_read_array;
- } else {
- array = os_aio_write_array;
- }
- } else if (mode == OS_AIO_IBUF) {
+ switch (mode) {
+ case OS_AIO_NORMAL:
+ array = (type == OS_FILE_READ)
+ ? os_aio_read_array
+ : os_aio_write_array;
+ break;
+ case OS_AIO_IBUF:
ut_ad(type == OS_FILE_READ);
/* Reduce probability of deadlock bugs in connection with ibuf:
do not let the ibuf i/o handler sleep */
@@ -4078,19 +4078,21 @@ try_again:
wake_later = FALSE;
array = os_aio_ibuf_array;
- } else if (mode == OS_AIO_LOG) {
-
+ break;
+ case OS_AIO_LOG:
array = os_aio_log_array;
- } else if (mode == OS_AIO_SYNC) {
+ break;
+ case OS_AIO_SYNC:
array = os_aio_sync_array;
#if defined(LINUX_NATIVE_AIO)
/* In Linux native AIO we don't use sync IO array. */
ut_a(!srv_use_native_aio);
#endif /* LINUX_NATIVE_AIO */
- } else {
- array = NULL; /* Eliminate compiler warning */
+ break;
+ default:
ut_error;
+ array = NULL; /* Eliminate compiler warning */
}
slot = os_aio_array_reserve_slot(type, array, message1, message2, file,
@@ -4253,11 +4255,17 @@ os_aio_windows_handle(
INFINITE);
}
- if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
- os_thread_exit(NULL);
+ os_mutex_enter(array->mutex);
+
+ if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS
+ && array->n_reserved == 0) {
+ *message1 = NULL;
+ *message2 = NULL;
+ os_mutex_exit(array->mutex);
+ return(TRUE);
}
- os_mutex_enter(array->mutex);
+ ut_a(i >= WAIT_OBJECT_0 && i <= WAIT_OBJECT_0 + n);
slot = os_aio_array_get_nth_slot(array, i + segment * n);
@@ -4403,14 +4411,6 @@ os_aio_linux_collect(
retry:
- /* Go down if we are in shutdown mode.
- In case of srv_fast_shutdown == 2, there may be pending
- IO requests but that should be OK as we essentially treat
- that as a crash of InnoDB. */
- if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
- os_thread_exit(NULL);
- }
-
/* Initialize the events. The timeout value is arbitrary.
We probably need to experiment with it a little. */
memset(events, 0, sizeof(*events) * seg_size);
@@ -4419,76 +4419,72 @@ retry:
ret = io_getevents(io_ctx, 1, seg_size, events, &timeout);
- /* This error handling is for any error in collecting the
- IO requests. The errors, if any, for any particular IO
- request are simply passed on to the calling routine. */
-
- /* Not enough resources! Try again. */
- if (ret == -EAGAIN) {
- goto retry;
- }
-
- /* Interrupted! I have tested the behaviour in case of an
- interrupt. If we have some completed IOs available then
- the return code will be the number of IOs. We get EINTR only
- if there are no completed IOs and we have been interrupted. */
- if (ret == -EINTR) {
- goto retry;
- }
-
- /* No pending request! Go back and check again. */
- if (ret == 0) {
- goto retry;
- }
+ if (ret > 0) {
+ for (i = 0; i < ret; i++) {
+ os_aio_slot_t* slot;
+ struct iocb* control;
- /* All other errors! should cause a trap for now. */
- if (UNIV_UNLIKELY(ret < 0)) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: unexpected ret_code[%d] from"
- " io_getevents()!\n", ret);
- ut_error;
- }
+ control = (struct iocb *)events[i].obj;
+ ut_a(control != NULL);
- ut_a(ret > 0);
+ slot = (os_aio_slot_t *) control->data;
- for (i = 0; i < ret; i++) {
- os_aio_slot_t* slot;
- struct iocb* control;
+ /* Some sanity checks. */
+ ut_a(slot != NULL);
+ ut_a(slot->reserved);
- control = (struct iocb *)events[i].obj;
- ut_a(control != NULL);
+#if defined(UNIV_AIO_DEBUG)
+ fprintf(stderr,
+ "io_getevents[%c]: slot[%p] ctx[%p]"
+ " seg[%lu]\n",
+ (slot->type == OS_FILE_WRITE) ? 'w' : 'r',
+ slot, io_ctx, segment);
+#endif
- slot = (os_aio_slot_t *) control->data;
+ /* We are not scribbling previous segment. */
+ ut_a(slot->pos >= start_pos);
- /* Some sanity checks. */
- ut_a(slot != NULL);
- ut_a(slot->reserved);
+ /* We have not overstepped to next segment. */
+ ut_a(slot->pos < end_pos);
-#if defined(UNIV_AIO_DEBUG)
- fprintf(stderr,
- "io_getevents[%c]: slot[%p] ctx[%p]"
- " seg[%lu]\n",
- (slot->type == OS_FILE_WRITE) ? 'w' : 'r',
- slot, io_ctx, segment);
-#endif
+ /* Mark this request as completed. The error handling
+ will be done in the calling function. */
+ os_mutex_enter(array->mutex);
+ slot->n_bytes = events[i].res;
+ slot->ret = events[i].res2;
+ slot->io_already_done = TRUE;
+ os_mutex_exit(array->mutex);
+ }
+ return;
+ }
- /* We are not scribbling previous segment. */
- ut_a(slot->pos >= start_pos);
+ if (UNIV_UNLIKELY(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS)) {
+ return;
+ }
- /* We have not overstepped to next segment. */
- ut_a(slot->pos < end_pos);
+ /* This error handling is for any error in collecting the
+ IO requests. The errors, if any, for any particular IO
+ request are simply passed on to the calling routine. */
- /* Mark this request as completed. The error handling
- will be done in the calling function. */
- os_mutex_enter(array->mutex);
- slot->n_bytes = events[i].res;
- slot->ret = events[i].res2;
- slot->io_already_done = TRUE;
- os_mutex_exit(array->mutex);
+ switch (ret) {
+ case -EAGAIN:
+ /* Not enough resources! Try again. */
+ case -EINTR:
+ /* Interrupted! I have tested the behaviour in case of an
+ interrupt. If we have some completed IOs available then
+ the return code will be the number of IOs. We get EINTR only
+ if there are no completed IOs and we have been interrupted. */
+ case 0:
+ /* No pending request! Go back and check again. */
+ goto retry;
}
- return;
+ /* All other errors should cause a trap for now. */
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: unexpected ret_code[%d] from io_getevents()!\n",
+ ret);
+ ut_error;
}
/**********************************************************************//**
@@ -4532,20 +4528,35 @@ os_aio_linux_handle(
/* Loop until we have found a completed request. */
for (;;) {
+ ibool any_reserved = FALSE;
os_mutex_enter(array->mutex);
for (i = 0; i < n; ++i) {
slot = os_aio_array_get_nth_slot(
- array, i + segment * n);
- if (slot->reserved && slot->io_already_done) {
+ array, i + segment * n);
+ if (!slot->reserved) {
+ continue;
+ } else if (slot->io_already_done) {
/* Something for us to work on. */
goto found;
+ } else {
+ any_reserved = TRUE;
}
}
os_mutex_exit(array->mutex);
- /* We don't have any completed request.
- Wait for some request. Note that we return
+ /* There is no completed request.
+ If there is no pending request at all,
+ and the system is being shut down, exit. */
+ if (UNIV_UNLIKELY
+ (!any_reserved
+ && srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS)) {
+ *message1 = NULL;
+ *message2 = NULL;
+ return(TRUE);
+ }
+
+ /* Wait for some request. Note that we return
from wait iff we have found a request. */
srv_set_io_thread_op_info(global_seg,
@@ -4641,6 +4652,7 @@ os_aio_simulated_handle(
byte* combined_buf;
byte* combined_buf2;
ibool ret;
+ ibool any_reserved;
ulint n;
ulint i;
@@ -4671,18 +4683,21 @@ restart:
goto recommended_sleep;
}
- os_mutex_enter(array->mutex);
-
srv_set_io_thread_op_info(global_segment,
"looking for i/o requests (b)");
/* Check if there is a slot for which the i/o has already been
done */
+ any_reserved = FALSE;
+
+ os_mutex_enter(array->mutex);
for (i = 0; i < n; i++) {
slot = os_aio_array_get_nth_slot(array, i + segment * n);
- if (slot->reserved && slot->io_already_done) {
+ if (!slot->reserved) {
+ continue;
+ } else if (slot->io_already_done) {
if (os_aio_print_debug) {
fprintf(stderr,
@@ -4694,9 +4709,23 @@ restart:
ret = TRUE;
goto slot_io_done;
+ } else {
+ any_reserved = TRUE;
}
}
+ /* There is no completed request.
+ If there is no pending request at all,
+ and the system is being shut down, exit. */
+ if (UNIV_UNLIKELY
+ (!any_reserved
+ && srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS)) {
+ os_mutex_exit(array->mutex);
+ *message1 = NULL;
+ *message2 = NULL;
+ return(TRUE);
+ }
+
n_consecutive = 0;
/* If there are at least 2 seconds old requests, then pick the oldest
diff --git a/storage/innobase/os/os0sync.c b/storage/innobase/os/os0sync.c
index b461f9b7c78..41a19843812 100644
--- a/storage/innobase/os/os0sync.c
+++ b/storage/innobase/os/os0sync.c
@@ -558,10 +558,7 @@ os_event_free(
}
/**********************************************************//**
-Waits for an event object until it is in the signaled state. If
-srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS this also exits the
-waiting thread when the event becomes signaled (or immediately if the
-event is already in the signaled state).
+Waits for an event object until it is in the signaled state.
Typically, if the event has been signalled after the os_event_reset()
we'll return immediately because event->is_set == TRUE.
@@ -586,8 +583,6 @@ os_event_wait_low(
returned by previous call of
os_event_reset(). */
{
- ib_int64_t old_signal_count;
-
#ifdef __WIN__
if(!srv_use_native_conditions) {
DWORD err;
@@ -600,43 +595,25 @@ os_event_wait_low(
err = WaitForSingleObject(event->handle, INFINITE);
ut_a(err == WAIT_OBJECT_0);
-
- if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
- os_thread_exit(NULL);
- }
return;
}
#endif
- os_fast_mutex_lock(&(event->os_mutex));
+ os_fast_mutex_lock(&event->os_mutex);
- if (reset_sig_count) {
- old_signal_count = reset_sig_count;
- } else {
- old_signal_count = event->signal_count;
+ if (!reset_sig_count) {
+ reset_sig_count = event->signal_count;
}
- for (;;) {
- if (event->is_set == TRUE
- || event->signal_count != old_signal_count) {
-
- os_fast_mutex_unlock(&(event->os_mutex));
-
- if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
-
- os_thread_exit(NULL);
- }
- /* Ok, we may return */
-
- return;
- }
-
+ while (!event->is_set && event->signal_count == reset_sig_count) {
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 */
}
+
+ os_fast_mutex_unlock(&event->os_mutex);
}
/**********************************************************//**
@@ -657,7 +634,6 @@ os_event_wait_time_low(
{
ibool timed_out = FALSE;
- ib_int64_t old_signal_count;
#ifdef __WIN__
DWORD time_in_ms;
@@ -727,15 +703,12 @@ os_event_wait_time_low(
os_fast_mutex_lock(&event->os_mutex);
- if (reset_sig_count) {
- old_signal_count = reset_sig_count;
- } else {
- old_signal_count = event->signal_count;
+ if (!reset_sig_count) {
+ reset_sig_count = event->signal_count;
}
do {
- if (event->is_set == TRUE
- || event->signal_count != old_signal_count) {
+ if (event->is_set || event->signal_count != reset_sig_count) {
break;
}
@@ -753,11 +726,6 @@ os_event_wait_time_low(
os_fast_mutex_unlock(&event->os_mutex);
- if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
-
- os_thread_exit(NULL);
- }
-
return(timed_out ? OS_SYNC_TIME_EXCEEDED : 0);
}
diff --git a/storage/innobase/os/os0thread.c b/storage/innobase/os/os0thread.c
index adc876be5d5..12b6805d98e 100644
--- a/storage/innobase/os/os0thread.c
+++ b/storage/innobase/os/os0thread.c
@@ -220,21 +220,6 @@ os_thread_exit(
}
/*****************************************************************//**
-Returns handle to the current thread.
-@return current thread handle */
-UNIV_INTERN
-os_thread_t
-os_thread_get_curr(void)
-/*====================*/
-{
-#ifdef __WIN__
- return(GetCurrentThread());
-#else
- return(pthread_self());
-#endif
-}
-
-/*****************************************************************//**
Advises the os to give up remainder of the thread's time slice. */
UNIV_INTERN
void
@@ -274,81 +259,3 @@ os_thread_sleep(
select(0, NULL, NULL, NULL, &t);
#endif
}
-
-#ifndef UNIV_HOTBACKUP
-/******************************************************************//**
-Sets a thread priority. */
-UNIV_INTERN
-void
-os_thread_set_priority(
-/*===================*/
- os_thread_t handle, /*!< in: OS handle to the thread */
- ulint pri) /*!< in: priority */
-{
-#ifdef __WIN__
- int os_pri;
-
- if (pri == OS_THREAD_PRIORITY_BACKGROUND) {
- os_pri = THREAD_PRIORITY_BELOW_NORMAL;
- } else if (pri == OS_THREAD_PRIORITY_NORMAL) {
- os_pri = THREAD_PRIORITY_NORMAL;
- } else if (pri == OS_THREAD_PRIORITY_ABOVE_NORMAL) {
- os_pri = THREAD_PRIORITY_HIGHEST;
- } else {
- ut_error;
- }
-
- ut_a(SetThreadPriority(handle, os_pri));
-#else
- UT_NOT_USED(handle);
- UT_NOT_USED(pri);
-#endif
-}
-
-/******************************************************************//**
-Gets a thread priority.
-@return priority */
-UNIV_INTERN
-ulint
-os_thread_get_priority(
-/*===================*/
- os_thread_t handle __attribute__((unused)))
- /*!< in: OS handle to the thread */
-{
-#ifdef __WIN__
- int os_pri;
- ulint pri;
-
- os_pri = GetThreadPriority(handle);
-
- if (os_pri == THREAD_PRIORITY_BELOW_NORMAL) {
- pri = OS_THREAD_PRIORITY_BACKGROUND;
- } else if (os_pri == THREAD_PRIORITY_NORMAL) {
- pri = OS_THREAD_PRIORITY_NORMAL;
- } else if (os_pri == THREAD_PRIORITY_HIGHEST) {
- pri = OS_THREAD_PRIORITY_ABOVE_NORMAL;
- } else {
- ut_error;
- }
-
- return(pri);
-#else
- return(0);
-#endif
-}
-
-/******************************************************************//**
-Gets the last operating system error code for the calling thread.
-@return last error on Windows, 0 otherwise */
-UNIV_INTERN
-ulint
-os_thread_get_last_error(void)
-/*==========================*/
-{
-#ifdef __WIN__
- return(GetLastError());
-#else
- return(0);
-#endif
-}
-#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/row/row0merge.c b/storage/innobase/row/row0merge.c
index 03e37a8c4a4..5be437add5a 100644
--- a/storage/innobase/row/row0merge.c
+++ b/storage/innobase/row/row0merge.c
@@ -1929,7 +1929,6 @@ row_merge_lock_table(
sel_node_t* node;
ut_ad(trx);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_ad(mode == LOCK_X || mode == LOCK_S);
heap = mem_heap_create(512);
@@ -2390,7 +2389,6 @@ row_merge_rename_tables(
pars_info_t* info;
char old_name[MAX_FULL_NAME_LEN + 1];
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_ad(old_table != new_table);
ut_ad(mutex_own(&dict_sys->mutex));
diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
index 5fb4b4ac8c3..f7e5c5fdceb 100644
--- a/storage/innobase/row/row0mysql.c
+++ b/storage/innobase/row/row0mysql.c
@@ -976,7 +976,6 @@ row_lock_table_autoinc_for_mysql(
ibool was_lock_wait;
ut_ad(trx);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
/* If we already hold an AUTOINC lock on the table then do nothing.
Note: We peek at the value of the current owner without acquiring
@@ -1056,7 +1055,6 @@ row_lock_table_for_mysql(
ibool was_lock_wait;
ut_ad(trx);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
trx->op_info = "setting table lock";
@@ -1130,7 +1128,6 @@ row_insert_for_mysql(
ins_node_t* node = prebuilt->ins_node;
ut_ad(trx);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
if (prebuilt->table->ibd_file_missing) {
ut_print_timestamp(stderr);
@@ -1364,7 +1361,6 @@ row_update_for_mysql(
trx_t* trx = prebuilt->trx;
ut_ad(prebuilt && trx);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
UT_NOT_USED(mysql_rec);
if (prebuilt->table->ibd_file_missing) {
@@ -1532,7 +1528,6 @@ row_unlock_for_mysql(
trx_t* trx = prebuilt->trx;
ut_ad(prebuilt && trx);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
if (UNIV_UNLIKELY
(!srv_locks_unsafe_for_binlog
@@ -1834,7 +1829,6 @@ row_create_table_for_mysql(
ulint table_name_len;
ulint err;
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
@@ -2008,7 +2002,6 @@ row_create_index_for_mysql(
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
ut_ad(mutex_own(&(dict_sys->mutex)));
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
trx->op_info = "creating index";
@@ -2411,8 +2404,6 @@ row_discard_tablespace_for_mysql(
table->n_foreign_key_checks_running > 0, we do not allow the
discard. We also reserve the data dictionary latch. */
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
-
trx->op_info = "discarding tablespace";
trx_start_if_not_started(trx);
@@ -2571,8 +2562,6 @@ row_import_tablespace_for_mysql(
ib_uint64_t current_lsn;
ulint err = DB_SUCCESS;
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
-
trx_start_if_not_started(trx);
trx->op_info = "importing tablespace";
@@ -2756,7 +2745,6 @@ row_truncate_table_for_mysql(
redo log records on the truncated tablespace, we will assign
a new tablespace identifier to the truncated tablespace. */
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_ad(table);
if (srv_created_new_raw) {
@@ -3607,7 +3595,6 @@ row_drop_database_for_mysql(
int err = DB_SUCCESS;
ulint namelen = strlen(name);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_a(name != NULL);
ut_a(name[namelen - 1] == '/');
@@ -3777,7 +3764,6 @@ row_rename_table_for_mysql(
ibool old_is_tmp, new_is_tmp;
pars_info_t* info = NULL;
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_a(old_name != NULL);
ut_a(new_name != NULL);
diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c
index 14deff2d465..66aff528f38 100644
--- a/storage/innobase/row/row0sel.c
+++ b/storage/innobase/row/row0sel.c
@@ -1951,7 +1951,7 @@ stop_for_a_while:
mtr_commit(&mtr);
#ifdef UNIV_SYNC_DEBUG
- ut_ad(sync_thread_levels_empty_gen(TRUE));
+ ut_ad(sync_thread_levels_empty_except_dict());
#endif /* UNIV_SYNC_DEBUG */
err = DB_SUCCESS;
goto func_exit;
@@ -1971,7 +1971,7 @@ commit_mtr_for_a_while:
mtr_has_extra_clust_latch = FALSE;
#ifdef UNIV_SYNC_DEBUG
- ut_ad(sync_thread_levels_empty_gen(TRUE));
+ ut_ad(sync_thread_levels_empty_except_dict());
#endif /* UNIV_SYNC_DEBUG */
goto table_loop;
@@ -1988,7 +1988,7 @@ lock_wait_or_error:
mtr_commit(&mtr);
#ifdef UNIV_SYNC_DEBUG
- ut_ad(sync_thread_levels_empty_gen(TRUE));
+ ut_ad(sync_thread_levels_empty_except_dict());
#endif /* UNIV_SYNC_DEBUG */
func_exit:
@@ -3370,7 +3370,6 @@ row_search_for_mysql(
rec_offs_init(offsets_);
ut_ad(index && pcur && search_tuple);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
if (UNIV_UNLIKELY(prebuilt->table->ibd_file_missing)) {
ut_print_timestamp(stderr);
@@ -3387,11 +3386,17 @@ row_search_for_mysql(
"InnoDB: how you can resolve the problem.\n",
prebuilt->table->name);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
return(DB_ERROR);
}
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
return(DB_MISSING_HISTORY);
}
@@ -4680,6 +4685,10 @@ func_exit:
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
}
}
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
return(err);
}
diff --git a/storage/innobase/srv/srv0srv.c b/storage/innobase/srv/srv0srv.c
index 3af7a86a164..23e690b1105 100644
--- a/storage/innobase/srv/srv0srv.c
+++ b/storage/innobase/srv/srv0srv.c
@@ -86,12 +86,6 @@ Created 10/8/1995 Heikki Tuuri
#include "mysql/plugin.h"
#include "mysql/service_thd_wait.h"
-/* This is set to the MySQL server value for this variable. It is only
-needed for FOREIGN KEY definition parsing since FOREIGN KEY names are not
-stored in the server metadata. The server stores and enforces it for
-regular database and table names.*/
-UNIV_INTERN uint srv_lower_case_table_names = 0;
-
/* The following counter is incremented whenever there is some user activity
in the server */
UNIV_INTERN ulint srv_activity_count = 0;
@@ -687,8 +681,6 @@ Unix.*/
/* Thread slot in the thread table */
struct srv_slot_struct{
- os_thread_id_t id; /*!< thread id */
- os_thread_t handle; /*!< thread handle */
unsigned type:1; /*!< thread type: user, utility etc. */
unsigned in_use:1; /*!< TRUE if this slot is in use */
unsigned suspended:1; /*!< TRUE if the thread is waiting
@@ -887,8 +879,6 @@ srv_table_reserve_slot(
slot->suspended = FALSE;
slot->type = type;
ut_ad(srv_slot_get_type(slot) == type);
- slot->id = os_thread_get_curr_id();
- slot->handle = os_thread_get_curr();
return(slot);
}
@@ -907,7 +897,6 @@ srv_suspend_thread(
ut_ad(mutex_own(&kernel_mutex));
ut_ad(slot->in_use);
ut_ad(!slot->suspended);
- ut_ad(slot->id == os_thread_get_curr_id());
if (srv_print_thread_releases) {
fprintf(stderr,
@@ -962,10 +951,9 @@ srv_release_threads(
if (srv_print_thread_releases) {
fprintf(stderr,
- "Releasing thread %lu type %lu"
+ "Releasing thread type %lu"
" from slot %lu\n",
- (ulong) slot->id, (ulong) type,
- (ulong) i);
+ (ulong) type, (ulong) i);
}
count++;
@@ -1149,6 +1137,10 @@ srv_conc_enter_innodb(
srv_conc_slot_t* slot = NULL;
ulint i;
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
+
if (trx->mysql_thd != NULL
&& thd_is_replication_slave_thread(trx->mysql_thd)) {
@@ -1272,6 +1264,10 @@ retry:
/* Go to wait for the event; when a thread leaves InnoDB it will
release this thread */
+ ut_ad(!trx->has_search_latch);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
trx->op_info = "waiting in InnoDB queue";
thd_wait_begin(trx->mysql_thd, THD_WAIT_ROW_TABLE_LOCK);
@@ -1307,6 +1303,10 @@ srv_conc_force_enter_innodb(
trx_t* trx) /*!< in: transaction object associated with the
thread */
{
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
+
if (UNIV_LIKELY(!srv_thread_concurrency)) {
return;
@@ -1378,6 +1378,10 @@ srv_conc_force_exit_innodb(
if (slot != NULL) {
os_event_set(slot->event);
}
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
}
/*********************************************************************//**
@@ -1389,6 +1393,10 @@ srv_conc_exit_innodb(
trx_t* trx) /*!< in: transaction object associated with the
thread */
{
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
+
if (trx->n_tickets_to_enter_innodb > 0) {
/* We will pretend the thread is still inside InnoDB though it
now leaves the InnoDB engine. In this way we save
@@ -1505,10 +1513,9 @@ srv_table_reserve_slot_for_mysql(void)
slot = srv_mysql_table + i;
fprintf(stderr,
- "Slot %lu: thread id %lu, type %lu,"
+ "Slot %lu: thread type %lu,"
" in use %lu, susp %lu, time %lu\n",
(ulong) i,
- (ulong) os_thread_pf(slot->id),
(ulong) slot->type,
(ulong) slot->in_use,
(ulong) slot->suspended,
@@ -1525,8 +1532,6 @@ srv_table_reserve_slot_for_mysql(void)
ut_a(slot->in_use == FALSE);
slot->in_use = TRUE;
- slot->id = os_thread_get_curr_id();
- slot->handle = os_thread_get_curr();
return(slot);
}
@@ -1613,17 +1618,6 @@ srv_suspend_mysql_thread(
mutex_exit(&kernel_mutex);
- if (trx->declared_to_be_inside_innodb) {
-
- was_declared_inside_innodb = TRUE;
-
- /* We must declare this OS thread to exit InnoDB, since a
- possible other thread holding a lock which this thread waits
- for must be allowed to enter, sooner or later */
-
- srv_conc_force_exit_innodb(trx);
- }
-
had_dict_lock = trx->dict_operation_lock_mode;
switch (had_dict_lock) {
@@ -1651,12 +1645,34 @@ srv_suspend_mysql_thread(
ut_a(trx->dict_operation_lock_mode == 0);
+ if (trx->declared_to_be_inside_innodb) {
+
+ was_declared_inside_innodb = TRUE;
+
+ /* We must declare this OS thread to exit InnoDB, since a
+ possible other thread holding a lock which this thread waits
+ for must be allowed to enter, sooner or later */
+
+ srv_conc_force_exit_innodb(trx);
+ }
+
/* Suspend this thread and wait for the event. */
thd_wait_begin(trx->mysql_thd, THD_WAIT_ROW_TABLE_LOCK);
os_event_wait(event);
thd_wait_end(trx->mysql_thd);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
+
+ if (was_declared_inside_innodb) {
+
+ /* Return back inside InnoDB */
+
+ srv_conc_force_enter_innodb(trx);
+ }
+
/* After resuming, reacquire the data dictionary latch if
necessary. */
@@ -1672,13 +1688,6 @@ srv_suspend_mysql_thread(
break;
}
- if (was_declared_inside_innodb) {
-
- /* Return back inside InnoDB */
-
- srv_conc_force_enter_innodb(trx);
- }
-
mutex_enter(&kernel_mutex);
/* Release the slot for others to use */
@@ -3067,11 +3076,7 @@ suspend_thread:
os_event_wait(slot->event);
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
- /* This is only extra safety, the thread should exit
- already when the event wait ends */
-
os_thread_exit(NULL);
-
}
/* When there is user activity, InnoDB will set the event and the
diff --git a/storage/innobase/srv/srv0start.c b/storage/innobase/srv/srv0start.c
index 79eae610a05..cf11e75b8e0 100644
--- a/storage/innobase/srv/srv0start.c
+++ b/storage/innobase/srv/srv0start.c
@@ -2097,17 +2097,6 @@ innobase_shutdown_for_mysql(void)
The step 1 is the real InnoDB shutdown. The remaining steps 2 - ...
just free data structures after the shutdown. */
-
- if (srv_fast_shutdown == 2) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: MySQL has requested a very fast shutdown"
- " without flushing "
- "the InnoDB buffer pool to data files."
- " At the next mysqld startup "
- "InnoDB will do a crash recovery!\n");
- }
-
logs_empty_and_mark_files_at_shutdown();
if (srv_conc_n_threads != 0) {
@@ -2122,17 +2111,9 @@ innobase_shutdown_for_mysql(void)
srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS;
- /* In a 'very fast' shutdown, we do not need to wait for these threads
- to die; all which counts is that we flushed the log; a 'very fast'
- shutdown is essentially a crash. */
-
- if (srv_fast_shutdown == 2) {
- return(DB_SUCCESS);
- }
-
/* All threads end up waiting for certain events. Put those events
- to the signaled state. Then the threads will exit themselves in
- os_thread_event_wait(). */
+ to the signaled state. Then the threads will exit themselves after
+ os_event_wait(). */
for (i = 0; i < 1000; i++) {
/* NOTE: IF YOU CREATE THREADS IN INNODB, YOU MUST EXIT THEM
diff --git a/storage/innobase/sync/sync0sync.c b/storage/innobase/sync/sync0sync.c
index 23fd64cc5ed..0b56e736209 100644
--- a/storage/innobase/sync/sync0sync.c
+++ b/storage/innobase/sync/sync0sync.c
@@ -189,12 +189,12 @@ UNIV_INTERN sync_array_t* sync_primary_wait_array;
/** This variable is set to TRUE when sync_init is called */
UNIV_INTERN ibool sync_initialized = FALSE;
+#ifdef UNIV_SYNC_DEBUG
/** An acquired mutex or rw-lock and its level in the latching order */
typedef struct sync_level_struct sync_level_t;
/** Mutexes or rw-locks held by a thread */
typedef struct sync_thread_struct sync_thread_t;
-#ifdef UNIV_SYNC_DEBUG
/** The latch levels currently owned by threads are stored in this data
structure; the size of this array is OS_THREAD_MAX_N */
@@ -221,7 +221,6 @@ UNIV_INTERN mysql_pfs_key_t mutex_list_mutex_key;
#ifdef UNIV_SYNC_DEBUG
/** Latching order checks start when this is set TRUE */
UNIV_INTERN ibool sync_order_checks_on = FALSE;
-#endif /* UNIV_SYNC_DEBUG */
/** Number of slots reserved for each OS thread in the sync level array */
static const ulint SYNC_THREAD_N_LEVELS = 10000;
@@ -258,6 +257,7 @@ struct sync_level_struct{
the ordinal value of the next free
element */
};
+#endif /* UNIV_SYNC_DEBUG */
/******************************************************************//**
Creates, or rather, initializes a mutex object in a specified memory
@@ -1020,9 +1020,7 @@ void*
sync_thread_levels_nonempty_gen(
/*============================*/
ibool dict_mutex_allowed) /*!< in: TRUE if dictionary mutex is
- allowed to be owned by the thread,
- also purge_is_running mutex is
- allowed */
+ allowed to be owned by the thread */
{
ulint i;
sync_arr_t* arr;
@@ -1069,14 +1067,61 @@ sync_thread_levels_nonempty_gen(
}
/******************************************************************//**
-Checks that the level array for the current thread is empty.
-@return TRUE if empty */
+Checks if the level array for the current thread is empty,
+except for the btr_search_latch.
+@return a latch, or NULL if empty except the exceptions specified below */
UNIV_INTERN
-ibool
-sync_thread_levels_empty(void)
-/*==========================*/
+void*
+sync_thread_levels_nonempty_trx(
+/*============================*/
+ ibool has_search_latch)
+ /*!< in: TRUE if and only if the thread
+ is supposed to hold btr_search_latch */
{
- return(sync_thread_levels_empty_gen(FALSE));
+ ulint i;
+ sync_arr_t* arr;
+ sync_thread_t* thread_slot;
+
+ if (!sync_order_checks_on) {
+
+ return(NULL);
+ }
+
+ ut_a(!has_search_latch
+ || sync_thread_levels_contains(SYNC_SEARCH_SYS));
+
+ mutex_enter(&sync_thread_mutex);
+
+ thread_slot = sync_thread_level_arrays_find_slot();
+
+ if (thread_slot == NULL) {
+
+ mutex_exit(&sync_thread_mutex);
+
+ return(NULL);
+ }
+
+ arr = thread_slot->levels;
+
+ for (i = 0; i < arr->n_elems; ++i) {
+ const sync_level_t* slot;
+
+ slot = &arr->elems[i];
+
+ if (slot->latch != NULL
+ && (!has_search_latch
+ || slot->level != SYNC_SEARCH_SYS)) {
+
+ mutex_exit(&sync_thread_mutex);
+ ut_error;
+
+ return(slot->latch);
+ }
+ }
+
+ mutex_exit(&sync_thread_mutex);
+
+ return(NULL);
}
/******************************************************************//**
diff --git a/storage/innobase/trx/trx0roll.c b/storage/innobase/trx/trx0roll.c
index f9d421e3705..b55471959ce 100644
--- a/storage/innobase/trx/trx0roll.c
+++ b/storage/innobase/trx/trx0roll.c
@@ -460,10 +460,6 @@ trx_rollback_active(
(ulong) rows_to_undo, unit);
mutex_exit(&kernel_mutex);
- trx->mysql_thread_id = os_thread_get_curr_id();
-
- trx->mysql_process_no = os_proc_get_number();
-
if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
row_mysql_lock_data_dictionary(trx);
dictionary_locked = TRUE;
diff --git a/storage/innobase/trx/trx0sys.c b/storage/innobase/trx/trx0sys.c
index 7af9fbb1af8..8e595353024 100644
--- a/storage/innobase/trx/trx0sys.c
+++ b/storage/innobase/trx/trx0sys.c
@@ -37,6 +37,7 @@ Created 3/26/1996 Heikki Tuuri
#include "trx0rseg.h"
#include "trx0undo.h"
#include "srv0srv.h"
+#include "srv0start.h"
#include "trx0purge.h"
#include "log0log.h"
#include "log0recv.h"
@@ -1617,10 +1618,12 @@ void
trx_sys_close(void)
/*===============*/
{
+ trx_t* trx;
trx_rseg_t* rseg;
read_view_t* view;
ut_ad(trx_sys != NULL);
+ ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
/* Check that all read views are closed except read view owned
by a purge. */
@@ -1652,6 +1655,13 @@ trx_sys_close(void)
mem_free(trx_doublewrite);
trx_doublewrite = NULL;
+ /* Only prepared transactions may be left in the system. Free them. */
+ ut_a(UT_LIST_GET_LEN(trx_sys->trx_list) == trx_n_prepared);
+
+ while ((trx = UT_LIST_GET_FIRST(trx_sys->trx_list)) != NULL) {
+ trx_free_prepared(trx);
+ }
+
/* There can't be any active transactions. */
rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
diff --git a/storage/innobase/trx/trx0trx.c b/storage/innobase/trx/trx0trx.c
index 0d01bedc4fb..7b99b86c732 100644
--- a/storage/innobase/trx/trx0trx.c
+++ b/storage/innobase/trx/trx0trx.c
@@ -50,6 +50,9 @@ UNIV_INTERN sess_t* trx_dummy_sess = NULL;
/** Number of transactions currently allocated for MySQL: protected by
the kernel mutex */
UNIV_INTERN ulint trx_n_mysql_transactions = 0;
+/** Number of transactions currently in the XA PREPARED state: protected by
+the kernel mutex */
+UNIV_INTERN ulint trx_n_prepared = 0;
#ifdef UNIV_PFS_MUTEX
/* Key to register the mutex with performance schema */
@@ -214,10 +217,6 @@ trx_allocate_for_mysql(void)
mutex_exit(&kernel_mutex);
- trx->mysql_thread_id = os_thread_get_curr_id();
-
- trx->mysql_process_no = os_proc_get_number();
-
return(trx);
}
@@ -342,6 +341,60 @@ trx_free(
}
/********************************************************************//**
+At shutdown, frees a transaction object that is in the PREPARED state. */
+UNIV_INTERN
+void
+trx_free_prepared(
+/*==============*/
+ trx_t* trx) /*!< in, own: trx object */
+{
+ ut_ad(mutex_own(&kernel_mutex));
+ ut_a(trx->conc_state == TRX_PREPARED);
+ ut_a(trx->magic_n == TRX_MAGIC_N);
+
+ /* Prepared transactions are sort of active; they allow
+ ROLLBACK and COMMIT operations. Because the system does not
+ contain any other transactions than prepared transactions at
+ the shutdown stage and because a transaction cannot become
+ PREPARED while holding locks, it is safe to release the locks
+ held by PREPARED transactions here at shutdown.*/
+ lock_release_off_kernel(trx);
+
+ trx_undo_free_prepared(trx);
+
+ mutex_free(&trx->undo_mutex);
+
+ if (trx->undo_no_arr) {
+ trx_undo_arr_free(trx->undo_no_arr);
+ }
+
+ ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
+ ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0);
+
+ ut_a(trx->wait_lock == NULL);
+ ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
+
+ ut_a(!trx->has_search_latch);
+
+ ut_a(trx->dict_operation_lock_mode == 0);
+
+ if (trx->lock_heap) {
+ mem_heap_free(trx->lock_heap);
+ }
+
+ if (trx->global_read_view_heap) {
+ mem_heap_free(trx->global_read_view_heap);
+ }
+
+ ut_a(ib_vector_is_empty(trx->autoinc_locks));
+ ib_vector_free(trx->autoinc_locks);
+
+ UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
+
+ mem_free(trx);
+}
+
+/********************************************************************//**
Frees a transaction object for MySQL. */
UNIV_INTERN
void
@@ -471,6 +524,7 @@ trx_lists_init_at_db_start(void)
if (srv_force_recovery == 0) {
trx->conc_state = TRX_PREPARED;
+ trx_n_prepared++;
} else {
fprintf(stderr,
"InnoDB: Since"
@@ -547,6 +601,7 @@ trx_lists_init_at_db_start(void)
trx->conc_state
= TRX_PREPARED;
+ trx_n_prepared++;
} else {
fprintf(stderr,
"InnoDB: Since"
@@ -881,6 +936,11 @@ trx_commit_off_kernel(
ut_ad(trx->conc_state == TRX_ACTIVE || trx->conc_state == TRX_PREPARED);
ut_ad(mutex_own(&kernel_mutex));
+ if (UNIV_UNLIKELY(trx->conc_state == TRX_PREPARED)) {
+ ut_a(trx_n_prepared > 0);
+ trx_n_prepared--;
+ }
+
/* The following assignment makes the transaction committed in memory
and makes its changes to data visible to other transactions.
NOTE that there is a small discrepancy from the strict formal
@@ -1729,12 +1789,6 @@ trx_print(
fprintf(f, " state %lu", (ulong) trx->conc_state);
}
-#ifdef UNIV_LINUX
- fprintf(f, ", process no %lu", trx->mysql_process_no);
-#endif
- fprintf(f, ", OS thread id %lu",
- (ulong) os_thread_pf(trx->mysql_thread_id));
-
if (*trx->op_info) {
putc(' ', f);
fputs(trx->op_info, f);
@@ -1911,6 +1965,7 @@ trx_prepare_off_kernel(
/*--------------------------------------*/
trx->conc_state = TRX_PREPARED;
+ trx_n_prepared++;
/*--------------------------------------*/
if (lsn) {
@@ -2087,7 +2142,8 @@ trx_get_trx_by_xid(
of gtrid_length+bqual_length bytes should be
the same */
- if (trx->conc_state == TRX_PREPARED
+ if (trx->is_recovered
+ && trx->conc_state == TRX_PREPARED
&& xid->gtrid_length == trx->xid.gtrid_length
&& xid->bqual_length == trx->xid.bqual_length
&& memcmp(xid->data, trx->xid.data,
diff --git a/storage/innobase/trx/trx0undo.c b/storage/innobase/trx/trx0undo.c
index 4021a2ed573..070d6332a4f 100644
--- a/storage/innobase/trx/trx0undo.c
+++ b/storage/innobase/trx/trx0undo.c
@@ -36,6 +36,7 @@ Created 3/26/1996 Heikki Tuuri
#include "trx0rseg.h"
#include "trx0trx.h"
#include "srv0srv.h"
+#include "srv0start.h"
#include "trx0rec.h"
#include "trx0purge.h"
@@ -1975,4 +1976,31 @@ trx_undo_insert_cleanup(
mutex_exit(&(rseg->mutex));
}
+
+/********************************************************************//**
+At shutdown, frees the undo logs of a PREPARED transaction. */
+UNIV_INTERN
+void
+trx_undo_free_prepared(
+/*===================*/
+ trx_t* trx) /*!< in/out: PREPARED transaction */
+{
+ mutex_enter(&trx->rseg->mutex);
+
+ ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
+
+ if (trx->update_undo) {
+ ut_a(trx->update_undo->state == TRX_UNDO_PREPARED);
+ UT_LIST_REMOVE(undo_list, trx->rseg->update_undo_list,
+ trx->update_undo);
+ trx_undo_mem_free(trx->update_undo);
+ }
+ if (trx->insert_undo) {
+ ut_a(trx->insert_undo->state == TRX_UNDO_PREPARED);
+ UT_LIST_REMOVE(undo_list, trx->rseg->insert_undo_list,
+ trx->insert_undo);
+ trx_undo_mem_free(trx->insert_undo);
+ }
+ mutex_exit(&trx->rseg->mutex);
+}
#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc
index 16457088f9c..428601b7f6f 100644
--- a/storage/myisam/ha_myisam.cc
+++ b/storage/myisam/ha_myisam.cc
@@ -643,9 +643,10 @@ ha_myisam::ha_myisam(handlerton *hton, TABLE_SHARE *table_arg)
can_enable_indexes(1)
{}
-handler *ha_myisam::clone(MEM_ROOT *mem_root)
+handler *ha_myisam::clone(const char *name, MEM_ROOT *mem_root)
{
- ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(mem_root));
+ ha_myisam *new_handler= static_cast <ha_myisam *>(handler::clone(name,
+ mem_root));
if (new_handler)
new_handler->file->state= file->state;
return new_handler;
diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h
index 46b732512ac..f84b7bdfe66 100644
--- a/storage/myisam/ha_myisam.h
+++ b/storage/myisam/ha_myisam.h
@@ -50,7 +50,7 @@ class ha_myisam: public handler
public:
ha_myisam(handlerton *hton, TABLE_SHARE *table_arg);
~ha_myisam() {}
- handler *clone(MEM_ROOT *mem_root);
+ handler *clone(const char *name, MEM_ROOT *mem_root);
const char *table_type() const { return "MyISAM"; }
const char *index_type(uint key_number);
const char **bas_ext() const;
diff --git a/storage/myisammrg/ha_myisammrg.cc b/storage/myisammrg/ha_myisammrg.cc
index 79696cad721..38238a8f6c6 100644
--- a/storage/myisammrg/ha_myisammrg.cc
+++ b/storage/myisammrg/ha_myisammrg.cc
@@ -681,7 +681,7 @@ CPP_UNNAMED_NS_END
@return A cloned handler instance.
*/
-handler *ha_myisammrg::clone(MEM_ROOT *mem_root)
+handler *ha_myisammrg::clone(const char *name, MEM_ROOT *mem_root)
{
MYRG_TABLE *u_table,*newu_table;
ha_myisammrg *new_handler=
@@ -702,8 +702,8 @@ handler *ha_myisammrg::clone(MEM_ROOT *mem_root)
return NULL;
}
- if (new_handler->ha_open(table, table->s->normalized_path.str, table->db_stat,
- HA_OPEN_IGNORE_IF_LOCKED))
+ if (new_handler->ha_open(table, name, table->db_stat,
+ HA_OPEN_IGNORE_IF_LOCKED))
{
delete new_handler;
return NULL;
diff --git a/storage/myisammrg/ha_myisammrg.h b/storage/myisammrg/ha_myisammrg.h
index cae4bd17f50..1b8e1038c3f 100644
--- a/storage/myisammrg/ha_myisammrg.h
+++ b/storage/myisammrg/ha_myisammrg.h
@@ -110,7 +110,7 @@ public:
int add_children_list(void);
int attach_children(void);
int detach_children(void);
- virtual handler *clone(MEM_ROOT *mem_root);
+ virtual handler *clone(const char *name, MEM_ROOT *mem_root);
int close(void);
int write_row(uchar * buf);
int update_row(const uchar * old_data, uchar * new_data);
diff --git a/storage/ndb/src/kernel/blocks/lgman.cpp b/storage/ndb/src/kernel/blocks/lgman.cpp
index 53cb1e113e1..7dc71e7399a 100644
--- a/storage/ndb/src/kernel/blocks/lgman.cpp
+++ b/storage/ndb/src/kernel/blocks/lgman.cpp
@@ -1,17 +1,19 @@
-/* Copyright (C) 2003 MySQL AB
+/* Copyright (c) 2003, 2011, 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 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
+ 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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ 02110-1301 USA */
#include "lgman.hpp"
#include "diskpage.hpp"
@@ -2501,7 +2503,7 @@ Lgman::init_run_undo_log(Signal* signal)
sendSignal(reference(), GSN_CONTINUEB, signal, 2, JBB);
/**
- * Insert in correct postion in list of logfile_group's
+ * Insert in correct position in list of logfile_group's
*/
Ptr<Logfile_group> pos;
for(tmp.first(pos); !pos.isNull(); tmp.next(pos))
diff --git a/vio/viosocket.c b/vio/viosocket.c
index 0f3a32d62ae..daa5e6602c8 100644
--- a/vio/viosocket.c
+++ b/vio/viosocket.c
@@ -1,17 +1,19 @@
/* Copyright (c) 2000, 2011, 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 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
+ 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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ 02110-1301 USA */
/*
Note that we can't have assertion on file descriptors; The reason for
@@ -22,6 +24,10 @@
#include "vio_priv.h"
+#ifdef FIONREAD_IN_SYS_FILIO
+# include <sys/filio.h>
+#endif
+
int vio_errno(Vio *vio __attribute__((unused)))
{
return socket_errno; /* On Win32 this mapped to WSAGetLastError() */
@@ -583,13 +589,13 @@ static my_bool socket_poll_read(my_socket sd, uint timeout)
static my_bool socket_peek_read(Vio *vio, uint *bytes)
{
-#ifdef __WIN__
+#if defined(_WIN32)
int len;
if (ioctlsocket(vio->sd, FIONREAD, &len))
return TRUE;
*bytes= len;
return FALSE;
-#elif FIONREAD_IN_SYS_IOCTL
+#elif defined(FIONREAD_IN_SYS_IOCTL) || defined(FIONREAD_IN_SYS_FILIO)
int len;
if (ioctl(vio->sd, FIONREAD, &len) < 0)
return TRUE;
@@ -861,7 +867,7 @@ size_t vio_read_shared_memory(Vio * vio, uchar* buf, size_t size)
{
size_t length;
size_t remain_local;
- char *current_postion;
+ char *current_position;
HANDLE events[2];
DBUG_ENTER("vio_read_shared_memory");
@@ -869,7 +875,7 @@ size_t vio_read_shared_memory(Vio * vio, uchar* buf, size_t size)
size));
remain_local = size;
- current_postion=buf;
+ current_position=buf;
events[0]= vio->event_server_wrote;
events[1]= vio->event_conn_closed;
@@ -903,11 +909,11 @@ size_t vio_read_shared_memory(Vio * vio, uchar* buf, size_t size)
if (length > remain_local)
length = remain_local;
- memcpy(current_postion,vio->shared_memory_pos,length);
+ memcpy(current_position,vio->shared_memory_pos,length);
vio->shared_memory_remain-=length;
vio->shared_memory_pos+=length;
- current_postion+=length;
+ current_position+=length;
remain_local-=length;
if (!vio->shared_memory_remain)
@@ -927,7 +933,7 @@ size_t vio_write_shared_memory(Vio * vio, const uchar* buf, size_t size)
{
size_t length, remain, sz;
HANDLE pos;
- const uchar *current_postion;
+ const uchar *current_position;
HANDLE events[2];
DBUG_ENTER("vio_write_shared_memory");
@@ -935,7 +941,7 @@ size_t vio_write_shared_memory(Vio * vio, const uchar* buf, size_t size)
size));
remain = size;
- current_postion = buf;
+ current_position = buf;
events[0]= vio->event_server_read;
events[1]= vio->event_conn_closed;
@@ -953,9 +959,9 @@ size_t vio_write_shared_memory(Vio * vio, const uchar* buf, size_t size)
int4store(vio->handle_map,sz);
pos = vio->handle_map + 4;
- memcpy(pos,current_postion,sz);
+ memcpy(pos,current_position,sz);
remain-=sz;
- current_postion+=sz;
+ current_position+=sz;
if (!SetEvent(vio->event_client_wrote))
DBUG_RETURN((size_t) -1);
}