3477 Rafal Somla 2011-04-28
BUG#11879051: FIRST REPLY LENGTH LIMIT (255) CAN BE VIOLATED
BEFORE: First packet sent by client-side plugin (generated by Windows
function InitializeSecurityContext()) could be longer than 255 bytes
violating the limitation imposed by authentication protocol.
AFTER: Handshake protocol is changed so that if first client's reply is
longer than 254 bytes then it is be sent in 2 parts. However, for replies
shorter than 255 bytes nothing changes.
ADDITIONAL CHANGES:
- The generic packet processing loop (Handshake::packet_processing_loop)
has been refactored. Communication with the peer has been abstracted
into virtual methods read/write_packet() which are implemented in client
and server and transparently do the required splitting and gluing of packets.
- Make it possible to optionally use dbug library in the plugin.
- Add code for testing splitting of long first client reply.
modified:
libmysql/authentication_win/CMakeLists.txt
libmysql/authentication_win/common.h
libmysql/authentication_win/handshake.cc
libmysql/authentication_win/handshake.h
libmysql/authentication_win/handshake_client.cc
3476 Rafal Somla 2011-04-28
Bug#11766631 (59780) - Move the client authentication_windows plugin
into the server repository
This patch adds client windows authentication plugin code to the client
library libmysql (only on Windows platform). The plugin is compiled into
the library and added to the list of built-in plugins. This way clients
should be able to connect to a server which uses windows authentication
plugin even as an SQL user which uses such authentication.
Note: this makes the client library to depend on Secur32 Windows system
library. When building clients, they must be linked against Secur32.
Command mysql_config --libs correctly lists Secur32 as a required
dependency.
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
modified:
libmysql/CMakeLists.txt
sql-common/client.c
3475 Georgi Kodinov 2011-04-28
Backport of (part of) bug #11760838 to 5.5.
Enabled the ABI check to run on MacOSX.
modified:
cmake/abi_check.cmake
3474 Georgi Kodinov 2011-04-28
Fixed the ABI check files after the push of bug # 12325444.
modified:
include/mysql/client_plugin.h.pp
3473 Georgi Kodinov 2011-04-06
Bug #12325444 : 60746: CLIENT_PLUGIN.H IS BROKEN
Removed the STDCALL macro and the function from the .def file,
since it's not used by the connectors atm.
modified:
include/mysql/client_plugin.h
libmysql/libmysql.def
3472 Sven Sandberg 2011-04-27
Marked test experimental because it fails due to BUG#12403008
modified:
mysql-test/collections/default.experimental
3471 Nirbhay Choubey 2011-04-27 [merge]
Merge of fix for bug#12329909 from mysql-5.1 -> mysql-5.5.
modified:
cmd-line-utils/libedit/vi.c
3470 Magnus Blåudd 2011-04-27
BUG#47741 rpl_ndb_extraCol fails in next-mr (mysql-5.1-rep+2) in RBR
- fix the fix to properly detect when engine is NDB and
also don't drop the table t9 if it hasn't been created
modified:
mysql-test/extra/rpl_tests/rpl_extra_col_slave.test
3469 Sergey Glukhov 2011-04-27 [merge]
5.1 -> 5.5 merge
@ mysql-test/r/func_time.result
5.1 -> 5.5 merge
@ mysql-test/t/func_time.test
5.1 -> 5.5 merge
@ sql-common/my_time.c
5.1 -> 5.5 merge
@ sql/item_timefunc.cc
5.1 -> 5.5 merge
modified:
mysql-test/r/func_time.result
mysql-test/t/func_time.test
sql-common/my_time.c
sql/item_timefunc.cc
3468 Guilhem Bichot 2011-04-26 [merge]
merge from latest 5.5
modified:
mysql-test/suite/parts/inc/partition_check_drop.inc
mysql-test/suite/parts/inc/partition_layout_check1.inc
mysql-test/suite/parts/inc/partition_layout_check2.inc
3467 Guilhem Bichot 2011-04-26 [merge]
merge from latest 5.5
modified:
sql/ha_partition.cc
3466 Guilhem Bichot 2011-04-26 [merge]
merge from 5.1
modified:
mysql-test/r/loaddata.result
mysql-test/t/loaddata.test
sql/sql_load.cc
3465 Guilhem Bichot 2011-04-26
Fix for Bug#11892055 - "GCC COMPILER FLAG -WOVERLOADED-VIRTUAL NOT USED, WHICH LETS BUGS IN"
modified:
cmake/maintainer.cmake
3464 Serge Kozlov 2011-04-26 [merge]
autocommit 5.1->5.5
modified:
mysql-test/suite/binlog/r/binlog_bug23533.result
mysql-test/suite/binlog/t/binlog_bug23533.test
3463 Mattias Jonsson 2011-04-23 [merge]
merge
3462 Mattias Jonsson 2011-04-23 [merge]
merge
modified:
.bzrignore
sql/ha_partition.cc
sql/ha_partition.h
sql/handler.cc
sql/handler.h
sql/opt_range.cc
storage/heap/ha_heap.cc
storage/heap/ha_heap.h
storage/myisam/ha_myisam.cc
storage/myisam/ha_myisam.h
storage/myisammrg/ha_myisammrg.cc
storage/myisammrg/ha_myisammrg.h
3461 Sergey Glukhov 2011-04-22 [merge]
5.1 -> 5.5 merge
@ mysql-test/r/having.result
5.1 -> 5.5 merge
@ mysql-test/t/having.test
5.1 -> 5.5 merge
@ sql/sql_select.cc
5.1 -> 5.5 merge
modified:
mysql-test/r/having.result
mysql-test/t/having.test
sql/sql_select.cc
3460 Sergey Vojtovich 2011-04-22 [merge]
Merge.
modified:
include/m_ctype.h
sql/mysqld.h
3459 Vasil Dimov 2011-04-21 [merge]
Merge mysql-5.5-innodb -> mysql-5.5
modified:
mysql-test/suite/innodb/t/innodb_bug59641.test
3458 Vasil Dimov 2011-04-21 [merge]
Merge mysql-5.5-innodb -> mysql-5.5
added:
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:
client/mysqltest.cc
sql/sql_class.cc
storage/innobase/btr/btr0cur.c
storage/innobase/buf/buf0flu.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/log0log.ic
storage/innobase/include/os0sync.h
storage/innobase/include/os0thread.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/row0merge.c
storage/innobase/row/row0mysql.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
3457 Jon Olav Hauglid 2011-04-20 [merge]
Null merge from mysql-5.1 to mysql-5.5
3456 Sergey Glukhov 2011-04-20 [merge]
5.1 -> 5.5 merge
@ mysql-test/r/func_math.result
5.1 -> 5.5 merge
@ mysql-test/t/func_math.test
5.1 -> 5.5 merge
@ sql/item_func.cc
5.1 -> 5.5 merge
modified:
mysql-test/r/func_math.result
mysql-test/t/func_math.test
sql/item_func.cc
3455 Serge Kozlov 2011-04-19 [merge]
autocommit 5.1 -> 5.5
modified:
mysql-test/collections/default.experimental
mysql-test/suite/binlog/r/binlog_bug23533.result
mysql-test/suite/binlog/t/binlog_bug23533.test
3454 Sven Sandberg 2011-04-18 [merge]
null merge
3453 Martin Hansson 2011-04-18 [merge]
Merge of test case for bug#11758558 - 50774
modified:
mysql-test/r/type_timestamp.result
mysql-test/t/type_timestamp.test
3452 Bjorn Munch 2011-04-16 [merge]
null upmerge
3451 Bjorn Munch 2011-04-16 [merge]
merge from 5.5-mtr
modified:
mysql-test/lib/My/Find.pm
mysql-test/lib/mtr_gcov.pl
mysql-test/mysql-test-run.pl
3450 Alexander Nozdrin 2011-04-15
A patch for Bug#11763166 (55847: SHOW WARNINGS returns empty
result set when SQLEXCEPTION is active.
The problem was in a hackish THD::no_warnings_for_error attribute.
When it was set, an error was not written to Warning_info -- only
Diagnostics_area state was changed. That means, Diagnostics_area
might contain error state, which is not present in Warning_info.
The user-visible problem was that in some cases SHOW WARNINGS
returned empty result set (i.e. there were no warnings) while
the previous SQL statement failed. According to the MySQL
protocol errors must be presented in warning list.
The main idea of this patch is to remove THD::no_warnings_for_error.
There were few places where it was used:
- sql_admin.cc, handling of REPAIR TABLE USE_FRM.
- sql_show.cc, when calling fill_schema_table_from_frm().
- sql_show.cc, when calling fill_table().
The fix is to either use internal-error-handlers, or to use
temporary Warning_info storing warnings, which might be ignored.
This patch is needed to fix Bug 11763162 (55843).
modified:
mysql-test/r/warnings.result
mysql-test/t/warnings.test
sql/sp_head.cc
sql/sql_admin.cc
sql/sql_class.cc
sql/sql_class.h
sql/sql_error.cc
sql/sql_error.h
sql/sql_parse.cc
sql/sql_prepare.cc
sql/sql_show.cc
sql/sql_trigger.cc
3449 Sergey Glukhov 2011-04-15 [merge]
5.1 -> 5.5 merge
@ mysql-test/r/loaddata.result
5.1 -> 5.5 merge
@ mysql-test/t/loaddata.test
5.1 -> 5.5 merge
@ sql/sql_load.cc
5.1 -> 5.5 merge
modified:
mysql-test/r/loaddata.result
mysql-test/t/loaddata.test
sql/sql_load.cc
3448 Tor Didriksen 2011-04-15 [merge]
Merge fix for Bug#11765713 from 5.1
modified:
mysql-test/r/subselect.result
mysql-test/t/subselect.test
sql/opt_sum.cc
sql/sql_select.cc
sql/sql_select.h
3447 Serge Kozlov 2011-04-14 [merge]
autocommit 5.1 -> 5.5
modified:
mysql-test/suite/binlog/r/binlog_bug23533.result
mysql-test/suite/binlog/t/binlog_bug23533.test
3446 Sergey Glukhov 2011-04-14 [merge]
automerge
@ mysql-test/r/xa.result
automerge
@ mysql-test/t/xa.test
automerge
@ sql/transaction.cc
automerge
modified:
mysql-test/r/xa.result
mysql-test/t/xa.test
sql/transaction.cc
3445 Sergey Glukhov 2011-04-14 [merge]
5.1 -> 5.5 merge
@ mysql-test/r/func_analyse.result
5.1 -> 5.5 merge
@ mysql-test/t/func_analyse.test
5.1 -> 5.5 merge
@ sql/sql_select.cc
5.1 -> 5.5 merge
modified:
mysql-test/r/func_analyse.result
mysql-test/t/func_analyse.test
sql/sql_select.cc
3444 Magne Mahre 2011-04-14
Bug#11766320 MYSQL SYMBOLIC LINKS NOT WORKING
When MySQL converted from autotools to CMake, the
preprocessor symbol USE_SYMDIR was omitted by mistake.
Without this symbol, the code for checking .sym files
is not built.
This patch defines USE_SYMDIR when built on MS Windows.
modified:
cmake/os/Windows.cmake
config.h.cmake
3443 Serge Kozlov 2011-04-14 [merge]
autocommit 5.1->5.5
removed:
mysql-test/suite/bugs/
mysql-test/suite/bugs/combinations
mysql-test/suite/bugs/data/
mysql-test/suite/bugs/data/rpl_bug12691.dat
mysql-test/suite/bugs/r/
mysql-test/suite/bugs/r/bug57108.result
mysql-test/suite/bugs/r/rpl_bug12691.result
mysql-test/suite/bugs/r/rpl_bug31582.result
mysql-test/suite/bugs/r/rpl_bug31583.result
mysql-test/suite/bugs/r/rpl_bug33029.result
mysql-test/suite/bugs/r/rpl_bug38205.result
mysql-test/suite/bugs/t/
mysql-test/suite/bugs/t/bug57108-master.opt
mysql-test/suite/bugs/t/bug57108.test
mysql-test/suite/bugs/t/rpl_bug12691.test
mysql-test/suite/bugs/t/rpl_bug31582.test
mysql-test/suite/bugs/t/rpl_bug31583.test
mysql-test/suite/bugs/t/rpl_bug33029.test
mysql-test/suite/bugs/t/rpl_bug38205.test
renamed:
mysql-test/suite/bugs/r/rpl_bug23533.result => mysql-test/suite/binlog/r/binlog_bug23533.result
mysql-test/suite/bugs/r/rpl_bug36391.result => mysql-test/suite/binlog/r/binlog_bug36391.result
mysql-test/suite/bugs/r/rpl_bug37426.result => mysql-test/suite/rpl/r/rpl_bug37426.result
mysql-test/suite/bugs/t/rpl_bug23533.test => mysql-test/suite/binlog/t/binlog_bug23533.test
mysql-test/suite/bugs/t/rpl_bug36391-master.opt => mysql-test/suite/binlog/t/binlog_bug36391-master.opt
mysql-test/suite/bugs/t/rpl_bug36391.test => mysql-test/suite/binlog/t/binlog_bug36391.test
mysql-test/suite/bugs/t/rpl_bug37426.test => mysql-test/suite/rpl/t/rpl_bug37426.test
modified:
mysql-test/collections/default.experimental
mysql-test/suite/binlog/r/binlog_bug23533.result
mysql-test/suite/binlog/r/binlog_bug36391.result
mysql-test/suite/rpl/r/rpl_bug37426.result
mysql-test/suite/binlog/t/binlog_bug23533.test
mysql-test/suite/binlog/t/binlog_bug36391.test
mysql-test/suite/rpl/t/rpl_bug37426.test
3442 Davi Arnaut 2011-04-13
Remove some leftovers from the removal of the gethostbyname wrappers.
modified:
cmake/os/WindowsCache.cmake
config.h.cmake
configure.cmake
include/my_global.h
mysys/my_init.c
mysys/my_thr_init.c
mysys/mysys_priv.h
sql/mysqld.cc
3441 Davi Arnaut 2011-04-13
Increment the I_P_List counter whenever a element is inserted into
the list. Previously, the counter would only be incremented if the
insertion method push_front() was used, in which case the counter
wouldn't be incremented if a element was inserted using the push_back()
and/or insert_after() methods.
Currently this does not affect the code base because there isn't any
code that uses a counted list with the push_back() or insert_after()
methods.
modified:
sql/sql_plist.h
3440 Anitha Gopi 2011-04-13
Bug#11762246 : Test is not failing in PB2. Remove from experimental group
modified:
mysql-test/collections/default.experimental
3439 Dmitry Lenev 2011-04-13
Bug#11938039 "RE-EXECUTION OF FRM-ONLY ALTER TABLE WITH RENAME
CLAUSE FAILS OR ABORTS SERVER".
Attempt to re-execute prepared ALTER TABLE statement which
involves .FRM-only changes and also have RENAME clause led
to unwarranted 'Table doesn't exist' error in production
builds and assertion failure for debug builds.
This problem stemmed from the fact that for such ALTER TABLE
mysql_alter_table() code changed table list element for table
to be altered when it tried to re-open table under new name.
Since this change was not reverted back before next
re-execution, it made this statement re-execution unsafe.
This fix addresses this problem by avoiding changing table list
element from the main table list in such a situation. Instead
temporary TABLE_LIST object is used.
@ mysql-test/r/alter_table.result
Added test case for bug#11938039 "RE-EXECUTION OF FRM-ONLY
ALTER TABLE WITH RENAME CLAUSE FAILS OR ABORTS SERVER".
@ mysql-test/t/alter_table.test
Added test case for bug#11938039 "RE-EXECUTION OF FRM-ONLY
ALTER TABLE WITH RENAME CLAUSE FAILS OR ABORTS SERVER".
@ sql/sql_table.cc
Changed mysql_alter_table() not to modify table list element
for the table being altered while re-opening table after
.FRM-only changes. Doing this made .FRM-only ALTER TABLE
which also had RENAME clause unsafe for re-execution.
modified:
mysql-test/r/alter_table.result
mysql-test/t/alter_table.test
sql/sql_table.cc
3438 Sven Sandberg 2011-04-12 {bug11766631-base} [merge]
null merge
=== modified file '.bzrignore'
--- a/.bzrignore 2011-03-28 10:57:54 +0000
+++ b/.bzrignore 2011-04-20 17:53:08 +0000
@@ -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 2011-03-22 14:40:25 +0000
+++ b/client/mysqltest.cc 2011-04-11 14:03:32 +0000
@@ -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 2010-10-13 15:11:29 +0000
+++ b/cmake/abi_check.cmake 2011-04-28 10:13:36 +0000
@@ -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 2010-12-15 10:30:09 +0000
+++ b/cmake/maintainer.cmake 2011-04-26 09:18:29 +0000
@@ -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/Windows.cmake'
--- a/cmake/os/Windows.cmake 2010-11-19 23:20:18 +0000
+++ b/cmake/os/Windows.cmake 2011-04-14 08:08:12 +0000
@@ -1,4 +1,4 @@
-# Copyright (C) 2010 Sun Microsystems, Inc
+# Copyright (C) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -192,3 +192,4 @@ IF(NOT HAVE_SIZE_OF_SSIZE_T)
ENDIF()
SET(FN_NO_CASE_SENSE 1)
+SET(USE_SYMDIR 1)
=== modified file 'cmake/os/WindowsCache.cmake'
--- a/cmake/os/WindowsCache.cmake 2010-11-19 23:56:07 +0000
+++ b/cmake/os/WindowsCache.cmake 2011-04-13 19:05:26 +0000
@@ -76,9 +76,6 @@ SET(HAVE_FTRUNCATE CACHE INTERNAL "")
SET(HAVE_GETADDRINFO 1 CACHE INTERNAL "")
SET(HAVE_GETCWD 1 CACHE INTERNAL "")
SET(HAVE_GETHOSTBYADDR_R CACHE INTERNAL "")
-SET(HAVE_GETHOSTBYNAME_R CACHE INTERNAL "")
-SET(HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE CACHE INTERNAL "")
-SET(HAVE_GETHOSTBYNAME_R_RETURN_INT CACHE INTERNAL "")
SET(HAVE_GETHRTIME CACHE INTERNAL "")
SET(HAVE_GETLINE CACHE INTERNAL "")
SET(HAVE_GETNAMEINFO CACHE INTERNAL "")
=== modified file 'cmd-line-utils/libedit/vi.c'
--- a/cmd-line-utils/libedit/vi.c 2010-10-19 22:51:34 +0000
+++ b/cmd-line-utils/libedit/vi.c 2011-04-27 11:57:51 +0000
@@ -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 2011-02-02 18:13:28 +0000
+++ b/config.h.cmake 2011-04-14 08:08:12 +0000
@@ -157,7 +157,6 @@
#cmakedefine HAVE_GETADDRINFO 1
#cmakedefine HAVE_GETCWD 1
#cmakedefine HAVE_GETHOSTBYADDR_R 1
-#cmakedefine HAVE_GETHOSTBYNAME_R 1
#cmakedefine HAVE_GETHRTIME 1
#cmakedefine HAVE_GETLINE 1
#cmakedefine HAVE_GETNAMEINFO 1
@@ -448,8 +447,6 @@
#cmakedefine HAVE_SOLARIS_STYLE_GETHOST 1
-#cmakedefine HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE 1
-#cmakedefine HAVE_GETHOSTBYNAME_R_RETURN_INT 1
#cmakedefine MY_ATOMIC_MODE_DUMMY 1
#cmakedefine MY_ATOMIC_MODE_RWLOCKS 1
@@ -513,6 +510,7 @@
#cmakedefine EXTRA_DEBUG 1
#cmakedefine BACKUP_TEST 1
#cmakedefine CYBOZU 1
+#cmakedefine USE_SYMDIR 1
/* Character sets and collations */
#cmakedefine MYSQL_DEFAULT_CHARSET_NAME "@MYSQL_DEFAULT_CHARSET_NAME@"
=== modified file 'configure.cmake'
--- a/configure.cmake 2011-02-02 18:13:28 +0000
+++ b/configure.cmake 2011-04-13 19:05:26 +0000
@@ -350,7 +350,6 @@ CHECK_FUNCTION_EXISTS (fseeko HAVE_FSEEK
CHECK_FUNCTION_EXISTS (fsync HAVE_FSYNC)
CHECK_FUNCTION_EXISTS (getcwd HAVE_GETCWD)
CHECK_FUNCTION_EXISTS (gethostbyaddr_r HAVE_GETHOSTBYADDR_R)
-CHECK_FUNCTION_EXISTS (gethostbyname_r HAVE_GETHOSTBYNAME_R)
CHECK_FUNCTION_EXISTS (gethrtime HAVE_GETHRTIME)
CHECK_FUNCTION_EXISTS (getnameinfo HAVE_GETNAMEINFO)
CHECK_FUNCTION_EXISTS (getpass HAVE_GETPASS)
@@ -920,44 +919,6 @@ CHECK_CXX_SOURCE_COMPILES("
}
"
HAVE_SOLARIS_STYLE_GETHOST)
-
-CHECK_CXX_SOURCE_COMPILES("
- #undef inline
- #if !defined(SCO) && !defined(__osf__) && !defined(_REENTRANT)
- #define _REENTRANT
- #endif
- #include <pthread.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- int main()
- {
- int ret = gethostbyname_r((const char *) 0,
- (struct hostent*) 0, (char*) 0, 0, (struct hostent **) 0, (int *) 0);
- return 0;
- }"
- HAVE_GETHOSTBYNAME_R_GLIBC2_STYLE)
-
-CHECK_CXX_SOURCE_COMPILES("
- #undef inline
- #if !defined(SCO) && !defined(__osf__) && !defined(_REENTRANT)
- #define _REENTRANT
- #endif
- #include <pthread.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- int main()
- {
- int ret = gethostbyname_r((const char *) 0, (struct hostent*) 0, (struct hostent_data*) 0);
- return 0;
- }"
- HAVE_GETHOSTBYNAME_R_RETURN_INT)
-
# Use of ALARMs to wakeup on timeout on sockets
#
=== modified file 'include/m_ctype.h'
--- a/include/m_ctype.h 2010-12-01 22:15:14 +0000
+++ b/include/m_ctype.h 2011-03-18 06:37:08 +0000
@@ -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/my_global.h'
--- a/include/my_global.h 2011-03-29 12:43:49 +0000
+++ b/include/my_global.h 2011-04-13 19:05:26 +0000
@@ -301,9 +301,6 @@ C_MODE_END
#undef HAVE_PWRITE
#endif
-#ifdef UNDEF_HAVE_GETHOSTBYNAME_R /* For OSF4.x */
-#undef HAVE_GETHOSTBYNAME_R
-#endif
#ifdef UNDEF_HAVE_INITGROUPS /* For AIX 4.3 */
#undef HAVE_INITGROUPS
#endif
=== modified file 'include/mysql/client_plugin.h'
--- a/include/mysql/client_plugin.h 2010-11-10 15:55:57 +0000
+++ b/include/mysql/client_plugin.h 2011-04-06 14:31:26 +0000
@@ -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 2010-10-13 15:11:29 +0000
+++ b/include/mysql/client_plugin.h.pp 2011-04-28 10:08:05 +0000
@@ -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 2011-03-28 08:49:43 +0000
+++ b/libmysql/CMakeLists.txt 2011-04-28 19:17:29 +0000
@@ -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
@@ -150,6 +156,10 @@ DTRACE_INSTRUMENT(clientlib)
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.
=== 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 2011-04-28 19:39:42 +0000
@@ -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 2011-04-28 19:17:29 +0000
@@ -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 2011-04-28 19:39:42 +0000
@@ -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 2011-04-28 19:39:42 +0000
@@ -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 2011-04-28 19:39:42 +0000
@@ -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 2011-04-28 19:39:42 +0000
@@ -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 2011-04-28 19:17:29 +0000
@@ -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 2011-04-28 19:17:29 +0000
@@ -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 2010-10-04 12:54:41 +0000
+++ b/libmysql/libmysql.def 2011-04-06 14:31:26 +0000
@@ -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 2011-04-12 11:17:25 +0000
+++ b/mysql-test/collections/default.experimental 2011-04-27 12:57:45 +0000
@@ -2,6 +2,7 @@
# in alphabetical order. This also helps with merge conflict resolution.
binlog.binlog_multi_engine # joro : NDB tests marked as experimental as agreed with bochklin
+binlog.binlog_bug23533 # skozlov: BUG#12371924
funcs_1.charset_collation_1 # depends on compile-time decisions
@@ -14,11 +15,11 @@ 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
sys_vars.max_sp_recursion_depth_func @solaris # Bug#47791 2010-01-20 alik Several test cases fail on Solaris with error Thread stack overrun
sys_vars.plugin_dir_basic # Bug#52223 2010-11-24 alik Test "plugin_dir_basic" does not support RPM build (test) directory structure
-sys_vars.slow_query_log_func @solaris # Bug#54819 2010-06-26 alik sys_vars.slow_query_log_func fails sporadically on Solaris 10
sys_vars.wait_timeout_func # Bug#41255 2010-04-26 alik wait_timeout_func fails
# BUG #59055 : All ndb tests should be removed from the repository
=== modified file 'mysql-test/extra/rpl_tests/rpl_extra_col_slave.test'
--- a/mysql-test/extra/rpl_tests/rpl_extra_col_slave.test 2011-02-23 11:54:58 +0000
+++ b/mysql-test/extra/rpl_tests/rpl_extra_col_slave.test 2011-04-27 09:02:34 +0000
@@ -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/Find.pm'
--- a/mysql-test/lib/My/Find.pm 2011-02-24 14:11:05 +0000
+++ b/mysql-test/lib/My/Find.pm 2011-04-15 08:37:20 +0000
@@ -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/mtr_gcov.pl'
--- a/mysql-test/lib/mtr_gcov.pl 2011-01-18 11:01:40 +0000
+++ b/mysql-test/lib/mtr_gcov.pl 2011-04-14 12:25:15 +0000
@@ -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 2011-04-07 08:12:52 +0000
+++ b/mysql-test/mysql-test-run.pl 2011-04-15 08:37:20 +0000
@@ -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;
@@ -507,7 +507,7 @@ sub main {
mtr_print_line();
if ( $opt_gcov ) {
- gcov_collect($basedir, $opt_gcov_exe,
+ gcov_collect($bindir, $opt_gcov_exe,
$opt_gcov_msg, $opt_gcov_err);
}
@@ -1198,7 +1198,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 +1209,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;
=== modified file 'mysql-test/r/alter_table.result'
--- a/mysql-test/r/alter_table.result 2011-02-21 11:30:08 +0000
+++ b/mysql-test/r/alter_table.result 2011-04-13 06:16:40 +0000
@@ -1391,3 +1391,16 @@ CREATE DATABASE db1 CHARACTER SET utf8;
CREATE TABLE db1.t1 (bar TINYTEXT, KEY (bar(100)));
ALTER TABLE db1.t1 ADD baz INT;
DROP DATABASE db1;
+#
+# Bug#11938039 RE-EXECUTION OF FRM-ONLY ALTER TABLE WITH RENAME
+# CLAUSE FAILS OR ABORTS SERVER.
+#
+drop table if exists t1;
+create table t1 (a int);
+prepare stmt1 from 'alter table t1 alter column a set default 1, rename to t2';
+execute stmt1;
+rename table t2 to t1;
+# The below statement should succeed and not emit error or abort server.
+execute stmt1;
+deallocate prepare stmt1;
+drop table t2;
=== modified file 'mysql-test/r/func_analyse.result'
--- a/mysql-test/r/func_analyse.result 2011-03-14 18:06:44 +0000
+++ b/mysql-test/r/func_analyse.result 2011-04-14 09:10:11 +0000
@@ -135,4 +135,17 @@ SELECT * FROM t1 PROCEDURE ANALYSE();
Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
test.t1.a e e- 1 2 0 0 1.3333 NULL ENUM('e','e-') NOT NULL
DROP TABLE t1;
+#
+# Bug#11756242 48137: PROCEDURE ANALYSE() LEAKS MEMORY WHEN RETURNING NULL
+#
+CREATE TABLE t1(f1 INT) ENGINE=MYISAM;
+CREATE TABLE t2(f2 INT) ENGINE=INNODB;
+INSERT INTO t2 VALUES (1);
+SELECT DISTINCTROW f1 FROM t1 NATURAL RIGHT OUTER JOIN t2 PROCEDURE ANALYSE();
+Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
+test.t1.f1 NULL NULL 0 0 0 1 0.0 0.0 CHAR(0)
+SELECT * FROM t2 LIMIT 1 PROCEDURE ANALYSE();
+Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype
+test.t2.f2 1 1 1 1 0 0 1.0000 0.0000 ENUM('1') NOT NULL
+DROP TABLE t1, t2;
End of 5.1 tests
=== modified file 'mysql-test/r/func_math.result'
--- a/mysql-test/r/func_math.result 2011-03-28 08:52:47 +0000
+++ b/mysql-test/r/func_math.result 2011-04-20 07:52:40 +0000
@@ -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 2011-03-30 07:25:49 +0000
+++ b/mysql-test/r/func_time.result 2011-04-27 07:46:23 +0000
@@ -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 2010-07-09 10:46:46 +0000
+++ b/mysql-test/r/having.result 2011-04-22 07:39:42 +0000
@@ -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 2010-07-14 12:05:20 +0000
+++ b/mysql-test/r/loaddata.result 2011-04-26 09:52:58 +0000
@@ -532,4 +532,20 @@ a
0
1
DROP TABLE t1;
+#
+# Bug#11765139 58069: LOAD DATA INFILE: VALGRIND REPORTS INVALID MEMORY READS AND WRITES WITH U
+#
+CREATE TABLE t1(f1 INT);
+SELECT 0xE1BB30 INTO OUTFILE 't1.dat';
+LOAD DATA INFILE 't1.dat' IGNORE INTO TABLE t1 CHARACTER SET utf8;
+DROP TABLE t1;
+#
+# Bug#11765141 - 58072: LOAD DATA INFILE: LEAKS IO CACHE MEMORY
+# WHEN ERROR OCCURS
+#
+SELECT '1\n' INTO DUMPFILE 'MYSQLTEST_VARDIR/tmp/bug11735141.txt';
+create table t1(a point);
+LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug11735141.txt' INTO TABLE t1;
+ERROR 22003: Cannot get geometry object from data you send to the GEOMETRY field
+drop table t1;
End of 5.1 tests
=== modified file 'mysql-test/r/subselect.result'
--- a/mysql-test/r/subselect.result 2011-01-12 12:15:22 +0000
+++ b/mysql-test/r/subselect.result 2011-04-15 06:54:05 +0000
@@ -5058,6 +5058,24 @@ i
DROP TABLE t1,t1s,t2s;
End of 5.1 tests
#
+# Bug #11765713 58705:
+# OPTIMIZER LET ENGINE DEPEND ON UNINITIALIZED VALUES
+# CREATED BY OPT_SUM_QUERY
+#
+CREATE TABLE t1(a INT NOT NULL, KEY (a));
+INSERT INTO t1 VALUES (0), (1);
+SELECT 1 as foo FROM t1 WHERE a < SOME
+(SELECT a FROM t1 WHERE a <=>
+(SELECT a FROM t1)
+);
+ERROR 21000: Subquery returns more than 1 row
+SELECT 1 as foo FROM t1 WHERE a < SOME
+(SELECT a FROM t1 WHERE a <=>
+(SELECT a FROM t1 where a is null)
+);
+foo
+DROP TABLE t1;
+#
# Bug #57704: Cleanup code dies with void TABLE::set_keyread(bool):
# Assertion `file' failed.
#
=== modified file 'mysql-test/r/type_timestamp.result'
--- a/mysql-test/r/type_timestamp.result 2011-01-12 12:58:47 +0000
+++ b/mysql-test/r/type_timestamp.result 2011-04-18 08:46:17 +0000
@@ -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/r/warnings.result'
--- a/mysql-test/r/warnings.result 2010-02-24 13:52:27 +0000
+++ b/mysql-test/r/warnings.result 2011-04-15 12:02:22 +0000
@@ -316,3 +316,25 @@ SHOW ERRORS;
Level Code Message
Error 1051 Unknown table 't1'
End of 5.0 tests
+
+-- Bug#55847
+
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS f1;
+CREATE TABLE t1(a INT UNIQUE);
+CREATE FUNCTION f1(x INT) RETURNS INT
+BEGIN
+INSERT INTO t1 VALUES(x);
+INSERT INTO t1 VALUES(x);
+RETURN x;
+END|
+
+SHOW TABLES WHERE f1(11) = 11;
+ERROR 23000: Duplicate entry '11' for key 'a'
+
+SHOW WARNINGS;
+Level Code Message
+Error 1062 Duplicate entry '11' for key 'a'
+
+DROP TABLE t1;
+DROP FUNCTION f1;
=== modified file 'mysql-test/r/xa.result'
--- a/mysql-test/r/xa.result 2011-04-12 10:57:02 +0000
+++ b/mysql-test/r/xa.result 2011-04-14 08:13:28 +0000
@@ -200,3 +200,32 @@ SELECT * FROM t1;
a
1
DROP TABLE t1;
+#
+# Bug#12352846 - TRANS_XA_START(THD*):
+# ASSERTION THD->TRANSACTION.XID_STATE.XID.IS_NULL()
+# FAILED
+#
+DROP TABLE IF EXISTS t1, t2;
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (a INT);
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+# Connection con2
+XA START 'xid1';
+# Sending:
+INSERT INTO t2 SELECT a FROM t1;
+# Connection default
+# Waiting until INSERT ... is blocked
+DELETE FROM t1;
+COMMIT;
+# Connection con2
+# Reaping: INSERT INTO t2 SELECT a FROM t1
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+XA COMMIT 'xid1';
+ERROR XA102: XA_RBDEADLOCK: Transaction branch was rolled back: deadlock was detected
+XA START 'xid1';
+XA END 'xid1';
+XA PREPARE 'xid1';
+XA ROLLBACK 'xid1';
+# Connection default
+DROP TABLE t1, t2;
=== renamed file 'mysql-test/suite/bugs/r/rpl_bug23533.result' => 'mysql-test/suite/binlog/r/binlog_bug23533.result'
--- a/mysql-test/suite/bugs/r/rpl_bug23533.result 2008-02-28 21:50:15 +0000
+++ b/mysql-test/suite/binlog/r/binlog_bug23533.result 2011-04-25 19:49:56 +0000
@@ -1,23 +1,15 @@
-stop slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-reset master;
-reset slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-start slave;
-DROP TABLE IF EXISTS t1,t2;
SET AUTOCOMMIT=0;
-SET GLOBAL max_binlog_cache_size=4096;
-SHOW VARIABLES LIKE 'max_binlog_cache_size';
-Variable_name Value
-max_binlog_cache_size 4096
CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT, b TEXT, PRIMARY KEY(a)) ENGINE=InnoDB;
SELECT COUNT(*) FROM t1;
COUNT(*)
1000
+SET GLOBAL binlog_cache_size=4096;
+SET GLOBAL max_binlog_cache_size=4096;
START TRANSACTION;
CREATE TABLE t2 SELECT * FROM t1;
-ERROR HY000: Writing one row to the row-based binary log failed
+ERROR HY000: Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage; increase this mysqld variable and try again
COMMIT;
SHOW TABLES LIKE 't%';
Tables_in_test (t%)
t1
+DROP TABLE t1;
=== renamed file 'mysql-test/suite/bugs/r/rpl_bug36391.result' => 'mysql-test/suite/binlog/r/binlog_bug36391.result'
--- a/mysql-test/suite/bugs/r/rpl_bug36391.result 2010-05-24 13:54:08 +0000
+++ b/mysql-test/suite/binlog/r/binlog_bug36391.result 2011-04-13 20:18:08 +0000
@@ -1,18 +1,10 @@
-stop slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-reset master;
-reset slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-start slave;
-drop table if exists t1;
-Warnings:
-Note 1051 Unknown table 't1'
-create table t1(id int);
-show tables;
+CREATE TABLE t1(id INT);
+SHOW TABLES;
Tables_in_test
t1
-show master status;
-File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000001 # <Binlog_Do_DB> <Binlog_Ignore_DB>
-flush logs;
-drop table t1;
+FLUSH LOGS;
+DROP TABLE t1;
+SHOW TABLES;
+Tables_in_test
+t1
+DROP TABLE t1;
=== renamed file 'mysql-test/suite/bugs/t/rpl_bug23533.test' => 'mysql-test/suite/binlog/t/binlog_bug23533.test'
--- a/mysql-test/suite/bugs/t/rpl_bug23533.test 2010-12-19 17:07:28 +0000
+++ b/mysql-test/suite/binlog/t/binlog_bug23533.test 2011-04-25 19:49:56 +0000
@@ -4,33 +4,47 @@
#############################################################
--source include/have_innodb.inc
+--source include/have_log_bin.inc
--source include/have_binlog_format_row.inc
---source include/master-slave.inc
SET AUTOCOMMIT=0;
-SET GLOBAL max_binlog_cache_size=4096;
-SHOW VARIABLES LIKE 'max_binlog_cache_size';
+# Create 1st table
CREATE TABLE t1 (a INT NOT NULL AUTO_INCREMENT, b TEXT, PRIMARY KEY(a)) ENGINE=InnoDB;
-
--disable_query_log
let $i= 1000;
while ($i)
{
+ BEGIN;
eval INSERT INTO t1 VALUES($i, REPEAT('x', 4096));
+ COMMIT;
dec $i;
}
--enable_query_log
-
SELECT COUNT(*) FROM t1;
+# Set small value for max_binlog_cache_size
+let $saved_binlog_cache_size= query_get_value(SELECT @@binlog_cache_size AS Value, Value, 1);
+let $saved_max_binlog_cache_size= query_get_value(SELECT @@max_binlog_cache_size AS Value, Value, 1);
+SET GLOBAL binlog_cache_size=4096;
+SET GLOBAL max_binlog_cache_size=4096;
+
+# New value of max_binlog_cache_size will apply to new session
+disconnect default;
+connect(default,localhost,root,,test);
+
# Copied data from t1 into t2 large than max_binlog_cache_size
START TRANSACTION;
---error 1534
+--error 1197
CREATE TABLE t2 SELECT * FROM t1;
COMMIT;
SHOW TABLES LIKE 't%';
-
# 5.1 End of Test
---source include/rpl_end.inc
+--disable_query_log
+eval SET GLOBAL max_binlog_cache_size=$saved_max_binlog_cache_size;
+eval SET GLOBAL binlog_cache_size=$saved_binlog_cache_size;
+--enable_query_log
+DROP TABLE t1;
+disconnect default;
+connect(default,localhost,root,,test);
=== renamed file 'mysql-test/suite/bugs/t/rpl_bug36391-master.opt' => 'mysql-test/suite/binlog/t/binlog_bug36391-master.opt'
=== renamed file 'mysql-test/suite/bugs/t/rpl_bug36391.test' => 'mysql-test/suite/binlog/t/binlog_bug36391.test'
--- a/mysql-test/suite/bugs/t/rpl_bug36391.test 2010-12-19 17:07:28 +0000
+++ b/mysql-test/suite/binlog/t/binlog_bug36391.test 2011-04-13 20:18:08 +0000
@@ -13,17 +13,18 @@
#
#
---source include/master-slave.inc
+--source include/have_log_bin.inc
+--source include/have_binlog_format_mixed.inc
-create table t1(id int);
+CREATE TABLE t1(id INT);
+let $binlog= query_get_value(SHOW MASTER STATUS, File, 1);
+let $binlog_path= `SELECT CONCAT(@@DATADIR, '$binlog')`;
+SHOW TABLES;
+FLUSH LOGS;
+DROP TABLE t1;
-show tables;
+--exec $MYSQL_BINLOG $binlog_path | $MYSQL test
+SHOW TABLES;
---source include/show_master_status.inc
-
-flush logs;
-
---exec $MYSQL_BINLOG $MYSQL_TEST_DIR/var/log/master-bin.000001 | $MYSQL test
-
-drop table t1;
---source include/rpl_end.inc
+# Clean up
+DROP TABLE t1;
=== removed directory 'mysql-test/suite/bugs'
=== removed file 'mysql-test/suite/bugs/combinations'
--- a/mysql-test/suite/bugs/combinations 2008-09-05 13:31:09 +0000
+++ b/mysql-test/suite/bugs/combinations 1970-01-01 00:00:00 +0000
@@ -1,8 +0,0 @@
-[row]
-binlog-format=row
-
-[stmt]
-binlog-format=statement
-
-[mix]
-binlog-format=mixed
=== removed directory 'mysql-test/suite/bugs/data'
=== removed file 'mysql-test/suite/bugs/data/rpl_bug12691.dat'
--- a/mysql-test/suite/bugs/data/rpl_bug12691.dat 2008-01-31 13:23:27 +0000
+++ b/mysql-test/suite/bugs/data/rpl_bug12691.dat 1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
-a
-b
-c
=== removed directory 'mysql-test/suite/bugs/r'
=== removed file 'mysql-test/suite/bugs/r/bug57108.result'
--- a/mysql-test/suite/bugs/r/bug57108.result 2010-11-04 10:00:59 +0000
+++ b/mysql-test/suite/bugs/r/bug57108.result 1970-01-01 00:00:00 +0000
@@ -1,5 +0,0 @@
-INSTALL PLUGIN example SONAME 'ha_example.so';
-SELECT @@global.connect_timeout AS connect_timeout, @@global.local_infile AS local_infile;
-connect_timeout 4711
-local_infile 1
-UNINSTALL PLUGIN example;
=== removed file 'mysql-test/suite/bugs/r/rpl_bug12691.result'
--- a/mysql-test/suite/bugs/r/rpl_bug12691.result 2010-05-24 13:54:08 +0000
+++ b/mysql-test/suite/bugs/r/rpl_bug12691.result 1970-01-01 00:00:00 +0000
@@ -1,33 +0,0 @@
-stop slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-reset master;
-reset slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-start slave;
-
-**** On Master ****
-CREATE TABLE t1 (b CHAR(10));
-
-**** On Slave ****
-STOP SLAVE;
-
-**** On Master ****
-LOAD DATA INFILE FILENAME
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-3
-show binlog events from <binlog_start>;
-Log_name Pos Event_type Server_id End_log_pos Info
-master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (b CHAR(10))
-master-bin.000001 # Begin_load_query # # ;file_id=#;block_len=#
-master-bin.000001 # Execute_load_query # # use `test`; LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/rpl_bug12691.dat' INTO TABLE `t1` FIELDS TERMINATED BY '|' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`b`) ;file_id=#
-
-**** On Slave ****
-SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
-START SLAVE;
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-0
-
-**** On Master ****
-DROP TABLE t1;
=== removed file 'mysql-test/suite/bugs/r/rpl_bug31582.result'
--- a/mysql-test/suite/bugs/r/rpl_bug31582.result 2007-12-05 19:49:50 +0000
+++ b/mysql-test/suite/bugs/r/rpl_bug31582.result 1970-01-01 00:00:00 +0000
@@ -1,16 +0,0 @@
-stop slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-reset master;
-reset slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-start slave;
-CREATE TABLE t1 (a VARCHAR(10) PRIMARY KEY) ENGINE=MyISAM;
-INSERT INTO t1 VALUES ('a');
-UPDATE t1 SET a = 'MyISAM';
-SELECT * FROM t1 ORDER BY a;
-a
-MyISAM
-SELECT * FROM t1 ORDER BY a;
-a
-MyISAM
-DROP TABLE t1;
=== removed file 'mysql-test/suite/bugs/r/rpl_bug31583.result'
--- a/mysql-test/suite/bugs/r/rpl_bug31583.result 2008-02-18 14:48:17 +0000
+++ b/mysql-test/suite/bugs/r/rpl_bug31583.result 1970-01-01 00:00:00 +0000
@@ -1,16 +0,0 @@
-stop slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-reset master;
-reset slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-start slave;
-CREATE TABLE t1 ( a INT, b INT DEFAULT -3 );
-INSERT INTO t1 VALUES (1, DEFAULT);
-UPDATE t1 SET a = 3;
-SELECT * FROM t1 ORDER BY a;
-a b
-3 -3
-SELECT * FROM t1 ORDER BY a;
-a b
-3 -3
-DROP TABLE t1;
=== removed file 'mysql-test/suite/bugs/r/rpl_bug33029.result'
--- a/mysql-test/suite/bugs/r/rpl_bug33029.result 2008-06-19 18:47:59 +0000
+++ b/mysql-test/suite/bugs/r/rpl_bug33029.result 1970-01-01 00:00:00 +0000
@@ -1,15 +0,0 @@
-stop slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-reset master;
-reset slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-start slave;
-create table `t1` (`id` int not null auto_increment primary key);
-create trigger `trg` before insert on `t1` for each row begin end;
-set @@global.debug="+d,simulate_bug33029";
-stop slave;
-start slave;
-insert into `t1` values ();
-select * from t1;
-id
-1
=== removed file 'mysql-test/suite/bugs/r/rpl_bug38205.result'
--- a/mysql-test/suite/bugs/r/rpl_bug38205.result 2009-04-09 13:05:41 +0000
+++ b/mysql-test/suite/bugs/r/rpl_bug38205.result 1970-01-01 00:00:00 +0000
@@ -1,56 +0,0 @@
-stop slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-reset master;
-reset slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-start slave;
-create table t1i(n int primary key) engine=innodb;
-create table t2m(n int primary key) engine=myisam;
-begin;
-insert into t1i values (1);
-insert into t1i values (2);
-insert into t1i values (3);
-commit;
-begin;
-insert into t1i values (5);
-begin;
-insert into t1i values (4);
-insert into t2m values (1);
-update t1i set n = 5 where n = 4;
-commit;
-zero
-0
-*** kill sql thread ***
-rollback;
-*** sql thread is *not* running: No ***
-*** the prove: the killed slave has not finished the current transaction ***
-three
-3
-one
-1
-zero
-0
-delete from t2m;
-start slave sql_thread;
-delete from t1i;
-delete from t2m;
-begin;
-insert into t1i values (5);
-begin;
-insert into t1i values (4);
-update t1i set n = 5 where n = 4;
-commit;
-zero
-0
-stop slave sql_thread;
-rollback;
-*** sql thread is *not* running: No ***
-*** the prove: the stopped slave has rolled back the current transaction ***
-zero
-0
-zero
-0
-one
-1
-start slave sql_thread;
-drop table t1i, t2m;
=== removed directory 'mysql-test/suite/bugs/t'
=== removed file 'mysql-test/suite/bugs/t/bug57108-master.opt'
--- a/mysql-test/suite/bugs/t/bug57108-master.opt 2010-11-04 10:00:59 +0000
+++ b/mysql-test/suite/bugs/t/bug57108-master.opt 1970-01-01 00:00:00 +0000
@@ -1,2 +0,0 @@
---defaults-file=std_data/bug57108.cnf
-$EXAMPLE_PLUGIN_OPT
=== removed file 'mysql-test/suite/bugs/t/bug57108.test'
--- a/mysql-test/suite/bugs/t/bug57108.test 2011-01-11 13:27:03 +0000
+++ b/mysql-test/suite/bugs/t/bug57108.test 1970-01-01 00:00:00 +0000
@@ -1,12 +0,0 @@
---source include/not_windows_embedded.inc
---source include/have_example_plugin.inc
-
-# Test that we can install a plugin despite the fact that we have
-# switched directory after starting the server and am using a relative
-# --defaults-file.
---replace_regex /\.dll/.so/
-eval INSTALL PLUGIN example SONAME '$EXAMPLE_PLUGIN';
-
---query_vertical SELECT @@global.connect_timeout AS connect_timeout, @@global.local_infile AS local_infile
-
-UNINSTALL PLUGIN example;
=== removed file 'mysql-test/suite/bugs/t/rpl_bug12691.test'
--- a/mysql-test/suite/bugs/t/rpl_bug12691.test 2010-12-19 17:15:12 +0000
+++ b/mysql-test/suite/bugs/t/rpl_bug12691.test 1970-01-01 00:00:00 +0000
@@ -1,48 +0,0 @@
-# Bug#12691: Exec_master_log_pos corrupted with SQL_SLAVE_SKIP_COUNTER
-
---source include/master-slave.inc
---source include/have_binlog_format_mixed_or_statement.inc
-
---echo
---echo **** On Master ****
-CREATE TABLE t1 (b CHAR(10));
---echo
---echo **** On Slave ****
---sync_slave_with_master
-STOP SLAVE;
---source include/wait_for_slave_to_stop.inc
-
---connection master
-
---echo
---echo **** On Master ****
---exec cp $MYSQL_TEST_DIR/suite/bugs/data/rpl_bug12691.dat $MYSQLTEST_VARDIR/tmp/
---echo LOAD DATA INFILE FILENAME
---disable_query_log
---eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/rpl_bug12691.dat' INTO TABLE t1 FIELDS TERMINATED BY '|'
---enable_query_log
---remove_file $MYSQLTEST_VARDIR/tmp/rpl_bug12691.dat
-
-SELECT COUNT(*) FROM t1;
-
-source include/show_binlog_events.inc;
-
---save_master_pos
-
---connection slave
---echo
---echo **** On Slave ****
-SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
-START SLAVE;
---source include/wait_for_slave_to_start.inc
---sync_with_master
-
-SELECT COUNT(*) FROM t1;
-
-# Clean up
---connection master
---echo
---echo **** On Master ****
-DROP TABLE t1;
-
---source include/rpl_end.inc
=== removed file 'mysql-test/suite/bugs/t/rpl_bug31582.test'
--- a/mysql-test/suite/bugs/t/rpl_bug31582.test 2010-12-19 17:07:28 +0000
+++ b/mysql-test/suite/bugs/t/rpl_bug31582.test 1970-01-01 00:00:00 +0000
@@ -1,25 +0,0 @@
-
-# BUG#31582: 5.1-telco-6.1 -> 5.1.22. Slave crashes when reading
-# UPDATE for VARCHAR
-
-# This is a problem for any update statement replicating from an old
-# server to a new server. The bug consisted of a new slave trying to
-# read two column bitmaps, but there is only one available in the old
-# format.
-
-# This test case should be executed replicating from an old server to
-# a new server, so make sure you have one handy.
-
-source include/master-slave.inc;
-
-CREATE TABLE t1 (a VARCHAR(10) PRIMARY KEY) ENGINE=MyISAM;
-INSERT INTO t1 VALUES ('a');
-UPDATE t1 SET a = 'MyISAM';
-SELECT * FROM t1 ORDER BY a;
-sync_slave_with_master;
-SELECT * FROM t1 ORDER BY a;
-
-connection master;
-DROP TABLE t1;
-
---source include/rpl_end.inc
=== removed file 'mysql-test/suite/bugs/t/rpl_bug31583.test'
--- a/mysql-test/suite/bugs/t/rpl_bug31583.test 2010-12-19 17:07:28 +0000
+++ b/mysql-test/suite/bugs/t/rpl_bug31583.test 1970-01-01 00:00:00 +0000
@@ -1,25 +0,0 @@
-#
-# BUG#31583: 5.1-telco-6.1 -> 5.1.22. Slave returns Error in unknown event
-
-# This is a problem for any update statement replicating from an old
-# server to a new server. The bug consisted of a new slave trying to
-# read two column bitmaps, but there is only one available in the old
-# format.
-
-# This test case should be executed replicating from an old server to
-# a new server, so make sure you have one handy.
-
-source include/master-slave.inc;
-
-CREATE TABLE t1 ( a INT, b INT DEFAULT -3 );
-
-INSERT INTO t1 VALUES (1, DEFAULT);
-UPDATE t1 SET a = 3;
-SELECT * FROM t1 ORDER BY a;
-sync_slave_with_master;
-SELECT * FROM t1 ORDER BY a;
-
-connection master;
-DROP TABLE t1;
-
---source include/rpl_end.inc
=== removed file 'mysql-test/suite/bugs/t/rpl_bug33029.test'
--- a/mysql-test/suite/bugs/t/rpl_bug33029.test 2010-12-19 17:07:28 +0000
+++ b/mysql-test/suite/bugs/t/rpl_bug33029.test 1970-01-01 00:00:00 +0000
@@ -1,26 +0,0 @@
-#
-# Bug #36443 Server crashes when executing insert when insert trigger on table
-#
-# Emulating the former bug#33029 situation to see that there is no crash anymore.
-#
-
-
-source include/master-slave.inc;
-
-create table `t1` (`id` int not null auto_increment primary key);
-create trigger `trg` before insert on `t1` for each row begin end;
-
-sync_slave_with_master;
-set @@global.debug="+d,simulate_bug33029";
-
-stop slave;
-start slave;
-
-connection master;
-
-insert into `t1` values ();
-
-sync_slave_with_master;
-select * from t1;
-
---source include/rpl_end.inc
=== removed file 'mysql-test/suite/bugs/t/rpl_bug38205.test'
--- a/mysql-test/suite/bugs/t/rpl_bug38205.test 2010-12-19 17:07:28 +0000
+++ b/mysql-test/suite/bugs/t/rpl_bug38205.test 1970-01-01 00:00:00 +0000
@@ -1,166 +0,0 @@
-#
-# Bug #38205 Row-based Replication (RBR) causes inconsistencies: HA_ERR_FOUND_DUPP_KEY
-# Bug#319 if while a non-transactional slave is replicating a transaction possible problem
-#
-# Verifying the fact that STOP SLAVE in the middle of a group execution waits
-# for the end of the group before the slave sql thread will stop.
-# The patch refines STOP SLAVE to not interrupt a transaction or other type of
-# the replication events group (the part I).
-# Killing the sql thread continues to provide a "hard" stop (the part II).
-#
-# Non-deterministic tests
-#
-
-source include/master-slave.inc;
-source include/have_innodb.inc;
-
-
-#
-# Part II, killed sql slave leaves instantly
-#
-
-# A. multi-statement transaction as the replication group
-
-connection master;
-
-create table t1i(n int primary key) engine=innodb;
-create table t2m(n int primary key) engine=myisam;
-
-sync_slave_with_master;
-
-connection master;
-
-begin;
-insert into t1i values (1);
-insert into t1i values (2);
-insert into t1i values (3);
-commit;
-
-sync_slave_with_master;
-
-#
-# todo: first challenge is to find out the SQL thread id
-# the following is not fully reliable
-#
-
-let $id=`SELECT id from information_schema.processlist where user like 'system user' and state like '%Has read all relay log%' or user like 'system user' and state like '%Reading event from the relay log%'`;
-connection slave;
-begin;
-insert into t1i values (5);
-
-connection master;
-let $pos0_master= query_get_value(SHOW MASTER STATUS, Position, 1);
-begin;
-insert into t1i values (4);
-insert into t2m values (1); # non-ta update
-update t1i set n = 5 where n = 4; # to block at. can't be played with killed
-commit;
-let $pos1_master= query_get_value(SHOW MASTER STATUS, Position, 1);
-
-connection slave;
-# slave sql thread must be locked out by the conn `slave' explicit lock
-let $pos0_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
---disable_query_log
-eval select $pos0_master - $pos0_slave as zero;
---enable_query_log
-
-connection slave1;
-
-let $count= 1;
-let $table= t2m;
-source include/wait_until_rows_count.inc;
-#
-# todo: may fail as said above
-#
---echo *** kill sql thread ***
---disable_query_log
-eval kill connection $id;
---enable_query_log
-
-connection slave;
-rollback; # release the sql thread
-
-connection slave1;
-
-source include/wait_for_slave_sql_to_stop.inc;
-let $sql_status= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1);
---echo *** sql thread is *not* running: $sql_status ***
-let $pos1_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
-
-connection slave;
---echo *** the prove: the killed slave has not finished the current transaction ***
-
---disable_query_log
-select count(*) as three from t1i;
-eval select $pos1_master > $pos1_slave as one;
-eval select $pos1_slave - $pos0_slave as zero;
---enable_query_log
-
-delete from t2m; # remove the row to be able to replay
-start slave sql_thread;
-
-#
-# Part I: B The homogenous transaction remains interuptable in between
-#
-
-connection master;
-delete from t1i;
-delete from t2m;
-
-sync_slave_with_master;
-begin;
-insert into t1i values (5);
-
-connection master;
-let $pos0_master= query_get_value(SHOW MASTER STATUS, Position, 1);
-begin;
-insert into t1i values (4);
-update t1i set n = 5 where n = 4; # to block at. not to be played
-commit;
-let $pos1_master= query_get_value(SHOW MASTER STATUS, Position, 1);
-
-
-connection slave1;
-# slave sql can't advance as must be locked by the conn `slave' trans
-let $pos0_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
---disable_query_log
-eval select $pos0_master - $pos0_slave as zero;
---enable_query_log
-
-#
-# the replicated trans is blocked by the slave's local.
-# However, it's not easy to catch the exact moment when it happens.
-# The test issues sleep which makes the test either non-deterministic or
-# wasting too much time.
-#
---sleep 3
-
-send stop slave sql_thread;
-
-connection slave;
-rollback; # release the sql thread
-
-connection slave1;
-reap;
-source include/wait_for_slave_sql_to_stop.inc;
-let $sql_status= query_get_value(SHOW SLAVE STATUS, Slave_SQL_Running, 1);
---echo *** sql thread is *not* running: $sql_status ***
-
-let $pos1_slave= query_get_value(SHOW SLAVE STATUS, Exec_Master_Log_Pos, 1);
-
---echo *** the prove: the stopped slave has rolled back the current transaction ***
-
---disable_query_log
-select count(*) as zero from t1i;
-eval select $pos0_master - $pos0_slave as zero;
-eval select $pos1_master > $pos0_slave as one;
---enable_query_log
-
-start slave sql_thread;
-
-# clean-up
-
-connection master;
-drop table t1i, t2m;
-
---source include/rpl_end.inc
=== 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 2011-04-05 08:30:38 +0000
@@ -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 2011-04-07 18:12:54 +0000
@@ -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;
=== 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 2011-04-06 11:40:57 +0000
@@ -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 2011-04-21 07:48:30 +0000
@@ -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/parts/inc/partition_check_drop.inc'
--- a/mysql-test/suite/parts/inc/partition_check_drop.inc 2011-01-28 12:28:15 +0000
+++ b/mysql-test/suite/parts/inc/partition_check_drop.inc 2011-04-26 09:35:17 +0000
@@ -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_layout_check1.inc'
--- a/mysql-test/suite/parts/inc/partition_layout_check1.inc 2011-01-28 12:28:15 +0000
+++ b/mysql-test/suite/parts/inc/partition_layout_check1.inc 2011-04-26 09:35:17 +0000
@@ -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 2011-01-28 12:28:15 +0000
+++ b/mysql-test/suite/parts/inc/partition_layout_check2.inc 2011-04-26 09:35:17 +0000
@@ -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)
{
=== renamed file 'mysql-test/suite/bugs/r/rpl_bug37426.result' => 'mysql-test/suite/rpl/r/rpl_bug37426.result'
--- a/mysql-test/suite/bugs/r/rpl_bug37426.result 2008-06-30 20:11:18 +0000
+++ b/mysql-test/suite/rpl/r/rpl_bug37426.result 2011-04-13 20:18:08 +0000
@@ -1,13 +1,6 @@
-stop slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-reset master;
-reset slave;
-drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
-start slave;
-CREATE TABLE char128_utf8 (
-i1 INT NOT NULL,
-c CHAR(128) CHARACTER SET utf8 NOT NULL,
-i2 INT NOT NULL);
+include/master-slave.inc
+[connection master]
+CREATE TABLE char128_utf8 (i1 INT NOT NULL, c CHAR(128) CHARACTER SET utf8 NOT NULL, i2 INT NOT NULL);
INSERT INTO char128_utf8 VALUES ( 1, "123", 1 );
SELECT * FROM char128_utf8;
i1 c i2
@@ -15,3 +8,5 @@ i1 c i2
SELECT * FROM char128_utf8;
i1 c i2
1 123 1
+DROP TABLE char128_utf8;
+include/rpl_end.inc
=== renamed file 'mysql-test/suite/bugs/t/rpl_bug37426.test' => 'mysql-test/suite/rpl/t/rpl_bug37426.test'
--- a/mysql-test/suite/bugs/t/rpl_bug37426.test 2010-12-19 17:07:28 +0000
+++ b/mysql-test/suite/rpl/t/rpl_bug37426.test 2011-04-13 20:18:08 +0000
@@ -7,15 +7,16 @@ source include/master-slave.inc;
source include/have_binlog_format_row.inc;
connection master;
-CREATE TABLE char128_utf8 (
- i1 INT NOT NULL,
- c CHAR(128) CHARACTER SET utf8 NOT NULL,
- i2 INT NOT NULL);
-
+CREATE TABLE char128_utf8 (i1 INT NOT NULL, c CHAR(128) CHARACTER SET utf8 NOT NULL, i2 INT NOT NULL);
INSERT INTO char128_utf8 VALUES ( 1, "123", 1 );
SELECT * FROM char128_utf8;
sync_slave_with_master;
SELECT * FROM char128_utf8;
+
+# Clean up
+connection master;
+DROP TABLE char128_utf8;
+sync_slave_with_master;
--source include/rpl_end.inc
=== modified file 'mysql-test/t/alter_table.test'
--- a/mysql-test/t/alter_table.test 2011-02-21 11:30:08 +0000
+++ b/mysql-test/t/alter_table.test 2011-04-13 06:16:40 +0000
@@ -1159,3 +1159,20 @@ CREATE TABLE db1.t1 (bar TINYTEXT, KEY (
ALTER TABLE db1.t1 ADD baz INT;
DROP DATABASE db1;
+
+
+--echo #
+--echo # Bug#11938039 RE-EXECUTION OF FRM-ONLY ALTER TABLE WITH RENAME
+--echo # CLAUSE FAILS OR ABORTS SERVER.
+--echo #
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+create table t1 (a int);
+prepare stmt1 from 'alter table t1 alter column a set default 1, rename to t2';
+execute stmt1;
+rename table t2 to t1;
+--echo # The below statement should succeed and not emit error or abort server.
+execute stmt1;
+deallocate prepare stmt1;
+drop table t2;
=== modified file 'mysql-test/t/func_analyse.test'
--- a/mysql-test/t/func_analyse.test 2011-03-14 18:06:44 +0000
+++ b/mysql-test/t/func_analyse.test 2011-04-14 09:10:11 +0000
@@ -1,6 +1,7 @@
#
# Test of procedure analyse
#
+-- source include/have_innodb.inc
--disable_warnings
drop table if exists t1,t2;
@@ -143,5 +144,16 @@ CREATE TABLE t1 (a VARCHAR(2) CHARSET UT
INSERT INTO t1 VALUES ('e'),('e'),('e-');
SELECT * FROM t1 PROCEDURE ANALYSE();
DROP TABLE t1;
+
+--echo #
+--echo # Bug#11756242 48137: PROCEDURE ANALYSE() LEAKS MEMORY WHEN RETURNING NULL
+--echo #
+
+CREATE TABLE t1(f1 INT) ENGINE=MYISAM;
+CREATE TABLE t2(f2 INT) ENGINE=INNODB;
+INSERT INTO t2 VALUES (1);
+SELECT DISTINCTROW f1 FROM t1 NATURAL RIGHT OUTER JOIN t2 PROCEDURE ANALYSE();
+SELECT * FROM t2 LIMIT 1 PROCEDURE ANALYSE();
+DROP TABLE t1, t2;
--echo End of 5.1 tests
=== modified file 'mysql-test/t/func_math.test'
--- a/mysql-test/t/func_math.test 2011-03-28 08:52:47 +0000
+++ b/mysql-test/t/func_math.test 2011-04-20 07:52:40 +0000
@@ -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 2011-03-30 07:25:49 +0000
+++ b/mysql-test/t/func_time.test 2011-04-27 07:46:23 +0000
@@ -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 2010-07-09 10:39:47 +0000
+++ b/mysql-test/t/having.test 2011-04-22 07:20:55 +0000
@@ -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 2010-07-14 12:05:20 +0000
+++ b/mysql-test/t/loaddata.test 2011-04-26 09:52:58 +0000
@@ -601,5 +601,33 @@ DROP TABLE t1;
let $MYSQLD_DATADIR= `select @@datadir`;
remove_file $MYSQLD_DATADIR/test/tmpp2.txt;
+--echo #
+--echo # Bug#11765139 58069: LOAD DATA INFILE: VALGRIND REPORTS INVALID MEMORY READS AND WRITES WITH U
+--echo #
+
+CREATE TABLE t1(f1 INT);
+EVAL SELECT 0xE1BB30 INTO OUTFILE 't1.dat';
+--disable_warnings
+LOAD DATA INFILE 't1.dat' IGNORE INTO TABLE t1 CHARACTER SET utf8;
+--enable_warnings
+
+DROP TABLE t1;
+let $MYSQLD_DATADIR= `select @@datadir`;
+remove_file $MYSQLD_DATADIR/test/t1.dat;
+
+--echo #
+--echo # Bug#11765141 - 58072: LOAD DATA INFILE: LEAKS IO CACHE MEMORY
+--echo # WHEN ERROR OCCURS
+--echo #
+
+--let $file=$MYSQLTEST_VARDIR/tmp/bug11735141.txt
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--eval SELECT '1\n' INTO DUMPFILE '$file'
+
+create table t1(a point);
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+--error ER_CANT_CREATE_GEOMETRY_OBJECT
+--eval LOAD DATA INFILE '$file' INTO TABLE t1
+drop table t1;
--echo End of 5.1 tests
=== modified file 'mysql-test/t/subselect.test'
--- a/mysql-test/t/subselect.test 2011-01-12 12:15:22 +0000
+++ b/mysql-test/t/subselect.test 2011-04-15 06:54:05 +0000
@@ -3997,6 +3997,28 @@ DROP TABLE t1,t1s,t2s;
--echo End of 5.1 tests
--echo #
+--echo # Bug #11765713 58705:
+--echo # OPTIMIZER LET ENGINE DEPEND ON UNINITIALIZED VALUES
+--echo # CREATED BY OPT_SUM_QUERY
+--echo #
+
+CREATE TABLE t1(a INT NOT NULL, KEY (a));
+INSERT INTO t1 VALUES (0), (1);
+
+--error ER_SUBQUERY_NO_1_ROW
+SELECT 1 as foo FROM t1 WHERE a < SOME
+ (SELECT a FROM t1 WHERE a <=>
+ (SELECT a FROM t1)
+ );
+
+SELECT 1 as foo FROM t1 WHERE a < SOME
+ (SELECT a FROM t1 WHERE a <=>
+ (SELECT a FROM t1 where a is null)
+ );
+
+DROP TABLE t1;
+
+--echo #
--echo # Bug #57704: Cleanup code dies with void TABLE::set_keyread(bool):
--echo # Assertion `file' failed.
--echo #
=== modified file 'mysql-test/t/type_timestamp.test'
--- a/mysql-test/t/type_timestamp.test 2011-01-12 12:58:47 +0000
+++ b/mysql-test/t/type_timestamp.test 2011-04-18 08:46:17 +0000
@@ -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 'mysql-test/t/warnings.test'
--- a/mysql-test/t/warnings.test 2009-11-13 10:17:53 +0000
+++ b/mysql-test/t/warnings.test 2011-04-15 12:02:22 +0000
@@ -228,3 +228,43 @@ DROP TABLE t1;
SHOW ERRORS;
--echo End of 5.0 tests
+
+#
+# Bug#55847: SHOW WARNINGS returns empty result set when SQLEXCEPTION is active
+#
+
+--echo
+--echo -- Bug#55847
+--echo
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP FUNCTION IF EXISTS f1;
+--enable_warnings
+
+CREATE TABLE t1(a INT UNIQUE);
+
+delimiter |;
+
+CREATE FUNCTION f1(x INT) RETURNS INT
+BEGIN
+ INSERT INTO t1 VALUES(x);
+ INSERT INTO t1 VALUES(x);
+ RETURN x;
+END|
+
+delimiter ;|
+
+--echo
+
+--error ER_DUP_ENTRY
+SHOW TABLES WHERE f1(11) = 11;
+
+--echo
+
+SHOW WARNINGS;
+
+--echo
+
+DROP TABLE t1;
+DROP FUNCTION f1;
=== modified file 'mysql-test/t/xa.test'
--- a/mysql-test/t/xa.test 2011-04-12 10:57:02 +0000
+++ b/mysql-test/t/xa.test 2011-04-14 08:13:28 +0000
@@ -3,6 +3,8 @@
#
-- source include/have_innodb.inc
+--source include/not_embedded.inc
+
# Save the initial number of concurrent sessions
--source include/count_sessions.inc
@@ -324,6 +326,59 @@ UPDATE t1 SET a=1 WHERE a=2;
XA COMMIT 'a';
SELECT * FROM t1;
DROP TABLE t1;
+
+
+--echo #
+--echo # Bug#12352846 - TRANS_XA_START(THD*):
+--echo # ASSERTION THD->TRANSACTION.XID_STATE.XID.IS_NULL()
+--echo # FAILED
+--echo #
+
+--disable_warnings
+DROP TABLE IF EXISTS t1, t2;
+--enable_warnings
+
+CREATE TABLE t1 (a INT);
+CREATE TABLE t2 (a INT);
+
+START TRANSACTION;
+INSERT INTO t1 VALUES (1);
+
+--echo # Connection con2
+--connect (con2,localhost,root)
+XA START 'xid1';
+--echo # Sending:
+--send INSERT INTO t2 SELECT a FROM t1
+
+--echo # Connection default
+--connection default
+let $wait_condition=
+ SELECT COUNT(*) = 1 FROM information_schema.processlist
+ WHERE state = "Sending data"
+ AND info = "INSERT INTO t2 SELECT a FROM t1";
+--echo # Waiting until INSERT ... is blocked
+--source include/wait_condition.inc
+DELETE FROM t1;
+COMMIT;
+
+--echo # Connection con2
+--connection con2
+--echo # Reaping: INSERT INTO t2 SELECT a FROM t1
+--error ER_LOCK_DEADLOCK
+--reap
+--error ER_XA_RBDEADLOCK
+XA COMMIT 'xid1';
+# This caused the assert to be triggered
+XA START 'xid1';
+
+XA END 'xid1';
+XA PREPARE 'xid1';
+XA ROLLBACK 'xid1';
+
+--echo # Connection default
+connection default;
+DROP TABLE t1, t2;
+disconnect con2;
# Wait till all disconnects are completed
=== modified file 'mysys/my_init.c'
--- a/mysys/my_init.c 2011-03-01 13:36:47 +0000
+++ b/mysys/my_init.c 2011-04-13 19:05:26 +0000
@@ -467,10 +467,6 @@ PSI_mutex_key key_my_file_info_mutex;
PSI_mutex_key key_LOCK_localtime_r;
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
-#ifndef HAVE_GETHOSTBYNAME_R
-PSI_mutex_key key_LOCK_gethostbyname_r;
-#endif /* HAVE_GETHOSTBYNAME_R */
-
PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock,
key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock, key_LOCK_alarm,
key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
@@ -487,9 +483,6 @@ static PSI_mutex_info all_mysys_mutexes[
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
{ &key_LOCK_localtime_r, "LOCK_localtime_r", PSI_FLAG_GLOBAL},
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
-#ifndef HAVE_GETHOSTBYNAME_R
- { &key_LOCK_gethostbyname_r, "LOCK_gethostbyname_r", PSI_FLAG_GLOBAL},
-#endif /* HAVE_GETHOSTBYNAME_R */
{ &key_BITMAP_mutex, "BITMAP::mutex", 0},
{ &key_IO_CACHE_append_buffer_lock, "IO_CACHE::append_buffer_lock", 0},
{ &key_IO_CACHE_SHARE_mutex, "IO_CACHE::SHARE_mutex", 0},
=== modified file 'mysys/my_thr_init.c'
--- a/mysys/my_thr_init.c 2011-03-01 13:36:47 +0000
+++ b/mysys/my_thr_init.c 2011-04-13 19:05:26 +0000
@@ -34,9 +34,6 @@ uint my_thread_end_wait_time= 5;
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
mysql_mutex_t LOCK_localtime_r;
#endif
-#ifndef HAVE_GETHOSTBYNAME_R
-mysql_mutex_t LOCK_gethostbyname_r;
-#endif
#ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP
pthread_mutexattr_t my_fast_mutexattr;
#endif
@@ -222,10 +219,6 @@ my_bool my_thread_global_init(void)
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
mysql_mutex_init(key_LOCK_localtime_r, &LOCK_localtime_r, MY_MUTEX_INIT_SLOW);
#endif
-#ifndef HAVE_GETHOSTBYNAME_R
- mysql_mutex_init(key_LOCK_gethostbyname_r,
- &LOCK_gethostbyname_r, MY_MUTEX_INIT_SLOW);
-#endif
#ifdef _MSC_VER
install_sigabrt_handler();
@@ -288,9 +281,6 @@ void my_thread_global_end(void)
}
#if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
mysql_mutex_destroy(&LOCK_localtime_r);
-#endif
-#ifndef HAVE_GETHOSTBYNAME_R
- mysql_mutex_destroy(&LOCK_gethostbyname_r);
#endif
my_thread_global_init_done= 0;
=== modified file 'mysys/mysys_priv.h'
--- a/mysys/mysys_priv.h 2011-01-12 20:36:39 +0000
+++ b/mysys/mysys_priv.h 2011-04-13 19:05:26 +0000
@@ -36,10 +36,6 @@ extern PSI_mutex_key key_my_file_info_mu
extern PSI_mutex_key key_LOCK_localtime_r;
#endif /* !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R) */
-#ifndef HAVE_GETHOSTBYNAME_R
-extern PSI_mutex_key key_LOCK_gethostbyname_r;
-#endif /* HAVE_GETHOSTBYNAME_R */
-
extern PSI_mutex_key key_BITMAP_mutex, key_IO_CACHE_append_buffer_lock,
key_IO_CACHE_SHARE_mutex, key_KEY_CACHE_cache_lock, key_LOCK_alarm,
key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
=== modified file 'sql-common/client.c'
--- a/sql-common/client.c 2011-02-11 14:00:09 +0000
+++ b/sql-common/client.c 2011-04-28 19:17:29 +0000
@@ -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/my_time.c'
--- a/sql-common/my_time.c 2011-02-02 18:13:28 +0000
+++ b/sql-common/my_time.c 2011-04-27 07:46:23 +0000
@@ -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 2011-03-18 10:03:54 +0000
+++ b/sql/ha_partition.cc 2011-04-26 11:26:41 +0000
@@ -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;
+ DBUG_ASSERT(ref_length >= (*file)->ref_length);
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;
=== modified file 'sql/ha_partition.h'
--- a/sql/ha_partition.h 2010-12-03 09:33:29 +0000
+++ b/sql/ha_partition.h 2011-04-20 17:53:08 +0000
@@ -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 2011-03-25 14:03:44 +0000
+++ b/sql/handler.cc 2011-04-20 17:53:08 +0000
@@ -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 2011-03-29 12:43:49 +0000
+++ b/sql/handler.h 2011-04-20 17:53:08 +0000
@@ -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 2011-04-08 13:15:23 +0000
+++ b/sql/item_func.cc 2011-04-20 07:52:40 +0000
@@ -2407,10 +2407,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 2011-03-28 13:33:35 +0000
+++ b/sql/item_timefunc.cc 2011-04-27 07:46:23 +0000
@@ -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.cc'
--- a/sql/mysqld.cc 2011-03-25 12:55:22 +0000
+++ b/sql/mysqld.cc 2011-04-13 19:05:26 +0000
@@ -245,11 +245,7 @@ inline void setup_fpu()
#define MYSQL_KILL_SIGNAL SIGTERM
-#ifdef HAVE_GLIBC2_STYLE_GETHOSTBYNAME_R
-#include <sys/types.h>
-#else
#include <my_pthread.h> // For thr_setconcurency()
-#endif
#ifdef SOLARIS
extern "C" int gethostname(char *name, int namelen);
=== modified file 'sql/mysqld.h'
--- a/sql/mysqld.h 2011-03-15 12:57:36 +0000
+++ b/sql/mysqld.h 2011-04-22 06:56:56 +0000
@@ -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 pthread_attr_t connection_attrib;
extern MYSQL_FILE *bootstrap_file;
extern my_bool old_mode;
@@ -310,7 +311,7 @@ extern uint mysql_real_data_home_len;
extern const char *mysql_real_data_home_ptr;
extern ulong thread_handling;
extern MYSQL_PLUGIN_IMPORT char *mysql_data_home;
-extern char server_version[SERVER_VERSION_LENGTH];
+extern "C" MYSQL_PLUGIN_IMPORT char server_version[SERVER_VERSION_LENGTH];
extern MYSQL_PLUGIN_IMPORT char mysql_real_data_home[];
extern char mysql_unpacked_real_data_home[];
extern MYSQL_PLUGIN_IMPORT struct system_variables global_system_variables;
=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc 2010-12-29 00:26:31 +0000
+++ b/sql/opt_range.cc 2011-04-20 17:53:08 +0000
@@ -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/opt_sum.cc'
--- a/sql/opt_sum.cc 2010-12-08 12:28:06 +0000
+++ b/sql/opt_sum.cc 2011-04-15 06:54:05 +0000
@@ -212,6 +212,7 @@ static int get_index_max_value(TABLE *ta
/**
Substitutes constants for some COUNT(), MIN() and MAX() functions.
+ @param thd thread handler
@param tables list of leaves of join table tree
@param all_fields All fields to be returned
@param conds WHERE clause
@@ -229,9 +230,12 @@ static int get_index_max_value(TABLE *ta
HA_ERR_KEY_NOT_FOUND on impossible conditions
@retval
HA_ERR_... if a deadlock or a lock wait timeout happens, for example
+ @retval
+ ER_... e.g. ER_SUBQUERY_NO_1_ROW
*/
-int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
+int opt_sum_query(THD *thd,
+ TABLE_LIST *tables, List<Item> &all_fields, COND *conds)
{
List_iterator_fast<Item> it(all_fields);
int const_result= 1;
@@ -243,6 +247,8 @@ int opt_sum_query(TABLE_LIST *tables, Li
Item *item;
int error;
+ DBUG_ENTER("opt_sum_query");
+
if (conds)
where_tables= conds->used_tables();
@@ -270,7 +276,7 @@ int opt_sum_query(TABLE_LIST *tables, Li
WHERE t2.field IS NULL;
*/
if (tl->table->map & where_tables)
- return 0;
+ DBUG_RETURN(0);
}
else
used_tables|= tl->table->map;
@@ -297,7 +303,7 @@ int opt_sum_query(TABLE_LIST *tables, Li
if(error)
{
tl->table->file->print_error(error, MYF(ME_FATALERROR));
- return error;
+ DBUG_RETURN(error);
}
count*= tl->table->file->stats.records;
}
@@ -390,10 +396,10 @@ int opt_sum_query(TABLE_LIST *tables, Li
if (error)
{
if (error == HA_ERR_KEY_NOT_FOUND || error == HA_ERR_END_OF_FILE)
- return HA_ERR_KEY_NOT_FOUND; // No rows matching WHERE
+ DBUG_RETURN(HA_ERR_KEY_NOT_FOUND); // No rows matching WHERE
/* HA_ERR_LOCK_DEADLOCK or some other error */
table->file->print_error(error, MYF(0));
- return(error);
+ DBUG_RETURN(error);
}
removed_tables|= table->map;
}
@@ -442,6 +448,10 @@ int opt_sum_query(TABLE_LIST *tables, Li
const_result= 0;
}
}
+
+ if (thd->is_error())
+ DBUG_RETURN(thd->stmt_da->sql_errno());
+
/*
If we have a where clause, we can only ignore searching in the
tables if MIN/MAX optimisation replaced all used tables
@@ -451,7 +461,7 @@ int opt_sum_query(TABLE_LIST *tables, Li
*/
if (removed_tables && used_tables != removed_tables)
const_result= 0; // We didn't remove all tables
- return const_result;
+ DBUG_RETURN(const_result);
}
@@ -737,6 +747,12 @@ static bool matching_cond(bool max_fl, T
if (is_null || (is_null_safe_eq && args[1]->is_null()))
{
+ /*
+ If we have a non-nullable index, we cannot use it,
+ since set_null will be ignored, and we will compare uninitialized data.
+ */
+ if (!part->field->real_maybe_null())
+ DBUG_RETURN(false);
part->field->set_null();
*key_ptr= (uchar) 1;
}
@@ -807,8 +823,9 @@ static bool matching_cond(bool max_fl, T
@param[out] prefix_len Length of prefix for the search range
@note
- This function may set table->key_read to 1, which must be reset after
- index is used! (This can only happen when function returns 1)
+ This function may set field->table->key_read to true,
+ which must be reset after index is used!
+ (This can only happen when function returns 1)
@retval
0 Index can not be used to optimize MIN(field)/MAX(field)
@@ -823,7 +840,9 @@ static bool find_key_for_maxmin(bool max
uint *range_fl, uint *prefix_len)
{
if (!(field->flags & PART_KEY_FLAG))
- return 0; // Not key field
+ return false; // Not key field
+
+ DBUG_ENTER("find_key_for_maxmin");
TABLE *table= field->table;
uint idx= 0;
@@ -848,7 +867,7 @@ static bool find_key_for_maxmin(bool max
part++, jdx++, key_part_to_use= (key_part_to_use << 1) | 1)
{
if (!(table->file->index_flags(idx, jdx, 0) & HA_READ_ORDER))
- return 0;
+ DBUG_RETURN(false);
/* Check whether the index component is partial */
Field *part_field= table->field[part->fieldnr-1];
@@ -897,12 +916,12 @@ static bool find_key_for_maxmin(bool max
*/
if (field->part_of_key.is_set(idx))
table->set_keyread(TRUE);
- return 1;
+ DBUG_RETURN(true);
}
}
}
}
- return 0;
+ DBUG_RETURN(false);
}
=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc 2011-02-16 16:27:35 +0000
+++ b/sql/sp_head.cc 2011-04-15 12:02:22 +0000
@@ -1,4 +1,4 @@
-/* Copyright 2002-2008 MySQL AB, 2008-2010 Sun Microsystems, Inc.
+/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -11,7 +11,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
#include "sql_priv.h"
@@ -1217,7 +1217,8 @@ sp_head::execute(THD *thd, bool merge_da
String old_packet;
Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer;
Object_creation_ctx *saved_creation_ctx;
- Warning_info *saved_warning_info, warning_info(thd->warning_info->warn_id());
+ Warning_info *saved_warning_info;
+ Warning_info warning_info(thd->warning_info->warn_id(), false);
/*
Just reporting a stack overrun error
=== modified file 'sql/sql_admin.cc'
--- a/sql/sql_admin.cc 2011-03-08 08:41:57 +0000
+++ b/sql/sql_admin.cc 2011-04-15 12:02:22 +0000
@@ -263,7 +263,7 @@ static bool mysql_admin_table(THD* thd,
const char *operator_name,
thr_lock_type lock_type,
bool open_for_modify,
- bool no_warnings_for_error,
+ bool repair_table_use_frm,
uint extra_open_options,
int (*prepare_func)(THD *, TABLE_LIST *,
HA_CHECK_OPT *),
@@ -331,18 +331,43 @@ static bool mysql_admin_table(THD* thd,
lex->query_tables= table;
lex->query_tables_last= &table->next_global;
lex->query_tables_own_last= 0;
- /*
- Under locked tables, we know that the table can be opened,
- so any errors opening the table are logical errors.
- In these cases it makes sense to report them.
- */
- if (!thd->locked_tables_mode)
- thd->no_warnings_for_error= no_warnings_for_error;
+
if (view_operator_func == NULL)
table->required_type=FRMTYPE_TABLE;
- open_error= open_and_lock_tables(thd, table, TRUE, 0);
- thd->no_warnings_for_error= 0;
+ if (!thd->locked_tables_mode && repair_table_use_frm)
+ {
+ /*
+ If we're not under LOCK TABLES and we're executing REPAIR TABLE
+ USE_FRM, we need to ignore errors from open_and_lock_tables().
+ REPAIR TABLE USE_FRM is a heavy weapon used when a table is
+ critically damaged, so open_and_lock_tables() will most likely
+ report errors. Those errors are not interesting for the user
+ because it's already known that the table is badly damaged.
+ */
+
+ Warning_info wi(thd->query_id, false);
+ Warning_info *wi_saved= thd->warning_info;
+
+ thd->warning_info= &wi;
+
+ open_error= open_and_lock_tables(thd, table, TRUE, 0);
+
+ thd->warning_info= wi_saved;
+ }
+ else
+ {
+ /*
+ It's assumed that even if it is REPAIR TABLE USE_FRM, the table
+ can be opened if we're under LOCK TABLES (otherwise LOCK TABLES
+ would fail). Thus, the only errors we could have from
+ open_and_lock_tables() are logical ones, like incorrect locking
+ mode. It does make sense for the user to see such errors.
+ */
+
+ open_error= open_and_lock_tables(thd, table, TRUE, 0);
+ }
+
table->next_global= save_next_global;
table->next_local= save_next_local;
thd->open_options&= ~extra_open_options;
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2011-01-27 13:25:27 +0000
+++ b/sql/sql_class.cc 2011-04-21 05:34:21 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -11,8 +11,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/*****************************************************************************
**
@@ -522,7 +521,7 @@ THD::THD()
#if defined(ENABLED_DEBUG_SYNC)
debug_sync_control(0),
#endif /* defined(ENABLED_DEBUG_SYNC) */
- main_warning_info(0)
+ main_warning_info(0, false)
{
ulong tmp;
@@ -581,7 +580,7 @@ THD::THD()
client_capabilities= 0; // minimalistic client
ull=0;
system_thread= NON_SYSTEM_THREAD;
- cleanup_done= abort_on_warning= no_warnings_for_error= 0;
+ cleanup_done= abort_on_warning= 0;
peer_port= 0; // For SHOW PROCESSLIST
transaction.m_pending_rows_event= 0;
transaction.on= 1;
@@ -854,10 +853,6 @@ MYSQL_ERROR* THD::raise_condition(uint s
query_cache_abort(&query_cache_tls);
- /* FIXME: broken special case */
- if (no_warnings_for_error && (level == MYSQL_ERROR::WARN_LEVEL_ERROR))
- DBUG_RETURN(NULL);
-
/* When simulating OOM, skip writing to error log to avoid mtr errors */
DBUG_EXECUTE_IF("simulate_out_of_memory", DBUG_RETURN(NULL););
@@ -3675,6 +3670,7 @@ bool xid_cache_insert(XID *xid, enum xa_
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_class.h'
--- a/sql/sql_class.h 2011-03-08 17:39:25 +0000
+++ b/sql/sql_class.h 2011-04-15 12:02:22 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -2089,7 +2089,6 @@ public:
bool enable_slow_log; /* enable slow log for current statement */
bool abort_on_warning;
bool got_warning; /* Set on call to push_warning() */
- bool no_warnings_for_error; /* no warnings on call to my_error() */
/* set during loop of derived table processing */
bool derived_tables_processing;
my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */
@@ -2807,6 +2806,7 @@ private:
/** The current internal error handler for this thread, or NULL. */
Internal_error_handler *m_internal_handler;
+
/**
The lex to hold the parsed tree of conventional (non-prepared) queries.
Whereas for prepared and stored procedure statements we use an own lex
=== modified file 'sql/sql_error.cc'
--- a/sql/sql_error.cc 2010-11-12 14:20:12 +0000
+++ b/sql/sql_error.cc 2011-04-15 12:02:22 +0000
@@ -1,5 +1,4 @@
-/* Copyright (C) 1995-2002 MySQL AB,
- Copyright (C) 2008-2009 Sun Microsystems, Inc
+/* Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -458,10 +457,11 @@ Diagnostics_area::disable_status()
m_status= DA_DISABLED;
}
-Warning_info::Warning_info(ulonglong warn_id_arg)
+Warning_info::Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings)
:m_statement_warn_count(0),
m_current_row_for_warning(1),
m_warn_id(warn_id_arg),
+ m_allow_unlimited_warnings(allow_unlimited_warnings),
m_read_only(FALSE)
{
/* Initialize sub structures */
@@ -543,7 +543,8 @@ MYSQL_ERROR *Warning_info::push_warning(
if (! m_read_only)
{
- if (m_warn_list.elements < thd->variables.max_error_count)
+ if (m_allow_unlimited_warnings ||
+ m_warn_list.elements < thd->variables.max_error_count)
{
cond= new (& m_warn_root) MYSQL_ERROR(& m_warn_root);
if (cond)
@@ -557,6 +558,20 @@ MYSQL_ERROR *Warning_info::push_warning(
m_statement_warn_count++;
return cond;
+}
+
+MYSQL_ERROR *Warning_info::push_warning(THD *thd, const MYSQL_ERROR *sql_condition)
+{
+ MYSQL_ERROR *new_condition= push_warning(thd,
+ sql_condition->get_sql_errno(),
+ sql_condition->get_sqlstate(),
+ sql_condition->get_level(),
+ sql_condition->get_message_text());
+
+ if (new_condition)
+ new_condition->copy_opt_attributes(sql_condition);
+
+ return new_condition;
}
/*
=== modified file 'sql/sql_error.h'
--- a/sql/sql_error.h 2010-11-12 12:56:21 +0000
+++ b/sql/sql_error.h 2011-04-15 12:02:22 +0000
@@ -1,5 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB,
- Copyright (C) 2008-2009 Sun Microsystems, Inc
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -12,7 +11,7 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifndef SQL_ERROR_H
#define SQL_ERROR_H
@@ -323,10 +322,13 @@ class Warning_info
{
/** A memory root to allocate warnings and errors */
MEM_ROOT m_warn_root;
+
/** List of warnings of all severities (levels). */
List <MYSQL_ERROR> m_warn_list;
+
/** A break down of the number of warnings per severity (level). */
uint m_warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
+
/**
The number of warnings of the current statement. Warning_info
life cycle differs from statement life cycle -- it may span
@@ -334,20 +336,25 @@ class Warning_info
m_statement_warn_count 0, whereas m_warn_list is not empty.
*/
uint m_statement_warn_count;
+
/*
Row counter, to print in errors and warnings. Not increased in
create_sort_index(); may differ from examined_row_count.
*/
ulong m_current_row_for_warning;
- /** Used to optionally clear warnings only once per statement. */
+
+ /** Used to optionally clear warnings only once per statement. */
ulonglong m_warn_id;
+ /** Indicates if push_warning() allows unlimited number of warnings. */
+ bool m_allow_unlimited_warnings;
+
private:
Warning_info(const Warning_info &rhs); /* Not implemented */
Warning_info& operator=(const Warning_info &rhs); /* Not implemented */
public:
- Warning_info(ulonglong warn_id_arg);
+ Warning_info(ulonglong warn_id_arg, bool allow_unlimited_warnings);
~Warning_info();
/**
@@ -384,19 +391,13 @@ public:
void append_warnings(THD *thd, List<MYSQL_ERROR> *src)
{
MYSQL_ERROR *err;
- MYSQL_ERROR *copy;
List_iterator_fast<MYSQL_ERROR> it(*src);
/*
Don't use ::push_warning() to avoid invocation of condition
handlers or escalation of warnings to errors.
*/
while ((err= it++))
- {
- copy= Warning_info::push_warning(thd, err->get_sql_errno(), err->get_sqlstate(),
- err->get_level(), err->get_message_text());
- if (copy)
- copy->copy_opt_attributes(err);
- }
+ Warning_info::push_warning(thd, err);
}
/**
@@ -461,6 +462,9 @@ public:
uint sql_errno, const char* sqlstate,
MYSQL_ERROR::enum_warning_level level,
const char* msg);
+
+ /** Add a new condition to the current list. */
+ MYSQL_ERROR *push_warning(THD *thd, const MYSQL_ERROR *sql_condition);
/**
Set the read only status for this statement area.
=== modified file 'sql/sql_load.cc'
--- a/sql/sql_load.cc 2011-02-10 10:50:53 +0000
+++ b/sql/sql_load.cc 2011-04-26 09:52:58 +0000
@@ -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,12 +1333,10 @@ 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 */
- uint length=max(field_term_length,line_term_length)+1;
+ uint length= max(cs->mbmaxlen, max(field_term_length, line_term_length)) + 1;
set_if_bigger(length,line_start.length());
stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
@@ -1379,7 +1378,7 @@ READ_INFO::READ_INFO(File file_par, uint
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_parse.cc'
--- a/sql/sql_parse.cc 2011-03-08 17:39:25 +0000
+++ b/sql/sql_parse.cc 2011-04-15 12:02:22 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -7223,10 +7223,20 @@ bool parse_sql(THD *thd,
bool mysql_parse_status= MYSQLparse(thd) != 0;
- /* Check that if MYSQLparse() failed, thd->is_error() is set. */
+ /*
+ Check that if MYSQLparse() failed either thd->is_error() is set, or an
+ internal error handler is set.
+
+ The assert will not catch a situation where parsing fails without an
+ error reported if an error handler exists. The problem is that the
+ error handler might have intercepted the error, so thd->is_error() is
+ not set. However, there is no way to be 100% sure here (the error
+ handler might be for other errors than parsing one).
+ */
DBUG_ASSERT(!mysql_parse_status ||
- (mysql_parse_status && thd->is_error()));
+ (mysql_parse_status && thd->is_error()) ||
+ (mysql_parse_status && thd->get_internal_handler()));
/* Reset parser state. */
=== modified file 'sql/sql_plist.h'
--- a/sql/sql_plist.h 2011-04-11 11:39:15 +0000
+++ b/sql/sql_plist.h 2011-04-13 11:23:10 +0000
@@ -95,6 +95,7 @@ public:
*last= a;
*B::prev_ptr(a)= last;
I::set_last(B::next_ptr(a));
+ C::inc();
}
inline void insert_after(T *pos, T *a)
{
@@ -112,6 +113,7 @@ public:
}
else
I::set_last(B::next_ptr(a));
+ C::inc();
}
}
inline void remove(T *a)
=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc 2011-03-15 12:57:36 +0000
+++ b/sql/sql_prepare.cc 2011-04-15 12:02:22 +0000
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -2842,7 +2842,8 @@ void mysql_stmt_get_longdata(THD *thd, c
param= stmt->param_array[param_number];
Diagnostics_area new_stmt_da, *save_stmt_da= thd->stmt_da;
- Warning_info new_warnning_info(thd->query_id), *save_warinig_info= thd->warning_info;
+ Warning_info new_warnning_info(thd->query_id, false);
+ Warning_info *save_warinig_info= thd->warning_info;
thd->stmt_da= &new_stmt_da;
thd->warning_info= &new_warnning_info;
@@ -3900,7 +3901,7 @@ Ed_result_set::Ed_result_set(List<Ed_row
*/
Ed_connection::Ed_connection(THD *thd)
- :m_warning_info(thd->query_id),
+ :m_warning_info(thd->query_id, false),
m_thd(thd),
m_rsets(0),
m_current_rset(0)
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2011-03-16 14:11:20 +0000
+++ b/sql/sql_select.cc 2011-04-22 07:39:42 +0000
@@ -991,7 +991,7 @@ JOIN::optimize()
If all items were resolved by opt_sum_query, there is no need to
open any tables.
*/
- if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds)))
+ if ((res=opt_sum_query(thd, select_lex->leaf_tables, all_fields, conds)))
{
if (res == HA_ERR_KEY_NOT_FOUND)
{
@@ -1972,7 +1972,11 @@ JOIN::exec()
if (!curr_join->sort_and_group &&
curr_join->const_tables != curr_join->tables)
curr_join->join_tab[curr_join->const_tables].sorted= 0;
- if ((tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, 0)))
+
+ Procedure *save_proc= curr_join->procedure;
+ tmp_error= do_select(curr_join, (List<Item> *) 0, curr_tmp_table, 0);
+ curr_join->procedure= save_proc;
+ if (tmp_error)
{
error= tmp_error;
DBUG_VOID_RETURN;
@@ -2259,7 +2263,7 @@ JOIN::exec()
Item* sort_table_cond= make_cond_for_table(curr_join->tmp_having,
used_tables,
- used_tables);
+ (table_map) 0);
if (sort_table_cond)
{
if (!curr_table->select)
@@ -12620,10 +12624,14 @@ end_send(JOIN *join, JOIN_TAB *join_tab
}
if (join->having && join->having->val_int() == 0)
DBUG_RETURN(NESTED_LOOP_OK); // Didn't match having
- error=0;
if (join->procedure)
- error=join->procedure->send_row(join->procedure_fields_list);
- else if (join->do_send_rows)
+ {
+ if (join->procedure->send_row(join->procedure_fields_list))
+ DBUG_RETURN(NESTED_LOOP_ERROR);
+ DBUG_RETURN(NESTED_LOOP_OK);
+ }
+ error=0;
+ if (join->do_send_rows)
error=join->result->send_data(*join->fields);
if (error)
DBUG_RETURN(NESTED_LOOP_ERROR); /* purecov: inspected */
@@ -13094,6 +13102,42 @@ static bool test_if_ref(Item_field *left
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 'sql/sql_select.h'
--- a/sql/sql_select.h 2011-01-07 14:29:17 +0000
+++ b/sql/sql_select.h 2011-04-15 06:54:05 +0000
@@ -619,7 +619,8 @@ bool is_indexed_agg_distinct(JOIN *join,
/* functions from opt_sum.cc */
bool simple_pred(Item_func *func_item, Item **args, bool *inv_order);
-int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds);
+int opt_sum_query(THD* thd,
+ TABLE_LIST *tables, List<Item> &all_fields, COND *conds);
/* from sql_delete.cc, used by opt_range.cc */
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b);
=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc 2011-04-06 15:11:43 +0000
+++ b/sql/sql_show.cc 2011-04-15 12:02:22 +0000
@@ -3416,6 +3416,45 @@ end:
/**
+ Trigger_error_handler is intended to intercept and silence SQL conditions
+ that might happen during trigger loading for SHOW statements.
+ The potential SQL conditions are:
+
+ - ER_PARSE_ERROR -- this error is thrown if a trigger definition file
+ is damaged or contains invalid CREATE TRIGGER statement. That should
+ not happen in normal life.
+
+ - ER_TRG_NO_DEFINER -- this warning is thrown when we're loading a
+ trigger created/imported in/from the version of MySQL, which does not
+ support trigger definers.
+
+ - ER_TRG_NO_CREATION_CTX -- this warning is thrown when we're loading a
+ trigger created/imported in/from the version of MySQL, which does not
+ support trigger creation contexts.
+*/
+
+class Trigger_error_handler : public Internal_error_handler
+{
+public:
+ bool handle_condition(THD *thd,
+ uint sql_errno,
+ const char* sqlstate,
+ MYSQL_ERROR::enum_warning_level level,
+ const char* msg,
+ MYSQL_ERROR ** cond_hdl)
+ {
+ if (sql_errno == ER_PARSE_ERROR ||
+ sql_errno == ER_TRG_NO_DEFINER ||
+ sql_errno == ER_TRG_NO_CREATION_CTX)
+ return true;
+
+ return false;
+ }
+};
+
+
+
+/**
@brief Fill I_S tables whose data are retrieved
from frm files and storage engine
@@ -3570,7 +3609,6 @@ int get_all_tables(THD *thd, TABLE_LIST
acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0))
#endif
{
- thd->no_warnings_for_error= 1;
List<LEX_STRING> table_names;
int res= make_table_name_list(thd, &table_names, lex,
&lookup_field_vals,
@@ -3619,9 +3657,24 @@ int get_all_tables(THD *thd, TABLE_LIST
if (!(table_open_method & ~OPEN_FRM_ONLY) &&
!with_i_schema)
{
- if (!fill_schema_table_from_frm(thd, tables, schema_table, db_name,
- table_name, schema_table_idx,
- can_deadlock))
+ /*
+ Here we need to filter out warnings, which can happen
+ during loading of triggers in fill_schema_table_from_frm(),
+ because we don't need those warnings to pollute output of
+ SELECT from I_S / SHOW-statements.
+ */
+
+ Trigger_error_handler err_handler;
+ thd->push_internal_handler(&err_handler);
+
+ int res= fill_schema_table_from_frm(thd, tables, schema_table,
+ db_name, table_name,
+ schema_table_idx,
+ can_deadlock);
+
+ thd->pop_internal_handler();
+
+ if (!res)
continue;
}
@@ -3631,7 +3684,6 @@ int get_all_tables(THD *thd, TABLE_LIST
Set the parent lex of 'sel' because it is needed by
sel.init_query() which is called inside make_table_list.
*/
- thd->no_warnings_for_error= 1;
sel.parent_lex= lex;
if (make_table_list(thd, &sel, db_name, table_name))
goto err;
@@ -6675,6 +6727,92 @@ int make_schema_select(THD *thd, SELECT_
}
+/**
+ Fill INFORMATION_SCHEMA-table, leave correct Diagnostics_area /
+ Warning_info state after itself.
+
+ This function is a wrapper around ST_SCHEMA_TABLE::fill_table(), which
+ may "partially silence" some errors. The thing is that during
+ fill_table() many errors might be emitted. These errors stem from the
+ nature of fill_table().
+
+ For example, SELECT ... FROM INFORMATION_SCHEMA.xxx WHERE TABLE_NAME = 'xxx'
+ results in a number of 'Table <db name>.xxx does not exist' errors,
+ because fill_table() tries to open the 'xxx' table in every possible
+ database.
+
+ Those errors are cleared (the error status is cleared from
+ Diagnostics_area) inside fill_table(), but they remain in Warning_info
+ (Warning_info is not cleared because it may contain useful warnings).
+
+ This function is responsible for making sure that Warning_info does not
+ contain warnings corresponding to the cleared errors.
+
+ @note: THD::no_warnings_for_error used to be set before calling
+ fill_table(), thus those errors didn't go to Warning_info. This is not
+ the case now (THD::no_warnings_for_error was eliminated as a hack), so we
+ need to take care of those warnings here.
+
+ @param thd Thread context.
+ @param table_list I_S table.
+ @param join_table JOIN/SELECT table.
+
+ @return Error status.
+ @retval TRUE Error.
+ @retval FALSE Success.
+*/
+static bool do_fill_table(THD *thd,
+ TABLE_LIST *table_list,
+ JOIN_TAB *join_table)
+{
+ // NOTE: fill_table() may generate many "useless" warnings, which will be
+ // ignored afterwards. On the other hand, there might be "useful"
+ // warnings, which should be presented to the user. Warning_info usually
+ // stores no more than THD::variables.max_error_count warnings.
+ // The problem is that "useless warnings" may occupy all the slots in the
+ // Warning_info, so "useful warnings" get rejected. In order to avoid
+ // that problem we create a Warning_info instance, which is capable of
+ // storing "unlimited" number of warnings.
+ Warning_info wi(thd->query_id, true);
+ Warning_info *wi_saved= thd->warning_info;
+
+ thd->warning_info= &wi;
+
+ bool res= table_list->schema_table->fill_table(
+ thd, table_list, join_table->select_cond);
+
+ thd->warning_info= wi_saved;
+
+ // Pass an error if any.
+
+ if (thd->stmt_da->is_error())
+ {
+ thd->warning_info->push_warning(thd,
+ thd->stmt_da->sql_errno(),
+ thd->stmt_da->get_sqlstate(),
+ MYSQL_ERROR::WARN_LEVEL_ERROR,
+ thd->stmt_da->message());
+ }
+
+ // Pass warnings (if any).
+ //
+ // Filter out warnings with WARN_LEVEL_ERROR level, because they
+ // correspond to the errors which were filtered out in fill_table().
+
+
+ List_iterator_fast<MYSQL_ERROR> it(wi.warn_list());
+ MYSQL_ERROR *err;
+
+ while ((err= it++))
+ {
+ if (err->get_level() != MYSQL_ERROR::WARN_LEVEL_ERROR)
+ thd->warning_info->push_warning(thd, err);
+ }
+
+ return res;
+}
+
+
/*
Fill temporary schema tables before SELECT
@@ -6697,7 +6835,6 @@ bool get_schema_tables_result(JOIN *join
bool result= 0;
DBUG_ENTER("get_schema_tables_result");
- thd->no_warnings_for_error= 1;
for (JOIN_TAB *tab= join->join_tab; tab < tmp_join_tab; tab++)
{
if (!tab->table || !tab->table->pos_in_table_list)
@@ -6748,8 +6885,7 @@ bool get_schema_tables_result(JOIN *join
else
table_list->table->file->stats.records= 0;
- if (table_list->schema_table->fill_table(thd, table_list,
- tab->select_cond))
+ if (do_fill_table(thd, table_list, tab))
{
result= 1;
join->error= 1;
@@ -6761,7 +6897,6 @@ bool get_schema_tables_result(JOIN *join
table_list->schema_table_state= executed_place;
}
}
- thd->no_warnings_for_error= 0;
DBUG_RETURN(result);
}
=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc 2011-03-25 14:03:44 +0000
+++ b/sql/sql_table.cc 2011-04-13 06:16:40 +0000
@@ -6660,15 +6660,15 @@ bool mysql_alter_table(THD *thd,char *ne
NO need to tamper with MERGE tables. The real open is done later.
*/
Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
- TABLE *t_table;
+ TABLE_LIST temp_table_list;
+ TABLE_LIST *t_table_list;
if (new_name != table_name || new_db != db)
{
- table_list->alias= new_name;
- table_list->table_name= new_name;
- table_list->table_name_length= strlen(new_name);
- table_list->db= new_db;
- table_list->db_length= strlen(new_db);
- table_list->mdl_request.ticket= target_mdl_request.ticket;
+ temp_table_list.init_one_table(new_db, strlen(new_db),
+ new_name, strlen(new_name),
+ new_name, TL_READ_NO_INSERT);
+ temp_table_list.mdl_request.ticket= target_mdl_request.ticket;
+ t_table_list= &temp_table_list;
}
else
{
@@ -6678,20 +6678,21 @@ bool mysql_alter_table(THD *thd,char *ne
to request the lock.
*/
table_list->mdl_request.ticket= mdl_ticket;
+ t_table_list= table_list;
}
- if (open_table(thd, table_list, thd->mem_root, &ot_ctx))
+ if (open_table(thd, t_table_list, thd->mem_root, &ot_ctx))
{
goto err_with_mdl;
}
- t_table= table_list->table;
/* Tell the handler that a new frm file is in place. */
- error= t_table->file->ha_create_handler_files(path, NULL, CHF_INDEX_FLAG,
- create_info);
+ error= t_table_list->table->file->ha_create_handler_files(path, NULL,
+ CHF_INDEX_FLAG,
+ create_info);
- DBUG_ASSERT(thd->open_tables == t_table);
+ DBUG_ASSERT(thd->open_tables == t_table_list->table);
close_thread_table(thd, &thd->open_tables);
- table_list->table= 0;
+ t_table_list->table= NULL;
if (error)
goto err_with_mdl;
=== modified file 'sql/sql_trigger.cc'
--- a/sql/sql_trigger.cc 2011-03-10 08:07:57 +0000
+++ b/sql/sql_trigger.cc 2011-04-15 12:02:22 +0000
@@ -1225,13 +1225,12 @@ bool Table_triggers_list::check_n_load(T
DBUG_RETURN(1); // EOM
}
-
- if (!thd->no_warnings_for_error)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRG_NO_CREATION_CTX,
- ER(ER_TRG_NO_CREATION_CTX),
- (const char*) db,
- (const char*) table_name);
+
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRG_NO_CREATION_CTX,
+ ER(ER_TRG_NO_CREATION_CTX),
+ (const char*) db,
+ (const char*) table_name);
if (!(trg_client_cs_name= alloc_lex_string(&table->mem_root)) ||
!(trg_connection_cl_name= alloc_lex_string(&table->mem_root)) ||
@@ -1362,12 +1361,12 @@ bool Table_triggers_list::check_n_load(T
MySQL, which does not support triggers definers. We should emit
warning here.
*/
- if (!thd->no_warnings_for_error)
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER),
- (const char*) db,
- (const char*) sp->m_name.str);
-
+
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_TRG_NO_DEFINER, ER(ER_TRG_NO_DEFINER),
+ (const char*) db,
+ (const char*) sp->m_name.str);
+
/*
Set definer to the '' to correct displaying in the information
schema.
=== modified file 'sql/transaction.cc'
--- a/sql/transaction.cc 2011-04-12 10:57:02 +0000
+++ b/sql/transaction.cc 2011-04-14 08:13:28 +0000
@@ -79,6 +79,33 @@ static bool xa_trans_rolled_back(XID_STA
/**
+ Rollback the active XA transaction.
+
+ @note Resets rm_error before calling ha_rollback(), so
+ the thd->transaction.xid structure gets reset
+ by ha_rollback() / THD::transaction::cleanup().
+
+ @return TRUE if the rollback failed, FALSE otherwise.
+*/
+
+static bool xa_trans_force_rollback(THD *thd)
+{
+ /*
+ We must reset rm_error before calling ha_rollback(),
+ so thd->transaction.xid structure gets reset
+ by ha_rollback()/THD::transaction::cleanup().
+ */
+ thd->transaction.xid_state.rm_error= 0;
+ if (ha_rollback_trans(thd, true))
+ {
+ my_error(ER_XAER_RMERR, MYF(0));
+ return true;
+ }
+ return false;
+}
+
+
+/**
Begin a new transaction.
@note Beginning a transaction implicitly commits any current
@@ -649,8 +676,7 @@ bool trans_xa_commit(THD *thd)
if (xa_trans_rolled_back(&thd->transaction.xid_state))
{
- if (ha_rollback_trans(thd, TRUE))
- my_error(ER_XAER_RMERR, MYF(0));
+ xa_trans_force_rollback(thd);
res= thd->is_error();
}
else if (xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
@@ -739,15 +765,7 @@ bool trans_xa_rollback(THD *thd)
DBUG_RETURN(TRUE);
}
- /*
- Resource Manager error is meaningless at this point, as we perform
- explicit rollback request by user. We must reset rm_error before
- calling ha_rollback(), so thd->transaction.xid structure gets reset
- by ha_rollback()/THD::transaction::cleanup().
- */
- thd->transaction.xid_state.rm_error= 0;
- if ((res= test(ha_rollback_trans(thd, TRUE))))
- my_error(ER_XAER_RMERR, MYF(0));
+ res= xa_trans_force_rollback(thd);
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.modified_non_trans_table= FALSE;
=== modified file 'storage/heap/ha_heap.cc'
--- a/storage/heap/ha_heap.cc 2010-10-06 14:34:28 +0000
+++ b/storage/heap/ha_heap.cc 2011-04-20 17:53:08 +0000
@@ -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 2010-10-06 14:34:28 +0000
+++ b/storage/heap/ha_heap.h 2011-04-20 17:53:08 +0000
@@ -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 2011-03-24 12:00:14 +0000
+++ b/storage/innobase/btr/btr0cur.c 2011-04-20 08:29:10 +0000
@@ -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 2010-12-01 08:43:33 +0000
+++ b/storage/innobase/buf/buf0flu.c 2011-04-05 07:18:43 +0000
@@ -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/fil/fil0fil.c'
--- a/storage/innobase/fil/fil0fil.c 2011-03-24 12:00:14 +0000
+++ b/storage/innobase/fil/fil0fil.c 2011-04-05 07:37:58 +0000
@@ -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 2011-04-07 06:59:07 +0000
+++ b/storage/innobase/handler/ha_innodb.cc 2011-04-21 05:34:21 +0000
@@ -6242,10 +6242,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 */
@@ -6366,6 +6362,8 @@ err_col:
col_len);
}
+ srv_lower_case_table_names = lower_case_table_names;
+
error = row_create_table_for_mysql(table, trx);
if (error == DB_DUPLICATE_KEY) {
@@ -6782,38 +6780,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 +6932,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,14 +7217,14 @@ 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);
/* Drop the table in InnoDB */
+ srv_lower_case_table_names = lower_case_table_names;
+
error = row_drop_table_for_mysql(norm_name, trx,
thd_sql_command(thd)
== SQLCOM_DROP_DB);
@@ -7342,8 +7340,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));
@@ -7358,6 +7354,8 @@ innobase_rename_table(
row_mysql_lock_data_dictionary(trx);
}
+ srv_lower_case_table_names = lower_case_table_names;
+
error = row_rename_table_for_mysql(
norm_from, norm_to, trx, lock_and_commit);
@@ -10263,7 +10261,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 +10287,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 +10922,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 +10946,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 2010-10-27 06:54:20 +0000
+++ b/storage/innobase/handler/ha_innodb.h 2011-04-11 14:03:32 +0000
@@ -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 2011-02-14 10:17:51 +0000
+++ b/storage/innobase/handler/handler0alter.cc 2011-04-11 14:03:32 +0000
@@ -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 2011-03-24 12:00:14 +0000
+++ b/storage/innobase/ibuf/ibuf0ibuf.c 2011-04-20 07:10:54 +0000
@@ -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/log0log.ic'
--- a/storage/innobase/include/log0log.ic 2010-07-21 14:22:29 +0000
+++ b/storage/innobase/include/log0log.ic 2011-04-05 07:18:43 +0000
@@ -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 2010-10-14 03:12:02 +0000
+++ b/storage/innobase/include/os0sync.h 2011-04-05 07:37:58 +0000
@@ -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 2010-06-22 15:58:28 +0000
+++ b/storage/innobase/include/os0thread.h 2011-04-06 06:22:36 +0000
@@ -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/sync0sync.h'
--- a/storage/innobase/include/sync0sync.h 2011-03-24 12:00:14 +0000
+++ b/storage/innobase/include/sync0sync.h 2011-04-05 07:18:43 +0000
@@ -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 2011-01-27 11:30:59 +0000
+++ b/storage/innobase/include/trx0trx.h 2011-04-11 14:03:32 +0000
@@ -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 2010-10-27 01:45:58 +0000
+++ b/storage/innobase/include/trx0undo.h 2011-04-11 14:03:32 +0000
@@ -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 2011-02-17 12:00:27 +0000
+++ b/storage/innobase/include/univ.i 2011-04-08 07:23:46 +0000
@@ -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;
@@ -254,6 +254,19 @@ easy way to get it to work. See http://b
# define UNIV_INTERN __attribute__((visibility ("hidden")))
#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
=== modified file 'storage/innobase/include/ut0dbg.h'
--- a/storage/innobase/include/ut0dbg.h 2010-07-15 13:47:50 +0000
+++ b/storage/innobase/include/ut0dbg.h 2011-04-06 06:22:36 +0000
@@ -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 2010-12-02 08:36:45 +0000
+++ b/storage/innobase/include/ut0ut.h 2011-04-06 06:22:36 +0000
@@ -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 2010-10-14 03:12:02 +0000
+++ b/storage/innobase/log/log0log.c 2011-04-11 14:03:32 +0000
@@ -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 2010-12-01 08:43:33 +0000
+++ b/storage/innobase/os/os0file.c 2011-04-05 07:37:58 +0000
@@ -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,7 +4709,21 @@ 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;
=== modified file 'storage/innobase/os/os0sync.c'
--- a/storage/innobase/os/os0sync.c 2010-11-01 13:12:59 +0000
+++ b/storage/innobase/os/os0sync.c 2011-04-05 07:37:58 +0000
@@ -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;
}
@@ -752,11 +725,6 @@ os_event_wait_time_low(
} while (!timed_out);
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 2010-07-21 14:22:29 +0000
+++ b/storage/innobase/os/os0thread.c 2011-04-05 10:58:37 +0000
@@ -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/row0merge.c'
--- a/storage/innobase/row/row0merge.c 2011-02-08 13:59:03 +0000
+++ b/storage/innobase/row/row0merge.c 2011-04-05 07:18:43 +0000
@@ -1929,7 +1929,6 @@ row_merge_lock_table(
sel_node_t* node;
ut_ad(trx);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_ad(mode == LOCK_X || mode == LOCK_S);
heap = mem_heap_create(512);
@@ -2390,7 +2389,6 @@ row_merge_rename_tables(
pars_info_t* info;
char old_name[MAX_FULL_NAME_LEN + 1];
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_ad(old_table != new_table);
ut_ad(mutex_own(&dict_sys->mutex));
=== modified file 'storage/innobase/row/row0mysql.c'
--- a/storage/innobase/row/row0mysql.c 2011-02-09 09:15:06 +0000
+++ b/storage/innobase/row/row0mysql.c 2011-04-05 07:18:43 +0000
@@ -976,7 +976,6 @@ row_lock_table_autoinc_for_mysql(
ibool was_lock_wait;
ut_ad(trx);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
/* If we already hold an AUTOINC lock on the table then do nothing.
Note: We peek at the value of the current owner without acquiring
@@ -1056,7 +1055,6 @@ row_lock_table_for_mysql(
ibool was_lock_wait;
ut_ad(trx);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
trx->op_info = "setting table lock";
@@ -1130,7 +1128,6 @@ row_insert_for_mysql(
ins_node_t* node = prebuilt->ins_node;
ut_ad(trx);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
if (prebuilt->table->ibd_file_missing) {
ut_print_timestamp(stderr);
@@ -1364,7 +1361,6 @@ row_update_for_mysql(
trx_t* trx = prebuilt->trx;
ut_ad(prebuilt && trx);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
UT_NOT_USED(mysql_rec);
if (prebuilt->table->ibd_file_missing) {
@@ -1532,7 +1528,6 @@ row_unlock_for_mysql(
trx_t* trx = prebuilt->trx;
ut_ad(prebuilt && trx);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
if (UNIV_UNLIKELY
(!srv_locks_unsafe_for_binlog
@@ -1834,7 +1829,6 @@ row_create_table_for_mysql(
ulint table_name_len;
ulint err;
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
@@ -2008,7 +2002,6 @@ row_create_index_for_mysql(
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
ut_ad(mutex_own(&(dict_sys->mutex)));
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
trx->op_info = "creating index";
@@ -2411,8 +2404,6 @@ row_discard_tablespace_for_mysql(
table->n_foreign_key_checks_running > 0, we do not allow the
discard. We also reserve the data dictionary latch. */
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
-
trx->op_info = "discarding tablespace";
trx_start_if_not_started(trx);
@@ -2571,8 +2562,6 @@ row_import_tablespace_for_mysql(
ib_uint64_t current_lsn;
ulint err = DB_SUCCESS;
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
-
trx_start_if_not_started(trx);
trx->op_info = "importing tablespace";
@@ -2756,7 +2745,6 @@ row_truncate_table_for_mysql(
redo log records on the truncated tablespace, we will assign
a new tablespace identifier to the truncated tablespace. */
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_ad(table);
if (srv_created_new_raw) {
@@ -3607,7 +3595,6 @@ row_drop_database_for_mysql(
int err = DB_SUCCESS;
ulint namelen = strlen(name);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_a(name != NULL);
ut_a(name[namelen - 1] == '/');
@@ -3777,7 +3764,6 @@ row_rename_table_for_mysql(
ibool old_is_tmp, new_is_tmp;
pars_info_t* info = NULL;
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
ut_a(old_name != NULL);
ut_a(new_name != NULL);
=== modified file 'storage/innobase/row/row0sel.c'
--- a/storage/innobase/row/row0sel.c 2010-12-17 11:11:34 +0000
+++ b/storage/innobase/row/row0sel.c 2011-04-05 07:18:43 +0000
@@ -1951,7 +1951,7 @@ stop_for_a_while:
mtr_commit(&mtr);
#ifdef UNIV_SYNC_DEBUG
- ut_ad(sync_thread_levels_empty_gen(TRUE));
+ ut_ad(sync_thread_levels_empty_except_dict());
#endif /* UNIV_SYNC_DEBUG */
err = DB_SUCCESS;
goto func_exit;
@@ -1971,7 +1971,7 @@ commit_mtr_for_a_while:
mtr_has_extra_clust_latch = FALSE;
#ifdef UNIV_SYNC_DEBUG
- ut_ad(sync_thread_levels_empty_gen(TRUE));
+ ut_ad(sync_thread_levels_empty_except_dict());
#endif /* UNIV_SYNC_DEBUG */
goto table_loop;
@@ -1988,7 +1988,7 @@ lock_wait_or_error:
mtr_commit(&mtr);
#ifdef UNIV_SYNC_DEBUG
- ut_ad(sync_thread_levels_empty_gen(TRUE));
+ ut_ad(sync_thread_levels_empty_except_dict());
#endif /* UNIV_SYNC_DEBUG */
func_exit:
@@ -3370,7 +3370,6 @@ row_search_for_mysql(
rec_offs_init(offsets_);
ut_ad(index && pcur && search_tuple);
- ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
if (UNIV_UNLIKELY(prebuilt->table->ibd_file_missing)) {
ut_print_timestamp(stderr);
@@ -3387,11 +3386,17 @@ row_search_for_mysql(
"InnoDB: how you can resolve the problem.\n",
prebuilt->table->name);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
return(DB_ERROR);
}
if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
return(DB_MISSING_HISTORY);
}
@@ -4680,6 +4685,10 @@ func_exit:
prebuilt->row_read_type = ROW_READ_TRY_SEMI_CONSISTENT;
}
}
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
return(err);
}
=== modified file 'storage/innobase/srv/srv0srv.c'
--- a/storage/innobase/srv/srv0srv.c 2011-03-30 11:52:26 +0000
+++ b/storage/innobase/srv/srv0srv.c 2011-04-12 06:22:43 +0000
@@ -687,8 +687,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 +885,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 +903,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 +957,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 +1143,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 +1270,10 @@ retry:
/* Go to wait for the event; when a thread leaves InnoDB it will
release this thread */
+ ut_ad(!trx->has_search_latch);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
trx->op_info = "waiting in InnoDB queue";
thd_wait_begin(trx->mysql_thd, THD_WAIT_ROW_TABLE_LOCK);
@@ -1307,6 +1309,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 +1384,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 +1399,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 +1519,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 +1538,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 +1624,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 +1651,34 @@ srv_suspend_mysql_thread(
ut_a(trx->dict_operation_lock_mode == 0);
+ if (trx->declared_to_be_inside_innodb) {
+
+ was_declared_inside_innodb = TRUE;
+
+ /* We must declare this OS thread to exit InnoDB, since a
+ possible other thread holding a lock which this thread waits
+ for must be allowed to enter, sooner or later */
+
+ srv_conc_force_exit_innodb(trx);
+ }
+
/* Suspend this thread and wait for the event. */
thd_wait_begin(trx->mysql_thd, THD_WAIT_ROW_TABLE_LOCK);
os_event_wait(event);
thd_wait_end(trx->mysql_thd);
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(!sync_thread_levels_nonempty_trx(trx->has_search_latch));
+#endif /* UNIV_SYNC_DEBUG */
+
+ if (was_declared_inside_innodb) {
+
+ /* Return back inside InnoDB */
+
+ srv_conc_force_enter_innodb(trx);
+ }
+
/* After resuming, reacquire the data dictionary latch if
necessary. */
@@ -1672,13 +1694,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 +3082,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 2011-03-24 12:00:14 +0000
+++ b/storage/innobase/srv/srv0start.c 2011-04-06 07:34:49 +0000
@@ -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 2011-02-25 11:21:02 +0000
+++ b/storage/innobase/sync/sync0sync.c 2011-04-05 07:18:43 +0000
@@ -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 2011-01-31 08:23:38 +0000
+++ b/storage/innobase/trx/trx0roll.c 2011-04-05 07:18:43 +0000
@@ -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 2011-02-22 05:04:08 +0000
+++ b/storage/innobase/trx/trx0sys.c 2011-04-11 14:03:32 +0000
@@ -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. */
@@ -1651,6 +1654,13 @@ trx_sys_close(void)
mutex_free(&trx_doublewrite->mutex);
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 2011-03-24 12:00:14 +0000
+++ b/storage/innobase/trx/trx0trx.c 2011-04-11 14:03:32 +0000
@@ -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 2011-03-08 17:39:25 +0000
+++ b/storage/innobase/trx/trx0undo.c 2011-04-11 14:03:32 +0000
@@ -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"
@@ -1974,5 +1975,32 @@ 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 2011-03-08 08:41:57 +0000
+++ b/storage/myisam/ha_myisam.cc 2011-04-20 17:53:08 +0000
@@ -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 2010-10-06 14:34:28 +0000
+++ b/storage/myisam/ha_myisam.h 2011-04-20 17:53:08 +0000
@@ -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 2010-10-20 19:02:59 +0000
+++ b/storage/myisammrg/ha_myisammrg.cc 2011-04-20 17:53:08 +0000
@@ -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 2010-10-06 14:34:28 +0000
+++ b/storage/myisammrg/ha_myisammrg.h 2011-04-20 17:53:08 +0000
@@ -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);
No bundle (reason: useless for push emails).| Thread |
|---|
| • bzr push into mysql-5.5 branch (rafal.somla:3438 to 3477) Bug#11879051 | Rafal Somla | 28 Apr |