#At file:///home/acorreia/workspace.sun/repository.mysql.new/bzrwork/wl-2775/mysql-next-mr-rpl-merge.crash-safe.2775/ based on revid:alfranio.correia@stripped
3003 Alfranio Correia 2010-07-14 [merge]
merge mysql-next-mr-rpl-merge --> mysql-next-mr-rpl-merge.crash-safe
added:
config/ac-macros/gtest.m4
sql/sql_alloc_error_handler.cc
sql/thr_malloc.h.moved
unittest/CMakeLists.txt
unittest/gunit/
unittest/gunit/CMakeLists.txt
unittest/gunit/FindGTest.cmake
unittest/gunit/Makefile.am
unittest/gunit/gunit_test_main.cc
unittest/gunit/mdl-t.cc
unittest/gunit/mdl_mytap-t.cc
unittest/gunit/sql_list-t.cc
unittest/gunit/tap_event_listener.cc
unittest/gunit/thread_utils-t.cc
unittest/gunit/thread_utils.cc
unittest/gunit/thread_utils.h
unittest/mytap/t/CMakeLists.txt
modified:
.bzrignore
CMakeLists.txt
Makefile.am
client/mysqlbinlog.cc
cmake/ssl.cmake
configure.in
libmysqld/CMakeLists.txt
libmysqld/Makefile.am
mysql-test/include/mtr_warnings.sql
mysql-test/mysql-test-run.pl
mysql-test/suite/rpl/r/rpl_server_uuid.result
mysql-test/suite/rpl/t/rpl_server_uuid.test
mysql-test/t/disabled.def
mysys/default.c
sql/CMakeLists.txt
sql/Makefile.am
sql/mysqld.cc
sql/rpl_record.cc
sql/rpl_slave.cc
sql/rpl_slave.h
sql/sql_show.h
sql/thr_malloc.cc
unittest/Makefile.am
unittest/unit.pl
=== modified file '.bzrignore'
--- a/.bzrignore 2010-06-17 16:58:30 +0000
+++ b/.bzrignore 2010-06-23 11:01:12 +0000
@@ -1,4 +1,5 @@
*-t
+*_test
*.Plo
*.Po
*.a
@@ -1162,6 +1163,7 @@ libmysqld/sp_pcontext.cc
libmysqld/sp_rcontext.cc
libmysqld/spatial.cc
libmysqld/sql_acl.cc
+libmysqld/sql_alloc_error_handler.cc
libmysqld/sql_analyse.cc
libmysqld/sql_base.cc
libmysqld/sql_builtin.cc
=== modified file 'CMakeLists.txt'
--- a/CMakeLists.txt 2010-06-21 13:20:18 +0000
+++ b/CMakeLists.txt 2010-06-23 11:01:12 +0000
@@ -246,9 +246,12 @@ IF(WITH_UNIT_TESTS)
ENABLE_TESTING()
ENDIF()
IF(WITH_UNIT_TESTS)
+ ADD_SUBDIRECTORY(unittest)
ADD_SUBDIRECTORY(unittest/examples)
ADD_SUBDIRECTORY(unittest/mytap)
+ ADD_SUBDIRECTORY(unittest/mytap/t)
ADD_SUBDIRECTORY(unittest/mysys)
+ ADD_SUBDIRECTORY(unittest/gunit)
ENDIF()
ADD_SUBDIRECTORY(extra)
=== modified file 'Makefile.am'
--- a/Makefile.am 2010-05-24 19:01:36 +0000
+++ b/Makefile.am 2010-06-01 11:42:26 +0000
@@ -25,8 +25,9 @@ EXTRA_DIST = INSTALL-SOURCE INSTALL-WIN
SUBDIRS = . include @docs_dirs@ @zlib_dir@ \
@readline_topdir@ sql-common scripts \
@pstack_dir@ libservices \
- @sql_union_dirs@ unittest \
- @sql_server@ @man_dirs@ tests \
+ @sql_union_dirs@ \
+ unittest/mytap \
+ @sql_server@ unittest @man_dirs@ tests \
netware @libmysqld_dirs@ \
mysql-test support-files sql-bench \
win \
=== modified file 'client/mysqlbinlog.cc'
--- a/client/mysqlbinlog.cc 2010-06-19 07:50:33 +0000
+++ b/client/mysqlbinlog.cc 2010-07-12 11:55:16 +0000
@@ -1184,7 +1184,7 @@ static struct my_option my_long_options[
(uchar**) &opt_binlog_rows_event_max_size,
(uchar**) &opt_binlog_rows_event_max_size, 0,
GET_ULONG, REQUIRED_ARG,
- /* def_value 4GB */ 4*1024L*1024L*1024L - 1, /* min_value */ 256,
+ /* def_value 4GB */ UINT_MAX, /* min_value */ 256,
/* max_value */ ULONG_MAX, /* sub_size */ 0,
/* block_size */ 256, /* app_type */ 0},
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
=== modified file 'cmake/ssl.cmake'
--- a/cmake/ssl.cmake 2010-06-08 23:44:25 +0000
+++ b/cmake/ssl.cmake 2010-06-23 08:23:41 +0000
@@ -25,7 +25,7 @@ MACRO (MYSQL_USE_BUNDLED_SSL)
SET(SSL_LIBRARIES yassl taocrypt)
SET(SSL_INCLUDE_DIRS ${INC_DIRS})
SET(SSL_INTERNAL_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/extra/yassl/taocrypt/mySTL)
- SET(SSL_DEFINES"-DHAVE_YASSL -DYASSL_PURE_C -DYASSL_PREFIX -DHAVE_OPENSSL -DYASSL_THREAD_SAFE")
+ SET(SSL_DEFINES "-DHAVE_YASSL -DYASSL_PURE_C -DYASSL_PREFIX -DHAVE_OPENSSL -DYASSL_THREAD_SAFE")
CHANGE_SSL_SETTINGS("bundled")
#Remove -fno-implicit-templates
#(yassl sources cannot be compiled with it)
=== added file 'config/ac-macros/gtest.m4'
--- a/config/ac-macros/gtest.m4 1970-01-01 00:00:00 +0000
+++ b/config/ac-macros/gtest.m4 2010-04-09 09:29:33 +0000
@@ -0,0 +1,151 @@
+dnl
+dnl Autoconf macros for detecting the Google C++ Testing Framework
+dnl
+
+dnl MY_PUSH_VAR(variable, value)
+AC_DEFUN([MY_PUSH_VAR],
+[
+ my_save_$1="$[$1]"
+ [$1]="$[$1] [$2]"
+])
+
+dnl MY_POP_VAR(variable)
+AC_DEFUN([MY_POP_VAR],
+[
+ [$1]="$[my_save_$1]"
+])
+
+
+dnl MY_SET_GTEST_COMMAND(commandline-var, path-to-gtest-config)
+dnl On some platforms we need to override /bin/sh in gtest-config,
+dnl because it uses some posix features.
+AC_DEFUN([MY_SET_GTEST_COMMAND],
+[
+ case "$target_os" in
+ *solaris*)
+ $1="/bin/bash $2" ;;
+ *)
+ $1="$2" ;;
+ esac
+])
+
+
+dnl MYSQL_LINK_GTEST(gtest-config-command,
+dnl [action-if-found],[action-if-not-found])
+dnl
+dnl Given a command to execute gtest-config, try to compile a gtest program.
+dnl Export variables which contain the compilation flags required by gtest.
+dnl The exported variables are:
+dnl GTEST_CPPFLAGS, GTEST_CXXFLAGS, GTEST_LDFLAGS, GTEST_LIBS.
+dnl
+AC_DEFUN([MYSQL_LINK_GTEST], [
+ dnl Retrieve compilation flags
+ GTEST_CPPFLAGS=`$1 --cppflags`
+ GTEST_CXXFLAGS=`$1 --cxxflags`
+ GTEST_LDFLAGS=`$1 --ldflags`
+ GTEST_LIBS=`$1 --libs`
+
+ AC_SUBST(GTEST_CPPFLAGS)
+ AC_SUBST(GTEST_CXXFLAGS)
+ AC_SUBST(GTEST_LDFLAGS)
+ AC_SUBST(GTEST_LIBS)
+
+ MY_PUSH_VAR([CPPFLAGS], [${GTEST_CPPFLAGS}])
+ MY_PUSH_VAR([CXXFLAGS], [${GTEST_CXXFLAGS} ${CXXFLAGS_OVERRIDE}])
+ MY_PUSH_VAR([LDFLAGS], [${GTEST_LDFLAGS}])
+ MY_PUSH_VAR([LIBS], [${GTEST_LIBS}])
+
+ AC_LANG_PUSH([C++])
+ AC_MSG_CHECKING([for ::testing::InitGoogleTest])
+
+dnl Note that we depend on an installed version of gtest for this to work,
+dnl see comments in the gtest-config script which comes with gtest.
+dnl 'gtest-config --libs' will return the name of the libtool file if we
+dnl are using a non-installed version. For that to work, we would have
+dnl to do this linkage test with libtools.
+ AC_LINK_IFELSE([
+ AC_LANG_PROGRAM([[
+ #include <gtest/gtest.h>
+ TEST(foo, bar) {}
+ ]], [[
+ int c;
+ char **v= NULL;
+ ::testing::InitGoogleTest(&c, v);
+ ]])],
+ [
+ AC_MSG_RESULT([yes])
+ $2
+ ],
+ [
+ AC_MSG_RESULT([no])
+ $3
+ ])
+
+ MY_POP_VAR([CPPFLAGS])
+ MY_POP_VAR([CXXFLAGS])
+ MY_POP_VAR([LDFLAGS])
+ MY_POP_VAR([LIBS])
+
+ AC_LANG_POP([C++])
+])
+
+dnl MYSQL_CHECK_GTEST_CONFIG([minimum version])
+dnl
+dnl Look for gtest-config and verify the minimum required version.
+dnl If we find it, then try to compile/link a simple unit test application.
+AC_DEFUN([MYSQL_CHECK_GTEST_CONFIG], [
+ AC_ARG_WITH([gtest],
+ [AS_HELP_STRING([--with-gtest[[=/path/to/gtest]]],
+ [Enable unit tests using the Google C++ Testing Framework.])
+ ],
+ [],
+ [with_gtest=check]
+ )
+
+ AC_MSG_CHECKING([whether to use the Google C++ Testing Framework])
+ if test "x${with_gtest}" = xno; then
+ AC_MSG_RESULT([no])
+ else
+ dnl If a path is supplied, it must exist.
+ if test "x$with_gtest" != xcheck; then
+ GTEST_CONFIG_PATH="${with_gtest}/bin"
+ elif test "x$GTEST_PREFIX" != x; then
+ GTEST_CONFIG_PATH="${GTEST_PREFIX}/bin"
+ else
+ GTEST_CONFIG_PATH=$PATH
+ fi
+
+ AC_MSG_RESULT([yes])
+
+ dnl Look for the absolute name of gtest-config.
+ AC_PATH_PROG([GTEST_CONFIG], [gtest-config], [], [$GTEST_CONFIG_PATH])
+
+ if test "x$GTEST_CONFIG" = x; then
+ dnl Fail if gtest was requested but gtest-config couldn't be found.
+ if test "x$with_gtest" != xcheck; then
+ AC_MSG_ERROR([Could not find gtest-config in $GTEST_CONFIG_PATH])
+ else
+ AC_MSG_WARN([Could not find gtest-config in $PATH])
+ fi
+ else
+ MY_SET_GTEST_COMMAND(GTEST_CONFIG_CMD, $GTEST_CONFIG)
+ AC_MSG_CHECKING([whether gtest-config is at least version $1])
+ if $GTEST_CONFIG_CMD --min-version=$1 >/dev/null 2>&1
+ then
+ AC_MSG_RESULT([yes])
+ MYSQL_LINK_GTEST($GTEST_CONFIG_CMD, [have_gtest=yes], [have_gtest=no])
+ else
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR(
+ [The installed version of the Google Testing Framework is too old.])
+ fi
+ fi
+ fi
+ AM_CONDITIONAL([HAVE_GTEST], [test "x$have_gtest" = "xyes"])
+])
+
+dnl MYSQL_CHECK_GTEST([minimum version])
+dnl
+AC_DEFUN([MYSQL_CHECK_GTEST], [
+ MYSQL_CHECK_GTEST_CONFIG([$1])
+])
=== modified file 'configure.in'
--- a/configure.in 2010-06-23 09:56:24 +0000
+++ b/configure.in 2010-07-12 11:55:16 +0000
@@ -85,6 +85,7 @@ sinclude(config/ac-macros/character_sets
sinclude(config/ac-macros/compiler_flag.m4)
sinclude(config/ac-macros/plugins.m4)
sinclude(config/ac-macros/dtrace.m4)
+sinclude(config/ac-macros/gtest.m4)
sinclude(config/ac-macros/ha_ndbcluster.m4)
sinclude(config/ac-macros/large_file.m4)
sinclude(config/ac-macros/misc.m4)
@@ -407,6 +408,7 @@ AC_SUBST(CC)
AC_SUBST(CFLAGS)
AC_SUBST(CXX)
AC_SUBST(CXXFLAGS)
+AC_SUBST(CXXFLAGS_OVERRIDE)
AC_SUBST(ASFLAGS)
AC_SUBST(LD)
AC_SUBST(INSTALL_SCRIPT)
@@ -422,6 +424,7 @@ then
# regarding offset() usage in C++ which are done in a safe manner in the
# server
CXXFLAGS="$CXXFLAGS -fno-implicit-templates -fno-exceptions -fno-rtti"
+ CXXFLAGS_OVERRIDE="-fimplicit-templates -fexceptions -frtti"
AC_DEFINE([HAVE_EXPLICIT_TEMPLATE_INSTANTIATION],
[1], [Defined by configure. Use explicit template instantiation.])
fi
@@ -2776,6 +2779,7 @@ MYSQL_CHECK_BIG_TABLES
MYSQL_CHECK_MAX_INDEXES
MYSQL_CHECK_VIO
MYSQL_CHECK_SSL
+MYSQL_CHECK_GTEST([1.5.0])
#--------------------------------------------------------------------
# Declare our plugin modules
@@ -3213,6 +3217,7 @@ if test -d "$srcdir/cmd-line-utils/readl
fi
AC_CONFIG_FILES(Makefile extra/Makefile mysys/Makefile dnl
+ unittest/gunit/Makefile dnl
unittest/Makefile unittest/mytap/Makefile unittest/mytap/t/Makefile dnl
unittest/mysys/Makefile unittest/examples/Makefile dnl
strings/Makefile regex/Makefile storage/Makefile dnl
=== modified file 'libmysqld/CMakeLists.txt'
--- a/libmysqld/CMakeLists.txt 2010-06-23 09:56:24 +0000
+++ b/libmysqld/CMakeLists.txt 2010-06-26 07:56:33 +0000
@@ -59,6 +59,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc l
../sql/rpl_injector.cc ../sql/set_var.cc ../sql/spatial.cc
../sql/sp_cache.cc ../sql/sp.cc ../sql/sp_head.cc
../sql/sp_pcontext.cc ../sql/sp_rcontext.cc ../sql/sql_acl.cc
+ ../sql/sql_alloc_error_handler.cc
../sql/sql_analyse.cc ../sql/sql_base.cc ../sql/sql_cache.cc
../sql/sql_class.cc ../sql/sql_crypt.cc ../sql/sql_cursor.cc
../sql/sql_db.cc ../sql/sql_delete.cc ../sql/sql_derived.cc
=== modified file 'libmysqld/Makefile.am'
--- a/libmysqld/Makefile.am 2010-06-23 09:56:24 +0000
+++ b/libmysqld/Makefile.am 2010-06-26 07:56:33 +0000
@@ -71,6 +71,7 @@ sqlsources = derror.cc field.cc field_co
sql_prepare.cc sql_derived.cc sql_rename.cc \
sql_select.cc sql_do.cc sql_show.cc set_var.cc sys_vars.cc \
sql_string.cc sql_table.cc sql_test.cc sql_udf.cc \
+ sql_alloc_error_handler.cc \
sql_update.cc sql_yacc.cc table.cc thr_malloc.cc sql_time.cc \
unireg.cc uniques.cc sql_union.cc hash_filo.cc \
spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \
=== modified file 'mysql-test/include/mtr_warnings.sql'
--- a/mysql-test/include/mtr_warnings.sql 2010-06-22 09:34:59 +0000
+++ b/mysql-test/include/mtr_warnings.sql 2010-07-12 11:55:16 +0000
@@ -162,13 +162,13 @@ INSERT INTO global_suppressions VALUES
("Slave: Unknown column 'c7' in 't15' Error_code: 1054"),
("Slave: Can't DROP 'c7'.* 1091"),
("Slave: Key column 'c6'.* 1072"),
- ("The slave I.O thread stops because a fatal error is encountered when it try to get the value of SERVER_UUID variable from master."),
- ("init-command:'.*' failed with error:.*"),
+ ("The slave I.O thread stops because a fatal error is encountered when it tries to get the value of SERVER_UUID variable from master.*"),
+ ("The initialization command '.*' failed with the following error.*"),
("The slave I.O thread stops because a fatal error is encountered when it try to get the value of SERVER_ID variable from master."),
(".SELECT UNIX_TIMESTAMP... failed on master, do not trust column Seconds_Behind_Master of SHOW SLAVE STATUS"),
/*It will print a warning if a new UUID of server is generated.*/
- ("It might be a maiden lunch of the server, for there is no UUID existing.*"),
+ ("No existing UUID has been found, so we assume that this is the first time that this server has been started.*"),
/* Test case for Bug#31590 in order_by.test produces the following error */
("Out of sort memory; increase server sort buffer size"),
=== modified file 'mysql-test/mysql-test-run.pl'
--- a/mysql-test/mysql-test-run.pl 2010-06-23 09:56:24 +0000
+++ b/mysql-test/mysql-test-run.pl 2010-07-12 11:55:16 +0000
@@ -4831,7 +4831,12 @@ sub start_servers($) {
# Save this test case information, so next can examine it
$mysqld->{'started_tinfo'}= $tinfo;
- mtr_milli_sleep(500);
+
+ # Wait until server's uuid is generated. This avoids that master and
+ # slave generate the same UUID sporadically.
+ sleep_until_file_created("$datadir/auto.cnf", $opt_start_timeout,
+ $mysqld->{'proc'});
+
}
}
=== modified file 'mysql-test/suite/rpl/r/rpl_server_uuid.result'
--- a/mysql-test/suite/rpl/r/rpl_server_uuid.result 2010-07-06 22:01:07 +0000
+++ b/mysql-test/suite/rpl/r/rpl_server_uuid.result 2010-07-14 12:32:57 +0000
@@ -4,6 +4,8 @@ reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
+call mtr.add_suppression("Slave I/O thread .* register on master");
+call mtr.add_suppression("Slave I/O: Master command COM_REGISTER_SLAVE failed: .*");
CALL mtr.add_suppression(".*master and slave have equal MySQL server UUIDs.*");
CALL mtr.add_suppression("Master's UUID has changed, its old UUID is.*");
CALL mtr.add_suppression("Slave I/O: Master command COM_REGISTER_SLAVE failed: failed registering on master");
=== modified file 'mysql-test/suite/rpl/t/rpl_server_uuid.test'
--- a/mysql-test/suite/rpl/t/rpl_server_uuid.test 2010-07-06 22:01:07 +0000
+++ b/mysql-test/suite/rpl/t/rpl_server_uuid.test 2010-07-14 12:32:57 +0000
@@ -13,6 +13,8 @@
--source include/have_debug.inc
--source include/have_debug_sync.inc
+call mtr.add_suppression("Slave I/O thread .* register on master");
+call mtr.add_suppression("Slave I/O: Master command COM_REGISTER_SLAVE failed: .*");
CALL mtr.add_suppression(".*master and slave have equal MySQL server UUIDs.*");
CALL mtr.add_suppression("Master's UUID has changed, its old UUID is.*");
CALL mtr.add_suppression("Slave I/O: Master command COM_REGISTER_SLAVE failed: failed registering on master");
=== modified file 'mysql-test/t/disabled.def'
--- a/mysql-test/t/disabled.def 2010-06-19 09:24:34 +0000
+++ b/mysql-test/t/disabled.def 2010-07-12 11:55:16 +0000
@@ -16,3 +16,4 @@ plugin_load : Bug#42144 200
partition_innodb_plugin : Bug#53307 2010-04-30 VasilDimov valgrind warnings
mysqlhotcopy_myisam : bug#54129 2010-06-04 Horst
mysqlhotcopy_archive : bug#54129 2010-06-04 Horst
+xa : Bug#54549 2010-06-17 Andrei
=== modified file 'mysys/default.c'
--- a/mysys/default.c 2010-06-22 09:34:59 +0000
+++ b/mysys/default.c 2010-07-12 11:55:16 +0000
@@ -458,12 +458,11 @@ int my_load_defaults(const char *conf_fi
MEM_ROOT alloc;
char *ptr,**res;
struct handle_option_ctx ctx;
- const char **dirs= NULL;
+ const char **dirs;
DBUG_ENTER("load_defaults");
init_alloc_root(&alloc,512,0);
- if (default_directories != NULL &&
- (dirs= init_default_directories(&alloc)) == NULL)
+ if ((dirs= init_default_directories(&alloc)) == NULL)
goto err;
/*
Check if the user doesn't want any default option processing
=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt 2010-07-06 22:01:07 +0000
+++ b/sql/CMakeLists.txt 2010-07-14 12:32:57 +0000
@@ -73,6 +73,7 @@ SET (SQL_SOURCE
sql_connect.cc scheduler.cc
sql_profile.cc event_parse_data.cc
sql_signal.cc mdl.cc
+ sql_alloc_error_handler.cc
transaction.cc sys_vars.cc rpl_handler.cc sql_truncate.cc datadict.cc
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE})
=== modified file 'sql/Makefile.am'
--- a/sql/Makefile.am 2010-07-06 22:01:07 +0000
+++ b/sql/Makefile.am 2010-07-14 12:32:57 +0000
@@ -93,6 +93,7 @@ noinst_HEADERS = item.h item_func.h item
item_strfunc.h item_timefunc.h \
item_xmlfunc.h sql_plugin_services.h \
item_create.h item_subselect.h item_row.h \
+ thr_malloc.h \
sql_priv.h item_geofunc.h sql_bitmap.h \
procedure.h sql_class.h sql_lex.h sql_list.h \
sql_map.h sql_string.h unireg.h \
@@ -140,6 +141,7 @@ noinst_HEADERS = item.h item_func.h item
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
+ sql_alloc_error_handler.cc \
thr_malloc.cc item_create.cc item_subselect.cc \
item_row.cc item_geofunc.cc item_xmlfunc.cc \
field.cc strfunc.cc key.cc sql_class.cc sql_list.cc \
=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc 2010-07-06 22:01:07 +0000
+++ b/sql/mysqld.cc 2010-07-14 12:32:57 +0000
@@ -4089,7 +4089,7 @@ static int init_server_auto_options()
{
bool flush= false;
char fname[FN_REFLEN];
- char *name= "auto";
+ char *name= (char *)"auto";
const char *groups[]= {"auto", NULL};
char *uuid= 0;
my_option auto_options[]= {
@@ -4123,7 +4123,7 @@ static int init_server_auto_options()
{
if (strlen(uuid) != UUID_LENGTH)
{
- sql_print_error("Invalid UUID in the auto.cnf file");
+ sql_print_error("The UUID stored in auto.cnf file is the wrong length.");
goto err;
}
strcpy(server_uuid, uuid);
@@ -4134,8 +4134,9 @@ static int init_server_auto_options()
/* server_uuid will be set in the function */
if (generate_server_uuid())
goto err;
- sql_print_warning("It might be a maiden lunch of the server, for there is"
- " no UUID existing. A new UUID is generated. it is %s",
+ sql_print_warning("No existing UUID has been found, so we assume that this"
+ " is the first time that this server has been started."
+ " Generating a new UUID: %s.",
server_uuid);
}
/*
@@ -4374,15 +4375,6 @@ a file name for --log-bin-index option",
if (opt_help)
unireg_abort(0);
- /*
- Each server should have one UUID. We will create it automatically, if it
- does not exist.
- */
- if (!opt_bootstrap && init_server_auto_options())
- {
- sql_print_error("Initializing server's UUID failed");
- unireg_abort(1);
- }
/* if the errmsg.sys is not loaded, terminate to maintain behaviour */
if (!DEFAULT_ERRMSGS[0][0])
@@ -4928,6 +4920,19 @@ int mysqld_main(int argc, char **argv)
if (init_server_components())
unireg_abort(1);
+ /*
+ Each server should have one UUID. We will create it automatically, if it
+ does not exist.
+ */
+ if (!opt_bootstrap && init_server_auto_options())
+ {
+ sql_print_error("Initialzation of the server's UUID failed because it could"
+ " not be read from the auto.cnf file. If this is a new"
+ " server, the initialization failed because it was not"
+ " possible to generate a new UUID.");
+ unireg_abort(1);
+ }
+
init_ssl();
network_init();
=== modified file 'sql/rpl_record.cc'
--- a/sql/rpl_record.cc 2010-06-22 06:03:00 +0000
+++ b/sql/rpl_record.cc 2010-07-12 11:55:16 +0000
@@ -238,7 +238,7 @@ unpack_row(Relay_log_info const *rli,
conv_field ? conv_field : *field_ptr;
DBUG_PRINT("debug", ("Conversion %srequired for field '%s' (#%ld)",
conv_field ? "" : "not ",
- (*field_ptr)->field_name, field_ptr - begin_ptr));
+ (*field_ptr)->field_name, (long)(field_ptr - begin_ptr)));
DBUG_ASSERT(f != NULL);
/*
=== modified file 'sql/rpl_slave.cc'
--- a/sql/rpl_slave.cc 2010-07-06 22:01:07 +0000
+++ b/sql/rpl_slave.cc 2010-07-14 12:32:57 +0000
@@ -1299,6 +1299,14 @@ bool is_network_error(uint errorno)
return FALSE;
}
+/**
+ Set user variables after connecting to the master.
+
+ @param mysql MYSQL to request uuid from master.
+ @param mi Master_info to set master_uuid
+
+ @return 0: Success, 1: Fatal error, 2: Network error.
+ */
int io_thread_init_commands(MYSQL *mysql, Master_info *mi)
{
char query[256];
@@ -1316,13 +1324,20 @@ err:
if (mysql_errno(mysql) && is_network_error(mysql_errno(mysql)))
{
mi->report(WARNING_LEVEL, mysql_errno(mysql),
- "init-command:'%s' failed with error: %s", query, mysql_error(mysql));
+ "The initialization command '%s' failed with the following"
+ " error: '%s'.", query, mysql_error(mysql));
ret= 2;
}
else
{
+ char errmsg[512];
+ const char *errmsg_fmt=
+ "The slave I/O thread stops because a fatal error is encountered "
+ "when it tries to send query to master(query: %s).";
+
+ my_sprintf(errmsg, (errmsg, errmsg_fmt, query));
mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, ER(ER_SLAVE_FATAL_ERROR),
- query);
+ errmsg);
ret= 1;
}
mysql_free_result(mysql_store_result(mysql));
@@ -1371,8 +1386,10 @@ static int get_master_uuid(MYSQL *mysql,
else
{
if (mi->master_uuid[0] != 0 && strcmp(mi->master_uuid, master_row[1]))
- sql_print_warning("Master's UUID has changed, its old UUID is %s, "
- "the new one is %s", mi->master_uuid, master_row[1]);
+ sql_print_warning("The master's UUID has changed, although this should"
+ " not happen unless you have changed it manually."
+ " The old UUID was %s.",
+ mi->master_uuid, master_row[1]);
strncpy(mi->master_uuid, master_row[1], UUID_LENGTH);
mi->master_uuid[UUID_LENGTH]= 0;
}
@@ -1390,7 +1407,7 @@ static int get_master_uuid(MYSQL *mysql,
{
/* Fatal error */
errmsg= "The slave I/O thread stops because a fatal error is encountered "
- "when it try to get the value of SERVER_UUID variable from master.";
+ "when it tries to get the value of SERVER_UUID variable from master.";
mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, ER(ER_SLAVE_FATAL_ERROR),
errmsg);
ret= 1;
=== modified file 'sql/rpl_slave.h'
--- a/sql/rpl_slave.h 2010-07-06 22:01:07 +0000
+++ b/sql/rpl_slave.h 2010-07-14 12:32:57 +0000
@@ -187,10 +187,6 @@ int start_slave_thread(
volatile ulong *slave_run_id,
Master_info *mi);
-/* If fd is -1, dump to NET */
-int mysql_table_dump(THD* thd, const char* db,
- const char* tbl_name, int fd = -1);
-
/* retrieve table from master and copy to slave*/
int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
Master_info* mi, MYSQL* mysql, bool overwrite);
=== added file 'sql/sql_alloc_error_handler.cc'
--- a/sql/sql_alloc_error_handler.cc 1970-01-01 00:00:00 +0000
+++ b/sql/sql_alloc_error_handler.cc 2010-06-21 07:13:21 +0000
@@ -0,0 +1,51 @@
+/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "log.h"
+#include "sql_class.h"
+#include "mysqld.h"
+
+extern "C" void sql_alloc_error_handler(void)
+{
+ THD *thd= current_thd;
+ if (thd && !thd->is_error())
+ {
+ /*
+ This thread is Out Of Memory.
+ An OOM condition is a fatal error.
+ It should not be caught by error handlers in stored procedures.
+ Also, recording that SQL condition in the condition area could
+ cause more memory allocations, which in turn could raise more
+ OOM conditions, causing recursion in the error handling code itself.
+ As a result, my_error() should not be invoked, and the
+ thread diagnostics area is set to an error status directly.
+ Note that Diagnostics_area::set_error_status() is safe,
+ since it does not call any memory allocation routines.
+ The visible result for a client application will be:
+ - a query fails with an ER_OUT_OF_RESOURCES error,
+ returned in the error packet.
+ - SHOW ERROR/SHOW WARNINGS may be empty.
+ */
+ thd->stmt_da->set_error_status(thd,
+ ER_OUT_OF_RESOURCES,
+ ER(ER_OUT_OF_RESOURCES),
+ NULL);
+ }
+
+ /* Skip writing to the error log to avoid mtr complaints */
+ DBUG_EXECUTE_IF("simulate_out_of_memory", return;);
+
+ sql_print_error("%s", ER(ER_OUT_OF_RESOURCES));
+}
=== modified file 'sql/sql_show.h'
--- a/sql/sql_show.h 2010-03-31 14:05:33 +0000
+++ b/sql/sql_show.h 2010-07-12 11:55:16 +0000
@@ -93,7 +93,6 @@ int copy_event_to_schema_table(THD *thd,
void append_identifier(THD *thd, String *packet, const char *name,
uint length);
void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
-int mysqld_dump_create_info(THD *thd, TABLE_LIST *table_list, int fd);
bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create);
=== modified file 'sql/thr_malloc.cc'
--- a/sql/thr_malloc.cc 2010-06-11 13:48:24 +0000
+++ b/sql/thr_malloc.cc 2010-06-21 07:13:21 +0000
@@ -21,44 +21,7 @@
#include "thr_malloc.h"
#include "sql_class.h"
-extern "C" {
- void sql_alloc_error_handler(void)
- {
- THD *thd= current_thd;
- if (thd)
- {
- if (! thd->is_error())
- {
- /*
- This thread is Out Of Memory.
- An OOM condition is a fatal error.
- It should not be caught by error handlers in stored procedures.
- Also, recording that SQL condition in the condition area could
- cause more memory allocations, which in turn could raise more
- OOM conditions, causing recursion in the error handling code itself.
- As a result, my_error() should not be invoked, and the
- thread diagnostics area is set to an error status directly.
- Note that Diagnostics_area::set_error_status() is safe,
- since it does not call any memory allocation routines.
- The visible result for a client application will be:
- - a query fails with an ER_OUT_OF_RESOURCES error,
- returned in the error packet.
- - SHOW ERROR/SHOW WARNINGS may be empty.
- */
- thd->stmt_da->set_error_status(thd,
- ER_OUT_OF_RESOURCES,
- ER(ER_OUT_OF_RESOURCES),
- NULL);
- }
- }
-
- /* Skip writing to the error log to avoid mtr complaints */
- DBUG_EXECUTE_IF("simulate_out_of_memory", return;);
-
- sql_print_error("%s", ER(ER_OUT_OF_RESOURCES));
-
- }
-}
+extern "C" void sql_alloc_error_handler(void);
void init_sql_alloc(MEM_ROOT *mem_root, uint block_size, uint pre_alloc)
{
=== added file 'sql/thr_malloc.h.moved'
--- a/sql/thr_malloc.h.moved 1970-01-01 00:00:00 +0000
+++ b/sql/thr_malloc.h.moved 2010-04-12 10:50:39 +0000
@@ -0,0 +1,34 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ 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 SQL_THR_MALLOC_INCLUDED
+#define SQL_THR_MALLOC_INCLUDED
+
+#include <my_global.h>
+#include <my_alloc.h>
+#include <m_ctype.h>
+
+void init_sql_alloc(MEM_ROOT *root, uint block_size, uint pre_alloc_size);
+void *sql_alloc(size_t);
+void *sql_calloc(size_t);
+char *sql_strdup(const char *str);
+char *sql_strmake(const char *str, size_t len);
+void *sql_memdup(const void * ptr, size_t size);
+char *sql_strmake_with_convert(const char *str, size_t arg_length,
+ CHARSET_INFO *from_cs,
+ size_t max_res_length,
+ CHARSET_INFO *to_cs, size_t *result_length);
+
+#endif // SQL_THR_MALLOC_INCLUDED
=== added file 'unittest/CMakeLists.txt'
--- a/unittest/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ b/unittest/CMakeLists.txt 2010-05-27 12:03:17 +0000
@@ -0,0 +1,20 @@
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ADD_CUSTOM_TARGET(
+ test-unit
+ COMMAND perl ${CMAKE_CURRENT_SOURCE_DIR}/unit.pl run .
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+)
=== modified file 'unittest/Makefile.am'
--- a/unittest/Makefile.am 2010-05-19 13:00:23 +0000
+++ b/unittest/Makefile.am 2010-05-27 12:03:17 +0000
@@ -13,15 +13,13 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-SUBDIRS = mytap . mysys examples
+SUBDIRS = mytap . mysys examples gunit
EXTRA_DIST = unit.pl
CLEANFILES = unit
-unittests = mytap mysys @mysql_se_unittest_dirs@ @mysql_pg_unittest_dirs@
-
test:
- perl unit.pl run $(unittests)
+ perl unit.pl run .
test-verbose:
- HARNESS_VERBOSE=1 perl unit.pl run $(unittests)
+ HARNESS_VERBOSE=1 perl unit.pl run .
=== added directory 'unittest/gunit'
=== added file 'unittest/gunit/CMakeLists.txt'
--- a/unittest/gunit/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/CMakeLists.txt 2010-06-18 09:09:40 +0000
@@ -0,0 +1,217 @@
+# Copyright (C) 2009 Sun Microsystems,Inc
+#
+# 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
+
+# In case we need to override the choice of compiler, see below.
+INCLUDE(CMakeForceCompiler)
+
+# Builtin GTest support is only available with CMake 2.8. For 2.6, we use
+# own copy of the FindGTest.cmake module, located in current source directory.
+IF("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS "2.8")
+ SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}")
+ELSE()
+ SET(HAVE_CMAKE_2_8 1)
+ENDIF()
+
+IF(CMAKE_COMPILER_IS_GNUCXX)
+ # Remove -fno-implicit-templates, gunit sources cannot be compiled with it.
+ STRING(REPLACE "-fno-implicit-templates" "" CMAKE_CXX_FLAGS
+ ${CMAKE_CXX_FLAGS})
+
+ # MySQL is often compiled/linked with gcc rather than g++
+ # (to avoid dependencies on libstdc++.so)
+ # This does not work for googletest binaries.
+ # If we are building with ccache, we need to change arg1.
+ IF(CMAKE_CXX_COMPILER_ARG1)
+ IF(${CMAKE_CXX_COMPILER_ARG1} MATCHES "gcc")
+ SET(CMAKE_CXX_COMPILER_ARG1 "g++")
+ ENDIF()
+ # If we are building with gcc, substitute gcc with g++
+ ELSEIF(${CMAKE_CXX_COMPILER} MATCHES ".*/gcc")
+ STRING(REGEX REPLACE "/gcc$" "/g++" PATH_TO_GCC ${CMAKE_CXX_COMPILER})
+ CMAKE_FORCE_CXX_COMPILER(${PATH_TO_GCC} "GNU g++")
+ ENDIF()
+ENDIF()
+
+IF(MSVC)
+ # Restore exception handling flags to avoid tons of warnings when using STL.
+ ADD_DEFINITIONS(/EHcs)
+ENDIF()
+
+# Where to download and build gtest if not found.
+IF(NOT DOWNLOAD_ROOT)
+ SET(DOWNLOAD_ROOT ${CMAKE_SOURCE_DIR}/source_downloads)
+ENDIF()
+IF(NOT EXISTS DOWNLOAD_ROOT)
+ MAKE_DIRECTORY(${DOWNLOAD_ROOT})
+ENDIF()
+SET(GTEST_PACKAGE_NAME "gtest-1.5.0")
+SET(GTEST_SOURCE_DIR ${DOWNLOAD_ROOT}/${GTEST_PACKAGE_NAME})
+
+
+# Hint for FindGTest: With MSVC, we compile with static CRT (compile flags
+# /MT or /MTd) and need compatible gtest.lib
+SET(GTEST_MSVC_SEARCH MT)
+
+# Hint for where to look: pushbuild uses GTEST_ROOT env.var.
+IF (DEFINED ENV{GTEST_PREFIX} AND NOT DEFINED ENV{GTEST_ROOT})
+ SET(ENV{GTEST_ROOT} $ENV{GTEST_PREFIX})
+ENDIF()
+
+# We may have downloaded gtest already, building in a different directory.
+IF(NOT DEFINED ENV{GTEST_ROOT} AND EXISTS ${GTEST_SOURCE_DIR})
+ MESSAGE(STATUS "GTEST_SOURCE_DIR:${GTEST_SOURCE_DIR}")
+ SET(GTEST_DOWNLOADED 1 CACHE INTERNAL "")
+ SET(GTEST_FOUND 1 CACHE INTERNAL "")
+ENDIF()
+
+
+IF(NOT GTEST_DOWNLOADED)
+ # Hint for find_library(): reverse list ".so;.a" to prefer static linking.
+ LIST(REVERSE CMAKE_FIND_LIBRARY_SUFFIXES)
+
+ # Now look for gtest.
+ FIND_PACKAGE(GTest)
+
+ # Revert suffix list back to what it was before.
+ LIST(REVERSE CMAKE_FIND_LIBRARY_SUFFIXES)
+ENDIF()
+
+
+OPTION(ENABLE_DOWNLOADS
+ "Download and build 3rd party source code components, e.g google test"
+ OFF)
+
+# While experimenting, use local URL rather than google.
+SET(GTEST_TARBALL "${GTEST_PACKAGE_NAME}.tar.gz")
+SET(GTEST_DOWNLOAD_URL
+ "http://googletest.googlecode.com/files/${GTEST_TARBALL}"
+# "https://clustra.norway.sun.com/~td136807/${GTEST_TARBALL}"
+ )
+
+IF(NOT GTEST_FOUND)
+ IF(NOT ENABLE_DOWNLOADS)
+ # Give one-time warning
+ IF(NOT ONETIME_GTEST_WARNING)
+ MESSAGE(STATUS
+ "Googletest was not found. gtest-based unit tests will be disabled. "
+ "You can run cmake . -DENABLE_DOWNLOADS=1 to automatically download and "
+ "build required components from source.")
+ SET(ONETIME_GTEST_WARNING 1 CACHE INTERNAL "")
+ ENDIF()
+ RETURN()
+ ENDIF()
+
+ # Download gtest source
+ IF(NOT EXISTS ${GTEST_SOURCE_DIR})
+ IF(NOT EXISTS ${DOWNLOAD_ROOT}/${GTEST_TARBALL})
+ # Download the tarball
+ IF(NOT HAVE_CMAKE_2_8)
+ # In versions earlier than 2.8, try wget for downloading
+ FIND_PROGRAM(WGET_EXECUTABLE wget)
+ MARK_AS_ADVANCED(WGET_EXECUTABLE)
+ IF(WGET_EXECUTABLE)
+ EXECUTE_PROCESS(COMMAND ${WGET_EXECUTABLE} -T 30 ${GTEST_DOWNLOAD_URL}
+ WORKING_DIRECTORY ${DOWNLOAD_ROOT} RESULT_VARIABLE ERR)
+ IF(ERR EQUAL 0)
+ SET(DOWNLOAD_SUCCEEDED 1)
+ ENDIF()
+ ENDIF()
+ ELSE()
+ # Use CMake builtin download capabilities
+ FILE(DOWNLOAD ${GTEST_DOWNLOAD_URL}
+ ${DOWNLOAD_ROOT}/${GTEST_TARBALL} 30 STATUS ERR)
+ IF(ERR EQUAL 0)
+ SET(DOWNLOAD_SUCCEEDED 1)
+ ENDIF()
+ ENDIF()
+
+ IF (DOWNLOAD_SUCCEEDED)
+ MESSAGE(STATUS
+ "Successfully downloaded ${GTEST_DOWNLOAD_URL} to ${DOWNLOAD_ROOT}")
+ ELSE()
+ MESSAGE(STATUS
+ "To enable google test, please download ${GTEST_DOWNLOAD_URL} "
+ "to the directory ${DOWNLOAD_ROOT}")
+ RETURN()
+ ENDIF()
+ ENDIF()
+
+ # Unpack tarball
+ EXECUTE_PROCESS(
+ COMMAND ${CMAKE_COMMAND} -E tar xfz "${DOWNLOAD_ROOT}/${GTEST_TARBALL}"
+ WORKING_DIRECTORY "${DOWNLOAD_ROOT}"
+ OUTPUT_QUIET
+ ERROR_QUIET
+ )
+ ENDIF()
+ SET(GTEST_DOWNLOADED 1 CACHE INTERNAL "")
+ SET(GTEST_FOUND 1 CACHE INTERNAL "")
+ENDIF()
+
+IF(NOT GTEST_FOUND)
+ RETURN()
+ENDIF()
+
+IF(GTEST_DOWNLOADED)
+ # Build gtest library
+ INCLUDE_DIRECTORIES(
+ ${GTEST_SOURCE_DIR}
+ ${GTEST_SOURCE_DIR}/include
+ )
+ ADD_LIBRARY(gtest STATIC ${GTEST_SOURCE_DIR}/src/gtest-all.cc)
+
+ # Set CMake variables to make FindPackage(GTest) happy next time.
+ SET(GTEST_FOUND 1 CACHE INTERNAL "")
+ SET(GTEST_LIBRARY gtest CACHE INTERNAL "")
+ SET(GTEST_LIBRARIES gtest CACHE INTERNAL "")
+ SET(GTEST_MAIN_LIBRARY no_gtest_main_library CACHE INTERNAL "")
+ SET(GTEST_INCLUDE_DIRS ${GTEST_SOURCE_DIR}/include CACHE INTERNAL "")
+ SET(GTEST_INCLUDE_DIR "${GTEST_SOURCE_DIR}/include" CACHE INTERNAL "")
+ENDIF()
+
+
+INCLUDE_DIRECTORIES(
+ ${GTEST_INCLUDE_DIRS}
+ ${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/sql
+ ${CMAKE_SOURCE_DIR}/unittest/mytap
+)
+
+# main-wrapper library (with tap-compatible option).
+ADD_LIBRARY(gunit STATIC
+ gunit_test_main.cc tap_event_listener.cc thread_utils.cc)
+TARGET_LINK_LIBRARIES(gunit mysys mytap dbug strings ${GTEST_LIBRARIES})
+MESSAGE(STATUS "GTEST_LIBRARIES:${GTEST_LIBRARIES}")
+
+# Add some defines.
+ADD_DEFINITIONS(-DMYSQL_SERVER)
+# We use -fno-rtti with gcc, so disable RTTI in gtest as well.
+ADD_DEFINITIONS(-DGTEST_HAS_RTTI=0)
+# /opt/studio12/SUNWspro/bin/CC complains about
+# iterator_traits is not a member of std
+IF (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
+ ADD_DEFINITIONS("-library=stlport4")
+ENDIF()
+
+# Add tests (link them with sql library)
+SET(TESTS sql_list mdl mdl_mytap thread_utils)
+FOREACH(test ${TESTS})
+ ADD_EXECUTABLE(${test}-t ${test}-t.cc)
+ TARGET_LINK_LIBRARIES(${test}-t gunit sql)
+ IF (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
+ SET_TARGET_PROPERTIES(${test}-t PROPERTIES LINK_FLAGS "-library=stlport4")
+ ENDIF()
+ ADD_TEST(${test} ${test}-t)
+ENDFOREACH()
=== added file 'unittest/gunit/FindGTest.cmake'
--- a/unittest/gunit/FindGTest.cmake 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/FindGTest.cmake 2010-03-18 12:52:56 +0000
@@ -0,0 +1,204 @@
+# Locate the Google C++ Testing Framework.
+#
+# Defines the following variables:
+#
+# GTEST_FOUND - Found the Google Testing framework
+# GTEST_INCLUDE_DIRS - Include directories
+#
+# Also defines the library variables below as normal
+# variables. These contain debug/optimized keywords when
+# a debugging library is found.
+#
+# GTEST_BOTH_LIBRARIES - Both libgtest & libgtest-main
+# GTEST_LIBRARIES - libgtest
+# GTEST_MAIN_LIBRARIES - libgtest-main
+#
+# Accepts the following variables as input:
+#
+# GTEST_ROOT - (as CMake or env. variable)
+# The root directory of the gtest install prefix
+#
+# GTEST_MSVC_SEARCH - If on MSVC, enables searching the build tree of
+# GTest if set to MD or MT (defaults: MD)
+#
+#-----------------------
+# Example Usage:
+#
+# enable_testing(true)
+# find_package(GTest REQUIRED)
+# include_directories(${GTEST_INCLUDE_DIRS})
+#
+# add_executable(foo foo.cc)
+# target_link_libraries(foo ${GTEST_BOTH_LIBRARIES})
+#
+# add_test(AllTestsInFoo foo)
+#
+#-----------------------
+#
+# If you would like each Google test to show up in CTest as
+# a test you may use the following macro. NOTE: It WILL slow
+# down your tests, so be warned.
+#
+# GTEST_ADD_TESTS(executable extra_args ARGN)
+# executable = The path to the test executable
+# extra_args = Pass a list of extra arguments to be passed to
+# executable enclosed in quotes (or "" for none)
+# ARGN = A list of source files to search for tests & test
+# fixtures.
+#
+# Example:
+# set(FooTestArgs --foo 1 --bar 2)
+# add_executable(FooTest FooUnitTest.cc)
+# GTEST_ADD_TESTS(FooTest "${FooTestArgs}" FooUnitTest.cc)
+
+#=============================================================================
+# Copyright 2009 Kitware, Inc.
+# Copyright 2009 Philip Lowman <philip@stripped>
+# Copyright 2009 Daniel Blezek <blezek@stripped>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# CMake - Cross Platform Makefile Generator
+# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+# All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# * Neither the names of Kitware, Inc., the Insight Software Consortium,
+# nor the names of their contributors may be used to endorse or promote
+# products derived from this software without specific prior written
+# permission.
+
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# ------------------------------------------------------------------------------
+#
+# The above copyright and license notice applies to distributions of
+# CMake in source and binary form. Some source files contain additional
+# notices of original copyright by their contributors; see each source
+# for details. Third-party software packages supplied with CMake under
+# compatible licenses provide their own copyright notices documented in
+# corresponding subdirectories.
+#----------------------------------------------------------------------------
+
+# CMake was initially developed by Kitware with the following sponsorship:
+#
+# * National Library of Medicine at the National Institutes of Health
+# as part of the Insight Segmentation and Registration Toolkit (ITK).
+#
+# * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel
+# Visualization Initiative.
+#
+# * National Alliance for Medical Image Computing (NAMIC) is funded by the
+# National Institutes of Health through the NIH Roadmap for Medical Research,
+# Grant U54 EB005149.
+#
+# * Kitware, Inc.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+#
+# Thanks to Daniel Blezek <blezek@stripped> for the GTEST_ADD_TESTS code
+
+function(GTEST_ADD_TESTS executable extra_args)
+ if(NOT ARGN)
+ message(FATAL_ERROR "Missing ARGN: Read the documentation for GTEST_ADD_TESTS")
+ endif()
+ foreach(source ${ARGN})
+ file(READ "${source}" contents)
+ string(REGEX MATCHALL "TEST_?F?\\(([A-Za-z_0-9 ,]+)\\)" found_tests ${contents})
+ foreach(hit ${found_tests})
+ string(REGEX REPLACE ".*\\(([A-Za-z_0-9]+)[, ]*([A-Za-z_0-9]+)\\).*" "\\1.\\2" test_name ${hit})
+ add_test(${test_name} ${executable} --gtest_filter=${test_name} ${extra_args})
+ endforeach()
+ endforeach()
+endfunction()
+
+function(_gtest_append_debugs _endvar _library)
+ if(${_library} AND ${_library}_DEBUG)
+ set(_output optimized ${${_library}} debug ${${_library}_DEBUG})
+ else()
+ set(_output ${${_library}})
+ endif()
+ set(${_endvar} ${_output} PARENT_SCOPE)
+endfunction()
+
+function(_gtest_find_library _name)
+ find_library(${_name}
+ NAMES ${ARGN}
+ HINTS
+ $ENV{GTEST_ROOT}
+ ${GTEST_ROOT}
+ PATH_SUFFIXES ${_gtest_libpath_suffixes}
+ )
+ mark_as_advanced(${_name})
+endfunction()
+
+#
+
+if(NOT DEFINED GTEST_MSVC_SEARCH)
+ set(GTEST_MSVC_SEARCH MD)
+endif()
+
+set(_gtest_libpath_suffixes lib)
+if(MSVC)
+ if(GTEST_MSVC_SEARCH STREQUAL "MD")
+ list(APPEND _gtest_libpath_suffixes
+ msvc/gtest-md/Debug
+ msvc/gtest-md/Release)
+ elseif(GTEST_MSVC_SEARCH STREQUAL "MT")
+ list(APPEND _gtest_libpath_suffixes
+ msvc/gtest/Debug
+ msvc/gtest/Release)
+ endif()
+endif()
+
+
+find_path(GTEST_INCLUDE_DIR gtest/gtest.h
+ HINTS
+ $ENV{GTEST_ROOT}/include
+ ${GTEST_ROOT}/include
+)
+mark_as_advanced(GTEST_INCLUDE_DIR)
+
+if(MSVC AND GTEST_MSVC_SEARCH STREQUAL "MD")
+ # The provided /MD project files for Google Test add -md suffixes to the
+ # library names.
+ _gtest_find_library(GTEST_LIBRARY gtest-md gtest)
+ _gtest_find_library(GTEST_LIBRARY_DEBUG gtest-mdd gtestd)
+ _gtest_find_library(GTEST_MAIN_LIBRARY gtest_main-md gtest_main)
+ _gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_main-mdd gtest_maind)
+else()
+ _gtest_find_library(GTEST_LIBRARY gtest)
+ _gtest_find_library(GTEST_LIBRARY_DEBUG gtestd)
+ _gtest_find_library(GTEST_MAIN_LIBRARY gtest_main)
+ _gtest_find_library(GTEST_MAIN_LIBRARY_DEBUG gtest_maind)
+endif()
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTest DEFAULT_MSG GTEST_LIBRARY GTEST_INCLUDE_DIR GTEST_MAIN_LIBRARY)
+
+if(GTEST_FOUND)
+ set(GTEST_INCLUDE_DIRS ${GTEST_INCLUDE_DIR})
+ _gtest_append_debugs(GTEST_LIBRARIES GTEST_LIBRARY)
+ _gtest_append_debugs(GTEST_MAIN_LIBRARIES GTEST_MAIN_LIBRARY)
+ set(GTEST_BOTH_LIBRARIES ${GTEST_LIBRARIES} ${GTEST_MAIN_LIBRARIES})
+endif()
+
=== added file 'unittest/gunit/Makefile.am'
--- a/unittest/gunit/Makefile.am 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/Makefile.am 2010-06-17 06:12:36 +0000
@@ -0,0 +1,67 @@
+# Copyright (C) 2009 Sun Microsystems, Inc.
+#
+# 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
+
+AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/sql $(GTEST_CPPFLAGS)
+AM_CXXFLAGS = $(GTEST_CXXFLAGS)
+AM_LDFLAGS = $(GTEST_LDFLAGS)
+AM_LIBS = $(GTEST_LIBS)
+DEFS = -DMYSQL_SERVER @DEFS@
+EXTRA_DIST = CMakeLists.txt FindGTest.cmake
+
+# Allow implicit templates when compiling gtest.h
+override CXXFLAGS += @CXXFLAGS_OVERRIDE@
+
+UNIT_TEST_LIBS= $(top_builddir)/mysys/.libs/libmysys.a \
+ $(top_builddir)/dbug/.libs/libdbug.a \
+ $(top_builddir)/strings/.libs/libmystrings.a
+
+UNIT_TEST_OBJS= $(top_builddir)/sql/sql_state.o \
+ $(top_builddir)/sql/sql_string.o \
+ $(top_builddir)/sql/thr_malloc.o
+
+LDADD = libgunit.la $(UNIT_TEST_OBJS) $(UNIT_TEST_LIBS) $(AM_LIBS)
+
+if HAVE_GTEST
+
+noinst_HEADERS = thread_utils.h
+
+noinst_LTLIBRARIES = libgunit.la
+
+libgunit_la_SOURCES = \
+ gunit_test_main.cc \
+ tap_event_listener.cc \
+ thread_utils.cc
+
+noinst_PROGRAMS = \
+ mdl-t$(EXEEXT) \
+ mdl_mytap-t$(EXEEXT) \
+ sql_list-t$(EXEEXT) \
+ thread_utils-t$(EXEEXT)
+
+sql_list_t_LDADD = $(top_builddir)/sql/sql_list.o $(LDADD)
+sql_list_t_SOURCES = sql_list-t.cc
+
+mdl_t_LDADD = $(top_builddir)/sql/mdl.o $(LDADD)
+mdl_t_SOURCES = mdl-t.cc
+
+mdl_mytap_t_CPPFLAGS = -I$(top_srcdir)/unittest/mytap $(AM_CPPFLAGS)
+mdl_mytap_t_LDADD = $(top_builddir)/sql/mdl.o \
+ $(top_builddir)/unittest/mytap/tap.o \
+ $(LDADD)
+mdl_mytap_t_SOURCES = mdl_mytap-t.cc
+
+thread_utils_t_SOURCES = thread_utils-t.cc
+
+endif
=== added file 'unittest/gunit/gunit_test_main.cc'
--- a/unittest/gunit/gunit_test_main.cc 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/gunit_test_main.cc 2010-03-18 10:09:22 +0000
@@ -0,0 +1,69 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ 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 <gtest/gtest.h>
+
+#include "mdl.h" // SHOULD BE my_sys.h
+#include "my_getopt.h"
+
+#include <stdlib.h>
+
+namespace {
+
+my_bool opt_use_tap= true;
+my_bool opt_help= false;
+
+struct my_option unittest_options[] =
+{
+ { "tap-output", 1, "TAP (default) or gunit output.",
+ (uchar**) &opt_use_tap, (uchar**) &opt_use_tap, NULL,
+ GET_BOOL, OPT_ARG,
+ opt_use_tap, 0, 1, 0,
+ 0, NULL
+ },
+ { "help", 2, "Help.",
+ (uchar**) &opt_help, (uchar**) &opt_help, NULL,
+ GET_BOOL, NO_ARG,
+ opt_help, 0, 1, 0,
+ 0, NULL
+ },
+ {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+
+extern "C" my_bool get_one_option(int, const struct my_option *, char *)
+{
+ return FALSE;
+}
+
+} // namespace
+
+
+extern void install_tap_listener();
+
+int main(int argc, char **argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ MY_INIT(argv[0]);
+
+ if (handle_options(&argc, &argv, unittest_options, get_one_option))
+ return EXIT_FAILURE;
+ if (opt_use_tap)
+ install_tap_listener();
+ if (opt_help)
+ printf("\n\nTest options: [--[disable-]tap-output]\n");
+
+ return RUN_ALL_TESTS();
+}
=== added file 'unittest/gunit/mdl-t.cc'
--- a/unittest/gunit/mdl-t.cc 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/mdl-t.cc 2010-06-23 11:01:12 +0000
@@ -0,0 +1,680 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ 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 */
+
+/**
+ This is a unit test for the 'meta data locking' classes.
+ It is written to illustrate how we can use googletest for unit testing
+ of MySQL code.
+ For documentation on googletest, see http://code.google.com/p/googletest/
+ and the contained wiki pages GoogleTestPrimer and GoogleTestAdvancedGuide.
+ The code below should hopefully be (mostly) self-explanatory.
+ */
+
+// Must include gtest first, since MySQL source has macros for min() etc ....
+#include <gtest/gtest.h>
+
+#include "mdl.h"
+#include <mysqld_error.h>
+
+#include "thr_malloc.h"
+#include "thread_utils.h"
+
+pthread_key(MEM_ROOT**,THR_MALLOC);
+pthread_key(THD*, THR_THD);
+mysql_mutex_t LOCK_open;
+uint opt_debug_sync_timeout= 0;
+
+/*
+ A mock error handler.
+*/
+static uint expected_error= 0;
+extern "C" void test_error_handler_hook(uint err, const char *str, myf MyFlags)
+{
+ EXPECT_EQ(expected_error, err) << str;
+}
+
+/*
+ A mock out-of-memory handler.
+ We do not expect this to be called during testing.
+*/
+extern "C" void sql_alloc_error_handler(void)
+{
+ ADD_FAILURE();
+}
+
+namespace {
+bool notify_thread(THD*);
+}
+
+/*
+ We need to mock away this global function, because the real version
+ pulls in a lot of dependencies.
+ (The @note for the real version of this function indicates that the
+ coupling between THD and MDL is too tight.)
+ @retval TRUE if the thread was woken up
+ @retval FALSE otherwise.
+*/
+bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
+ bool needs_thr_lock_abort)
+{
+ if (in_use != NULL)
+ return notify_thread(in_use);
+ return FALSE;
+}
+
+/*
+ Mock away this function as well, with an empty function.
+ @todo didrik: Consider verifying that the MDL module actually calls
+ this with correct arguments.
+*/
+void mysql_ha_flush(THD *)
+{
+ DBUG_PRINT("mysql_ha_flush", ("mock version"));
+}
+
+/*
+ We need to mock away this global function, the real version pulls in
+ too many dependencies.
+ */
+extern "C" const char *set_thd_proc_info(void *thd, const char *info,
+ const char *calling_function,
+ const char *calling_file,
+ const unsigned int calling_line)
+{
+ DBUG_PRINT("proc_info", ("%s:%d %s", calling_file, calling_line,
+ (info != NULL) ? info : "(null)"));
+ return info;
+}
+
+/*
+ Mock away this global function.
+ We don't need DEBUG_SYNC functionality in a unit test.
+ */
+void debug_sync(THD *thd, const char *sync_point_name, size_t name_len)
+{
+ DBUG_PRINT("debug_sync_point", ("hit: '%s'", sync_point_name));
+ FAIL() << "Not yet implemented.";
+}
+
+/*
+ Putting everything in an unnamed namespace prevents any (unintentional)
+ name clashes with the code under test.
+*/
+namespace {
+
+using thread::Notification;
+using thread::Thread;
+
+const char db_name[]= "some_database";
+const char table_name1[]= "some_table1";
+const char table_name2[]= "some_table2";
+const char table_name3[]= "some_table3";
+const char table_name4[]= "some_table4";
+const ulong zero_timeout= 0;
+const ulong long_timeout= (ulong) 3600L*24L*365L;
+
+
+class MDL_test : public ::testing::Test
+{
+protected:
+ MDL_test()
+ : m_thd(NULL),
+ m_null_ticket(NULL),
+ m_null_request(NULL)
+ {
+ }
+
+ static void SetUpTestCase()
+ {
+ error_handler_hook= test_error_handler_hook;
+ }
+
+ void SetUp()
+ {
+ expected_error= 0;
+ mdl_init();
+ m_mdl_context.init(m_thd);
+ EXPECT_FALSE(m_mdl_context.has_locks());
+ m_global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE);
+ }
+
+ void TearDown()
+ {
+ m_mdl_context.destroy();
+ mdl_destroy();
+ }
+
+ // A utility member for testing single lock requests.
+ void test_one_simple_shared_lock(enum_mdl_type lock_type);
+
+ THD *m_thd;
+ const MDL_ticket *m_null_ticket;
+ const MDL_request *m_null_request;
+ MDL_context m_mdl_context;
+ MDL_request m_request;
+ MDL_request m_global_request;
+ MDL_request_list m_request_list;
+private:
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(MDL_test);
+};
+
+
+/*
+ Will grab a lock on table_name of given type in the run() function.
+ The two notifications are for synchronizing with the main thread.
+ Does *not* take ownership of the notifications.
+*/
+class MDL_thread : public Thread
+{
+public:
+ MDL_thread(const char *table_name,
+ enum_mdl_type mdl_type,
+ Notification *lock_grabbed,
+ Notification *release_locks)
+ : m_table_name(table_name),
+ m_mdl_type(mdl_type),
+ m_lock_grabbed(lock_grabbed),
+ m_release_locks(release_locks),
+ m_ignore_notify(false)
+ {
+ m_thd= reinterpret_cast<THD*>(this); // See notify_thread below.
+ m_mdl_context.init(m_thd);
+ }
+
+ ~MDL_thread()
+ {
+ m_mdl_context.destroy();
+ }
+
+ virtual void run();
+ void ignore_notify() { m_ignore_notify= true; }
+
+ bool notify()
+ {
+ if (m_ignore_notify)
+ return false;
+ m_release_locks->notify();
+ return true;
+ }
+
+private:
+ const char *m_table_name;
+ enum_mdl_type m_mdl_type;
+ Notification *m_lock_grabbed;
+ Notification *m_release_locks;
+ bool m_ignore_notify;
+ THD *m_thd;
+ MDL_context m_mdl_context;
+};
+
+
+// Admittedly an ugly hack, to avoid pulling in the THD in this unit test.
+bool notify_thread(THD *thd)
+{
+ MDL_thread *thread = (MDL_thread*) thd;
+ return thread->notify();
+}
+
+
+void MDL_thread::run()
+{
+ MDL_request request;
+ MDL_request global_request;
+ MDL_request_list request_list;
+ global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE);
+ request.init(MDL_key::TABLE, db_name, m_table_name, m_mdl_type);
+
+ request_list.push_front(&request);
+ if (m_mdl_type >= MDL_SHARED_NO_WRITE)
+ request_list.push_front(&global_request);
+
+ EXPECT_FALSE(m_mdl_context.acquire_locks(&request_list, long_timeout));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, m_table_name, m_mdl_type));
+
+ // Tell the main thread that we have grabbed our locks.
+ m_lock_grabbed->notify();
+ // Hold on to locks until we are told to release them
+ m_release_locks->wait_for_notification();
+
+ m_mdl_context.rollback_to_savepoint(NULL);
+}
+
+// googletest recommends DeathTest suffix for classes use in death tests.
+typedef MDL_test MDL_DeathTest;
+
+
+/*
+ Verifies that we die with a DBUG_ASSERT if we destry a non-empty MDL_context.
+ */
+#if GTEST_HAS_DEATH_TEST && !defined(DBUG_OFF)
+TEST_F(MDL_DeathTest, die_when_m_tickets_nonempty)
+{
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&m_request));
+ EXPECT_DEATH(m_mdl_context.destroy(), ".*Assertion .*m_tickets.is_empty.*");
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+}
+#endif // GTEST_HAS_DEATH_TEST && !defined(DBUG_OFF)
+
+
+
+/*
+ The most basic test: just construct and destruct our test fixture.
+ */
+TEST_F(MDL_test, construct_and_destruct)
+{
+}
+
+
+/*
+ Verifies that we can create requests with the factory function
+ MDL_request::create().
+ */
+TEST_F(MDL_test, factory_function)
+{
+ MEM_ROOT mem_root;
+ init_sql_alloc(&mem_root, 1024, 0);
+ // This request should not be destroyed in the normal C++ fashion.
+ MDL_request *request=
+ MDL_request::create(MDL_key::TABLE,
+ db_name, table_name1, MDL_SHARED, &mem_root);
+ ASSERT_NE(m_null_request, request);
+ EXPECT_EQ(m_null_ticket, request->ticket);
+ free_root(&mem_root, MYF(0));
+}
+
+
+void MDL_test::test_one_simple_shared_lock(enum_mdl_type lock_type)
+{
+ m_request.init(MDL_key::TABLE, db_name, table_name1, lock_type);
+
+ EXPECT_EQ(lock_type, m_request.type);
+ EXPECT_EQ(m_null_ticket, m_request.ticket);
+
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&m_request));
+ EXPECT_NE(m_null_ticket, m_request.ticket);
+ EXPECT_TRUE(m_mdl_context.has_locks());
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, lock_type));
+
+ MDL_request request_2;
+ request_2.init(&m_request.key, lock_type);
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&request_2));
+ EXPECT_EQ(m_request.ticket, request_2.ticket);
+
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+ EXPECT_FALSE(m_mdl_context.has_locks());
+}
+
+
+/*
+ Acquires one lock of type MDL_SHARED.
+ */
+TEST_F(MDL_test, one_shared)
+{
+ test_one_simple_shared_lock(MDL_SHARED);
+}
+
+
+/*
+ Acquires one lock of type MDL_SHARED_HIGH_PRIO.
+ */
+TEST_F(MDL_test, one_shared_high_prio)
+{
+ test_one_simple_shared_lock(MDL_SHARED_HIGH_PRIO);
+}
+
+
+/*
+ Acquires one lock of type MDL_SHARED_READ.
+ */
+TEST_F(MDL_test, one_shared_read)
+{
+ test_one_simple_shared_lock(MDL_SHARED_READ);
+}
+
+
+/*
+ Acquires one lock of type MDL_SHARED_WRITE.
+ */
+TEST_F(MDL_test, one_shared_write)
+{
+ test_one_simple_shared_lock(MDL_SHARED_WRITE);
+}
+
+
+/*
+ Acquires one lock of type MDL_EXCLUSIVE.
+ */
+TEST_F(MDL_test, one_exclusive)
+{
+ const enum_mdl_type lock_type= MDL_EXCLUSIVE;
+ m_request.init(MDL_key::TABLE, db_name, table_name1, lock_type);
+ EXPECT_EQ(m_null_ticket, m_request.ticket);
+
+ m_request_list.push_front(&m_request);
+ m_request_list.push_front(&m_global_request);
+
+ EXPECT_FALSE(m_mdl_context.acquire_locks(&m_request_list, long_timeout));
+
+ EXPECT_NE(m_null_ticket, m_request.ticket);
+ EXPECT_NE(m_null_ticket, m_global_request.ticket);
+ EXPECT_TRUE(m_mdl_context.has_locks());
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, lock_type));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE));
+ EXPECT_TRUE(m_request.ticket->is_upgradable_or_exclusive());
+
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+ m_mdl_context.release_lock(m_global_request.ticket);
+ EXPECT_FALSE(m_mdl_context.has_locks());
+}
+
+
+/*
+ Acquires two locks, on different tables, of type MDL_SHARED.
+ Verifies that they are independent.
+ */
+TEST_F(MDL_test, two_shared)
+{
+ MDL_request request_2;
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+ request_2.init(MDL_key::TABLE, db_name, table_name2, MDL_SHARED);
+
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&m_request));
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&request_2));
+ EXPECT_TRUE(m_mdl_context.has_locks());
+ ASSERT_NE(m_null_ticket, m_request.ticket);
+ ASSERT_NE(m_null_ticket, request_2.ticket);
+
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name2, MDL_SHARED));
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name3, MDL_SHARED));
+
+ m_mdl_context.release_lock(m_request.ticket);
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+ EXPECT_TRUE(m_mdl_context.has_locks());
+
+ m_mdl_context.release_lock(request_2.ticket);
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name2, MDL_SHARED));
+ EXPECT_FALSE(m_mdl_context.has_locks());
+}
+
+
+/*
+ Verifies that two different contexts can acquire a shared lock
+ on the same table.
+ */
+TEST_F(MDL_test, shared_locks_between_contexts)
+{
+ THD *thd2= (THD*) this;
+ MDL_context mdl_context2;
+ mdl_context2.init(thd2);
+ MDL_request request_2;
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+ request_2.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&m_request));
+ EXPECT_FALSE(mdl_context2.try_acquire_lock(&request_2));
+
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+ EXPECT_TRUE(mdl_context2.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+ mdl_context2.release_all_locks_for_name(request_2.ticket);
+}
+
+
+/*
+ Verifies that we can upgrade a shared lock to exclusive.
+ */
+TEST_F(MDL_test, upgrade_shared_upgradable)
+{
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED_NO_WRITE);
+
+ m_request_list.push_front(&m_request);
+ m_request_list.push_front(&m_global_request);
+
+ EXPECT_FALSE(m_mdl_context.acquire_locks(&m_request_list, long_timeout));
+ EXPECT_FALSE(m_mdl_context.
+ upgrade_shared_lock_to_exclusive(m_request.ticket, long_timeout));
+ EXPECT_EQ(MDL_EXCLUSIVE, m_request.ticket->get_type());
+
+ // Another upgrade should be a no-op.
+ EXPECT_FALSE(m_mdl_context.
+ upgrade_shared_lock_to_exclusive(m_request.ticket, long_timeout));
+ EXPECT_EQ(MDL_EXCLUSIVE, m_request.ticket->get_type());
+
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+ m_mdl_context.release_lock(m_global_request.ticket);
+}
+
+
+/*
+ Verifies that only upgradable locks can be upgraded to exclusive.
+ */
+TEST_F(MDL_DeathTest, die_upgrade_shared)
+{
+ MDL_request request_2;
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+ request_2.init(MDL_key::TABLE, db_name, table_name2, MDL_SHARED_NO_READ_WRITE);
+
+ m_request_list.push_front(&m_request);
+ m_request_list.push_front(&request_2);
+ m_request_list.push_front(&m_global_request);
+
+ EXPECT_FALSE(m_mdl_context.acquire_locks(&m_request_list, long_timeout));
+
+#if GTEST_HAS_DEATH_TEST && !defined(DBUG_OFF)
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ EXPECT_DEATH_IF_SUPPORTED(m_mdl_context.
+ upgrade_shared_lock_to_exclusive(m_request.ticket,
+ long_timeout),
+ ".*MDL_SHARED_NO_.*");
+#endif
+ EXPECT_FALSE(m_mdl_context.
+ upgrade_shared_lock_to_exclusive(request_2.ticket, long_timeout));
+ m_mdl_context.rollback_to_savepoint(NULL);
+}
+
+
+/*
+ Verfies that locks are released when we roll back to a savepoint.
+ */
+TEST_F(MDL_test, savepoint)
+{
+ MDL_request request_2;
+ MDL_request request_3;
+ MDL_request request_4;
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+ request_2.init(MDL_key::TABLE, db_name, table_name2, MDL_SHARED);
+ request_3.init(MDL_key::TABLE, db_name, table_name3, MDL_SHARED);
+ request_4.init(MDL_key::TABLE, db_name, table_name4, MDL_SHARED);
+
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&m_request));
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&request_2));
+ MDL_ticket *savepoint= m_mdl_context.mdl_savepoint();
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&request_3));
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&request_4));
+
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name2, MDL_SHARED));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name3, MDL_SHARED));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name4, MDL_SHARED));
+
+ m_mdl_context.rollback_to_savepoint(savepoint);
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name2, MDL_SHARED));
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name3, MDL_SHARED));
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name4, MDL_SHARED));
+
+ m_mdl_context.rollback_to_savepoint(NULL);
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name2, MDL_SHARED));
+}
+
+
+/*
+ Verifies that we can grab shared locks concurrently, in different threads.
+ */
+TEST_F(MDL_test, concurrent_shared)
+{
+ Notification lock_grabbed;
+ Notification release_locks;
+ MDL_thread mdl_thread(table_name1, MDL_SHARED, &lock_grabbed, &release_locks);
+ mdl_thread.start();
+ lock_grabbed.wait_for_notification();
+
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+
+ EXPECT_FALSE(m_mdl_context.acquire_lock(&m_request, long_timeout));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+
+ release_locks.notify();
+ mdl_thread.join();
+
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+}
+
+
+/*
+ Verifies that we cannot grab an exclusive lock on something which
+ is locked with a shared lock in a different thread.
+ */
+TEST_F(MDL_test, concurrent_shared_exclusive)
+{
+ expected_error= ER_LOCK_WAIT_TIMEOUT;
+
+ Notification lock_grabbed;
+ Notification release_locks;
+ MDL_thread mdl_thread(table_name1, MDL_SHARED, &lock_grabbed, &release_locks);
+ mdl_thread.ignore_notify();
+ mdl_thread.start();
+ lock_grabbed.wait_for_notification();
+
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_EXCLUSIVE);
+
+ m_request_list.push_front(&m_request);
+ m_request_list.push_front(&m_global_request);
+
+ // We should *not* be able to grab the lock here.
+ EXPECT_TRUE(m_mdl_context.acquire_locks(&m_request_list, zero_timeout));
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE,
+ db_name, table_name1, MDL_EXCLUSIVE));
+
+ release_locks.notify();
+ mdl_thread.join();
+
+ // Now we should be able to grab the lock.
+ EXPECT_FALSE(m_mdl_context.acquire_locks(&m_request_list, zero_timeout));
+ EXPECT_NE(m_null_ticket, m_request.ticket);
+
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+ m_mdl_context.release_lock(m_global_request.ticket);
+}
+
+
+/*
+ Verifies that we cannot we cannot grab a shared lock on something which
+ is locked exlusively in a different thread.
+ */
+TEST_F(MDL_test, concurrent_exclusive_shared)
+{
+ Notification lock_grabbed;
+ Notification release_locks;
+ MDL_thread mdl_thread(table_name1, MDL_EXCLUSIVE,
+ &lock_grabbed, &release_locks);
+ mdl_thread.start();
+ lock_grabbed.wait_for_notification();
+
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+
+ // We should *not* be able to grab the lock here.
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&m_request));
+ EXPECT_EQ(m_null_ticket, m_request.ticket);
+
+ release_locks.notify();
+
+ // The other thread should eventually release its locks.
+ EXPECT_FALSE(m_mdl_context.acquire_lock(&m_request, long_timeout));
+ EXPECT_NE(m_null_ticket, m_request.ticket);
+
+ mdl_thread.join();
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+}
+
+
+/*
+ Verifies the following scenario:
+ Thread 1: grabs a shared upgradable lock.
+ Thread 2: grabs a shared lock.
+ Thread 1: asks for an upgrade to exclusive (needs to wait for thread 2)
+ Thread 2: gets notified, and releases lock.
+ Thread 1: gets the exclusive lock.
+ */
+TEST_F(MDL_test, concurrent_upgrade)
+{
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED_NO_WRITE);
+ m_request_list.push_front(&m_request);
+ m_request_list.push_front(&m_global_request);
+
+ EXPECT_FALSE(m_mdl_context.acquire_locks(&m_request_list, long_timeout));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE,
+ db_name, table_name1, MDL_SHARED_NO_WRITE));
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE,
+ db_name, table_name1, MDL_EXCLUSIVE));
+
+ Notification lock_grabbed;
+ Notification release_locks;
+ MDL_thread mdl_thread(table_name1, MDL_SHARED, &lock_grabbed, &release_locks);
+ mdl_thread.start();
+ lock_grabbed.wait_for_notification();
+
+ EXPECT_FALSE(m_mdl_context.
+ upgrade_shared_lock_to_exclusive(m_request.ticket, long_timeout));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE,
+ db_name, table_name1, MDL_EXCLUSIVE));
+
+ mdl_thread.join();
+ m_mdl_context.rollback_to_savepoint(NULL);
+}
+
+} // namespace
=== added file 'unittest/gunit/mdl_mytap-t.cc'
--- a/unittest/gunit/mdl_mytap-t.cc 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/mdl_mytap-t.cc 2010-06-23 11:01:12 +0000
@@ -0,0 +1,796 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ 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 */
+
+/**
+ This is a port of the corresponding mdl_test.cc (written for googletest)
+ to mytap. Do a 'tkdiff mdl-t.cc mdl_mytap-t.cc' to see the differences.
+ In order to illustrate (some of) the features of googletest, I have
+ added some extensions below, notably support for reporting of line
+ numbers in case of failures.
+ */
+
+#include <string>
+#include <iostream>
+#include <stdio.h>
+
+#include <tap.h>
+
+#include "mdl.h"
+#include <mysqld_error.h>
+
+#include "thr_malloc.h"
+#include "thread_utils.h"
+
+pthread_key(MEM_ROOT**,THR_MALLOC);
+pthread_key(THD*, THR_THD);
+mysql_mutex_t LOCK_open;
+uint opt_debug_sync_timeout= 0;
+
+// Reimplemented some macros from googletest, so that the tests below
+// could be kept unchanged. No support for streaming of user messages
+// in this simplified version.
+void print_message(const char* file, int line, const char* message)
+{
+ std::cout << "# " << file << ":" << line << " " << message << "\n";
+}
+
+// Some macro tricks to generate names like result123 and result456
+#define CONCAT_TOKEN_(foo, bar) CONCAT_TOKEN_IMPL_(foo, bar)
+#define CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
+#define BOOL_VAR_ CONCAT_TOKEN_(result, __LINE__)
+
+#define MESSAGE_(message) \
+ print_message(__FILE__, __LINE__, message)
+
+// This is where we call the ok() function from mytap!!!
+#define TEST_BOOLEAN_(boolexpr, booltext, actual, expected, fail) \
+do { \
+ const bool BOOL_VAR_ = boolexpr; \
+ ok(BOOL_VAR_, BOOL_VAR_ ? "" : booltext); \
+ if (!BOOL_VAR_) \
+ fail("\n# Value of: " booltext \
+ "\n# Actual: " #actual \
+ "\n# Expected: " #expected); \
+} while(0)
+
+// Boolean assertions.
+#define EXPECT_TRUE(condition) \
+ TEST_BOOLEAN_(condition, #condition, false, true, MESSAGE_)
+#define EXPECT_FALSE(condition) \
+ TEST_BOOLEAN_(!(condition), #condition, true, false, MESSAGE_)
+
+
+// Some (very) simplified versions of comparison predicates.
+// There is no distinction between ASSERT and EXPECT in mytap.
+#define ASSERT_NE(val1, val2) \
+ EXPECT_NE(val1, val2)
+
+// This version will not print expected or actual values for arguments.
+#define EXPECT_NE(val1, val2) \
+ EXPECT_TRUE(val1 != val2)
+
+// This version will not print expected or actual values for arguments.
+#define EXPECT_EQ(val1, val2) \
+ EXPECT_TRUE(val1 == val2)
+
+#define FAIL() \
+ EXPECT_TRUE(1 == 0)
+
+
+
+/*
+ A mock error handler.
+*/
+static uint expected_error= 0;
+extern "C" void test_error_handler_hook(uint err, const char *str, myf MyFlags)
+{
+ EXPECT_EQ(expected_error, err);
+}
+
+/*
+ A mock out-of-memory handler.
+ We do not expect this to be called during testing.
+*/
+extern "C" void sql_alloc_error_handler(void)
+{
+ FAIL();
+}
+
+namespace {
+bool notify_thread(THD*);
+}
+
+/*
+ We need to mock away this global function, because the real version
+ pulls in a lot of dependencies.
+ (The @note for the real version of this function indicates that the
+ coupling between THD and MDL is too tight.)
+ @retval TRUE if the thread was woken up
+ @retval FALSE otherwise.
+*/
+bool mysql_notify_thread_having_shared_lock(THD *thd, THD *in_use,
+ bool needs_thr_lock_abort)
+{
+ if (in_use != NULL)
+ return notify_thread(in_use);
+ return FALSE;
+}
+
+/*
+ Mock away this function as well, with an empty function.
+ @todo didrik: Consider verifying that the MDL module actually calls
+ this with correct arguments.
+*/
+void mysql_ha_flush(THD *)
+{
+ DBUG_PRINT("mysql_ha_flush", ("mock version"));
+}
+
+/*
+ We need to mock away this global function, the real version pulls in
+ too many dependencies.
+ */
+extern "C" const char *set_thd_proc_info(void *thd, const char *info,
+ const char *calling_function,
+ const char *calling_file,
+ const unsigned int calling_line)
+{
+ DBUG_PRINT("proc_info", ("%s:%d %s", calling_file, calling_line,
+ (info != NULL) ? info : "(null)"));
+ return info;
+}
+
+/*
+ Mock away this global function.
+ We don't need DEBUG_SYNC functionality in a unit test.
+ */
+void debug_sync(THD *thd, const char *sync_point_name, size_t name_len)
+{
+ DBUG_PRINT("debug_sync_point", ("hit: '%s'", sync_point_name));
+ FAIL();
+}
+
+/*
+ Putting everything in an unnamed namespace prevents any (unintentional)
+ name clashes with the code under test.
+*/
+namespace {
+
+using thread::Notification;
+using thread::Thread;
+
+const char db_name[]= "some_database";
+const char table_name1[]= "some_table1";
+const char table_name2[]= "some_table2";
+const char table_name3[]= "some_table3";
+const char table_name4[]= "some_table4";
+const ulong zero_timeout= 0;
+const ulong long_timeout= (ulong) 3600L*24L*365L;
+
+
+class MDL_test
+{
+public:
+ // Utility function to run one test case.
+ typedef void (MDL_test::* Pmdl_mem)();
+ static void run_one_test(Pmdl_mem member_function);
+
+ // Utility function to run all the test cases.
+ static int RUN_ALL_TESTS();
+
+protected:
+ MDL_test()
+ : m_thd(NULL),
+ m_null_ticket(NULL),
+ m_null_request(NULL)
+ {
+ }
+
+ static void SetUpTestCase()
+ {
+ error_handler_hook= test_error_handler_hook;
+ }
+
+ void SetUp()
+ {
+ expected_error= 0;
+ mdl_init();
+ m_mdl_context.init(m_thd);
+ EXPECT_FALSE(m_mdl_context.has_locks());
+ m_global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE);
+ }
+
+ void TearDown()
+ {
+ m_mdl_context.destroy();
+ mdl_destroy();
+ }
+
+ // A utility member for testing single lock requests.
+ void test_one_simple_shared_lock(enum_mdl_type lock_type);
+
+ // We must list all the individual tests here.
+ void die_when_m_tickets_nonempty();
+ void die_when_holding_global_shared_lock();
+ void construct_and_destruct();
+ void factory_function();
+ void one_shared();
+ void one_shared_high_prio();
+ void one_shared_read();
+ void one_shared_write();
+ void one_exclusive();
+ void two_shared();
+ void shared_locks_between_contexts();
+ void upgrade_shared_upgradable();
+ void die_upgrade_shared();
+ void savepoint();
+ void concurrent_shared();
+ void concurrent_shared_exclusive();
+ void concurrent_exclusive_shared();
+ void concurrent_upgrade();
+
+ THD *m_thd;
+ const MDL_ticket *m_null_ticket;
+ const MDL_request *m_null_request;
+ MDL_context m_mdl_context;
+ MDL_request m_request;
+ MDL_request m_global_request;
+ MDL_request_list m_request_list;
+private:
+ // GTEST_DISALLOW_COPY_AND_ASSIGN_(MDL_test);
+};
+
+
+/*
+ Will grab a lock on table_name of given type in the run() function.
+ The two notifications are for synchronizing with the main thread.
+ Does *not* take ownership of the notifications.
+*/
+class MDL_thread : public Thread
+{
+public:
+ MDL_thread(const char *table_name,
+ enum_mdl_type mdl_type,
+ Notification *lock_grabbed,
+ Notification *release_locks)
+ : m_table_name(table_name),
+ m_mdl_type(mdl_type),
+ m_lock_grabbed(lock_grabbed),
+ m_release_locks(release_locks),
+ m_ignore_notify(false)
+ {
+ m_thd= reinterpret_cast<THD*>(this); // See notify_thread below.
+ m_mdl_context.init(m_thd);
+ }
+
+ ~MDL_thread()
+ {
+ m_mdl_context.destroy();
+ }
+
+ virtual void run();
+ void ignore_notify() { m_ignore_notify= true; }
+
+ bool notify()
+ {
+ if (m_ignore_notify)
+ return false;
+ m_release_locks->notify();
+ return true;
+ }
+
+private:
+ const char *m_table_name;
+ enum_mdl_type m_mdl_type;
+ Notification *m_lock_grabbed;
+ Notification *m_release_locks;
+ bool m_ignore_notify;
+ THD *m_thd;
+ MDL_context m_mdl_context;
+};
+
+
+// Admittedly an ugly hack, to avoid pulling in the THD in this unit test.
+bool notify_thread(THD *thd)
+{
+ MDL_thread *thread = (MDL_thread*) thd;
+ return thread->notify();
+}
+
+
+void MDL_thread::run()
+{
+ MDL_request request;
+ MDL_request global_request;
+ MDL_request_list request_list;
+ global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE);
+ request.init(MDL_key::TABLE, db_name, m_table_name, m_mdl_type);
+
+ request_list.push_front(&request);
+ if (m_mdl_type >= MDL_SHARED_NO_WRITE)
+ request_list.push_front(&global_request);
+
+ EXPECT_FALSE(m_mdl_context.acquire_locks(&request_list, long_timeout));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, m_table_name, m_mdl_type));
+
+ // Tell the main thread that we have grabbed our locks.
+ m_lock_grabbed->notify();
+ // Hold on to locks until we are told to release them
+ m_release_locks->wait_for_notification();
+
+ m_mdl_context.rollback_to_savepoint(NULL);
+}
+
+// googletest recommends DeathTest suffix for classes use in death tests.
+typedef MDL_test MDL_DeathTest;
+
+// Our own (simplified) version of the TEST_F macro.
+#define TEST_F(Fixture_class, function_name) \
+ void Fixture_class::function_name()
+
+
+/*
+ The most basic test: just construct and destruct our test fixture.
+ */
+TEST_F(MDL_test, construct_and_destruct)
+{
+}
+
+
+/*
+ Verifies that we can create requests with the factory function
+ MDL_request::create().
+ */
+TEST_F(MDL_test, factory_function)
+{
+ MEM_ROOT mem_root;
+ init_sql_alloc(&mem_root, 1024, 0);
+ // This request should not be destroyed in the normal C++ fashion.
+ MDL_request *request=
+ MDL_request::create(MDL_key::TABLE,
+ db_name, table_name1, MDL_SHARED, &mem_root);
+ ASSERT_NE(m_null_request, request);
+ EXPECT_EQ(m_null_ticket, request->ticket);
+ free_root(&mem_root, MYF(0));
+}
+
+
+void MDL_test::test_one_simple_shared_lock(enum_mdl_type lock_type)
+{
+ m_request.init(MDL_key::TABLE, db_name, table_name1, lock_type);
+
+ EXPECT_EQ(lock_type, m_request.type);
+ EXPECT_EQ(m_null_ticket, m_request.ticket);
+
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&m_request));
+ EXPECT_NE(m_null_ticket, m_request.ticket);
+ EXPECT_TRUE(m_mdl_context.has_locks());
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, lock_type));
+
+ MDL_request request_2;
+ request_2.init(&m_request.key, lock_type);
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&request_2));
+ EXPECT_EQ(m_request.ticket, request_2.ticket);
+
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+ EXPECT_FALSE(m_mdl_context.has_locks());
+}
+
+
+/*
+ Acquires one lock of type MDL_SHARED.
+ */
+TEST_F(MDL_test, one_shared)
+{
+ test_one_simple_shared_lock(MDL_SHARED);
+}
+
+
+/*
+ Acquires one lock of type MDL_SHARED_HIGH_PRIO.
+ */
+TEST_F(MDL_test, one_shared_high_prio)
+{
+ test_one_simple_shared_lock(MDL_SHARED_HIGH_PRIO);
+}
+
+
+/*
+ Acquires one lock of type MDL_SHARED_READ.
+ */
+TEST_F(MDL_test, one_shared_read)
+{
+ test_one_simple_shared_lock(MDL_SHARED_READ);
+}
+
+
+/*
+ Acquires one lock of type MDL_SHARED_WRITE.
+ */
+TEST_F(MDL_test, one_shared_write)
+{
+ test_one_simple_shared_lock(MDL_SHARED_WRITE);
+}
+
+
+/*
+ Acquires one lock of type MDL_EXCLUSIVE.
+ */
+TEST_F(MDL_test, one_exclusive)
+{
+ const enum_mdl_type lock_type= MDL_EXCLUSIVE;
+ m_request.init(MDL_key::TABLE, db_name, table_name1, lock_type);
+ EXPECT_EQ(m_null_ticket, m_request.ticket);
+
+ m_request_list.push_front(&m_request);
+ m_request_list.push_front(&m_global_request);
+
+ EXPECT_FALSE(m_mdl_context.acquire_locks(&m_request_list, long_timeout));
+
+ EXPECT_NE(m_null_ticket, m_request.ticket);
+ EXPECT_NE(m_null_ticket, m_global_request.ticket);
+ EXPECT_TRUE(m_mdl_context.has_locks());
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, lock_type));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE));
+ EXPECT_TRUE(m_request.ticket->is_upgradable_or_exclusive());
+
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+ m_mdl_context.release_lock(m_global_request.ticket);
+ EXPECT_FALSE(m_mdl_context.has_locks());
+}
+
+
+/*
+ Acquires two locks, on different tables, of type MDL_SHARED.
+ Verifies that they are independent.
+ */
+TEST_F(MDL_test, two_shared)
+{
+ MDL_request request_2;
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+ request_2.init(MDL_key::TABLE, db_name, table_name2, MDL_SHARED);
+
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&m_request));
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&request_2));
+ EXPECT_TRUE(m_mdl_context.has_locks());
+ ASSERT_NE(m_null_ticket, m_request.ticket);
+ ASSERT_NE(m_null_ticket, request_2.ticket);
+
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name2, MDL_SHARED));
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name3, MDL_SHARED));
+
+ m_mdl_context.release_lock(m_request.ticket);
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+ EXPECT_TRUE(m_mdl_context.has_locks());
+
+ m_mdl_context.release_lock(request_2.ticket);
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name2, MDL_SHARED));
+ EXPECT_FALSE(m_mdl_context.has_locks());
+}
+
+
+/*
+ Verifies that two different contexts can acquire a shared lock
+ on the same table.
+ */
+TEST_F(MDL_test, shared_locks_between_contexts)
+{
+ THD *thd2= (THD*) this;
+ MDL_context mdl_context2;
+ mdl_context2.init(thd2);
+ MDL_request request_2;
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+ request_2.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&m_request));
+ EXPECT_FALSE(mdl_context2.try_acquire_lock(&request_2));
+
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+ EXPECT_TRUE(mdl_context2.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+ mdl_context2.release_all_locks_for_name(request_2.ticket);
+}
+
+
+/*
+ Verifies that we can upgrade a shared lock to exclusive.
+ */
+TEST_F(MDL_test, upgrade_shared_upgradable)
+{
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED_NO_WRITE);
+
+ m_request_list.push_front(&m_request);
+ m_request_list.push_front(&m_global_request);
+
+ EXPECT_FALSE(m_mdl_context.acquire_locks(&m_request_list, long_timeout));
+ EXPECT_FALSE(m_mdl_context.
+ upgrade_shared_lock_to_exclusive(m_request.ticket, long_timeout));
+ EXPECT_EQ(MDL_EXCLUSIVE, m_request.ticket->get_type());
+
+ // Another upgrade should be a no-op.
+ EXPECT_FALSE(m_mdl_context.
+ upgrade_shared_lock_to_exclusive(m_request.ticket, long_timeout));
+ EXPECT_EQ(MDL_EXCLUSIVE, m_request.ticket->get_type());
+
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+ m_mdl_context.release_lock(m_global_request.ticket);
+}
+
+
+/*
+ Verifies that only upgradable locks can be upgraded to exclusive.
+ */
+TEST_F(MDL_DeathTest, die_upgrade_shared)
+{
+ MDL_request request_2;
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+ request_2.init(MDL_key::TABLE, db_name, table_name2, MDL_SHARED_NO_READ_WRITE);
+
+ m_request_list.push_front(&m_request);
+ m_request_list.push_front(&request_2);
+ m_request_list.push_front(&m_global_request);
+
+ EXPECT_FALSE(m_mdl_context.acquire_locks(&m_request_list, long_timeout));
+
+#if GTEST_HAS_DEATH_TEST && !defined(DBUG_OFF)
+ ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+ EXPECT_DEATH_IF_SUPPORTED(m_mdl_context.
+ upgrade_shared_lock_to_exclusive(m_request.ticket,
+ long_timeout),
+ ".*MDL_SHARED_NO_.*");
+#endif
+ EXPECT_FALSE(m_mdl_context.
+ upgrade_shared_lock_to_exclusive(request_2.ticket, long_timeout));
+ m_mdl_context.rollback_to_savepoint(NULL);
+}
+
+
+/*
+ Verfies that locks are released when we roll back to a savepoint.
+ */
+TEST_F(MDL_test, savepoint)
+{
+ MDL_request request_2;
+ MDL_request request_3;
+ MDL_request request_4;
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+ request_2.init(MDL_key::TABLE, db_name, table_name2, MDL_SHARED);
+ request_3.init(MDL_key::TABLE, db_name, table_name3, MDL_SHARED);
+ request_4.init(MDL_key::TABLE, db_name, table_name4, MDL_SHARED);
+
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&m_request));
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&request_2));
+ MDL_ticket *savepoint= m_mdl_context.mdl_savepoint();
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&request_3));
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&request_4));
+
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name2, MDL_SHARED));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name3, MDL_SHARED));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name4, MDL_SHARED));
+
+ m_mdl_context.rollback_to_savepoint(savepoint);
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name2, MDL_SHARED));
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name3, MDL_SHARED));
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name4, MDL_SHARED));
+
+ m_mdl_context.rollback_to_savepoint(NULL);
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name2, MDL_SHARED));
+}
+
+
+/*
+ Verifies that we can grab shared locks concurrently, in different threads.
+ */
+TEST_F(MDL_test, concurrent_shared)
+{
+ Notification lock_grabbed;
+ Notification release_locks;
+ MDL_thread mdl_thread(table_name1, MDL_SHARED, &lock_grabbed, &release_locks);
+ mdl_thread.start();
+ lock_grabbed.wait_for_notification();
+
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+
+ EXPECT_FALSE(m_mdl_context.acquire_lock(&m_request, long_timeout));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE, db_name, table_name1, MDL_SHARED));
+
+ release_locks.notify();
+ mdl_thread.join();
+
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+}
+
+
+/*
+ Verifies that we cannot grab an exclusive lock on something which
+ is locked with a shared lock in a different thread.
+ */
+TEST_F(MDL_test, concurrent_shared_exclusive)
+{
+ expected_error= ER_LOCK_WAIT_TIMEOUT;
+
+ Notification lock_grabbed;
+ Notification release_locks;
+ MDL_thread mdl_thread(table_name1, MDL_SHARED, &lock_grabbed, &release_locks);
+ mdl_thread.ignore_notify();
+ mdl_thread.start();
+ lock_grabbed.wait_for_notification();
+
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_EXCLUSIVE);
+
+ m_request_list.push_front(&m_request);
+ m_request_list.push_front(&m_global_request);
+
+ // We should *not* be able to grab the lock here.
+ EXPECT_TRUE(m_mdl_context.acquire_locks(&m_request_list, zero_timeout));
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE,
+ db_name, table_name1, MDL_EXCLUSIVE));
+
+ release_locks.notify();
+ mdl_thread.join();
+
+ // Now we should be able to grab the lock.
+ EXPECT_FALSE(m_mdl_context.acquire_locks(&m_request_list, zero_timeout));
+ EXPECT_NE(m_null_ticket, m_request.ticket);
+
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+ m_mdl_context.release_lock(m_global_request.ticket);
+}
+
+
+/*
+ Verifies that we cannot we cannot grab a shared lock on something which
+ is locked exlusively in a different thread.
+ */
+TEST_F(MDL_test, concurrent_exclusive_shared)
+{
+ Notification lock_grabbed;
+ Notification release_locks;
+ MDL_thread mdl_thread(table_name1, MDL_EXCLUSIVE,
+ &lock_grabbed, &release_locks);
+ mdl_thread.start();
+ lock_grabbed.wait_for_notification();
+
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED);
+
+ // We should *not* be able to grab the lock here.
+ EXPECT_FALSE(m_mdl_context.try_acquire_lock(&m_request));
+ EXPECT_EQ(m_null_ticket, m_request.ticket);
+
+ release_locks.notify();
+
+ // The other thread should eventually release its locks.
+ EXPECT_FALSE(m_mdl_context.acquire_lock(&m_request, long_timeout));
+ EXPECT_NE(m_null_ticket, m_request.ticket);
+
+ mdl_thread.join();
+ m_mdl_context.release_all_locks_for_name(m_request.ticket);
+}
+
+
+/*
+ Verifies the following scenario:
+ Thread 1: grabs a shared upgradable lock.
+ Thread 2: grabs a shared lock.
+ Thread 1: asks for an upgrade to exclusive (needs to wait for thread 2)
+ Thread 2: gets notified, and releases lock.
+ Thread 1: gets the exclusive lock.
+ */
+TEST_F(MDL_test, concurrent_upgrade)
+{
+ m_request.init(MDL_key::TABLE, db_name, table_name1, MDL_SHARED_NO_WRITE);
+ m_request_list.push_front(&m_request);
+ m_request_list.push_front(&m_global_request);
+
+ EXPECT_FALSE(m_mdl_context.acquire_locks(&m_request_list, long_timeout));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE,
+ db_name, table_name1, MDL_SHARED_NO_WRITE));
+ EXPECT_FALSE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE,
+ db_name, table_name1, MDL_EXCLUSIVE));
+
+ Notification lock_grabbed;
+ Notification release_locks;
+ MDL_thread mdl_thread(table_name1, MDL_SHARED, &lock_grabbed, &release_locks);
+ mdl_thread.start();
+ lock_grabbed.wait_for_notification();
+
+ EXPECT_FALSE(m_mdl_context.
+ upgrade_shared_lock_to_exclusive(m_request.ticket, long_timeout));
+ EXPECT_TRUE(m_mdl_context.
+ is_lock_owner(MDL_key::TABLE,
+ db_name, table_name1, MDL_EXCLUSIVE));
+
+ mdl_thread.join();
+ m_mdl_context.rollback_to_savepoint(NULL);
+}
+
+} // namespace
+
+
+// Creates a new fixture object for each test case.
+void MDL_test::run_one_test(Pmdl_mem member_function)
+{
+ MDL_test *test_object = new MDL_test;
+ test_object->SetUp();
+ (test_object->*member_function)();
+ test_object->TearDown();
+ delete test_object;
+}
+
+
+// We have to invoke each test explicitly here, since we don't have
+// the auto-registration support from the TEST and TEST_F macros.
+int MDL_test::RUN_ALL_TESTS()
+{
+ MDL_test::SetUpTestCase();
+
+ run_one_test(&MDL_test::construct_and_destruct);
+ run_one_test(&MDL_test::factory_function);
+ run_one_test(&MDL_test::one_shared);
+ run_one_test(&MDL_test::one_shared_high_prio);
+ run_one_test(&MDL_test::one_shared_read);
+ run_one_test(&MDL_test::one_shared_write);
+ run_one_test(&MDL_test::one_exclusive);
+ run_one_test(&MDL_test::two_shared);
+ run_one_test(&MDL_test::shared_locks_between_contexts);
+ run_one_test(&MDL_test::upgrade_shared_upgradable);
+ run_one_test(&MDL_test::die_upgrade_shared);
+ run_one_test(&MDL_test::savepoint);
+ run_one_test(&MDL_test::concurrent_shared);
+ run_one_test(&MDL_test::concurrent_shared_exclusive);
+ run_one_test(&MDL_test::concurrent_exclusive_shared);
+ run_one_test(&MDL_test::concurrent_upgrade);
+
+ // Execute MDL_test::TearDownTestCase() here, if it is defined.
+ return exit_status();
+}
+
+
+int main(int argc, char **argv) {
+ // ::testing::InitGoogleTest(&argc, argv);
+ MY_INIT(argv[0]);
+ plan(NO_PLAN);
+ return MDL_test::RUN_ALL_TESTS();
+}
=== added file 'unittest/gunit/sql_list-t.cc'
--- a/unittest/gunit/sql_list-t.cc 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/sql_list-t.cc 2010-04-21 07:26:14 +0000
@@ -0,0 +1,217 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ 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 */
+
+/*
+ This is a simple example of how to use the google unit test framework.
+
+ For an introduction to the constructs used below, see:
+ http://code.google.com/p/googletest/wiki/GoogleTestPrimer
+*/
+
+// Must include gtest first, since MySQL source has macros for min() etc ....
+#include <gtest/gtest.h>
+
+#include "sql_list.h"
+
+#include "thr_malloc.h"
+#include "sql_string.h"
+#include "sql_error.h"
+#include <my_pthread.h>
+
+pthread_key(MEM_ROOT**, THR_MALLOC);
+pthread_key(THD*, THR_THD);
+
+extern "C" void sql_alloc_error_handler(void)
+{
+ ADD_FAILURE();
+}
+
+namespace {
+
+// A simple helper function to determine array size.
+template <class T, int size>
+int array_size(const T (&)[size])
+{
+ return size;
+}
+
+// A simple helper function to insert values into a List.
+template <class T, int size>
+void insert_values(T (&array)[size], List<T> *list)
+{
+ for (int ix= 0; ix < size; ++ix)
+ {
+ EXPECT_FALSE(list->push_back(&array[ix]));
+ }
+}
+
+/*
+ The fixture for testing the MySQL List and List_iterator classes.
+ A fresh instance of this class will be created for each of the
+ TEST_F functions below.
+ The functions SetUp(), TearDown(), SetUpTestCase(), TearDownTestCase() are
+ inherited from ::testing::Test (google naming style differs from MySQL).
+*/
+class Sql_list_test : public ::testing::Test
+{
+protected:
+ Sql_list_test()
+ : m_mem_root_p(&m_mem_root), m_int_list(), m_int_list_iter(m_int_list)
+ {
+ }
+
+ virtual void SetUp()
+ {
+ init_sql_alloc(&m_mem_root, 1024, 0);
+ ASSERT_EQ(0, my_pthread_setspecific_ptr(THR_MALLOC, &m_mem_root_p));
+ MEM_ROOT *root= *my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC);
+ ASSERT_EQ(root, m_mem_root_p);
+ }
+
+ virtual void TearDown()
+ {
+ free_root(&m_mem_root, MYF(0));
+ }
+
+ static void SetUpTestCase()
+ {
+ ASSERT_EQ(0, pthread_key_create(&THR_THD, NULL));
+ ASSERT_EQ(0, pthread_key_create(&THR_MALLOC, NULL));
+ }
+
+ static void TearDownTestCase()
+ {
+ pthread_key_delete(THR_THD);
+ pthread_key_delete(THR_MALLOC);
+ }
+
+ MEM_ROOT m_mem_root;
+ MEM_ROOT *m_mem_root_p;
+ List<int> m_int_list;
+ List_iterator<int> m_int_list_iter;
+
+private:
+ // Declares (but does not define) copy constructor and assignment operator.
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(Sql_list_test);
+};
+
+
+// Tests that we can construct and destruct lists.
+TEST_F(Sql_list_test, construct_and_destruct)
+{
+ EXPECT_TRUE(m_int_list.is_empty());
+ List<int> *p_int_list= new List<int>;
+ EXPECT_TRUE(p_int_list->is_empty());
+ delete p_int_list;
+}
+
+
+// Tests basic operations push and pop.
+TEST_F(Sql_list_test, basic_operations)
+{
+ int i1= 1;
+ int i2= 2;
+ EXPECT_FALSE(m_int_list.push_front(&i1));
+ EXPECT_FALSE(m_int_list.push_back(&i2));
+ EXPECT_FALSE(m_int_list.is_empty());
+ EXPECT_EQ(2U, m_int_list.elements);
+
+ EXPECT_EQ(&i1, m_int_list.head());
+ EXPECT_EQ(&i1, m_int_list.pop());
+ EXPECT_EQ(&i2, m_int_list.head());
+ EXPECT_EQ(&i2, m_int_list.pop());
+ EXPECT_TRUE(m_int_list.is_empty()) << "The list should be empty now!";
+}
+
+
+// Tests list copying.
+TEST_F(Sql_list_test, deep_copy)
+{
+ int values[] = {11, 22, 33, 42, 5};
+ insert_values(values, &m_int_list);
+ MEM_ROOT *mem_root= (MEM_ROOT*) malloc(1 << 20);
+ init_alloc_root(mem_root, 4096, 4096);
+ List<int> list_copy(m_int_list, mem_root);
+ EXPECT_EQ(list_copy.elements, m_int_list.elements);
+ while (!list_copy.is_empty())
+ {
+ EXPECT_EQ(*m_int_list.pop(), *list_copy.pop());
+ }
+ EXPECT_TRUE(m_int_list.is_empty());
+ free(mem_root);
+}
+
+
+// Tests that we can iterate over values.
+TEST_F(Sql_list_test, iterate)
+{
+ int values[] = {3, 2, 1};
+ insert_values(values, &m_int_list);
+ for (int ix= 0; ix < array_size(values); ++ix)
+ {
+ EXPECT_EQ(values[ix], *m_int_list_iter++);
+ }
+ m_int_list_iter.init(m_int_list);
+ int *value;
+ int value_number= 0;
+ while ((value= m_int_list_iter++))
+ {
+ EXPECT_EQ(values[value_number++], *value);
+ }
+}
+
+
+// A simple helper class for testing intrusive lists.
+class Linked_node : public ilink
+{
+public:
+ Linked_node(int val) : m_value(val) {}
+ int get_value() const { return m_value; }
+private:
+ int m_value;
+};
+
+
+// An example of a test without any fixture.
+TEST(Sql_ilist_test, construct_and_destruct)
+{
+ I_List<Linked_node> i_list;
+ I_List_iterator<Linked_node> i_list_iter(i_list);
+ EXPECT_TRUE(i_list.is_empty());
+ const Linked_node *null_node= NULL;
+ EXPECT_EQ(null_node, i_list_iter++);
+}
+
+
+// Tests iteration over intrusive lists.
+TEST(Sql_ilist_test, iterate)
+{
+ I_List<Linked_node> i_list;
+ I_List_iterator<Linked_node> i_list_iter(i_list);
+ int values[] = {11, 22, 33, 42, 5};
+ for (int ix= 0; ix < array_size(values); ++ix)
+ {
+ i_list.push_back(new Linked_node(values[ix]));
+ }
+
+ Linked_node *node;
+ int value_number= 0;
+ while ((node= i_list_iter++))
+ {
+ EXPECT_EQ(values[value_number++], node->get_value());
+ }
+}
+
+} // namespace
=== added file 'unittest/gunit/tap_event_listener.cc'
--- a/unittest/gunit/tap_event_listener.cc 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/tap_event_listener.cc 2010-03-19 07:48:37 +0000
@@ -0,0 +1,258 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ 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 <gtest/gtest.h>
+#include <stdarg.h>
+#include <string>
+#include <sstream>
+
+using testing::TestEventListeners;
+using testing::TestCase;
+using testing::TestEventListener;
+using testing::TestInfo;
+using testing::TestPartResult;
+using testing::UnitTest;
+using testing::UnitTest;
+
+
+/**
+ Receives events from googletest, and outputs interesting events
+ in TAP compliant format.
+ Implementation is inspired by PrettyUnitTestResultPrinter.
+ See documentation for base class.
+ */
+class TapEventListener : public TestEventListener
+{
+public:
+ TapEventListener() : m_test_number(0) {}
+ virtual ~TapEventListener() {}
+
+ virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
+ virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestCaseStart(const TestCase& test_case);
+ virtual void OnTestStart(const TestInfo& test_info);
+ virtual void OnTestPartResult(const TestPartResult& test_part_result);
+ virtual void OnTestEnd(const TestInfo& test_info);
+ virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {};
+ virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
+ virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
+ virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
+ virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
+private:
+ int m_test_number;
+ std::string m_test_case_name;
+};
+
+
+/**
+ Prints argument to stdout, prefixing all lines with "# ".
+ */
+static void tap_diagnostic_printf(const std::stringstream &str_stream)
+{
+ std::string message= str_stream.str();
+ size_t pos = 0;
+ while((pos = message.find("\n", pos)) != std::string::npos)
+ {
+ message.replace(pos, 1, "\n# ");
+ pos += 1;
+ }
+ printf("# %s\n", message.c_str());
+ fflush(stdout);
+}
+
+// Convenience wrapper function.
+static void tap_diagnostic_printf(const std::string &txt)
+{
+ std::stringstream str_str;
+ str_str << txt;
+ tap_diagnostic_printf(str_str);
+}
+
+// Convenience wrapper function.
+static void tap_diagnostic_printf(const char *txt)
+{
+ tap_diagnostic_printf(std::string(txt));
+}
+
+
+namespace {
+// Helper struct to simplify output of "1 test" or "n tests".
+struct num_tests
+{
+ num_tests(int num) : m_num(num) {}
+ int m_num;
+};
+
+std::ostream &operator<< (std::ostream &s, const num_tests &num)
+{
+ return s << num.m_num << (num.m_num == 1 ? " test" : " tests");
+}
+
+// Helper struct to simplify output of "1 test case" or "n test cases".
+struct num_test_cases
+{
+ num_test_cases(int num) : m_num(num) {}
+ int m_num;
+};
+
+std::ostream &operator<< (std::ostream &s, const num_test_cases &num)
+{
+ return s << num.m_num << (num.m_num == 1 ? " test case" : " test cases");
+}
+} // namespace
+
+
+/**
+ Converts a TestPartResult::Type enum to human-friendly string
+ representation.
+*/
+static std::string test_part_result_type_tostring(TestPartResult::Type type)
+{
+ switch (type)
+ {
+ case TestPartResult::kSuccess:
+ return "Success";
+
+ case TestPartResult::kNonFatalFailure:
+ case TestPartResult::kFatalFailure:
+ return "Failure";
+ }
+ return "";
+}
+
+
+/**
+ Formats a source file path and a line number as they would appear
+ in a compiler error message.
+*/
+static std::string format_file_location(const TestPartResult &test_part_result)
+{
+ const char* const file= test_part_result.file_name();
+ const char* const file_name = file == NULL ? "unknown file" : file;
+ const int line= test_part_result.line_number();
+ std::stringstream str_stream;
+ str_stream << file_name << ":";
+ if (line >= 0)
+ str_stream << line << ":";
+ return str_stream.str();
+}
+
+
+/**
+ Formats a TestPartResult as a string.
+ */
+static std::string test_part_result_tostring(const TestPartResult
+ &test_part_result)
+{
+ return format_file_location(test_part_result)
+ + " "
+ + test_part_result_type_tostring(test_part_result.type())
+ + test_part_result.message();
+}
+
+
+void TapEventListener::OnTestIterationStart(const UnitTest& unit_test,
+ int iteration)
+{
+ std::stringstream str_stream;
+ str_stream << "Running " << num_tests(unit_test.test_to_run_count())
+ << " from " << num_test_cases(unit_test.test_case_to_run_count());
+ tap_diagnostic_printf(str_stream);
+ printf("%d..%d\n", 1, unit_test.test_to_run_count());
+ fflush(stdout);
+}
+
+
+void TapEventListener::OnEnvironmentsSetUpStart(const UnitTest& unit_test)
+{
+ tap_diagnostic_printf("Global test environment set-up");
+}
+
+
+void TapEventListener::OnTestCaseStart(const TestCase& test_case)
+{
+ m_test_case_name = test_case.name();
+}
+
+
+void TapEventListener::OnTestStart(const TestInfo& test_info)
+{
+ ++m_test_number;
+ std::stringstream str_stream;
+ str_stream << "Run " << m_test_number << " "
+ << m_test_case_name << "." << test_info.name();
+ tap_diagnostic_printf(str_stream);
+}
+
+
+void TapEventListener::OnTestPartResult(const TestPartResult& test_part_result)
+{
+ if (test_part_result.passed())
+ return;
+ tap_diagnostic_printf(test_part_result_tostring(test_part_result));
+}
+
+
+void TapEventListener::OnTestEnd(const TestInfo& test_info)
+{
+ if (test_info.result()->Passed())
+ printf("ok %d\n", m_test_number);
+ else
+ printf("not ok %d\n", m_test_number);
+ fflush(stdout);
+}
+
+
+void TapEventListener::OnEnvironmentsTearDownStart(const UnitTest& unit_test)
+{
+ tap_diagnostic_printf("Global test environment tear-down");
+}
+
+
+void TapEventListener::OnTestIterationEnd(const UnitTest& unit_test,
+ int iteration)
+{
+ std::stringstream str_stream;
+ str_stream << "Ran " << num_tests(unit_test.test_to_run_count())
+ << " from " << num_test_cases(unit_test.test_case_to_run_count())
+ << "\n"
+ << "Passed " << num_tests(unit_test.successful_test_count());
+
+ if (!unit_test.Passed())
+ str_stream << "\n"
+ << "Failed " << num_tests(unit_test.failed_test_count());
+
+ const int num_disabled = unit_test.disabled_test_count();
+ if (num_disabled && !testing::GTEST_FLAG(also_run_disabled_tests))
+ str_stream << "\n"
+ << "YOU HAVE " << num_disabled << " DISABLED "
+ << (num_disabled == 1 ? "TEST" : "TESTS");
+
+ tap_diagnostic_printf(str_stream);
+}
+
+
+/**
+ Removes the default googletest listener (a PrettyUnitTestResultPrinter),
+ and installs our own TAP compliant pretty printer instead.
+ */
+void install_tap_listener()
+{
+ TestEventListeners& listeners = UnitTest::GetInstance()->listeners();
+ delete listeners.Release(listeners.default_result_printer());
+ listeners.Append(new TapEventListener);
+}
=== added file 'unittest/gunit/thread_utils-t.cc'
--- a/unittest/gunit/thread_utils-t.cc 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/thread_utils-t.cc 2010-03-18 13:39:53 +0000
@@ -0,0 +1,114 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ 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 */
+
+// Must include gtest first, since MySQL source has macros for min() etc ....
+#include <gtest/gtest.h>
+
+#include "thread_utils.h"
+
+#include "mdl.h"
+
+pthread_key(MEM_ROOT**,THR_MALLOC);
+pthread_key(THD*, THR_THD);
+
+extern "C" void sql_alloc_error_handler(void)
+{
+ ADD_FAILURE();
+}
+
+using thread::Mutex_lock;
+using thread::Notification;
+using thread::Thread;
+
+namespace {
+
+const int counter_start_value= 42;
+
+class Notification_thread : public Thread
+{
+public:
+ Notification_thread(Notification *start_notification,
+ Notification *end_notfication,
+ int *counter)
+ : m_start_notification(start_notification),
+ m_end_notification(end_notfication),
+ m_counter(counter)
+ {
+ }
+
+ virtual void run()
+ {
+ // Verify counter, increment it, notify the main thread.
+ EXPECT_EQ(counter_start_value, *m_counter);
+ (*m_counter)+= 1;
+ m_start_notification->notify();
+
+ // Wait for notification from other thread.
+ m_end_notification->wait_for_notification();
+ EXPECT_EQ(counter_start_value, *m_counter);
+
+ // Set counter again before returning from thread.
+ (*m_counter)+= 1;
+ }
+
+private:
+ Notification *m_start_notification;
+ Notification *m_end_notification;
+ int *m_counter;
+
+ Notification_thread(const Notification_thread&); // Not copyable.
+ void operator=(const Notification_thread&); // Not assignable.
+};
+
+
+/*
+ A basic, single-threaded test of Notification.
+ */
+TEST(Notification, notify)
+{
+ Notification notification;
+ EXPECT_FALSE(notification.has_been_notified());
+ notification.notify();
+ EXPECT_TRUE(notification.has_been_notified());
+}
+
+/*
+ Starts a thread, and verifies that the notification/synchronization
+ mechanism works.
+ */
+TEST(Notification_thread, start_and_wait)
+{
+ Notification start_notification;
+ Notification end_notfication;
+ int counter= counter_start_value;
+ Notification_thread
+ notification_thread(&start_notification, &end_notfication, &counter);
+ notification_thread.start();
+
+ // Wait for the other thread to increment counter, and notify us.
+ start_notification.wait_for_notification();
+ EXPECT_EQ(counter_start_value + 1, counter);
+ EXPECT_TRUE(start_notification.has_been_notified());
+
+ // Reset counter, and notify other thread.
+ counter= counter_start_value;
+ end_notfication.notify();
+ notification_thread.join();
+
+ // We should see the final results of the thread we have joined.
+ EXPECT_EQ(counter_start_value + 1, counter);
+}
+
+} // namespace
=== added file 'unittest/gunit/thread_utils.cc'
--- a/unittest/gunit/thread_utils.cc 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/thread_utils.cc 2010-05-21 13:02:27 +0000
@@ -0,0 +1,118 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ 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 <gtest/gtest.h>
+#include "thread_utils.h"
+
+namespace thread {
+
+namespace {
+void *thread_start_routine(void *arg)
+{
+ Thread *thread= (Thread*) arg;
+ Thread::run_wrapper(thread);
+ return NULL;
+}
+
+// We cannot use ASSERT_FALSE in constructors/destructors,
+// so we add a local helper routine.
+#define LOCAL_ASSERT_FALSE(arg) assert_false(arg, __LINE__)
+void assert_false(int arg, int line)
+{
+ ASSERT_FALSE(arg) << "failed with arg " << arg << " at line " << line;
+}
+
+} // namespace
+
+Thread::~Thread()
+{
+}
+
+
+int Thread::start()
+{
+ return pthread_create(&m_thread_id, NULL, thread_start_routine, this);
+}
+
+
+void Thread::join()
+{
+ int failed= pthread_join(m_thread_id, NULL);
+ ASSERT_FALSE(failed);
+}
+
+
+void Thread::run_wrapper(Thread *thread)
+{
+ const my_bool error= my_thread_init();
+ ASSERT_FALSE(error);
+ thread->run();
+ my_thread_end();
+}
+
+
+Mutex_lock::Mutex_lock(pthread_mutex_t *mutex) : m_mutex(mutex)
+{
+ pthread_mutex_lock(m_mutex);
+}
+
+
+Mutex_lock::~Mutex_lock()
+{
+ const int failed= pthread_mutex_unlock(m_mutex);
+ LOCAL_ASSERT_FALSE(failed);
+}
+
+
+Notification::Notification() : m_notified(FALSE)
+{
+ const int failed1= pthread_cond_init(&m_cond, NULL);
+ LOCAL_ASSERT_FALSE(failed1);
+ const int failed2= pthread_mutex_init(&m_mutex, MY_MUTEX_INIT_FAST);
+ LOCAL_ASSERT_FALSE(failed2);
+}
+
+Notification::~Notification()
+{
+ pthread_mutex_destroy(&m_mutex);
+ pthread_cond_destroy(&m_cond);
+}
+
+bool Notification::has_been_notified()
+{
+ Mutex_lock lock(&m_mutex);
+ return m_notified;
+}
+
+void Notification::wait_for_notification()
+{
+ Mutex_lock lock(&m_mutex);
+ while (!m_notified)
+ {
+ const int failed= pthread_cond_wait(&m_cond, &m_mutex);
+ ASSERT_FALSE(failed);
+ }
+}
+
+void Notification::notify()
+{
+ Mutex_lock lock(&m_mutex);
+ m_notified= TRUE;
+ const int failed= pthread_cond_broadcast(&m_cond);
+ ASSERT_FALSE(failed);
+}
+
+
+} // namespace thread
=== added file 'unittest/gunit/thread_utils.h'
--- a/unittest/gunit/thread_utils.h 1970-01-01 00:00:00 +0000
+++ b/unittest/gunit/thread_utils.h 2010-03-19 11:46:14 +0000
@@ -0,0 +1,108 @@
+/* Copyright (C) 2009 Sun Microsystems, Inc.
+
+ 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 SQL_THREAD_INCLUDED
+#define SQL_THREAD_INCLUDED
+
+#include <my_global.h>
+#include <my_pthread.h>
+
+namespace thread {
+
+/*
+ An abstract class for creating/running/joining threads.
+ Thread::start() will create a new pthread, and execute the run() function.
+*/
+class Thread
+{
+public:
+ Thread() : m_thread_id(0) {}
+ virtual ~Thread();
+
+ /*
+ Will create a new pthread, and invoke run();
+ Returns the value from pthread_create().
+ */
+ int start();
+
+ /*
+ You may invoke this to wait for the thread to finish.
+ You should probalbly join() a thread before deleting it.
+ */
+ void join();
+
+ // The id of the thread (valid only if it is actually running).
+ pthread_t thread_id() const { return m_thread_id; }
+
+ /*
+ A wrapper for the run() function.
+ Users should *not* call this function directly, they should rather
+ invoke the start() function.
+ */
+ static void run_wrapper(Thread*);
+
+protected:
+ /*
+ Define this function in derived classes.
+ Users should *not* call this function directly, they should rather
+ invoke the start() function.
+ */
+ virtual void run() = 0;
+
+private:
+ pthread_t m_thread_id;
+
+ Thread(const Thread&); /* Not copyable. */
+ void operator=(const Thread&); /* Not assignable. */
+};
+
+
+// A simple wrapper around a mutex:
+// Grabs the mutex in the CTOR, releases it in the DTOR.
+class Mutex_lock
+{
+public:
+ Mutex_lock(pthread_mutex_t *mutex);
+ ~Mutex_lock();
+private:
+ pthread_mutex_t *m_mutex;
+
+ Mutex_lock(const Mutex_lock&); /* Not copyable. */
+ void operator=(const Mutex_lock&); /* Not assignable. */
+};
+
+
+// A barrier which can be used for one-time synchronization between threads.
+class Notification
+{
+public:
+ Notification();
+ ~Notification();
+
+ bool has_been_notified();
+ void wait_for_notification();
+ void notify();
+private:
+ bool m_notified;
+ pthread_cond_t m_cond;
+ pthread_mutex_t m_mutex;
+
+ Notification(const Notification&); /* Not copyable. */
+ void operator=(const Notification&); /* Not assignable. */
+};
+
+} // namespace thread
+
+#endif // SQL_THREAD_INCLUDED
=== added file 'unittest/mytap/t/CMakeLists.txt'
--- a/unittest/mytap/t/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ b/unittest/mytap/t/CMakeLists.txt 2010-05-10 12:26:05 +0000
@@ -0,0 +1,22 @@
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; version 2 of the License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include
+ ${CMAKE_SOURCE_DIR}/unittest/mytap)
+
+ADD_EXECUTABLE(basic-t basic-t.c)
+TARGET_LINK_LIBRARIES(basic-t mytap)
+ADD_TEST(basic basic-t)
=== modified file 'unittest/unit.pl'
--- a/unittest/unit.pl 2009-11-18 04:29:26 +0000
+++ b/unittest/unit.pl 2010-03-19 08:02:31 +0000
@@ -66,6 +66,7 @@ sub _find_test_files (@) {
my @files;
find sub {
$File::Find::prune = 1 if /^SCCS$/;
+ $File::Find::prune = 1 if /^.libs$/;
push(@files, $File::Find::name) if -x _ && (/-t\z/ || /-t\.exe\z/);
}, @dirs;
return @files;
Attachment: [text/bzr-bundle]
| Thread |
|---|
| • bzr commit into mysql-next-mr-rpl-merge branch (alfranio.correia:3003) | Alfranio Correia | 14 Jul |