List:Commits« Previous MessageNext Message »
From:Mikael Ronstrom Date:May 4 2011 9:08am
Subject:bzr commit into mysql-5.5 branch (mikael.ronstrom:3142)
View as plain text  
#At file:///home/mikael/mysql_clones/mysql-5.5-wl5136_community/ based on revid:mikael.ronstrom@stripped

 3142 Mikael Ronstrom	2011-05-04 [merge]
      merge

    added:
      libmysql/authentication_win/
      libmysql/authentication_win/CMakeLists.txt
      libmysql/authentication_win/common.cc
      libmysql/authentication_win/common.h
      libmysql/authentication_win/handshake.cc
      libmysql/authentication_win/handshake.h
      libmysql/authentication_win/handshake_client.cc
      libmysql/authentication_win/log_client.cc
      libmysql/authentication_win/plugin_client.cc
      mysql-test/suite/innodb/r/innodb_bug59410.result
      mysql-test/suite/innodb/r/innodb_bug59641.result
      mysql-test/suite/innodb/t/innodb_bug59410.test
      mysql-test/suite/innodb/t/innodb_bug59641.test
    modified:
      .bzrignore
      client/mysqltest.cc
      cmake/abi_check.cmake
      cmake/maintainer.cmake
      cmake/os/WindowsCache.cmake
      cmd-line-utils/libedit/el.c
      cmd-line-utils/libedit/vi.c
      config.h.cmake
      configure.cmake
      include/m_ctype.h
      include/mysql/client_plugin.h
      include/mysql/client_plugin.h.pp
      libmysql/CMakeLists.txt
      libmysql/libmysql.def
      mysql-test/collections/default.experimental
      mysql-test/extra/rpl_tests/rpl_extra_col_slave.test
      mysql-test/lib/My/ConfigFactory.pm
      mysql-test/lib/My/Find.pm
      mysql-test/lib/My/SafeProcess/safe_process.pl
      mysql-test/lib/mtr_gcov.pl
      mysql-test/mysql-test-run.pl
      mysql-test/r/func_math.result
      mysql-test/r/func_time.result
      mysql-test/r/having.result
      mysql-test/r/loaddata.result
      mysql-test/r/partition_myisam.result
      mysql-test/r/type_timestamp.result
      mysql-test/suite/binlog/r/binlog_bug23533.result
      mysql-test/suite/binlog/t/binlog_bug23533.test
      mysql-test/suite/innodb/r/innodb_bug60196.result
      mysql-test/suite/innodb/t/innodb_bug60196.test
      mysql-test/suite/parts/inc/partition_check_drop.inc
      mysql-test/suite/parts/inc/partition_fail.inc
      mysql-test/suite/parts/inc/partition_layout_check1.inc
      mysql-test/suite/parts/inc/partition_layout_check2.inc
      mysql-test/t/func_math.test
      mysql-test/t/func_time.test
      mysql-test/t/having.test
      mysql-test/t/loaddata.test
      mysql-test/t/partition_myisam.test
      mysql-test/t/type_timestamp.test
      sql-common/client.c
      sql-common/client_plugin.c
      sql-common/my_time.c
      sql/ha_partition.cc
      sql/ha_partition.h
      sql/handler.cc
      sql/handler.h
      sql/item_func.cc
      sql/item_timefunc.cc
      sql/mysqld.h
      sql/opt_range.cc
      sql/sql_class.cc
      sql/sql_load.cc
      sql/sql_select.cc
      storage/heap/ha_heap.cc
      storage/heap/ha_heap.h
      storage/innobase/btr/btr0cur.c
      storage/innobase/buf/buf0flu.c
      storage/innobase/dict/dict0dict.c
      storage/innobase/dict/dict0load.c
      storage/innobase/dict/dict0mem.c
      storage/innobase/fil/fil0fil.c
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/handler/ha_innodb.h
      storage/innobase/handler/handler0alter.cc
      storage/innobase/ibuf/ibuf0ibuf.c
      storage/innobase/include/dict0mem.h
      storage/innobase/include/ha_prototypes.h
      storage/innobase/include/log0log.ic
      storage/innobase/include/os0sync.h
      storage/innobase/include/os0thread.h
      storage/innobase/include/srv0srv.h
      storage/innobase/include/sync0sync.h
      storage/innobase/include/trx0trx.h
      storage/innobase/include/trx0undo.h
      storage/innobase/include/univ.i
      storage/innobase/include/ut0dbg.h
      storage/innobase/include/ut0ut.h
      storage/innobase/log/log0log.c
      storage/innobase/os/os0file.c
      storage/innobase/os/os0sync.c
      storage/innobase/os/os0thread.c
      storage/innobase/row/row0sel.c
      storage/innobase/srv/srv0srv.c
      storage/innobase/srv/srv0start.c
      storage/innobase/sync/sync0sync.c
      storage/innobase/trx/trx0roll.c
      storage/innobase/trx/trx0sys.c
      storage/innobase/trx/trx0trx.c
      storage/innobase/trx/trx0undo.c
      storage/myisam/ha_myisam.cc
      storage/myisam/ha_myisam.h
      storage/myisammrg/ha_myisammrg.cc
      storage/myisammrg/ha_myisammrg.h
      vio/viosocket.c
=== modified file '.bzrignore'
--- a/.bzrignore	revid:mikael.ronstrom@stripped
+++ b/.bzrignore	revid:mikael.ronstrom@stripped
@@ -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

=== modified file 'client/mysqltest.cc'
--- a/client/mysqltest.cc	revid:mikael.ronstrom@stripped
+++ b/client/mysqltest.cc	revid:mikael.ronstrom@stripped
@@ -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_comman
 
   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_comman
       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);
   }
 

=== modified file 'cmake/abi_check.cmake'
--- a/cmake/abi_check.cmake	revid:mikael.ronstrom@stripped
+++ b/cmake/abi_check.cmake	revid:mikael.ronstrom@stripped
@@ -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})

=== modified file 'cmake/maintainer.cmake'
--- a/cmake/maintainer.cmake	revid:mikael.ronstrom@stripped
+++ b/cmake/maintainer.cmake	revid:mikael.ronstrom@stripped
@@ -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()
 

=== modified file 'cmake/os/WindowsCache.cmake'
--- a/cmake/os/WindowsCache.cmake	revid:mikael.ronstrom@stripped
+++ b/cmake/os/WindowsCache.cmake	revid:mikael.ronstrom@stripped
@@ -101,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 "")

=== modified file 'cmd-line-utils/libedit/el.c'
--- a/cmd-line-utils/libedit/el.c	revid:mikael.ronstrom@stripped
+++ b/cmd-line-utils/libedit/el.c	revid:mikael.ronstrom@stripped
@@ -478,7 +478,13 @@ el_source(EditLine *el, const char *fnam
 
 	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 *fnam
 #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 *fnam
 		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

=== modified file 'cmd-line-utils/libedit/vi.c'
--- a/cmd-line-utils/libedit/vi.c	revid:mikael.ronstrom@stripped
+++ b/cmd-line-utils/libedit/vi.c	revid:mikael.ronstrom@stripped
@@ -1012,8 +1012,10 @@ vi_histedit(EditLine *el, int c __attrib
 	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 __attrib
 	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():

=== modified file 'config.h.cmake'
--- a/config.h.cmake	revid:mikael.ronstrom@stripped
+++ b/config.h.cmake	revid:mikael.ronstrom@stripped
@@ -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
@@ -173,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

=== modified file 'configure.cmake'
--- a/configure.cmake	revid:mikael.ronstrom@stripped
+++ b/configure.cmake	revid:mikael.ronstrom@stripped
@@ -362,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)
@@ -487,6 +491,7 @@ CHECK_SYMBOL_EXISTS(getpagesize "unistd.
 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)

=== modified file 'include/m_ctype.h'
--- a/include/m_ctype.h	revid:mikael.ronstrom@stripped
+++ b/include/m_ctype.h	revid:mikael.ronstrom@stripped
@@ -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;

=== modified file 'include/mysql/client_plugin.h'
--- a/include/mysql/client_plugin.h	revid:mikael.ronstrom@stripped
+++ b/include/mysql/client_plugin.h	revid:mikael.ronstrom@stripped
@@ -156,8 +156,7 @@ mysql_client_register_plugin(struct st_m
 
   @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
 

=== modified file 'include/mysql/client_plugin.h.pp'
--- a/include/mysql/client_plugin.h.pp	revid:mikael.ronstrom@stripped
+++ b/include/mysql/client_plugin.h.pp	revid:mikael.ronstrom@stripped
@@ -35,6 +35,5 @@ mysql_client_find_plugin(struct st_mysql
 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);

=== modified file 'libmysql/CMakeLists.txt'
--- a/libmysql/CMakeLists.txt	revid:mikael.ronstrom@stripped
+++ b/libmysql/CMakeLists.txt	revid:mikael.ronstrom@stripped
@@ -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 cl
 
 )
 
+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)

=== added directory 'libmysql/authentication_win'
=== added file 'libmysql/authentication_win/CMakeLists.txt'
--- a/libmysql/authentication_win/CMakeLists.txt	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/CMakeLists.txt	revid:mikael.ronstrom@stripped
@@ -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$")

=== added file 'libmysql/authentication_win/common.cc'
--- a/libmysql/authentication_win/common.cc	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/common.cc	revid:mikael.ronstrom@stripped
@@ -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;
+}

=== added file 'libmysql/authentication_win/common.h'
--- a/libmysql/authentication_win/common.h	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/common.h	revid:mikael.ronstrom@stripped
@@ -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

=== added file 'libmysql/authentication_win/handshake.cc'
--- a/libmysql/authentication_win/handshake.cc	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/handshake.cc	revid:mikael.ronstrom@stripped
@@ -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;
+}

=== added file 'libmysql/authentication_win/handshake.h'
--- a/libmysql/authentication_win/handshake.h	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/handshake.h	revid:mikael.ronstrom@stripped
@@ -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

=== added file 'libmysql/authentication_win/handshake_client.cc'
--- a/libmysql/authentication_win/handshake_client.cc	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/handshake_client.cc	revid:mikael.ronstrom@stripped
@@ -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);
+}

=== added file 'libmysql/authentication_win/log_client.cc'
--- a/libmysql/authentication_win/log_client.cc	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/log_client.cc	revid:mikael.ronstrom@stripped
@@ -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);
+}

=== added file 'libmysql/authentication_win/plugin_client.cc'
--- a/libmysql/authentication_win/plugin_client.cc	1970-01-01 00:00:00 +0000
+++ b/libmysql/authentication_win/plugin_client.cc	revid:mikael.ronstrom@stripped
@@ -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
+};

=== modified file 'libmysql/libmysql.def'
--- a/libmysql/libmysql.def	revid:mikael.ronstrom@stripped
+++ b/libmysql/libmysql.def	revid:mikael.ronstrom@stripped
@@ -104,4 +104,3 @@ EXPORTS
 	mysql_server_end
 	mysql_set_character_set
 	mysql_get_character_set_info
-        mysql_plugin_options

=== modified file 'mysql-test/collections/default.experimental'
--- a/mysql-test/collections/default.experimental	revid:mikael.ronstrom@stripped
+++ b/mysql-test/collections/default.experimental	revid:mikael.ronstrom@stripped
@@ -2,9 +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                   # WL#5867: skozlov: test case moved from unused bugs suite
-binlog.binlog_bug36391                   # WL#5867: skozlov: test case moved from unused bugs suite
-
+binlog.binlog_bug23533                   # skozlov: BUG#12371924
 
 funcs_1.charset_collation_1              # depends on compile-time decisions
 
@@ -17,8 +15,9 @@ main.sp @solaris                        
 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_bug37426                         # WL#5867: skozlov: test case moved from unused bugs suite
+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

=== modified file 'mysql-test/extra/rpl_tests/rpl_extra_col_slave.test'
--- a/mysql-test/extra/rpl_tests/rpl_extra_col_slave.test	revid:mikael.ronstrom@stripped
+++ b/mysql-test/extra/rpl_tests/rpl_extra_col_slave.test	revid:mikael.ronstrom@stripped
@@ -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 #

=== modified file 'mysql-test/lib/My/ConfigFactory.pm'
--- a/mysql-test/lib/My/ConfigFactory.pm	revid:mikael.ronstrom@stripped
+++ b/mysql-test/lib/My/ConfigFactory.pm	revid:mikael.ronstrom@stripped
@@ -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 {

=== modified file 'mysql-test/lib/My/Find.pm'
--- a/mysql-test/lib/My/Find.pm	revid:mikael.ronstrom@stripped
+++ b/mysql-test/lib/My/Find.pm	revid:mikael.ronstrom@stripped
@@ -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){

=== modified file 'mysql-test/lib/My/SafeProcess/safe_process.pl'
--- a/mysql-test/lib/My/SafeProcess/safe_process.pl	revid:mikael.ronstrom@stripped
+++ b/mysql-test/lib/My/SafeProcess/safe_process.pl	revid:mikael.ronstrom@stripped
@@ -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");

=== modified file 'mysql-test/lib/mtr_gcov.pl'
--- a/mysql-test/lib/mtr_gcov.pl	revid:mikael.ronstrom@stripped
+++ b/mysql-test/lib/mtr_gcov.pl	revid:mikael.ronstrom@stripped
@@ -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";
 }
 
 

=== modified file 'mysql-test/mysql-test-run.pl'
--- a/mysql-test/mysql-test-run.pl	revid:mikael.ronstrom@stripped
+++ b/mysql-test/mysql-test-run.pl	revid:mikael.ronstrom@stripped
@@ -210,8 +210,8 @@ our $opt_clean_vardir= $ENV{'MTR_CLEAN_V
 
 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

=== modified file 'mysql-test/r/func_math.result'
--- a/mysql-test/r/func_math.result	revid:mikael.ronstrom@stripped
+++ b/mysql-test/r/func_math.result	revid:mikael.ronstrom@stripped
@@ -521,6 +521,28 @@ CREATE TABLE t1 SELECT CEIL(LINESTRINGFR
 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

=== modified file 'mysql-test/r/func_time.result'
--- a/mysql-test/r/func_time.result	revid:mikael.ronstrom@stripped
+++ b/mysql-test/r/func_time.result	revid:mikael.ronstrom@stripped
@@ -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.

=== modified file 'mysql-test/r/having.result'
--- a/mysql-test/r/having.result	revid:mikael.ronstrom@stripped
+++ b/mysql-test/r/having.result	revid:mikael.ronstrom@stripped
@@ -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

=== modified file 'mysql-test/r/loaddata.result'
--- a/mysql-test/r/loaddata.result	revid:mikael.ronstrom@stripped
+++ b/mysql-test/r/loaddata.result	revid:mikael.ronstrom@stripped
@@ -539,4 +539,13 @@ 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

=== modified file 'mysql-test/r/partition_myisam.result'
--- a/mysql-test/r/partition_myisam.result	revid:mikael.ronstrom@stripped
+++ b/mysql-test/r/partition_myisam.result	revid:mikael.ronstrom@stripped
@@ -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;

=== modified file 'mysql-test/r/type_timestamp.result'
--- a/mysql-test/r/type_timestamp.result	revid:mikael.ronstrom@stripped
+++ b/mysql-test/r/type_timestamp.result	revid:mikael.ronstrom@stripped
@@ -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

=== modified file 'mysql-test/suite/binlog/r/binlog_bug23533.result'
--- a/mysql-test/suite/binlog/r/binlog_bug23533.result	revid:mikael.ronstrom@stripped
+++ b/mysql-test/suite/binlog/r/binlog_bug23533.result	revid:mikael.ronstrom@stripped
@@ -3,7 +3,7 @@ CREATE TABLE t1 (a INT NOT NULL AUTO_INC
 SELECT COUNT(*) FROM t1;
 COUNT(*)
 1000
-SET @saved_max_binlog_cache_size=@@max_binlog_cache_size;
+SET GLOBAL binlog_cache_size=4096;
 SET GLOBAL max_binlog_cache_size=4096;
 START TRANSACTION;
 CREATE TABLE t2 SELECT * FROM t1;
@@ -12,5 +12,4 @@ COMMIT;
 SHOW TABLES LIKE 't%';
 Tables_in_test (t%)
 t1
-SET GLOBAL max_binlog_cache_size=@saved_max_binlog_cache_size;
 DROP TABLE t1;

=== modified file 'mysql-test/suite/binlog/t/binlog_bug23533.test'
--- a/mysql-test/suite/binlog/t/binlog_bug23533.test	revid:mikael.ronstrom@stripped
+++ b/mysql-test/suite/binlog/t/binlog_bug23533.test	revid:mikael.ronstrom@stripped
@@ -15,16 +15,24 @@ CREATE TABLE t1 (a INT NOT NULL AUTO_INC
 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
-SET @saved_max_binlog_cache_size=@@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 1197
@@ -33,5 +41,10 @@ COMMIT;
 SHOW TABLES LIKE 't%';
 
 # 5.1 End of Test
-SET GLOBAL max_binlog_cache_size=@saved_max_binlog_cache_size;
+--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);

=== added file 'mysql-test/suite/innodb/r/innodb_bug59410.result'
--- a/mysql-test/suite/innodb/r/innodb_bug59410.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/r/innodb_bug59410.result	revid:mikael.ronstrom@stripped
@@ -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;

=== added file 'mysql-test/suite/innodb/r/innodb_bug59641.result'
--- a/mysql-test/suite/innodb/r/innodb_bug59641.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/r/innodb_bug59641.result	revid:mikael.ronstrom@stripped
@@ -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;

=== modified file 'mysql-test/suite/innodb/r/innodb_bug60196.result'
--- a/mysql-test/suite/innodb/r/innodb_bug60196.result	revid:mikael.ronstrom@stripped
+++ b/mysql-test/suite/innodb/r/innodb_bug60196.result	revid:mikael.ronstrom@stripped
@@ -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;

=== added file 'mysql-test/suite/innodb/t/innodb_bug59410.test'
--- a/mysql-test/suite/innodb/t/innodb_bug59410.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/t/innodb_bug59410.test	revid:mikael.ronstrom@stripped
@@ -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;

=== added file 'mysql-test/suite/innodb/t/innodb_bug59641.test'
--- a/mysql-test/suite/innodb/t/innodb_bug59641.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/t/innodb_bug59641.test	revid:mikael.ronstrom@stripped
@@ -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;

=== modified file 'mysql-test/suite/innodb/t/innodb_bug60196.test'
--- a/mysql-test/suite/innodb/t/innodb_bug60196.test	revid:mikael.ronstrom@stripped
+++ b/mysql-test/suite/innodb/t/innodb_bug60196.test	revid:mikael.ronstrom@stripped
@@ -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;

=== modified file 'mysql-test/suite/parts/inc/partition_check_drop.inc'
--- a/mysql-test/suite/parts/inc/partition_check_drop.inc	revid:mikael.ronstrom@stripped
+++ b/mysql-test/suite/parts/inc/partition_check_drop.inc	revid:mikael.ronstrom@stripped
@@ -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)
 {

=== modified file 'mysql-test/suite/parts/inc/partition_fail.inc'
--- a/mysql-test/suite/parts/inc/partition_fail.inc	revid:mikael.ronstrom@stripped
+++ b/mysql-test/suite/parts/inc/partition_fail.inc	revid:mikael.ronstrom@stripped
@@ -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

=== modified file 'mysql-test/suite/parts/inc/partition_layout_check1.inc'
--- a/mysql-test/suite/parts/inc/partition_layout_check1.inc	revid:mikael.ronstrom@stripped
+++ b/mysql-test/suite/parts/inc/partition_layout_check1.inc	revid:mikael.ronstrom@stripped
@@ -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)
 {

=== modified file 'mysql-test/suite/parts/inc/partition_layout_check2.inc'
--- a/mysql-test/suite/parts/inc/partition_layout_check2.inc	revid:mikael.ronstrom@stripped
+++ b/mysql-test/suite/parts/inc/partition_layout_check2.inc	revid:mikael.ronstrom@stripped
@@ -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)
 {

=== modified file 'mysql-test/t/func_math.test'
--- a/mysql-test/t/func_math.test	revid:mikael.ronstrom@stripped
+++ b/mysql-test/t/func_math.test	revid:mikael.ronstrom@stripped
@@ -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 #

=== modified file 'mysql-test/t/func_time.test'
--- a/mysql-test/t/func_time.test	revid:mikael.ronstrom@stripped
+++ b/mysql-test/t/func_time.test	revid:mikael.ronstrom@stripped
@@ -894,6 +894,14 @@ SELECT CAST((MONTH(FROM_UNIXTIME(@@GLOBA
 
 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 #

=== modified file 'mysql-test/t/having.test'
--- a/mysql-test/t/having.test	revid:mikael.ronstrom@stripped
+++ b/mysql-test/t/having.test	revid:mikael.ronstrom@stripped
@@ -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

=== modified file 'mysql-test/t/loaddata.test'
--- a/mysql-test/t/loaddata.test	revid:mikael.ronstrom@stripped
+++ b/mysql-test/t/loaddata.test	revid:mikael.ronstrom@stripped
@@ -615,4 +615,19 @@ 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

=== modified file 'mysql-test/t/partition_myisam.test'
--- a/mysql-test/t/partition_myisam.test	revid:mikael.ronstrom@stripped
+++ b/mysql-test/t/partition_myisam.test	revid:mikael.ronstrom@stripped
@@ -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;

=== modified file 'mysql-test/t/type_timestamp.test'
--- a/mysql-test/t/type_timestamp.test	revid:mikael.ronstrom@stripped
+++ b/mysql-test/t/type_timestamp.test	revid:mikael.ronstrom@stripped
@@ -362,6 +362,53 @@ SELECT a FROM t1 WHERE a >= '20000101000
 
 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

=== modified file 'sql-common/client.c'
--- a/sql-common/client.c	revid:mikael.ronstrom@stripped
+++ b/sql-common/client.c	revid:mikael.ronstrom@stripped
@@ -2314,11 +2314,18 @@ static auth_plugin_t clear_password_clie
   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
 };
 

=== modified file 'sql-common/client_plugin.c'
--- a/sql-common/client_plugin.c	revid:mikael.ronstrom@stripped
+++ b/sql-common/client_plugin.c	revid:mikael.ronstrom@stripped
@@ -460,7 +460,7 @@ mysql_client_find_plugin(MYSQL *mysql, c
 
 
 /* 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)
 {

=== modified file 'sql-common/my_time.c'
--- a/sql-common/my_time.c	revid:mikael.ronstrom@stripped
+++ b/sql-common/my_time.c	revid:mikael.ronstrom@stripped
@@ -772,7 +772,7 @@ long calc_daynr(uint year,uint month,uin
   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,uin
   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 */
 

=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc	revid:mikael.ronstrom@stripped
+++ b/sql/ha_partition.cc	revid:mikael.ronstrom@stripped
@@ -162,8 +162,7 @@ const uint ha_partition::NO_CURRENT_PART
 */
 
 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 *h
 */
 
 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_variable
   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_variable
     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(
     */
     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(con
     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 c
 }
 
 
-/*
+/**
   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(c
      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(c
   }
   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(c
   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_R
   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_P
 
 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,
   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,
   {
     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,
 
   /* 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,
   */
   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));
+  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);
 
-#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
   DBUG_VOID_RETURN;
 }
 

=== modified file 'sql/ha_partition.h'
--- a/sql/ha_partition.h	revid:mikael.ronstrom@stripped
+++ b/sql/ha_partition.h	revid:mikael.ronstrom@stripped
@@ -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();

=== modified file 'sql/handler.cc'
--- a/sql/handler.cc	revid:mikael.ronstrom@stripped
+++ b/sql/handler.cc	revid:mikael.ronstrom@stripped
@@ -2076,22 +2076,29 @@ int ha_delete_table(THD *thd, handlerton
 /****************************************************************************
 ** 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;
 }
 
 

=== modified file 'sql/handler.h'
--- a/sql/handler.h	revid:mikael.ronstrom@stripped
+++ b/sql/handler.h	revid:mikael.ronstrom@stripped
@@ -1262,7 +1262,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()
   {

=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc	revid:mikael.ronstrom@stripped
+++ b/sql/item_func.cc	revid:mikael.ronstrom@stripped
@@ -2409,10 +2409,7 @@ my_decimal *Item_func_round::decimal_op(
   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;
 }
 

=== modified file 'sql/item_timefunc.cc'
--- a/sql/item_timefunc.cc	revid:mikael.ronstrom@stripped
+++ b/sql/item_timefunc.cc	revid:mikael.ronstrom@stripped
@@ -669,7 +669,7 @@ bool make_date_time(DATE_TIME_FORMAT *fo
                     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 *fo
                     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 *fo
       }
       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);

=== modified file 'sql/mysqld.h'
--- a/sql/mysqld.h	revid:mikael.ronstrom@stripped
+++ b/sql/mysqld.h	revid:mikael.ronstrom@stripped
@@ -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_s
 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 MYSQL_PLUGIN_IMPORT pthread_attr_t connection_attrib;
 extern MYSQL_FILE *bootstrap_file;
 extern my_bool old_mode;
@@ -312,7 +313,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;

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	revid:mikael.ronstrom@stripped
+++ b/sql/opt_range.cc	revid:mikael.ronstrom@stripped
@@ -1368,7 +1368,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_
   }
 
   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

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	revid:mikael.ronstrom@stripped
+++ b/sql/sql_class.cc	revid:mikael.ronstrom@stripped
@@ -3916,6 +3916,7 @@ bool xid_cache_insert(XID *xid, enum xa_
     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);

=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc	revid:mikael.ronstrom@stripped
+++ b/sql/sql_load.cc	revid:mikael.ronstrom@stripped
@@ -1302,9 +1302,10 @@ READ_INFO::READ_INFO(File file_par, uint
 		     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,8 +1333,6 @@ READ_INFO::READ_INFO(File file_par, uint
     (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 */
@@ -1379,7 +1378,7 @@ READ_INFO::READ_INFO(File file_par, uint
 
 READ_INFO::~READ_INFO()
 {
-  if (!error && need_end_io_cache)
+  if (need_end_io_cache)
     ::end_io_cache(&cache);
 
   if (buffer != NULL)

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	revid:mikael.ronstrom@stripped
+++ b/sql/sql_select.cc	revid:mikael.ronstrom@stripped
@@ -2263,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)
@@ -13102,6 +13102,42 @@ static bool test_if_ref(Item_field *left
   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)

=== modified file 'storage/heap/ha_heap.cc'
--- a/storage/heap/ha_heap.cc	revid:mikael.ronstrom@stripped
+++ b/storage/heap/ha_heap.cc	revid:mikael.ronstrom@stripped
@@ -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,

=== modified file 'storage/heap/ha_heap.h'
--- a/storage/heap/ha_heap.h	revid:mikael.ronstrom@stripped
+++ b/storage/heap/ha_heap.h	revid:mikael.ronstrom@stripped
@@ -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) ?

=== modified file 'storage/innobase/btr/btr0cur.c'
--- a/storage/innobase/btr/btr0cur.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/btr/btr0cur.c	revid:mikael.ronstrom@stripped
@@ -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

=== modified file 'storage/innobase/buf/buf0flu.c'
--- a/storage/innobase/buf/buf0flu.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/buf/buf0flu.c	revid:mikael.ronstrom@stripped
@@ -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);

=== modified file 'storage/innobase/dict/dict0dict.c'
--- a/storage/innobase/dict/dict0dict.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/dict/dict0dict.c	revid:mikael.ronstrom@stripped
@@ -52,7 +52,6 @@ UNIV_INTERN dict_index_t*	dict_ind_compa
 #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);

=== modified file 'storage/innobase/dict/dict0load.c'
--- a/storage/innobase/dict/dict0load.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/dict/dict0load.c	revid:mikael.ronstrom@stripped
@@ -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;
 	}

=== modified file 'storage/innobase/dict/dict0mem.c'
--- a/storage/innobase/dict/dict0mem.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/dict/dict0mem.c	revid:mikael.ronstrom@stripped
@@ -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_se
 	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,

=== modified file 'storage/innobase/fil/fil0fil.c'
--- a/storage/innobase/fil/fil0fil.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/fil/fil0fil.c	revid:mikael.ronstrom@stripped
@@ -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");
 

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/handler/ha_innodb.cc	revid:mikael.ronstrom@stripped
@@ -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, SH
   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 "

=== modified file 'storage/innobase/handler/ha_innodb.h'
--- a/storage/innobase/handler/ha_innodb.h	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/handler/ha_innodb.h	revid:mikael.ronstrom@stripped
@@ -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. */
 

=== modified file 'storage/innobase/handler/handler0alter.cc'
--- a/storage/innobase/handler/handler0alter.cc	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/handler/handler0alter.cc	revid:mikael.ronstrom@stripped
@@ -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;

=== modified file 'storage/innobase/ibuf/ibuf0ibuf.c'
--- a/storage/innobase/ibuf/ibuf0ibuf.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/ibuf/ibuf0ibuf.c	revid:mikael.ronstrom@stripped
@@ -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);

=== modified file 'storage/innobase/include/dict0mem.h'
--- a/storage/innobase/include/dict0mem.h	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/include/dict0mem.h	revid:mikael.ronstrom@stripped
@@ -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(

=== modified file 'storage/innobase/include/ha_prototypes.h'
--- a/storage/innobase/include/ha_prototypes.h	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/include/ha_prototypes.h	revid:mikael.ronstrom@stripped
@@ -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

=== modified file 'storage/innobase/include/log0log.ic'
--- a/storage/innobase/include/log0log.ic	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/include/log0log.ic	revid:mikael.ronstrom@stripped
@@ -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) {

=== modified file 'storage/innobase/include/os0sync.h'
--- a/storage/innobase/include/os0sync.h	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/include/os0sync.h	revid:mikael.ronstrom@stripped
@@ -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.

=== modified file 'storage/innobase/include/os0thread.h'
--- a/storage/innobase/include/os0thread.h	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/include/os0thread.h	revid:mikael.ronstrom@stripped
@@ -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"

=== modified file 'storage/innobase/include/srv0srv.h'
--- a/storage/innobase/include/srv0srv.h	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/include/srv0srv.h	revid:mikael.ronstrom@stripped
@@ -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 */

=== modified file 'storage/innobase/include/sync0sync.h'
--- a/storage/innobase/include/sync0sync.h	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/include/sync0sync.h	revid:mikael.ronstrom@stripped
@@ -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

=== modified file 'storage/innobase/include/trx0trx.h'
--- a/storage/innobase/include/trx0trx.h	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/include/trx0trx.h	revid:mikael.ronstrom@stripped
@@ -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

=== modified file 'storage/innobase/include/trx0undo.h'
--- a/storage/innobase/include/trx0undo.h	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/include/trx0undo.h	revid:mikael.ronstrom@stripped
@@ -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.

=== modified file 'storage/innobase/include/univ.i'
--- a/storage/innobase/include/univ.i	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/include/univ.i	revid:mikael.ronstrom@stripped
@@ -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://b
 #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 */

=== modified file 'storage/innobase/include/ut0dbg.h'
--- a/storage/innobase/include/ut0dbg.h	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/include/ut0dbg.h	revid:mikael.ronstrom@stripped
@@ -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

=== modified file 'storage/innobase/include/ut0ut.h'
--- a/storage/innobase/include/ut0ut.h	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/include/ut0ut.h	revid:mikael.ronstrom@stripped
@@ -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

=== modified file 'storage/innobase/log/log0log.c'
--- a/storage/innobase/log/log0log.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/log/log0log.c	revid:mikael.ronstrom@stripped
@@ -3078,6 +3078,7 @@ logs_empty_and_mark_files_at_shutdown(vo
 {
 	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. */
-
-	if (srv_fast_shutdown < 2
-	   && (srv_error_monitor_active
-	      || srv_lock_timeout_active
-	      || srv_monitor_active)) {
+	/* We need the monitor threads to stop before we proceed with
+	a shutdown. */
+
+	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()) {

=== modified file 'storage/innobase/os/os0file.c'
--- a/storage/innobase/os/os0file.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/os/os0file.c	revid:mikael.ronstrom@stripped
@@ -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. */
+	if (ret > 0) {
+		for (i = 0; i < ret; i++) {
+			os_aio_slot_t*	slot;
+			struct iocb*	control;
+
+			control = (struct iocb *)events[i].obj;
+			ut_a(control != NULL);
+
+			slot = (os_aio_slot_t *) control->data;
+
+			/* Some sanity checks. */
+			ut_a(slot != NULL);
+			ut_a(slot->reserved);
 
-	/* Not enough resources! Try again. */
-	if (ret == -EAGAIN) {
-		goto retry;
-	}
+#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
 
-	/* 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;
-	}
+			/* We are not scribbling previous segment. */
+			ut_a(slot->pos >= start_pos);
 
-	/* No pending request! Go back and check again. */
-	if (ret == 0) {
-		goto retry;
-	}
+			/* We have not overstepped to next segment. */
+			ut_a(slot->pos < end_pos);
 
-	/* 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;
+			/* 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;
 	}
 
-	ut_a(ret > 0);
-
-	for (i = 0; i < ret; i++) {
-		os_aio_slot_t*	slot;
-		struct iocb*	control;
-
-		control = (struct iocb *)events[i].obj;
-		ut_a(control != NULL);
-
-		slot = (os_aio_slot_t *) control->data;
-
-		/* Some sanity checks. */
-		ut_a(slot != NULL);
-		ut_a(slot->reserved);
-
-#if defined(UNIV_AIO_DEBUG)
-		fprintf(stderr,
-			"io_getevents[%c]: slot[%p] ctx[%p]"
-			" seg[%lu]\n",
-			(slot->type == OS_FILE_WRITE) ? 'w' : 'r',
-			slot, io_ctx, segment);
-#endif
-
-		/* We are not scribbling previous segment. */
-		ut_a(slot->pos >= start_pos);
+	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

=== modified file 'storage/innobase/os/os0sync.c'
--- a/storage/innobase/os/os0sync.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/os/os0sync.c	revid:mikael.ronstrom@stripped
@@ -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);
 }
 

=== modified file 'storage/innobase/os/os0thread.c'
--- a/storage/innobase/os/os0thread.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/os/os0thread.c	revid:mikael.ronstrom@stripped
@@ -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 */

=== modified file 'storage/innobase/row/row0sel.c'
--- a/storage/innobase/row/row0sel.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/row/row0sel.c	revid:mikael.ronstrom@stripped
@@ -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:
@@ -3386,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);
 	}
 
@@ -4679,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);
 }
 

=== modified file 'storage/innobase/srv/srv0srv.c'
--- a/storage/innobase/srv/srv0srv.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/srv/srv0srv.c	revid:mikael.ronstrom@stripped
@@ -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_USER_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_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

=== modified file 'storage/innobase/srv/srv0start.c'
--- a/storage/innobase/srv/srv0start.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/srv/srv0start.c	revid:mikael.ronstrom@stripped
@@ -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

=== modified file 'storage/innobase/sync/sync0sync.c'
--- a/storage/innobase/sync/sync0sync.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/sync/sync0sync.c	revid:mikael.ronstrom@stripped
@@ -189,12 +189,12 @@ UNIV_INTERN sync_array_t*	sync_primary_w
 /** 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_m
 #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);
 }
 
 /******************************************************************//**

=== modified file 'storage/innobase/trx/trx0roll.c'
--- a/storage/innobase/trx/trx0roll.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/trx/trx0roll.c	revid:mikael.ronstrom@stripped
@@ -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;

=== modified file 'storage/innobase/trx/trx0sys.c'
--- a/storage/innobase/trx/trx0sys.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/trx/trx0sys.c	revid:mikael.ronstrom@stripped
@@ -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);
 

=== modified file 'storage/innobase/trx/trx0trx.c'
--- a/storage/innobase/trx/trx0trx.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/trx/trx0trx.c	revid:mikael.ronstrom@stripped
@@ -50,6 +50,9 @@ UNIV_INTERN sess_t*		trx_dummy_sess = NU
 /** 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,

=== modified file 'storage/innobase/trx/trx0undo.c'
--- a/storage/innobase/trx/trx0undo.c	revid:mikael.ronstrom@stripped
+++ b/storage/innobase/trx/trx0undo.c	revid:mikael.ronstrom@stripped
@@ -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 */

=== modified file 'storage/myisam/ha_myisam.cc'
--- a/storage/myisam/ha_myisam.cc	revid:mikael.ronstrom@stripped
+++ b/storage/myisam/ha_myisam.cc	revid:mikael.ronstrom@stripped
@@ -643,9 +643,10 @@ ha_myisam::ha_myisam(handlerton *hton, T
    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;

=== modified file 'storage/myisam/ha_myisam.h'
--- a/storage/myisam/ha_myisam.h	revid:mikael.ronstrom@stripped
+++ b/storage/myisam/ha_myisam.h	revid:mikael.ronstrom@stripped
@@ -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;

=== modified file 'storage/myisammrg/ha_myisammrg.cc'
--- a/storage/myisammrg/ha_myisammrg.cc	revid:mikael.ronstrom@stripped
+++ b/storage/myisammrg/ha_myisammrg.cc	revid:mikael.ronstrom@stripped
@@ -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 *m
     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;

=== modified file 'storage/myisammrg/ha_myisammrg.h'
--- a/storage/myisammrg/ha_myisammrg.h	revid:mikael.ronstrom@stripped
+++ b/storage/myisammrg/ha_myisammrg.h	revid:mikael.ronstrom@stripped
@@ -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);

=== modified file 'vio/viosocket.c'
--- a/vio/viosocket.c	revid:mikael.ronstrom@stripped
+++ b/vio/viosocket.c	revid:mikael.ronstrom@stripped
@@ -22,6 +22,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 +587,13 @@ static my_bool socket_poll_read(my_socke
 
 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;

No bundle (reason: revision is a merge (you can force generation of a bundle with env var BZR_FORCE_BUNDLE=1)).
Thread
bzr commit into mysql-5.5 branch (mikael.ronstrom:3142) Mikael Ronstrom4 May