diff options
157 files changed, 3298 insertions, 1339 deletions
diff --git a/.bzrignore b/.bzrignore index f9f9c146692..d8be10eacdb 100644 --- a/.bzrignore +++ b/.bzrignore @@ -800,6 +800,7 @@ ndb/test/ndbapi/testNodeRestart ndb/test/ndbapi/testOIBasic ndb/test/ndbapi/testOperations ndb/test/ndbapi/testRestartGci +ndb/test/ndbapi/testSRBank ndb/test/ndbapi/testScan ndb/test/ndbapi/testScan.dsp ndb/test/ndbapi/testScanInterpreter @@ -825,6 +826,7 @@ ndb/test/tools/hugoScanUpdate ndb/test/tools/ndb_cpcc ndb/test/tools/restart ndb/test/tools/verify_index +ndb/tools/ndb_config ndb/tools/ndb_delete_all ndb/tools/ndb_delete_all.dsp ndb/tools/ndb_desc @@ -969,7 +971,9 @@ support-files/MacOSX/Description.plist support-files/MacOSX/Info.plist support-files/MacOSX/ReadMe.txt support-files/MacOSX/StartupParameters.plist +support-files/MacOSX/postflight support-files/MacOSX/postinstall +support-files/MacOSX/preflight support-files/MacOSX/preinstall support-files/binary-configure support-files/my-huge.cnf @@ -1053,6 +1057,3 @@ vio/test-ssl vio/test-sslclient vio/test-sslserver vio/viotest-ssl -ndb/tools/ndb_config -support-files/MacOSX/postflight -support-files/MacOSX/preflight @@ -1,52 +1,35 @@ -This is a release of MySQL, a GPL (free) SQL database server (more -licence information in the PUBLIC file and in the reference manual). +This is a release of MySQL, a dual-license SQL database server. +MySQL is brought to you by the MySQL team at MySQL AB. -Please read the "Upgrading from..." section in the manual first, if you are -migrating from older versions of MySQL! +License information can be found in these files: +- For GPL (free) distributions, see the COPYING file. +- For commercial distributions, see the MySQLEULA.txt file. -The latest information about MySQL can be found at: -http://www.mysql.com -To see what it can do take a look at the features section in the -manual. +For further information about MySQL or additional documentation, see: +- The latest information about MySQL: http://www.mysql.com +- The current MySQL documentation: http:/dev.mysql.com/doc -For installation instructions see the Installation chapter in the -manual. +Some manual sections of special interest: -For future plans see the TODO appendix in the manual. +- If you are migrating from an older version of MySQL, please read the + "Upgrading from..." section first! +- To see what MySQL can do, take a look at the features section. +- For installation instructions, see the Installation chapter. +- For future plans, see the TODO appendix. +- For the new features/bugfix history, see the News appendix. +- For the currently known bugs/misfeatures (known errors) see the problems + appendix. +- For a list of developers and other contributors, see the Credits + appendix. -New features/bug fixes history is in the news appendix in the manual. - -For the currently known bugs/misfeatures (known errors) see the bugs -appendix in the manual. - -For examples of SQL and benchmarking information see the bench -directory. - -The manual mentioned above can be found in the Docs directory. The -manual is available in the following formats: as plain ASCII text in -Docs/manual.txt, in HTML format in Docs/manual_toc.html, as GNU Info in -Docs/mysql.info and as PostScript in Docs/manual.ps. - -MySQL is brought to you by the MySQL team at MySQL AB - -For a list of developers and other contributors, see the Credits appendix -in the manual. +A local copy of the MySQL Reference Manual can be found in the Docs +directory in GNU Info format. You can also browse the manual online or +download it in any of several formats at the URL given earlier in this +file. ************************************************************ IMPORTANT: -Send bug (error) reports, questions and comments to the mailing list -at mysql@lists.mysql.com - -Please use the 'mysqlbug' script when posting bug reports or questions -about MySQL. mysqlbug will gather some information about your system -and start your editor with a form in which you can describe your -problem. Bug reports might be silently ignored by the MySQL -maintainers if there is not a good reason included in the report as to -why mysqlbug has not been used. A report that says 'MySQL does not -work for me. Why?' is not considered a valid bug report. - -The mysqlbug script can be found in the 'scripts' directory of the -distribution, that is '<where-you-installed-mysql>/scripts'. +Bug or error reports should be sent to http://bugs.mysql.com. diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 019e3080023..ca4acd82db6 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -37,8 +37,9 @@ static char *add_load_option(char *ptr,const char *object, const char *statement); static my_bool verbose=0,lock_tables=0,ignore_errors=0,opt_delete=0, - replace=0,silent=0,ignore=0,opt_compress=0,opt_local_file=0, + replace=0,silent=0,ignore=0,opt_compress=0, opt_low_priority= 0, tty_password= 0; +static uint opt_local_file=0; static MYSQL mysql_connection; static char *opt_password=0, *current_user=0, *current_host=0, *current_db=0, *fields_terminated=0, diff --git a/client/mysqltest.c b/client/mysqltest.c index 33702e9d1d2..f5facccee3a 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -97,6 +97,10 @@ #define DEFAULT_DELIMITER ";" #define MAX_DELIMITER 16 +#define RESULT_OK 0 +#define RESULT_CONTENT_MISMATCH 1 +#define RESULT_LENGTH_MISMATCH 2 + enum {OPT_MANAGER_USER=256,OPT_MANAGER_HOST,OPT_MANAGER_PASSWD, OPT_MANAGER_PORT,OPT_MANAGER_WAIT_TIMEOUT, OPT_SKIP_SAFEMALLOC, OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA, OPT_SSL_CAPATH, @@ -456,6 +460,7 @@ my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } #endif static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, int len); +static int handle_no_error(struct st_query *q); static void do_eval(DYNAMIC_STRING* query_eval, const char *query) { @@ -649,7 +654,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) { DBUG_PRINT("info",("Size differs: result size: %u file size: %u", ds->length, stat_info.st_size)); - DBUG_RETURN(2); + DBUG_RETURN(RESULT_LENGTH_MISMATCH); } if (!(tmp = (char*) my_malloc(stat_info.st_size + 1, MYF(MY_WME)))) die(NullS); @@ -666,7 +671,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) res_ptr = res_ds.str; if ((res_len = res_ds.length) != ds->length) { - res = 2; + res= RESULT_LENGTH_MISMATCH; goto err; } } @@ -676,7 +681,8 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) res_len = stat_info.st_size; } - res = (memcmp(res_ptr, ds->str, res_len)) ? 1 : 0; + res= (memcmp(res_ptr, ds->str, res_len)) ? + RESULT_CONTENT_MISMATCH : RESULT_OK; err: if (res && eval_result) @@ -693,21 +699,21 @@ err: static int check_result(DYNAMIC_STRING* ds, const char *fname, my_bool require_option) { - int error = 0; - int res=dyn_string_cmp(ds, fname); + int error= RESULT_OK; + int res= dyn_string_cmp(ds, fname); if (res && require_option) abort_not_supported_test(); switch (res) { - case 0: + case RESULT_OK: break; /* ok */ - case 2: + case RESULT_LENGTH_MISMATCH: verbose_msg("Result length mismatch"); - error = 1; + error= RESULT_LENGTH_MISMATCH; break; - case 1: + case RESULT_CONTENT_MISMATCH: verbose_msg("Result content mismatch"); - error = 1; + error= RESULT_CONTENT_MISMATCH; break; default: /* impossible */ die("Unknown error code from dyn_string_cmp()"); @@ -812,9 +818,9 @@ int var_set(const char *var_name, const char *var_name_end, int open_file(const char *name) { + char buff[FN_REFLEN]; DBUG_ENTER("open_file"); DBUG_PRINT("enter", ("name: %s", name)); - char buff[FN_REFLEN]; if (!test_if_hard_path(name)) { strxmov(buff, opt_basedir, name, NullS); @@ -843,9 +849,9 @@ int open_file(const char *name) int check_eol_junk(const char *eol) { + const char *p= eol; DBUG_ENTER("check_eol_junk"); DBUG_PRINT("enter", ("eol: %s", eol)); - const char *p= eol; /* Remove all spacing chars except new line */ while (*p && my_isspace(charset_info, *p) && (*p != '\n')) p++; @@ -2170,7 +2176,10 @@ int read_line(char *buf, int size) { found_eof: if (cur_file->file != stdin) + { my_fclose(cur_file->file, MYF(0)); + cur_file->file= 0; + } my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); cur_file->file_name= 0; lineno--; @@ -2556,10 +2565,11 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), argument= buff; } fn_format(buff, argument, "", "", 4); - DBUG_ASSERT(cur_file->file == 0); + DBUG_ASSERT(cur_file == file_stack && cur_file->file == 0); if (!(cur_file->file= my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME)))) - die("Could not open %s: errno = %d", argument, errno); + die("Could not open %s: errno = %d", buff, errno); + cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); break; } case 'm': @@ -2904,22 +2914,9 @@ static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) } - if (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0) - { - /* Error code we wanted was != 0, i.e. not an expected success */ - verbose_msg("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0].code.errnum); - error = 1; - goto end; - } - else if (q->expected_errno[0].type == ERR_SQLSTATE && - strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0) + if (handle_no_error(q)) { - /* SQLSTATE we wanted was != "00000", i.e. not an expected success */ - verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...", - q->query, q->expected_errno[0].code.sqlstate); - error = 1; + error= 1; goto end; } @@ -3099,10 +3096,8 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) { if (q->abort_on_error) { - die("unable to prepare statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - query, - mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); + die("query '%s' failed: %d: %s", query, + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); } else { @@ -3183,12 +3178,8 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) } /* If we got here the statement was both executed and read succeesfully */ - - if (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0) + if (handle_no_error(q)) { - verbose_msg("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0].code.errnum); error= 1; goto end; } @@ -3515,8 +3506,14 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q, dynstr_append_mem(ds,"\n",1); if (i) { - verbose_msg("query '%s' failed with wrong errno %d instead of %d...", - q->query, mysql_stmt_errno(stmt), q->expected_errno[0]); + if (q->expected_errno[0].type == ERR_ERRNO) + verbose_msg("query '%s' failed with wrong errno %d instead of %d...", + q->query, mysql_stmt_errno(stmt), + q->expected_errno[0].code.errnum); + else + verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...", + q->query, mysql_stmt_sqlstate(stmt), + q->expected_errno[0].code.sqlstate); return 1; /* Error */ } verbose_msg("query '%s' failed: %d: %s", q->query, mysql_stmt_errno(stmt), @@ -3531,6 +3528,43 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q, return 0; } + +/* + Handle absence of errors after execution + + SYNOPSIS + handle_no_error() + q - context of query + + RETURN VALUE + 0 - OK + 1 - Some error was expected from this query. +*/ + +static int handle_no_error(struct st_query *q) +{ + DBUG_ENTER("handle_no_error"); + + if (q->expected_errno[0].type == ERR_ERRNO && + q->expected_errno[0].code.errnum != 0) + { + /* Error code we wanted was != 0, i.e. not an expected success */ + verbose_msg("query '%s' succeeded - should have failed with errno %d...", + q->query, q->expected_errno[0].code.errnum); + DBUG_RETURN(1); + } + else if (q->expected_errno[0].type == ERR_SQLSTATE && + strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0) + { + /* SQLSTATE we wanted was != "00000", i.e. not an expected success */ + verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...", + q->query, q->expected_errno[0].code.sqlstate); + DBUG_RETURN(1); + } + + DBUG_RETURN(0); +} + /****************************************************************************\ * Functions to match SQL statements that can be prepared \****************************************************************************/ @@ -3709,8 +3743,9 @@ int main(int argc, char **argv) { int error = 0; struct st_query *q; - my_bool require_file=0, q_send_flag=0; + my_bool require_file=0, q_send_flag=0, query_executed= 0; char save_file[FN_REFLEN]; + MY_STAT res_info; MY_INIT(argv[0]); { DBUG_ENTER("main"); @@ -3746,9 +3781,8 @@ int main(int argc, char **argv) embedded_server_args, (char**) embedded_server_groups)) die("Can't initialize MySQL server"); - if (cur_file == file_stack) + if (cur_file == file_stack && cur_file->file == 0) { - DBUG_ASSERT(cur_file->file == 0); cur_file->file= stdin; cur_file->file_name= my_strdup("<stdin>", MYF(MY_WME)); } @@ -3904,6 +3938,7 @@ int main(int argc, char **argv) save_file[0]=0; } error |= run_query(&cur_con->mysql, q, flags); + query_executed= 1; q->last_argument= q->end; break; } @@ -3924,6 +3959,7 @@ int main(int argc, char **argv) is given on this connection. */ error |= run_query(&cur_con->mysql, q, QUERY_SEND); + query_executed= 1; q->last_argument= q->end; break; case Q_RESULT: @@ -3964,6 +4000,7 @@ int main(int argc, char **argv) break; case Q_EXEC: do_exec(q); + query_executed= 1; break; case Q_START_TIMER: /* Overwrite possible earlier start of timer */ @@ -4020,6 +4057,18 @@ int main(int argc, char **argv) parser.current_line += current_line_inc; } + if (!query_executed && result_file && my_stat(result_file, &res_info, 0)) + { + /* + my_stat() successful on result file. Check if we have not run a + single query, but we do have a result file that contains data. + Note that we don't care, if my_stat() fails. For example for + non-existing or non-readable file we assume it's fine to have + no query output from the test file, e.g. regarded as no error. + */ + if (res_info.st_size) + error|= (RESULT_CONTENT_MISMATCH | RESULT_LENGTH_MISMATCH); + } if (result_file && ds_res.length && !error) { if (!record) diff --git a/configure.in b/configure.in index f3840e6f1a8..97eb0cb0edf 100644 --- a/configure.in +++ b/configure.in @@ -381,19 +381,19 @@ case "$target_os" in ;; esac ;; - sysv5UnixWare*) + sysv5UnixWare* | sysv5OpenUNIX8*) if test "$GCC" != "yes"; then - # We are using built-in inline function + # Use the built-in alloca() CFLAGS="$CFLAGS -Kalloca" fi CXXFLAGS="$CXXFLAGS -DNO_CPLUSPLUS_ALLOCA" ;; - sysv5OpenUNIX8*) + sysv5SCO_SV6.0.0*) if test "$GCC" != "yes"; then - # We are using built-in inline function + # Use the built-in alloca() CFLAGS="$CFLAGS -Kalloca" + CXXFLAGS="$CFLAGS -Kalloca" fi - CXXFLAGS="$CXXFLAGS -DNO_CPLUSPLUS_ALLOCA" ;; esac AC_SUBST(CC) @@ -1128,6 +1128,15 @@ case $SYSTEM_TYPE in MAX_C_OPTIMIZE="-O" fi ;; + *darwin9*) + if test "$ac_cv_prog_gcc" = "yes" + then + FLAGS="-D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT" + CFLAGS="$CFLAGS $FLAGS" + CXXFLAGS="$CXXFLAGS $FLAGS" + MAX_C_OPTIMIZE="-O" + fi + ;; *freebsd*) echo "Adding fix for interrupted reads" OSVERSION=`sysctl -a | grep osreldate | awk '{ print $2 }'` @@ -1440,8 +1449,6 @@ then if expr "$SYSTEM_TYPE" : ".*unixware7.0.0" > /dev/null then AC_DEFINE(HAVE_UNIXWARE7_THREADS, [1]) - else - AC_DEFINE(HAVE_UNIXWARE7_POSIX, [1]) fi AC_MSG_RESULT("yes") # We must have cc @@ -1467,87 +1474,41 @@ then AC_MSG_RESULT("no") fi fi -# Hack for SCO UnixWare7 + +# +# Check for SCO threading libraries # if test "$with_named_thread" = "no" then - AC_MSG_CHECKING("SCO UnixWare7 native threads") - if expr "$SYSTEM_TYPE" : ".*UnixWare*" > /dev/null + AC_MSG_CHECKING([SCO OpenServer 6, UnixWare 7 or OpenUNIX 8 native threads]) + if expr "$SYSTEM_TYPE" : ".*UnixWare.*" > /dev/null || \ + expr "$SYSTEM_TYPE" : ".*SCO_SV6.*" > /dev/null || \ + expr "$SYSTEM_TYPE" : ".*OpenUNIX.*" > /dev/null then if test -f /usr/lib/libthread.so -o -f /usr/lib/libthreadT.so then MYSQL_REMOVE_SOCKET_FROM_LIBS_HACK - if expr "$CC" : ".*gcc.*" - then - with_named_thread="-pthread -lsocket -lnsl" - else - with_named_thread="-Kthread -lsocket -lnsl" - fi - if expr "$SYSTEM_TYPE" : ".*unixware7.0.0" > /dev/null - then - AC_DEFINE(HAVE_UNIXWARE7_THREADS, [1]) - else - AC_DEFINE(HAVE_UNIXWARE7_POSIX, [1]) - fi - # We must have cc - AC_MSG_CHECKING("for gcc") - if expr "$CC" : ".*gcc.*" + if expr "$CC" : ".*gcc.*" > /dev/null then + with_named_thread="-pthread -lsocket -lnsl" CC="$CC -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; CXX="$CXX -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; else + with_named_thread="-Kthread -lsocket -lnsl" CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; fi - AC_MSG_RESULT("yes") - else - { echo "configure: error: Can't find thread libs on SCO UnixWare7. See the Installation chapter in the Reference Manual." 1>&2; exit 1; }; - fi - else - AC_MSG_RESULT("no") - fi -fi - -# Hack for Caldera OpenUNIX8 -# -if test "$with_named_thread" = "no" -then - AC_MSG_CHECKING("OpenUNIX8 native threads") - if expr "$SYSTEM_TYPE" : ".*OpenUNIX*" > /dev/null - then - if test -f /usr/lib/libthread.so -o -f /usr/lib/libthreadT.so - then - MYSQL_REMOVE_SOCKET_FROM_LIBS_HACK - if expr "$CC" : ".*gcc.*" - then - with_named_thread="-pthread -lsocket -lnsl" - else - with_named_thread="-Kthread -lsocket -lnsl" - fi if expr "$SYSTEM_TYPE" : ".*unixware7.0.0" > /dev/null then - AC_DEFINE([HAVE_UNIXWARE7_THREADS], [1], - [UNIXWARE7 threads are not posix]) - else - AC_DEFINE([HAVE_UNIXWARE7_POSIX], [1], - [new UNIXWARE7 threads that are not yet posix]) - fi - # We must have cc - AC_MSG_CHECKING("for gcc") - if expr "$CC" : ".*gcc.*" - then - CC="$CC -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; - CXX="$CXX -pthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; - else - CC="$CC -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; - CXX="$CXX -Kthread -DUNIXWARE_7 -DHAVE_BROKEN_RWLOCK"; + AC_DEFINE(HAVE_UNIXWARE7_THREADS, [1], [Have UnixWare 7 (or similar) almost-POSIX threading library]) fi - AC_MSG_RESULT("yes") + AC_MSG_RESULT(yes) else - { echo "configure: error: Can't find thread libs on Caldera OpenUNIX 8. See the Installation chapter in the Reference Manual." 1>&2; exit 1; }; + AC_MSG_RESULT(failed) + { echo "configure: error: Can't find thread libs on SCO UnixWare7. See the Installation chapter in the Reference Manual." 1>&2; exit 1; }; fi else - AC_MSG_RESULT("no") + AC_MSG_RESULT(no) fi fi @@ -3016,7 +2977,7 @@ then AC_CONFIG_FILES(bdb/Makefile) echo "CONFIGURING FOR BERKELEY DB" - bdb_conf_flags="--disable-shared" + bdb_conf_flags="--disable-shared --build=$build_alias" if test $with_debug = "yes" then bdb_conf_flags="$bdb_conf_flags --enable-debug --enable-diagnostic" diff --git a/include/keycache.h b/include/keycache.h index a292a69b0a3..9fe1cce5da5 100644 --- a/include/keycache.h +++ b/include/keycache.h @@ -90,10 +90,10 @@ typedef struct st_key_cache /* Statistics variables. These are reset in reset_key_cache_counters(). */ ulong global_blocks_changed; /* number of currently dirty blocks */ - ulong global_cache_w_requests;/* number of write requests (write hits) */ - ulong global_cache_write; /* number of writes from the cache to files */ - ulong global_cache_r_requests;/* number of read requests (read hits) */ - ulong global_cache_read; /* number of reads from files to the cache */ + ulonglong global_cache_w_requests;/* number of write requests (write hits) */ + ulonglong global_cache_write; /* number of writes from cache to files */ + ulonglong global_cache_r_requests;/* number of read requests (read hits) */ + ulonglong global_cache_read; /* number of reads from files to cache */ int blocks; /* max number of blocks in the cache */ my_bool in_init; /* Set to 1 in MySQL during init/resize */ diff --git a/include/my_global.h b/include/my_global.h index f3d42106458..0f99aacd079 100644 --- a/include/my_global.h +++ b/include/my_global.h @@ -801,6 +801,7 @@ typedef off_t os_off_t; #define socket_errno WSAGetLastError() #define SOCKET_EINTR WSAEINTR #define SOCKET_EAGAIN WSAEINPROGRESS +#define SOCKET_ETIMEDOUT WSAETIMEDOUT #define SOCKET_EWOULDBLOCK WSAEWOULDBLOCK #define SOCKET_ENFILE ENFILE #define SOCKET_EMFILE EMFILE @@ -808,6 +809,7 @@ typedef off_t os_off_t; #define socket_errno sock_errno() #define SOCKET_EINTR SOCEINTR #define SOCKET_EAGAIN SOCEINPROGRESS +#define SOCKET_ETIMEDOUT SOCKET_EINTR #define SOCKET_EWOULDBLOCK SOCEWOULDBLOCK #define SOCKET_ENFILE SOCENFILE #define SOCKET_EMFILE SOCEMFILE @@ -817,6 +819,7 @@ typedef off_t os_off_t; #define closesocket(A) close(A) #define SOCKET_EINTR EINTR #define SOCKET_EAGAIN EAGAIN +#define SOCKET_ETIMEDOUT SOCKET_EINTR #define SOCKET_EWOULDBLOCK EWOULDBLOCK #define SOCKET_ENFILE ENFILE #define SOCKET_EMFILE EMFILE diff --git a/include/my_pthread.h b/include/my_pthread.h index fde62655c5f..d83ddf62a80 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -298,11 +298,6 @@ extern int my_pthread_create_detached; int sigwait(sigset_t *set, int *sig); #endif -#if defined(HAVE_UNIXWARE7_POSIX) -#undef HAVE_NONPOSIX_SIGWAIT -#define HAVE_NONPOSIX_SIGWAIT /* sigwait takes only 1 argument */ -#endif - #ifndef HAVE_NONPOSIX_SIGWAIT #define my_sigwait(A,B) sigwait((A),(B)) #else diff --git a/include/my_sys.h b/include/my_sys.h index ab0efe247ef..02ea188a18e 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -216,9 +216,6 @@ extern CHARSET_INFO *all_charsets[256]; extern CHARSET_INFO compiled_charsets[]; /* statistics */ -extern ulong my_cache_w_requests, my_cache_write, my_cache_r_requests, - my_cache_read; -extern ulong my_blocks_used, my_blocks_changed; extern ulong my_file_opened,my_stream_opened, my_tmp_file_created; extern uint mysys_usage_id; extern my_bool my_init_done; diff --git a/include/violite.h b/include/violite.h index 4b644051dd2..fbc6a546cc5 100644 --- a/include/violite.h +++ b/include/violite.h @@ -68,6 +68,8 @@ int vio_fastsend(Vio *vio); int vio_keepalive(Vio *vio, my_bool onoff); /* Whenever we should retry the last read/write operation. */ my_bool vio_should_retry(Vio *vio); +/* Check that operation was timed out */ +my_bool vio_was_interrupted(Vio *vio); /* Short text description of the socket for those, who are curious.. */ const char* vio_description(Vio *vio); /* Return the type of the connection */ @@ -146,6 +148,7 @@ int vio_close_shared_memory(Vio * vio); #define vio_fastsend(vio) (vio)->fastsend(vio) #define vio_keepalive(vio, set_keep_alive) (vio)->viokeepalive(vio, set_keep_alive) #define vio_should_retry(vio) (vio)->should_retry(vio) +#define vio_was_interrupted(vio) (vio)->was_interrupted(vio) #define vio_close(vio) ((vio)->vioclose)(vio) #define vio_peer_addr(vio, buf, prt) (vio)->peer_addr(vio, buf, prt) #define vio_in_addr(vio, in) (vio)->in_addr(vio, in) @@ -188,6 +191,7 @@ struct st_vio my_bool (*peer_addr)(Vio*, char *, uint16*); void (*in_addr)(Vio*, struct in_addr*); my_bool (*should_retry)(Vio*); + my_bool (*was_interrupted)(Vio*); int (*vioclose)(Vio*); void (*timeout)(Vio*, unsigned int which, unsigned int timeout); void *ssl_arg; diff --git a/man/which.2 b/man/which.2 deleted file mode 100644 index 30d5557ed01..00000000000 --- a/man/which.2 +++ /dev/null @@ -1,54 +0,0 @@ -.TH WHICH 1 "20 December 2000" -.SH NAME -which - Jani please supply one. -.SH USAGE -which [options] [--] programname [...] -.SH SYNOPSIS -.B which -.RB [ \-\-version | \-[vV] ] -.RB [ \-\-skip\-dot ] -.RB [ \-\-skip\-tilde ] -.RB [ \-\-show\-dot ] -.RB [ \-\-show\-tilde ] -.RB [ \-\-tty\-only ] -.RB [ \-\-all | \-a ] -.RB [ \-\-read\-alias | \-i ] -.RB [ \-\-skip\-alias ] -.SH DESCRIPTION -.TP -.BR which -supports by executing -.TP -.BR \-\-version | \-[vV] -Print version and exit successfully. -.TP -.BR \-\-skip\-dot -Skip directories in PATH that start with a dot. -.TP -.BR \-\-skip\-tilde -Skip directories in PATH that start with a tilde. -.TP -.BR \-\-show\-dot -Don\'t expand a dot to current directory in output. -.TP -.BR \-\-show\-tilde -Output a tilde for HOME directory for non-root. -.TP -.BR \-\-tty\-only -Stop processing options on the right if not on tty. -.TP -.BR \-\-all | \-a -Print all matches in PATH, not just the first -.TP -.BR \-\-read\-alias | \-i -Read list of aliases from stdin. -.TP -.BR \-\-skip\-alias -Ignore option -.BR --read-alias; -don\'t read stdin. -.SH "SEE ALSO" -isamchk (1), isamlog (1), mysqlaccess (1), mysqladmin (1), mysqlbug (1), mysqld (1), mysqldump (1), mysqlshow (1), msql2mysql (1), perror (1), replace (1), mysqld_safe (1), which1 (1), zap (1), -.SH AUTHOR -Ver 1.0, distribution 3.23.29a Michael (Monty) Widenius (monty@tcx.se), TCX Datakonsult AB (http://www.tcx.se). This software comes with no warranty. Manual page by L. (Kill-9) Pedersen (kill-9@kill-9.dk), Mercurmedia Data Model Architect / system developer (http://www.mercurmedia.com) -.\" end of man page
\ No newline at end of file diff --git a/myisam/mi_check.c b/myisam/mi_check.c index 246d2c58dde..038ce8d953f 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -3193,9 +3193,11 @@ int sort_write_record(MI_SORT_PARAM *sort_param) break; case COMPRESSED_RECORD: reclength=info->packed_length; - length=save_pack_length(block_buff,reclength); + length= save_pack_length((uint) share->pack.version, block_buff, + reclength); if (info->s->base.blobs) - length+=save_pack_length(block_buff+length,info->blob_length); + length+= save_pack_length((uint) share->pack.version, + block_buff + length, info->blob_length); if (my_b_write(&info->rec_cache,block_buff,length) || my_b_write(&info->rec_cache,(byte*) sort_param->rec_buff,reclength)) { diff --git a/myisam/mi_packrec.c b/myisam/mi_packrec.c index 1a71d43a7f1..322420b71db 100644 --- a/myisam/mi_packrec.c +++ b/myisam/mi_packrec.c @@ -149,11 +149,12 @@ my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys) my_errno=HA_ERR_END_OF_FILE; goto err0; } - if (memcmp((byte*) header,(byte*) myisam_pack_file_magic,4)) + if (memcmp((byte*) header, (byte*) myisam_pack_file_magic, 3)) { my_errno=HA_ERR_WRONG_IN_RECORD; goto err0; } + share->pack.version= header[3]; share->pack.header_length= uint4korr(header+4); share->min_pack_length=(uint) uint4korr(header+8); share->max_pack_length=(uint) uint4korr(header+12); @@ -1040,38 +1041,12 @@ uint _mi_pack_get_block_info(MI_INFO *myisam, MI_BLOCK_INFO *info, File file, return BLOCK_FATAL_ERROR; DBUG_DUMP("header",(byte*) header,ref_length); } - if (header[0] < 254) - { - info->rec_len=header[0]; - head_length=1; - } - else if (header[0] == 254) - { - info->rec_len=uint2korr(header+1); - head_length=3; - } - else - { - info->rec_len=uint3korr(header+1); - head_length=4; - } + head_length= read_pack_length((uint) myisam->s->pack.version, header, + &info->rec_len); if (myisam->s->base.blobs) { - if (header[head_length] < 254) - { - info->blob_len=header[head_length]; - head_length++; - } - else if (header[head_length] == 254) - { - info->blob_len=uint2korr(header+head_length+1); - head_length+=3; - } - else - { - info->blob_len=uint3korr(header+head_length+1); - head_length+=4; - } + head_length+= read_pack_length((uint) myisam->s->pack.version, + header + head_length, &info->blob_len); if (!(mi_alloc_rec_buff(myisam,info->rec_len + info->blob_len, &myisam->rec_buff))) return BLOCK_FATAL_ERROR; /* not enough memory */ @@ -1220,34 +1195,12 @@ void _mi_unmap_file(MI_INFO *info) static uchar *_mi_mempack_get_block_info(MI_INFO *myisam,MI_BLOCK_INFO *info, uchar *header) { - if (header[0] < 254) - info->rec_len= *header++; - else if (header[0] == 254) - { - info->rec_len=uint2korr(header+1); - header+=3; - } - else - { - info->rec_len=uint3korr(header+1); - header+=4; - } + header+= read_pack_length((uint) myisam->s->pack.version, header, + &info->rec_len); if (myisam->s->base.blobs) { - if (header[0] < 254) - { - info->blob_len= *header++; - } - else if (header[0] == 254) - { - info->blob_len=uint2korr(header+1); - header+=3; - } - else - { - info->blob_len=uint3korr(header+1); - header+=4; - } + header+= read_pack_length((uint) myisam->s->pack.version, header, + &info->blob_len); /* mi_alloc_rec_buff sets my_errno on error */ if (!(mi_alloc_rec_buff(myisam, info->blob_len, &myisam->rec_buff))) @@ -1319,7 +1272,7 @@ static int _mi_read_rnd_mempack_record(MI_INFO *info, byte *buf, /* Save length of row */ -uint save_pack_length(byte *block_buff,ulong length) +uint save_pack_length(uint version, byte *block_buff, ulong length) { if (length < 254) { @@ -1333,6 +1286,46 @@ uint save_pack_length(byte *block_buff,ulong length) return 3; } *(uchar*) block_buff=255; - int3store(block_buff+1,(ulong) length); - return 4; + if (version == 1) /* old format */ + { + DBUG_ASSERT(length <= 0xFFFFFF); + int3store(block_buff + 1, (ulong) length); + return 4; + } + else + { + int4store(block_buff + 1, (ulong) length); + return 5; + } +} + + +uint read_pack_length(uint version, const uchar *buf, ulong *length) +{ + if (buf[0] < 254) + { + *length= buf[0]; + return 1; + } + else if (buf[0] == 254) + { + *length= uint2korr(buf + 1); + return 3; + } + if (version == 1) /* old format */ + { + *length= uint3korr(buf + 1); + return 4; + } + else + { + *length= uint4korr(buf + 1); + return 5; + } +} + + +uint calc_pack_length(uint version, ulong length) +{ + return (length < 254) ? 1 : (length < 65536) ? 3 : (version == 1) ? 4 : 5; } diff --git a/myisam/mi_static.c b/myisam/mi_static.c index f41aeff8453..9725c120f44 100644 --- a/myisam/mi_static.c +++ b/myisam/mi_static.c @@ -27,7 +27,7 @@ LIST *myisam_open_list=0; uchar NEAR myisam_file_magic[]= { (uchar) 254, (uchar) 254,'\007', '\001', }; uchar NEAR myisam_pack_file_magic[]= -{ (uchar) 254, (uchar) 254,'\010', '\001', }; +{ (uchar) 254, (uchar) 254,'\010', '\002', }; my_string myisam_log_filename=(char*) "myisam.log"; File myisam_log_file= -1; uint myisam_quick_table_bits=9; diff --git a/myisam/mi_test2.c b/myisam/mi_test2.c index 95c8ce56a13..6a6dcb971a2 100644 --- a/myisam/mi_test2.c +++ b/myisam/mi_test2.c @@ -831,17 +831,19 @@ end: puts("Locking used"); if (use_blob) puts("blobs used"); -#if 0 printf("key cache status: \n\ blocks used:%10lu\n\ +not flushed:%10lu\n\ w_requests: %10lu\n\ writes: %10lu\n\ r_requests: %10lu\n\ reads: %10lu\n", - my_blocks_used, - my_cache_w_requests, my_cache_write, - my_cache_r_requests, my_cache_read); -#endif + dflt_key_cache->blocks_used, + dflt_key_cache->global_blocks_changed, + (ulong) dflt_key_cache->global_cache_w_requests, + (ulong) dflt_key_cache->global_cache_write, + (ulong) dflt_key_cache->global_cache_r_requests, + (ulong) dflt_key_cache->global_cache_read); } end_key_cache(dflt_key_cache,1); if (blob_buffer) diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index a41bcf5449b..15b310e907e 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -149,6 +149,7 @@ typedef struct st_mi_blob /* Info of record */ typedef struct st_mi_isam_pack { ulong header_length; uint ref_length; + uchar version; } MI_PACK; @@ -669,7 +670,9 @@ extern void _myisam_log_record(enum myisam_log_commands command,MI_INFO *info, int result); extern my_bool _mi_memmap_file(MI_INFO *info); extern void _mi_unmap_file(MI_INFO *info); -extern uint save_pack_length(byte *block_buff,ulong length); +extern uint save_pack_length(uint version, byte *block_buff, ulong length); +extern uint read_pack_length(uint version, const uchar *buf, ulong *length); +extern uint calc_pack_length(uint version, ulong length); uint mi_state_info_write(File file, MI_STATE_INFO *state, uint pWrite); char *mi_state_info_read(char *ptr, MI_STATE_INFO *state); diff --git a/myisam/myisampack.c b/myisam/myisampack.c index c5db66ef209..f017e4d23ab 100644 --- a/myisam/myisampack.c +++ b/myisam/myisampack.c @@ -1675,6 +1675,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) HUFF_COUNTS *count,*end_count; HUFF_TREE *tree; MI_INFO *isam_file=mrg->file[0]; + uint pack_version= (uint) isam_file->s->pack.version; DBUG_ENTER("compress_isam_file"); if (!(record=(byte*) my_alloca(isam_file->s->base.reclength))) @@ -1702,23 +1703,10 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) huff_counts[i].tree->height+huff_counts[i].length_bits; } max_calc_length/=8; - if (max_calc_length < 254) - pack_ref_length=1; - else if (max_calc_length <= 65535) - pack_ref_length=3; - else - pack_ref_length=4; + pack_ref_length= calc_pack_length(pack_version, max_calc_length); record_count=0; - pack_blob_length=0; - if (isam_file->s->base.blobs) - { - if (mrg->max_blob_length < 254) - pack_blob_length=1; - else if (mrg->max_blob_length <= 65535) - pack_blob_length=3; - else - pack_blob_length=4; - } + pack_blob_length= isam_file->s->base.blobs ? + calc_pack_length(pack_version, mrg->max_blob_length) : 0; max_pack_length=pack_ref_length+pack_blob_length; mrg_reset(mrg); @@ -1874,9 +1862,10 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts) } flush_bits(); length=(ulong) (file_buffer.pos-record_pos)-max_pack_length; - pack_length=save_pack_length(record_pos,length); + pack_length= save_pack_length(pack_version, record_pos, length); if (pack_blob_length) - pack_length+=save_pack_length(record_pos+pack_length,tot_blob_length); + pack_length+= save_pack_length(pack_version, record_pos + pack_length, + tot_blob_length); /* Correct file buffer if the header was smaller */ if (pack_length != max_pack_length) diff --git a/mysql-test/include/mysqltest-x.inc b/mysql-test/include/mysqltest-x.inc new file mode 100644 index 00000000000..dd1468aed07 --- /dev/null +++ b/mysql-test/include/mysqltest-x.inc @@ -0,0 +1,2 @@ +echo Output from mysqltest-x.inc; + diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index bae66353825..9176a246835 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -166,7 +166,7 @@ sub spawn_impl ($$$$$$$$) { { if ( ! open(STDOUT,$log_file_open_mode,$output) ) { - mtr_error("can't redirect STDOUT to \"$output\": $!"); + mtr_child_error("can't redirect STDOUT to \"$output\": $!"); } } @@ -176,14 +176,14 @@ sub spawn_impl ($$$$$$$$) { { if ( ! open(STDERR,">&STDOUT") ) { - mtr_error("can't dup STDOUT: $!"); + mtr_child_error("can't dup STDOUT: $!"); } } else { if ( ! open(STDERR,$log_file_open_mode,$error) ) { - mtr_error("can't redirect STDERR to \"$error\": $!"); + mtr_child_error("can't redirect STDERR to \"$error\": $!"); } } } @@ -192,13 +192,13 @@ sub spawn_impl ($$$$$$$$) { { if ( ! open(STDIN,"<",$input) ) { - mtr_error("can't redirect STDIN to \"$input\": $!"); + mtr_child_error("can't redirect STDIN to \"$input\": $!"); } } if ( ! exec($path,@$arg_list_t) ) { - mtr_error("failed to execute \"$path\": $!"); + mtr_child_error("failed to execute \"$path\": $!"); } } } diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index 868653afaa4..9002f204602 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -19,6 +19,7 @@ sub mtr_print_header (); sub mtr_report (@); sub mtr_warning (@); sub mtr_error (@); +sub mtr_child_error (@); sub mtr_debug (@); @@ -74,7 +75,7 @@ sub mtr_show_failed_diff ($) { sub mtr_report_test_name ($) { my $tinfo= shift; - printf "%-31s ", $tinfo->{'name'}; + printf "%-30s ", $tinfo->{'name'}; } sub mtr_report_test_skipped ($) { @@ -122,13 +123,13 @@ sub mtr_report_test_failed ($) { # we should write out into $::path_timefile when the error occurs. if ( -f $::path_timefile ) { - print "Errors are (from $::path_timefile) :\n"; + print "\nErrors are (from $::path_timefile) :\n"; print mtr_fromfile($::path_timefile); # FIXME print_file() instead print "\n(the last lines may be the most important ones)\n"; } else { - print "Unexpected termination, probably when starting mysqld\n"; + print "\nUnexpected termination, probably when starting mysqld\n"; } } @@ -286,6 +287,11 @@ sub mtr_error (@) { mtr_exit(1); } +sub mtr_child_error (@) { + print STDERR "mysql-test-run: *** ERROR(child): ",join(" ", @_),"\n"; + exit(1); +} + sub mtr_debug (@) { if ( $::opt_script_debug ) { diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 013b8d49967..cd182e8fc73 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -237,8 +237,10 @@ our $opt_ps_protocol; our $opt_sleep_time_after_restart= 1; our $opt_sleep_time_for_delete= 10; -our $opt_testcase_timeout= 5; # 5 min max -our $opt_suite_timeout= 120; # 2 hours max +our $opt_testcase_timeout; +our $opt_suite_timeout; +my $default_testcase_timeout= 10; # 10 min max +my $default_suite_timeout= 120; # 2 hours max our $opt_socket; @@ -256,6 +258,7 @@ our $opt_user; our $opt_user_test; our $opt_valgrind; +our $opt_valgrind_mysqltest; our $opt_valgrind_all; our $opt_valgrind_options; @@ -509,8 +512,9 @@ sub command_line_setup () { # Coverage, profiling etc 'gcov' => \$opt_gcov, 'gprof' => \$opt_gprof, - 'valgrind' => \$opt_valgrind, - 'valgrind-all' => \$opt_valgrind_all, + 'valgrind:s' => \$opt_valgrind, + 'valgrind-mysqltest:s' => \$opt_valgrind_mysqltest, + 'valgrind-all:s' => \$opt_valgrind_all, 'valgrind-options=s' => \$opt_valgrind_options, # Misc @@ -688,29 +692,42 @@ sub command_line_setup () { $opt_with_ndbcluster= 0; } - # FIXME + # The ":s" in the argument spec, means we have three different cases + # + # undefined option not set + # "" option set with no argument + # "somestring" option is name/path of valgrind executable + + # Take executable path from any of them, if any + $opt_valgrind= $opt_valgrind_mysqltest if $opt_valgrind_mysqltest; + $opt_valgrind= $opt_valgrind_all if $opt_valgrind_all; + + # If valgrind flag not defined, define if other valgrind flags are + unless ( defined $opt_valgrind ) + { + $opt_valgrind= "" + if defined $opt_valgrind_mysqltest or defined $opt_valgrind_all; + } - #if ( $opt_valgrind or $opt_valgrind_all ) - #{ - # VALGRIND=`which valgrind` # this will print an error if not found FIXME - # Give good warning to the user and stop - # if ( ! $VALGRIND ) - # { - # print "You need to have the 'valgrind' program in your PATH to run mysql-test-run with option --valgrind. Valgrind's home page is http://valgrind.kde.org.\n" - # exit 1 - # } + if ( ! $opt_testcase_timeout ) + { + $opt_testcase_timeout= $default_testcase_timeout; + $opt_testcase_timeout*= 10 if defined $opt_valgrind; + } + + if ( ! $opt_suite_timeout ) + { + $opt_suite_timeout= $default_suite_timeout; + $opt_suite_timeout*= 4 if defined $opt_valgrind; + } + + if ( defined $opt_valgrind ) + { + $opt_sleep_time_after_restart= 10; + $opt_sleep_time_for_delete= 60; # >=2.1.2 requires the --tool option, some versions write to stdout, some to stderr - # valgrind --help 2>&1 | grep "\-\-tool" > /dev/null && VALGRIND="$VALGRIND --tool=memcheck" - # VALGRIND="$VALGRIND --alignment=8 --leak-check=yes --num-callers=16" - # $opt_extra_mysqld_opt.= " --skip-safemalloc --skip-bdb"; - # SLEEP_TIME_AFTER_RESTART=10 - # $opt_sleep_time_for_delete= 60 - # $glob_use_running_server= "" - # if ( "$1"= "--valgrind-all" ) - # { - # VALGRIND="$VALGRIND -v --show-reachable=yes" - # } - #} + # valgrind --help 2>&1 | grep "\-\-tool" > /dev/null && VALGRIND="$VALGRIND --tool=memcheck" + } if ( ! $opt_user ) { @@ -1703,7 +1720,7 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--language=%s", $prefix, $path_language); mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix); - if ( $opt_valgrind ) + if ( defined $opt_valgrind ) { mtr_add_arg($args, "%s--skip-safemalloc", $prefix); mtr_add_arg($args, "%s--skip-bdb", $prefix); @@ -1928,29 +1945,9 @@ sub mysqld_start ($$$$) { mtr_init_args(\$args); - if ( $opt_valgrind ) + if ( defined $opt_valgrind ) { - - mtr_add_arg($args, "--tool=memcheck"); - mtr_add_arg($args, "--alignment=8"); - mtr_add_arg($args, "--leak-check=yes"); - mtr_add_arg($args, "--num-callers=16"); - - if ( $opt_valgrind_all ) - { - mtr_add_arg($args, "-v"); - mtr_add_arg($args, "--show-reachable=yes"); - } - - if ( $opt_valgrind_options ) - { - # FIXME split earlier and put into @glob_valgrind_* - mtr_add_arg($args, split(' ', $opt_valgrind_options)); - } - - mtr_add_arg($args, $exe); - - $exe= $opt_valgrind; + valgrind_arguments($args, \$exe); } mysqld_arguments($args,$type,$idx,$extra_opt,$slave_master_info); @@ -2121,6 +2118,11 @@ sub run_mysqltest ($) { mtr_init_args(\$args); + if ( defined $opt_valgrind_mysqltest ) + { + valgrind_arguments($args, \$exe); + } + mtr_add_arg($args, "--no-defaults"); mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_mysock'}); mtr_add_arg($args, "--database=test"); @@ -2205,6 +2207,36 @@ sub run_mysqltest ($) { return mtr_run_test($exe,$args,$tinfo->{'path'},"",$path_timefile,""); } + +sub valgrind_arguments { + my $args= shift; + my $exe= shift; + + mtr_add_arg($args, "--tool=memcheck"); # From >= 2.1.2 needs this option + mtr_add_arg($args, "--alignment=8"); + mtr_add_arg($args, "--leak-check=yes"); + mtr_add_arg($args, "--num-callers=16"); + mtr_add_arg($args, "--suppressions=%s/valgrind.supp", $glob_mysql_test_dir) + if -f "$glob_mysql_test_dir/valgrind.supp"; + + if ( defined $opt_valgrind_all ) + { + mtr_add_arg($args, "-v"); + mtr_add_arg($args, "--show-reachable=yes"); + } + + if ( $opt_valgrind_options ) + { + # FIXME split earlier and put into @glob_valgrind_* + mtr_add_arg($args, split(' ', $opt_valgrind_options)); + } + + mtr_add_arg($args, $$exe); + + $$exe= $opt_valgrind || "valgrind"; +} + + ############################################################################## # # Usage @@ -2271,8 +2303,11 @@ Options for coverage, profiling etc gcov FIXME gprof FIXME - valgrind FIXME - valgrind-all FIXME + valgrind[=EXE] Run the "mysqltest" executable as well as the "mysqld" + server using valgrind, optionally specifying the + executable path/name + valgrind-mysqltest[=EXE] In addition, run the "mysqltest" executable with valgrind + valgrind-all[=EXE] Adds verbose flag, and --show-reachable to valgrind valgrind-options=ARGS Extra options to give valgrind Misc options diff --git a/mysql-test/r/analyse.result b/mysql-test/r/analyse.result index 09c606b5a04..0ebd4a3e409 100644 --- a/mysql-test/r/analyse.result +++ b/mysql-test/r/analyse.result @@ -102,3 +102,9 @@ select * from t1 procedure analyse(); Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype test.t1.v " \\ 1 19 0 0 3.7619 NULL ENUM('"','""','"c','\'\0\\"','\'','\'\'','\'b','a\0\0\0b','a\0','a""""b','a\'\'\'\'b','abc','abc\'def\\hij"klm\0opq','a\\\\\\\\b','b\'','c"','d\\','The\ZEnd','\\','\\d','\\\\') NOT NULL drop table t1; +create table t1 (d double); +insert into t1 values (100000); +select * from t1 procedure analyse (1,1); +Field_name Min_value Max_value Min_length Max_length Empties_or_zeros Nulls Avg_value_or_avg_length Std Optimal_fieldtype +test.t1.d 100000 100000 6 6 0 0 100000 0 MEDIUMINT(6) UNSIGNED NOT NULL +drop table t1; diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result index edf30e7f6e4..68c86b80e60 100644 --- a/mysql-test/r/connect.result +++ b/mysql-test/r/connect.result @@ -1,3 +1,4 @@ +drop table if exists t1,t2; show tables; Tables_in_mysql columns_priv @@ -65,3 +66,8 @@ show tables; Tables_in_test delete from mysql.user where user=_binary"test"; flush privileges; +create table t1 (id integer not null auto_increment primary key); +create temporary table t2(id integer not null auto_increment primary key); +set @id := 1; +delete from t1 where id like @id; +drop table t1; diff --git a/mysql-test/r/create.result b/mysql-test/r/create.result index 95757fbd7dc..6edd4cbc48f 100644 --- a/mysql-test/r/create.result +++ b/mysql-test/r/create.result @@ -9,6 +9,8 @@ NULL drop table if exists t1; create table t1 (b char(0) not null); create table if not exists t1 (b char(0) not null); +Warnings: +Note 1050 Table 't1' already exists insert into t1 values (""),(null); Warnings: Warning 1263 Data truncated; NULL supplied to NOT NULL column 'b' at row 2 @@ -232,9 +234,13 @@ create table t1 select x'4132'; drop table t1; create table t1 select 1,2,3; create table if not exists t1 select 1,2; +Warnings: +Note 1050 Table 't1' already exists create table if not exists t1 select 1,2,3,4; ERROR 21S01: Column count doesn't match value count at row 1 create table if not exists t1 select 1; +Warnings: +Note 1050 Table 't1' already exists select * from t1; 1 2 3 1 2 3 @@ -243,9 +249,13 @@ select * from t1; drop table t1; create table t1 select 1,2,3; create table if not exists t1 select 1,2; +Warnings: +Note 1050 Table 't1' already exists create table if not exists t1 select 1,2,3,4; ERROR 21S01: Column count doesn't match value count at row 1 create table if not exists t1 select 1; +Warnings: +Note 1050 Table 't1' already exists select * from t1; 1 2 3 1 2 3 @@ -255,11 +265,15 @@ drop table t1; create table t1 (a int not null, b int, primary key (a)); insert into t1 values (1,1); create table if not exists t1 select 2; +Warnings: +Note 1050 Table 't1' already exists select * from t1; a b 1 1 0 2 create table if not exists t1 select 3 as 'a',4 as 'b'; +Warnings: +Note 1050 Table 't1' already exists create table if not exists t1 select 3 as 'a',3 as 'b'; ERROR 23000: Duplicate entry '3' for key 1 select * from t1; @@ -593,3 +607,17 @@ drop database mysqltest; create table test.t1 like x; ERROR 42000: Incorrect database name 'NULL' drop table if exists test.t1; +create database mysqltest; +create database if not exists mysqltest character set latin2; +Warnings: +Note 1007 Can't create database 'mysqltest'; database exists +show create database mysqltest; +Database Create Database +mysqltest CREATE DATABASE `mysqltest` /*!40100 DEFAULT CHARACTER SET latin1 */ +drop database mysqltest; +use test; +create table t1 (a int); +create table if not exists t1 (a int); +Warnings: +Note 1050 Table 't1' already exists +drop table t1; diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 748361d3178..9f2d7eac700 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -955,6 +955,10 @@ char_length(a) length(a) a 2 4 ан drop table t1; set names utf8; +select 'andre%' like 'andreñ%' escape 'ñ'; +'andre%' like 'andreñ%' escape 'ñ' +1 +set names utf8; select 'a\\' like 'a\\'; 'a\\' like 'a\\' 1 diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index a6c25fcd26c..d7a741827d5 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -469,6 +469,15 @@ select collation(group_concat(a,b)) from t1; ERROR HY000: Illegal mix of collations (cp1250_general_ci,IMPLICIT) and (koi8r_general_ci,IMPLICIT) for operation 'group_concat' drop table t1; drop table t2; +CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850); +INSERT INTO t1 VALUES ('À'); +SELECT a FROM t1; +a +À +SELECT GROUP_CONCAT(a) FROM t1; +GROUP_CONCAT(a) +À +DROP TABLE t1; CREATE TABLE t1 (id int); SELECT GROUP_CONCAT(id) AS gc FROM t1 HAVING gc IS NULL; gc @@ -551,3 +560,32 @@ DROP TABLE t1,t2; select * from (select group_concat('c') from DUAL) t; group_concat('c') NULL +create table t1 ( a int not null default 0); +select * from (select group_concat(a) from t1) t2; +group_concat(a) +NULL +select group_concat('x') UNION ALL select 1; +group_concat('x') +NULL +1 +drop table t1; +CREATE TABLE t1 (id int, a varchar(9)); +INSERT INTO t1 VALUES +(2, ''), (1, ''), (2, 'x'), (1, 'y'), (3, 'z'), (3, ''); +SELECT GROUP_CONCAT(a) FROM t1; +GROUP_CONCAT(a) +,,x,y,z, +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1; +GROUP_CONCAT(a ORDER BY a) +,,,x,y,z +SELECT GROUP_CONCAT(a) FROM t1 GROUP BY id; +GROUP_CONCAT(a) +,y +,x +z, +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY id; +GROUP_CONCAT(a ORDER BY a) +,y +,x +,z +DROP TABLE t1; diff --git a/mysql-test/r/func_like.result b/mysql-test/r/func_like.result index a58432cb06e..bc658f9f7de 100644 --- a/mysql-test/r/func_like.result +++ b/mysql-test/r/func_like.result @@ -158,3 +158,10 @@ DROP TABLE t1; select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin; _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin 1 +set names koi8r; +select 'andre%' like 'andreÊ%' escape 'Ê'; +'andre%' like 'andreÊ%' escape 'Ê' +1 +select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê'; +_cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê' +1 diff --git a/mysql-test/r/func_math.result b/mysql-test/r/func_math.result index 80b15d1d3c8..b36902d7872 100644 --- a/mysql-test/r/func_math.result +++ b/mysql-test/r/func_math.result @@ -140,3 +140,8 @@ drop table t1; select abs(-2) * -2; abs(-2) * -2 -4 +create table t1 (i int); +insert into t1 values (1); +select rand(i) from t1; +ERROR HY000: Incorrect arguments to RAND +drop table t1; diff --git a/mysql-test/r/group_by.result b/mysql-test/r/group_by.result index 8287a042d60..4ad28091164 100644 --- a/mysql-test/r/group_by.result +++ b/mysql-test/r/group_by.result @@ -764,3 +764,12 @@ select date(left(f1+0,8)) from t1 group by 1; date(left(f1+0,8)) 2005-06-06 drop table t1; +create table t1(f1 varchar(5) key); +insert into t1 values (1),(2); +select sql_buffer_result max(f1) is null from t1; +max(f1) is null +0 +select sql_buffer_result max(f1)+1 from t1; +max(f1)+1 +3 +drop table t1; diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index 858daacffe9..c7aef8ed792 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1674,3 +1674,23 @@ select * from t1; a 42 drop table t1; +create table t1 (a int not null, b int not null, c blob not null, d int not null, e int, primary key (a,b,c(255),d)) engine=innodb; +insert into t1 values (2,2,"b",2,2),(1,1,"a",1,1),(3,3,"ab",3,3); +select * from t1 order by a,b,c,d; +a b c d e +1 1 a 1 1 +2 2 b 2 2 +3 3 ab 3 3 +explain select * from t1 order by a,b,c,d; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 3 Using filesort +drop table t1; +create table t1 (a char(1), b char(1), key(a, b)) engine=innodb; +insert into t1 values ('8', '6'), ('4', '7'); +select min(a) from t1; +min(a) +4 +select min(b) from t1 where a='8'; +min(b) +6 +drop table t1; diff --git a/mysql-test/r/insert_select.result b/mysql-test/r/insert_select.result index 2ac73fe7662..d4eb4e8b788 100644 --- a/mysql-test/r/insert_select.result +++ b/mysql-test/r/insert_select.result @@ -668,3 +668,13 @@ ERROR 42S02: Unknown table 't2' in field list insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= t1.a + t2.b; ERROR 42S02: Unknown table 't2' in field list drop table t1,t2,t3; +create table t1(f1 varchar(5) key); +insert into t1(f1) select if(max(f1) is null, '2000',max(f1)+1) from t1; +insert into t1(f1) select if(max(f1) is null, '2000',max(f1)+1) from t1; +insert into t1(f1) select if(max(f1) is null, '2000',max(f1)+1) from t1; +select * from t1; +f1 +2000 +2001 +2002 +drop table t1; diff --git a/mysql-test/r/join_outer.result b/mysql-test/r/join_outer.result index b6265aac4a3..d5ae1a58e83 100644 --- a/mysql-test/r/join_outer.result +++ b/mysql-test/r/join_outer.result @@ -883,3 +883,136 @@ Warnings: Warning 1260 2 line(s) were cut by GROUP_CONCAT() drop table t1, t2; set group_concat_max_len=default; +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); +INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10); +INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b; +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b; +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b); +a b a b +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b); +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b; +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b); +a b a b +2 1 NULL NULL +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +8 7 NULL NULL +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b; +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b)); +a b a b +3 2 3 0 +4 3 4 1 +6 5 6 4 +7 8 7 5 +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL PRIMARY NULL NULL NULL 4 +1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t2.a 1 Using where +DROP TABLE t1,t2; diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 9175bdc7250..ae44233aab6 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -179,7 +179,6 @@ source database echo message echo message mysqltest: At line 1: Empty variable -mysqltest: At line 1: command "';' 2> /dev/null" failed mysqltest: At line 1: Missing argument in exec MySQL "MySQL" @@ -301,7 +300,6 @@ mysqltest: At line 1: First argument to dec must be a variable (start with $) mysqltest: At line 1: End of line junk detected: "1000" mysqltest: At line 1: Missing arguments to system, nothing to do! mysqltest: At line 1: Missing arguments to system, nothing to do! -mysqltest: At line 1: system command 'NonExistsinfComamdn 2> /dev/null' failed test test2 test3 diff --git a/mysql-test/r/ndb_autodiscover.result b/mysql-test/r/ndb_autodiscover.result index 5a1a82832fa..c61270c02a8 100644 --- a/mysql-test/r/ndb_autodiscover.result +++ b/mysql-test/r/ndb_autodiscover.result @@ -99,6 +99,8 @@ id int not null primary key, id2 int not null, name char(20) ) engine=ndb; +Warnings: +Note 1050 Table 't3' already exists show status like 'handler_discover%'; Variable_name Value Handler_discover 0 diff --git a/mysql-test/r/olap.result b/mysql-test/r/olap.result index 7178895cf80..fef990297d9 100644 --- a/mysql-test/r/olap.result +++ b/mysql-test/r/olap.result @@ -516,3 +516,28 @@ a b c count 1 NULL NULL 2 NULL NULL NULL 2 DROP TABLE t1; +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); +SELECT * FROM (SELECT a, a + 1, COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +a a + 1 COUNT(*) +1 2 1 +2 3 1 +NULL NULL 2 +SELECT * FROM (SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +a LENGTH(a) COUNT(*) +1 1 1 +2 1 1 +NULL NULL 2 +DROP TABLE t1; +create table t1 ( a varchar(9), b int ); +insert into t1 values('a',1),(null,2); +select a, max(b) from t1 group by a with rollup; +a max(b) +NULL 2 +a 1 +NULL 2 +select distinct a, max(b) from t1 group by a with rollup; +a max(b) +NULL 2 +a 1 +drop table t1; diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index c17015df757..f5bf3ffa96d 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -334,39 +334,37 @@ create table t1 (a int); insert into t1 (a) values (1), (2), (3), (4); set @precision=10000000000; select rand(), -cast(rand(10)*@precision as unsigned integer), -cast(rand(a)*@precision as unsigned integer) from t1; -rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) -- 6570515219 - -- 1282061302 - -- 6698761160 - -- 9647622201 - +cast(rand(10)*@precision as unsigned integer) from t1; +rand() cast(rand(10)*@precision as unsigned integer) +- 6570515219 +- 1282061302 +- 6698761160 +- 9647622201 prepare stmt from "select rand(), cast(rand(10)*@precision as unsigned integer), - cast(rand(a)*@precision as unsigned integer), cast(rand(?)*@precision as unsigned integer) from t1"; set @var=1; execute stmt using @var; -rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) -- 6570515219 - 4054035371 -- 1282061302 - 8716141803 -- 6698761160 - 1418603212 -- 9647622201 - 944590960 +rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) +- 6570515219 - +- 1282061302 - +- 6698761160 - +- 9647622201 - set @var=2; execute stmt using @var; -rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) -- 6570515219 1559528654 6555866465 -- 1282061302 6238114970 1223466192 -- 6698761160 6511989195 6449731873 -- 9647622201 3845601374 8578261098 +rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) +- 6570515219 6555866465 +- 1282061302 1223466192 +- 6698761160 6449731873 +- 9647622201 8578261098 set @var=3; execute stmt using @var; -rand() cast(rand(10)*@precision as unsigned integer) cast(rand(a)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) -- 6570515219 1559528654 9057697559 -- 1282061302 6238114970 3730790581 -- 6698761160 6511989195 1480860534 -- 9647622201 3845601374 6211931236 +rand() cast(rand(10)*@precision as unsigned integer) cast(rand(?)*@precision as unsigned integer) +- 6570515219 9057697559 +- 1282061302 3730790581 +- 6698761160 1480860534 +- 9647622201 6211931236 drop table t1; deallocate prepare stmt; create database mysqltest1; diff --git a/mysql-test/r/ps_1general.result b/mysql-test/r/ps_1general.result index c4ccdf9eb34..49e858eca56 100644 --- a/mysql-test/r/ps_1general.result +++ b/mysql-test/r/ps_1general.result @@ -470,12 +470,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 14 N 1 31 8 +def Extra 253 255 14 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 ALL NULL NULL NULL NULL 4 Using filesort SET @arg00=1 ; @@ -486,12 +486,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 5 Y 0 31 8 -def possible_keys 252 4096 7 Y 0 31 8 +def possible_keys 253 4096 7 Y 0 31 8 def key 253 64 7 Y 0 31 8 def key_len 8 3 1 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 27 N 1 31 8 +def Extra 253 255 27 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range PRIMARY PRIMARY 4 NULL 3 Using where; Using filesort drop table if exists t2; diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index 6ef61b05577..4b655cfb854 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -1153,12 +1153,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 0 N 1 31 8 +def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 2 drop table if exists t2 ; diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 96047ac3182..4d2a62887d6 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -1153,12 +1153,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 0 N 1 31 8 +def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 2 test_sequence diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index bff4b6a5ad8..a4919b664c4 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -1154,12 +1154,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 0 N 1 31 8 +def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 2 test_sequence diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index 5ed6c10a47c..f98cc1b3cdf 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -1196,12 +1196,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 0 N 1 31 8 +def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 2 test_sequence @@ -4210,12 +4210,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 0 N 1 31 8 +def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 2 test_sequence diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index ef74e13a41d..acd7f45de95 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -1153,12 +1153,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 0 N 1 31 8 +def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 3 test_sequence diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index e7ffbb7c6ef..27a1ea0925d 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -1153,12 +1153,12 @@ def id 8 3 1 N 32929 0 63 def select_type 253 19 6 N 1 31 8 def table 253 64 2 Y 0 31 8 def type 253 10 3 Y 0 31 8 -def possible_keys 252 4096 0 Y 0 31 8 +def possible_keys 253 4096 0 Y 0 31 8 def key 253 64 0 Y 0 31 8 def key_len 8 3 0 Y 32928 0 63 -def ref 252 1024 0 Y 0 31 8 +def ref 253 1024 0 Y 0 31 8 def rows 8 10 1 Y 32928 0 63 -def Extra 252 255 0 N 1 31 8 +def Extra 253 255 0 N 1 31 8 id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t9 ALL NULL NULL NULL NULL 2 test_sequence diff --git a/mysql-test/r/rpl_multi_delete2.result b/mysql-test/r/rpl_multi_delete2.result index c6c088111fc..73db9f62eb4 100644 --- a/mysql-test/r/rpl_multi_delete2.result +++ b/mysql-test/r/rpl_multi_delete2.result @@ -4,6 +4,26 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; +set sql_log_bin=0; +create database mysqltest_from; +set sql_log_bin=1; +create database mysqltest_to; +use mysqltest_from; +drop table if exists a; +CREATE TABLE a (i INT); +INSERT INTO a VALUES(1); +DELETE alias FROM a alias WHERE alias.i=1; +SELECT * FROM a; +i +insert into a values(2),(3); +delete a alias FROM a alias where alias.i=2; +select * from a; +i +3 +use mysqltest_to; +select * from a; +i +3 create table t1 (a int); create table t2 (a int); insert into t1 values (1); @@ -15,7 +35,10 @@ select * from t2; a 1 select * from t1; -ERROR 42S02: Table 'test.t1' doesn't exist +ERROR 42S02: Table 'mysqltest_to.t1' doesn't exist select * from t2; -ERROR 42S02: Table 'test.t2' doesn't exist -drop table t1,t2; +ERROR 42S02: Table 'mysqltest_to.t2' doesn't exist +set sql_log_bin=0; +drop database mysqltest_from; +set sql_log_bin=1; +drop database mysqltest_to; diff --git a/mysql-test/r/rpl_slave_status.result b/mysql-test/r/rpl_slave_status.result index 8badbab85ff..2146132aeb0 100644 --- a/mysql-test/r/rpl_slave_status.result +++ b/mysql-test/r/rpl_slave_status.result @@ -19,7 +19,7 @@ flush privileges; stop slave; start slave; show slave status; -Slave_IO_State Connecting to master +Slave_IO_State # Master_Host 127.0.0.1 Master_User rpl Master_Port MASTER_MYPORT diff --git a/mysql-test/r/temp_table.result b/mysql-test/r/temp_table.result index f08fe6ddd0f..0b6bc48c350 100644 --- a/mysql-test/r/temp_table.result +++ b/mysql-test/r/temp_table.result @@ -23,6 +23,8 @@ a b 6 g create TEMPORARY TABLE t2 engine=heap select * from t1; create TEMPORARY TABLE IF NOT EXISTS t2 (a int) engine=heap; +Warnings: +Note 1050 Table 't2' already exists CREATE TEMPORARY TABLE t1 (a int not null, b char (10) not null); ERROR 42S01: Table 't1' already exists ALTER TABLE t1 RENAME t2; diff --git a/mysql-test/r/warnings.result b/mysql-test/r/warnings.result index e97b309547a..b9c05bc388c 100644 --- a/mysql-test/r/warnings.result +++ b/mysql-test/r/warnings.result @@ -63,9 +63,11 @@ show count(*) warnings; 1 create table t1(id int); create table if not exists t1(id int); +Warnings: +Note 1050 Table 't1' already exists select @@warning_count; @@warning_count -0 +1 drop table t1; create table t1(a tinyint, b int not null, c date, d char(5)); load data infile '../../std_data/warnings_loaddata.dat' into table t1 fields terminated by ','; diff --git a/mysql-test/t/analyse.test b/mysql-test/t/analyse.test index e7fbf09c19a..e38e43381bc 100644 --- a/mysql-test/t/analyse.test +++ b/mysql-test/t/analyse.test @@ -48,4 +48,13 @@ insert into t1 values ('abc'),('abc\'def\\hij\"klm\0opq'),('\''),('\"'),('\\'),( select * from t1 procedure analyse(); drop table t1; +# +# Bug#10716 - Procedure Analyse results in wrong values for optimal field type +# + +create table t1 (d double); +insert into t1 values (100000); +select * from t1 procedure analyse (1,1); +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test index 1a6dca5b69e..ff15d74e5ac 100644 --- a/mysql-test/t/connect.test +++ b/mysql-test/t/connect.test @@ -6,6 +6,10 @@ # This test makes no sense with the embedded server --source include/not_embedded.inc +--disable_warnings +drop table if exists t1,t2; +--enable_warnings + #connect (con1,localhost,root,,""); #show tables; connect (con1,localhost,root,,mysql); @@ -77,4 +81,18 @@ show tables; delete from mysql.user where user=_binary"test"; flush privileges; +# +# Bug#12517: Clear user variables and replication events before +# closing temp tables in thread cleanup. +connect (con2,localhost,root,,test); +connection con2; +create table t1 (id integer not null auto_increment primary key); +create temporary table t2(id integer not null auto_increment primary key); +set @id := 1; +delete from t1 where id like @id; +disconnect con2; +--sleep 5 +connection default; +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/create.test b/mysql-test/t/create.test index 9ea810aaf7d..73184853d1a 100644 --- a/mysql-test/t/create.test +++ b/mysql-test/t/create.test @@ -513,4 +513,17 @@ create table test.t1 like x; drop table if exists test.t1; --enable_warnings +# +# Bug #6008 MySQL does not create warnings when +# creating database and using IF NOT EXISTS +# +create database mysqltest; +create database if not exists mysqltest character set latin2; +show create database mysqltest; +drop database mysqltest; +use test; +create table t1 (a int); +create table if not exists t1 (a int); +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index e6342777839..0cdda648899 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -810,6 +810,12 @@ alter table t1 modify a char(2) character set utf8; select char_length(a), length(a), a from t1 order by a; drop table t1; +# +# Bugs#12611 +# ESCAPE + LIKE do not work when the escape char is a multibyte one +# +set names utf8; +select 'andre%' like 'andreñ%' escape 'ñ'; # # Bugs#11754: SET NAMES utf8 followed by SELECT "A\\" LIKE "A\\" returns 0 diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 827a2813718..eb1cbc3d667 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -282,6 +282,16 @@ drop table t1; drop table t2; # +# Bug #12829 +# Cannot convert the charset of a GROUP_CONCAT result +# +CREATE TABLE t1 (a CHAR(10) CHARACTER SET cp850); +INSERT INTO t1 VALUES ('À'); +SELECT a FROM t1; +SELECT GROUP_CONCAT(a) FROM t1; +DROP TABLE t1; + +# # bug #7769: group_concat returning null is checked in having # CREATE TABLE t1 (id int); @@ -348,4 +358,28 @@ DROP TABLE t1,t2; # select * from (select group_concat('c') from DUAL) t; +# +# Bug #12859 group_concat in subquery cause incorrect not null +# +create table t1 ( a int not null default 0); +select * from (select group_concat(a) from t1) t2; +select group_concat('x') UNION ALL select 1; +drop table t1; + +# +# Bug #12863 : missing separators after first empty cancatanated elements +# + +CREATE TABLE t1 (id int, a varchar(9)); +INSERT INTO t1 VALUES + (2, ''), (1, ''), (2, 'x'), (1, 'y'), (3, 'z'), (3, ''); + +SELECT GROUP_CONCAT(a) FROM t1; +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1; + +SELECT GROUP_CONCAT(a) FROM t1 GROUP BY id; +SELECT GROUP_CONCAT(a ORDER BY a) FROM t1 GROUP BY id; + +DROP TABLE t1; + # End of 4.1 tests diff --git a/mysql-test/t/func_like.test b/mysql-test/t/func_like.test index 684d7032038..4e1183afeff 100644 --- a/mysql-test/t/func_like.test +++ b/mysql-test/t/func_like.test @@ -96,4 +96,21 @@ DROP TABLE t1; # select _cp866'aaaaaaaaa' like _cp866'%aaaa%' collate cp866_bin; +# +# Check 8bit escape character +# +set names koi8r; +select 'andre%' like 'andreÊ%' escape 'Ê'; + +# Check 8bit escape character with charset conversion: +# For "a LIKE b ESCAPE c" expressions, +# escape character is converted into the operation character set, +# which is result of aggregation of character sets of "a" and "b". +# "c" itself doesn't take part in aggregation, because its collation +# doesn't matter, escape character is always compared binary. +# In the example below, escape character is converted from koi8r into cp1251: +# +select _cp1251'andre%' like convert('andreÊ%' using cp1251) escape 'Ê'; + +# # End of 4.1 tests diff --git a/mysql-test/t/func_math.test b/mysql-test/t/func_math.test index ebbc594952c..c75454a96d4 100644 --- a/mysql-test/t/func_math.test +++ b/mysql-test/t/func_math.test @@ -77,4 +77,13 @@ drop table t1; # select abs(-2) * -2; +# +# Bug #6172 RAND(a) should only accept constant values as arguments +# +create table t1 (i int); +insert into t1 values (1); +--error 1210 +select rand(i) from t1; +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/group_by.test b/mysql-test/t/group_by.test index 815da66c717..f14fab2d30e 100644 --- a/mysql-test/t/group_by.test +++ b/mysql-test/t/group_by.test @@ -600,4 +600,14 @@ insert into t1 values('2005-06-06'); select date(left(f1+0,8)) from t1 group by 1; drop table t1; +# +# BUG#12695: Item_func_isnull::update_used_tables +# did not update const_item_cache +# +create table t1(f1 varchar(5) key); +insert into t1 values (1),(2); +select sql_buffer_result max(f1) is null from t1; +select sql_buffer_result max(f1)+1 from t1; +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 33432209e65..b966ea5b281 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1220,4 +1220,23 @@ insert into t1 values (42); select * from t1; drop table t1; +# +# Bug #13025 Server crash during filesort +# + +create table t1 (a int not null, b int not null, c blob not null, d int not null, e int, primary key (a,b,c(255),d)) engine=innodb; +insert into t1 values (2,2,"b",2,2),(1,1,"a",1,1),(3,3,"ab",3,3); +select * from t1 order by a,b,c,d; +explain select * from t1 order by a,b,c,d; +drop table t1; + +# +# BUG#11039,#13218 Wrong key length in min() +# + +create table t1 (a char(1), b char(1), key(a, b)) engine=innodb; +insert into t1 values ('8', '6'), ('4', '7'); +select min(a) from t1; +select min(b) from t1 where a='8'; +drop table t1; # End of 4.1 tests diff --git a/mysql-test/t/insert_select.test b/mysql-test/t/insert_select.test index 14853b38db2..6fcdef6ab03 100644 --- a/mysql-test/t/insert_select.test +++ b/mysql-test/t/insert_select.test @@ -204,4 +204,14 @@ insert into t1 select t2.a from t2 on duplicate key update t2.a= a + t2.b; insert into t1 select t2.a from t2 group by t2.a on duplicate key update a= t1.a + t2.b; drop table t1,t2,t3; +# +# Bug #12695 Item_func_isnull::update_used_tables() did not update +# const_item_cache +create table t1(f1 varchar(5) key); +insert into t1(f1) select if(max(f1) is null, '2000',max(f1)+1) from t1; +insert into t1(f1) select if(max(f1) is null, '2000',max(f1)+1) from t1; +insert into t1(f1) select if(max(f1) is null, '2000',max(f1)+1) from t1; +select * from t1; +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/join_outer.test b/mysql-test/t/join_outer.test index fa2dd93c9ba..05cd2fb152e 100644 --- a/mysql-test/t/join_outer.test +++ b/mysql-test/t/join_outer.test @@ -625,4 +625,50 @@ select group_concat(t1.b,t2.c) from t1 inner join t2 using(a) group by t1.a; drop table t1, t2; set group_concat_max_len=default; +# +# Test for bugs +# #12101: erroneously applied outer join elimination in case of WHERE NOT BETWEEN +# #12102: erroneously missing outer join elimination in case of WHERE IN/IF +# + +CREATE TABLE t1 (a int PRIMARY KEY, b int); +CREATE TABLE t2 (a int PRIMARY KEY, b int); + +INSERT INTO t1 VALUES (1,2), (2,1), (3,2), (4,3), (5,6), (6,5), (7,8), (8,7), (9,10); +INSERT INTO t2 VALUES (3,0), (4,1), (6,4), (7,5); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b <= t1.a AND t1.a <= t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a BETWEEN t2.b AND t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.b > t1.a OR t1.a > t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT BETWEEN t2.b AND t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t2.b > t1.a OR t1.a > t1.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a AND t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a AND (t2.b > t1.a OR t1.a > t1.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a != t2.a OR t1.a BETWEEN t2.b AND t1.b); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a NOT IN(t2.a, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a != t1.b AND t1.a != t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a NOT IN(t1.b, t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t1.a IN(t1.b, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b OR (t1.a != t2.a AND t1.a != t2.b); +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b AND t1.a IN(t2.a, t2.b)); + +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t2.a != t2.b AND t1.a != t1.b AND t1.a != t2.b; +SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE NOT(t2.a = t2.b OR t1.a IN(t1.b, t2.b)); + +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a = t2.a OR t1.a = t2.b; +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a IN(t2.a, t2.b); +EXPLAIN SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a WHERE t1.a > IF(t1.a = t2.b-2, t2.b, t2.b-1); + +DROP TABLE t1,t2; + # End of 4.1 tests diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index bfb1919e75c..4d3bcc037d1 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -358,8 +358,11 @@ select 3 from t1 ; # Missing delimiter # The comment will be "sucked into" the sleep command since # delimiter is missing until after "show status" +--system echo "sleep 4" > var/log/mysqltest.sql +--system echo "# A comment" >> var/log/mysqltest.sql +--system echo "show status;" >> var/log/mysqltest.sql --error 1 ---exec echo -e "sleep 4\n # A comment\nshow status;" | $MYSQL_TEST 2>&1 +--exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 # # Extra delimiter @@ -423,8 +426,9 @@ echo ; # ---------------------------------------------------------------------------- # Illegal use of exec ---error 1 ---exec echo "--exec ';' 2> /dev/null" | $MYSQL_TEST 2>&1 +# Disabled, some shells prints the failed command regardless of pipes +#--error 1 +#--exec echo "--exec ';' 2> /dev/null" | $MYSQL_TEST 2>&1 --error 1 --exec echo "--exec " | $MYSQL_TEST 2>&1 @@ -588,7 +592,7 @@ while ($num) --source var/tmp/sourced1.sql dec $num; } ---enable_abort_on_error; +--enable_abort_on_error --enable_query_log # ---------------------------------------------------------------------------- @@ -671,8 +675,9 @@ system echo "hej" > /dev/null; --exec echo "system;" | $MYSQL_TEST 2>&1 --error 1 --exec echo "system $NONEXISTSINFVAREABLI;" | $MYSQL_TEST 2>&1 ---error 1 ---exec echo "system NonExistsinfComamdn 2> /dev/null;" | $MYSQL_TEST 2>&1 +# Disabled, some shells prints the failed command regardless of pipes +#--error 1 +#--exec echo "system NonExistsinfComamdn 2> /dev/null;" | $MYSQL_TEST 2>&1 --disable_abort_on_error system NonExistsinfComamdn; @@ -722,12 +727,21 @@ while ($i) --exec echo "end;" | $MYSQL_TEST 2>&1 --error 1 --exec echo "{;" | $MYSQL_TEST 2>&1 + +--system echo "while (0)" > var/log/mysqltest.sql +--system echo "echo hej;" >> var/log/mysqltest.sql --error 1 ---exec echo -e "while (0)\necho hej;" | $MYSQL_TEST 2>&1 +--exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 + +--system echo "while (0)" > var/log/mysqltest.sql +--system echo "{echo hej;" >> var/log/mysqltest.sql --error 1 ---exec echo -e "while (0)\n{echo hej;" | $MYSQL_TEST 2>&1 +--exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 + +--system echo "while (0){" > var/log/mysqltest.sql +--system echo "echo hej;" >> var/log/mysqltest.sql --error 1 ---exec echo -e "while (0){\n echo hej;" | $MYSQL_TEST 2>&1 +--exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 # ---------------------------------------------------------------------------- # Test error messages returned from comments starting with a command @@ -792,6 +806,19 @@ select "a" as col1, "c" as col2; --error 1 --exec echo "save_master_pos; sync_with_master a;" | $MYSQL_TEST 2>&1 + +# ---------------------------------------------------------------------------- +# Test mysqltest arguments +# ---------------------------------------------------------------------------- + +# -x <file_name>, use the file specified after -x as the test file +#--exec $MYSQL_TEST < $MYSQL_TEST_DIR/include/mysqltest-x.inc 2>&1 +#--exec $MYSQL_TEST -x $MYSQL_TEST_DIR/include/mysqltest-x.inc 2>&1 +#--exec $MYSQL_TEST --result_file=$MYSQL_TEST_DIR/include/mysqltest-x.inc 2>&1 +#--error 1 +#--exec $MYSQL_TEST -x non_existing_file.inc 2>&1 + + # ---------------------------------------------------------------------------- # TODO Test queries, especially their errormessages... so it's easy to debug # new scripts and diagnose errors diff --git a/mysql-test/t/olap.test b/mysql-test/t/olap.test index c9a16b897c6..4f9790b0de6 100644 --- a/mysql-test/t/olap.test +++ b/mysql-test/t/olap.test @@ -250,4 +250,26 @@ SELECT a, b, a AS c, COUNT(*) AS count FROM t1 GROUP BY a, b, c WITH ROLLUP; DROP TABLE t1; +# +# Bug #11885: derived table specified by a subquery with +# ROLLUP over expressions on not nullable group by attributes +# + +CREATE TABLE t1 (a int(11) NOT NULL); +INSERT INTO t1 VALUES (1),(2); + +SELECT * FROM (SELECT a, a + 1, COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; +SELECT * FROM (SELECT a, LENGTH(a), COUNT(*) FROM t1 GROUP BY a WITH ROLLUP) t; + +DROP TABLE t1; + +# +# Bug #12887 Distinct is not always applied after rollup +# +create table t1 ( a varchar(9), b int ); +insert into t1 values('a',1),(null,2); +select a, max(b) from t1 group by a with rollup; +select distinct a, max(b) from t1 group by a with rollup; +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/openssl_1.test b/mysql-test/t/openssl_1.test index 3698ab54ec1..3f398a91834 100644 --- a/mysql-test/t/openssl_1.test +++ b/mysql-test/t/openssl_1.test @@ -20,22 +20,22 @@ connect (con4,localhost,ssl_user4,,); connection con1; select * from t1; ---error 1044; +--error 1044 delete from t1; connection con2; select * from t1; ---error 1044; +--error 1044 delete from t1; connection con3; select * from t1; ---error 1044; +--error 1044 delete from t1; connection con4; select * from t1; ---error 1044; +--error 1044 delete from t1; connection default; diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 5a2e469fbc4..c4cb0056763 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -368,12 +368,10 @@ insert into t1 (a) values (1), (2), (3), (4); set @precision=10000000000; --replace_column 1 - 3 - select rand(), - cast(rand(10)*@precision as unsigned integer), - cast(rand(a)*@precision as unsigned integer) from t1; + cast(rand(10)*@precision as unsigned integer) from t1; prepare stmt from "select rand(), cast(rand(10)*@precision as unsigned integer), - cast(rand(a)*@precision as unsigned integer), cast(rand(?)*@precision as unsigned integer) from t1"; set @var=1; --replace_column 1 - 3 - diff --git a/mysql-test/t/rpl_multi_delete2-slave.opt b/mysql-test/t/rpl_multi_delete2-slave.opt index b828d03fafb..0febb2891b1 100644 --- a/mysql-test/t/rpl_multi_delete2-slave.opt +++ b/mysql-test/t/rpl_multi_delete2-slave.opt @@ -1 +1 @@ ---replicate-wild-ignore-table=test.% +"--replicate-rewrite-db=mysqltest_from->mysqltest_to" --replicate-do-table=mysqltest_to.a diff --git a/mysql-test/t/rpl_multi_delete2.test b/mysql-test/t/rpl_multi_delete2.test index 62d95a3a90f..c50311de363 100644 --- a/mysql-test/t/rpl_multi_delete2.test +++ b/mysql-test/t/rpl_multi_delete2.test @@ -1,4 +1,41 @@ +#multi delete replication bugs + + source include/master-slave.inc; + +#BUG#11139 - improper wild-table and table rules +#checking for multi deletes with an alias + +connection master; +set sql_log_bin=0; +create database mysqltest_from; +set sql_log_bin=1; + +connection slave; +create database mysqltest_to; + + +connection master; +use mysqltest_from; +--disable_warnings +drop table if exists a; +--enable_warnings +CREATE TABLE a (i INT); +INSERT INTO a VALUES(1); +DELETE alias FROM a alias WHERE alias.i=1; +SELECT * FROM a; +insert into a values(2),(3); +delete a alias FROM a alias where alias.i=2; +select * from a; +save_master_pos; +connection slave; + +use mysqltest_to; +sync_with_master; +select * from a; + +# BUG#3461 +connection master; create table t1 (a int); create table t2 (a int); @@ -19,7 +56,13 @@ select * from t1; error 1146; select * from t2; +# cleanup connection master; -drop table t1,t2; +set sql_log_bin=0; +drop database mysqltest_from; +set sql_log_bin=1; +connection slave; +drop database mysqltest_to; # End of 4.1 tests + diff --git a/mysql-test/t/rpl_slave_status.test b/mysql-test/t/rpl_slave_status.test index 2c5bd2bffb0..67d3816f443 100644 --- a/mysql-test/t/rpl_slave_status.test +++ b/mysql-test/t/rpl_slave_status.test @@ -23,7 +23,9 @@ connection slave; stop slave; start slave; --replace_result $MASTER_MYPORT MASTER_MYPORT ---replace_column 7 # 8 # 9 # 22 # 23 # +# Column 1 is replaced, since the output can be either +# "Connecting to master" or "Waiting for master update" +--replace_column 1 # 7 # 8 # 9 # 22 # 23 # --vertical_results show slave status; diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index f14af44dbb9..ca683f16415 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -632,12 +632,13 @@ void end_key_cache(KEY_CACHE *keycache, my_bool cleanup) keycache->blocks_changed= 0; } - DBUG_PRINT("status", - ("used: %d changed: %d w_requests: %ld \ -writes: %ld r_requests: %ld reads: %ld", - keycache->blocks_used, keycache->global_blocks_changed, - keycache->global_cache_w_requests, keycache->global_cache_write, - keycache->global_cache_r_requests, keycache->global_cache_read)); + DBUG_PRINT("status", ("used: %d changed: %d w_requests: %lu " + "writes: %lu r_requests: %lu reads: %lu", + keycache->blocks_used, keycache->global_blocks_changed, + (ulong) keycache->global_cache_w_requests, + (ulong) keycache->global_cache_write, + (ulong) keycache->global_cache_r_requests, + (ulong) keycache->global_cache_read)); if (cleanup) { diff --git a/ndb/include/kernel/signaldata/BackupImpl.hpp b/ndb/include/kernel/signaldata/BackupImpl.hpp index 2032e2347b5..298440ad377 100644 --- a/ndb/include/kernel/signaldata/BackupImpl.hpp +++ b/ndb/include/kernel/signaldata/BackupImpl.hpp @@ -33,7 +33,7 @@ class DefineBackupReq { friend bool printDEFINE_BACKUP_REQ(FILE *, const Uint32 *, Uint32, Uint16); public: - STATIC_CONST( SignalLength = 8 + NdbNodeBitmask::Size); + STATIC_CONST( SignalLength = 9 + NdbNodeBitmask::Size); private: /** @@ -60,6 +60,13 @@ private: * Length of backup data */ Uint32 backupDataLen; + + /** + * Backup flags + */ + /* & 0x3 - waitCompleted + */ + Uint32 flags; }; class DefineBackupRef { diff --git a/ndb/include/kernel/signaldata/BackupSignalData.hpp b/ndb/include/kernel/signaldata/BackupSignalData.hpp index b38dd8d14b2..e1b8c6203a1 100644 --- a/ndb/include/kernel/signaldata/BackupSignalData.hpp +++ b/ndb/include/kernel/signaldata/BackupSignalData.hpp @@ -36,11 +36,14 @@ class BackupReq { friend bool printBACKUP_REQ(FILE *, const Uint32 *, Uint32, Uint16); public: - STATIC_CONST( SignalLength = 2 ); + STATIC_CONST( SignalLength = 3 ); private: Uint32 senderData; Uint32 backupDataLen; + /* & 0x3 - waitCompleted + */ + Uint32 flags; }; class BackupData { diff --git a/ndb/include/kernel/signaldata/NFCompleteRep.hpp b/ndb/include/kernel/signaldata/NFCompleteRep.hpp index c8bde705a86..764da85b163 100644 --- a/ndb/include/kernel/signaldata/NFCompleteRep.hpp +++ b/ndb/include/kernel/signaldata/NFCompleteRep.hpp @@ -30,28 +30,12 @@ * from the failed NDB node * */ -class NFCompleteRep { - /** - * Sender(s) - */ - friend class Dbdict; - friend class Dblqh; - friend class Dbtc; - friend class Qmgr; - - /** - * Sender/Reciver - */ - friend class Dbdih; - friend class ClusterMgr; +struct NFCompleteRep { friend bool printNF_COMPLETE_REP(FILE *, const Uint32 *, Uint32, Uint16); -public: STATIC_CONST( SignalLength = 5 ); -private: - /** * Which block has completed... * diff --git a/ndb/include/kernel/signaldata/NodeFailRep.hpp b/ndb/include/kernel/signaldata/NodeFailRep.hpp index 060acd6a3e2..fe57ba1a712 100644 --- a/ndb/include/kernel/signaldata/NodeFailRep.hpp +++ b/ndb/include/kernel/signaldata/NodeFailRep.hpp @@ -24,34 +24,8 @@ * This signals is sent by Qmgr to NdbCntr * and then from NdbCntr sent to: dih, dict, lqh, tc & API */ -class NodeFailRep { - /** - * Sender(s) - */ - friend class Qmgr; - - /** - * Sender(s) / Reciver(s) - */ - friend class Ndbcntr; - friend class Dbdict; - - /** - * Reciver(s) - */ - friend class Dbdih; - friend class Dblqh; - friend class Dbtc; - friend class ClusterMgr; - friend class Trix; - friend class Backup; - friend class Suma; - friend class Grep; - friend class SafeCounterManager; - -public: +struct NodeFailRep { STATIC_CONST( SignalLength = 3 + NodeBitmask::Size ); -private: Uint32 failNo; diff --git a/ndb/include/kernel/signaldata/SignalData.hpp b/ndb/include/kernel/signaldata/SignalData.hpp index f9d3a6faa64..b0cfbc1540c 100644 --- a/ndb/include/kernel/signaldata/SignalData.hpp +++ b/ndb/include/kernel/signaldata/SignalData.hpp @@ -215,5 +215,6 @@ GSN_PRINT_SIGNATURE(printSCAN_FRAGREQ); GSN_PRINT_SIGNATURE(printCONTINUEB_NDBFS); GSN_PRINT_SIGNATURE(printCONTINUEB_DBDIH); +GSN_PRINT_SIGNATURE(printSTART_FRAG_REQ); #endif diff --git a/ndb/include/kernel/signaldata/StartFragReq.hpp b/ndb/include/kernel/signaldata/StartFragReq.hpp index ec05c1ee366..ab17a147195 100644 --- a/ndb/include/kernel/signaldata/StartFragReq.hpp +++ b/ndb/include/kernel/signaldata/StartFragReq.hpp @@ -32,6 +32,8 @@ class StartFragReq { public: STATIC_CONST( SignalLength = 19 ); + friend bool printSTART_FRAG_REQ(FILE *, const Uint32 *, Uint32, Uint16); + private: Uint32 userPtr; Uint32 userRef; diff --git a/ndb/include/util/Parser.hpp b/ndb/include/util/Parser.hpp index c117498e1ba..3baf7601a6c 100644 --- a/ndb/include/util/Parser.hpp +++ b/ndb/include/util/Parser.hpp @@ -285,7 +285,7 @@ template<class T> inline void Parser<T>::setBreakOnInvalidArg(bool v){ - impl->m_breakOnInvalidArg; + impl->m_breakOnInvalidArg = v; } #endif diff --git a/ndb/include/util/ndb_opts.h b/ndb/include/util/ndb_opts.h index ca4ca5eac83..462d9996582 100644 --- a/ndb/include/util/ndb_opts.h +++ b/ndb/include/util/ndb_opts.h @@ -30,8 +30,14 @@ my_bool opt_ndb_optimized_node_selection bool opt_endinfo= 0; my_bool opt_ndb_shm; +my_bool opt_core; #define OPT_NDB_CONNECTSTRING 'c' +#if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) +#define OPT_WANT_CORE_DEFAULT 1 +#else +#define OPT_WANT_CORE_DEFAULT 0 +#endif #define NDB_STD_OPTS_COMMON \ { "usage", '?', "Display this help and exit.", \ @@ -57,7 +63,10 @@ my_bool opt_ndb_shm; GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},\ { "connect-string", OPT_NDB_CONNECTSTRING, "same as --ndb-connectstring",\ (gptr*) &opt_connect_str, (gptr*) &opt_connect_str, 0,\ - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 } + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },\ + { "core-file", OPT_WANT_CORE, "Write core on errors.",\ + (gptr*) &opt_core, (gptr*) &opt_core, 0,\ + GET_BOOL, NO_ARG, OPT_WANT_CORE_DEFAULT, 0, 0, 0, 0, 0} #ifndef DBUG_OFF #define NDB_STD_OPTS(prog_name) \ @@ -80,6 +89,7 @@ enum ndb_std_options { OPT_NDB_SHM= 256, OPT_NDB_SHM_SIGNUM, OPT_NDB_OPTIMIZED_NODE_SELECTION, + OPT_WANT_CORE, NDB_STD_OPTIONS_LAST /* should always be last in this enum */ }; diff --git a/ndb/src/common/debugger/EventLogger.cpp b/ndb/src/common/debugger/EventLogger.cpp index 97945394690..f7cef644c64 100644 --- a/ndb/src/common/debugger/EventLogger.cpp +++ b/ndb/src/common/debugger/EventLogger.cpp @@ -585,11 +585,13 @@ EventLogger::getText(char * m_text, size_t m_text_len, BaseString::snprintf(m_text, m_text_len, "%sTable ID = %u, fragment ID = %u has completed LCP " - "on Node %u", + "on Node %u maxGciStarted: %d maxGciCompleted: %d", theNodeId, theData[2], theData[3], - theData[1]); + theData[1], + theData[4], + theData[5]); break; case EventReport::TransReportCounters: // ------------------------------------------------------------------- diff --git a/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp index a4cee38e06f..bd1dff074f9 100644 --- a/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp +++ b/ndb/src/common/debugger/signaldata/SignalDataPrint.cpp @@ -195,6 +195,7 @@ SignalDataPrintFunctions[] = { ,{ GSN_ACC_LOCKREQ, printACC_LOCKREQ } ,{ GSN_LQH_TRANSCONF, printLQH_TRANSCONF } ,{ GSN_SCAN_FRAGREQ, printSCAN_FRAGREQ } + ,{ GSN_START_FRAGREQ, printSTART_FRAG_REQ } ,{ 0, 0 } }; diff --git a/ndb/src/common/debugger/signaldata/StartRec.cpp b/ndb/src/common/debugger/signaldata/StartRec.cpp index 482e3cb0728..54830e533c5 100644 --- a/ndb/src/common/debugger/signaldata/StartRec.cpp +++ b/ndb/src/common/debugger/signaldata/StartRec.cpp @@ -17,6 +17,7 @@ #include <RefConvert.hpp> #include <signaldata/StartRec.hpp> +#include <signaldata/StartFragReq.hpp> bool printSTART_REC_REQ(FILE * output, @@ -50,3 +51,27 @@ printSTART_REC_CONF(FILE * output, return true; } + +bool +printSTART_FRAG_REQ(FILE * output, + const Uint32 * theData, + Uint32 len, + Uint16 recBlockNo) +{ + StartFragReq* sig = (StartFragReq*)theData; + + fprintf(output, " table: %d frag: %d lcpId: %d lcpNo: %d #nodes: %d \n", + sig->tableId, sig->fragId, sig->lcpId, sig->lcpNo, + sig->noOfLogNodes); + + for(Uint32 i = 0; i<sig->noOfLogNodes; i++) + { + fprintf(output, " (node: %d startGci: %d lastGci: %d)", + sig->lqhLogNode[i], + sig->startGci[i], + sig->lastGci[i]); + } + + fprintf(output, "\n"); + return true; +} diff --git a/ndb/src/common/portlib/NdbThread.c b/ndb/src/common/portlib/NdbThread.c index 55ebc4c8111..48d00956ec2 100644 --- a/ndb/src/common/portlib/NdbThread.c +++ b/ndb/src/common/portlib/NdbThread.c @@ -53,6 +53,16 @@ ndb_thread_wrapper(void* _ss){ } #endif { + /** + * Block all signals to thread by default + * let them go to main process instead + */ + sigset_t mask; + sigfillset(&mask); + pthread_sigmask(SIG_BLOCK, &mask, 0); + } + + { void *ret; struct NdbThread * ss = (struct NdbThread *)_ss; ret= (* ss->func)(ss->object); diff --git a/ndb/src/kernel/blocks/ERROR_codes.txt b/ndb/src/kernel/blocks/ERROR_codes.txt index 5193d3eae9d..791df915d66 100644 --- a/ndb/src/kernel/blocks/ERROR_codes.txt +++ b/ndb/src/kernel/blocks/ERROR_codes.txt @@ -6,7 +6,7 @@ Next DBTUP 4013 Next DBLQH 5042 Next DBDICT 6006 Next DBDIH 7174 -Next DBTC 8035 +Next DBTC 8037 Next CMVMI 9000 Next BACKUP 10022 Next DBUTIL 11002 @@ -406,8 +406,11 @@ Drop Table/Index: 4001: Crash on REL_TABMEMREQ in TUP 4002: Crash on DROP_TABFILEREQ in TUP 4003: Fail next trigger create in TUP +4004: Fail next trigger drop in TUP 8033: Fail next trigger create in TC 8034: Fail next index create in TC +8035: Fail next trigger drop in TC +8036: Fail next index drop in TC System Restart: --------------- diff --git a/ndb/src/kernel/blocks/backup/Backup.cpp b/ndb/src/kernel/blocks/backup/Backup.cpp index 3334d69ae89..ec5c7a5d588 100644 --- a/ndb/src/kernel/blocks/backup/Backup.cpp +++ b/ndb/src/kernel/blocks/backup/Backup.cpp @@ -69,6 +69,9 @@ static const Uint32 BACKUP_SEQUENCE = 0x1F000000; static Uint32 g_TypeOfStart = NodeState::ST_ILLEGAL_TYPE; +#define SEND_BACKUP_STARTED_FLAG(A) (((A) & 0x3) > 0) +#define SEND_BACKUP_COMPLETED_FLAG(A) (((A) & 0x3) > 1) + void Backup::execSTTOR(Signal* signal) { @@ -852,23 +855,24 @@ Backup::execBACKUP_REQ(Signal* signal) const Uint32 senderData = req->senderData; const BlockReference senderRef = signal->senderBlockRef(); const Uint32 dataLen32 = req->backupDataLen; // In 32 bit words - + const Uint32 flags = signal->getLength() > 2 ? req->flags : 2; + if(getOwnNodeId() != getMasterNodeId()) { jam(); - sendBackupRef(senderRef, signal, senderData, BackupRef::IAmNotMaster); + sendBackupRef(senderRef, flags, signal, senderData, BackupRef::IAmNotMaster); return; }//if if (m_diskless) { - sendBackupRef(senderRef, signal, senderData, + sendBackupRef(senderRef, flags, signal, senderData, BackupRef::CannotBackupDiskless); return; } if(dataLen32 != 0) { jam(); - sendBackupRef(senderRef, signal, senderData, + sendBackupRef(senderRef, flags, signal, senderData, BackupRef::BackupDefinitionNotImplemented); return; }//if @@ -883,7 +887,7 @@ Backup::execBACKUP_REQ(Signal* signal) c_backups.seize(ptr); if(ptr.i == RNIL) { jam(); - sendBackupRef(senderRef, signal, senderData, BackupRef::OutOfBackupRecord); + sendBackupRef(senderRef, flags, signal, senderData, BackupRef::OutOfBackupRecord); return; }//if @@ -894,6 +898,7 @@ Backup::execBACKUP_REQ(Signal* signal) ptr.p->errorCode = 0; ptr.p->clientRef = senderRef; ptr.p->clientData = senderData; + ptr.p->flags = flags; ptr.p->masterRef = reference(); ptr.p->nodes = c_aliveNodes; ptr.p->backupId = 0; @@ -931,20 +936,23 @@ void Backup::sendBackupRef(Signal* signal, BackupRecordPtr ptr, Uint32 errorCode) { jam(); - sendBackupRef(ptr.p->clientRef, signal, ptr.p->clientData, errorCode); + sendBackupRef(ptr.p->clientRef, ptr.p->flags, signal, ptr.p->clientData, errorCode); cleanup(signal, ptr); } void -Backup::sendBackupRef(BlockReference senderRef, Signal *signal, +Backup::sendBackupRef(BlockReference senderRef, Uint32 flags, Signal *signal, Uint32 senderData, Uint32 errorCode) { jam(); - BackupRef* ref = (BackupRef*)signal->getDataPtrSend(); - ref->senderData = senderData; - ref->errorCode = errorCode; - ref->masterRef = numberToRef(BACKUP, getMasterNodeId()); - sendSignal(senderRef, GSN_BACKUP_REF, signal, BackupRef::SignalLength, JBB); + if (SEND_BACKUP_STARTED_FLAG(flags)) + { + BackupRef* ref = (BackupRef*)signal->getDataPtrSend(); + ref->senderData = senderData; + ref->errorCode = errorCode; + ref->masterRef = numberToRef(BACKUP, getMasterNodeId()); + sendSignal(senderRef, GSN_BACKUP_REF, signal, BackupRef::SignalLength, JBB); + } if(errorCode != BackupRef::IAmNotMaster){ signal->theData[0] = EventReport::BackupFailedToStart; @@ -1098,6 +1106,7 @@ Backup::sendDefineBackupReq(Signal *signal, BackupRecordPtr ptr) req->backupKey[1] = ptr.p->backupKey[1]; req->nodes = ptr.p->nodes; req->backupDataLen = ptr.p->backupDataLen; + req->flags = ptr.p->flags; ptr.p->masterData.gsn = GSN_DEFINE_BACKUP_REQ; ptr.p->masterData.sendCounter = ptr.p->nodes; @@ -1193,13 +1202,18 @@ Backup::defineBackupReply(Signal* signal, BackupRecordPtr ptr, Uint32 nodeId) /** * Reply to client */ - BackupConf * conf = (BackupConf*)signal->getDataPtrSend(); - conf->backupId = ptr.p->backupId; - conf->senderData = ptr.p->clientData; - conf->nodes = ptr.p->nodes; - sendSignal(ptr.p->clientRef, GSN_BACKUP_CONF, signal, - BackupConf::SignalLength, JBB); - + CRASH_INSERTION((10034)); + + if (SEND_BACKUP_STARTED_FLAG(ptr.p->flags)) + { + BackupConf * conf = (BackupConf*)signal->getDataPtrSend(); + conf->backupId = ptr.p->backupId; + conf->senderData = ptr.p->clientData; + conf->nodes = ptr.p->nodes; + sendSignal(ptr.p->clientRef, GSN_BACKUP_CONF, signal, + BackupConf::SignalLength, JBB); + } + signal->theData[0] = EventReport::BackupStarted; signal->theData[1] = ptr.p->clientRef; signal->theData[2] = ptr.p->backupId; @@ -2080,19 +2094,22 @@ Backup::stopBackupReply(Signal* signal, BackupRecordPtr ptr, Uint32 nodeId) if(!ptr.p->checkError()) { - BackupCompleteRep * rep = (BackupCompleteRep*)signal->getDataPtrSend(); - rep->backupId = ptr.p->backupId; - rep->senderData = ptr.p->clientData; - rep->startGCP = ptr.p->startGCP; - rep->stopGCP = ptr.p->stopGCP; - rep->noOfBytes = ptr.p->noOfBytes; - rep->noOfRecords = ptr.p->noOfRecords; - rep->noOfLogBytes = ptr.p->noOfLogBytes; - rep->noOfLogRecords = ptr.p->noOfLogRecords; - rep->nodes = ptr.p->nodes; - sendSignal(ptr.p->clientRef, GSN_BACKUP_COMPLETE_REP, signal, - BackupCompleteRep::SignalLength, JBB); - + if (SEND_BACKUP_COMPLETED_FLAG(ptr.p->flags)) + { + BackupCompleteRep * rep = (BackupCompleteRep*)signal->getDataPtrSend(); + rep->backupId = ptr.p->backupId; + rep->senderData = ptr.p->clientData; + rep->startGCP = ptr.p->startGCP; + rep->stopGCP = ptr.p->stopGCP; + rep->noOfBytes = ptr.p->noOfBytes; + rep->noOfRecords = ptr.p->noOfRecords; + rep->noOfLogBytes = ptr.p->noOfLogBytes; + rep->noOfLogRecords = ptr.p->noOfLogRecords; + rep->nodes = ptr.p->nodes; + sendSignal(ptr.p->clientRef, GSN_BACKUP_COMPLETE_REP, signal, + BackupCompleteRep::SignalLength, JBB); + } + signal->theData[0] = EventReport::BackupCompleted; signal->theData[1] = ptr.p->clientRef; signal->theData[2] = ptr.p->backupId; @@ -2129,13 +2146,15 @@ Backup::masterAbort(Signal* signal, BackupRecordPtr ptr) return; } - BackupAbortRep* rep = (BackupAbortRep*)signal->getDataPtrSend(); - rep->backupId = ptr.p->backupId; - rep->senderData = ptr.p->clientData; - rep->reason = ptr.p->errorCode; - sendSignal(ptr.p->clientRef, GSN_BACKUP_ABORT_REP, signal, - BackupAbortRep::SignalLength, JBB); - + if (SEND_BACKUP_COMPLETED_FLAG(ptr.p->flags)) + { + BackupAbortRep* rep = (BackupAbortRep*)signal->getDataPtrSend(); + rep->backupId = ptr.p->backupId; + rep->senderData = ptr.p->clientData; + rep->reason = ptr.p->errorCode; + sendSignal(ptr.p->clientRef, GSN_BACKUP_ABORT_REP, signal, + BackupAbortRep::SignalLength, JBB); + } signal->theData[0] = EventReport::BackupAborted; signal->theData[1] = ptr.p->clientRef; signal->theData[2] = ptr.p->backupId; @@ -2267,6 +2286,13 @@ Backup::execDEFINE_BACKUP_REQ(Signal* signal) ptr.p->errorCode = 0; ptr.p->clientRef = req->clientRef; ptr.p->clientData = req->clientData; + if(senderRef == reference()) + ptr.p->flags = req->flags; + else + ptr.p->flags = req->flags & ~((Uint32)0x3); /* remove waitCompleted flags + * as non master should never + * reply + */ ptr.p->masterRef = senderRef; ptr.p->nodes = req->nodes; ptr.p->backupId = backupId; diff --git a/ndb/src/kernel/blocks/backup/Backup.hpp b/ndb/src/kernel/blocks/backup/Backup.hpp index 7bcea5655b4..f3d180b9467 100644 --- a/ndb/src/kernel/blocks/backup/Backup.hpp +++ b/ndb/src/kernel/blocks/backup/Backup.hpp @@ -413,6 +413,7 @@ public: Uint32 clientRef; Uint32 clientData; + Uint32 flags; Uint32 backupId; Uint32 backupKey[2]; Uint32 masterRef; @@ -595,7 +596,7 @@ public: bool insertFileHeader(BackupFormat::FileType, BackupRecord*, BackupFile*); void sendBackupRef(Signal* signal, BackupRecordPtr ptr, Uint32 errorCode); - void sendBackupRef(BlockReference ref, Signal *signal, + void sendBackupRef(BlockReference ref, Uint32 flags, Signal *signal, Uint32 senderData, Uint32 errorCode); void dumpUsedResources(); void cleanup(Signal*, BackupRecordPtr ptr); diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp index 3d5eb0c52aa..90f4ac73411 100644 --- a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp +++ b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp @@ -6740,14 +6740,16 @@ Dbdict::createIndex_sendReply(Signal* signal, OpCreateIndexPtr opPtr, CreateIndxRef* rep = (CreateIndxRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_CREATE_INDX_CONF; Uint32 length = CreateIndxConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); if (opPtr.p->m_requestType == CreateIndxReq::RT_DICT_ABORT) sendRef = false; } else { + sendRef = opPtr.p->hasError(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); rep->setRequestType(opPtr.p->m_request.getRequestType()); @@ -6816,11 +6818,8 @@ Dbdict::execDROP_INDX_REQ(Signal* signal) goto error; } - if (tmp.p->indexState == TableRecord::IS_DROPPING){ - jam(); - err = DropIndxRef::IndexNotFound; - goto error; - } + if (tmp.p->indexState != TableRecord::IS_ONLINE) + req->addRequestFlag(RequestFlag::RF_FORCE); tmp.p->indexState = TableRecord::IS_DROPPING; @@ -7083,14 +7082,16 @@ Dbdict::dropIndex_sendReply(Signal* signal, OpDropIndexPtr opPtr, DropIndxRef* rep = (DropIndxRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_DROP_INDX_CONF; Uint32 length = DropIndxConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); if (opPtr.p->m_requestType == DropIndxReq::RT_DICT_ABORT) sendRef = false; } else { + sendRef = opPtr.p->hasError(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); rep->setRequestType(opPtr.p->m_request.getRequestType()); @@ -9607,7 +9608,7 @@ Dbdict::alterIndex_fromCreateTc(Signal* signal, OpAlterIndexPtr opPtr) { jam(); // mark created in local TC - if (! opPtr.p->hasError()) { + if (! opPtr.p->hasLastError()) { TableRecordPtr indexPtr; c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); indexPtr.p->indexLocal |= TableRecord::IL_CREATED_TC; @@ -9623,9 +9624,10 @@ Dbdict::alterIndex_toDropTc(Signal* signal, OpAlterIndexPtr opPtr) jam(); TableRecordPtr indexPtr; c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); - // broken index + // broken index allowed if force if (! (indexPtr.p->indexLocal & TableRecord::IL_CREATED_TC)) { jam(); + ndbrequire(opPtr.p->m_requestFlag & RequestFlag::RF_FORCE); alterIndex_sendReply(signal, opPtr, false); return; } @@ -9647,8 +9649,8 @@ Dbdict::alterIndex_fromDropTc(Signal* signal, OpAlterIndexPtr opPtr) { jam(); ndbrequire(opPtr.p->m_requestType == AlterIndxReq::RT_DICT_TC); - if (! opPtr.p->hasError()) { - // mark dropped in local TC + // mark dropped locally + if (! opPtr.p->hasLastError()) { TableRecordPtr indexPtr; c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId()); indexPtr.p->indexLocal &= ~TableRecord::IL_CREATED_TC; @@ -9786,51 +9788,46 @@ Dbdict::alterIndex_toDropTrigger(Signal* signal, OpAlterIndexPtr opPtr) req->setUserRef(reference()); req->setConnectionPtr(opPtr.p->key); req->setRequestType(DropTrigReq::RT_ALTER_INDEX); + req->addRequestFlag(opPtr.p->m_requestFlag); req->setTableId(opPtr.p->m_request.getTableId()); req->setIndexId(opPtr.p->m_request.getIndexId()); req->setTriggerInfo(0); // not used opPtr.p->m_triggerCounter = 0; - // insert - if (indexPtr.p->insertTriggerId != RNIL) { + if (indexPtr.p->isHashIndex()) { + // insert req->setTriggerId(indexPtr.p->insertTriggerId); sendSignal(reference(), GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB); opPtr.p->m_triggerCounter++; - } - // update - if (indexPtr.p->updateTriggerId != RNIL) { + // update req->setTriggerId(indexPtr.p->updateTriggerId); sendSignal(reference(), GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB); opPtr.p->m_triggerCounter++; - } - // delete - if (indexPtr.p->deleteTriggerId != RNIL) { + // delete req->setTriggerId(indexPtr.p->deleteTriggerId); sendSignal(reference(), GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB); opPtr.p->m_triggerCounter++; + // build + if (indexPtr.p->buildTriggerId != RNIL) { + req->setTriggerId(indexPtr.p->buildTriggerId); + sendSignal(reference(), GSN_DROP_TRIG_REQ, + signal, DropTrigReq::SignalLength, JBB); + opPtr.p->m_triggerCounter++; + } + return; } - // custom - if (indexPtr.p->customTriggerId != RNIL) { + if (indexPtr.p->isOrderedIndex()) { + // custom + req->addRequestFlag(RequestFlag::RF_NOTCTRIGGER); req->setTriggerId(indexPtr.p->customTriggerId); sendSignal(reference(), GSN_DROP_TRIG_REQ, signal, DropTrigReq::SignalLength, JBB); opPtr.p->m_triggerCounter++; + return; } - // build - if (indexPtr.p->buildTriggerId != RNIL) { - req->setTriggerId(indexPtr.p->buildTriggerId); - sendSignal(reference(), GSN_DROP_TRIG_REQ, - signal, DropTrigReq::SignalLength, JBB); - opPtr.p->m_triggerCounter++; - } - if (opPtr.p->m_triggerCounter == 0) { - // drop in each TC - jam(); - opPtr.p->m_requestType = AlterIndxReq::RT_DICT_TC; - alterIndex_sendSlaveReq(signal, opPtr); - } + ndbrequire(false); } void @@ -9948,14 +9945,16 @@ Dbdict::alterIndex_sendReply(Signal* signal, OpAlterIndexPtr opPtr, AlterIndxRef* rep = (AlterIndxRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_ALTER_INDX_CONF; Uint32 length = AlterIndxConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); if (opPtr.p->m_requestType == AlterIndxReq::RT_DICT_ABORT) sendRef = false; } else { + sendRef = opPtr.p->hasError(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); rep->setRequestType(opPtr.p->m_request.getRequestType()); @@ -10368,8 +10367,10 @@ Dbdict::buildIndex_toOnline(Signal* signal, OpBuildIndexPtr opPtr) req->setUserRef(reference()); req->setConnectionPtr(opPtr.p->key); if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TC) { + jam(); req->setRequestType(AlterIndxReq::RT_TC); } else if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TUX) { + jam(); req->setRequestType(AlterIndxReq::RT_TUX); } else { ndbrequire(false); @@ -10380,8 +10381,10 @@ Dbdict::buildIndex_toOnline(Signal* signal, OpBuildIndexPtr opPtr) req->setOnline(true); BlockReference blockRef = 0; if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TC) { + jam(); blockRef = calcTcBlockRef(getOwnNodeId()); } else if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TUX) { + jam(); blockRef = calcTuxBlockRef(getOwnNodeId()); } else { ndbrequire(false); @@ -10408,15 +10411,14 @@ Dbdict::buildIndex_sendSlaveReq(Signal* signal, OpBuildIndexPtr opPtr) req->setConnectionPtr(opPtr.p->key); req->setRequestType(opPtr.p->m_requestType); req->addRequestFlag(opPtr.p->m_requestFlag); - if(opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) - { + if(opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) { + jam(); opPtr.p->m_signalCounter.clearWaitingFor(); opPtr.p->m_signalCounter.setWaitingFor(getOwnNodeId()); sendSignal(reference(), GSN_BUILDINDXREQ, signal, BuildIndxReq::SignalLength, JBB); - } - else - { + } else { + jam(); opPtr.p->m_signalCounter = c_aliveNodes; NodeReceiverGroup rg(DBDICT, c_aliveNodes); sendSignal(rg, GSN_BUILDINDXREQ, @@ -10431,14 +10433,16 @@ Dbdict::buildIndex_sendReply(Signal* signal, OpBuildIndexPtr opPtr, BuildIndxRef* rep = (BuildIndxRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_BUILDINDXCONF; Uint32 length = BuildIndxConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_ABORT) sendRef = false; } else { + sendRef = opPtr.p->hasError(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); rep->setRequestType(opPtr.p->m_request.getRequestType()); @@ -10925,14 +10929,16 @@ Dbdict::createTrigger_sendReply(Signal* signal, OpCreateTriggerPtr opPtr, CreateTrigRef* rep = (CreateTrigRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_CREATE_TRIG_CONF; Uint32 length = CreateTrigConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); if (opPtr.p->m_requestType == CreateTrigReq::RT_DICT_ABORT) sendRef = false; } else { + sendRef = opPtr.p->hasError(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); rep->setRequestType(opPtr.p->m_request.getRequestType()); @@ -11020,8 +11026,10 @@ Dbdict::execDROP_TRIG_REQ(Signal* signal) OpDropTrigger opBad; opPtr.p = &opBad; opPtr.p->save(req); - opPtr.p->m_errorCode = DropTrigRef::TriggerNotFound; - opPtr.p->m_errorLine = __LINE__; + if (! (req->getRequestFlag() & RequestFlag::RF_FORCE)) { + opPtr.p->m_errorCode = DropTrigRef::TriggerNotFound; + opPtr.p->m_errorLine = __LINE__; + } dropTrigger_sendReply(signal, opPtr, true); return; } @@ -11188,6 +11196,7 @@ Dbdict::dropTrigger_toAlterTrigger(Signal* signal, OpDropTriggerPtr opPtr) req->setUserRef(reference()); req->setConnectionPtr(opPtr.p->key); req->setRequestType(AlterTrigReq::RT_DROP_TRIGGER); + req->addRequestFlag(opPtr.p->m_requestFlag); req->setTableId(opPtr.p->m_request.getTableId()); req->setTriggerId(opPtr.p->m_request.getTriggerId()); req->setTriggerInfo(0); // not used @@ -11283,14 +11292,16 @@ Dbdict::dropTrigger_sendReply(Signal* signal, OpDropTriggerPtr opPtr, DropTrigRef* rep = (DropTrigRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_DROP_TRIG_CONF; Uint32 length = DropTrigConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); if (opPtr.p->m_requestType == DropTrigReq::RT_DICT_ABORT) sendRef = false; } else { + sendRef = opPtr.p->hasError(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); rep->setRequestType(opPtr.p->m_request.getRequestType()); @@ -11514,28 +11525,37 @@ Dbdict::alterTrigger_recvReply(Signal* signal, const AlterTrigConf* conf, if (! (opPtr.p->m_request.getRequestFlag() & RequestFlag::RF_NOTCTRIGGER)) { if (requestType == AlterTrigReq::RT_DICT_PREPARE) { jam(); - if (opPtr.p->m_request.getOnline()) + if (opPtr.p->m_request.getOnline()) { + jam(); opPtr.p->m_requestType = AlterTrigReq::RT_DICT_TC; - else + } else { + jam(); opPtr.p->m_requestType = AlterTrigReq::RT_DICT_LQH; + } alterTrigger_sendSlaveReq(signal, opPtr); return; } if (requestType == AlterTrigReq::RT_DICT_TC) { jam(); - if (opPtr.p->m_request.getOnline()) + if (opPtr.p->m_request.getOnline()) { + jam(); opPtr.p->m_requestType = AlterTrigReq::RT_DICT_LQH; - else + } else { + jam(); opPtr.p->m_requestType = AlterTrigReq::RT_DICT_COMMIT; + } alterTrigger_sendSlaveReq(signal, opPtr); return; } if (requestType == AlterTrigReq::RT_DICT_LQH) { jam(); - if (opPtr.p->m_request.getOnline()) + if (opPtr.p->m_request.getOnline()) { + jam(); opPtr.p->m_requestType = AlterTrigReq::RT_DICT_COMMIT; - else + } else { + jam(); opPtr.p->m_requestType = AlterTrigReq::RT_DICT_TC; + } alterTrigger_sendSlaveReq(signal, opPtr); return; } @@ -11595,8 +11615,10 @@ Dbdict::alterTrigger_toCreateLocal(Signal* signal, OpAlterTriggerPtr opPtr) req->setUserRef(reference()); req->setConnectionPtr(opPtr.p->key); if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + jam(); req->setRequestType(CreateTrigReq::RT_TC); } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + jam(); req->setRequestType(CreateTrigReq::RT_LQH); } else { ndbassert(false); @@ -11613,8 +11635,10 @@ Dbdict::alterTrigger_toCreateLocal(Signal* signal, OpAlterTriggerPtr opPtr) req->setReceiverRef(opPtr.p->m_request.getReceiverRef()); BlockReference blockRef = 0; if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + jam(); blockRef = calcTcBlockRef(getOwnNodeId()); } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + jam(); blockRef = calcLqhBlockRef(getOwnNodeId()); } else { ndbassert(false); @@ -11628,13 +11652,15 @@ void Dbdict::alterTrigger_fromCreateLocal(Signal* signal, OpAlterTriggerPtr opPtr) { jam(); - if (! opPtr.p->hasError()) { + if (! opPtr.p->hasLastError()) { // mark created locally TriggerRecordPtr triggerPtr; c_triggerRecordPool.getPtr(triggerPtr, opPtr.p->m_request.getTriggerId()); if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + jam(); triggerPtr.p->triggerLocal |= TriggerRecord::TL_CREATED_TC; } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + jam(); triggerPtr.p->triggerLocal |= TriggerRecord::TL_CREATED_LQH; } else { ndbrequire(false); @@ -11654,17 +11680,21 @@ Dbdict::alterTrigger_toDropLocal(Signal* signal, OpAlterTriggerPtr opPtr) req->setUserRef(reference()); req->setConnectionPtr(opPtr.p->key); if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { - // broken trigger + jam(); + // broken trigger allowed if force if (! (triggerPtr.p->triggerLocal & TriggerRecord::TL_CREATED_TC)) { jam(); + ndbrequire(opPtr.p->m_requestFlag & RequestFlag::RF_FORCE); alterTrigger_sendReply(signal, opPtr, false); return; } req->setRequestType(DropTrigReq::RT_TC); } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { - // broken trigger + jam(); + // broken trigger allowed if force if (! (triggerPtr.p->triggerLocal & TriggerRecord::TL_CREATED_LQH)) { jam(); + ndbrequire(opPtr.p->m_requestFlag & RequestFlag::RF_FORCE); alterTrigger_sendReply(signal, opPtr, false); return; } @@ -11682,8 +11712,10 @@ Dbdict::alterTrigger_toDropLocal(Signal* signal, OpAlterTriggerPtr opPtr) req->setMonitorAllAttributes(triggerPtr.p->monitorAllAttributes); BlockReference blockRef = 0; if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + jam(); blockRef = calcTcBlockRef(getOwnNodeId()); } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + jam(); blockRef = calcLqhBlockRef(getOwnNodeId()); } else { ndbassert(false); @@ -11696,13 +11728,15 @@ void Dbdict::alterTrigger_fromDropLocal(Signal* signal, OpAlterTriggerPtr opPtr) { jam(); - if (! opPtr.p->hasError()) { + if (! opPtr.p->hasLastError()) { // mark dropped locally TriggerRecordPtr triggerPtr; c_triggerRecordPool.getPtr(triggerPtr, opPtr.p->m_request.getTriggerId()); if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) { + jam(); triggerPtr.p->triggerLocal &= ~TriggerRecord::TL_CREATED_TC; } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) { + jam(); triggerPtr.p->triggerLocal &= ~TriggerRecord::TL_CREATED_LQH; } else { ndbrequire(false); @@ -11759,8 +11793,9 @@ Dbdict::alterTrigger_sendReply(Signal* signal, OpAlterTriggerPtr opPtr, AlterTrigRef* rep = (AlterTrigRef*)signal->getDataPtrSend(); Uint32 gsn = GSN_ALTER_TRIG_CONF; Uint32 length = AlterTrigConf::InternalLength; - bool sendRef = opPtr.p->hasError(); + bool sendRef; if (! toUser) { + sendRef = opPtr.p->hasLastError(); rep->setUserRef(opPtr.p->m_coordinatorRef); rep->setConnectionPtr(opPtr.p->key); rep->setRequestType(opPtr.p->m_requestType); @@ -11771,6 +11806,7 @@ Dbdict::alterTrigger_sendReply(Signal* signal, OpAlterTriggerPtr opPtr, jam(); } } else { + sendRef = opPtr.p->hasError(); jam(); rep->setUserRef(opPtr.p->m_request.getUserRef()); rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr()); diff --git a/ndb/src/kernel/blocks/dbdict/Dbdict.hpp b/ndb/src/kernel/blocks/dbdict/Dbdict.hpp index abe253bcaa7..bcee4a52b6a 100644 --- a/ndb/src/kernel/blocks/dbdict/Dbdict.hpp +++ b/ndb/src/kernel/blocks/dbdict/Dbdict.hpp @@ -924,7 +924,8 @@ private: enum { RF_LOCAL = 1 << 0, // create on local node only RF_NOBUILD = 1 << 1, // no need to build index - RF_NOTCTRIGGER = 1 << 2 // alter trigger: no trigger in TC + RF_NOTCTRIGGER = 1 << 2, // alter trigger: no trigger in TC + RF_FORCE = 1 << 4 // force drop }; }; @@ -944,6 +945,7 @@ private: CreateIndxReq::RequestType m_requestType; Uint32 m_requestFlag; // error info + CreateIndxRef::ErrorCode m_lastError; CreateIndxRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -955,6 +957,7 @@ private: m_coordinatorRef = 0; m_requestType = CreateIndxReq::RT_UNDEFINED; m_requestFlag = 0; + m_lastError = CreateIndxRef::NoError; m_errorCode = CreateIndxRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -964,34 +967,49 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != CreateIndxRef::NoError; + } bool hasError() { return m_errorCode != CreateIndxRef::NoError; } void setError(const CreateIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = CreateIndxRef::NoError; + if (ref != 0) { + m_lastError = ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const CreateTableRef* ref) { - if (ref != 0 && ! hasError()) { + m_lastError = CreateIndxRef::NoError; + if (ref != 0) { switch (ref->getErrorCode()) { case CreateTableRef::TableAlreadyExist: - m_errorCode = CreateIndxRef::IndexExists; + m_lastError = CreateIndxRef::IndexExists; break; default: - m_errorCode = (CreateIndxRef::ErrorCode)ref->getErrorCode(); + m_lastError = (CreateIndxRef::ErrorCode)ref->getErrorCode(); break; } - m_errorLine = ref->getErrorLine(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + } } } void setError(const AlterIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (CreateIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = CreateIndxRef::NoError; + if (ref != 0) { + m_lastError = (CreateIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } }; @@ -1010,6 +1028,7 @@ private: DropIndxReq::RequestType m_requestType; Uint32 m_requestFlag; // error info + DropIndxRef::ErrorCode m_lastError; DropIndxRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -1021,6 +1040,7 @@ private: m_coordinatorRef = 0; m_requestType = DropIndxReq::RT_UNDEFINED; m_requestFlag = 0; + m_lastError = DropIndxRef::NoError; m_errorCode = DropIndxRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -1030,44 +1050,59 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != DropIndxRef::NoError; + } bool hasError() { return m_errorCode != DropIndxRef::NoError; } void setError(const DropIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = DropIndxRef::NoError; + if (ref != 0) { + m_lastError = ref->getErrorCode(); + if (! hasError()) { + m_errorCode = ref->getErrorCode(); + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const AlterIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (DropIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = DropIndxRef::NoError; + if (ref != 0) { + m_lastError = (DropIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const DropTableRef* ref) { - if (ref != 0 && ! hasError()) { - switch(ref->errorCode) { - case(DropTableRef::Busy): - m_errorCode = DropIndxRef::Busy; + m_lastError = DropIndxRef::NoError; + if (ref != 0) { + switch (ref->errorCode) { + case DropTableRef::Busy: + m_lastError = DropIndxRef::Busy; break; - case(DropTableRef::NoSuchTable): - m_errorCode = DropIndxRef::IndexNotFound; + case DropTableRef::NoSuchTable: + m_lastError = DropIndxRef::IndexNotFound; break; - case(DropTableRef::DropInProgress): - m_errorCode = DropIndxRef::Busy; + case DropTableRef::DropInProgress: + m_lastError = DropIndxRef::Busy; break; - case(DropTableRef::NoDropTableRecordAvailable): - m_errorCode = DropIndxRef::Busy; + case DropTableRef::NoDropTableRecordAvailable: + m_lastError = DropIndxRef::Busy; break; default: - m_errorCode = (DropIndxRef::ErrorCode)ref->errorCode; + m_lastError = (DropIndxRef::ErrorCode)ref->errorCode; break; } - //m_errorLine = ref->getErrorLine(); - //m_errorNode = ref->getErrorNode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = 0; + m_errorNode = 0; + } } } }; @@ -1088,6 +1123,7 @@ private: AlterIndxReq::RequestType m_requestType; Uint32 m_requestFlag; // error info + AlterIndxRef::ErrorCode m_lastError; AlterIndxRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -1100,6 +1136,7 @@ private: m_coordinatorRef = 0; m_requestType = AlterIndxReq::RT_UNDEFINED; m_requestFlag = 0; + m_lastError = AlterIndxRef::NoError; m_errorCode = AlterIndxRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -1110,47 +1147,76 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != AlterIndxRef::NoError; + } bool hasError() { return m_errorCode != AlterIndxRef::NoError; } void setError(const AlterIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterIndxRef::NoError; + if (ref != 0) { + m_lastError = ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const CreateIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterIndxRef::NoError; + if (ref != 0) { + m_lastError = (AlterIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const DropIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterIndxRef::NoError; + if (ref != 0) { + m_lastError = (AlterIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const BuildIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterIndxRef::ErrorCode)ref->getErrorCode(); + m_lastError = AlterIndxRef::NoError; + if (ref != 0) { + m_lastError = (AlterIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = 0; + m_errorNode = 0; + } } } void setError(const CreateTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterIndxRef::NoError; + if (ref != 0) { + m_lastError = (AlterIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const DropTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterIndxRef::NoError; + if (ref != 0) { + m_lastError = (AlterIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } }; @@ -1172,6 +1238,7 @@ private: Uint32 m_requestFlag; Uint32 m_constrTriggerId; // error info + BuildIndxRef::ErrorCode m_lastError; BuildIndxRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -1183,7 +1250,7 @@ private: m_coordinatorRef = 0; m_requestType = BuildIndxReq::RT_UNDEFINED; m_requestFlag = 0; -// Uint32 m_constrTriggerId = RNIL; + m_lastError = BuildIndxRef::NoError; m_errorCode = BuildIndxRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -1193,33 +1260,54 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != BuildIndxRef::NoError; + } bool hasError() { return m_errorCode != BuildIndxRef::NoError; } void setError(const BuildIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = ref->getErrorCode(); + m_lastError = BuildIndxRef::NoError; + if (ref != 0) { + m_lastError = ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = 0; + m_errorNode = 0; + } } } void setError(const AlterIndxRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (BuildIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = BuildIndxRef::NoError; + if (ref != 0) { + m_lastError = (BuildIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const CreateTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (BuildIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = BuildIndxRef::NoError; + if (ref != 0) { + m_lastError = (BuildIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const DropTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (BuildIndxRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = BuildIndxRef::NoError; + if (ref != 0) { + m_lastError = (BuildIndxRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } }; @@ -1352,6 +1440,7 @@ private: CreateTrigReq::RequestType m_requestType; Uint32 m_requestFlag; // error info + CreateTrigRef::ErrorCode m_lastError; CreateTrigRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -1363,6 +1452,7 @@ private: m_coordinatorRef = 0; m_requestType = CreateTrigReq::RT_UNDEFINED; m_requestFlag = 0; + m_lastError = CreateTrigRef::NoError; m_errorCode = CreateTrigRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -1372,21 +1462,32 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != CreateTrigRef::NoError; + } bool hasError() { return m_errorCode != CreateTrigRef::NoError; } void setError(const CreateTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = CreateTrigRef::NoError; + if (ref != 0) { + m_lastError = ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const AlterTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (CreateTrigRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = CreateTrigRef::NoError; + if (ref != 0) { + m_lastError = (CreateTrigRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } }; @@ -1405,6 +1506,7 @@ private: DropTrigReq::RequestType m_requestType; Uint32 m_requestFlag; // error info + DropTrigRef::ErrorCode m_lastError; DropTrigRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -1416,6 +1518,7 @@ private: m_coordinatorRef = 0; m_requestType = DropTrigReq::RT_UNDEFINED; m_requestFlag = 0; + m_lastError = DropTrigRef::NoError; m_errorCode = DropTrigRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -1425,21 +1528,32 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != DropTrigRef::NoError; + } bool hasError() { return m_errorCode != DropTrigRef::NoError; } void setError(const DropTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = DropTrigRef::NoError; + if (ref != 0) { + m_lastError = ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const AlterTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (DropTrigRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = DropTrigRef::NoError; + if (ref != 0) { + m_lastError = (DropTrigRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } }; @@ -1460,6 +1574,7 @@ private: AlterTrigReq::RequestType m_requestType; Uint32 m_requestFlag; // error info + AlterTrigRef::ErrorCode m_lastError; AlterTrigRef::ErrorCode m_errorCode; Uint32 m_errorLine; Uint32 m_errorNode; @@ -1471,6 +1586,7 @@ private: m_coordinatorRef = 0; m_requestType = AlterTrigReq::RT_UNDEFINED; m_requestFlag = 0; + m_lastError = AlterTrigRef::NoError; m_errorCode = AlterTrigRef::NoError; m_errorLine = 0; m_errorNode = 0; @@ -1480,28 +1596,43 @@ private: m_requestType = req->getRequestType(); m_requestFlag = req->getRequestFlag(); } + bool hasLastError() { + return m_lastError != AlterTrigRef::NoError; + } bool hasError() { return m_errorCode != AlterTrigRef::NoError; } void setError(const AlterTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterTrigRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterTrigRef::NoError; + if (ref != 0) { + m_lastError = (AlterTrigRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const CreateTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterTrigRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterTrigRef::NoError; + if (ref != 0) { + m_lastError = (AlterTrigRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } void setError(const DropTrigRef* ref) { - if (ref != 0 && ! hasError()) { - m_errorCode = (AlterTrigRef::ErrorCode)ref->getErrorCode(); - m_errorLine = ref->getErrorLine(); - m_errorNode = ref->getErrorNode(); + m_lastError = AlterTrigRef::NoError; + if (ref != 0) { + m_lastError = (AlterTrigRef::ErrorCode)ref->getErrorCode(); + if (! hasError()) { + m_errorCode = m_lastError; + m_errorLine = ref->getErrorLine(); + m_errorNode = ref->getErrorNode(); + } } } }; diff --git a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp index 669be2b48f0..ca066b588e7 100644 --- a/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp +++ b/ndb/src/kernel/blocks/dbdih/DbdihMain.cpp @@ -9640,6 +9640,9 @@ void Dbdih::execLCP_FRAG_REP(Signal* signal) } bool tableDone = reportLcpCompletion(lcpReport); + + Uint32 started = lcpReport->maxGciStarted; + Uint32 completed = lcpReport->maxGciCompleted; if(tableDone){ jam(); @@ -9673,7 +9676,9 @@ void Dbdih::execLCP_FRAG_REP(Signal* signal) signal->theData[1] = nodeId; signal->theData[2] = tableId; signal->theData[3] = fragId; - sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 4, JBB); + signal->theData[4] = started; + signal->theData[5] = completed; + sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 6, JBB); #endif bool ok = false; @@ -10790,7 +10795,9 @@ void Dbdih::findMinGci(ReplicaRecordPtr fmgReplicaPtr, lcpNo = fmgReplicaPtr.p->nextLcp; do { ndbrequire(lcpNo < MAX_LCP_STORED); - if (fmgReplicaPtr.p->lcpStatus[lcpNo] == ZVALID) { + if (fmgReplicaPtr.p->lcpStatus[lcpNo] == ZVALID && + fmgReplicaPtr.p->maxGciStarted[lcpNo] <= coldgcp) + { jam(); keepGci = fmgReplicaPtr.p->maxGciCompleted[lcpNo]; oldestRestorableGci = fmgReplicaPtr.p->maxGciStarted[lcpNo]; @@ -10798,7 +10805,6 @@ void Dbdih::findMinGci(ReplicaRecordPtr fmgReplicaPtr, return; } else { jam(); - ndbrequire(fmgReplicaPtr.p->lcpStatus[lcpNo] == ZINVALID); if (fmgReplicaPtr.p->createGci[0] == fmgReplicaPtr.p->initialGci) { jam(); /*------------------------------------------------------------------- diff --git a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp index 836fc9398e5..951d1e90251 100644 --- a/ndb/src/kernel/blocks/dblqh/Dblqh.hpp +++ b/ndb/src/kernel/blocks/dblqh/Dblqh.hpp @@ -86,6 +86,17 @@ #define ZCURR_PAGE_INDEX 8 #define ZLAST_LOG_PREP_REF 10 #define ZPOS_DIRTY 11 +/* A number of debug items written in the page header of all log files */ +#define ZPOS_LOG_TIMER 12 +#define ZPOS_PAGE_I 13 +#define ZPOS_PLACE_WRITTEN_FROM 14 +#define ZPOS_PAGE_NO 15 +#define ZPOS_PAGE_FILE_NO 16 +#define ZPOS_WORD_WRITTEN 17 +#define ZPOS_IN_WRITING 18 +#define ZPOS_PREV_PAGE_NO 19 +#define ZPOS_IN_FREE_LIST 20 + /* ------------------------------------------------------------------------- */ /* CONSTANTS FOR THE VARIOUS REPLICA AND NODE TYPES. */ /* ------------------------------------------------------------------------- */ @@ -2278,7 +2289,7 @@ private: const LogPartRecordPtr &sltLogPartPtr); void checkGcpCompleted(Signal* signal, Uint32 pageWritten, Uint32 wordWritten); void initFsopenconf(Signal* signal); - void initFsrwconf(Signal* signal); + void initFsrwconf(Signal* signal, bool write); void initLfo(Signal* signal); void initLogfile(Signal* signal, Uint32 fileNo); void initLogpage(Signal* signal); @@ -2294,7 +2305,8 @@ private: void writeFileDescriptor(Signal* signal); void writeFileHeaderOpen(Signal* signal, Uint32 type); void writeInitMbyte(Signal* signal); - void writeSinglePage(Signal* signal, Uint32 pageNo, Uint32 wordWritten); + void writeSinglePage(Signal* signal, Uint32 pageNo, + Uint32 wordWritten, Uint32 place); void buildLinkedLogPageList(Signal* signal); void changeMbyte(Signal* signal); Uint32 checkIfExecLog(Signal* signal); @@ -2303,7 +2315,7 @@ private: void checkScanTcCompleted(Signal* signal); void checkSrCompleted(Signal* signal); void closeFile(Signal* signal, LogFileRecordPtr logFilePtr); - void completedLogPage(Signal* signal, Uint32 clpType); + void completedLogPage(Signal* signal, Uint32 clpType, Uint32 place); void deleteFragrec(Uint32 fragId); void deleteTransidHash(Signal* signal); void findLogfile(Signal* signal, @@ -2399,7 +2411,9 @@ private: void writeAbortLog(Signal* signal); void writeCommitLog(Signal* signal, LogPartRecordPtr regLogPartPtr); void writeCompletedGciLog(Signal* signal); - void writeDirty(Signal* signal); + void writeDbgInfoPageHeader(LogPageRecordPtr logPagePtr, Uint32 place, + Uint32 pageNo, Uint32 wordWritten); + void writeDirty(Signal* signal, Uint32 place); void writeKey(Signal* signal); void writeLogHeader(Signal* signal); void writeLogWord(Signal* signal, Uint32 data); diff --git a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp index 5e2e6dc392c..b6178227d31 100644 --- a/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp +++ b/ndb/src/kernel/blocks/dblqh/DblqhMain.cpp @@ -11749,42 +11749,34 @@ void Dblqh::execFSCLOSECONF(Signal* signal) ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); exitFromInvalidate(signal); return; - break; case LogFileRecord::CLOSING_INIT: jam(); closingInitLab(signal); return; - break; case LogFileRecord::CLOSING_SR: jam(); closingSrLab(signal); return; - break; case LogFileRecord::CLOSING_EXEC_SR: jam(); closeExecSrLab(signal); return; - break; case LogFileRecord::CLOSING_EXEC_SR_COMPLETED: jam(); closeExecSrCompletedLab(signal); return; - break; case LogFileRecord::CLOSING_WRITE_LOG: jam(); closeWriteLogLab(signal); return; - break; case LogFileRecord::CLOSING_EXEC_LOG: jam(); closeExecLogLab(signal); return; - break; default: jam(); systemErrorLab(signal); return; - break; }//switch }//Dblqh::execFSCLOSECONF() @@ -11802,77 +11794,64 @@ void Dblqh::execFSOPENCONF(Signal* signal) logFilePtr.p->logFileStatus = LogFileRecord::OPEN; readFileInInvalidate(signal); return; - break; case LogFileRecord::OPENING_INIT: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openFileInitLab(signal); return; - break; case LogFileRecord::OPEN_SR_FRONTPAGE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrFrontpageLab(signal); return; - break; case LogFileRecord::OPEN_SR_LAST_FILE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrLastFileLab(signal); return; - break; case LogFileRecord::OPEN_SR_NEXT_FILE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrNextFileLab(signal); return; - break; case LogFileRecord::OPEN_EXEC_SR_START: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openExecSrStartLab(signal); return; - break; case LogFileRecord::OPEN_EXEC_SR_NEW_MBYTE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openExecSrNewMbyteLab(signal); return; - break; case LogFileRecord::OPEN_SR_FOURTH_PHASE: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrFourthPhaseLab(signal); return; - break; case LogFileRecord::OPEN_SR_FOURTH_NEXT: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrFourthNextLab(signal); return; - break; case LogFileRecord::OPEN_SR_FOURTH_ZERO: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openSrFourthZeroLab(signal); return; - break; case LogFileRecord::OPENING_WRITE_LOG: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; return; - break; case LogFileRecord::OPEN_EXEC_LOG: jam(); logFilePtr.p->logFileStatus = LogFileRecord::OPEN; openExecLogLab(signal); return; - break; default: jam(); systemErrorLab(signal); return; - break; }//switch }//Dblqh::execFSOPENCONF() @@ -11883,7 +11862,7 @@ void Dblqh::execFSOPENCONF(Signal* signal) void Dblqh::execFSREADCONF(Signal* signal) { jamEntry(); - initFsrwconf(signal); + initFsrwconf(signal, false); switch (lfoPtr.p->lfoState) { case LogFileOperationRecord::READ_SR_LAST_MBYTE: @@ -11891,57 +11870,47 @@ void Dblqh::execFSREADCONF(Signal* signal) releaseLfo(signal); readSrLastMbyteLab(signal); return; - break; case LogFileOperationRecord::READ_SR_FRONTPAGE: jam(); releaseLfo(signal); readSrFrontpageLab(signal); return; - break; case LogFileOperationRecord::READ_SR_LAST_FILE: jam(); releaseLfo(signal); readSrLastFileLab(signal); return; - break; case LogFileOperationRecord::READ_SR_NEXT_FILE: jam(); releaseLfo(signal); readSrNextFileLab(signal); return; - break; case LogFileOperationRecord::READ_EXEC_SR: jam(); readExecSrLab(signal); return; - break; case LogFileOperationRecord::READ_EXEC_LOG: jam(); readExecLogLab(signal); return; - break; case LogFileOperationRecord::READ_SR_INVALIDATE_PAGES: jam(); invalidateLogAfterLastGCI(signal); return; - break; case LogFileOperationRecord::READ_SR_FOURTH_PHASE: jam(); releaseLfo(signal); readSrFourthPhaseLab(signal); return; - break; case LogFileOperationRecord::READ_SR_FOURTH_ZERO: jam(); releaseLfo(signal); readSrFourthZeroLab(signal); return; - break; default: jam(); systemErrorLab(signal); return; - break; }//switch }//Dblqh::execFSREADCONF() @@ -11998,63 +11967,52 @@ void Dblqh::execFSREADREF(Signal* signal) void Dblqh::execFSWRITECONF(Signal* signal) { jamEntry(); - initFsrwconf(signal); + initFsrwconf(signal, true); switch (lfoPtr.p->lfoState) { case LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES: jam(); invalidateLogAfterLastGCI(signal); return; - break; case LogFileOperationRecord::WRITE_PAGE_ZERO: jam(); writePageZeroLab(signal); return; - break; case LogFileOperationRecord::LAST_WRITE_IN_FILE: jam(); lastWriteInFileLab(signal); return; - break; case LogFileOperationRecord::INIT_WRITE_AT_END: jam(); initWriteEndLab(signal); return; - break; case LogFileOperationRecord::INIT_FIRST_PAGE: jam(); initFirstPageLab(signal); return; - break; case LogFileOperationRecord::WRITE_GCI_ZERO: jam(); writeGciZeroLab(signal); return; - break; case LogFileOperationRecord::WRITE_DIRTY: jam(); writeDirtyLab(signal); return; - break; case LogFileOperationRecord::WRITE_INIT_MBYTE: jam(); writeInitMbyteLab(signal); return; - break; case LogFileOperationRecord::ACTIVE_WRITE_LOG: jam(); writeLogfileLab(signal); return; - break; case LogFileOperationRecord::FIRST_PAGE_WRITE_IN_LOGFILE: jam(); firstPageWriteLab(signal); return; - break; default: jam(); systemErrorLab(signal); return; - break; }//switch }//Dblqh::execFSWRITECONF() @@ -12130,16 +12088,35 @@ void Dblqh::initFsopenconf(Signal* signal) /* ======= INITIATE WHEN RECEIVING FSREADCONF AND FSWRITECONF ======= */ /* */ /* ========================================================================= */ -void Dblqh::initFsrwconf(Signal* signal) +void Dblqh::initFsrwconf(Signal* signal, bool write) { + LogPageRecordPtr logP; + Uint32 noPages, totPages; lfoPtr.i = signal->theData[0]; ptrCheckGuard(lfoPtr, clfoFileSize, logFileOperationRecord); + totPages= lfoPtr.p->noPagesRw; logFilePtr.i = lfoPtr.p->logFileRec; ptrCheckGuard(logFilePtr, clogFileFileSize, logFileRecord); logPartPtr.i = logFilePtr.p->logPartRec; ptrCheckGuard(logPartPtr, clogPartFileSize, logPartRecord); logPagePtr.i = lfoPtr.p->firstLfoPage; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); + logP= logPagePtr; + noPages= 1; + ndbassert(totPages > 0); + for (;;) + { + logP.p->logPageWord[ZPOS_IN_WRITING]= 0; + logP.p->logPageWord[ZPOS_IN_FREE_LIST]= 0; + if (noPages == totPages) + return; + if (write) + logP.i= logP.p->logPageWord[ZNEXT_PAGE]; + else + logP.i= lfoPtr.p->logPageArray[noPages]; + ptrCheckGuard(logP, clogPageFileSize, logPageRecord); + noPages++; + } }//Dblqh::initFsrwconf() /* ######################################################################### */ @@ -12227,7 +12204,7 @@ void Dblqh::timeSup(Signal* signal) ndbrequire(wordWritten < ZPAGE_SIZE); if (logFilePtr.p->noLogpagesInBuffer > 0) { jam(); - completedLogPage(signal, ZENFORCE_WRITE); + completedLogPage(signal, ZENFORCE_WRITE, __LINE__); /*---------------------------------------------------------------------------*/ /*SINCE WE ARE ONLY WRITING PART OF THE LAST PAGE WE HAVE TO UPDATE THE WORD */ /*WRITTEN TO REFLECT THE REAL LAST WORD WRITTEN. WE ALSO HAVE TO MOVE THE */ @@ -12249,7 +12226,8 @@ void Dblqh::timeSup(Signal* signal) releaseLogpage(signal); } else { jam(); - writeSinglePage(signal, logFilePtr.p->currentFilepage, wordWritten); + writeSinglePage(signal, logFilePtr.p->currentFilepage, + wordWritten, __LINE__); lfoPtr.p->lfoState = LogFileOperationRecord::ACTIVE_WRITE_LOG; }//if }//if @@ -12385,7 +12363,7 @@ void Dblqh::firstPageWriteLab(Signal* signal) logPagePtr.i = logFilePtr.p->logPageZero; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] = fileNo; - writeSinglePage(signal, 0, ZPAGE_SIZE - 1); + writeSinglePage(signal, 0, ZPAGE_SIZE - 1, __LINE__); lfoPtr.p->logFileRec = currLogFile; lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_PAGE_ZERO; return; @@ -12474,7 +12452,7 @@ void Dblqh::lastWriteInFileLab(Signal* signal) logPagePtr.i = logFilePtr.p->logPageZero; ptrCheckGuard(logPagePtr, clogPageFileSize, logPageRecord); logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + ZPOS_FILE_NO] = fileNo; - writeSinglePage(signal, 0, ZPAGE_SIZE - 1); + writeSinglePage(signal, 0, ZPAGE_SIZE - 1, __LINE__); lfoPtr.p->logFileRec = currLogFile; lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_PAGE_ZERO; return; @@ -12509,7 +12487,8 @@ void Dblqh::openFileInitLab(Signal* signal) { logFilePtr.p->logFileStatus = LogFileRecord::OPEN_INIT; seizeLogpage(signal); - writeSinglePage(signal, (ZNO_MBYTES_IN_FILE * ZPAGES_IN_MBYTE) - 1, ZPAGE_SIZE - 1); + writeSinglePage(signal, (ZNO_MBYTES_IN_FILE * ZPAGES_IN_MBYTE) - 1, + ZPAGE_SIZE - 1, __LINE__); lfoPtr.p->lfoState = LogFileOperationRecord::INIT_WRITE_AT_END; return; }//Dblqh::openFileInitLab() @@ -12550,7 +12529,7 @@ void Dblqh::initFirstPageLab(Signal* signal) logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 1; logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE] = ZCOMPLETED_GCI_TYPE; logPagePtr.p->logPageWord[ZPAGE_HEADER_SIZE + 1] = 1; - writeSinglePage(signal, 1, ZPAGE_SIZE - 1); + writeSinglePage(signal, 1, ZPAGE_SIZE - 1, __LINE__); lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_GCI_ZERO; return; }//if @@ -12852,17 +12831,13 @@ void Dblqh::releaseLogpage(Signal* signal) { #ifdef VM_TRACE // Check that log page isn't already in free list - LogPageRecordPtr TlogPagePtr; - TlogPagePtr.i = cfirstfreeLogPage; - while (TlogPagePtr.i != RNIL){ - ptrCheckGuard(TlogPagePtr, clogPageFileSize, logPageRecord); - ndbrequire(TlogPagePtr.i != logPagePtr.i); - TlogPagePtr.i = TlogPagePtr.p->logPageWord[ZNEXT_PAGE]; - } + ndbrequire(logPagePtr.p->logPageWord[ZPOS_IN_FREE_LIST] == 0); #endif cnoOfLogPages++; logPagePtr.p->logPageWord[ZNEXT_PAGE] = cfirstfreeLogPage; + logPagePtr.p->logPageWord[ZPOS_IN_WRITING]= 0; + logPagePtr.p->logPageWord[ZPOS_IN_FREE_LIST]= 1; cfirstfreeLogPage = logPagePtr.i; }//Dblqh::releaseLogpage() @@ -12908,6 +12883,7 @@ void Dblqh::seizeLogpage(Signal* signal) /* ------------------------------------------------------------------------- */ cfirstfreeLogPage = logPagePtr.p->logPageWord[ZNEXT_PAGE]; logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; + logPagePtr.p->logPageWord[ZPOS_IN_FREE_LIST] = 0; }//Dblqh::seizeLogpage() /* ------------------------------------------------------------------------- */ @@ -13015,7 +12991,7 @@ WMO_LOOP: /* LOG FILE. THIS HAS SPECIAL SIGNIFANCE TO FIND */ /* THE END OF THE LOG AT SYSTEM RESTART. */ /* ------------------------------------------------------- */ - writeSinglePage(signal, 0, ZPAGE_SIZE - 1); + writeSinglePage(signal, 0, ZPAGE_SIZE - 1, __LINE__); if (wmoType == ZINIT) { jam(); lfoPtr.p->lfoState = LogFileOperationRecord::INIT_FIRST_PAGE; @@ -13049,7 +13025,8 @@ WMO_LOOP: void Dblqh::writeInitMbyte(Signal* signal) { initLogpage(signal); - writeSinglePage(signal, logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE, ZPAGE_SIZE - 1); + writeSinglePage(signal, logFilePtr.p->currentMbyte * ZPAGES_IN_MBYTE, + ZPAGE_SIZE - 1, __LINE__); lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_INIT_MBYTE; }//Dblqh::writeInitMbyte() @@ -13059,13 +13036,15 @@ void Dblqh::writeInitMbyte(Signal* signal) /* INPUT: TWSP_PAGE_NO THE PAGE NUMBER WRITTEN */ /* SUBROUTINE SHORT NAME: WSP */ /* ------------------------------------------------------------------------- */ -void Dblqh::writeSinglePage(Signal* signal, Uint32 pageNo, Uint32 wordWritten) +void Dblqh::writeSinglePage(Signal* signal, Uint32 pageNo, + Uint32 wordWritten, Uint32 place) { seizeLfo(signal); initLfo(signal); lfoPtr.p->firstLfoPage = logPagePtr.i; logPagePtr.p->logPageWord[ZNEXT_PAGE] = RNIL; + writeDbgInfoPageHeader(logPagePtr, place, pageNo, wordWritten); // Calculate checksum for page logPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(logPagePtr); @@ -14534,7 +14513,7 @@ void Dblqh::execSr(Signal* signal) * IN THIS WE HAVE COMPLETED EXECUTION OF THE CURRENT LOG PAGE * AND CAN WRITE IT TO DISK SINCE IT IS DIRTY. * ----------------------------------------------------------------- */ - writeDirty(signal); + writeDirty(signal, __LINE__); return; break; case LogPartRecord::LES_EXEC_LOG: @@ -14545,7 +14524,7 @@ void Dblqh::execSr(Signal* signal) * ------------------------------------------------------------------- */ if (logFilePtr.p->currentLogpage != logPartPtr.p->prevLogpage) { jam(); - writeDirty(signal); + writeDirty(signal, __LINE__); return; }//if break; @@ -14989,7 +14968,8 @@ void Dblqh::invalidateLogAfterLastGCI(Signal* signal) { // This page must be invalidated. logPagePtr.p->logPageWord[ZPOS_LOG_LAP] = 0; // Contact NDBFS. Real time break. - writeSinglePage(signal, logPartPtr.p->invalidatePageNo, ZPAGE_SIZE - 1); + writeSinglePage(signal, logPartPtr.p->invalidatePageNo, + ZPAGE_SIZE - 1, __LINE__); lfoPtr.p->lfoState = LogFileOperationRecord::WRITE_SR_INVALIDATE_PAGES; } else { // We are done with invalidating. Finish start phase 3.4. @@ -15937,7 +15917,7 @@ void Dblqh::closeFile(Signal* signal, LogFileRecordPtr clfLogFilePtr) // logPartPtr // Defines lfoPtr /* ---------------------------------------------------------------- */ -void Dblqh::completedLogPage(Signal* signal, Uint32 clpType) +void Dblqh::completedLogPage(Signal* signal, Uint32 clpType, Uint32 place) { LogPageRecordPtr clpLogPagePtr; LogPageRecordPtr wlpLogPagePtr; @@ -15980,6 +15960,9 @@ void Dblqh::completedLogPage(Signal* signal, Uint32 clpType) twlpNoPages++; ptrCheckGuard(wlpLogPagePtr, clogPageFileSize, logPageRecord); + writeDbgInfoPageHeader(wlpLogPagePtr, place, + logFilePtr.p->filePosition + twlpNoPages - 1, + ZPAGE_SIZE); // Calculate checksum for page wlpLogPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(wlpLogPagePtr); wlpLogPagePtr.i = wlpLogPagePtr.p->logPageWord[ZNEXT_PAGE]; @@ -16382,6 +16365,8 @@ void Dblqh::initialiseLogPage(Signal* signal) refresh_watch_dog(); ptrAss(logPagePtr, logPageRecord); logPagePtr.p->logPageWord[ZNEXT_PAGE] = logPagePtr.i + 1; + logPagePtr.p->logPageWord[ZPOS_IN_FREE_LIST]= 1; + logPagePtr.p->logPageWord[ZPOS_IN_WRITING]= 0; }//for logPagePtr.i = clogPageFileSize - 1; ptrAss(logPagePtr, logPageRecord); @@ -18038,10 +18023,14 @@ void Dblqh::writeCompletedGciLog(Signal* signal) * * SUBROUTINE SHORT NAME: WD * ------------------------------------------------------------------------- */ -void Dblqh::writeDirty(Signal* signal) +void Dblqh::writeDirty(Signal* signal, Uint32 place) { logPagePtr.p->logPageWord[ZPOS_DIRTY] = ZNOT_DIRTY; + ndbassert(logPartPtr.p->prevFilepage == + logPagePtr.p->logPageWord[ZPOS_PAGE_NO]); + writeDbgInfoPageHeader(logPagePtr, place, logPartPtr.p->prevFilepage, + ZPAGE_SIZE); // Calculate checksum for page logPagePtr.p->logPageWord[ZPOS_CHECKSUM] = calcPageCheckSum(logPagePtr); @@ -18075,7 +18064,7 @@ void Dblqh::writeLogWord(Signal* signal, Uint32 data) logPagePtr.p->logPageWord[ZCURR_PAGE_INDEX] = logPos + 1; if ((logPos + 1) == ZPAGE_SIZE) { jam(); - completedLogPage(signal, ZNORMAL); + completedLogPage(signal, ZNORMAL, __LINE__); seizeLogpage(signal); initLogpage(signal); logFilePtr.p->currentLogpage = logPagePtr.i; @@ -18133,7 +18122,7 @@ void Dblqh::writeNextLog(Signal* signal) /* -------------------------------------------------- */ /* WE HAVE TO CHANGE LOG FILE */ /* -------------------------------------------------- */ - completedLogPage(signal, ZLAST_WRITE_IN_FILE); + completedLogPage(signal, ZLAST_WRITE_IN_FILE, __LINE__); if (wnlNextLogFilePtr.p->fileNo == 0) { jam(); /* -------------------------------------------------- */ @@ -18152,7 +18141,7 @@ void Dblqh::writeNextLog(Signal* signal) /* INCREMENT THE CURRENT MBYTE */ /* SET PAGE INDEX TO PAGE HEADER SIZE */ /* -------------------------------------------------- */ - completedLogPage(signal, ZENFORCE_WRITE); + completedLogPage(signal, ZENFORCE_WRITE, __LINE__); twnlNewMbyte = logFilePtr.p->currentMbyte + 1; }//if /* -------------------------------------------------- */ @@ -18520,3 +18509,16 @@ Uint32 Dblqh::calcPageCheckSum(LogPageRecordPtr logP){ return checkSum; } +void Dblqh::writeDbgInfoPageHeader(LogPageRecordPtr logP, Uint32 place, + Uint32 pageNo, Uint32 wordWritten) +{ + logP.p->logPageWord[ZPOS_LOG_TIMER]= logPartPtr.p->logTimer; + logP.p->logPageWord[ZPOS_PREV_PAGE_NO]= logP.p->logPageWord[ZPOS_PAGE_NO]; + logP.p->logPageWord[ZPOS_PAGE_I]= logP.i; + logP.p->logPageWord[ZPOS_PLACE_WRITTEN_FROM]= place; + logP.p->logPageWord[ZPOS_PAGE_NO]= pageNo; + logP.p->logPageWord[ZPOS_PAGE_FILE_NO]= logFilePtr.p->fileNo; + logP.p->logPageWord[ZPOS_WORD_WRITTEN]= wordWritten; + logP.p->logPageWord[ZPOS_IN_WRITING]= 1; +} + diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp index ba6d65ca838..6eadefe5df5 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp @@ -134,7 +134,9 @@ bool PrepareOperationRecord::check() { return true; } -Uint32 PrepareOperationRecord::getLogRecordSize() { +Uint32 PrepareOperationRecord::getLogRecordSize(Uint32 wordsRead) { + if (wordsRead < 2) + return 2; // make sure we read more return m_logRecordSize; } @@ -264,7 +266,16 @@ NdbOut& operator<<(NdbOut& no, const PageHeader& ph) { printOut("Current page index:", ph.m_current_page_index); printOut("Oldest prepare op. file No.:", ph.m_old_prepare_file_number); printOut("Oldest prepare op. page ref.:", ph.m_old_prepare_page_reference); - printOut("Dirty flag:", ph.m_dirty_flag); + printOut("Dirty flag:", ph.m_dirty_flag); + printOut("Write Timer:", ph.m_log_timer); + printOut("Page i-val:", ph.m_page_i_value); + printOut("Place written:", ph.m_place_written_from); + printOut("Page No in File:", ph.m_page_no); + printOut("File No:", ph.m_file_no); + printOut("Word Written:", ph.m_word_written); + printOut("In Writing (should be 1)", ph.m_in_writing_flag); + printOut("Prev Page No (can be garbage)", ph.m_prev_page_no); + printOut("In Free List (should be 0):", ph.m_in_free_list); no << endl; return no; } diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp index 11b8dc4a6fa..06bf7a85d53 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp @@ -83,7 +83,7 @@ class PrepareOperationRecord { friend NdbOut& operator<<(NdbOut&, const PrepareOperationRecord&); public: bool check(); - Uint32 getLogRecordSize(); + Uint32 getLogRecordSize(Uint32 wordsRead); protected: Uint32 m_recordType; @@ -147,6 +147,17 @@ protected: Uint32 m_old_prepare_file_number; Uint32 m_old_prepare_page_reference; Uint32 m_dirty_flag; +/* Debug info Start */ + Uint32 m_log_timer; + Uint32 m_page_i_value; + Uint32 m_place_written_from; + Uint32 m_page_no; + Uint32 m_file_no; + Uint32 m_word_written; + Uint32 m_in_writing_flag; + Uint32 m_prev_page_no; + Uint32 m_in_free_list; +/* Debug info End */ }; //---------------------------------------------------------------- diff --git a/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp b/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp index aa8b1d25e4e..751d27db74e 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/redoLogFileReader.cpp @@ -41,6 +41,7 @@ void doExit(); FILE * f= 0; char fileName[256]; +bool theDumpFlag = false; bool thePrintFlag = true; bool theCheckFlag = true; bool onlyPageHeaders = false; @@ -208,7 +209,7 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read case ZPREP_OP_TYPE: poRecord = (PrepareOperationRecord *) redoLogPagePos; - wordIndex += poRecord->getLogRecordSize(); + wordIndex += poRecord->getLogRecordSize(PAGESIZE-wordIndex); if (wordIndex <= PAGESIZE) { if (thePrintFlag) ndbout << (*poRecord); if (theCheckFlag) { @@ -277,10 +278,9 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read ndbout << " ------ERROR: UNKNOWN RECORD TYPE------" << endl; // Print out remaining data in this page - for (int j = wordIndex; j < PAGESIZE; j++){ - Uint32 unknown = redoLogPage[i*PAGESIZE + j]; - - ndbout_c("%-30d%-12u%-12x", j, unknown, unknown); + for (int k = wordIndex; k < PAGESIZE; k++){ + Uint32 unknown = redoLogPage[i*PAGESIZE + k]; + ndbout_c("%-30d%-12u%-12x", k, unknown, unknown); } doExit(); @@ -289,8 +289,19 @@ NDB_COMMAND(redoLogFileReader, "redoLogFileReader", "redoLogFileReader", "Read if (lastPage) + { + if (theDumpFlag) + { + ndbout << " ------PAGE END: DUMPING REST OF PAGE------" << endl; + for (int k = wordIndex > PAGESIZE ? oldWordIndex : wordIndex; + k < PAGESIZE; k++) + { + Uint32 word = redoLogPage[i*PAGESIZE + k]; + ndbout_c("%-30d%-12u%-12x", k, word, word); + } + } break; - + } if (wordIndex > PAGESIZE) { words_from_previous_page = PAGESIZE - oldWordIndex; ndbout << " ----------- Record continues on next page -----------" << endl; @@ -353,6 +364,8 @@ void readArguments(int argc, const char** argv) { if (strcmp(argv[i], "-noprint") == 0) { thePrintFlag = false; + } else if (strcmp(argv[i], "-dump") == 0) { + theDumpFlag = true; } else if (strcmp(argv[i], "-nocheck") == 0) { theCheckFlag = false; } else if (strcmp(argv[i], "-mbyteheaders") == 0) { diff --git a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index 93b122b9a99..04b40dafcb5 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -4404,7 +4404,7 @@ Dbtc::DIVER_node_fail_handling(Signal* signal, UintR Tgci) *------------------------------------------------------------------------*/ tabortInd = ZFALSE; setupFailData(signal); - if (tabortInd == ZFALSE) { + if (false && tabortInd == ZFALSE) { jam(); commitGciHandling(signal, Tgci); toCommitHandlingLab(signal); @@ -10833,6 +10833,7 @@ void Dbtc::execCREATE_TRIG_REQ(Signal* signal) if (ERROR_INSERTED(8033) || !c_theDefinedTriggers.seizeId(triggerPtr, createTrigReq->getTriggerId())) { + jam(); CLEAR_ERROR_INSERT_VALUE; // Failed to allocate trigger record CreateTrigRef * const createTrigRef = @@ -10867,8 +10868,10 @@ void Dbtc::execDROP_TRIG_REQ(Signal* signal) DropTrigReq * const dropTrigReq = (DropTrigReq *)&signal->theData[0]; BlockReference sender = signal->senderBlockRef(); - if ((c_theDefinedTriggers.getPtr(dropTrigReq->getTriggerId())) == NULL) { + if (ERROR_INSERTED(8035) || + (c_theDefinedTriggers.getPtr(dropTrigReq->getTriggerId())) == NULL) { jam(); + CLEAR_ERROR_INSERT_VALUE; // Failed to find find trigger record DropTrigRef * const dropTrigRef = (DropTrigRef *)&signal->theData[0]; @@ -10900,6 +10903,7 @@ void Dbtc::execCREATE_INDX_REQ(Signal* signal) if (ERROR_INSERTED(8034) || !c_theIndexes.seizeId(indexPtr, createIndxReq->getIndexId())) { + jam(); CLEAR_ERROR_INSERT_VALUE; // Failed to allocate index record CreateIndxRef * const createIndxRef = @@ -11111,8 +11115,10 @@ void Dbtc::execDROP_INDX_REQ(Signal* signal) TcIndexData* indexData; BlockReference sender = signal->senderBlockRef(); - if ((indexData = c_theIndexes.getPtr(dropIndxReq->getIndexId())) == NULL) { + if (ERROR_INSERTED(8036) || + (indexData = c_theIndexes.getPtr(dropIndxReq->getIndexId())) == NULL) { jam(); + CLEAR_ERROR_INSERT_VALUE; // Failed to find index record DropIndxRef * const dropIndxRef = (DropIndxRef *)signal->getDataPtrSend(); diff --git a/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp b/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp index 575d08efffc..0acfd390360 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp @@ -305,6 +305,10 @@ Dbtup::primaryKey(Tablerec* const regTabPtr, Uint32 attrId) Uint32 Dbtup::dropTrigger(Tablerec* table, const DropTrigReq* req) { + if (ERROR_INSERTED(4004)) { + CLEAR_ERROR_INSERT_VALUE; + return 9999; + } Uint32 triggerId = req->getTriggerId(); TriggerType::Value ttype = req->getTriggerType(); diff --git a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp index 2e2c834ad9c..071a85c96da 100644 --- a/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp +++ b/ndb/src/kernel/blocks/ndbcntr/NdbcntrMain.cpp @@ -2493,6 +2493,14 @@ void Ndbcntr::Missra::sendNextSTTOR(Signal* signal){ const Uint32 start = currentBlockIndex; + if (currentStartPhase == ZSTART_PHASE_6) + { + // Ndbd has passed the critical startphases. + // Change error handler from "startup" state + // to normal state. + ErrorReporter::setErrorHandlerShutdownType(); + } + for(; currentBlockIndex < ALL_BLOCKS_SZ; currentBlockIndex++){ jam(); if(ALL_BLOCKS[currentBlockIndex].NextSP == currentStartPhase){ diff --git a/ndb/src/kernel/error/ErrorReporter.cpp b/ndb/src/kernel/error/ErrorReporter.cpp index e4ead4ce34d..25409db48a8 100644 --- a/ndb/src/kernel/error/ErrorReporter.cpp +++ b/ndb/src/kernel/error/ErrorReporter.cpp @@ -152,6 +152,14 @@ ErrorReporter::formatMessage(ErrorCategory type, return; } +NdbShutdownType ErrorReporter::s_errorHandlerShutdownType = NST_ErrorHandler; + +void +ErrorReporter::setErrorHandlerShutdownType(NdbShutdownType nst) +{ + s_errorHandlerShutdownType = nst; +} + void ErrorReporter::handleAssert(const char* message, const char* file, int line) { @@ -170,7 +178,7 @@ ErrorReporter::handleAssert(const char* message, const char* file, int line) WriteMessage(assert, ERR_ERROR_PRGERR, message, refMessage, theEmulatedJamIndex, theEmulatedJam); - NdbShutdown(NST_ErrorHandler); + NdbShutdown(s_errorHandlerShutdownType); } void @@ -182,7 +190,7 @@ ErrorReporter::handleThreadAssert(const char* message, BaseString::snprintf(refMessage, 100, "file: %s lineNo: %d - %s", file, line, message); - NdbShutdown(NST_ErrorHandler); + NdbShutdown(s_errorHandlerShutdownType); }//ErrorReporter::handleThreadAssert() @@ -201,6 +209,8 @@ ErrorReporter::handleError(ErrorCategory type, int messageID, if(messageID == ERR_ERROR_INSERT){ NdbShutdown(NST_ErrorInsert); } else { + if (nst == NST_ErrorHandler) + nst = s_errorHandlerShutdownType; NdbShutdown(nst); } } diff --git a/ndb/src/kernel/error/ErrorReporter.hpp b/ndb/src/kernel/error/ErrorReporter.hpp index 2c79f242eea..c5533df46f4 100644 --- a/ndb/src/kernel/error/ErrorReporter.hpp +++ b/ndb/src/kernel/error/ErrorReporter.hpp @@ -26,6 +26,7 @@ class ErrorReporter { public: + static void setErrorHandlerShutdownType(NdbShutdownType nst = NST_ErrorHandler); static void handleAssert(const char* message, const char* file, int line); @@ -57,6 +58,7 @@ public: static const char* formatTimeStampString(); private: + static enum NdbShutdownType s_errorHandlerShutdownType; }; #endif diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp index 1e5cd5270e4..d9953b920d2 100644 --- a/ndb/src/kernel/main.cpp +++ b/ndb/src/kernel/main.cpp @@ -45,8 +45,14 @@ extern NdbMutex * theShutdownMutex; void catchsigs(bool ignore); // for process signal handling +#define MAX_FAILED_STARTUPS 3 +// Flag set by child through SIGUSR1 to signal a failed startup +static bool failed_startup_flag = false; +// Counter for consecutive failed startups +static Uint32 failed_startups = 0; extern "C" void handler_shutdown(int signum); // for process signal handling extern "C" void handler_error(int signum); // for process signal handling +extern "C" void handler_sigusr1(int signum); // child signalling failed restart // Shows system information void systemInfo(const Configuration & conf, @@ -57,7 +63,7 @@ int main(int argc, char** argv) NDB_INIT(argv[0]); // Print to stdout/console g_eventLogger.createConsoleHandler(); - g_eventLogger.setCategory("NDB"); + g_eventLogger.setCategory("ndbd"); g_eventLogger.enable(Logger::LL_ON, Logger::LL_CRITICAL); g_eventLogger.enable(Logger::LL_ON, Logger::LL_ERROR); g_eventLogger.enable(Logger::LL_ON, Logger::LL_WARNING); @@ -92,6 +98,8 @@ int main(int argc, char** argv) } #ifndef NDB_WIN32 + signal(SIGUSR1, handler_sigusr1); + for(pid_t child = fork(); child != 0; child = fork()){ /** * Parent @@ -137,6 +145,20 @@ int main(int argc, char** argv) */ exit(0); } + if (!failed_startup_flag) + { + // Reset the counter for consecutive failed startups + failed_startups = 0; + } + else if (failed_startups >= MAX_FAILED_STARTUPS && !theConfig->stopOnError()) + { + /** + * Error shutdown && stopOnError() + */ + g_eventLogger.alert("Ndbd has failed %u consecutive startups. Not restarting", failed_startups); + exit(0); + } + failed_startup_flag = false; g_eventLogger.info("Ndb has terminated (pid %d) restarting", child); theConfig->fetch_configuration(); } @@ -170,6 +192,9 @@ int main(int argc, char** argv) /** * Do startup */ + + ErrorReporter::setErrorHandlerShutdownType(NST_ErrorHandlerStartup); + switch(globalData.theRestartFlag){ case initial_state: globalEmulatorData.theThreadConfig->doStart(NodeState::SL_CMVMI); @@ -359,3 +384,15 @@ handler_error(int signum){ BaseString::snprintf(errorData, 40, "Signal %d received", signum); ERROR_SET_SIGNAL(fatal, 0, errorData, __FILE__); } + +extern "C" +void +handler_sigusr1(int signum) +{ + if (!failed_startup_flag) + { + failed_startups++; + failed_startup_flag = true; + } + g_eventLogger.info("Angel received ndbd startup failure count %u.", failed_startups); +} diff --git a/ndb/src/kernel/vm/Emulator.cpp b/ndb/src/kernel/vm/Emulator.cpp index d6ed6c0dafd..058829e05e2 100644 --- a/ndb/src/kernel/vm/Emulator.cpp +++ b/ndb/src/kernel/vm/Emulator.cpp @@ -30,13 +30,16 @@ #include <NodeState.hpp> #include <NdbMem.h> -#include <NdbOut.hpp> #include <NdbMutex.h> #include <NdbSleep.h> +#include <EventLogger.hpp> + extern "C" { extern void (* ndb_new_handler)(); } +extern EventLogger g_eventLogger; +extern my_bool opt_core; /** * Declare the global variables @@ -141,45 +144,50 @@ NdbShutdown(NdbShutdownType type, switch(type){ case NST_Normal: - ndbout << "Shutdown initiated" << endl; + g_eventLogger.info("Shutdown initiated"); break; case NST_Watchdog: - ndbout << "Watchdog " << shutting << " system" << endl; + g_eventLogger.info("Watchdog %s system", shutting); break; case NST_ErrorHandler: - ndbout << "Error handler " << shutting << " system" << endl; + g_eventLogger.info("Error handler %s system", shutting); break; case NST_ErrorHandlerSignal: - ndbout << "Error handler signal " << shutting << " system" << endl; + g_eventLogger.info("Error handler signal %s system", shutting); + break; + case NST_ErrorHandlerStartup: + g_eventLogger.info("Error handler startup %s system", shutting); break; case NST_Restart: - ndbout << "Restarting system" << endl; + g_eventLogger.info("Restarting system"); break; default: - ndbout << "Error handler " << shutting << " system" - << " (unknown type: " << (unsigned)type << ")" << endl; + g_eventLogger.info("Error handler %s system (unknown type: %u)", + shutting, (unsigned)type); type = NST_ErrorHandler; break; } const char * exitAbort = 0; -#if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) - exitAbort = "aborting"; -#else - exitAbort = "exiting"; -#endif + if (opt_core) + exitAbort = "aborting"; + else + exitAbort = "exiting"; if(type == NST_Watchdog){ /** * Very serious, don't attempt to free, just die!! */ - ndbout << "Watchdog shutdown completed - " << exitAbort << endl; -#if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) - signal(6, SIG_DFL); - abort(); -#else - exit(-1); -#endif + g_eventLogger.info("Watchdog shutdown completed - %s", exitAbort); + if (opt_core) + { + signal(6, SIG_DFL); + abort(); + } + else + { + exit(-1); + } } #ifndef NDB_WIN32 @@ -227,13 +235,19 @@ NdbShutdown(NdbShutdownType type, } if(type != NST_Normal && type != NST_Restart){ - ndbout << "Error handler shutdown completed - " << exitAbort << endl; -#if ( defined VM_TRACE || defined ERROR_INSERT ) && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) - signal(6, SIG_DFL); - abort(); -#else - exit(-1); -#endif + // Signal parent that error occured during startup + if (type == NST_ErrorHandlerStartup) + kill(getppid(), SIGUSR1); + g_eventLogger.info("Error handler shutdown completed - %s", exitAbort); + if (opt_core) + { + signal(6, SIG_DFL); + abort(); + } + else + { + exit(-1); + } } /** @@ -243,7 +257,7 @@ NdbShutdown(NdbShutdownType type, exit(restartType); } - ndbout << "Shutdown completed - exiting" << endl; + g_eventLogger.info("Shutdown completed - exiting"); } else { /** * Shutdown is already in progress @@ -253,7 +267,7 @@ NdbShutdown(NdbShutdownType type, * If this is the watchdog, kill system the hard way */ if (type== NST_Watchdog){ - ndbout << "Watchdog is killing system the hard way" << endl; + g_eventLogger.info("Watchdog is killing system the hard way"); #if defined VM_TRACE && ( ! ( defined NDB_OSE || defined NDB_SOFTOSE) ) signal(6, SIG_DFL); abort(); diff --git a/ndb/src/kernel/vm/Emulator.hpp b/ndb/src/kernel/vm/Emulator.hpp index dba8cb3ab9b..cd194202d85 100644 --- a/ndb/src/kernel/vm/Emulator.hpp +++ b/ndb/src/kernel/vm/Emulator.hpp @@ -83,7 +83,8 @@ enum NdbShutdownType { NST_ErrorHandler, NST_ErrorHandlerSignal, NST_Restart, - NST_ErrorInsert + NST_ErrorInsert, + NST_ErrorHandlerStartup }; enum NdbRestartType { diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp index bf78adec970..06b534ac0ca 100644 --- a/ndb/src/mgmapi/mgmapi.cpp +++ b/ndb/src/mgmapi/mgmapi.cpp @@ -638,12 +638,10 @@ ndb_mgm_get_status(NdbMgmHandle handle) Vector<BaseString> split; tmp.split(split, ":"); if(split.size() != 2){ - abort(); return NULL; } if(!(split[0].trim() == "nodes")){ - abort(); return NULL; } @@ -692,7 +690,6 @@ ndb_mgm_get_status(NdbMgmHandle handle) if(i+1 != noOfNodes){ free(state); - abort(); return NULL; } diff --git a/ndb/src/mgmsrv/ConfigInfo.cpp b/ndb/src/mgmsrv/ConfigInfo.cpp index cface035174..36a72dcb975 100644 --- a/ndb/src/mgmsrv/ConfigInfo.cpp +++ b/ndb/src/mgmsrv/ConfigInfo.cpp @@ -25,6 +25,7 @@ #include <m_string.h> extern my_bool opt_ndb_shm; +extern my_bool opt_core; #define MAX_LINE_LENGTH 255 #define KEY_INTERNAL 0 @@ -2140,11 +2141,10 @@ static void require(bool v) { if(!v) { -#ifndef DBUG_OFF - abort(); -#else - exit(-1); -#endif + if (opt_core) + abort(); + else + exit(-1); } } @@ -2214,7 +2214,7 @@ ConfigInfo::ConfigInfo() ndbout << "Error: Parameter " << param._fname << " defined twice in section " << param._section << "." << endl; - exit(-1); + require(false); } // Add new pinfo to section @@ -2264,7 +2264,7 @@ ConfigInfo::ConfigInfo() ndbout << "Check that each entry has a section failed." << endl; ndbout << "Parameter \"" << m_ParamInfo[i]._fname << endl; ndbout << "Edit file " << __FILE__ << "." << endl; - exit(-1); + require(false); } if(m_ParamInfo[i]._type == ConfigInfo::CI_SECTION) @@ -2277,7 +2277,7 @@ ConfigInfo::ConfigInfo() << "\" does not exist in section \"" << m_ParamInfo[i]._section << "\"." << endl; ndbout << "Edit file " << __FILE__ << "." << endl; - exit(-1); + require(false); } } } diff --git a/ndb/src/mgmsrv/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index 452dabc50e0..56c24e5f862 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.cpp +++ b/ndb/src/mgmsrv/MgmtSrvr.cpp @@ -39,6 +39,8 @@ #include <signaldata/BackupSignalData.hpp> #include <signaldata/GrepImpl.hpp> #include <signaldata/ManagementServer.hpp> +#include <signaldata/NFCompleteRep.hpp> +#include <signaldata/NodeFailRep.hpp> #include <NdbSleep.h> #include <EventLogger.hpp> #include <DebuggerNames.hpp> @@ -56,6 +58,8 @@ #include <mgmapi_config_parameters.h> #include <m_string.h> +#include <SignalSender.hpp> + //#define MGM_SRV_DEBUG #ifdef MGM_SRV_DEBUG #define DEBUG(x) do ndbout << x << endl; while(0) @@ -65,6 +69,18 @@ extern int global_flag_send_heartbeat_now; extern int g_no_nodeid_checks; +extern my_bool opt_core; + +static void require(bool v) +{ + if(!v) + { + if (opt_core) + abort(); + else + exit(-1); + } +} void * MgmtSrvr::logLevelThread_C(void* m) @@ -436,14 +452,14 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, if (tmp_nodeid == 0) { ndbout_c(m_config_retriever->getErrorString()); - exit(-1); + require(false); } // read config from other managent server _config= fetchConfig(); if (_config == 0) { ndbout << m_config_retriever->getErrorString() << endl; - exit(-1); + require(false); } _ownNodeId= tmp_nodeid; } @@ -454,7 +470,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, _config= readConfig(); if (_config == 0) { ndbout << "Unable to read config file" << endl; - exit(-1); + require(false); } } @@ -511,7 +527,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, if ((m_node_id_mutex = NdbMutex_Create()) == 0) { ndbout << "mutex creation failed line = " << __LINE__ << endl; - exit(-1); + require(false); } if (_ownNodeId == 0) // we did not get node id from other server @@ -522,7 +538,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, 0, 0, error_string)){ ndbout << "Unable to obtain requested nodeid: " << error_string.c_str() << endl; - exit(-1); + require(false); } _ownNodeId = tmp; } @@ -533,7 +549,7 @@ MgmtSrvr::MgmtSrvr(SocketServer *socket_server, _ownNodeId)) { ndbout << m_config_retriever->getErrorString() << endl; - exit(-1); + require(false); } } @@ -697,6 +713,15 @@ int MgmtSrvr::okToSendTo(NodeId processId, bool unCond) } } +void report_unknown_signal(SimpleSignal *signal) +{ + g_eventLogger.error("Unknown signal received. SignalNumber: " + "%i from (%d, %x)", + signal->readSignalNumber(), + refToNode(signal->header.theSendersBlockRef), + refToBlock(signal->header.theSendersBlockRef)); +} + /***************************************************************************** * Starting and stopping database nodes ****************************************************************************/ @@ -1899,81 +1924,6 @@ MgmtSrvr::handleReceivedSignal(NdbApiSignal* signal) } break; - case GSN_BACKUP_CONF:{ - const BackupConf * const conf = - CAST_CONSTPTR(BackupConf, signal->getDataPtr()); - BackupEvent event; - event.Event = BackupEvent::BackupStarted; - event.Started.BackupId = conf->backupId; - event.Nodes = conf->nodes; -#ifdef VM_TRACE - ndbout_c("Backup master is %d", refToNode(signal->theSendersBlockRef)); -#endif - backupCallback(event); - } - break; - - case GSN_BACKUP_REF:{ - const BackupRef * const ref = - CAST_CONSTPTR(BackupRef, signal->getDataPtr()); - Uint32 errCode = ref->errorCode; - if(ref->errorCode == BackupRef::IAmNotMaster){ - const Uint32 aNodeId = refToNode(ref->masterRef); -#ifdef VM_TRACE - ndbout_c("I'm not master resending to %d", aNodeId); -#endif - theWaitNode= aNodeId; - NdbApiSignal aSignal(_ownReference); - BackupReq* req = CAST_PTR(BackupReq, aSignal.getDataPtrSend()); - aSignal.set(TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ, - BackupReq::SignalLength); - req->senderData = 19; - req->backupDataLen = 0; - - int i = theFacade->sendSignalUnCond(&aSignal, aNodeId); - if(i == 0){ - return; - } - errCode = 5030; - } - BackupEvent event; - event.Event = BackupEvent::BackupFailedToStart; - event.FailedToStart.ErrorCode = errCode; - backupCallback(event); - break; - } - - case GSN_BACKUP_ABORT_REP:{ - const BackupAbortRep * const rep = - CAST_CONSTPTR(BackupAbortRep, signal->getDataPtr()); - BackupEvent event; - event.Event = BackupEvent::BackupAborted; - event.Aborted.Reason = rep->reason; - event.Aborted.BackupId = rep->backupId; - event.Aborted.ErrorCode = rep->reason; - backupCallback(event); - } - break; - - case GSN_BACKUP_COMPLETE_REP:{ - const BackupCompleteRep * const rep = - CAST_CONSTPTR(BackupCompleteRep, signal->getDataPtr()); - BackupEvent event; - event.Event = BackupEvent::BackupCompleted; - event.Completed.BackupId = rep->backupId; - - event.Completed.NoOfBytes = rep->noOfBytes; - event.Completed.NoOfLogBytes = rep->noOfLogBytes; - event.Completed.NoOfRecords = rep->noOfRecords; - event.Completed.NoOfLogRecords = rep->noOfLogRecords; - event.Completed.stopGCP = rep->stopGCP; - event.Completed.startGCP = rep->startGCP; - event.Nodes = rep->nodes; - - backupCallback(event); - } - break; - case GSN_MGM_LOCK_CONFIG_REP: case GSN_MGM_LOCK_CONFIG_REQ: case GSN_MGM_UNLOCK_CONFIG_REP: @@ -2203,18 +2153,18 @@ MgmtSrvr::alloc_node_id(NodeId * nodeId, iter(*(ndb_mgm_configuration *)_config->m_configValues, CFG_SECTION_NODE); for(iter.first(); iter.valid(); iter.next()) { unsigned tmp= 0; - if(iter.get(CFG_NODE_ID, &tmp)) abort(); + if(iter.get(CFG_NODE_ID, &tmp)) require(false); if (*nodeId && *nodeId != tmp) continue; found_matching_id= true; - if(iter.get(CFG_TYPE_OF_SECTION, &type_c)) abort(); + if(iter.get(CFG_TYPE_OF_SECTION, &type_c)) require(false); if(type_c != (unsigned)type) continue; found_matching_type= true; if (connected_nodes.get(tmp)) continue; found_free_node= true; - if(iter.get(CFG_NODE_HOST, &config_hostname)) abort(); + if(iter.get(CFG_NODE_HOST, &config_hostname)) require(false); if (config_hostname && config_hostname[0] == 0) config_hostname= 0; else if (client_addr) { @@ -2434,6 +2384,9 @@ MgmtSrvr::eventReport(NodeId nodeId, const Uint32 * theData) int MgmtSrvr::startBackup(Uint32& backupId, int waitCompleted) { + SignalSender ss(theFacade); + ss.lock(); // lock will be released on exit + bool next; NodeId nodeId = 0; while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true && @@ -2441,50 +2394,124 @@ MgmtSrvr::startBackup(Uint32& backupId, int waitCompleted) if(!next) return NO_CONTACT_WITH_DB_NODES; - NdbApiSignal* signal = getSignal(); - if (signal == NULL) { - return COULD_NOT_ALLOCATE_MEMORY; - } + SimpleSignal ssig; - BackupReq* req = CAST_PTR(BackupReq, signal->getDataPtrSend()); - signal->set(TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ, - BackupReq::SignalLength); + BackupReq* req = CAST_PTR(BackupReq, ssig.getDataPtrSend()); + ssig.set(ss, TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ, + BackupReq::SignalLength); req->senderData = 19; req->backupDataLen = 0; + assert(waitCompleted < 3); + req->flags = waitCompleted & 0x3; - int result; - if (waitCompleted == 2) { - result = sendRecSignal(nodeId, WAIT_BACKUP_COMPLETED, - signal, true, 48*60*60*1000 /* 48 hours */); - } - else if (waitCompleted == 1) { - result = sendRecSignal(nodeId, WAIT_BACKUP_STARTED, - signal, true, 5*60*1000 /*5 mins*/); - } - else { - result = sendRecSignal(nodeId, NO_WAIT, signal, true); - } - if (result == -1) { - return SEND_OR_RECEIVE_FAILED; - } - - if (waitCompleted){ - switch(m_lastBackupEvent.Event){ - case BackupEvent::BackupCompleted: - backupId = m_lastBackupEvent.Completed.BackupId; + BackupEvent event; + int do_send = 1; + while (1) { + if (do_send) + { + SendStatus result = ss.sendSignal(nodeId, &ssig); + if (result != SEND_OK) { + return SEND_OR_RECEIVE_FAILED; + } + if (waitCompleted == 0) + return 0; + do_send = 0; + } + SimpleSignal *signal = ss.waitFor(); + + int gsn = signal->readSignalNumber(); + switch (gsn) { + case GSN_BACKUP_CONF:{ + const BackupConf * const conf = + CAST_CONSTPTR(BackupConf, signal->getDataPtr()); + event.Event = BackupEvent::BackupStarted; + event.Started.BackupId = conf->backupId; + event.Nodes = conf->nodes; +#ifdef VM_TRACE + ndbout_c("Backup(%d) master is %d", conf->backupId, + refToNode(signal->header.theSendersBlockRef)); +#endif + backupId = conf->backupId; + if (waitCompleted == 1) + return 0; + // wait for next signal break; - case BackupEvent::BackupStarted: - backupId = m_lastBackupEvent.Started.BackupId; + } + case GSN_BACKUP_COMPLETE_REP:{ + const BackupCompleteRep * const rep = + CAST_CONSTPTR(BackupCompleteRep, signal->getDataPtr()); +#ifdef VM_TRACE + ndbout_c("Backup(%d) completed %d", rep->backupId); +#endif + event.Event = BackupEvent::BackupCompleted; + event.Completed.BackupId = rep->backupId; + + event.Completed.NoOfBytes = rep->noOfBytes; + event.Completed.NoOfLogBytes = rep->noOfLogBytes; + event.Completed.NoOfRecords = rep->noOfRecords; + event.Completed.NoOfLogRecords = rep->noOfLogRecords; + event.Completed.stopGCP = rep->stopGCP; + event.Completed.startGCP = rep->startGCP; + event.Nodes = rep->nodes; + + backupId = rep->backupId; + return 0; + } + case GSN_BACKUP_REF:{ + const BackupRef * const ref = + CAST_CONSTPTR(BackupRef, signal->getDataPtr()); + if(ref->errorCode == BackupRef::IAmNotMaster){ + nodeId = refToNode(ref->masterRef); +#ifdef VM_TRACE + ndbout_c("I'm not master resending to %d", nodeId); +#endif + do_send = 1; // try again + continue; + } + event.Event = BackupEvent::BackupFailedToStart; + event.FailedToStart.ErrorCode = ref->errorCode; + return ref->errorCode; + } + case GSN_BACKUP_ABORT_REP:{ + const BackupAbortRep * const rep = + CAST_CONSTPTR(BackupAbortRep, signal->getDataPtr()); + event.Event = BackupEvent::BackupAborted; + event.Aborted.Reason = rep->reason; + event.Aborted.BackupId = rep->backupId; + event.Aborted.ErrorCode = rep->reason; +#ifdef VM_TRACE + ndbout_c("Backup %d aborted", rep->backupId); +#endif + return rep->reason; + } + case GSN_NF_COMPLETEREP:{ + const NFCompleteRep * const rep = + CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr()); +#ifdef VM_TRACE + ndbout_c("Node %d fail completed", rep->failedNodeId); +#endif + if (rep->failedNodeId == nodeId || + waitCompleted == 1) + return 1326; + // wait for next signal + // master node will report aborted backup break; - case BackupEvent::BackupFailedToStart: - return m_lastBackupEvent.FailedToStart.ErrorCode; - case BackupEvent::BackupAborted: - return m_lastBackupEvent.Aborted.ErrorCode; - default: - return -1; + } + case GSN_NODE_FAILREP:{ + const NodeFailRep * const rep = + CAST_CONSTPTR(NodeFailRep, signal->getDataPtr()); + if (NodeBitmask::get(rep->theNodes,nodeId) || + waitCompleted == 1) + return 1326; + // wait for next signal + // master node will report aborted backup break; } + default: + report_unknown_signal(signal); + return SEND_OR_RECEIVE_FAILED; + } } return 0; @@ -2523,36 +2550,6 @@ MgmtSrvr::abortBackup(Uint32 backupId) return 0; } -void -MgmtSrvr::backupCallback(BackupEvent & event) -{ - DBUG_ENTER("MgmtSrvr::backupCallback"); - m_lastBackupEvent = event; - switch(event.Event){ - case BackupEvent::BackupFailedToStart: - DBUG_PRINT("info",("BackupEvent::BackupFailedToStart")); - theWaitState = NO_WAIT; - break; - case BackupEvent::BackupAborted: - DBUG_PRINT("info",("BackupEvent::BackupAborted")); - theWaitState = NO_WAIT; - break; - case BackupEvent::BackupCompleted: - DBUG_PRINT("info",("BackupEvent::BackupCompleted")); - theWaitState = NO_WAIT; - break; - case BackupEvent::BackupStarted: - if(theWaitState == WAIT_BACKUP_STARTED) - { - DBUG_PRINT("info",("BackupEvent::BackupStarted NO_WAIT")); - theWaitState = NO_WAIT; - } else { - DBUG_PRINT("info",("BackupEvent::BackupStarted")); - } - } - DBUG_VOID_RETURN; -} - /***************************************************************************** * Global Replication @@ -2561,7 +2558,7 @@ MgmtSrvr::backupCallback(BackupEvent & event) int MgmtSrvr::repCommand(Uint32* repReqId, Uint32 request, bool waitCompleted) { - abort(); + require(false); return 0; } @@ -2715,7 +2712,7 @@ MgmtSrvr::setDbParameter(int node, int param, const char * value, ndbout_c("Updating node %d param: %d to %s", node, param, val_char); break; default: - abort(); + require(false); } assert(res); } while(node == 0 && iter.next() == 0); diff --git a/ndb/src/mgmsrv/MgmtSrvr.hpp b/ndb/src/mgmsrv/MgmtSrvr.hpp index c132852338b..f8c244a1bf1 100644 --- a/ndb/src/mgmsrv/MgmtSrvr.hpp +++ b/ndb/src/mgmsrv/MgmtSrvr.hpp @@ -757,9 +757,6 @@ private: static void *signalRecvThread_C(void *); void signalRecvThreadRun(); - void backupCallback(BackupEvent &); - BackupEvent m_lastBackupEvent; - Config *_props; int send(class NdbApiSignal* signal, Uint32 node, Uint32 node_type); diff --git a/ndb/src/mgmsrv/Services.cpp b/ndb/src/mgmsrv/Services.cpp index 00cf6390c73..46bfb531b61 100644 --- a/ndb/src/mgmsrv/Services.cpp +++ b/ndb/src/mgmsrv/Services.cpp @@ -343,8 +343,6 @@ MgmApiSession::getConfig_old(Parser_t::Context &ctx) { } #endif /* MGM_GET_CONFIG_BACKWARDS_COMPAT */ -inline void require(bool b){ if(!b) abort(); } - void MgmApiSession::getConfig(Parser_t::Context &ctx, const class Properties &args) { diff --git a/ndb/src/ndbapi/Makefile.am b/ndb/src/ndbapi/Makefile.am index 9f8a851b995..1ba80ef7d85 100644 --- a/ndb/src/ndbapi/Makefile.am +++ b/ndb/src/ndbapi/Makefile.am @@ -35,7 +35,8 @@ libndbapi_la_SOURCES = \ NdbDictionaryImpl.cpp \ DictCache.cpp \ ndb_cluster_connection.cpp \ - NdbBlob.cpp + NdbBlob.cpp \ + SignalSender.cpp INCLUDES_LOC = -I$(top_srcdir)/ndb/src/mgmapi diff --git a/ndb/src/ndbapi/NdbConnection.cpp b/ndb/src/ndbapi/NdbConnection.cpp index e1f70160fb7..c9e26f8ccaf 100644 --- a/ndb/src/ndbapi/NdbConnection.cpp +++ b/ndb/src/ndbapi/NdbConnection.cpp @@ -280,6 +280,7 @@ NdbConnection::execute(ExecType aTypeOfExec, AbortOption abortOption, int forceSend) { + NdbError savedError= theError; DBUG_ENTER("NdbConnection::execute"); DBUG_PRINT("enter", ("aTypeOfExec: %d, abortOption: %d", aTypeOfExec, abortOption)); @@ -309,7 +310,11 @@ NdbConnection::execute(ExecType aTypeOfExec, NdbBlob* tBlob = tPrepOp->theBlobList; while (tBlob != NULL) { if (tBlob->preExecute(tExecType, batch) == -1) + { ret = -1; + if(savedError.code==0) + savedError= theError; + } tBlob = tBlob->theNext; } if (batch) { @@ -338,7 +343,11 @@ NdbConnection::execute(ExecType aTypeOfExec, NdbBlob* tBlob = tOp->theBlobList; while (tBlob != NULL) { if (tBlob->preCommit() == -1) - ret = -1; + { + ret = -1; + if(savedError.code==0) + savedError= theError; + } tBlob = tBlob->theNext; } } @@ -360,7 +369,12 @@ NdbConnection::execute(ExecType aTypeOfExec, } if (executeNoBlobs(tExecType, abortOption, forceSend) == -1) - ret = -1; + { + ret = -1; + if(savedError.code==0) + savedError= theError; + } + #ifdef ndb_api_crash_on_complex_blob_abort assert(theFirstOpInList == NULL && theLastOpInList == NULL); #else @@ -375,7 +389,11 @@ NdbConnection::execute(ExecType aTypeOfExec, while (tBlob != NULL) { // may add new operations if batch if (tBlob->postExecute(tExecType) == -1) + { ret = -1; + if(savedError.code==0) + savedError= theError; + } tBlob = tBlob->theNext; } } @@ -406,6 +424,10 @@ NdbConnection::execute(ExecType aTypeOfExec, ndbout << "completed ops: " << n << endl; } #endif + + if(savedError.code!=0 && theError.code==4350) // Trans already aborted + theError= savedError; + DBUG_RETURN(ret); } diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp index a11dd842495..cbb344d3680 100644 --- a/ndb/src/ndbapi/Ndbinit.cpp +++ b/ndb/src/ndbapi/Ndbinit.cpp @@ -296,7 +296,8 @@ NdbImpl::NdbImpl(Ndb_cluster_connection *ndb_cluster_connection, : m_ndb_cluster_connection(ndb_cluster_connection->m_impl), m_dictionary(ndb), theCurrentConnectIndex(0), - theNdbObjectIdMap(1024,1024), + theNdbObjectIdMap(ndb_cluster_connection->m_impl.m_transporter_facade->theMutexPtr, + 1024,1024), theNoOfDBnodes(0) { int i; diff --git a/ndb/src/ndbapi/ObjectMap.hpp b/ndb/src/ndbapi/ObjectMap.hpp index 21407279f0b..c730d1ce6b1 100644 --- a/ndb/src/ndbapi/ObjectMap.hpp +++ b/ndb/src/ndbapi/ObjectMap.hpp @@ -30,7 +30,7 @@ class NdbObjectIdMap //: NdbLockable { public: STATIC_CONST( InvalidId = ~(Uint32)0 ); - NdbObjectIdMap(Uint32 initalSize = 128, Uint32 expandSize = 10); + NdbObjectIdMap(NdbMutex*, Uint32 initalSize = 128, Uint32 expandSize = 10); ~NdbObjectIdMap(); Uint32 map(void * object); @@ -46,14 +46,16 @@ private: void * m_obj; } * m_map; + NdbMutex * m_mutex; void expand(Uint32 newSize); }; inline -NdbObjectIdMap::NdbObjectIdMap(Uint32 sz, Uint32 eSz) { +NdbObjectIdMap::NdbObjectIdMap(NdbMutex* mutex, Uint32 sz, Uint32 eSz) { m_size = 0; m_firstFree = InvalidId; m_map = 0; + m_mutex = mutex; m_expandSize = eSz; expand(sz); #ifdef DEBUG_OBJECTMAP @@ -131,21 +133,26 @@ NdbObjectIdMap::getObject(Uint32 id){ inline void NdbObjectIdMap::expand(Uint32 incSize){ + NdbMutex_Lock(m_mutex); Uint32 newSize = m_size + incSize; - MapEntry * tmp = (MapEntry*)malloc(newSize * sizeof(MapEntry)); + MapEntry * tmp = (MapEntry*)realloc(m_map, newSize * sizeof(MapEntry)); - if (m_map) { - memcpy(tmp, m_map, m_size * sizeof(MapEntry)); - free((void*)m_map); + if (likely(tmp != 0)) + { + m_map = tmp; + + for(Uint32 i = m_size; i<newSize; i++){ + m_map[i].m_next = i + 1; + } + m_firstFree = m_size; + m_map[newSize-1].m_next = InvalidId; + m_size = newSize; } - m_map = tmp; - - for(Uint32 i = m_size; i<newSize; i++){ - m_map[i].m_next = i + 1; + else + { + ndbout_c("NdbObjectIdMap::expand unable to expand!!"); } - m_firstFree = m_size; - m_map[newSize-1].m_next = InvalidId; - m_size = newSize; + NdbMutex_Unlock(m_mutex); } #endif diff --git a/ndb/src/ndbapi/SignalSender.cpp b/ndb/src/ndbapi/SignalSender.cpp new file mode 100644 index 00000000000..a29fe68937b --- /dev/null +++ b/ndb/src/ndbapi/SignalSender.cpp @@ -0,0 +1,280 @@ +/* Copyright (C) 2003 MySQL AB + + 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; either version 2 of the License, or + (at your option) any later version. + + 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 "SignalSender.hpp" +#include <NdbSleep.h> +#include <SignalLoggerManager.hpp> +#include <signaldata/NFCompleteRep.hpp> +#include <signaldata/NodeFailRep.hpp> + +SimpleSignal::SimpleSignal(bool dealloc){ + memset(this, 0, sizeof(* this)); + deallocSections = dealloc; +} + +SimpleSignal::~SimpleSignal(){ + if(!deallocSections) + return; + if(ptr[0].p != 0) delete []ptr[0].p; + if(ptr[1].p != 0) delete []ptr[1].p; + if(ptr[2].p != 0) delete []ptr[2].p; +} + +void +SimpleSignal::set(class SignalSender& ss, + Uint8 trace, Uint16 recBlock, Uint16 gsn, Uint32 len){ + + header.theTrace = trace; + header.theReceiversBlockNumber = recBlock; + header.theVerId_signalNumber = gsn; + header.theLength = len; + header.theSendersBlockRef = refToBlock(ss.getOwnRef()); +} + +void +SimpleSignal::print(FILE * out){ + fprintf(out, "---- Signal ----------------\n"); + SignalLoggerManager::printSignalHeader(out, header, 0, 0, false); + SignalLoggerManager::printSignalData(out, header, theData); + for(Uint32 i = 0; i<header.m_noOfSections; i++){ + Uint32 len = ptr[i].sz; + fprintf(out, " --- Section %d size=%d ---\n", i, len); + Uint32 * signalData = ptr[i].p; + while(len >= 7){ + fprintf(out, + " H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x H\'%.8x\n", + signalData[0], signalData[1], signalData[2], signalData[3], + signalData[4], signalData[5], signalData[6]); + len -= 7; + signalData += 7; + } + if(len > 0){ + fprintf(out, " H\'%.8x", signalData[0]); + for(Uint32 i = 1; i<len; i++) + fprintf(out, " H\'%.8x", signalData[i]); + fprintf(out, "\n"); + } + } +} + +SignalSender::SignalSender(TransporterFacade *facade) + : m_lock(0) +{ + m_cond = NdbCondition_Create(); + theFacade = facade; + m_blockNo = theFacade->open(this, execSignal, execNodeStatus); + assert(m_blockNo > 0); +} + +SignalSender::~SignalSender(){ + int i; + if (m_lock) + unlock(); + theFacade->close(m_blockNo,0); + // free these _after_ closing theFacade to ensure that + // we delete all signals + for (i= m_jobBuffer.size()-1; i>= 0; i--) + delete m_jobBuffer[i]; + for (i= m_usedBuffer.size()-1; i>= 0; i--) + delete m_usedBuffer[i]; + NdbCondition_Destroy(m_cond); +} + +int SignalSender::lock() +{ + if (NdbMutex_Lock(theFacade->theMutexPtr)) + return -1; + m_lock= 1; + return 0; +} + +int SignalSender::unlock() +{ + if (NdbMutex_Unlock(theFacade->theMutexPtr)) + return -1; + m_lock= 0; + return 0; +} + +Uint32 +SignalSender::getOwnRef() const { + return numberToRef(m_blockNo, theFacade->ownId()); +} + +Uint32 +SignalSender::getAliveNode() const{ + return theFacade->get_an_alive_node(); +} + +const ClusterMgr::Node & +SignalSender::getNodeInfo(Uint16 nodeId) const { + return theFacade->theClusterMgr->getNodeInfo(nodeId); +} + +Uint32 +SignalSender::getNoOfConnectedNodes() const { + return theFacade->theClusterMgr->getNoOfConnectedNodes(); +} + +SendStatus +SignalSender::sendSignal(Uint16 nodeId, const SimpleSignal * s){ + return theFacade->theTransporterRegistry->prepareSend(&s->header, + 1, // JBB + &s->theData[0], + nodeId, + &s->ptr[0]); +} + +template<class T> +SimpleSignal * +SignalSender::waitFor(Uint32 timeOutMillis, T & t) +{ + SimpleSignal * s = t.check(m_jobBuffer); + if(s != 0){ + return s; + } + + NDB_TICKS now = NdbTick_CurrentMillisecond(); + NDB_TICKS stop = now + timeOutMillis; + Uint32 wait = (timeOutMillis == 0 ? 10 : timeOutMillis); + do { + NdbCondition_WaitTimeout(m_cond, + theFacade->theMutexPtr, + wait); + + + SimpleSignal * s = t.check(m_jobBuffer); + if(s != 0){ + m_usedBuffer.push_back(s); + return s; + } + + now = NdbTick_CurrentMillisecond(); + wait = (timeOutMillis == 0 ? 10 : stop - now); + } while(stop > now || timeOutMillis == 0); + + return 0; +} + +class WaitForAny { +public: + SimpleSignal * check(Vector<SimpleSignal*> & m_jobBuffer){ + if(m_jobBuffer.size() > 0){ + SimpleSignal * s = m_jobBuffer[0]; + m_jobBuffer.erase(0); + return s; + } + return 0; + } +}; + +SimpleSignal * +SignalSender::waitFor(Uint32 timeOutMillis){ + + WaitForAny w; + return waitFor(timeOutMillis, w); +} + +class WaitForNode { +public: + Uint32 m_nodeId; + SimpleSignal * check(Vector<SimpleSignal*> & m_jobBuffer){ + Uint32 len = m_jobBuffer.size(); + for(Uint32 i = 0; i<len; i++){ + if(refToNode(m_jobBuffer[i]->header.theSendersBlockRef) == m_nodeId){ + SimpleSignal * s = m_jobBuffer[i]; + m_jobBuffer.erase(i); + return s; + } + } + return 0; + } +}; + +SimpleSignal * +SignalSender::waitFor(Uint16 nodeId, Uint32 timeOutMillis){ + + WaitForNode w; + w.m_nodeId = nodeId; + return waitFor(timeOutMillis, w); +} + +#include <NdbApiSignal.hpp> + +void +SignalSender::execSignal(void* signalSender, + NdbApiSignal* signal, + class LinearSectionPtr ptr[3]){ + SimpleSignal * s = new SimpleSignal(true); + s->header = * signal; + memcpy(&s->theData[0], signal->getDataPtr(), 4 * s->header.theLength); + for(Uint32 i = 0; i<s->header.m_noOfSections; i++){ + s->ptr[i].p = new Uint32[ptr[i].sz]; + s->ptr[i].sz = ptr[i].sz; + memcpy(s->ptr[i].p, ptr[i].p, 4 * ptr[i].sz); + } + SignalSender * ss = (SignalSender*)signalSender; + ss->m_jobBuffer.push_back(s); + NdbCondition_Signal(ss->m_cond); +} + +void +SignalSender::execNodeStatus(void* signalSender, + Uint32 nodeId, + bool alive, + bool nfCompleted){ + if (alive) { + // node connected + return; + } + + SimpleSignal * s = new SimpleSignal(true); + SignalSender * ss = (SignalSender*)signalSender; + + // node disconnected + if(nfCompleted) + { + // node shutdown complete + s->header.theVerId_signalNumber = GSN_NF_COMPLETEREP; + NFCompleteRep *rep = (NFCompleteRep *)s->getDataPtrSend(); + rep->blockNo = 0; + rep->nodeId = 0; + rep->failedNodeId = nodeId; + rep->unused = 0; + rep->from = 0; + } + else + { + // node failure + s->header.theVerId_signalNumber = GSN_NODE_FAILREP; + NodeFailRep *rep = (NodeFailRep *)s->getDataPtrSend(); + rep->failNo = 0; + rep->masterNodeId = 0; + rep->noOfNodes = 1; + NodeBitmask::clear(rep->theNodes); + NodeBitmask::set(rep->theNodes,nodeId); + } + + ss->m_jobBuffer.push_back(s); + NdbCondition_Signal(ss->m_cond); +} + +#if __SUNPRO_CC != 0x560 +template SimpleSignal* SignalSender::waitFor<WaitForNode>(unsigned, WaitForNode&); +template SimpleSignal* SignalSender::waitFor<WaitForAny>(unsigned, WaitForAny&); +#endif +template class Vector<SimpleSignal*>; + diff --git a/ndb/src/ndbapi/SignalSender.hpp b/ndb/src/ndbapi/SignalSender.hpp new file mode 100644 index 00000000000..4b991460034 --- /dev/null +++ b/ndb/src/ndbapi/SignalSender.hpp @@ -0,0 +1,83 @@ +/* Copyright (C) 2003 MySQL AB + + 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; either version 2 of the License, or + (at your option) any later version. + + 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 SIGNAL_SENDER_HPP +#define SIGNAL_SENDER_HPP + +#include <ndb_global.h> +#include "TransporterFacade.hpp" +#include <Vector.hpp> + +struct SimpleSignal { +public: + SimpleSignal(bool dealloc = false); + ~SimpleSignal(); + + void set(class SignalSender&, + Uint8 trace, Uint16 recBlock, Uint16 gsn, Uint32 len); + + struct SignalHeader header; + Uint32 theData[25]; + LinearSectionPtr ptr[3]; + + int readSignalNumber() {return header.theVerId_signalNumber; } + Uint32 *getDataPtrSend() { return theData; } + const Uint32 *getDataPtr() const { return theData; } + + void print(FILE * out = stdout); +private: + bool deallocSections; +}; + +class SignalSender { +public: + SignalSender(TransporterFacade *facade); + virtual ~SignalSender(); + + int lock(); + int unlock(); + + Uint32 getOwnRef() const; + Uint32 getAliveNode() const; + const ClusterMgr::Node &getNodeInfo(Uint16 nodeId) const; + Uint32 getNoOfConnectedNodes() const; + + SendStatus sendSignal(Uint16 nodeId, const SimpleSignal *); + + SimpleSignal * waitFor(Uint32 timeOutMillis = 0); + SimpleSignal * waitFor(Uint16 nodeId, Uint32 timeOutMillis = 0); + SimpleSignal * waitFor(Uint16 nodeId, Uint16 gsn, Uint32 timeOutMillis = 0); +private: + int m_blockNo; + TransporterFacade * theFacade; + + static void execSignal(void* signalSender, + NdbApiSignal* signal, + class LinearSectionPtr ptr[3]); + + static void execNodeStatus(void* signalSender, Uint32 nodeId, + bool alive, bool nfCompleted); + + int m_lock; + struct NdbCondition * m_cond; + Vector<SimpleSignal *> m_jobBuffer; + Vector<SimpleSignal *> m_usedBuffer; + + template<class T> + SimpleSignal * waitFor(Uint32 timeOutMillis, T & t); +}; + +#endif diff --git a/ndb/test/include/NDBT_Test.hpp b/ndb/test/include/NDBT_Test.hpp index a60228c1a5d..bcaa0bf4d40 100644 --- a/ndb/test/include/NDBT_Test.hpp +++ b/ndb/test/include/NDBT_Test.hpp @@ -64,7 +64,8 @@ public: const char* getPropertyWait(const char*, const char* ); void decProperty(const char *); - + void incProperty(const char *); + // Communicate with other tests void stopTest(); bool isTestStopped(); diff --git a/ndb/test/ndbapi/Makefile.am b/ndb/test/ndbapi/Makefile.am index 6f04ac3fce2..7b4a96f5890 100644 --- a/ndb/test/ndbapi/Makefile.am +++ b/ndb/test/ndbapi/Makefile.am @@ -31,7 +31,8 @@ testTimeout \ testTransactions \ testDeadlock \ test_event ndbapi_slow_select testReadPerf testLcp \ -DbCreate DbAsyncGenerator +DbCreate DbAsyncGenerator \ +testSRBank #flexTimedAsynch #testBlobs @@ -72,6 +73,7 @@ testReadPerf_SOURCES = testReadPerf.cpp testLcp_SOURCES = testLcp.cpp DbCreate_SOURCES= bench/mainPopulate.cpp bench/dbPopulate.cpp bench/userInterface.cpp bench/dbPopulate.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp DbAsyncGenerator_SOURCES= bench/mainAsyncGenerator.cpp bench/asyncGenerator.cpp bench/ndb_async2.cpp bench/dbGenerator.h bench/macros.h bench/userInterface.h bench/testData.h bench/testDefinitions.h bench/ndb_schema.hpp bench/ndb_error.hpp +testSRBank_SOURCES = testSRBank.cpp INCLUDES_LOC = -I$(top_srcdir)/ndb/include/kernel @@ -83,6 +85,7 @@ include $(top_srcdir)/ndb/config/type_ndbapitest.mk.am ##testSystemRestart_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel ##testTransactions_INCLUDES = $(INCLUDES) -I$(top_srcdir)/ndb/include/kernel testBackup_LDADD = $(LDADD) bank/libbank.a +testSRBank_LDADD = bank/libbank.a $(LDADD) # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/ndb/test/ndbapi/bank/Bank.cpp b/ndb/test/ndbapi/bank/Bank.cpp index c6029259357..346442367fc 100644 --- a/ndb/test/ndbapi/bank/Bank.cpp +++ b/ndb/test/ndbapi/bank/Bank.cpp @@ -19,12 +19,13 @@ #include <NdbSleep.h> #include <UtilTransactions.hpp> -Bank::Bank(): +Bank::Bank(bool _init): m_ndb("BANK"), m_maxAccount(-1), m_initialized(false) { - + if(_init) + init(); } int Bank::init(){ @@ -34,40 +35,39 @@ int Bank::init(){ myRandom48Init(NdbTick_CurrentMillisecond()); m_ndb.init(); - while (m_ndb.waitUntilReady(10) != 0) - ndbout << "Waiting for ndb to be ready" << endl; - + if (m_ndb.waitUntilReady(30) != 0) + { + ndbout << "Ndb not ready" << endl; + return NDBT_FAILED; + } + if (getNumAccounts() != NDBT_OK) return NDBT_FAILED; + + m_initialized = true; return NDBT_OK; } int Bank::performTransactions(int maxSleepBetweenTrans, int yield){ - if (init() != NDBT_OK) - return NDBT_FAILED; int transactions = 0; - while(1){ - - while(m_ndb.waitUntilReady(10) != 0) - ndbout << "Waiting for ndb to be ready" << endl; - - while(performTransaction() != NDBT_FAILED){ - transactions++; - - if (maxSleepBetweenTrans > 0){ - int val = myRandom48(maxSleepBetweenTrans); - NdbSleep_MilliSleep(val); - } - - if((transactions % 100) == 0) - g_info << transactions << endl; - - if (yield != 0 && transactions >= yield) - return NDBT_OK; + while(performTransaction() == NDBT_OK) + { + transactions++; + + if (maxSleepBetweenTrans > 0){ + int val = myRandom48(maxSleepBetweenTrans); + NdbSleep_MilliSleep(val); } + + if((transactions % 100) == 0) + g_info << transactions << endl; + + if (yield != 0 && transactions >= yield) + return NDBT_OK; } + return NDBT_FAILED; } @@ -92,7 +92,7 @@ int Bank::performTransaction(){ int amount = myRandom48(maxAmount); - retry_transaction: +retry_transaction: int res = performTransaction(fromAccount, toAccount, amount); if (res != 0){ switch (res){ @@ -158,8 +158,9 @@ int Bank::performTransactionImpl1(int fromAccountId, // Ok, all clear to do the transaction Uint64 transId; - if (getNextTransactionId(transId) != NDBT_OK){ - return NDBT_FAILED; + int result = NDBT_OK; + if ((result= getNextTransactionId(transId)) != NDBT_OK){ + return result; } NdbConnection* pTrans = m_ndb.startTransaction(); @@ -500,8 +501,6 @@ int Bank::performTransactionImpl1(int fromAccountId, int Bank::performMakeGLs(int yield){ int result; - if (init() != NDBT_OK) - return NDBT_FAILED; int counter, maxCounter; int yieldCounter = 0; @@ -512,9 +511,6 @@ int Bank::performMakeGLs(int yield){ counter = 0; maxCounter = 50 + myRandom48(100); - while(m_ndb.waitUntilReady(10) != 0) - ndbout << "Waiting for ndb to be ready" << endl; - /** * Validate GLs and Transactions for previous days * @@ -526,6 +522,7 @@ int Bank::performMakeGLs(int yield){ return NDBT_FAILED; } g_info << "performValidateGLs failed" << endl; + return NDBT_FAILED; continue; } @@ -536,7 +533,7 @@ int Bank::performMakeGLs(int yield){ return NDBT_FAILED; } g_info << "performValidatePurged failed" << endl; - continue; + return NDBT_FAILED; } while (1){ @@ -607,14 +604,9 @@ int Bank::performMakeGLs(int yield){ int Bank::performValidateAllGLs(){ int result; - if (init() != NDBT_OK) - return NDBT_FAILED; while (1){ - while(m_ndb.waitUntilReady(10) != 0) - ndbout << "Waiting for ndb to be ready" << endl; - /** * Validate GLs and Transactions for previous days * Set age so that ALL GL's are validated @@ -1937,39 +1929,29 @@ int Bank::findTransactionsToPurge(const Uint64 glTime, } - int Bank::performIncreaseTime(int maxSleepBetweenDays, int yield){ - if (init() != NDBT_OK) - return NDBT_FAILED; - +int Bank::performIncreaseTime(int maxSleepBetweenDays, int yield) +{ int yieldCounter = 0; - - while(1){ - - while(m_ndb.waitUntilReady(10) != 0) - ndbout << "Waiting for ndb to be ready" << endl; - - while(1){ - - Uint64 currTime; - if (incCurrTime(currTime) != NDBT_OK) - break; - - g_info << "Current time is " << currTime << endl; - if (maxSleepBetweenDays > 0){ - int val = myRandom48(maxSleepBetweenDays); - NdbSleep_SecSleep(val); - } - - yieldCounter++; - if (yield != 0 && yieldCounter >= yield) - return NDBT_OK; - - } - } - return NDBT_FAILED; - } - - + + while(1){ + + Uint64 currTime; + if (incCurrTime(currTime) != NDBT_OK) + break; + + g_info << "Current time is " << currTime << endl; + if (maxSleepBetweenDays > 0){ + int val = myRandom48(maxSleepBetweenDays); + NdbSleep_SecSleep(val); + } + + yieldCounter++; + if (yield != 0 && yieldCounter >= yield) + return NDBT_OK; + + } + return NDBT_FAILED; +} int Bank::readSystemValue(SystemValueId sysValId, Uint64 & value){ @@ -1978,22 +1960,30 @@ int Bank::readSystemValue(SystemValueId sysValId, Uint64 & value){ NdbConnection* pTrans = m_ndb.startTransaction(); if (pTrans == NULL){ ERR(m_ndb.getNdbError()); + if(m_ndb.getNdbError().status == NdbError::TemporaryError) + return NDBT_TEMPORARY; return NDBT_FAILED; } - if (prepareReadSystemValueOp(pTrans, sysValId, value) != NDBT_OK) { + int result; + if ((result= prepareReadSystemValueOp(pTrans, sysValId, value)) != NDBT_OK) { ERR(pTrans->getNdbError()); m_ndb.closeTransaction(pTrans); - return NDBT_FAILED; + return result; } check = pTrans->execute(Commit); if( check == -1 ) { ERR(pTrans->getNdbError()); + if(pTrans->getNdbError().status == NdbError::TemporaryError) + { + m_ndb.closeTransaction(pTrans); + return NDBT_TEMPORARY; + } m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } - + m_ndb.closeTransaction(pTrans); return NDBT_OK; @@ -2099,6 +2089,8 @@ int Bank::increaseSystemValue(SystemValueId sysValId, Uint64 &value){ NdbConnection* pTrans = m_ndb.startTransaction(); if (pTrans == NULL){ ERR(m_ndb.getNdbError()); + if (m_ndb.getNdbError().status == NdbError::TemporaryError) + DBUG_RETURN(NDBT_TEMPORARY); DBUG_RETURN(NDBT_FAILED); } @@ -2134,6 +2126,11 @@ int Bank::increaseSystemValue(SystemValueId sysValId, Uint64 &value){ check = pTrans->execute(NoCommit); if( check == -1 ) { ERR(pTrans->getNdbError()); + if (pTrans->getNdbError().status == NdbError::TemporaryError) + { + m_ndb.closeTransaction(pTrans); + DBUG_RETURN(NDBT_TEMPORARY); + } m_ndb.closeTransaction(pTrans); DBUG_RETURN(NDBT_FAILED); } @@ -2208,16 +2205,21 @@ int Bank::increaseSystemValue(SystemValueId sysValId, Uint64 &value){ check = pTrans->execute(Commit); if( check == -1 ) { ERR(pTrans->getNdbError()); + if (pTrans->getNdbError().status == NdbError::TemporaryError) + { + m_ndb.closeTransaction(pTrans); + DBUG_RETURN(NDBT_TEMPORARY); + } m_ndb.closeTransaction(pTrans); DBUG_RETURN(NDBT_FAILED); } // Check that value updated equals the value we read after the update if (valueNewRec->u_64_value() != value){ - + printf("value actual=%lld\n", valueNewRec->u_64_value()); printf("value expected=%lld actual=%lld\n", value, valueNewRec->u_64_value()); - + DBUG_PRINT("info", ("value expected=%ld actual=%ld", value, valueNewRec->u_64_value())); g_err << "getNextTransactionId: value was not updated" << endl; m_ndb.closeTransaction(pTrans); @@ -2225,7 +2227,7 @@ int Bank::increaseSystemValue(SystemValueId sysValId, Uint64 &value){ } m_ndb.closeTransaction(pTrans); - + DBUG_RETURN(0); } @@ -2242,6 +2244,8 @@ int Bank::increaseSystemValue2(SystemValueId sysValId, Uint64 &value){ NdbConnection* pTrans = m_ndb.startTransaction(); if (pTrans == NULL){ ERR(m_ndb.getNdbError()); + if(m_ndb.getNdbError().status == NdbError::TemporaryError) + return NDBT_TEMPORARY; return NDBT_FAILED; } @@ -2284,6 +2288,11 @@ int Bank::increaseSystemValue2(SystemValueId sysValId, Uint64 &value){ check = pTrans->execute(Commit); if( check == -1 ) { ERR(pTrans->getNdbError()); + if(pTrans->getNdbError().status == NdbError::TemporaryError) + { + m_ndb.closeTransaction(pTrans); + return NDBT_TEMPORARY; + } m_ndb.closeTransaction(pTrans); return NDBT_FAILED; } @@ -2308,16 +2317,11 @@ int Bank::prepareGetCurrTimeOp(NdbConnection *pTrans, Uint64 &time){ int Bank::performSumAccounts(int maxSleepBetweenSums, int yield){ - if (init() != NDBT_OK) - return NDBT_FAILED; int yieldCounter = 0; while (1){ - while (m_ndb.waitUntilReady(10) != 0) - ndbout << "Waiting for ndb to be ready" << endl; - Uint32 sumAccounts = 0; Uint32 numAccounts = 0; if (getSumAccounts(sumAccounts, numAccounts) != NDBT_OK){ diff --git a/ndb/test/ndbapi/bank/Bank.hpp b/ndb/test/ndbapi/bank/Bank.hpp index 34c5ff51cc2..14e01df29d5 100644 --- a/ndb/test/ndbapi/bank/Bank.hpp +++ b/ndb/test/ndbapi/bank/Bank.hpp @@ -27,7 +27,7 @@ class Bank { public: - Bank(); + Bank(bool init = true); int createAndLoadBank(bool overWrite, int num_accounts=10); int dropBank(); diff --git a/ndb/test/ndbapi/testSRBank.cpp b/ndb/test/ndbapi/testSRBank.cpp new file mode 100644 index 00000000000..5677f551da6 --- /dev/null +++ b/ndb/test/ndbapi/testSRBank.cpp @@ -0,0 +1,246 @@ +/* Copyright (C) 2003 MySQL AB + + 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; either version 2 of the License, or + (at your option) any later version. + + 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 <NDBT.hpp> +#include <NDBT_Test.hpp> +#include <HugoTransactions.hpp> +#include <UtilTransactions.hpp> +#include <NdbBackup.hpp> + +#include "bank/Bank.hpp" + +int runCreateBank(NDBT_Context* ctx, NDBT_Step* step){ + Bank bank; + int overWriteExisting = true; + if (bank.createAndLoadBank(overWriteExisting, 10) != NDBT_OK) + return NDBT_FAILED; + return NDBT_OK; +} + +/** + * + * SR 0 - normal + * SR 1 - shutdown in progress + * SR 2 - restart in progress + */ +int runBankTimer(NDBT_Context* ctx, NDBT_Step* step){ + int wait = 5; // Max seconds between each "day" + int yield = 1; // Loops before bank returns + + ctx->incProperty("ThreadCount"); + while (!ctx->isTestStopped()) + { + Bank bank; + while(!ctx->isTestStopped() && ctx->getProperty("SR") <= 1) + if(bank.performIncreaseTime(wait, yield) == NDBT_FAILED) + break; + + ndbout_c("runBankTimer is stopped"); + ctx->incProperty("ThreadStopped"); + if(ctx->getPropertyWait("SR", (Uint32)0)) + break; + } + return NDBT_OK; +} + +int runBankTransactions(NDBT_Context* ctx, NDBT_Step* step){ + int wait = 0; // Max ms between each transaction + int yield = 1; // Loops before bank returns + + ctx->incProperty("ThreadCount"); + while (!ctx->isTestStopped()) + { + Bank bank; + while(!ctx->isTestStopped() && ctx->getProperty("SR") <= 1) + if(bank.performTransactions(0, 1) == NDBT_FAILED) + break; + + ndbout_c("runBankTransactions is stopped"); + ctx->incProperty("ThreadStopped"); + if(ctx->getPropertyWait("SR", (Uint32)0)) + break; + } + return NDBT_OK; +} + +int runBankGL(NDBT_Context* ctx, NDBT_Step* step){ + int yield = 1; // Loops before bank returns + int result = NDBT_OK; + + ctx->incProperty("ThreadCount"); + while (ctx->isTestStopped() == false) + { + Bank bank; + while(!ctx->isTestStopped() && ctx->getProperty("SR") <= 1) + if (bank.performMakeGLs(yield) != NDBT_OK) + { + if(ctx->getProperty("SR") != 0) + break; + ndbout << "bank.performMakeGLs FAILED" << endl; + return NDBT_FAILED; + } + + ndbout_c("runBankGL is stopped"); + ctx->incProperty("ThreadStopped"); + if(ctx->getPropertyWait("SR", (Uint32)0)) + break; + } + return NDBT_OK; +} + +int runBankSum(NDBT_Context* ctx, NDBT_Step* step){ + Bank bank; + int wait = 2000; // Max ms between each sum of accounts + int yield = 1; // Loops before bank returns + int result = NDBT_OK; + + while (ctx->isTestStopped() == false) { + if (bank.performSumAccounts(wait, yield) != NDBT_OK){ + ndbout << "bank.performSumAccounts FAILED" << endl; + result = NDBT_FAILED; + } + } + return result ; +} + +#define CHECK(b) if (!(b)) { \ + g_err << "ERR: "<< step->getName() \ + << " failed on line " << __LINE__ << endl; \ + result = NDBT_FAILED; \ + continue; } + +int runSR(NDBT_Context* ctx, NDBT_Step* step) +{ + int result = NDBT_OK; + int runtime = ctx->getNumLoops(); + int sleeptime = ctx->getNumRecords(); + NdbRestarter restarter; + bool abort = true; + int timeout = 180; + + Uint32 now; + const Uint32 stop = time(0)+ runtime; + while(!ctx->isTestStopped() && ((now= time(0)) < stop) && result == NDBT_OK) + { + ndbout << " -- Sleep " << sleeptime << "s " << endl; + NdbSleep_SecSleep(sleeptime); + ndbout << " -- Shutting down " << endl; + ctx->setProperty("SR", 1); + CHECK(restarter.restartAll(false, true, abort) == 0); + ctx->setProperty("SR", 2); + CHECK(restarter.waitClusterNoStart(timeout) == 0); + + Uint32 cnt = ctx->getProperty("ThreadCount"); + Uint32 curr= ctx->getProperty("ThreadStopped"); + while(curr != cnt) + { + ndbout_c("%d %d", curr, cnt); + NdbSleep_MilliSleep(100); + curr= ctx->getProperty("ThreadStopped"); + } + + ctx->setProperty("ThreadStopped", (Uint32)0); + CHECK(restarter.startAll() == 0); + CHECK(restarter.waitClusterStarted(timeout) == 0); + + ndbout << " -- Validating starts " << endl; + { + int wait = 0; + int yield = 1; + Bank bank; + if (bank.performSumAccounts(wait, yield) != 0) + { + ndbout << "bank.performSumAccounts FAILED" << endl; + return NDBT_FAILED; + } + + if (bank.performValidateAllGLs() != 0) + { + ndbout << "bank.performValidateAllGLs FAILED" << endl; + return NDBT_FAILED; + } + } + + ndbout << " -- Validating complete " << endl; + ctx->setProperty("SR", (Uint32)0); + ctx->broadcast(); + } + ctx->stopTest(); + return NDBT_OK; +} + +int runDropBank(NDBT_Context* ctx, NDBT_Step* step){ + Bank bank; + if (bank.dropBank() != NDBT_OK) + return NDBT_FAILED; + return NDBT_OK; +} + + +NDBT_TESTSUITE(testSRBank); +TESTCASE("Graceful", + " Test that a consistent bank is restored after graceful shutdown\n" + "1. Create bank\n" + "2. Start bank and let it run\n" + "3. Restart ndb and verify consistency\n" + "4. Drop bank\n") +{ + INITIALIZER(runCreateBank); + STEP(runBankTimer); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankGL); + STEP(runSR); +} +TESTCASE("Abort", + " Test that a consistent bank is restored after graceful shutdown\n" + "1. Create bank\n" + "2. Start bank and let it run\n" + "3. Restart ndb and verify consistency\n" + "4. Drop bank\n") +{ + INITIALIZER(runCreateBank); + STEP(runBankTimer); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankTransactions); + STEP(runBankGL); + STEP(runSR); + FINALIZER(runDropBank); +} +NDBT_TESTSUITE_END(testSRBank); + +int main(int argc, const char** argv){ + ndb_init(); + return testSRBank.execute(argc, argv); +} + + diff --git a/ndb/test/src/NDBT_Test.cpp b/ndb/test/src/NDBT_Test.cpp index 600a5443f40..6355c21c997 100644 --- a/ndb/test/src/NDBT_Test.cpp +++ b/ndb/test/src/NDBT_Test.cpp @@ -145,6 +145,15 @@ NDBT_Context::decProperty(const char * name){ NdbCondition_Broadcast(propertyCondPtr); NdbMutex_Unlock(propertyMutexPtr); } +void +NDBT_Context::incProperty(const char * name){ + NdbMutex_Lock(propertyMutexPtr); + Uint32 val = 0; + props.get(name, &val); + props.put(name, (val + 1), true); + NdbCondition_Broadcast(propertyCondPtr); + NdbMutex_Unlock(propertyMutexPtr); +} void NDBT_Context::setProperty(const char* _name, const char* _val){ NdbMutex_Lock(propertyMutexPtr); diff --git a/ndb/test/src/NdbBackup.cpp b/ndb/test/src/NdbBackup.cpp index 28724323bd7..1e56db83c11 100644 --- a/ndb/test/src/NdbBackup.cpp +++ b/ndb/test/src/NdbBackup.cpp @@ -50,14 +50,17 @@ NdbBackup::start(unsigned int & _backup_id){ 2, // wait until completed &_backup_id, &reply) == -1) { - g_err << "Could not start backup " << endl; - g_err << "Error: " << reply.message << endl; + g_err << "Error: " << ndb_mgm_get_latest_error(handle) << endl; + g_err << "Error msg: " << ndb_mgm_get_latest_error_msg(handle) << endl; + g_err << "Error desc: " << ndb_mgm_get_latest_error_desc(handle) << endl; return -1; } if(reply.return_code != 0){ g_err << "PLEASE CHECK CODE NdbBackup.cpp line=" << __LINE__ << endl; - g_err << "Error: " << reply.message << endl; + g_err << "Error: " << ndb_mgm_get_latest_error(handle) << endl; + g_err << "Error msg: " << ndb_mgm_get_latest_error_msg(handle) << endl; + g_err << "Error desc: " << ndb_mgm_get_latest_error_desc(handle) << endl; return reply.return_code; } return 0; diff --git a/ndb/test/src/UtilTransactions.cpp b/ndb/test/src/UtilTransactions.cpp index 869f7fc76cb..92073143d34 100644 --- a/ndb/test/src/UtilTransactions.cpp +++ b/ndb/test/src/UtilTransactions.cpp @@ -766,19 +766,29 @@ UtilTransactions::selectCount(Ndb* pNdb, int check; NdbScanOperation *pOp; - if(!pTrans) - pTrans = pNdb->startTransaction(); while (true){ - if (retryAttempt >= retryMax){ g_info << "ERROR: has retried this operation " << retryAttempt << " times, failing!" << endl; return NDBT_FAILED; } + if(!pTrans) + pTrans = pNdb->startTransaction(); + + if(!pTrans) + { + const NdbError err = pNdb->getNdbError(); + + if (err.status == NdbError::TemporaryError) + continue; + return NDBT_FAILED; + } + pOp = pTrans->getNdbScanOperation(tab.getName()); if (pOp == NULL) { ERR(pTrans->getNdbError()); pNdb->closeTransaction(pTrans); + pTrans = 0; return NDBT_FAILED; } @@ -786,6 +796,7 @@ UtilTransactions::selectCount(Ndb* pNdb, if( rs == 0) { ERR(pTrans->getNdbError()); pNdb->closeTransaction(pTrans); + pTrans = 0; return NDBT_FAILED; } @@ -799,6 +810,7 @@ UtilTransactions::selectCount(Ndb* pNdb, if( check == -1 ) { ERR(pTrans->getNdbError()); pNdb->closeTransaction(pTrans); + pTrans = 0; return NDBT_FAILED; } } @@ -808,6 +820,7 @@ UtilTransactions::selectCount(Ndb* pNdb, if( check == -1 ) { ERR(pTrans->getNdbError()); pNdb->closeTransaction(pTrans); + pTrans = 0; return NDBT_FAILED; } @@ -823,16 +836,19 @@ UtilTransactions::selectCount(Ndb* pNdb, if (err.status == NdbError::TemporaryError){ pNdb->closeTransaction(pTrans); + pTrans = 0; NdbSleep_MilliSleep(50); retryAttempt++; continue; } ERR(err); pNdb->closeTransaction(pTrans); + pTrans = 0; return NDBT_FAILED; } pNdb->closeTransaction(pTrans); + pTrans = 0; if (count_rows != NULL){ *count_rows = rows; diff --git a/ndb/tools/Makefile.am b/ndb/tools/Makefile.am index 89830129576..795441380a8 100644 --- a/ndb/tools/Makefile.am +++ b/ndb/tools/Makefile.am @@ -30,7 +30,7 @@ ndb_restore_SOURCES = restore/restore_main.cpp \ restore/consumer.cpp \ restore/consumer_restore.cpp \ restore/consumer_printer.cpp \ - restore/Restore.cpp + restore/Restore.cpp $(tools_common_sources) ndb_config_SOURCES = ndb_config.cpp \ ../src/mgmsrv/Config.cpp \ diff --git a/ndb/tools/ndb_config.cpp b/ndb/tools/ndb_config.cpp index d188aec1337..725249a5af5 100644 --- a/ndb/tools/ndb_config.cpp +++ b/ndb/tools/ndb_config.cpp @@ -42,6 +42,7 @@ static const char * g_field_delimiter=","; static const char * g_row_delimiter=" "; int g_print_full_config, opt_ndb_shm; +my_bool opt_core; typedef ndb_mgm_configuration_iterator Iter; diff --git a/ndb/tools/restore/consumer_restore.cpp b/ndb/tools/restore/consumer_restore.cpp index d782a561e6a..70ea7460d78 100644 --- a/ndb/tools/restore/consumer_restore.cpp +++ b/ndb/tools/restore/consumer_restore.cpp @@ -14,9 +14,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <NDBT_ReturnCodes.h> #include "consumer_restore.hpp" #include <NdbSleep.h> +extern my_bool opt_core; + extern FilteredNdbOut err; extern FilteredNdbOut info; extern FilteredNdbOut debug; @@ -458,7 +461,11 @@ bool BackupRestore::errorHandler(restore_callback_t *cb) void BackupRestore::exitHandler() { release(); - exit(-1); + NDBT_ProgramExit(NDBT_FAILED); + if (opt_core) + abort(); + else + exit(NDBT_FAILED); } @@ -492,7 +499,7 @@ BackupRestore::logEntry(const LogEntry & tup) { // Deep shit, TODO: handle the error err << "Cannot start transaction" << endl; - exit(-1); + exitHandler(); } // if const NdbDictionary::Table * table = get_table(tup.m_table->m_dictTable); @@ -500,7 +507,7 @@ BackupRestore::logEntry(const LogEntry & tup) if (op == NULL) { err << "Cannot get operation: " << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if int check = 0; @@ -518,13 +525,13 @@ BackupRestore::logEntry(const LogEntry & tup) default: err << "Log entry has wrong operation type." << " Exiting..."; - exit(-1); + exitHandler(); } if (check != 0) { err << "Error defining op: " << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if Bitmask<4096> keys; @@ -553,7 +560,7 @@ BackupRestore::logEntry(const LogEntry & tup) if (check != 0) { err << "Error defining op: " << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if } @@ -582,7 +589,7 @@ BackupRestore::logEntry(const LogEntry & tup) if (!ok) { err << "execute failed: " << errobj << endl; - exit(-1); + exitHandler(); } } @@ -629,7 +636,7 @@ BackupRestore::tuple(const TupleS & tup) { // Deep shit, TODO: handle the error ndbout << "Cannot start transaction" << endl; - exit(-1); + exitHandler(); } // if const TableS * table = tup.getTable(); @@ -638,7 +645,7 @@ BackupRestore::tuple(const TupleS & tup) { ndbout << "Cannot get operation: "; ndbout << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if // TODO: check return value and handle error @@ -646,7 +653,7 @@ BackupRestore::tuple(const TupleS & tup) { ndbout << "writeTuple call failed: "; ndbout << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } // if for (int i = 0; i < tup.getNoOfAttributes(); i++) @@ -680,7 +687,7 @@ BackupRestore::tuple(const TupleS & tup) { ndbout << "execute failed: "; ndbout << trans->getNdbError() << endl; - exit(-1); + exitHandler(); } m_ndb->closeTransaction(trans); if (ret == 0) diff --git a/ndb/tools/restore/restore_main.cpp b/ndb/tools/restore/restore_main.cpp index 0c4419bb072..d786dffe89e 100644 --- a/ndb/tools/restore/restore_main.cpp +++ b/ndb/tools/restore/restore_main.cpp @@ -20,6 +20,7 @@ #include <ndb_limits.h> #include <NdbTCP.h> #include <NdbOut.hpp> +#include <NDBT_ReturnCodes.h> #include "consumer_restore.hpp" #include "consumer_printer.hpp" @@ -116,14 +117,14 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), if (ga_nodeId == 0) { printf("Error in --nodeid,-n setting, see --help\n"); - exit(1); + exit(NDBT_ProgramExit(NDBT_WRONGARGS)); } break; case 'b': if (ga_backupId == 0) { printf("Error in --backupid,-b setting, see --help\n"); - exit(1); + exit(NDBT_ProgramExit(NDBT_WRONGARGS)); } break; } @@ -136,7 +137,7 @@ readArguments(int *pargc, char*** pargv) load_defaults("my",load_default_groups,pargc,pargv); if (handle_options(pargc, pargv, my_long_options, get_one_option)) { - exit(1); + exit(NDBT_ProgramExit(NDBT_WRONGARGS)); } BackupPrinter* printer = new BackupPrinter(); @@ -226,6 +227,15 @@ free_data_callback() g_consumers[i]->tuple_free(); } +static void exitHandler(int code) +{ + NDBT_ProgramExit(code); + if (opt_core) + abort(); + else + exit(code); +} + int main(int argc, char** argv) { @@ -233,7 +243,7 @@ main(int argc, char** argv) if (!readArguments(&argc, &argv)) { - return -1; + exitHandler(NDBT_FAILED); } Ndb::setConnectString(opt_connect_str); @@ -245,7 +255,7 @@ main(int argc, char** argv) if (!metaData.readHeader()) { ndbout << "Failed to read " << metaData.getFilename() << endl << endl; - return -1; + exitHandler(NDBT_FAILED); } const BackupFormat::FileHeader & tmp = metaData.getFileHeader(); @@ -263,20 +273,20 @@ main(int argc, char** argv) if (res == 0) { ndbout_c("Restore: Failed to load content"); - return -1; + exitHandler(NDBT_FAILED); } if (metaData.getNoOfTables() == 0) { ndbout_c("Restore: The backup contains no tables "); - return -1; + exitHandler(NDBT_FAILED); } if (!metaData.validateFooter()) { ndbout_c("Restore: Failed to validate footer."); - return -1; + exitHandler(NDBT_FAILED); } Uint32 i; @@ -285,7 +295,7 @@ main(int argc, char** argv) if (!g_consumers[i]->init()) { clearConsumers(); - return -11; + exitHandler(NDBT_FAILED); } } @@ -300,7 +310,7 @@ main(int argc, char** argv) ndbout_c("Restore: Failed to restore table: %s. " "Exiting...", metaData[i]->getTableName()); - return -11; + exitHandler(NDBT_FAILED); } } } @@ -309,7 +319,7 @@ main(int argc, char** argv) if (!g_consumers[i]->endOfTables()) { ndbout_c("Restore: Failed while closing tables"); - return -11; + exitHandler(NDBT_FAILED); } if (ga_restore || ga_print) @@ -322,7 +332,7 @@ main(int argc, char** argv) if (!dataIter.readHeader()) { ndbout << "Failed to read header of data file. Exiting..." ; - return -11; + exitHandler(NDBT_FAILED); } @@ -340,12 +350,12 @@ main(int argc, char** argv) { ndbout_c("Restore: An error occured while restoring data. " "Exiting..."); - return -1; + exitHandler(NDBT_FAILED); } if (!dataIter.validateFragmentFooter()) { ndbout_c("Restore: Error validating fragment footer. " "Exiting..."); - return -1; + exitHandler(NDBT_FAILED); } } // while (dataIter.readFragmentHeader(res)) @@ -353,7 +363,7 @@ main(int argc, char** argv) { err << "Restore: An error occured while restoring data. Exiting... " << "res=" << res << endl; - return -1; + exitHandler(NDBT_FAILED); } @@ -366,7 +376,7 @@ main(int argc, char** argv) if (!logIter.readHeader()) { err << "Failed to read header of data file. Exiting..." << endl; - return -1; + exitHandler(NDBT_FAILED); } const LogEntry * logEntry = 0; @@ -380,7 +390,7 @@ main(int argc, char** argv) { err << "Restore: An restoring the data log. Exiting... res=" << res << endl; - return -1; + exitHandler(NDBT_FAILED); } logIter.validateFooter(); //not implemented for (i= 0; i < g_consumers.size(); i++) @@ -395,14 +405,14 @@ main(int argc, char** argv) ndbout_c("Restore: Failed to finalize restore table: %s. " "Exiting...", metaData[i]->getTableName()); - return -11; + exitHandler(NDBT_FAILED); } } } } } clearConsumers(); - return 0; + return NDBT_ProgramExit(NDBT_OK); } // main template class Vector<BackupConsumer*>; diff --git a/scripts/mysqld_multi.sh b/scripts/mysqld_multi.sh index ba46fd6fa29..7fff4cbb731 100644 --- a/scripts/mysqld_multi.sh +++ b/scripts/mysqld_multi.sh @@ -289,8 +289,10 @@ sub start_mysqlds() } else { - $options[$j]=~ s/;/\\;/g; - $tmp.= " $options[$j]"; + # we single-quote the argument, but first convert single-quotes to + # '"'"' so they are passed through correctly + $options[$j]=~ s/'/'"'"'/g; + $tmp.= " '$options[$j]'"; } } if ($opt_verbose && $com =~ m/\/safe_mysqld$/ && !$info_sent) @@ -374,7 +376,12 @@ sub get_mysqladmin_options $mysqladmin_found= 0 if (!length($mysqladmin)); $com = "$mysqladmin"; $tmp = " -u $opt_user"; - $tmp.= defined($opt_password) ? " -p$opt_password" : ""; + if (defined($opt_password)) { + my $pw= $opt_password; + # Protect single quotes in password + $pw =~ s/'/'"'"'/g; + $tmp.= " -p'$pw'"; + } $tmp.= $opt_tcp_ip ? " -h 127.0.0.1" : ""; for ($j = 0; defined($options[$j]); $j++) { diff --git a/sql-common/client.c b/sql-common/client.c index 73e136f7366..3979b9304f7 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -602,7 +602,7 @@ net_safe_read(MYSQL *mysql) DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %d", vio_description(net->vio),len)); #ifdef MYSQL_SERVER - if (vio_errno(net->vio) == SOCKET_EINTR) + if (vio_was_interrupted(net->vio)) return (packet_error); #endif /*MYSQL_SERVER*/ end_server(mysql); diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index 577ead8a86d..ee4cad25460 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -520,7 +520,7 @@ int ha_archive::create(const char *name, TABLE *table_arg, error= my_errno; goto error; } - if ((archive= gzdopen(create_file, "ab")) == NULL) + if ((archive= gzdopen(create_file, "wb")) == NULL) { error= errno; goto error2; diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index bbcdfb0dafb..8a9aa91c680 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -609,7 +609,8 @@ int ha_tina::rnd_init(bool scan) records= 0; chain_ptr= chain; #ifdef HAVE_MADVISE - (void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL); + if (scan) + (void)madvise(share->mapped_file,share->file_stat.st_size,MADV_SEQUENTIAL); #endif DBUG_RETURN(0); diff --git a/sql/filesort.cc b/sql/filesort.cc index 75b114fc140..63a8515020b 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -443,7 +443,7 @@ static ha_rows find_all_keys(SORTPARAM *param, SQL_SELECT *select, ha_store_ptr(ref_pos,ref_length,record); // Position to row record+=sort_form->db_record_offset; } - else + else if (!error) file->position(sort_form->record[0]); } if (error && error != HA_ERR_RECORD_DELETED) diff --git a/sql/hostname.cc b/sql/hostname.cc index 39223556024..32e1d84fac3 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -130,15 +130,23 @@ void reset_host_errors(struct in_addr *in) VOID(pthread_mutex_unlock(&hostname_cache->lock)); } +/* Deal with systems that don't defined INADDR_LOOPBACK */ +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK 0x7f000001UL +#endif my_string ip_to_hostname(struct in_addr *in, uint *errors) { uint i; host_entry *entry; DBUG_ENTER("ip_to_hostname"); + *errors= 0; + + /* We always treat the loopback address as "localhost". */ + if (in->s_addr == htonl(INADDR_LOOPBACK)) + DBUG_RETURN((char *)my_localhost); /* Check first if we have name in cache */ - *errors=0; if (!(specialflag & SPECIAL_NO_HOST_CACHE)) { VOID(pthread_mutex_lock(&hostname_cache->lock)); diff --git a/sql/item.cc b/sql/item.cc index 7aaa678ddb0..010189c321c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1973,14 +1973,7 @@ void Item::make_field(Send_field *tmp_field) void Item_empty_string::make_field(Send_field *tmp_field) { - enum_field_types type = FIELD_TYPE_VAR_STRING; - if (max_length >= 16777216) - type = FIELD_TYPE_LONG_BLOB; - else if (max_length >= 65536) - type = FIELD_TYPE_MEDIUM_BLOB; - else if (max_length >= 256) - type = FIELD_TYPE_BLOB; - init_make_field(tmp_field, type); + init_make_field(tmp_field,FIELD_TYPE_VAR_STRING); } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 9146b3c3b9e..74eed7fa41a 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -51,7 +51,8 @@ static void agg_cmp_type(Item_result *type, Item **items, uint nitems) type[0]= item_cmp_type(type[0], items[i]->result_type()); } -static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname) +static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, + const char *fname) { my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0), c1.collation->name,c1.derivation_name(), @@ -820,6 +821,55 @@ longlong Item_func_interval::val_int() return i-1; } + +/* + Perform context analysis of a BETWEEN item tree + + SYNOPSIS: + fix_fields() + thd reference to the global context of the query thread + tables list of all open tables involved in the query + ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + DESCRIPTION + This function performs context analysis (name resolution) and calculates + various attributes of the item tree with Item_func_between as its root. + The function saves in ref the pointer to the item or to a newly created + item that is considered as a replacement for the original one. + + NOTES + Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on + a predicate/function level. Then it's easy to show that: + T0(e BETWEEN e1 AND e2) = union(T1(e),T1(e1),T1(e2)) + T1(e BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) + T0(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) + T1(e NOT BETWEEN e1 AND e2) = union(T1(e),intersection(T1(e1),T1(e2))) + + RETURN + 0 ok + 1 got error +*/ + +bool Item_func_between::fix_fields(THD *thd, struct st_table_list *tables, + Item **ref) +{ + if (Item_func_opt_neg::fix_fields(thd, tables, ref)) + return 1; + + /* not_null_tables_cache == union(T1(e),T1(e1),T1(e2)) */ + if (pred_level && !negated) + return 0; + + /* not_null_tables_cache == union(T1(e), intersection(T1(e1),T1(e2))) */ + not_null_tables_cache= (args[0]->not_null_tables() | + (args[1]->not_null_tables() & + args[2]->not_null_tables())); + + return 0; +} + + void Item_func_between::fix_length_and_dec() { max_length= 1; @@ -871,8 +921,9 @@ longlong Item_func_between::val_int() a=args[1]->val_str(&value1); b=args[2]->val_str(&value2); if (!args[1]->null_value && !args[2]->null_value) - return (sortcmp(value,a,cmp_collation.collation) >= 0 && - sortcmp(value,b,cmp_collation.collation) <= 0) ? 1 : 0; + return (longlong) ((sortcmp(value,a,cmp_collation.collation) >= 0 && + sortcmp(value,b,cmp_collation.collation) <= 0) != + negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -894,7 +945,7 @@ longlong Item_func_between::val_int() a=args[1]->val_int(); b=args[2]->val_int(); if (!args[1]->null_value && !args[2]->null_value) - return (value >= a && value <= b) ? 1 : 0; + return (longlong) ((value >= a && value <= b) != negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -914,7 +965,7 @@ longlong Item_func_between::val_int() a=args[1]->val(); b=args[2]->val(); if (!args[1]->null_value && !args[2]->null_value) - return (value >= a && value <= b) ? 1 : 0; + return (longlong) ((value >= a && value <= b) != negated); if (args[1]->null_value && args[2]->null_value) null_value=1; else if (args[1]->null_value) @@ -926,7 +977,7 @@ longlong Item_func_between::val_int() null_value= value >= a; } } - return 0; + return (longlong) (!null_value && negated); } @@ -934,6 +985,8 @@ void Item_func_between::print(String *str) { str->append('('); args[0]->print(str); + if (negated) + str->append(" not", 4); str->append(" between ", 9); args[1]->print(str); str->append(" and ", 5); @@ -1019,6 +1072,49 @@ Item_func_ifnull::val_str(String *str) } +/* + Perform context analysis of an IF item tree + + SYNOPSIS: + fix_fields() + thd reference to the global context of the query thread + tables list of all open tables involved in the query + ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + DESCRIPTION + This function performs context analysis (name resolution) and calculates + various attributes of the item tree with Item_func_if as its root. + The function saves in ref the pointer to the item or to a newly created + item that is considered as a replacement for the original one. + + NOTES + Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on + a predicate/function level. Then it's easy to show that: + T0(IF(e,e1,e2) = T1(IF(e,e1,e2)) + T1(IF(e,e1,e2)) = intersection(T1(e1),T1(e2)) + + RETURN + 0 ok + 1 got error +*/ + +bool +Item_func_if::fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) +{ + DBUG_ASSERT(fixed == 0); + args[0]->top_level_item(); + + if (Item_func::fix_fields(thd, tlist, ref)) + return 1; + + not_null_tables_cache= (args[1]->not_null_tables() & + args[2]->not_null_tables()); + + return 0; +} + + void Item_func_if::fix_length_and_dec() { @@ -1750,6 +1846,56 @@ bool Item_func_in::nulls_in_row() } +/* + Perform context analysis of an IN item tree + + SYNOPSIS: + fix_fields() + thd reference to the global context of the query thread + tables list of all open tables involved in the query + ref pointer to Item* variable where pointer to resulting "fixed" + item is to be assigned + + DESCRIPTION + This function performs context analysis (name resolution) and calculates + various attributes of the item tree with Item_func_in as its root. + The function saves in ref the pointer to the item or to a newly created + item that is considered as a replacement for the original one. + + NOTES + Let T0(e)/T1(e) be the value of not_null_tables(e) when e is used on + a predicate/function level. Then it's easy to show that: + T0(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) + T1(e IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) + T0(e NOT IN(e1,...,en)) = union(T1(e),union(T1(ei))) + T1(e NOT IN(e1,...,en)) = union(T1(e),intersection(T1(ei))) + + RETURN + 0 ok + 1 got error +*/ + +bool +Item_func_in::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +{ + Item **arg, **arg_end; + + if (Item_func_opt_neg::fix_fields(thd, tables, ref)) + return 1; + + /* not_null_tables_cache == union(T1(e),union(T1(ei))) */ + if (pred_level && negated) + return 0; + + /* not_null_tables_cache = union(T1(e),intersection(T1(ei))) */ + not_null_tables_cache= ~(table_map) 0; + for (arg= args + 1, arg_end= args + arg_count; arg != arg_end; arg++) + not_null_tables_cache&= (*arg)->not_null_tables(); + not_null_tables_cache|= (*args)->not_null_tables(); + return 0; +} + + static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) { return cs->coll->strnncollsp(cs, @@ -1827,6 +1973,8 @@ void Item_func_in::print(String *str) { str->append('('); args[0]->print(str); + if (negated) + str->append(" not", 4); str->append(" in (", 5); print_args(str, 1); str->append("))", 2); @@ -1840,7 +1988,7 @@ longlong Item_func_in::val_int() { int tmp=array->find(args[0]); null_value=args[0]->null_value || (!tmp && have_null); - return tmp; + return (longlong) (!null_value && tmp != negated); } in_item->store_value(args[0]); if ((null_value=args[0]->null_value)) @@ -1849,11 +1997,11 @@ longlong Item_func_in::val_int() for (uint i=1 ; i < arg_count ; i++) { if (!in_item->cmp(args[i]) && !args[i]->null_value) - return 1; // Would maybe be nice with i ? + return (longlong) (!negated); have_null|= args[i]->null_value; } null_value= have_null; - return 0; + return (longlong) (!null_value && negated); } @@ -2293,7 +2441,42 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) { /* If we are on execution stage */ String *escape_str= escape_item->val_str(&tmp_value1); - escape= escape_str ? *(escape_str->ptr()) : '\\'; + if (escape_str) + { + CHARSET_INFO *cs= cmp.cmp_collation.collation; + if (use_mb(cs)) + { + my_wc_t wc; + int rc= cs->cset->mb_wc(cs, &wc, + (const uchar*) escape_str->ptr(), + (const uchar*) escape_str->ptr() + + escape_str->length()); + escape= (int) (rc > 0 ? wc : '\\'); + } + else + { + /* + In the case of 8bit character set, we pass native + code instead of Unicode code as "escape" argument. + Convert to "cs" if charset of escape differs. + */ + uint32 unused; + if (escape_str->needs_conversion(escape_str->length(), + escape_str->charset(), cs, &unused)) + { + char ch; + uint errors; + uint32 cnvlen= copy_and_convert(&ch, 1, cs, escape_str->ptr(), + escape_str->length(), + escape_str->charset(), &errors); + escape= cnvlen ? ch : '\\'; + } + else + escape= *(escape_str->ptr()); + } + } + else + escape= '\\'; /* We could also do boyer-more for non-const items, but as we would have to diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 47884f6064e..741ae90108a 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -358,17 +358,49 @@ public: }; -class Item_func_between :public Item_int_func +/* + The class Item_func_opt_neg is defined to factor out the functionality + common for the classes Item_func_between and Item_func_in. The objects + of these classes can express predicates or there negations. + The alternative approach would be to create pairs Item_func_between, + Item_func_notbetween and Item_func_in, Item_func_notin. + +*/ + +class Item_func_opt_neg :public Item_int_func +{ +public: + bool negated; /* <=> the item represents NOT <func> */ + bool pred_level; /* <=> [NOT] <func> is used on a predicate level */ +public: + Item_func_opt_neg(Item *a, Item *b, Item *c) + :Item_int_func(a, b, c), negated(0), pred_level(0) {} + Item_func_opt_neg(List<Item> &list) + :Item_int_func(list), negated(0), pred_level(0) {} +public: + inline void negate() { negated= !negated; } + inline void top_level_item() { pred_level= 1; } + Item *neg_transformer(THD *thd) + { + negated= !negated; + return this; + } +}; + + +class Item_func_between :public Item_func_opt_neg { DTCollation cmp_collation; public: Item_result cmp_type; String value0,value1,value2; - Item_func_between(Item *a,Item *b,Item *c) :Item_int_func(a,b,c) {} + Item_func_between(Item *a, Item *b, Item *c) + :Item_func_opt_neg(a, b, c) {} longlong val_int(); optimize_type select_optimize() const { return OPTIMIZE_KEY; } enum Functype functype() const { return BETWEEN; } const char *func_name() const { return "between"; } + bool fix_fields(THD *, struct st_table_list *, Item **); void fix_length_and_dec(); void print(String *str); CHARSET_INFO *compare_collation() { return cmp_collation.collation; } @@ -433,15 +465,9 @@ public: longlong val_int(); String *val_str(String *str); enum Item_result result_type () const { return cached_result_type; } - bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref) - { - DBUG_ASSERT(fixed == 0); - args[0]->top_level_item(); - return Item_func::fix_fields(thd, tlist, ref); - } + bool fix_fields(THD *, struct st_table_list *, Item **); void fix_length_and_dec(); const char *func_name() const { return "if"; } - table_map not_null_tables() const { return 0; } }; @@ -736,7 +762,7 @@ public: } }; -class Item_func_in :public Item_int_func +class Item_func_in :public Item_func_opt_neg { Item_result cmp_type; in_vector *array; @@ -745,11 +771,12 @@ class Item_func_in :public Item_int_func DTCollation cmp_collation; public: Item_func_in(List<Item> &list) - :Item_int_func(list), array(0), in_item(0), have_null(0) + :Item_func_opt_neg(list), array(0), in_item(0), have_null(0) { allowed_arg_cols= 0; // Fetch this value from first argument } longlong val_int(); + bool fix_fields(THD *, struct st_table_list *, Item **); void fix_length_and_dec(); void cleanup() { @@ -769,12 +796,6 @@ class Item_func_in :public Item_int_func bool nulls_in_row(); bool is_bool_func() { return 1; } CHARSET_INFO *compare_collation() { return cmp_collation.collation; } - /* - IN() protect from NULL only first argument, if construction like - "expression IN ()" will be allowed, we will need to check number of - argument here, because "NOT(NULL IN ())" is TRUE. - */ - table_map not_null_tables() const { return args[0]->not_null_tables(); } }; /* Functions used by where clause */ @@ -805,7 +826,7 @@ public: else { args[0]->update_used_tables(); - if (!(used_tables_cache=args[0]->used_tables())) + if ((const_item_cache= !(used_tables_cache= args[0]->used_tables()))) { /* Remember if the value is always NULL or never NULL */ cached_value= (longlong) args[0]->is_null(); @@ -879,7 +900,7 @@ class Item_func_like :public Item_bool_func2 Item *escape_item; public: - char escape; + int escape; Item_func_like(Item *a,Item *b, Item *escape_arg) :Item_bool_func2(a,b), canDoTurboBM(FALSE), pattern(0), pattern_len(0), diff --git a/sql/item_func.cc b/sql/item_func.cc index 41573406949..ebb200ec4da 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1038,6 +1038,11 @@ bool Item_func_rand::fix_fields(THD *thd, struct st_table_list *tables, used_tables_cache|= RAND_TABLE_BIT; if (arg_count) { // Only use argument once in query + if (!args[0]->const_during_execution()) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "RAND"); + return TRUE; + } /* Allocate rand structure once: we must use thd->current_arena to create rand in proper mem_root if it's a prepared statement or diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 000dcdb4997..6ae782db557 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1664,7 +1664,9 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)), char buff[MAX_FIELD_WIDTH]; String tmp((char *)&buff,sizeof(buff),default_charset_info), tmp2; - if (item->result.length()) + if (item->no_appended) + item->no_appended= FALSE; + else item->result.append(*item->separator); tmp.length(0); @@ -1856,6 +1858,7 @@ void Item_func_group_concat::clear() result.copy(); null_value= TRUE; warning_for_row= FALSE; + no_appended= TRUE; if (tree_mode) reset_tree(tree); } @@ -1898,8 +1901,7 @@ bool Item_func_group_concat::add() void Item_func_group_concat::reset_field() { - if (tree_mode) - reset_tree(tree); + DBUG_ASSERT(0); } @@ -1935,6 +1937,7 @@ Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) args, arg_count, MY_COLL_ALLOW_CONV)) return 1; + result.set_charset(collation.collation); result_field= 0; null_value= 1; max_length= group_concat_max_len; diff --git a/sql/item_sum.h b/sql/item_sum.h index a3b422565d1..d53d8d861ae 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -709,6 +709,7 @@ class Item_func_group_concat : public Item_sum uint arg_count_field; uint field_list_offset; uint count_cut_values; + bool no_appended; /* Following is 0 normal object and pointer to original one for copy (to correctly free resources) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 0af3ea3af63..32c5861028e 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -59,6 +59,7 @@ void kill_one_thread(THD *thd, ulong id); bool net_request_file(NET* net, const char* fname); char* query_table_status(THD *thd,const char *db,const char *table_name); + #define x_free(A) { my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); } #define safeFree(x) { if(x) { my_free((gptr) x,MYF(0)); x = NULL; } } #define PREV_BITS(type,A) ((type) (((type) 1 << (A)) -1)) @@ -412,6 +413,7 @@ struct Query_cache_query_flags #define query_cache_store_query(A, B) query_cache.store_query(A, B) #define query_cache_destroy() query_cache.destroy() #define query_cache_result_size_limit(A) query_cache.result_size_limit(A) +#define query_cache_init() query_cache.init() #define query_cache_resize(A) query_cache.resize(A) #define query_cache_set_min_res_unit(A) query_cache.set_min_res_unit(A) #define query_cache_invalidate3(A, B, C) query_cache.invalidate(A, B, C) @@ -425,6 +427,7 @@ struct Query_cache_query_flags #define query_cache_store_query(A, B) #define query_cache_destroy() #define query_cache_result_size_limit(A) +#define query_cache_init() #define query_cache_resize(A) #define query_cache_set_min_res_unit(A) #define query_cache_invalidate3(A, B, C) @@ -462,6 +465,7 @@ void mysql_reset_thd_for_next_command(THD *thd); bool mysql_new_select(LEX *lex, bool move_down); void create_select_for_variable(const char *var_name); void mysql_init_multi_delete(LEX *lex); +void fix_multi_delete_lex(LEX* lex); void init_max_user_conn(void); void init_update_queries(void); void free_max_user_conn(void); @@ -931,6 +935,7 @@ extern bool opt_using_transactions, mysqld_embedded; extern bool using_update_log, opt_large_files, server_id_supplied; extern bool opt_log, opt_update_log, opt_bin_log, opt_slow_log, opt_error_log; extern bool opt_disable_networking, opt_skip_show_db; +extern bool opt_character_set_client_handshake; extern bool volatile abort_loop, shutdown_in_progress, grant_option; extern uint volatile thread_count, thread_running, global_read_lock; extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8894ed39b08..86ba437596d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -271,6 +271,7 @@ arg_cmp_func Arg_comparator::comparator_matrix[4][2] = bool opt_log, opt_update_log, opt_bin_log, opt_slow_log; bool opt_error_log= IF_WIN(1,0); bool opt_disable_networking=0, opt_skip_show_db=0; +bool opt_character_set_client_handshake= 1; bool lower_case_table_names_used= 0; bool server_id_supplied = 0; bool opt_endinfo,using_udf_functions, locked_in_memory; @@ -2704,6 +2705,7 @@ static int init_server_components() query_cache_result_size_limit(query_cache_limit); query_cache_set_min_res_unit(query_cache_min_res_unit); + query_cache_init(); query_cache_resize(query_cache_size); randominit(&sql_rand,(ulong) start_time,(ulong) start_time/2); reset_floating_point_exceptions(); @@ -4216,6 +4218,7 @@ enum options_mysqld OPT_EXPIRE_LOGS_DAYS, OPT_GROUP_CONCAT_MAX_LEN, OPT_DEFAULT_COLLATION, + OPT_CHARACTER_SET_CLIENT_HANDSHAKE, OPT_INIT_CONNECT, OPT_INIT_SLAVE, OPT_SECURE_AUTH, @@ -4295,6 +4298,11 @@ Disable with --skip-bdb (will save memory).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"character-set-client-handshake", OPT_CHARACTER_SET_CLIENT_HANDSHAKE, + "Don't use client side character set value sent during handshake.", + (gptr*) &opt_character_set_client_handshake, + (gptr*) &opt_character_set_client_handshake, + 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, {"character-set-server", 'C', "Set the default character set.", (gptr*) &default_character_set_name, (gptr*) &default_character_set_name, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, @@ -5536,13 +5544,13 @@ struct show_var_st status_vars[]= { {"Key_blocks_used", (char*) &dflt_key_cache_var.blocks_used, SHOW_KEY_CACHE_CONST_LONG}, {"Key_read_requests", (char*) &dflt_key_cache_var.global_cache_r_requests, - SHOW_KEY_CACHE_LONG}, + SHOW_KEY_CACHE_LONGLONG}, {"Key_reads", (char*) &dflt_key_cache_var.global_cache_read, - SHOW_KEY_CACHE_LONG}, + SHOW_KEY_CACHE_LONGLONG}, {"Key_write_requests", (char*) &dflt_key_cache_var.global_cache_w_requests, - SHOW_KEY_CACHE_LONG}, + SHOW_KEY_CACHE_LONGLONG}, {"Key_writes", (char*) &dflt_key_cache_var.global_cache_write, - SHOW_KEY_CACHE_LONG}, + SHOW_KEY_CACHE_LONGLONG}, {"Max_used_connections", (char*) &max_used_connections, SHOW_LONG}, {"Not_flushed_delayed_rows", (char*) &delayed_rows_in_use, SHOW_LONG_CONST}, {"Open_files", (char*) &my_file_opened, SHOW_LONG_CONST}, diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 9d84d0b2427..93fa7ac938c 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -759,7 +759,7 @@ my_real_read(NET *net, ulong *complen) net->error= 2; /* Close socket */ net->report_error= 1; #ifdef MYSQL_SERVER - net->last_errno= (interrupted ? ER_NET_READ_INTERRUPTED : + net->last_errno= (vio_was_interrupted(net->vio) ? ER_NET_READ_INTERRUPTED : ER_NET_READ_ERROR); #endif goto end; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 2dd097cbaab..5cb330100f8 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -849,7 +849,8 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) if (cond_func->functype() == Item_func::BETWEEN) { - if (cond_func->arguments()[0]->type() == Item::FIELD_ITEM) + if (!((Item_func_between *)(cond_func))->negated && + cond_func->arguments()[0]->type() == Item::FIELD_ITEM) { Field *field=((Item_field*) (cond_func->arguments()[0]))->field; Item_result cmp_type=field->cmp_type(); @@ -866,7 +867,7 @@ static SEL_TREE *get_mm_tree(PARAM *param,COND *cond) if (cond_func->functype() == Item_func::IN_FUNC) { // COND OR Item_func_in *func=(Item_func_in*) cond_func; - if (func->key_item()->type() == Item::FIELD_ITEM) + if (!func->negated && func->key_item()->type() == Item::FIELD_ITEM) { Field *field=((Item_field*) (func->key_item()))->field; Item_result cmp_type=field->cmp_type(); diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 4ab506cc4e1..cb8e3c2d273 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -661,7 +661,8 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, If key_part2 may be NULL, then we want to find the first row that is not null */ - ref->key_buff[ref->key_length++]= 1; + ref->key_buff[ref->key_length]= 1; + ref->key_length+= part->store_length; *range_fl&= ~NO_MIN_RANGE; *range_fl|= NEAR_MIN; // > NULL } diff --git a/sql/slave.cc b/sql/slave.cc index 9ff7a432b89..1be3e3b4a17 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -746,14 +746,7 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len) rules (see code below). For that reason, users should not set conflicting rules because they may get unpredicted results (precedence order is explained in the manual). - If no table of the list is marked "updating" (so far this can only happen - if the statement is a multi-delete (SQLCOM_DELETE_MULTI) and the "tables" - is the tables in the FROM): then we always return 0, because there is no - reason we play this statement on this slave if it updates nothing. In the - case of SQLCOM_DELETE_MULTI, there will be a second call to tables_ok(), - with tables having "updating==TRUE" (those after the DELETE), so this - second call will make the decision (because - all_tables_not_ok() = !tables_ok(1st_list) && !tables_ok(2nd_list)). + RETURN VALUES 0 should not be logged/replicated diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index fb5d0eb0a3f..d2237c24139 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -788,19 +788,22 @@ void field_real::get_opt_type(String *answer, if (!max_notzero_dec_len) { + int len= (int) max_length - ((item->decimals == NOT_FIXED_DEC) ? + 0 : (item->decimals + 1)); + if (min_arg >= -128 && max_arg <= (min_arg >= 0 ? 255 : 127)) - sprintf(buff, "TINYINT(%d)", (int) max_length - (item->decimals + 1)); + sprintf(buff, "TINYINT(%d)", len); else if (min_arg >= INT_MIN16 && max_arg <= (min_arg >= 0 ? UINT_MAX16 : INT_MAX16)) - sprintf(buff, "SMALLINT(%d)", (int) max_length - (item->decimals + 1)); + sprintf(buff, "SMALLINT(%d)", len); else if (min_arg >= INT_MIN24 && max_arg <= (min_arg >= 0 ? UINT_MAX24 : INT_MAX24)) - sprintf(buff, "MEDIUMINT(%d)", (int) max_length - (item->decimals + 1)); + sprintf(buff, "MEDIUMINT(%d)", len); else if (min_arg >= INT_MIN32 && max_arg <= (min_arg >= 0 ? UINT_MAX32 : INT_MAX32)) - sprintf(buff, "INT(%d)", (int) max_length - (item->decimals + 1)); + sprintf(buff, "INT(%d)", len); else - sprintf(buff, "BIGINT(%d)", (int) max_length - (item->decimals + 1)); + sprintf(buff, "BIGINT(%d)", len); answer->append(buff, (uint) strlen(buff)); if (min_arg >= 0) answer->append(" UNSIGNED"); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1cedc89ef97..b48f2537069 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -868,6 +868,13 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, { if (table->version != refresh_version) { + if (! refresh) + { + /* Ignore flush for now, but force close after usage. */ + thd->version= table->version; + continue; + } + /* ** There is a refresh in progress for this table ** Wait until the table is freed or the thread is killed. diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 2dd88f40005..4214c9a7c07 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -574,13 +574,18 @@ void query_cache_insert(NET *net, const char *packet, ulong length) { DBUG_ENTER("query_cache_insert"); -#ifndef DBUG_OFF - // Check if we have called query_cache.wreck() (which disables the cache) - if (query_cache.query_cache_size == 0) + STRUCT_LOCK(&query_cache.structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after guard + mutex lock + */ + if (unlikely(query_cache.query_cache_size == 0)) + { + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); DBUG_VOID_RETURN; -#endif + } - STRUCT_LOCK(&query_cache.structure_guard_mutex); Query_cache_block *query_block = ((Query_cache_block*) net->query_cache_query); if (query_block) @@ -623,14 +628,20 @@ void query_cache_abort(NET *net) { DBUG_ENTER("query_cache_abort"); -#ifndef DBUG_OFF - // Check if we have called query_cache.wreck() (which disables the cache) - if (query_cache.query_cache_size == 0) - DBUG_VOID_RETURN; -#endif if (net->query_cache_query != 0) // Quick check on unlocked structure { STRUCT_LOCK(&query_cache.structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after guard + mutex lock + */ + if (unlikely(query_cache.query_cache_size == 0)) + { + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); + DBUG_VOID_RETURN; + } + Query_cache_block *query_block = ((Query_cache_block*) net->query_cache_query); if (query_block) // Test if changed by other thread @@ -652,11 +663,6 @@ void query_cache_end_of_result(THD *thd) { DBUG_ENTER("query_cache_end_of_result"); -#ifndef DBUG_OFF - // Check if we have called query_cache.wreck() (which disables the cache) - if (query_cache.query_cache_size == 0) DBUG_VOID_RETURN; -#endif - if (thd->net.query_cache_query != 0) // Quick check on unlocked structure { #ifdef EMBEDDED_LIBRARY @@ -664,6 +670,17 @@ void query_cache_end_of_result(THD *thd) emb_count_querycache_size(thd)); #endif STRUCT_LOCK(&query_cache.structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after guard + mutex lock + */ + if (unlikely(query_cache.query_cache_size == 0)) + { + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); + DBUG_VOID_RETURN; + } + Query_cache_block *query_block = ((Query_cache_block*) thd->net.query_cache_query); if (query_block) @@ -743,9 +760,14 @@ ulong Query_cache::resize(ulong query_cache_size_arg) DBUG_ENTER("Query_cache::resize"); DBUG_PRINT("qcache", ("from %lu to %lu",query_cache_size, query_cache_size_arg)); - free_cache(0); + DBUG_ASSERT(initialized); + STRUCT_LOCK(&structure_guard_mutex); + if (query_cache_size > 0) + free_cache(); query_cache_size= query_cache_size_arg; - DBUG_RETURN(::query_cache_size= init_cache()); + ::query_cache_size= init_cache(); + STRUCT_UNLOCK(&structure_guard_mutex); + DBUG_RETURN(::query_cache_size); } @@ -1388,7 +1410,7 @@ void Query_cache::destroy() } else { - free_cache(1); + free_cache(); pthread_mutex_destroy(&structure_guard_mutex); initialized = 0; } @@ -1417,8 +1439,6 @@ ulong Query_cache::init_cache() int align; DBUG_ENTER("Query_cache::init_cache"); - if (!initialized) - init(); approx_additional_data_size = (sizeof(Query_cache) + sizeof(gptr)*(def_query_hash_size+ def_table_hash_size)); @@ -1476,14 +1496,9 @@ ulong Query_cache::init_cache() goto err; query_cache_size -= additional_data_size; - STRUCT_LOCK(&structure_guard_mutex); - - if (!(cache = (byte *) - my_malloc_lock(query_cache_size+additional_data_size, MYF(0)))) - { - STRUCT_UNLOCK(&structure_guard_mutex); + if (!(cache= (byte *) + my_malloc_lock(query_cache_size+additional_data_size, MYF(0)))) goto err; - } DBUG_PRINT("qcache", ("cache length %lu, min unit %lu, %u bins", query_cache_size, min_allocation_unit, mem_bin_num)); @@ -1579,7 +1594,6 @@ ulong Query_cache::init_cache() queries_in_cache = 0; queries_blocks = 0; - STRUCT_UNLOCK(&structure_guard_mutex); DBUG_RETURN(query_cache_size + additional_data_size + approx_additional_data_size); @@ -1595,6 +1609,7 @@ void Query_cache::make_disabled() { DBUG_ENTER("Query_cache::make_disabled"); query_cache_size= 0; + queries_blocks= 0; free_memory= 0; bins= 0; steps= 0; @@ -1606,14 +1621,11 @@ void Query_cache::make_disabled() } -void Query_cache::free_cache(my_bool destruction) +void Query_cache::free_cache() { DBUG_ENTER("Query_cache::free_cache"); if (query_cache_size > 0) { - if (!destruction) - STRUCT_LOCK(&structure_guard_mutex); - flush_cache(); #ifndef DBUG_OFF if (bins[0].free_blocks == 0) @@ -1635,8 +1647,6 @@ void Query_cache::free_cache(my_bool destruction) make_disabled(); hash_free(&queries); hash_free(&tables); - if (!destruction) - STRUCT_UNLOCK(&structure_guard_mutex); } DBUG_VOID_RETURN; } @@ -2266,7 +2276,19 @@ Query_cache::allocate_block(ulong len, my_bool not_less, ulong min, } if (!under_guard) + { STRUCT_LOCK(&structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after + guard mutex lock + */ + if (unlikely(query_cache.query_cache_size == 0)) + { + STRUCT_UNLOCK(&structure_guard_mutex); + DBUG_RETURN(0); + } + } /* Free old queries until we have enough memory to store this block */ Query_cache_block *block; @@ -2764,6 +2786,17 @@ void Query_cache::pack_cache() { DBUG_ENTER("Query_cache::pack_cache"); STRUCT_LOCK(&structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after + guard mutex lock + */ + if (unlikely(query_cache_size == 0)) + { + STRUCT_UNLOCK(&structure_guard_mutex); + DBUG_VOID_RETURN; + } + DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1);); byte *border = 0; @@ -3073,6 +3106,7 @@ my_bool Query_cache::join_results(ulong join_limit) STRUCT_LOCK(&structure_guard_mutex); if (queries_blocks != 0) { + DBUG_ASSERT(query_cache_size > 0); Query_cache_block *block = queries_blocks; do { @@ -3369,7 +3403,19 @@ my_bool Query_cache::check_integrity(bool not_locked) DBUG_RETURN(0); } if (!not_locked) + { STRUCT_LOCK(&structure_guard_mutex); + /* + It is very unlikely that following condition is TRUE (it is possible + only if other thread is resizing cache), so we check it only after + guard mutex lock + */ + if (unlikely(query_cache_size == 0)) + { + STRUCT_UNLOCK(&query_cache.structure_guard_mutex); + DBUG_RETURN(0); + } + } if (hash_check(&queries)) { diff --git a/sql/sql_cache.h b/sql/sql_cache.h index c933a2349af..b0a045a8aad 100644 --- a/sql/sql_cache.h +++ b/sql/sql_cache.h @@ -312,10 +312,9 @@ protected: Following function control structure_guard_mutex by themself or don't need structure_guard_mutex */ - void init(); ulong init_cache(); void make_disabled(); - void free_cache(my_bool destruction); + void free_cache(); Query_cache_block *write_block_data(ulong data_len, gptr data, ulong header_len, Query_cache_block::block_type type, @@ -351,6 +350,8 @@ protected: uint def_query_hash_size = QUERY_CACHE_DEF_QUERY_HASH_SIZE, uint def_table_hash_size = QUERY_CACHE_DEF_TABLE_HASH_SIZE); + /* initialize cache (mutex) */ + void init(); /* resize query cache (return real query size, 0 if disabled) */ ulong resize(ulong query_cache_size); /* set limit on result size */ diff --git a/sql/sql_class.cc b/sql/sql_class.cc index e845769d7ad..11b45b848c8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -353,12 +353,12 @@ void THD::cleanup(void) mysql_ha_flush(this, (TABLE_LIST*) 0, MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL); hash_free(&handler_tables_hash); + delete_dynamic(&user_var_events); + hash_free(&user_vars); close_temporary_tables(this); my_free((char*) variables.time_format, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) variables.date_format, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) variables.datetime_format, MYF(MY_ALLOW_ZERO_PTR)); - delete_dynamic(&user_var_events); - hash_free(&user_vars); if (global_read_lock) unlock_global_read_lock(this); if (ull) diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 7635774e3ac..7c834c91183 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -427,7 +427,11 @@ int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, error= -1; goto exit; } - result= 0; + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db); + error= 0; + send_ok(thd); + goto exit; } else { diff --git a/sql/sql_load.cc b/sql/sql_load.cc index c4f5b1427af..7b963c7ea31 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -114,6 +114,10 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, MYF(0)); DBUG_RETURN(-1); } + /* + This needs to be done before external_lock + */ + ha_enable_transaction(thd, FALSE); if (!(table = open_ltable(thd,table_list,lock_type))) DBUG_RETURN(-1); transactional_table= table->file->has_transactions(); @@ -273,7 +277,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, if (ignore || handle_duplicates == DUP_REPLACE) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); - ha_enable_transaction(thd, FALSE); table->file->start_bulk_insert((ha_rows) 0); table->copy_blobs=1; if (!field_term->length() && !enclosed->length()) @@ -284,10 +287,10 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, skip_lines); if (table->file->end_bulk_insert()) error=1; /* purecov: inspected */ - ha_enable_transaction(thd, TRUE); table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); table->next_number_field=0; } + ha_enable_transaction(thd, TRUE); if (file >= 0) my_close(file,MYF(0)); free_blobs(table); /* if pack_blob was used */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 297ea8fbd67..a2df59e56c7 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -59,6 +59,9 @@ static void remove_escape(char *name); static void refresh_status(void); static bool append_file_to_dir(THD *thd, const char **filename_ptr, const char *table_name); + +static TABLE_LIST* get_table_by_alias(TABLE_LIST* tl, const char* db, + const char* alias); const char *any_db="*any*"; // Special symbol for check_access @@ -125,10 +128,7 @@ static bool end_active_trans(THD *thd) */ inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) { - return (table_rules_on && tables && !tables_ok(thd,tables) && - ((thd->lex->sql_command != SQLCOM_DELETE_MULTI) || - !tables_ok(thd, - (TABLE_LIST *)thd->lex->auxilliary_table_list.first))); + return (table_rules_on && tables && !tables_ok(thd,tables)); } #endif @@ -696,29 +696,19 @@ static int check_connection(THD *thd) return (ER_OUT_OF_RESOURCES); thd->host_or_ip= thd->ip; vio_in_addr(net->vio,&thd->remote.sin_addr); -#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread) - /* Fast local hostname resolve for Win32 */ - if (!strcmp(thd->ip,"127.0.0.1")) + if (!(specialflag & SPECIAL_NO_RESOLVE)) { - thd->host= (char*) my_localhost; - thd->host_or_ip= my_localhost; - } - else -#endif - { - if (!(specialflag & SPECIAL_NO_RESOLVE)) + vio_in_addr(net->vio,&thd->remote.sin_addr); + thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors); + /* Cut very long hostnames to avoid possible overflows */ + if (thd->host) { - vio_in_addr(net->vio,&thd->remote.sin_addr); - thd->host=ip_to_hostname(&thd->remote.sin_addr,&connect_errors); - /* Cut very long hostnames to avoid possible overflows */ - if (thd->host) - { - thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0; - thd->host_or_ip= thd->host; - } - if (connect_errors > max_connect_errors) - return(ER_HOST_IS_BLOCKED); + if (thd->host != my_localhost) + thd->host[min(strlen(thd->host), HOSTNAME_LENGTH)]= 0; + thd->host_or_ip= thd->host; } + if (connect_errors > max_connect_errors) + return(ER_HOST_IS_BLOCKED); } DBUG_PRINT("info",("Host: %s ip: %s", thd->host ? thd->host : "unknown host", @@ -814,11 +804,13 @@ static int check_connection(THD *thd) DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8])); /* Use server character set and collation if + - opt_character_set_client_handshake is not set - client has not specified a character set - client character set is the same as the servers - client character set doesn't exists in server */ - if (!(thd->variables.character_set_client= + if (!opt_character_set_client_handshake || + !(thd->variables.character_set_client= get_charset((uint) net->read_pos[8], MYF(0))) || !my_strcasecmp(&my_charset_latin1, global_system_variables.character_set_client->name, @@ -3335,7 +3327,6 @@ purposes internal to the MySQL server", MYF(0)); !db_ok_with_wild_table(lex->name))) { my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); - reset_one_shot_variables(thd); break; } #endif @@ -3371,7 +3362,6 @@ purposes internal to the MySQL server", MYF(0)); !db_ok_with_wild_table(lex->name))) { my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); - reset_one_shot_variables(thd); break; } #endif @@ -3412,7 +3402,6 @@ purposes internal to the MySQL server", MYF(0)); !db_ok_with_wild_table(db))) { my_error(ER_SLAVE_IGNORED_TABLE, MYF(0)); - reset_one_shot_variables(thd); break; } #endif @@ -4256,6 +4245,40 @@ void create_select_for_variable(const char *var_name) DBUG_VOID_RETURN; } +static TABLE_LIST* get_table_by_alias(TABLE_LIST* tl, const char* db, + const char* alias) +{ + for (;tl;tl= tl->next) + { + if (!strcmp(db,tl->db) && + tl->alias && !my_strcasecmp(table_alias_charset,tl->alias,alias)) + return tl; + } + + return 0; +} + +/* Sets up lex->auxilliary_table_list */ +void fix_multi_delete_lex(LEX* lex) +{ + TABLE_LIST *tl; + TABLE_LIST *good_list= (TABLE_LIST*)lex->select_lex.table_list.first; + + for (tl= (TABLE_LIST*)lex->auxilliary_table_list.first; tl; tl= tl->next) + { + TABLE_LIST* good_table= get_table_by_alias(good_list,tl->db,tl->alias); + if (good_table && !good_table->derived) + { + /* + real_name points to a member of Table_ident which is + allocated via thd->strmake() from THD memroot + */ + tl->real_name= good_table->real_name; + tl->real_name_length= good_table->real_name_length; + good_table->updating= tl->updating; + } + } +} void mysql_init_multi_delete(LEX *lex) { @@ -5578,13 +5601,7 @@ int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count) (*table_count)++; /* All tables in aux_tables must be found in FROM PART */ TABLE_LIST *walk; - for (walk= delete_tables; walk; walk= walk->next) - { - if (!my_strcasecmp(table_alias_charset, - target_tbl->alias, walk->alias) && - !strcmp(walk->db, target_tbl->db)) - break; - } + walk= get_table_by_alias(delete_tables,target_tbl->db,target_tbl->alias); if (!walk) { my_error(ER_UNKNOWN_TABLE, MYF(0), target_tbl->real_name, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e7af2a1aa75..59b82b53b32 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -618,7 +618,7 @@ JOIN::optimize() } if (group_list || tmp_table_param.sum_func_count) { - if (! hidden_group_fields) + if (! hidden_group_fields && rollup.state == ROLLUP::STATE_NONE) select_distinct=0; } else if (select_distinct && tables - const_tables == 1) @@ -9277,6 +9277,8 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) The function replaces occurrences of group by fields in expr by ref objects for these fields unless they are under aggregate functions. + The function also corrects value of the the maybe_null attribute + for the items of all subexpressions containing group by fields. IMPLEMENTATION The function recursively traverses the tree of the expr expression, @@ -9287,6 +9289,9 @@ void free_underlaid_joins(THD *thd, SELECT_LEX *select) This substitution is needed GROUP BY queries with ROLLUP if SELECT list contains expressions over group by attributes. + TODO: Some functions are not null-preserving. For those functions + updating of the maybe_null attribute is an overkill. + EXAMPLES SELECT a+1 FROM t1 GROUP BY a WITH ROLLUP SELECT SUM(a)+a FROM t1 GROUP BY a WITH ROLLUP @@ -9302,6 +9307,7 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, if (expr->arg_count) { Item **arg,**arg_end; + bool arg_changed= FALSE; for (arg= expr->arguments(), arg_end= expr->arguments()+expr->arg_count; arg != arg_end; arg++) @@ -9318,16 +9324,21 @@ static bool change_group_ref(THD *thd, Item_func *expr, ORDER *group_list, if(!(new_item= new Item_ref(group_tmp->item, 0, item->name))) return 1; // fatal_error is set thd->change_item_tree(arg, new_item); - *changed= TRUE; + arg_changed= TRUE; } } } else if (item->type() == Item::FUNC_ITEM) { - if (change_group_ref(thd, (Item_func *) item, group_list, changed)) + if (change_group_ref(thd, (Item_func *) item, group_list, &arg_changed)) return 1; } } + if (arg_changed) + { + expr->maybe_null= 1; + *changed= TRUE; + } } return 0; } @@ -9389,7 +9400,7 @@ bool JOIN::rollup_init() } if (item->type() == Item::FUNC_ITEM) { - bool changed= 0; + bool changed= FALSE; if (change_group_ref(thd, (Item_func *) item, group_list, &changed)) return 1; /* diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 647dfe2ac4d..c3c28535954 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -638,33 +638,6 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) DBUG_RETURN(0); } -/* - returns the length of the longest type on the given table. - - This is used so that show fields will return the data using the proper - lengths instead of forcing columns such as type to always return with a - given length. -*/ - -uint get_longest_type_in_table(TABLE *table, const char *wild) -{ - Field **ptr,*field; - char tmp[MAX_FIELD_WIDTH]; - uint max_len= 0; - - for (ptr=table->field; (field= *ptr); ptr++) - { - if (!wild || !wild[0] || - !wild_case_compare(system_charset_info, field->field_name,wild)) - { - String type(tmp,sizeof(tmp), system_charset_info); - field->sql_type(type); - max_len= max(max_len, type.length()); - } - } - return max_len; -} - /*************************************************************************** ** List all columns in a table_list->real_name @@ -694,14 +667,9 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, #ifndef NO_EMBEDDED_ACCESS_CHECKS (void) get_table_grant(thd, table_list); #endif - - /* we scan for the longest since long enum types can exceed 40 */ - uint max_len = get_longest_type_in_table(table, wild); - List<Item> field_list; field_list.push_back(new Item_empty_string("Field",NAME_LEN)); - field_list.push_back(new Item_empty_string("Type", - max_len > 40 ? max_len : 40)); + field_list.push_back(new Item_empty_string("Type", 40)); if (verbose) field_list.push_back(new Item_empty_string("Collation",40)); field_list.push_back(new Item_empty_string("Null",1)); @@ -2123,6 +2091,10 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache; end= int10_to_str(*(long*) value, buff, 10); break; + case SHOW_KEY_CACHE_LONGLONG: + value= (value-(char*) &dflt_key_cache_var)+ (char*) dflt_key_cache; + end= longlong10_to_str(*(longlong*) value, buff, 10); + break; case SHOW_UNDEF: // Show never happen case SHOW_SYS: break; // Return empty string diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 92db0143980..01126043764 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1360,6 +1360,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) { create_info->table_existed= 1; // Mark that table existed + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), + alias); DBUG_RETURN(0); } my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias); @@ -1373,12 +1376,8 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, if (!access(path,F_OK)) { if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) - { - create_info->table_existed= 1; // Mark that table existed - error= 0; - } - else - my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); + goto warn; + my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); goto end; } } @@ -1401,12 +1400,8 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, DBUG_PRINT("info", ("Table with same name already existed in handler")); if (create_if_not_exists) - { - create_info->table_existed= 1; // Mark that table existed - error= 0; - } - else - my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); + goto warn; + my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); goto end; } } @@ -1447,6 +1442,15 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, } } error=0; + goto end; + +warn: + error= 0; + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), + alias); + create_info->table_existed= 1; // Mark that table existed + end: VOID(pthread_mutex_unlock(&LOCK_open)); start_waiting_global_read_lock(thd); diff --git a/sql/sql_test.cc b/sql/sql_test.cc index 8af7903a910..d6afc888be2 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -309,6 +309,11 @@ end: static int print_key_cache_status(const char *name, KEY_CACHE *key_cache) { + char llbuff1[22]; + char llbuff2[22]; + char llbuff3[22]; + char llbuff4[22]; + if (!key_cache->key_cache_inited) { printf("%s: Not in use\n", name); @@ -322,16 +327,18 @@ Division_limit: %10lu\n\ Age_limit: %10lu\n\ blocks used: %10lu\n\ not flushed: %10lu\n\ -w_requests: %10lu\n\ -writes: %10lu\n\ -r_requests: %10lu\n\ -reads: %10lu\n\n", +w_requests: %10s\n\ +writes: %10s\n\ +r_requests: %10s\n\ +reads: %10s\n\n", name, (ulong) key_cache->param_buff_size, key_cache->param_block_size, key_cache->param_division_limit, key_cache->param_age_threshold, key_cache->blocks_used,key_cache->global_blocks_changed, - key_cache->global_cache_w_requests,key_cache->global_cache_write, - key_cache->global_cache_r_requests,key_cache->global_cache_read); + llstr(key_cache->global_cache_w_requests,llbuff1), + llstr(key_cache->global_cache_write,llbuff2), + llstr(key_cache->global_cache_r_requests,llbuff3), + llstr(key_cache->global_cache_read,llbuff4)); } return 0; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index be8ead8e157..e29aaac8f94 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2598,7 +2598,12 @@ expr_expr: expr IN_SYM '(' expr_list ')' { $4->push_front($1); $$= new Item_func_in(*$4); } | expr NOT IN_SYM '(' expr_list ')' - { $5->push_front($1); $$= new Item_func_not(new Item_func_in(*$5)); } + { + $5->push_front($1); + Item_func_in *item= new Item_func_in(*$5); + item->negate(); + $$= item; + } | expr IN_SYM in_subselect { $$= new Item_in_subselect($1, $3); } | expr NOT IN_SYM in_subselect @@ -2608,7 +2613,11 @@ expr_expr: | expr BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_between($1,$3,$5); } | expr NOT BETWEEN_SYM no_and_expr AND_SYM expr - { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } + { + Item_func_between *item= new Item_func_between($1,$4,$6); + item->negate(); + $$= item; + } | expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | expr OR_SYM expr { $$= new Item_cond_or($1,$3); } | expr XOR expr { $$= new Item_cond_xor($1,$3); } @@ -2656,7 +2665,11 @@ no_in_expr: no_in_expr BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_between($1,$3,$5); } | no_in_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr - { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } + { + Item_func_between *item= new Item_func_between($1,$4,$6); + item->negate(); + $$= item; + } | no_in_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | no_in_expr OR_SYM expr { $$= new Item_cond_or($1,$3); } | no_in_expr XOR expr { $$= new Item_cond_xor($1,$3); } @@ -2704,7 +2717,12 @@ no_and_expr: no_and_expr IN_SYM '(' expr_list ')' { $4->push_front($1); $$= new Item_func_in(*$4); } | no_and_expr NOT IN_SYM '(' expr_list ')' - { $5->push_front($1); $$= new Item_func_not(new Item_func_in(*$5)); } + { + $5->push_front($1); + Item_func_in *item= new Item_func_in(*$5); + item->negate(); + $$= item; + } | no_and_expr IN_SYM in_subselect { $$= new Item_in_subselect($1, $3); } | no_and_expr NOT IN_SYM in_subselect @@ -2714,7 +2732,11 @@ no_and_expr: | no_and_expr BETWEEN_SYM no_and_expr AND_SYM expr { $$= new Item_func_between($1,$3,$5); } | no_and_expr NOT BETWEEN_SYM no_and_expr AND_SYM expr - { $$= new Item_func_not(new Item_func_between($1,$4,$6)); } + { + Item_func_between *item= new Item_func_between($1,$4,$6); + item->negate(); + $$= item; + } | no_and_expr OR_OR_CONCAT expr { $$= or_or_concat(YYTHD, $1,$3); } | no_and_expr OR_SYM expr { $$= new Item_cond_or($1,$3); } | no_and_expr XOR expr { $$= new Item_cond_xor($1,$3); } @@ -4273,12 +4295,10 @@ single_multi: } where_clause opt_order_clause delete_limit_clause {} - | table_wild_list - { mysql_init_multi_delete(Lex); } - FROM join_table_list where_clause - | FROM table_wild_list - { mysql_init_multi_delete(Lex); } - USING join_table_list where_clause + | table_wild_list {mysql_init_multi_delete(Lex);} + FROM join_table_list {fix_multi_delete_lex(Lex);} where_clause + | FROM table_wild_list { mysql_init_multi_delete(Lex);} + USING join_table_list {fix_multi_delete_lex(Lex);} where_clause {} ; diff --git a/sql/structs.h b/sql/structs.h index ba081b570c1..081ada88bf7 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -181,7 +181,7 @@ enum SHOW_TYPE SHOW_SSL_GET_CIPHER_LIST, #endif /* HAVE_OPENSSL */ SHOW_RPL_STATUS, SHOW_SLAVE_RUNNING, SHOW_SLAVE_RETRIED_TRANS, - SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG + SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG, SHOW_KEY_CACHE_LONGLONG }; enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED}; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index ffcf5b6f34d..eadbd37f8f6 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -7182,7 +7182,7 @@ static void test_explain_bug() verify_prepare_field(result, 3, "type", "", MYSQL_TYPE_VAR_STRING, "", "", "", 10, 0); - verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_BLOB, + verify_prepare_field(result, 4, "possible_keys", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_LEN*64, 0); verify_prepare_field(result, 5, "key", "", MYSQL_TYPE_VAR_STRING, @@ -7195,13 +7195,13 @@ static void test_explain_bug() (mysql_get_server_version(mysql) <= 50000 ? 3 : 4096), 0); - verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_BLOB, + verify_prepare_field(result, 7, "ref", "", MYSQL_TYPE_VAR_STRING, "", "", "", NAME_LEN*16, 0); verify_prepare_field(result, 8, "rows", "", MYSQL_TYPE_LONGLONG, "", "", "", 10, 0); - verify_prepare_field(result, 9, "Extra", "", MYSQL_TYPE_BLOB, + verify_prepare_field(result, 9, "Extra", "", MYSQL_TYPE_VAR_STRING, "", "", "", 255, 0); mysql_free_result(result); diff --git a/vio/vio.c b/vio/vio.c index 4660efe3048..45572b93ed6 100644 --- a/vio/vio.c +++ b/vio/vio.c @@ -50,6 +50,7 @@ void vio_reset(Vio* vio, enum enum_vio_type type, vio->fastsend =vio_fastsend; vio->viokeepalive =vio_keepalive; vio->should_retry =vio_should_retry; + vio->was_interrupted=vio_was_interrupted; vio->vioclose =vio_close_pipe; vio->peer_addr =vio_peer_addr; vio->in_addr =vio_in_addr; @@ -69,6 +70,7 @@ void vio_reset(Vio* vio, enum enum_vio_type type, vio->fastsend =vio_fastsend; vio->viokeepalive =vio_keepalive; vio->should_retry =vio_should_retry; + vio->was_interrupted=vio_was_interrupted; vio->vioclose =vio_close_shared_memory; vio->peer_addr =vio_peer_addr; vio->in_addr =vio_in_addr; @@ -88,6 +90,7 @@ void vio_reset(Vio* vio, enum enum_vio_type type, vio->fastsend =vio_ssl_fastsend; vio->viokeepalive =vio_ssl_keepalive; vio->should_retry =vio_ssl_should_retry; + vio->was_interrupted=vio_ssl_was_interrupted; vio->vioclose =vio_ssl_close; vio->peer_addr =vio_ssl_peer_addr; vio->in_addr =vio_ssl_in_addr; @@ -105,6 +108,7 @@ void vio_reset(Vio* vio, enum enum_vio_type type, vio->fastsend =vio_fastsend; vio->viokeepalive =vio_keepalive; vio->should_retry =vio_should_retry; + vio->was_interrupted=vio_was_interrupted; vio->vioclose =vio_close; vio->peer_addr =vio_peer_addr; vio->in_addr =vio_in_addr; diff --git a/vio/vio_priv.h b/vio/vio_priv.h index 3a75a08021d..c1c78cc6efa 100644 --- a/vio/vio_priv.h +++ b/vio/vio_priv.h @@ -39,6 +39,8 @@ int vio_ssl_fastsend(Vio *vio); int vio_ssl_keepalive(Vio *vio, my_bool onoff); /* Whenever we should retry the last read/write operation. */ my_bool vio_ssl_should_retry(Vio *vio); +/* Check that operation was timed out */ +my_bool vio_ssl_was_interrupted(Vio *vio); /* When the workday is over... */ int vio_ssl_close(Vio *vio); /* Return last error number */ diff --git a/vio/viosocket.c b/vio/viosocket.c index c7561890ead..5213390e2e6 100644 --- a/vio/viosocket.c +++ b/vio/viosocket.c @@ -99,7 +99,7 @@ int vio_blocking(Vio * vio __attribute__((unused)), my_bool set_blocking_mode, #endif /* !defined(NO_FCNTL_NONBLOCK) */ #else /* !defined(__WIN__) && !defined(__EMX__) */ #ifndef __EMX__ - if (vio->type != VIO_TYPE_NAMEDPIPE) + if (vio->type != VIO_TYPE_NAMEDPIPE && vio->type != VIO_TYPE_SHARED_MEMORY) #endif { ulong arg; @@ -196,6 +196,15 @@ vio_should_retry(Vio * vio __attribute__((unused))) } +my_bool +vio_was_interrupted(Vio *vio __attribute__((unused))) +{ + int en= socket_errno; + return (en == SOCKET_EAGAIN || en == SOCKET_EINTR || + en == SOCKET_EWOULDBLOCK || en == SOCKET_ETIMEDOUT); +} + + int vio_close(Vio * vio) { int r=0; diff --git a/vio/viossl.c b/vio/viossl.c index 2f608209a53..a3a2e7190bd 100644 --- a/vio/viossl.c +++ b/vio/viossl.c @@ -184,6 +184,15 @@ vio_ssl_should_retry(Vio * vio __attribute__((unused))) } +my_bool +vio_ssl_was_interrupted(Vio *vio __attribute__((unused))) +{ + int en= socket_errno; + return (en == SOCKET_EAGAIN || en == SOCKET_EINTR || + en == SOCKET_EWOULDBLOCK || en == SOCKET_ETIMEDOUT); +} + + int vio_ssl_close(Vio * vio) { int r; |