diff options
210 files changed, 5405 insertions, 1873 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 diff --git a/Makefile.am b/Makefile.am index ae0d56ba9fd..9025251ff2a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -106,12 +106,12 @@ MYSQL_TEST_NDB_PORT = 9350 test: cd mysql-test ; \ - ./mysql-test-run.pl \ + ./mysql-test-run \ --manager-port=$(MYSQL_TEST_MANAGER_PORT) \ --master_port=$(MYSQL_TEST_MASTER_PORT) \ --slave_port=$(MYSQL_TEST_SLAVE_PORT) \ --ndbcluster_port=$(MYSQL_TEST_NDB_PORT) && \ - ./mysql-test-run.pl --ps-protocol \ + ./mysql-test-run --ps-protocol \ --manager-port=$(MYSQL_TEST_MANAGER_PORT) \ --master_port=$(MYSQL_TEST_MASTER_PORT) \ --slave_port=$(MYSQL_TEST_SLAVE_PORT) \ @@ -121,3 +121,14 @@ test-force: cd mysql-test; \ ./mysql-test-run --force ;\ ./mysql-test-run --ps-protocol --force + +# We are testing a new Perl version of the test script +test-pl: + cd mysql-test; \ + ./mysql-test-run.pl && \ + ./mysql-test-run.pl --ps-protocol + +test-force-pl: + cd mysql-test; \ + ./mysql-test-run.pl --force ; \ + ./mysql-test-run.pl --ps-protocol --force @@ -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/VC++Files/mysys/mysys.dsp b/VC++Files/mysys/mysys.dsp index f47203d37bf..2f3d7bb272c 100644 --- a/VC++Files/mysys/mysys.dsp +++ b/VC++Files/mysys/mysys.dsp @@ -361,6 +361,10 @@ SOURCE=.\my_compress.c # End Source File # Begin Source File +SOURCE=.\my_conio.c +# End Source File +# Begin Source File + SOURCE=.\my_copy.c # End Source File # Begin Source File diff --git a/VC++Files/mysys/mysys_ia64.dsp b/VC++Files/mysys/mysys_ia64.dsp index a0877457286..622ae1d5bce 100644 --- a/VC++Files/mysys/mysys_ia64.dsp +++ b/VC++Files/mysys/mysys_ia64.dsp @@ -362,6 +362,10 @@ SOURCE=.\my_compress.c # End Source File # Begin Source File +SOURCE=.\my_conio.c +# End Source File +# Begin Source File + SOURCE=.\my_copy.c # End Source File # Begin Source File diff --git a/client/mysql.cc b/client/mysql.cc index 51822b64c82..e73d627d67a 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -938,10 +938,15 @@ static int get_options(int argc, char **argv) static int read_lines(bool execute_commands) { -#if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) +#if defined(OS2) || defined(__NETWARE__) char linebuffer[254]; String buffer; #endif +#if defined(__WIN__) + String tmpbuf; + String buffer; +#endif + char *line; char in_string=0; ulong line_number=0; @@ -972,7 +977,7 @@ static int read_lines(bool execute_commands) #if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) tee_fputs(prompt, stdout); -#ifdef __NETWARE__ +#if defined(__NETWARE__) line=fgets(linebuffer, sizeof(linebuffer)-1, stdin); /* Remove the '\n' */ if (line) @@ -981,7 +986,22 @@ static int read_lines(bool execute_commands) if (p != NULL) *p = '\0'; } -#else +#elif defined(__WIN__) + if (!tmpbuf.is_alloced()) + tmpbuf.alloc(65535); + buffer.length(0); + unsigned long clen; + do + { + line= my_cgets(tmpbuf.ptr(), tmpbuf.alloced_length()-1, &clen); + buffer.append(line, clen); + /* + if we got buffer fully filled than there is a chance that + something else is still in console input buffer + */ + } while (tmpbuf.alloced_length() <= clen); + line= buffer.c_ptr(); +#else /* OS2 */ buffer.length(0); /* _cgets() expects the buffer size - 3 as the first byte */ linebuffer[0]= (char) sizeof(linebuffer) - 3; @@ -1057,9 +1077,14 @@ static int read_lines(bool execute_commands) status.exit_status=0; } } + #if defined( __WIN__) || defined(OS2) || defined(__NETWARE__) buffer.free(); #endif +#if defined( __WIN__) + tmpbuf.free(); +#endif + return status.exit_status; } 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 6963ff2f99e..eef9a7d50af 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -64,7 +64,11 @@ #include <sys/wait.h> #endif #ifndef WEXITSTATUS -# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +# ifdef __WIN__ +# define WEXITSTATUS(stat_val) (stat_val) +# else +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +# endif #endif #define MAX_QUERY 131072 #define MAX_VAR_NAME 256 @@ -97,6 +101,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, @@ -653,7 +661,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); @@ -670,7 +678,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; } } @@ -680,7 +688,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) @@ -697,21 +706,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()"); @@ -2166,7 +2175,8 @@ int read_line(char *buf, int size) if (feof(cur_file->file)) { found_eof: - if (cur_file->file != stdin){ + if (cur_file->file != stdin) + { my_fclose(cur_file->file, MYF(0)); cur_file->file= 0; } @@ -3733,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"); @@ -3903,6 +3914,7 @@ int main(int argc, char **argv) error|= run_query(&cur_con->mysql, q, QUERY_REAP|QUERY_SEND); display_result_vertically= old_display_result_vertically; q->last_argument= q->end; + query_executed= 1; break; } case Q_QUERY: @@ -3927,6 +3939,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; } @@ -3947,6 +3960,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: @@ -3987,6 +4001,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 */ @@ -4043,6 +4058,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 (ds_res.length && !error) { if (result_file) 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 8752aa30772..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; @@ -804,6 +801,9 @@ int my_security_attr_create(SECURITY_ATTRIBUTES **psa, const char **perror, void my_security_attr_free(SECURITY_ATTRIBUTES *sa); +/* implemented in my_conio.c */ +char* my_cgets(char *string, unsigned long clen, unsigned long* plen); + #endif #ifdef __NETWARE__ void netware_reg_user(const char *ip, const char *user, diff --git a/include/myisam.h b/include/myisam.h index 6d097770646..e276d4efdff 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -311,6 +311,20 @@ typedef struct st_sort_key_blocks /* Used when sorting */ } SORT_KEY_BLOCKS; +/* + MyISAM supports several statistics collection methods. Currently statistics + collection method is not stored in MyISAM file and has to be specified for + each table analyze/repair operation in MI_CHECK::stats_method. +*/ + +typedef enum +{ + /* Treat NULLs as inequal when collecting statistics (default for 4.1/5.0) */ + MI_STATS_METHOD_NULLS_NOT_EQUAL, + /* Treat NULLs as equal when collecting statistics (like 4.0 did) */ + MI_STATS_METHOD_NULLS_EQUAL +} enum_mi_stats_method; + typedef struct st_mi_check_param { ulonglong auto_increment_value; @@ -341,6 +355,7 @@ typedef struct st_mi_check_param void *thd; char *db_name,*table_name; char *op_name; + enum_mi_stats_method stats_method; } MI_CHECK; typedef struct st_sort_ft_buf 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 038ce8d953f..7397ee4e204 100644 --- a/myisam/mi_check.c +++ b/myisam/mi_check.c @@ -80,6 +80,7 @@ void myisamchk_init(MI_CHECK *param) param->start_check_pos=0; param->max_record_length= LONGLONG_MAX; param->key_cache_block_size= KEY_CACHE_BLOCK_SIZE; + param->stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL; } /* Check the status flags for the table */ @@ -558,10 +559,11 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, ha_checksum *key_checksum, uint level) { int flag; - uint used_length,comp_flag,nod_flag,key_length=0,not_used; + uint used_length,comp_flag,nod_flag,key_length=0; uchar key[MI_MAX_POSSIBLE_KEY_BUFF],*temp_buff,*keypos,*old_keypos,*endpos; my_off_t next_page,record; char llbuff[22]; + uint diff_pos; DBUG_ENTER("chk_index"); DBUG_DUMP("buff",(byte*) buff,mi_getint(buff)); @@ -619,7 +621,7 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, } if ((*keys)++ && (flag=ha_key_cmp(keyinfo->seg,info->lastkey,key,key_length, - comp_flag, ¬_used)) >=0) + comp_flag, &diff_pos)) >=0) { DBUG_DUMP("old",(byte*) info->lastkey, info->lastkey_length); DBUG_DUMP("new",(byte*) key, key_length); @@ -635,11 +637,11 @@ static int chk_index(MI_CHECK *param, MI_INFO *info, MI_KEYDEF *keyinfo, { if (*keys != 1L) /* not first_key */ { - uint diff; - ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY, - SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, - &diff); - param->unique_count[diff-1]++; + if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL) + ha_key_cmp(keyinfo->seg,info->lastkey,key,USE_WHOLE_KEY, + SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, + &diff_pos); + param->unique_count[diff_pos-1]++; } } (*key_checksum)+= mi_byte_checksum((byte*) key, @@ -2013,7 +2015,7 @@ int mi_repair_by_sort(MI_CHECK *param, register MI_INFO *info, sort_param.sort_info=&sort_info; sort_param.fix_datafile= (my_bool) (! rep_quick); sort_param.master =1; - + del=info->state->del; param->glob_crc=0; if (param->testflag & T_CALC_CHECKSUM) @@ -3249,9 +3251,10 @@ static int sort_key_write(MI_SORT_PARAM *sort_param, const void *a) cmp=ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey, (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_UPDATE, &diff_pos); - ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey, - (uchar*) a, USE_WHOLE_KEY,SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, - &diff_pos); + if (param->stats_method == MI_STATS_METHOD_NULLS_NOT_EQUAL) + ha_key_cmp(sort_param->seg,sort_info->key_block->lastkey, + (uchar*) a, USE_WHOLE_KEY, + SEARCH_FIND | SEARCH_NULL_ARE_NOT_EQUAL, &diff_pos); sort_param->unique[diff_pos-1]++; } else @@ -3989,9 +3992,10 @@ void update_auto_increment_key(MI_CHECK *param, MI_INFO *info, unique[0]= (#different values of {keypart1}) - 1 unique[1]= (#different values of {keypart2,keypart1} tuple) - unique[0] - 1 ... - Here we assume that NULL != NULL (see SEARCH_NULL_ARE_NOT_EQUAL). The - 'unique' array is collected in one sequential scan through the entire + The 'unique' array is collected in one sequential scan through the entire index. This is done in two places: in chk_index() and in sort_key_write(). + Statistics collection may consider NULLs as either equal or unequal (see + SEARCH_NULL_ARE_NOT_EQUAL, MI_STATS_METHOD_*). Output is an array: rec_per_key_part[k] = diff --git a/myisam/mi_dbug.c b/myisam/mi_dbug.c index 02d1c7d05d6..34105c490e4 100644 --- a/myisam/mi_dbug.c +++ b/myisam/mi_dbug.c @@ -40,12 +40,12 @@ void _mi_print_key(FILE *stream, register HA_KEYSEG *keyseg, end= key+ keyseg->length; if (keyseg->flag & HA_NULL_PART) { - if (!*key) + /* A NULL value is encoded by a 1-byte flag. Zero means NULL. */ + if (! *(key++)) { fprintf(stream,"NULL"); continue; } - key++; } switch (keyseg->type) { diff --git a/myisam/mi_rkey.c b/myisam/mi_rkey.c index 12db00337ee..9aa2be3c706 100644 --- a/myisam/mi_rkey.c +++ b/myisam/mi_rkey.c @@ -31,8 +31,8 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, HA_KEYSEG *last_used_keyseg; uint pack_key_length, use_key_length, nextflag; DBUG_ENTER("mi_rkey"); - DBUG_PRINT("enter",("base: %lx inx: %d search_flag: %d", - info,inx,search_flag)); + DBUG_PRINT("enter", ("base: %p buf: %p inx: %d search_flag: %d", + info, buf, inx, search_flag)); if ((inx = _mi_check_index(info,inx)) < 0) DBUG_RETURN(my_errno); @@ -56,9 +56,12 @@ int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len, { if (key_len == 0) key_len=USE_WHOLE_KEY; + /* Save the packed key for later use in the second buffer of lastkey. */ key_buff=info->lastkey+info->s->base.max_key_length; pack_key_length=_mi_pack_key(info,(uint) inx, key_buff, (uchar*) key, key_len, &last_used_keyseg); + /* Save packed_key_length for use by the MERGE engine. */ + info->pack_key_length= pack_key_length; DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE, keyinfo->seg, key_buff, pack_key_length);); } diff --git a/myisam/mi_search.c b/myisam/mi_search.c index 6ed245d9715..82177d331b7 100644 --- a/myisam/mi_search.c +++ b/myisam/mi_search.c @@ -908,11 +908,21 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, reg1 HA_KEYSEG *keyseg; uchar *start_key,*page,*page_end,*from,*from_end; uint length,tmp; + DBUG_ENTER("_mi_get_binary_pack_key"); page= *page_pos; page_end=page+MI_MAX_KEY_BUFF+1; start_key=key; + /* + Keys are compressed the following way: + + prefix length Packed length of prefix for the prev key. (1 or 3 bytes) + for each key segment: + [is null] Null indicator if can be null (1 byte, zero means null) + [length] Packed length if varlength (1 or 3 bytes) + pointer Reference to the data file (last_keyseg->length). + */ get_key_length(length,page); if (length) { @@ -922,7 +932,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, length, keyinfo->maxlength, *page_pos)); DBUG_DUMP("key",(char*) *page_pos,16); my_errno=HA_ERR_CRASHED; - return 0; /* Wrong key */ + DBUG_RETURN(0); /* Wrong key */ } from=key; from_end=key+length; } @@ -983,12 +993,12 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, { DBUG_PRINT("error",("Error when unpacking key")); my_errno=HA_ERR_CRASHED; - return 0; /* Error */ + DBUG_RETURN(0); /* Error */ } memcpy((byte*) key,(byte*) from,(size_t) length); *page_pos= from+length; } - return((uint) (key-start_key)+keyseg->length); + DBUG_RETURN((uint) (key-start_key)+keyseg->length); } 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/myisamchk.c b/myisam/myisamchk.c index 3b9742b79fb..2dd05cf7e67 100644 --- a/myisam/myisamchk.c +++ b/myisam/myisamchk.c @@ -67,6 +67,7 @@ static const char *field_pack[]= "no zeros", "blob", "constant", "table-lockup", "always zero","varchar","unique-hash","?","?"}; +static const char *myisam_stats_method_str="nulls_unequal"; static void get_options(int *argc,char * * *argv); static void print_version(void); @@ -155,7 +156,7 @@ enum options_mc { OPT_READ_BUFFER_SIZE, OPT_WRITE_BUFFER_SIZE, OPT_SORT_BUFFER_SIZE, OPT_SORT_KEY_BLOCKS, OPT_DECODE_BITS, OPT_FT_MIN_WORD_LEN, OPT_FT_MAX_WORD_LEN, OPT_FT_STOPWORD_FILE, - OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE + OPT_MAX_RECORD_LENGTH, OPT_AUTO_CLOSE, OPT_STATS_METHOD }; static struct my_option my_long_options[] = @@ -336,6 +337,11 @@ static struct my_option my_long_options[] = "Use stopwords from this file instead of built-in list.", (gptr*) &ft_stopword_file, (gptr*) &ft_stopword_file, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"stats_method", OPT_STATS_METHOD, + "Specifies how index statistics collection code should threat NULLs. " + "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), and \"nulls_equal\" (emulate 4.0 behavior).", + (gptr*) &myisam_stats_method_str, (gptr*) &myisam_stats_method_str, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; @@ -465,6 +471,12 @@ static void usage(void) #include <help_end.h> +const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal", + NullS}; +TYPELIB myisam_stats_method_typelib= { + array_elements(myisam_stats_method_names) - 1, "", + myisam_stats_method_names, NULL}; + /* Read options */ static my_bool @@ -684,6 +696,19 @@ get_one_option(int optid, else check_param.testflag|= T_CALC_CHECKSUM; break; + case OPT_STATS_METHOD: + { + int method; + myisam_stats_method_str= argument; + if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0) + { + fprintf(stderr, "Invalid value of stats_method: %s.\n", argument); + exit(1); + } + check_param.stats_method= test(method-1)? MI_STATS_METHOD_NULLS_EQUAL : + MI_STATS_METHOD_NULLS_NOT_EQUAL; + break; + } #ifdef DEBUG /* Only useful if debugging */ case OPT_START_CHECK_POS: check_param.start_check_pos= strtoull(argument, NULL, 0); diff --git a/myisam/myisamdef.h b/myisam/myisamdef.h index 15b310e907e..93a7bf96f59 100644 --- a/myisam/myisamdef.h +++ b/myisam/myisamdef.h @@ -261,6 +261,7 @@ struct st_myisam_info { uint last_rkey_length; /* Last length in mi_rkey() */ enum ha_rkey_function last_key_func; /* CONTAIN, OVERLAP, etc */ uint save_lastkey_length; + uint pack_key_length; /* For MYISAMMRG */ int errkey; /* Got last error on this key */ int lock_type; /* How database was locked */ int tmp_lock_type; /* When locked by readinfo */ diff --git a/myisammrg/myrg_rkey.c b/myisammrg/myrg_rkey.c index a85ef6a3b5e..f87b264081e 100644 --- a/myisammrg/myrg_rkey.c +++ b/myisammrg/myrg_rkey.c @@ -44,11 +44,12 @@ int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key, MYRG_TABLE *table; MI_INFO *mi; int err; + DBUG_ENTER("myrg_rkey"); LINT_INIT(key_buff); LINT_INIT(pack_key_length); if (_myrg_init_queue(info,inx,search_flag)) - return my_errno; + DBUG_RETURN(my_errno); for (table=info->open_tables ; table != info->end_table ; table++) { @@ -57,8 +58,9 @@ int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key, if (table == info->open_tables) { err=mi_rkey(mi,0,inx,key,key_len,search_flag); + /* Get the saved packed key and packed key length. */ key_buff=(byte*) mi->lastkey+mi->s->base.max_key_length; - pack_key_length=mi->last_rkey_length; + pack_key_length=mi->pack_key_length; } else { @@ -71,17 +73,22 @@ int myrg_rkey(MYRG_INFO *info,byte *buf,int inx, const byte *key, { if (err == HA_ERR_KEY_NOT_FOUND) continue; - return err; + DBUG_PRINT("exit", ("err: %d", err)); + DBUG_RETURN(err); } /* adding to queue */ queue_insert(&(info->by_key),(byte *)table); } + DBUG_PRINT("info", ("tables with matches: %u", info->by_key.elements)); if (!info->by_key.elements) - return HA_ERR_KEY_NOT_FOUND; + DBUG_RETURN(HA_ERR_KEY_NOT_FOUND); mi=(info->current_table=(MYRG_TABLE *)queue_top(&(info->by_key)))->table; mi->once_flags|= RRND_PRESERVE_LASTINX; - return _myrg_mi_read_record(mi,buf); + DBUG_PRINT("info", ("using table no: %d", + info->current_table - info->open_tables + 1)); + DBUG_DUMP("result key", (byte*) mi->lastkey, mi->lastkey_length); + DBUG_RETURN(_myrg_mi_read_record(mi,buf)); } 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 eed80b1e339..66c92151ea4 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_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 ( $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 ( 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"); @@ -2180,7 +2182,6 @@ sub run_mysqltest ($) { $glob_mysql_test_dir); } - # ---------------------------------------------------------------------- # If embedded server, we create server args to give mysqltest to pass on # ---------------------------------------------------------------------- @@ -2210,6 +2211,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 @@ -2276,8 +2307,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/cast.result b/mysql-test/r/cast.result index 7cd0934f7a3..1b681941a1d 100644 --- a/mysql-test/r/cast.result +++ b/mysql-test/r/cast.result @@ -54,6 +54,18 @@ CONVERT(DATE "2004-01-22 21:45:33",BINARY(4)) select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)); CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)) 2004 +select CAST(0xb3 as signed); +CAST(0xb3 as signed) +179 +select CAST(0x8fffffffffffffff as signed); +CAST(0x8fffffffffffffff as signed) +-8070450532247928833 +select CAST(0xffffffffffffffff as unsigned); +CAST(0xffffffffffffffff as unsigned) +18446744073709551615 +select CAST(0xfffffffffffffffe as signed); +CAST(0xfffffffffffffffe as signed) +-2 select cast('18446744073709551616' as unsigned); cast('18446744073709551616' as unsigned) 18446744073709551615 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 12bc5ca2582..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 @@ -560,3 +569,23 @@ 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_group.result b/mysql-test/r/func_group.result index 2fb18ca92c7..67966b999d4 100644 --- a/mysql-test/r/func_group.result +++ b/mysql-test/r/func_group.result @@ -780,3 +780,139 @@ SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; MAX(id) NULL DROP TABLE t1; +create table t1m (a int) engine=myisam; +create table t1i (a int) engine=innodb; +create table t2m (a int) engine=myisam; +create table t2i (a int) engine=innodb; +insert into t2m values (5); +insert into t2i values (5); +select min(a) from t1m; +min(a) +NULL +select min(7) from t1m; +min(7) +NULL +select min(7) from DUAL; +min(7) +NULL +explain select min(7) from t2m join t1m; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select min(7) from t2m join t1m; +min(7) +NULL +select max(a) from t1m; +max(a) +NULL +select max(7) from t1m; +max(7) +NULL +select max(7) from DUAL; +max(7) +NULL +explain select max(7) from t2m join t1m; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Select tables optimized away +select max(7) from t2m join t1m; +max(7) +NULL +select 1, min(a) from t1m where a=99; +1 min(a) +1 NULL +select 1, min(a) from t1m where 1=99; +1 min(a) +1 NULL +select 1, min(1) from t1m where a=99; +1 min(1) +select 1, min(1) from t1m where 1=99; +1 min(1) +1 NULL +select 1, max(a) from t1m where a=99; +1 max(a) +1 NULL +select 1, max(a) from t1m where 1=99; +1 max(a) +1 NULL +select 1, max(1) from t1m where a=99; +1 max(1) +select 1, max(1) from t1m where 1=99; +1 max(1) +1 NULL +select min(a) from t1i; +min(a) +NULL +select min(7) from t1i; +min(7) +NULL +select min(7) from DUAL; +min(7) +NULL +explain select min(7) from t2i join t1i; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2i ALL NULL NULL NULL NULL 1 +1 SIMPLE t1i ALL NULL NULL NULL NULL 1 +select min(7) from t2i join t1i; +min(7) +NULL +select max(a) from t1i; +max(a) +NULL +select max(7) from t1i; +max(7) +NULL +select max(7) from DUAL; +max(7) +NULL +explain select max(7) from t2i join t1i; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2i ALL NULL NULL NULL NULL 1 +1 SIMPLE t1i ALL NULL NULL NULL NULL 1 +select max(7) from t2i join t1i; +max(7) +NULL +select 1, min(a) from t1i where a=99; +1 min(a) +1 NULL +select 1, min(a) from t1i where 1=99; +1 min(a) +1 NULL +select 1, min(1) from t1i where a=99; +1 min(1) +1 NULL +select 1, min(1) from t1i where 1=99; +1 min(1) +1 NULL +select 1, max(a) from t1i where a=99; +1 max(a) +1 NULL +select 1, max(a) from t1i where 1=99; +1 max(a) +1 NULL +select 1, max(1) from t1i where a=99; +1 max(1) +1 NULL +select 1, max(1) from t1i where 1=99; +1 max(1) +1 NULL +explain select count(*), min(7), max(7) from t1m, t1i; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found +1 SIMPLE t1i ALL NULL NULL NULL NULL 1 +select count(*), min(7), max(7) from t1m, t1i; +count(*) min(7) max(7) +0 NULL NULL +explain select count(*), min(7), max(7) from t1m, t2i; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1m system NULL NULL NULL NULL 0 const row not found +1 SIMPLE t2i ALL NULL NULL NULL NULL 1 +select count(*), min(7), max(7) from t1m, t2i; +count(*) min(7) max(7) +0 NULL NULL +explain select count(*), min(7), max(7) from t2m, t1i; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2m system NULL NULL NULL NULL 1 +1 SIMPLE t1i ALL NULL NULL NULL NULL 1 +select count(*), min(7), max(7) from t2m, t1i; +count(*) min(7) max(7) +0 NULL NULL +drop table t1m, t1i, t2m, t2i; diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result index 516d0a28a21..3cf2afc83d1 100644 --- a/mysql-test/r/func_in.result +++ b/mysql-test/r/func_in.result @@ -193,3 +193,12 @@ select * from t1 where a in (NULL, 'aa'); a aa drop table t1; +create table t1 (id int, key(id)); +insert into t1 values (1),(2),(3); +select count(*) from t1 where id not in (1); +count(*) +2 +select count(*) from t1 where id not in (1,2); +count(*) +1 +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/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/loaddata.result b/mysql-test/r/loaddata.result index c0baabcc507..46db14a5871 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -66,3 +66,13 @@ a b 3 row 3 0 drop table t1; +SET @OLD_SQL_MODE=@@SQL_MODE, @@SQL_MODE=NO_AUTO_VALUE_ON_ZERO; +create table t1(id integer not null auto_increment primary key); +insert into t1 values(0); +select * from t1; +id +0 +select * from t1; +id +0 +SET @@SQL_MODE=@OLD_SQL_MODE; diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result index 6e14e9a56a8..0f055031572 100644 --- a/mysql-test/r/merge.result +++ b/mysql-test/r/merge.result @@ -651,6 +651,32 @@ ERROR HY000: You can't specify target table 't1' for update in FROM clause create table t3 engine=merge union=(t1, t2) select * from t2; ERROR HY000: You can't specify target table 't2' for update in FROM clause drop table t1, t2; +create table t1 ( +a double(16,6), +b varchar(10), +index (a,b) +) engine=merge union=(t2,t3); +create table t2 ( +a double(16,6), +b varchar(10), +index (a,b) +) engine=myisam; +create table t3 ( +a double(16,6), +b varchar(10), +index (a,b) +) engine=myisam; +insert into t2 values ( null, ''); +insert into t2 values ( 9999999999.999999, ''); +insert into t3 select * from t2; +select min(a), max(a) from t1; +min(a) max(a) +9999999999.999998 9999999999.999998 +flush tables; +select min(a), max(a) from t1; +min(a) max(a) +9999999999.999998 9999999999.999998 +drop table t1, t2, t3; create table t1 (a int,b int,c int, index (a,b,c)); create table t2 (a int,b int,c int, index (a,b,c)); create table t3 (a int,b int,c int, index (a,b,c)) diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 1837a4078a7..0a6f3ddc28b 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -609,3 +609,64 @@ checksum table t2; Table Checksum test.t2 984116287 drop table t1, t2; +show variables like 'myisam_stats_method'; +Variable_name Value +myisam_stats_method nulls_unequal +create table t1 (a int, key(a)); +insert into t1 values (0),(1),(2),(3),(4); +insert into t1 select NULL from t1; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 10 NULL NULL YES BTREE +insert into t1 values (11); +delete from t1 where a=11; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 10 NULL NULL YES BTREE +set myisam_stats_method=nulls_equal; +show variables like 'myisam_stats_method'; +Variable_name Value +myisam_stats_method nulls_equal +insert into t1 values (11); +delete from t1 where a=11; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 5 NULL NULL YES BTREE +insert into t1 values (11); +delete from t1 where a=11; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 5 NULL NULL YES BTREE +set myisam_stats_method=DEFAULT; +show variables like 'myisam_stats_method'; +Variable_name Value +myisam_stats_method nulls_unequal +insert into t1 values (11); +delete from t1 where a=11; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 10 NULL NULL YES BTREE +insert into t1 values (11); +delete from t1 where a=11; +check table t1; +Table Op Msg_type Msg_text +test.t1 check status OK +show index from t1; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t1 1 a 1 a A 10 NULL NULL YES BTREE +drop table t1; diff --git a/mysql-test/r/ndb_alter_table.result b/mysql-test/r/ndb_alter_table.result index 63afc07718f..3714ea14e16 100644 --- a/mysql-test/r/ndb_alter_table.result +++ b/mysql-test/r/ndb_alter_table.result @@ -200,3 +200,119 @@ a drop table t4; show tables; Tables_in_test +create table t1 ( +ai bigint auto_increment, +c001 int(11) not null, +c002 int(11) not null, +c003 int(11) not null, +c004 int(11) not null, +c005 int(11) not null, +c006 int(11) not null, +c007 int(11) not null, +c008 int(11) not null, +c009 int(11) not null, +c010 int(11) not null, +c011 int(11) not null, +c012 int(11) not null, +c013 int(11) not null, +c014 int(11) not null, +c015 int(11) not null, +c016 int(11) not null, +c017 int(11) not null, +c018 int(11) not null, +c019 int(11) not null, +c020 int(11) not null, +c021 int(11) not null, +c022 int(11) not null, +c023 int(11) not null, +c024 int(11) not null, +c025 int(11) not null, +c026 int(11) not null, +c027 int(11) not null, +c028 int(11) not null, +c029 int(11) not null, +c030 int(11) not null, +c031 int(11) not null, +c032 int(11) not null, +c033 int(11) not null, +c034 int(11) not null, +c035 int(11) not null, +c036 int(11) not null, +c037 int(11) not null, +c038 int(11) not null, +c039 int(11) not null, +c040 int(11) not null, +c041 int(11) not null, +c042 int(11) not null, +c043 int(11) not null, +c044 int(11) not null, +c045 int(11) not null, +c046 int(11) not null, +c047 int(11) not null, +c048 int(11) not null, +c049 int(11) not null, +c050 int(11) not null, +c051 int(11) not null, +c052 int(11) not null, +c053 int(11) not null, +c054 int(11) not null, +c055 int(11) not null, +c056 int(11) not null, +c057 int(11) not null, +c058 int(11) not null, +c059 int(11) not null, +c060 int(11) not null, +c061 int(11) not null, +c062 int(11) not null, +c063 int(11) not null, +c064 int(11) not null, +c065 int(11) not null, +c066 int(11) not null, +c067 int(11) not null, +c068 int(11) not null, +c069 int(11) not null, +c070 int(11) not null, +c071 int(11) not null, +c072 int(11) not null, +c073 int(11) not null, +c074 int(11) not null, +c075 int(11) not null, +c076 int(11) not null, +c077 int(11) not null, +c078 int(11) not null, +c079 int(11) not null, +c080 int(11) not null, +c081 int(11) not null, +c082 int(11) not null, +c083 int(11) not null, +c084 int(11) not null, +c085 int(11) not null, +c086 int(11) not null, +c087 int(11) not null, +c088 int(11) not null, +c089 int(11) not null, +c090 int(11) not null, +c091 int(11) not null, +c092 int(11) not null, +c093 int(11) not null, +c094 int(11) not null, +c095 int(11) not null, +c096 int(11) not null, +c097 int(11) not null, +c098 int(11) not null, +c099 int(11) not null, +c100 int(11) not null, +c101 int(11) not null, +c102 int(11) not null, +c103 int(11) not null, +c104 int(11) not null, +c105 int(11) not null, +c106 int(11) not null, +c107 int(11) not null, +c108 int(11) not null, +c109 int(11) not null, +primary key (ai), +unique key tx1 (c002, c003, c004, c005)) engine=ndb; +create index tx2 +on t1 (c010, c011, c012, c013); +drop table t1; 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_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/type_decimal.result b/mysql-test/r/type_decimal.result index a9dcabd121e..c3b2d5090ef 100644 --- a/mysql-test/r/type_decimal.result +++ b/mysql-test/r/type_decimal.result @@ -646,3 +646,12 @@ a 9999.999 0000.000 drop table t1; +create table t1(a decimal(10,5), b decimal(10,1)); +insert into t1 values(123.12345, 123.12345); +update t1 set b=a; +Warnings: +Warning 1265 Data truncated for column 'b' at row 1 +select * from t1; +a b +123.12345 123.1 +drop table t1; diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 1b5fa69d713..a3dd2c5c291 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -780,21 +780,6 @@ t1 CREATE TABLE `t1` ( `b` longblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1,t2; -create table t1 (d decimal(10,1)); -create table t2 (d decimal(10,9)); -insert into t1 values ("100000000.0"); -insert into t2 values ("1.23456780"); -create table t3 select * from t2 union select * from t1; -select * from t3; -d -1.234567800 -100000000.0 -show create table t3; -Table Create Table -t3 CREATE TABLE `t3` ( - `d` decimal(10,9) default NULL -) ENGINE=MyISAM DEFAULT CHARSET=latin1 -drop table t1,t2,t3; create table t1 select 1 union select -1; select * from t1; 1 diff --git a/mysql-test/r/update.result b/mysql-test/r/update.result index e35d4e29fe4..d6c1118f90c 100644 --- a/mysql-test/r/update.result +++ b/mysql-test/r/update.result @@ -251,3 +251,15 @@ f1 f2 1 1 2 2 drop table t1,t2; +create table t1(f1 int); +select DATABASE(); +DATABASE() +test +update t1 set f1=1 where count(*)=1; +ERROR HY000: Invalid use of group function +select DATABASE(); +DATABASE() +test +delete from t1 where count(*)=1; +ERROR HY000: Invalid use of group function +drop table t1; 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/cast.test b/mysql-test/t/cast.test index 394971f9648..bb01e8cea83 100644 --- a/mysql-test/t/cast.test +++ b/mysql-test/t/cast.test @@ -20,6 +20,10 @@ select CONVERT(DATE "2004-01-22 21:45:33",CHAR); select CONVERT(DATE "2004-01-22 21:45:33",CHAR(4)); select CONVERT(DATE "2004-01-22 21:45:33",BINARY(4)); select CAST(DATE "2004-01-22 21:45:33" AS BINARY(4)); +select CAST(0xb3 as signed); +select CAST(0x8fffffffffffffff as signed); +select CAST(0xffffffffffffffff as unsigned); +select CAST(0xfffffffffffffffe as signed); # out-of-range cases select cast('18446744073709551616' as unsigned); 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 9e003d19ab9..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); @@ -356,4 +366,20 @@ 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_group.test b/mysql-test/t/func_group.test index 4dc8d66c4f1..f833f482f73 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -527,4 +527,73 @@ INSERT INTO t1 VALUES SELECT MAX(id) FROM t1 WHERE id < 3 AND a=2 AND b=6; DROP TABLE t1; +# +# Bug #12882 min/max inconsistent on empty table +# + +create table t1m (a int) engine=myisam; +create table t1i (a int) engine=innodb; +create table t2m (a int) engine=myisam; +create table t2i (a int) engine=innodb; +insert into t2m values (5); +insert into t2i values (5); + +# test with MyISAM +select min(a) from t1m; +select min(7) from t1m; +select min(7) from DUAL; +explain select min(7) from t2m join t1m; +select min(7) from t2m join t1m; + +select max(a) from t1m; +select max(7) from t1m; +select max(7) from DUAL; +explain select max(7) from t2m join t1m; +select max(7) from t2m join t1m; + +select 1, min(a) from t1m where a=99; +select 1, min(a) from t1m where 1=99; +select 1, min(1) from t1m where a=99; +select 1, min(1) from t1m where 1=99; + +select 1, max(a) from t1m where a=99; +select 1, max(a) from t1m where 1=99; +select 1, max(1) from t1m where a=99; +select 1, max(1) from t1m where 1=99; + +# test with InnoDB +select min(a) from t1i; +select min(7) from t1i; +select min(7) from DUAL; +explain select min(7) from t2i join t1i; +select min(7) from t2i join t1i; + +select max(a) from t1i; +select max(7) from t1i; +select max(7) from DUAL; +explain select max(7) from t2i join t1i; +select max(7) from t2i join t1i; + +select 1, min(a) from t1i where a=99; +select 1, min(a) from t1i where 1=99; +select 1, min(1) from t1i where a=99; +select 1, min(1) from t1i where 1=99; + +select 1, max(a) from t1i where a=99; +select 1, max(a) from t1i where 1=99; +select 1, max(1) from t1i where a=99; +select 1, max(1) from t1i where 1=99; + +# mixed MyISAM/InnoDB test +explain select count(*), min(7), max(7) from t1m, t1i; +select count(*), min(7), max(7) from t1m, t1i; + +explain select count(*), min(7), max(7) from t1m, t2i; +select count(*), min(7), max(7) from t1m, t2i; + +explain select count(*), min(7), max(7) from t2m, t1i; +select count(*), min(7), max(7) from t2m, t1i; + +drop table t1m, t1i, t2m, t2i; + # End of 4.1 tests diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test index aec2de7a467..2ffe5a2d5f7 100644 --- a/mysql-test/t/func_in.test +++ b/mysql-test/t/func_in.test @@ -102,4 +102,11 @@ insert into t1 values ('aa'), ('bb'); select * from t1 where a in (NULL, 'aa'); drop table t1; +# BUG#13419 +create table t1 (id int, key(id)); +insert into t1 values (1),(2),(3); +select count(*) from t1 where id not in (1); +select count(*) from t1 where id not in (1,2); +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/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/loaddata.test b/mysql-test/t/loaddata.test index 689bdbbf92d..86fbdc62702 100644 --- a/mysql-test/t/loaddata.test +++ b/mysql-test/t/loaddata.test @@ -31,4 +31,31 @@ load data infile '../../std_data/loaddata4.dat' into table t1 fields terminated select * from t1; drop table t1; + +# +# Bug #12053 LOAD DATA INFILE ignores NO_AUTO_VALUE_ON_ZERO setting +# +SET @OLD_SQL_MODE=@@SQL_MODE, @@SQL_MODE=NO_AUTO_VALUE_ON_ZERO; +create table t1(id integer not null auto_increment primary key); +insert into t1 values(0); +disable_query_log; +eval SELECT * INTO OUTFILE '$MYSQL_TEST_DIR/var/tmp/t1' from t1; +delete from t1; +eval load data infile '$MYSQL_TEST_DIR/var/tmp/t1' into table t1; +enable_query_log; +select * from t1; +--exec rm $MYSQL_TEST_DIR/var/tmp/t1 + +disable_query_log; +eval SELECT * INTO OUTFILE '$MYSQL_TEST_DIR/var/tmp/t1' +FIELDS TERMINATED BY '' OPTIONALLY ENCLOSED BY '' LINES TERMINATED BY '\r\n' +FROM t1; +delete from t1; +eval load data infile '$MYSQL_TEST_DIR/var/tmp/t1' into table t1 +FIELDS TERMINATED BY '' OPTIONALLY ENCLOSED BY '' LINES TERMINATED BY '\r\n'; +enable_query_log; +select * from t1; +--exec rm $MYSQL_TEST_DIR/var/tmp/t1 +SET @@SQL_MODE=@OLD_SQL_MODE; + # End of 4.1 tests diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test index fa13107ca04..347a76c3991 100644 --- a/mysql-test/t/merge.test +++ b/mysql-test/t/merge.test @@ -286,6 +286,42 @@ create table t3 engine=merge union=(t1, t2) select * from t1; create table t3 engine=merge union=(t1, t2) select * from t2; drop table t1, t2; +# +# Bug#9112 - Merge table with composite index producing invalid results with some queries +# This test case will fail only without the bugfix and some +# non-deterministic circumstances. It depends on properly initialized +# "un-initialized" memory. At the time it happens with a standard +# non-debug build. But there is no guarantee that this will be always so. +# +create table t1 ( + a double(16,6), + b varchar(10), + index (a,b) +) engine=merge union=(t2,t3); + +create table t2 ( + a double(16,6), + b varchar(10), + index (a,b) +) engine=myisam; + +create table t3 ( + a double(16,6), + b varchar(10), + index (a,b) +) engine=myisam; + +insert into t2 values ( null, ''); +# We may have insufficient accuracy for 16 digits of '9'. +# Suppress a "truncate" warning due to accuracy problems. +--disable_warnings +insert into t2 values ( 9999999999.999999, ''); +--enable_warnings +insert into t3 select * from t2; +select min(a), max(a) from t1; +flush tables; +select min(a), max(a) from t1; +drop table t1, t2, t3; # BUG#6699 : no sorting on 'ref' retrieval create table t1 (a int,b int,c int, index (a,b,c)); create table t2 (a int,b int,c int, index (a,b,c)); diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 83e9e1ba7d2..dc40ecc2dd4 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -590,4 +590,51 @@ checksum table t1; checksum table t2; drop table t1, t2; +# BUG#12232: New myisam_stats_method variable. +show variables like 'myisam_stats_method'; + +create table t1 (a int, key(a)); +insert into t1 values (0),(1),(2),(3),(4); +insert into t1 select NULL from t1; + +# default: NULLs considered inequal +analyze table t1; +show index from t1; +insert into t1 values (11); +delete from t1 where a=11; +check table t1; +show index from t1; + +# Set nulls to be equal: +set myisam_stats_method=nulls_equal; +show variables like 'myisam_stats_method'; +insert into t1 values (11); +delete from t1 where a=11; + +analyze table t1; +show index from t1; + +insert into t1 values (11); +delete from t1 where a=11; + +check table t1; +show index from t1; + +# Set nulls back to be equal +set myisam_stats_method=DEFAULT; +show variables like 'myisam_stats_method'; +insert into t1 values (11); +delete from t1 where a=11; + +analyze table t1; +show index from t1; + +insert into t1 values (11); +delete from t1 where a=11; + +check table t1; +show index from t1; + +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/ndb_alter_table.test b/mysql-test/t/ndb_alter_table.test index b5b73ad1998..5c792f76316 100644 --- a/mysql-test/t/ndb_alter_table.test +++ b/mysql-test/t/ndb_alter_table.test @@ -199,4 +199,123 @@ drop table t4; show tables; connection server1; +create table t1 ( +ai bigint auto_increment, +c001 int(11) not null, +c002 int(11) not null, +c003 int(11) not null, +c004 int(11) not null, +c005 int(11) not null, +c006 int(11) not null, +c007 int(11) not null, +c008 int(11) not null, +c009 int(11) not null, +c010 int(11) not null, +c011 int(11) not null, +c012 int(11) not null, +c013 int(11) not null, +c014 int(11) not null, +c015 int(11) not null, +c016 int(11) not null, +c017 int(11) not null, +c018 int(11) not null, +c019 int(11) not null, +c020 int(11) not null, +c021 int(11) not null, +c022 int(11) not null, +c023 int(11) not null, +c024 int(11) not null, +c025 int(11) not null, +c026 int(11) not null, +c027 int(11) not null, +c028 int(11) not null, +c029 int(11) not null, +c030 int(11) not null, +c031 int(11) not null, +c032 int(11) not null, +c033 int(11) not null, +c034 int(11) not null, +c035 int(11) not null, +c036 int(11) not null, +c037 int(11) not null, +c038 int(11) not null, +c039 int(11) not null, +c040 int(11) not null, +c041 int(11) not null, +c042 int(11) not null, +c043 int(11) not null, +c044 int(11) not null, +c045 int(11) not null, +c046 int(11) not null, +c047 int(11) not null, +c048 int(11) not null, +c049 int(11) not null, +c050 int(11) not null, +c051 int(11) not null, +c052 int(11) not null, +c053 int(11) not null, +c054 int(11) not null, +c055 int(11) not null, +c056 int(11) not null, +c057 int(11) not null, +c058 int(11) not null, +c059 int(11) not null, +c060 int(11) not null, +c061 int(11) not null, +c062 int(11) not null, +c063 int(11) not null, +c064 int(11) not null, +c065 int(11) not null, +c066 int(11) not null, +c067 int(11) not null, +c068 int(11) not null, +c069 int(11) not null, +c070 int(11) not null, +c071 int(11) not null, +c072 int(11) not null, +c073 int(11) not null, +c074 int(11) not null, +c075 int(11) not null, +c076 int(11) not null, +c077 int(11) not null, +c078 int(11) not null, +c079 int(11) not null, +c080 int(11) not null, +c081 int(11) not null, +c082 int(11) not null, +c083 int(11) not null, +c084 int(11) not null, +c085 int(11) not null, +c086 int(11) not null, +c087 int(11) not null, +c088 int(11) not null, +c089 int(11) not null, +c090 int(11) not null, +c091 int(11) not null, +c092 int(11) not null, +c093 int(11) not null, +c094 int(11) not null, +c095 int(11) not null, +c096 int(11) not null, +c097 int(11) not null, +c098 int(11) not null, +c099 int(11) not null, +c100 int(11) not null, +c101 int(11) not null, +c102 int(11) not null, +c103 int(11) not null, +c104 int(11) not null, +c105 int(11) not null, +c106 int(11) not null, +c107 int(11) not null, +c108 int(11) not null, +c109 int(11) not null, +primary key (ai), +unique key tx1 (c002, c003, c004, c005)) engine=ndb; + +create index tx2 +on t1 (c010, c011, c012, c013); + +drop table t1; + # End of 4.1 tests 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/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/mysql-test/t/type_decimal.test b/mysql-test/t/type_decimal.test index a6fd99e8c9a..1f133666910 100644 --- a/mysql-test/t/type_decimal.test +++ b/mysql-test/t/type_decimal.test @@ -266,4 +266,14 @@ insert into t1 values ('1'),('+1'),('-1'),('0000000001'),('+0000000001'),('-0000 select * from t1; drop table t1; +# +# Bug #7589: a problem with update from column +# + +create table t1(a decimal(10,5), b decimal(10,1)); +insert into t1 values(123.12345, 123.12345); +update t1 set b=a; +select * from t1; +drop table t1; + # End of 4.1 tests diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 6acccaeafd5..6a54909536a 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -425,14 +425,6 @@ create table t1 SELECT b from t2 UNION select tx from t2; select * from t1; show create table t1; drop table t1,t2; -create table t1 (d decimal(10,1)); -create table t2 (d decimal(10,9)); -insert into t1 values ("100000000.0"); -insert into t2 values ("1.23456780"); -create table t3 select * from t2 union select * from t1; -select * from t3; -show create table t3; -drop table t1,t2,t3; create table t1 select 1 union select -1; select * from t1; show create table t1; diff --git a/mysql-test/t/update.test b/mysql-test/t/update.test index e4e751862f1..84e9ced2017 100644 --- a/mysql-test/t/update.test +++ b/mysql-test/t/update.test @@ -215,4 +215,16 @@ UPDATE t1 SET t1.f2=(SELECT MAX(t2.f4) FROM t2 WHERE t2.f3=t1.f1); select * from t1; drop table t1,t2; +# +# Bug #13180 sometimes server accepts sum func in update/delete where condition +# +create table t1(f1 int); +select DATABASE(); +--error 1111 +update t1 set f1=1 where count(*)=1; +select DATABASE(); +--error 1111 +delete from t1 where count(*)=1; +drop table t1; + # End of 4.1 tests 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/mysys/my_conio.c b/mysys/my_conio.c new file mode 100644 index 00000000000..e381f9f23ef --- /dev/null +++ b/mysys/my_conio.c @@ -0,0 +1,217 @@ +/* Copyright (C) 2000 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 "mysys_priv.h" + +#ifdef __WIN__ + +static HANDLE my_coninpfh= 0; /* console input */ + +/* + functions my_pthread_auto_mutex_lock & my_pthread_auto_mutex_free + are experimental at this moment, they are intended to bring + ability of protecting code sections without necessity to explicitly + initialize synchronization object in one of threads + + if found useful they are to be exported in mysys +*/ + +/* + int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name, + int id, int time) + + NOTES + creates a mutex with given name and tries to lock it time msec. + mutex name is appended with id to allow system wide or process wide + locks. Handle to created mutex returned in ph argument. + + RETURN + 0 thread owns mutex + <>0 error + +*/ +static +int my_pthread_auto_mutex_lock(HANDLE* ph, const char* name, int id, int time) +{ + int res; + char tname[FN_REFLEN]; + + sprintf(tname, "%s-%08X", name, id); + + *ph= CreateMutex(NULL, FALSE, tname); + if (*ph == NULL) + return GetLastError(); + + res= WaitForSingleObject(*ph, time); + + if (res == WAIT_TIMEOUT) + return ERROR_SEM_TIMEOUT; + + if (res == WAIT_FAILED) + return GetLastError(); + + return 0; +} + +/* + int my_pthread_auto_mutex_free(HANDLE* ph) + + + NOTES + releases a mutex. + + RETURN + 0 thread released mutex + <>0 error + +*/ +static +int my_pthread_auto_mutex_free(HANDLE* ph) +{ + if (*ph) + { + ReleaseMutex(*ph); + CloseHandle(*ph); + *ph= NULL; + } + + return 0; +} + + +#define pthread_auto_mutex_decl(name) \ + HANDLE __h##name= NULL; + +#define pthread_auto_mutex_lock(name, proc, time) \ + my_pthread_auto_mutex_lock(&__h##name, #name, (proc), (time)) + +#define pthread_auto_mutex_free(name) \ + my_pthread_auto_mutex_free(&__h##name) + + +/* + char* my_cgets(char *string, unsigned long clen, unsigned long* plen) + + NOTES + Replaces _cgets from libc to support input of more than 255 chars. + Reads from the console via ReadConsole into buffer which + should be at least clen characters. + Actual length of string returned in plen. + + WARNING + my_cgets() does NOT check the pushback character buffer (i.e., _chbuf). + Thus, my_cgets() will not return any character that is pushed back by + the _ungetch() call. + + RETURN + string pointer ok + NULL Error + +*/ +char* my_cgets(char *buffer, unsigned long clen, unsigned long* plen) +{ + ULONG state; + char *result; + CONSOLE_SCREEN_BUFFER_INFO csbi; + + pthread_auto_mutex_decl(my_conio_cs); + + /* lock the console for the current process*/ + if (pthread_auto_mutex_lock(my_conio_cs, GetCurrentProcessId(), INFINITE)) + { + /* can not lock console */ + pthread_auto_mutex_free(my_conio_cs); + return NULL; + } + + /* init console input */ + if (my_coninpfh == 0) + { + /* same handle will be used until process termination */ + my_coninpfh= CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + } + + if (my_coninpfh == INVALID_HANDLE_VALUE) + { + /* unlock the console */ + pthread_auto_mutex_free(my_conio_cs); + return(NULL); + } + + GetConsoleMode((HANDLE)my_coninpfh, &state); + SetConsoleMode((HANDLE)my_coninpfh, ENABLE_LINE_INPUT | + ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT); + + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); + + /* + there is no known way to determine allowed buffer size for input + though it is known it should not be more than 64K + so we cut 64K and try first size of screen buffer + if it is still to large we cut half of it and try again + later we may want to cycle from min(clen, 65535) to allowed size + with small decrement to determine exact allowed buffer + */ + clen= min(clen, 65535); + do + { + clen= min(clen, (unsigned long)csbi.dwSize.X*csbi.dwSize.Y); + if (!ReadConsole((HANDLE)my_coninpfh, (LPVOID)buffer, clen - 1, plen, NULL)) + { + result= NULL; + clen>>= 1; + } + else + { + result= buffer; + break; + } + } + while (GetLastError() == ERROR_NOT_ENOUGH_MEMORY); + + + if (result != NULL) + { + if (buffer[*plen - 2] == '\r') + { + *plen= *plen - 2; + } + else + { + if (buffer[*plen - 1] == '\r') + { + char tmp[3]; + int tmplen= sizeof(tmp); + + *plen= *plen - 1; + /* read /n left in the buffer */ + ReadConsole((HANDLE)my_coninpfh, (LPVOID)tmp, tmplen, &tmplen, NULL); + } + } + buffer[*plen]= '\0'; + } + + SetConsoleMode((HANDLE)my_coninpfh, state); + /* unlock the console */ + pthread_auto_mutex_free(my_conio_cs); + + return result; +} + +#endif /* __WIN__ */ 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/ndbapi/Ndb.hpp b/ndb/include/ndbapi/Ndb.hpp index 766409d64e2..e905a304c97 100644 --- a/ndb/include/ndbapi/Ndb.hpp +++ b/ndb/include/ndbapi/Ndb.hpp @@ -882,10 +882,10 @@ class BaseString; class NdbEventOperation; class NdbBlob; class NdbReceiver; +template <class T> struct Ndb_free_list_t; typedef void (* NdbEventCallback)(NdbEventOperation*, Ndb*, void*); - #if defined NDB_OSE /** * Default time to wait for response after request has been sent to @@ -1386,8 +1386,20 @@ public: */ NdbConnection* hupp( NdbConnection* ); Uint32 getReference() const { return theMyRef;} + + struct Free_list_usage + { + const char * m_name; + Uint32 m_created; + Uint32 m_free; + Uint32 m_sizeof; + }; + + Free_list_usage * get_free_list_usage(Free_list_usage*); #endif + + /***************************************************************************** * These are service routines used by the other classes in the NDBAPI. ****************************************************************************/ @@ -1562,22 +1574,8 @@ private: class NdbDictionaryImpl* theDictionary; class NdbGlobalEventBufferHandle* theGlobalEventBufferHandle; - NdbConnection* theConIdleList; // First connection in idle list. - - NdbOperation* theOpIdleList; // First operation in the idle list. - - NdbIndexScanOperation* theScanOpIdleList; // First scan operation in the idle list. - NdbIndexOperation* theIndexOpIdleList; // First index operation in the idle list. NdbConnection* theTransactionList; NdbConnection** theConnectionArray; - NdbRecAttr* theRecAttrIdleList; - NdbApiSignal* theSignalIdleList; // First signal in idlelist. - NdbLabel* theLabelList; // First label descriptor in list - NdbBranch* theBranchList; // First branch descriptor in list - NdbSubroutine* theSubroutineList; // First subroutine descriptor in - NdbCall* theCallList; // First call descriptor in list - NdbReceiver* theScanList; - NdbBlob* theNdbBlobIdleList; Uint32 theMyRef; // My block reference Uint32 theNode; // The node number of our node diff --git a/ndb/include/ndbapi/NdbBlob.hpp b/ndb/include/ndbapi/NdbBlob.hpp index b145c69b04b..a04f4f72bc9 100644 --- a/ndb/include/ndbapi/NdbBlob.hpp +++ b/ndb/include/ndbapi/NdbBlob.hpp @@ -262,7 +262,7 @@ private: // for keeping in lists NdbBlob* theNext; // initialization - NdbBlob(); + NdbBlob(Ndb*); void init(); void release(); // classify operations @@ -314,6 +314,10 @@ private: int getOperationType() const; friend class NdbOut& operator<<(NdbOut&, const NdbBlob&); #endif + + void next(NdbBlob* obj) { theNext= obj;} + NdbBlob* next() { return theNext;} + friend struct Ndb_free_list_t<NdbBlob>; }; #endif diff --git a/ndb/include/ndbapi/NdbConnection.hpp b/ndb/include/ndbapi/NdbConnection.hpp index 2ab6f7d6f64..75c3f80121d 100644 --- a/ndb/include/ndbapi/NdbConnection.hpp +++ b/ndb/include/ndbapi/NdbConnection.hpp @@ -18,8 +18,9 @@ #define NdbConnection_H #include <ndb_types.h> -#include <NdbError.hpp> -#include <NdbDictionary.hpp> +#include "NdbError.hpp" +#include "NdbDictionary.hpp" +#include "Ndb.hpp" class NdbConnection; class NdbOperation; @@ -465,10 +466,10 @@ private: /************************************************************************** * These are the create and delete methods of this class. * **************************************************************************/ - NdbConnection(Ndb* aNdb); - ~NdbConnection(); + NdbConnection* next(); // Returns the next pointer + void next(NdbConnection*); // Sets the next pointer void init(); // Initialize connection object for new transaction @@ -487,8 +488,6 @@ private: int getTC_ConnectPtr(); // Gets TC Connect pointer void setBuddyConPtr(Uint32); // Sets Buddy Con Ptr Uint32 getBuddyConPtr(); // Gets Buddy Con Ptr - NdbConnection* next(); // Returns the next pointer - void next(NdbConnection*); // Sets the next pointer enum ConStatusType { NotConnected, @@ -691,6 +690,7 @@ private: void define_scan_op(NdbIndexScanOperation*); friend class HugoOperations; + friend struct Ndb_free_list_t<NdbConnection>; }; inline diff --git a/ndb/include/ndbapi/NdbIndexOperation.hpp b/ndb/include/ndbapi/NdbIndexOperation.hpp index 1472f1b249e..2ab63cfc4f9 100644 --- a/ndb/include/ndbapi/NdbIndexOperation.hpp +++ b/ndb/include/ndbapi/NdbIndexOperation.hpp @@ -200,6 +200,7 @@ private: Uint32 m_theIndexDefined[NDB_MAX_ATTRIBUTES_IN_INDEX][3]; Uint32 m_theIndexLen; // Length of the index in words Uint32 m_theNoOfIndexDefined; // The number of index attributes + friend struct Ndb_free_list_t<NdbIndexOperation>; }; #endif diff --git a/ndb/include/ndbapi/NdbIndexScanOperation.hpp b/ndb/include/ndbapi/NdbIndexScanOperation.hpp index a3388f62f58..7cd2daea6a6 100644 --- a/ndb/include/ndbapi/NdbIndexScanOperation.hpp +++ b/ndb/include/ndbapi/NdbIndexScanOperation.hpp @@ -132,6 +132,8 @@ private: int compare(Uint32 key, Uint32 cols, const NdbReceiver*, const NdbReceiver*); Uint32 m_sort_columns; + + friend struct Ndb_free_list_t<NdbIndexScanOperation>; }; #endif diff --git a/ndb/include/ndbapi/NdbOperation.hpp b/ndb/include/ndbapi/NdbOperation.hpp index 46d4ddab0f5..46e44226e18 100644 --- a/ndb/include/ndbapi/NdbOperation.hpp +++ b/ndb/include/ndbapi/NdbOperation.hpp @@ -22,6 +22,7 @@ #include "NdbError.hpp" #include "NdbReceiver.hpp" #include "NdbDictionary.hpp" +#include "Ndb.hpp" class Ndb; class NdbApiSignal; @@ -723,8 +724,6 @@ protected: /****************************************************************************** * These are the methods used to create and delete the NdbOperation objects. *****************************************************************************/ - NdbOperation(Ndb* aNdb); - virtual ~NdbOperation(); bool needReply(); /****************************************************************************** @@ -736,8 +735,9 @@ protected: int init(const class NdbTableImpl*, NdbConnection* aCon); void initInterpreter(); + NdbOperation(Ndb* aNdb); + virtual ~NdbOperation(); void next(NdbOperation*); // Set next pointer - NdbOperation* next(); // Get next pointer enum OperationStatus{ @@ -925,6 +925,8 @@ protected: * IgnoreError on connection level. */ Int8 m_abortOption; + + friend struct Ndb_free_list_t<NdbOperation>; }; #ifdef NDB_NO_DROPPED_SIGNAL diff --git a/ndb/include/ndbapi/NdbRecAttr.hpp b/ndb/include/ndbapi/NdbRecAttr.hpp index 05635a99385..741ea3d52e2 100644 --- a/ndb/include/ndbapi/NdbRecAttr.hpp +++ b/ndb/include/ndbapi/NdbRecAttr.hpp @@ -17,7 +17,8 @@ #ifndef NdbRecAttr_H #define NdbRecAttr_H -#include <NdbDictionary.hpp> +#include "NdbDictionary.hpp" +#include "Ndb.hpp" class NdbOperation; @@ -242,7 +243,6 @@ public: */ ~NdbRecAttr(); private: - NdbRecAttr(); Uint32 attrId() const; /* Get attribute id */ bool setNULL(); /* Set NULL indicator */ @@ -251,6 +251,7 @@ private: void release(); /* Release memory if allocated */ void init(); /* Initialise object when allocated */ + NdbRecAttr(Ndb*); void next(NdbRecAttr* aRecAttr); NdbRecAttr* next() const; @@ -273,6 +274,8 @@ private: Uint32 theAttrSize; Uint32 theArraySize; const NdbDictionary::Column* m_column; + + friend struct Ndb_free_list_t<NdbRecAttr>; }; inline 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/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..56af24c5cf0 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; @@ -3239,6 +3265,7 @@ Backup::execBACKUP_FRAGMENT_REQ(Signal* signal) req->requestInfo = 0; req->savePointId = 0; req->tableId = table.tableId; + ScanFragReq::setReadCommittedFlag(req->requestInfo, 1); ScanFragReq::setLockMode(req->requestInfo, 0); ScanFragReq::setHoldLockFlag(req->requestInfo, 0); ScanFragReq::setKeyinfoFlag(req->requestInfo, 0); 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..5bd35812b47 100644 --- a/ndb/src/kernel/blocks/dbdict/Dbdict.cpp +++ b/ndb/src/kernel/blocks/dbdict/Dbdict.cpp @@ -3036,8 +3036,8 @@ Dbdict::alterTable_backup_mutex_locked(Signal* signal, lreq->gci = tablePtr.p->gciTableCreated; lreq->requestType = AlterTabReq::AlterTablePrepare; - sendSignal(rg, GSN_ALTER_TAB_REQ, signal, - AlterTabReq::SignalLength, JBB); + sendFragmentedSignal(rg, GSN_ALTER_TAB_REQ, signal, + AlterTabReq::SignalLength, JBB); } void Dbdict::alterTableRef(Signal * signal, @@ -3521,8 +3521,8 @@ Dbdict::execALTER_TAB_CONF(Signal * signal){ lreq->gci = gci; lreq->requestType = AlterTabReq::AlterTableCommit; - sendSignal(rg, GSN_ALTER_TAB_REQ, signal, - AlterTabReq::SignalLength, JBB); + sendFragmentedSignal(rg, GSN_ALTER_TAB_REQ, signal, + AlterTabReq::SignalLength, JBB); } } else { @@ -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/dbdict/Makefile.am b/ndb/src/kernel/blocks/dbdict/Makefile.am index 9a0d68f8148..3c1cf6735d9 100644 --- a/ndb/src/kernel/blocks/dbdict/Makefile.am +++ b/ndb/src/kernel/blocks/dbdict/Makefile.am @@ -1,12 +1,20 @@ -#SUBDIRS = printSchemafile - noinst_LIBRARIES = libdbdict.a +EXTRA_PROGRAMS = printSchemaFile libdbdict_a_SOURCES = Dbdict.cpp +printSchemaFile_SOURCES = printSchemaFile.cpp + include $(top_srcdir)/ndb/config/common.mk.am include $(top_srcdir)/ndb/config/type_kernel.mk.am +LDADD += \ + $(top_builddir)/ndb/src/common/util/libgeneral.la \ + $(top_builddir)/ndb/src/common/portlib/libportlib.la \ + $(top_builddir)/dbug/libdbug.a \ + $(top_builddir)/mysys/libmysys.a \ + $(top_builddir)/strings/libmystrings.a + # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp b/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp index 3e944485e1c..a8b84298ebe 100644 --- a/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp +++ b/ndb/src/kernel/blocks/dbdict/printSchemaFile.cpp @@ -1,11 +1,3 @@ -#if 0 -make -f Makefile -f - printSchemaFile <<'_eof_' -printSchemaFile: printSchemaFile.cpp - $(CXXCOMPILE) -o $@ $@.cpp -L../../../common/util/.libs -lgeneral -_eof_ -exit $? -#endif - /* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify @@ -58,8 +50,7 @@ print(const char * filename, const SchemaFile * file){ SchemaFile::TableEntry te = file->TableEntries[i]; if(te.m_tableState != SchemaFile::INIT){ ndbout << "Table " << i << ": State = " << te.m_tableState - << " version = " << table_version_major(te.m_tableVersion) << - << "(" << table_version_minor(te.m_tableVersion) << ")" + << " version = " << te.m_tableVersion << " type = " << te.m_tableType << " noOfPages = " << te.m_noOfPages << " gcp: " << te.m_gcp << endl; 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 b7e2ab072b5..6eadefe5df5 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.cpp @@ -266,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 b2da7427f4e..06bf7a85d53 100644 --- a/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp +++ b/ndb/src/kernel/blocks/dblqh/redoLogReader/records.hpp @@ -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/dbtc/DbtcMain.cpp b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp index f0861d1f0cc..04b40dafcb5 100644 --- a/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp +++ b/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp @@ -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/Dbtup.hpp b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp index dffafc1ab66..1cb3bd89997 100644 --- a/ndb/src/kernel/blocks/dbtup/Dbtup.hpp +++ b/ndb/src/kernel/blocks/dbtup/Dbtup.hpp @@ -1737,7 +1737,8 @@ private: Uint32* const mainBuffer, Uint32& noMainWords, Uint32* const copyBuffer, - Uint32& noCopyWords); + Uint32& noCopyWords, + bool xfrm); void sendTrigAttrInfo(Signal* signal, Uint32* data, diff --git a/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp b/ndb/src/kernel/blocks/dbtup/DbtupTrigger.cpp index 575d08efffc..59a31475617 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(); @@ -618,7 +622,8 @@ void Dbtup::executeTrigger(Signal* signal, mainBuffer, noMainWords, copyBuffer, - noCopyWords)) { + noCopyWords, + (ref == BACKUP ? false : true))) { ljam(); return; }//if @@ -723,7 +728,8 @@ bool Dbtup::readTriggerInfo(TupTriggerData* const trigPtr, Uint32* const mainBuffer, Uint32& noMainWords, Uint32* const copyBuffer, - Uint32& noCopyWords) + Uint32& noCopyWords, + bool xfrm) { noCopyWords = 0; noMainWords = 0; @@ -753,7 +759,7 @@ bool Dbtup::readTriggerInfo(TupTriggerData* const trigPtr, regTabPtr->noOfKeyAttr, keyBuffer, ZATTR_BUFFER_SIZE, - true); + xfrm); ndbrequire(ret != -1); noPrimKey= ret; @@ -796,7 +802,7 @@ bool Dbtup::readTriggerInfo(TupTriggerData* const trigPtr, numAttrsToRead, mainBuffer, ZATTR_BUFFER_SIZE, - true); + xfrm); ndbrequire(ret != -1); noMainWords= ret; } else { @@ -822,7 +828,7 @@ bool Dbtup::readTriggerInfo(TupTriggerData* const trigPtr, numAttrsToRead, copyBuffer, ZATTR_BUFFER_SIZE, - true); + xfrm); ndbrequire(ret != -1); noCopyWords = ret; diff --git a/ndb/src/kernel/main.cpp b/ndb/src/kernel/main.cpp index aa220b0ae05..d9953b920d2 100644 --- a/ndb/src/kernel/main.cpp +++ b/ndb/src/kernel/main.cpp @@ -394,5 +394,5 @@ handler_sigusr1(int signum) failed_startups++; failed_startup_flag = true; } - g_eventLogger.info("Received signal %d. Ndbd failed startup (%u).", signum, failed_startups); + g_eventLogger.info("Angel received ndbd startup failure count %u.", failed_startups); } 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/MgmtSrvr.cpp b/ndb/src/mgmsrv/MgmtSrvr.cpp index acab2ef9eac..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) @@ -709,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 ****************************************************************************/ @@ -1911,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: @@ -2446,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 && @@ -2453,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; @@ -2535,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 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/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/NdbApiSignal.cpp b/ndb/src/ndbapi/NdbApiSignal.cpp index a1d34896968..953d87ac7b0 100644 --- a/ndb/src/ndbapi/NdbApiSignal.cpp +++ b/ndb/src/ndbapi/NdbApiSignal.cpp @@ -62,6 +62,25 @@ NdbApiSignal::NdbApiSignal(BlockReference ref) theNextSignal = 0; } +NdbApiSignal::NdbApiSignal(Ndb* ndb) +{ + BlockReference ref = ndb->theMyRef; + theVerId_signalNumber = 0; // 4 bit ver id - 16 bit gsn + theReceiversBlockNumber = 0; // Only 16 bit blocknum + theSendersBlockRef = refToBlock(ref); + theLength = 0; + theSendersSignalId = 0; + theSignalId = 0; + theTrace = 0; + m_noOfSections = 0; + m_fragmentInfo = 0; + for (int i = 0; i < 25; i++) + theData[i] = 0x13579753; + + setDataPtr(&theData[0]); + theNextSignal = 0; +} + /** * Copy constructor */ diff --git a/ndb/src/ndbapi/NdbApiSignal.hpp b/ndb/src/ndbapi/NdbApiSignal.hpp index 52c3be2256c..9a8326bd666 100644 --- a/ndb/src/ndbapi/NdbApiSignal.hpp +++ b/ndb/src/ndbapi/NdbApiSignal.hpp @@ -46,7 +46,8 @@ class NdbApiSignal : public SignalHeader { public: - NdbApiSignal(BlockReference myRef); + NdbApiSignal(Ndb* ndb); + NdbApiSignal(BlockReference ref); NdbApiSignal(const NdbApiSignal &); NdbApiSignal(const SignalHeader &header) : SignalHeader(header), theNextSignal(0), theRealData(0) {}; diff --git a/ndb/src/ndbapi/NdbBlob.cpp b/ndb/src/ndbapi/NdbBlob.cpp index f72361b86ac..c5692d79e83 100644 --- a/ndb/src/ndbapi/NdbBlob.cpp +++ b/ndb/src/ndbapi/NdbBlob.cpp @@ -137,7 +137,7 @@ NdbBlob::getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnIm // initialization -NdbBlob::NdbBlob() +NdbBlob::NdbBlob(Ndb*) { init(); } 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/NdbImpl.hpp b/ndb/src/ndbapi/NdbImpl.hpp index 00a8ef19f3a..33aaca8de96 100644 --- a/ndb/src/ndbapi/NdbImpl.hpp +++ b/ndb/src/ndbapi/NdbImpl.hpp @@ -32,6 +32,21 @@ #include "NdbDictionaryImpl.hpp" #include "ObjectMap.hpp" +template <class T> +struct Ndb_free_list_t +{ + Ndb_free_list_t(); + ~Ndb_free_list_t(); + + void fill(Ndb*, Uint32 cnt); + T* seize(Ndb*); + void release(T*); + void clear(); + Uint32 get_sizeof() const { return sizeof(T); } + T * m_free_list; + Uint32 m_alloc_cnt, m_free_cnt; +}; + /** * Private parts of the Ndb object (corresponding to Ndb.hpp in public API) */ @@ -59,6 +74,23 @@ public: NdbWaiter theWaiter; int m_optimized_node_selection; + + /** + * NOTE free lists must be _after_ theNdbObjectIdMap take + * assure that destructors are run in correct order + */ + Ndb_free_list_t<NdbConnection> theConIdleList; + Ndb_free_list_t<NdbOperation> theOpIdleList; + Ndb_free_list_t<NdbIndexScanOperation> theScanOpIdleList; + Ndb_free_list_t<NdbIndexOperation> theIndexOpIdleList; + Ndb_free_list_t<NdbRecAttr> theRecAttrIdleList; + Ndb_free_list_t<NdbApiSignal> theSignalIdleList; + Ndb_free_list_t<NdbLabel> theLabelList; + Ndb_free_list_t<NdbBranch> theBranchList; + Ndb_free_list_t<NdbSubroutine> theSubroutineList; + Ndb_free_list_t<NdbCall> theCallList; + Ndb_free_list_t<NdbBlob> theNdbBlobIdleList; + Ndb_free_list_t<NdbReceiver> theScanList; }; #ifdef VM_TRACE @@ -133,4 +165,91 @@ enum LockMode { Delete }; +template<class T> +inline +Ndb_free_list_t<T>::Ndb_free_list_t() +{ + m_free_list= 0; + m_alloc_cnt= m_free_cnt= 0; +} + +template<class T> +inline +Ndb_free_list_t<T>::~Ndb_free_list_t() +{ + clear(); +} + +template<class T> +inline +void +Ndb_free_list_t<T>::fill(Ndb* ndb, Uint32 cnt) +{ + if (m_free_list == 0) + { + m_free_cnt++; + m_alloc_cnt++; + m_free_list = new T(ndb); + } + while(m_alloc_cnt < cnt) + { + T* obj= new T(ndb); + if(obj == 0) + return; + + obj->next(m_free_list); + m_free_cnt++; + m_alloc_cnt++; + m_free_list = obj; + } +} + +template<class T> +inline +T* +Ndb_free_list_t<T>::seize(Ndb* ndb) +{ + T* tmp = m_free_list; + if (tmp) + { + m_free_list = (T*)tmp->next(); + tmp->next(NULL); + m_free_cnt--; + return tmp; + } + + if((tmp = new T(ndb))) + { + m_alloc_cnt++; + } + + return tmp; +} + +template<class T> +inline +void +Ndb_free_list_t<T>::release(T* obj) +{ + obj->next(m_free_list); + m_free_list = obj; + m_free_cnt++; +} + + +template<class T> +inline +void +Ndb_free_list_t<T>::clear() +{ + T* obj = m_free_list; + while(obj) + { + T* curr = obj; + obj = (T*)obj->next(); + delete curr; + m_alloc_cnt--; + } +} + #endif diff --git a/ndb/src/ndbapi/NdbRecAttr.cpp b/ndb/src/ndbapi/NdbRecAttr.cpp index db83e9c5fcf..f993c652bf9 100644 --- a/ndb/src/ndbapi/NdbRecAttr.cpp +++ b/ndb/src/ndbapi/NdbRecAttr.cpp @@ -33,7 +33,7 @@ Adjust: 971206 UABRONM First version #include "NdbDictionaryImpl.hpp" #include <NdbTCP.h> -NdbRecAttr::NdbRecAttr() +NdbRecAttr::NdbRecAttr(Ndb*) { init(); } @@ -109,7 +109,7 @@ NdbRecAttr::copyout() NdbRecAttr * NdbRecAttr::clone() const { - NdbRecAttr * ret = new NdbRecAttr(); + NdbRecAttr * ret = new NdbRecAttr(0); ret->theAttrId = theAttrId; ret->theNULLind = theNULLind; diff --git a/ndb/src/ndbapi/NdbUtil.cpp b/ndb/src/ndbapi/NdbUtil.cpp index 5c74d251ff9..6019ea675a1 100644 --- a/ndb/src/ndbapi/NdbUtil.cpp +++ b/ndb/src/ndbapi/NdbUtil.cpp @@ -30,8 +30,7 @@ Comment: #include "NdbUtil.hpp" -NdbLabel::NdbLabel() : - theNext(NULL) +NdbLabel::NdbLabel(Ndb*) { } @@ -39,8 +38,7 @@ NdbLabel::~NdbLabel() { } -NdbSubroutine::NdbSubroutine() : - theNext(NULL) +NdbSubroutine::NdbSubroutine(Ndb*) { } @@ -48,9 +46,8 @@ NdbSubroutine::~NdbSubroutine() { } -NdbBranch::NdbBranch() : - theSignal(NULL), - theNext(NULL) +NdbBranch::NdbBranch(Ndb*) : + theSignal(NULL) { } @@ -58,9 +55,8 @@ NdbBranch::~NdbBranch() { } -NdbCall::NdbCall() : - theSignal(NULL), - theNext(NULL) +NdbCall::NdbCall(Ndb*) : + theSignal(NULL) { } diff --git a/ndb/src/ndbapi/NdbUtil.hpp b/ndb/src/ndbapi/NdbUtil.hpp index 80fc15ddd8c..d14ac65ddef 100644 --- a/ndb/src/ndbapi/NdbUtil.hpp +++ b/ndb/src/ndbapi/NdbUtil.hpp @@ -34,41 +34,49 @@ Comment: class NdbApiSignal; class NdbOperation; -class NdbLabel +template<class T> +struct Free_list_element +{ + Free_list_element() { theNext = 0;} + void next(T* obj) { theNext = obj;} + T* next() { return theNext;} + + T* theNext; +}; + +class NdbLabel : public Free_list_element<NdbLabel> { friend class NdbOperation; friend class Ndb; - -private: - NdbLabel(); +public: + NdbLabel(Ndb*); ~NdbLabel(); - NdbLabel* theNext; +private: Uint32 theSubroutine[16]; Uint32 theLabelAddress[16]; Uint32 theLabelNo[16]; }; -class NdbSubroutine +class NdbSubroutine : public Free_list_element<NdbSubroutine> { friend class NdbOperation; friend class Ndb; -private: - NdbSubroutine(); +public: + NdbSubroutine(Ndb*); ~NdbSubroutine(); - NdbSubroutine* theNext; Uint32 theSubroutineAddress[16]; }; -class NdbBranch +class NdbBranch : public Free_list_element<NdbBranch> { friend class NdbOperation; friend class Ndb; -private: - NdbBranch(); +public: + NdbBranch(Ndb*); ~NdbBranch(); NdbApiSignal* theSignal; @@ -76,22 +84,20 @@ private: Uint32 theBranchAddress; Uint32 theBranchLabel; Uint32 theSubroutine; - NdbBranch* theNext; }; -class NdbCall +class NdbCall : public Free_list_element<NdbCall> { friend class NdbOperation; friend class Ndb; -private: - NdbCall(); +public: + NdbCall(Ndb*); ~NdbCall(); NdbApiSignal* theSignal; Uint32 theSignalAddress; Uint32 theSubroutine; - NdbCall* theNext; }; #endif diff --git a/ndb/src/ndbapi/Ndbif.cpp b/ndb/src/ndbapi/Ndbif.cpp index 1caebe436ef..3ebba7e1c4a 100644 --- a/ndb/src/ndbapi/Ndbif.cpp +++ b/ndb/src/ndbapi/Ndbif.cpp @@ -143,15 +143,6 @@ Ndb::init(int aMaxNoOfTransactions) error_handler: ndbout << "error_handler" << endl; releaseTransactionArrays(); - while ( theConIdleList != NULL ) - freeNdbCon(); - while ( theSignalIdleList != NULL ) - freeSignal(); - while (theRecAttrIdleList != NULL) - freeRecAttr(); - while (theOpIdleList != NULL) - freeOperation(); - delete theDictionary; TransporterFacade::instance()->close(theNdbBlockNumber, 0); DBUG_RETURN(-1); diff --git a/ndb/src/ndbapi/Ndbinit.cpp b/ndb/src/ndbapi/Ndbinit.cpp index a11dd842495..59a6a825be4 100644 --- a/ndb/src/ndbapi/Ndbinit.cpp +++ b/ndb/src/ndbapi/Ndbinit.cpp @@ -29,6 +29,10 @@ #include <NdbOut.hpp> #include <NdbSleep.h> #include "ObjectMap.hpp" +#include <NdbIndexScanOperation.hpp> +#include <NdbIndexOperation.hpp> +#include "NdbUtil.hpp" +#include <NdbBlob.hpp> class NdbGlobalEventBufferHandle; NdbGlobalEventBufferHandle *NdbGlobalEventBuffer_init(int); @@ -99,20 +103,8 @@ void Ndb::setup(Ndb_cluster_connection *ndb_cluster_connection, theMaxNoOfTransactions= 0; theMinNoOfEventsToWakeUp= 0; prefixEnd= NULL; - theConIdleList= NULL; - theOpIdleList= NULL; - theScanOpIdleList= NULL; - theIndexOpIdleList= NULL; theTransactionList= NULL; theConnectionArray= NULL; - theRecAttrIdleList= NULL; - theSignalIdleList= NULL; - theLabelList= NULL; - theBranchList= NULL; - theSubroutineList= NULL; - theCallList= NULL; - theScanList= NULL; - theNdbBlobIdleList= NULL; the_last_check_time= 0; theFirstTransId= 0; theRestartGCI= 0; @@ -204,33 +196,6 @@ Ndb::~Ndb() TransporterFacade::instance()->close(theNdbBlockNumber, theFirstTransId); } -// if (theSchemaConToNdbList != NULL) -// closeSchemaTransaction(theSchemaConToNdbList); - while ( theConIdleList != NULL ) - freeNdbCon(); - while (theOpIdleList != NULL) - freeOperation(); - while (theScanOpIdleList != NULL) - freeScanOperation(); - while (theIndexOpIdleList != NULL) - freeIndexOperation(); - while (theLabelList != NULL) - freeNdbLabel(); - while (theBranchList != NULL) - freeNdbBranch(); - while (theSubroutineList != NULL) - freeNdbSubroutine(); - while (theCallList != NULL) - freeNdbCall(); - while (theScanList != NULL) - freeNdbScanRec(); - while (theNdbBlobIdleList != NULL) - freeNdbBlob(); - while (theRecAttrIdleList != NULL) - freeRecAttr(); - while ( theSignalIdleList != NULL ) - freeSignal(); - releaseTransactionArrays(); delete []theConnectionArray; @@ -296,7 +261,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/Ndblist.cpp b/ndb/src/ndbapi/Ndblist.cpp index 5902aa413dc..3001561a73a 100644 --- a/ndb/src/ndbapi/Ndblist.cpp +++ b/ndb/src/ndbapi/Ndblist.cpp @@ -76,25 +76,7 @@ Ndb::checkFailedNode() int Ndb::createConIdleList(int aNrOfCon) { - for (int i = 0; i < aNrOfCon; i++) - { - NdbConnection* tNdbCon = new NdbConnection(this); - if (tNdbCon == NULL) - { - return -1; - } - if (theConIdleList == NULL) - { - theConIdleList = tNdbCon; - theConIdleList->next(NULL); - } else - { - tNdbCon->next(theConIdleList); - theConIdleList = tNdbCon; - } - tNdbCon->Status(NdbConnection::NotConnected); - } - theNoOfAllocatedTransactions = aNrOfCon; + theImpl->theConIdleList.fill(this, aNrOfCon); return aNrOfCon; } @@ -110,19 +92,7 @@ Ndb::createConIdleList(int aNrOfCon) int Ndb::createOpIdleList(int aNrOfOp) { - for (int i = 0; i < aNrOfOp; i++){ - NdbOperation* tOp = new NdbOperation(this); - if ( tOp == NULL ){ - return -1; - } - if (theOpIdleList == NULL){ - theOpIdleList = tOp; - theOpIdleList->next(NULL); - } else{ - tOp->next(theOpIdleList); - theOpIdleList = tOp; - } - } + theImpl->theOpIdleList.fill(this, aNrOfOp); return aNrOfOp; } @@ -136,22 +106,7 @@ Ndb::createOpIdleList(int aNrOfOp) NdbBranch* Ndb::getNdbBranch() { - NdbBranch* tNdbBranch; - if ( theBranchList == NULL ) - { - tNdbBranch = new NdbBranch; - if (tNdbBranch == NULL) - { - return NULL; - } - tNdbBranch->theNext = NULL; - } else - { - tNdbBranch = theBranchList; - theBranchList = tNdbBranch->theNext; - tNdbBranch->theNext = NULL; - } - return tNdbBranch; + return theImpl->theBranchList.seize(this); } /*************************************************************************** @@ -164,22 +119,7 @@ Ndb::getNdbBranch() NdbCall* Ndb::getNdbCall() { - NdbCall* tNdbCall; - if ( theCallList == NULL ) - { - tNdbCall = new NdbCall; - if (tNdbCall == NULL) - { - return NULL; - } - tNdbCall->theNext = NULL; - } else - { - tNdbCall = theCallList; - theCallList = tNdbCall->theNext; - tNdbCall->theNext = NULL; - } - return tNdbCall; + return theImpl->theCallList.seize(this); } /*************************************************************************** @@ -192,25 +132,14 @@ Ndb::getNdbCall() NdbConnection* Ndb::getNdbCon() { - NdbConnection* tNdbCon; - if ( theConIdleList == NULL ) { - if (theNoOfAllocatedTransactions < theMaxNoOfTransactions) { - tNdbCon = new NdbConnection(this); - if (tNdbCon == NULL) { - return NULL; - }//if - theNoOfAllocatedTransactions++; - } else { - ndbout << "theNoOfAllocatedTransactions = " << theNoOfAllocatedTransactions << " theMaxNoOfTransactions = " << theMaxNoOfTransactions << endl; - return NULL; - }//if - tNdbCon->next(NULL); - } else + NdbConnection* tNdbCon = theImpl->theConIdleList.seize(this); + if (unlikely(theImpl->theConIdleList.m_alloc_cnt > theMaxNoOfTransactions)) { - tNdbCon = theConIdleList; - theConIdleList = tNdbCon->next(); - tNdbCon->next(NULL); - } + theImpl->theConIdleList.release(tNdbCon); + ndbout << "theNoOfAllocatedTransactions = " << theNoOfAllocatedTransactions << " theMaxNoOfTransactions = " << theMaxNoOfTransactions << endl; + return NULL; + }//if + tNdbCon->theMagicNumber = 0x37412619; return tNdbCon; } @@ -225,22 +154,7 @@ Ndb::getNdbCon() NdbLabel* Ndb::getNdbLabel() { - NdbLabel* tNdbLabel; - if ( theLabelList == NULL ) - { - tNdbLabel = new NdbLabel; - if (tNdbLabel == NULL) - { - return NULL; - } - tNdbLabel->theNext = NULL; - } else - { - tNdbLabel = theLabelList; - theLabelList = tNdbLabel->theNext; - tNdbLabel->theNext = NULL; - } - return tNdbLabel; + return theImpl->theLabelList.seize(this); } /*************************************************************************** @@ -254,23 +168,7 @@ Ndb::getNdbLabel() NdbReceiver* Ndb::getNdbScanRec() { - NdbReceiver* tNdbScanRec; - if ( theScanList == NULL ) - { - tNdbScanRec = new NdbReceiver(this); - if (tNdbScanRec == NULL) - { - return NULL; - } - tNdbScanRec->next(NULL); - } else - { - tNdbScanRec = theScanList; - theScanList = tNdbScanRec->next(); - tNdbScanRec->next(NULL); - } - - return tNdbScanRec; + return theImpl->theScanList.seize(this); } /*************************************************************************** @@ -283,22 +181,7 @@ Ndb::getNdbScanRec() NdbSubroutine* Ndb::getNdbSubroutine() { - NdbSubroutine* tNdbSubroutine; - if ( theSubroutineList == NULL ) - { - tNdbSubroutine = new NdbSubroutine; - if (tNdbSubroutine == NULL) - { - return NULL; - } - tNdbSubroutine->theNext = NULL; - } else - { - tNdbSubroutine = theSubroutineList; - theSubroutineList = tNdbSubroutine->theNext; - tNdbSubroutine->theNext = NULL; - } - return tNdbSubroutine; + return theImpl->theSubroutineList.seize(this); } /*************************************************************************** @@ -311,18 +194,7 @@ Remark: Get an operation from theOpIdleList and return the object . NdbOperation* Ndb::getOperation() { - NdbOperation* tOp = theOpIdleList; - if (tOp != NULL ) { - NdbOperation* tOpNext = tOp->next(); - tOp->next(NULL); - theOpIdleList = tOpNext; - return tOp; - } else { - tOp = new NdbOperation(this); - if (tOp != NULL) - tOp->next(NULL); - } - return tOp; + return theImpl->theOpIdleList.seize(this); } /*************************************************************************** @@ -335,18 +207,7 @@ Remark: Get an operation from theScanOpIdleList and return the object . NdbIndexScanOperation* Ndb::getScanOperation() { - NdbIndexScanOperation* tOp = theScanOpIdleList; - if (tOp != NULL ) { - NdbIndexScanOperation* tOpNext = (NdbIndexScanOperation*)tOp->next(); - tOp->next(NULL); - theScanOpIdleList = tOpNext; - return tOp; - } else { - tOp = new NdbIndexScanOperation(this); - if (tOp != NULL) - tOp->next(NULL); - } - return tOp; + return theImpl->theScanOpIdleList.seize(this); } /*************************************************************************** @@ -359,18 +220,7 @@ Remark: Get an operation from theIndexOpIdleList and return the object . NdbIndexOperation* Ndb::getIndexOperation() { - NdbIndexOperation* tOp = theIndexOpIdleList; - if (tOp != NULL ) { - NdbIndexOperation* tOpNext = (NdbIndexOperation*) tOp->next(); - tOp->next(NULL); - theIndexOpIdleList = tOpNext; - return tOp; - } else { - tOp = new NdbIndexOperation(this); - if (tOp != NULL) - tOp->next(NULL); - } - return tOp; + return theImpl->theIndexOpIdleList.seize(this); } /*************************************************************************** @@ -382,21 +232,14 @@ Return Value: Return a reference to a receive attribute object. NdbRecAttr* Ndb::getRecAttr() { - NdbRecAttr* tRecAttr; - tRecAttr = theRecAttrIdleList; - if (tRecAttr != NULL) { - NdbRecAttr* tRecAttrNext = tRecAttr->next(); + NdbRecAttr* tRecAttr = theImpl->theRecAttrIdleList.seize(this); + if (tRecAttr != NULL) + { tRecAttr->init(); - theRecAttrIdleList = tRecAttrNext; return tRecAttr; - } else { - tRecAttr = new NdbRecAttr; - if (tRecAttr == NULL) - return NULL; - tRecAttr->next(NULL); - }//if - tRecAttr->init(); - return tRecAttr; + } + + return NULL; } /*************************************************************************** @@ -408,34 +251,16 @@ Return Value: Return a reference to a signal object. NdbApiSignal* Ndb::getSignal() { - NdbApiSignal* tSignal = theSignalIdleList; - if (tSignal != NULL){ - NdbApiSignal* tSignalNext = tSignal->next(); - tSignal->next(NULL); - theSignalIdleList = tSignalNext; - } else { - tSignal = new NdbApiSignal(theMyRef); -#ifdef POORMANSPURIFY - cnewSignals++; -#endif - if (tSignal != NULL) - tSignal->next(NULL); - } -#ifdef POORMANSPURIFY - cgetSignals++; -#endif - return tSignal; + return theImpl->theSignalIdleList.seize(this); } NdbBlob* Ndb::getNdbBlob() { - NdbBlob* tBlob = theNdbBlobIdleList; - if (tBlob != NULL) { - theNdbBlobIdleList = tBlob->theNext; + NdbBlob* tBlob = theImpl->theNdbBlobIdleList.seize(this); + if(tBlob) + { tBlob->init(); - } else { - tBlob = new NdbBlob; } return tBlob; } @@ -449,8 +274,7 @@ Remark: Add a NdbBranch object into the Branch idlelist. void Ndb::releaseNdbBranch(NdbBranch* aNdbBranch) { - aNdbBranch->theNext = theBranchList; - theBranchList = aNdbBranch; + theImpl->theBranchList.release(aNdbBranch); } /*************************************************************************** @@ -462,8 +286,7 @@ Remark: Add a NdbBranch object into the Branch idlelist. void Ndb::releaseNdbCall(NdbCall* aNdbCall) { - aNdbCall->theNext = theCallList; - theCallList = aNdbCall; + theImpl->theCallList.release(aNdbCall); } /*************************************************************************** @@ -475,9 +298,8 @@ Remark: Add a Connection object into the signal idlelist. void Ndb::releaseNdbCon(NdbConnection* aNdbCon) { - aNdbCon->next(theConIdleList); aNdbCon->theMagicNumber = 0xFE11DD; - theConIdleList = aNdbCon; + theImpl->theConIdleList.release(aNdbCon); } /*************************************************************************** @@ -489,8 +311,7 @@ Remark: Add a NdbLabel object into the Label idlelist. void Ndb::releaseNdbLabel(NdbLabel* aNdbLabel) { - aNdbLabel->theNext = theLabelList; - theLabelList = aNdbLabel; + theImpl->theLabelList.release(aNdbLabel); } /*************************************************************************** @@ -502,8 +323,7 @@ Remark: Add a NdbScanReceiver object into the Scan idlelist. void Ndb::releaseNdbScanRec(NdbReceiver* aNdbScanRec) { - aNdbScanRec->next(theScanList); - theScanList = aNdbScanRec; + theImpl->theScanList.release(aNdbScanRec); } /*************************************************************************** @@ -515,8 +335,7 @@ Remark: Add a NdbSubroutine object into theSubroutine idlelist. void Ndb::releaseNdbSubroutine(NdbSubroutine* aNdbSubroutine) { - aNdbSubroutine->theNext = theSubroutineList; - theSubroutineList = aNdbSubroutine; + theImpl->theSubroutineList.release(aNdbSubroutine); } /*************************************************************************** @@ -529,16 +348,14 @@ void Ndb::releaseOperation(NdbOperation* anOperation) { if(anOperation->m_tcReqGSN == GSN_TCKEYREQ){ - anOperation->next(theOpIdleList); anOperation->theNdbCon = NULL; anOperation->theMagicNumber = 0xFE11D0; - theOpIdleList = anOperation; + theImpl->theOpIdleList.release(anOperation); } else { assert(anOperation->m_tcReqGSN == GSN_TCINDXREQ); - anOperation->next(theIndexOpIdleList); anOperation->theNdbCon = NULL; anOperation->theMagicNumber = 0xFE11D1; - theIndexOpIdleList = (NdbIndexOperation*)anOperation; + theImpl->theIndexOpIdleList.release((NdbIndexOperation*)anOperation); } } @@ -551,10 +368,9 @@ Remark: Add a NdbScanOperation object into the signal idlelist. void Ndb::releaseScanOperation(NdbIndexScanOperation* aScanOperation) { - aScanOperation->next(theScanOpIdleList); aScanOperation->theNdbCon = NULL; aScanOperation->theMagicNumber = 0xFE11D2; - theScanOpIdleList = aScanOperation; + theImpl->theScanOpIdleList.release(aScanOperation); } /*************************************************************************** @@ -567,8 +383,7 @@ void Ndb::releaseRecAttr(NdbRecAttr* aRecAttr) { aRecAttr->release(); - aRecAttr->next(theRecAttrIdleList); - theRecAttrIdleList = aRecAttr; + theImpl->theRecAttrIdleList.release(aRecAttr); } /*************************************************************************** @@ -595,8 +410,7 @@ Ndb::releaseSignal(NdbApiSignal* aSignal) #ifdef POORMANSPURIFY creleaseSignals++; #endif - aSignal->next(theSignalIdleList); - theSignalIdleList = aSignal; + theImpl->theSignalIdleList.release(aSignal); } void @@ -612,163 +426,7 @@ Ndb::releaseSignalsInList(NdbApiSignal** pList){ void Ndb::releaseNdbBlob(NdbBlob* aBlob) { - aBlob->release(); - aBlob->theNext = theNdbBlobIdleList; - theNdbBlobIdleList = aBlob; -} - -/*************************************************************************** -void freeOperation(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeOperation() -{ - NdbOperation* tOp = theOpIdleList; - theOpIdleList = theOpIdleList->next(); - delete tOp; -} - -/*************************************************************************** -void freeScanOperation(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeScanOperation() -{ - NdbIndexScanOperation* tOp = theScanOpIdleList; - theScanOpIdleList = (NdbIndexScanOperation *)tOp->next(); - delete tOp; -} - -/*************************************************************************** -void freeIndexOperation(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeIndexOperation() -{ - NdbIndexOperation* tOp = theIndexOpIdleList; - theIndexOpIdleList = (NdbIndexOperation *) theIndexOpIdleList->next(); - delete tOp; -} - -/*************************************************************************** -void freeNdbBranch(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeNdbBranch() -{ - NdbBranch* tNdbBranch = theBranchList; - theBranchList = theBranchList->theNext; - delete tNdbBranch; -} - -/*************************************************************************** -void freeNdbCall(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeNdbCall() -{ - NdbCall* tNdbCall = theCallList; - theCallList = theCallList->theNext; - delete tNdbCall; -} - -/*************************************************************************** -void freeNdbScanRec(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeNdbScanRec() -{ - NdbReceiver* tNdbScanRec = theScanList; - theScanList = theScanList->next(); - delete tNdbScanRec; -} - -/*************************************************************************** -void freeNdbCon(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeNdbCon() -{ - NdbConnection* tNdbCon = theConIdleList; - theConIdleList = theConIdleList->next(); - delete tNdbCon; -} - -/*************************************************************************** -void freeNdbLabel(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeNdbLabel() -{ - NdbLabel* tNdbLabel = theLabelList; - theLabelList = theLabelList->theNext; - delete tNdbLabel; -} - -/*************************************************************************** -void freeNdbSubroutine(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeNdbSubroutine() -{ - NdbSubroutine* tNdbSubroutine = theSubroutineList; - theSubroutineList = theSubroutineList->theNext; - delete tNdbSubroutine; -} - -/*************************************************************************** -void freeRecAttr(); - -Remark: Always release the first item in the free list -***************************************************************************/ -void -Ndb::freeRecAttr() -{ - NdbRecAttr* tRecAttr = theRecAttrIdleList; - theRecAttrIdleList = theRecAttrIdleList->next(); - delete tRecAttr; -} - -/*************************************************************************** -void freeSignal(); - -Remark: Delete a signal object from the signal idlelist. -***************************************************************************/ -void -Ndb::freeSignal() -{ - NdbApiSignal* tSignal = theSignalIdleList; - theSignalIdleList = tSignal->next(); - delete tSignal; -#ifdef POORMANSPURIFY - cfreeSignals++; -#endif -} - -void -Ndb::freeNdbBlob() -{ - NdbBlob* tBlob = theNdbBlobIdleList; - theNdbBlobIdleList = tBlob->theNext; - delete tBlob; + theImpl->theNdbBlobIdleList.release(aBlob); } /**************************************************************************** @@ -823,3 +481,102 @@ Ndb::releaseConnectToNdb(NdbConnection* a_con) DBUG_VOID_RETURN; } +template<class T> +static +Ndb::Free_list_usage* +update(Ndb::Free_list_usage* curr, + Ndb_free_list_t<T> & list, + const char * name) +{ + curr->m_name = name; + curr->m_created = list.m_alloc_cnt; + curr->m_free = list.m_free_cnt; + curr->m_sizeof = sizeof(T); + return curr; +} + +Ndb::Free_list_usage* +Ndb::get_free_list_usage(Ndb::Free_list_usage* curr) +{ + if (curr == 0) + { + return 0; + } + + if(curr->m_name == 0) + { + update(curr, theImpl->theConIdleList, "NdbTransaction"); + } + else if(!strcmp(curr->m_name, "NdbTransaction")) + { + update(curr, theImpl->theOpIdleList, "NdbOperation"); + } + else if(!strcmp(curr->m_name, "NdbOperation")) + { + update(curr, theImpl->theScanOpIdleList, "NdbIndexScanOperation"); + } + else if(!strcmp(curr->m_name, "NdbIndexScanOperation")) + { + update(curr, theImpl->theIndexOpIdleList, "NdbIndexOperation"); + } + else if(!strcmp(curr->m_name, "NdbIndexOperation")) + { + update(curr, theImpl->theRecAttrIdleList, "NdbRecAttr"); + } + else if(!strcmp(curr->m_name, "NdbRecAttr")) + { + update(curr, theImpl->theSignalIdleList, "NdbApiSignal"); + } + else if(!strcmp(curr->m_name, "NdbApiSignal")) + { + update(curr, theImpl->theLabelList, "NdbLabel"); + } + else if(!strcmp(curr->m_name, "NdbLabel")) + { + update(curr, theImpl->theBranchList, "NdbBranch"); + } + else if(!strcmp(curr->m_name, "NdbBranch")) + { + update(curr, theImpl->theSubroutineList, "NdbSubroutine"); + } + else if(!strcmp(curr->m_name, "NdbSubroutine")) + { + update(curr, theImpl->theCallList, "NdbCall"); + } + else if(!strcmp(curr->m_name, "NdbCall")) + { + update(curr, theImpl->theNdbBlobIdleList, "NdbBlob"); + } + else if(!strcmp(curr->m_name, "NdbBlob")) + { + update(curr, theImpl->theScanList, "NdbReceiver"); + } + else if(!strcmp(curr->m_name, "NdbReceiver")) + { + return 0; + } + else + { + update(curr, theImpl->theConIdleList, "NdbTransaction"); + } + + return curr; +} + +#define TI(T) \ + template Ndb::Free_list_usage* \ + update(Ndb::Free_list_usage*, Ndb_free_list_t<T> &, const char * name);\ + template struct Ndb_free_list_t<T> + +TI(NdbBlob); +TI(NdbCall); +TI(NdbLabel); +TI(NdbBranch); +TI(NdbSubroutine); +TI(NdbApiSignal); +TI(NdbRecAttr); +TI(NdbOperation); +TI(NdbReceiver); +TI(NdbConnection); +TI(NdbIndexOperation); +TI(NdbIndexScanOperation); 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..44eb24cd87e 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(); @@ -425,7 +426,7 @@ C##suitname():NDBT_TestSuite(#suitname){ \ pt->addTable(tableName, false); #define NDBT_TESTSUITE_END(suitname) \ - } } ; C##suitname suitname; + } } ; C##suitname suitname // Helper functions for retrieving variables from NDBT_Step #define GETNDB(ps) ((NDBT_NdbApiStep*)ps)->getNdb() 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/bank/BankLoad.cpp b/ndb/test/ndbapi/bank/BankLoad.cpp index 39dc8097115..2cc42240234 100644 --- a/ndb/test/ndbapi/bank/BankLoad.cpp +++ b/ndb/test/ndbapi/bank/BankLoad.cpp @@ -321,7 +321,7 @@ int Bank::loadGl(){ m_ndb.closeTransaction(pTrans); return NDBT_OK; -}; +} int Bank::getBalanceForAccountType(const Uint32 accountType, @@ -460,7 +460,7 @@ int Bank::loadAccountType(){ m_ndb.closeTransaction(pTrans); return NDBT_OK; -}; +} /** * Load ACCOUNT table diff --git a/ndb/test/ndbapi/testOIBasic.cpp b/ndb/test/ndbapi/testOIBasic.cpp index 9f8da850ff4..30a76da306a 100644 --- a/ndb/test/ndbapi/testOIBasic.cpp +++ b/ndb/test/ndbapi/testOIBasic.cpp @@ -2187,7 +2187,7 @@ pkinsert(Par par) } con.closeTransaction(); return 0; -}; +} static int pkupdate(Par par) @@ -2250,7 +2250,7 @@ pkupdate(Par par) } con.closeTransaction(); return 0; -}; +} static int pkdelete(Par par) @@ -2306,7 +2306,7 @@ pkdelete(Par par) } con.closeTransaction(); return 0; -}; +} static int pkread(Par par) 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/HugoCalculator.cpp b/ndb/test/src/HugoCalculator.cpp index 62c35c54a7a..86ff76831d7 100644 --- a/ndb/test/src/HugoCalculator.cpp +++ b/ndb/test/src/HugoCalculator.cpp @@ -51,7 +51,7 @@ HugoCalculator::HugoCalculator(const NdbDictionary::Table& tab) : m_tab(tab) { #endif // Check that idCol is not conflicting with updatesCol assert(m_idCol != m_updatesCol && m_idCol != -1 && m_updatesCol != -1); -}; +} Int32 HugoCalculator::calcValue(int record, @@ -73,7 +73,7 @@ HugoCalculator::calcValue(int record, else val = record + attrib + updates; return val; -}; +} #if 0 HugoCalculator::U_Int32 calcValue(int record, int attrib, int updates) const; HugoCalculator::U_Int64 calcValue(int record, int attrib, int updates) const; @@ -123,7 +123,7 @@ HugoCalculator::calcValue(int record, buf[len] = 0; } return buf; -}; +} int HugoCalculator::verifyRowValues(NDBT_ResultRow* const pRow) const{ diff --git a/ndb/test/src/NDBT_Test.cpp b/ndb/test/src/NDBT_Test.cpp index 600a5443f40..42bae193b35 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); @@ -615,7 +624,7 @@ int NDBT_TestCase::execute(NDBT_Context* ctx){ << endl; } return res; -}; +} void NDBT_TestCase::startTimer(NDBT_Context* ctx){ diff --git a/ndb/test/src/NdbBackup.cpp b/ndb/test/src/NdbBackup.cpp index 28724323bd7..9f65fe6b3bc 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; @@ -342,7 +345,7 @@ NdbBackup::NF(NdbRestarter& _restarter, int *NFDuringBackup_codes, const int sz, } return NDBT_OK; -}; +} int FailS_codes[] = { diff --git a/ndb/test/src/NdbRestarts.cpp b/ndb/test/src/NdbRestarts.cpp index 607e48c4126..c0f31af84ce 100644 --- a/ndb/test/src/NdbRestarts.cpp +++ b/ndb/test/src/NdbRestarts.cpp @@ -213,7 +213,7 @@ NdbRestarts::NdbRestart::NdbRestart(const char* _name, m_restartFunc = _func; m_numRequiredNodes = _requiredNodes; // m_arg1 = arg1; -}; +} int NdbRestarts::getNumRestarts(){ @@ -367,7 +367,7 @@ int restartRandomNodeGraceful(NdbRestarter& _restarter, "Could not restart node "<<nodeId); return NDBT_OK; -}; +} int restartRandomNodeAbort(NdbRestarter& _restarter, const NdbRestarts::NdbRestart* _restart){ @@ -382,7 +382,7 @@ int restartRandomNodeAbort(NdbRestarter& _restarter, "Could not restart node "<<nodeId); return NDBT_OK; -}; +} int restartRandomNodeError(NdbRestarter& _restarter, const NdbRestarts::NdbRestart* _restart){ @@ -397,7 +397,7 @@ int restartRandomNodeError(NdbRestarter& _restarter, "Could not restart node "<<nodeId); return NDBT_OK; -}; +} int restartMasterNodeError(NdbRestarter& _restarter, const NdbRestarts::NdbRestart* _restart){ @@ -410,7 +410,7 @@ int restartMasterNodeError(NdbRestarter& _restarter, "Could not restart node "<<nodeId); return NDBT_OK; -}; +} int restartRandomNodeInitial(NdbRestarter& _restarter, const NdbRestarts::NdbRestart* _restart){ @@ -425,7 +425,7 @@ int restartRandomNodeInitial(NdbRestarter& _restarter, "Could not restart node "<<nodeId); return NDBT_OK; -}; +} int twoNodeFailure(NdbRestarter& _restarter, const NdbRestarts::NdbRestart* _restart){ @@ -453,7 +453,7 @@ int twoNodeFailure(NdbRestarter& _restarter, "Could not restart node "<< nodeId); return NDBT_OK; -}; +} int twoMasterNodeFailure(NdbRestarter& _restarter, const NdbRestarts::NdbRestart* _restart){ @@ -478,7 +478,7 @@ int twoMasterNodeFailure(NdbRestarter& _restarter, "Could not restart node "<< nodeId); return NDBT_OK; -}; +} int get50PercentOfNodes(NdbRestarter& restarter, int * _nodes){ @@ -519,7 +519,7 @@ int fiftyPercentFail(NdbRestarter& _restarter, "Could not start all nodes"); return NDBT_OK; -}; +} int restartAllNodesGracfeul(NdbRestarter& _restarter, @@ -533,7 +533,7 @@ int restartAllNodesGracfeul(NdbRestarter& _restarter, return NDBT_OK; -}; +} int restartAllNodesAbort(NdbRestarter& _restarter, const NdbRestarts::NdbRestart* _restart){ @@ -545,7 +545,7 @@ int restartAllNodesAbort(NdbRestarter& _restarter, "Could not restart all nodes"); return NDBT_OK; -}; +} int restartAllNodesError9999(NdbRestarter& _restarter, const NdbRestarts::NdbRestart* _restart){ @@ -557,7 +557,7 @@ int restartAllNodesError9999(NdbRestarter& _restarter, "Could not restart all nodes "); return NDBT_OK; -}; +} int fiftyPercentStopAndWait(NdbRestarter& _restarter, const NdbRestarts::NdbRestart* _restart){ @@ -590,7 +590,7 @@ int fiftyPercentStopAndWait(NdbRestarter& _restarter, g_info << _restart->m_name << endl; return NDBT_OK; -}; +} int NFDuringNR_codes[] = { @@ -713,7 +713,7 @@ int restartNFDuringNR(NdbRestarter& _restarter, } return NDBT_OK; -}; +} int NRDuringLCP_Master_codes[] = { @@ -864,7 +864,7 @@ int stopOnError(NdbRestarter& _restarter, } while (false); return NDBT_OK; -}; +} int getRandomNodeId(NdbRestarter& _restarter) { myRandom48Init(NdbTick_CurrentMillisecond()); 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/restore/Restore.cpp b/ndb/tools/restore/Restore.cpp index 26bc08c63a9..79df49c6f26 100644 --- a/ndb/tools/restore/Restore.cpp +++ b/ndb/tools/restore/Restore.cpp @@ -869,7 +869,7 @@ operator<<(NdbOut& ndbout, const AttributeS& attr){ return ndbout; } - NdbRecAttr tmprec; + NdbRecAttr tmprec(0); tmprec.setup(desc.m_column, (char *)data.void_value); ndbout << tmprec; diff --git a/scripts/mysql_config.sh b/scripts/mysql_config.sh index 16e50c044ca..15b45391ef8 100644 --- a/scripts/mysql_config.sh +++ b/scripts/mysql_config.sh @@ -105,9 +105,12 @@ embedded_libs="$ldflags -L$pkglibdir -lmysqld @LIBS@ @WRAPLIBS@ @innodb_system_l embedded_libs=`echo "$embedded_libs" | sed -e 's; \+; ;g' | sed -e 's;^ *;;' | sed -e 's; *\$;;'` # Remove some options that a client doesn't have to care about +# FIXME until we have a --cxxflags, we need to remove -Xa +# and -xstrconst to make --cflags usable for Sun Forte C++ for remove in DDBUG_OFF DSAFEMALLOC USAFEMALLOC DSAFE_MUTEX \ DPEDANTIC_SAFEMALLOC DUNIV_MUST_NOT_INLINE DFORCE_INIT_OF_VARS \ - DEXTRA_DEBUG DHAVE_purify 'O[0-9]' 'W[-A-Za-z]*' + DEXTRA_DEBUG DHAVE_purify 'O[0-9]' 'W[-A-Za-z]*' \ + Xa xstrconst do # The first option we might strip will always have a space before it because # we set -I$pkgincludedir as the first option @@ -120,13 +123,13 @@ usage () { Usage: $0 [OPTIONS] Options: --cflags [$cflags] - --include [$include] + --include [$include] --libs [$libs] --libs_r [$libs_r] --socket [$socket] --port [$port] --version [$version] - --libmysqld-libs [$embedded_libs] + --libmysqld-libs [$embedded_libs] EOF exit 1 } @@ -136,13 +139,13 @@ if test $# -le 0; then usage; fi while test $# -gt 0; do case $1 in --cflags) echo "$cflags" ;; - --include) echo "$include" ;; + --include) echo "$include" ;; --libs) echo "$libs" ;; --libs_r) echo "$libs_r" ;; --socket) echo "$socket" ;; --port) echo "$port" ;; --version) echo "$version" ;; - --embedded-libs | --embedded | --libmysqld-libs) echo "$embedded_libs" ;; + --embedded-libs | --embedded | --libmysqld-libs) echo "$embedded_libs" ;; *) usage ;; esac 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/field_conv.cc b/sql/field_conv.cc index 7998dd6d5f8..d61b3735c91 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -599,6 +599,9 @@ void field_conv(Field *to,Field *from) !(to->flags & UNSIGNED_FLAG && !(from->flags & UNSIGNED_FLAG)) && to->real_type() != FIELD_TYPE_ENUM && to->real_type() != FIELD_TYPE_SET && + (to->real_type() != FIELD_TYPE_DECIMAL || + (to->field_length == from->field_length && + (((Field_num*) to)->dec == ((Field_num*) from)->dec))) && from->charset() == to->charset() && to->table->db_low_byte_first == from->table->db_low_byte_first) { // Identical fields 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/ha_myisam.cc b/sql/ha_myisam.cc index d8608c6a599..87529cc8713 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -39,6 +39,12 @@ const char *myisam_recover_names[] = TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"", myisam_recover_names, NULL}; +const char *myisam_stats_method_names[] = {"nulls_unequal", "nulls_equal", + NullS}; +TYPELIB myisam_stats_method_typelib= { + array_elements(myisam_stats_method_names) - 1, "", + myisam_stats_method_names, NULL}; + /***************************************************************************** ** MyISAM tables @@ -278,6 +284,7 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) param.db_name = table->table_cache_key; param.table_name = table->table_name; param.testflag = check_opt->flags | T_CHECK | T_SILENT; + param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method; if (!(table->db_stat & HA_READ_ONLY)) param.testflag|= T_STATISTICS; @@ -367,6 +374,7 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt) param.testflag=(T_FAST | T_CHECK | T_SILENT | T_STATISTICS | T_DONT_CHECK_CHECKSUM); param.using_global_keycache = 1; + param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method; if (!(share->state.changed & STATE_NOT_ANALYZED)) return HA_ADMIN_ALREADY_DONE; @@ -920,6 +928,7 @@ int ha_myisam::enable_indexes(uint mode) T_CREATE_MISSING_KEYS); param.myf_rw&= ~MY_WAIT_IF_FULL; param.sort_buffer_length= thd->variables.myisam_sort_buff_size; + param.stats_method= (enum_mi_stats_method)thd->variables.myisam_stats_method; param.tmpdir=&mysql_tmpdir_list; if ((error= (repair(thd,param,0) != HA_ADMIN_OK)) && param.retry_repair) { diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index d1de0bd100e..c478e565220 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -598,8 +598,8 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field, blob_ptr= (char*)""; } - DBUG_PRINT("value", ("set blob ptr=%x len=%u", - (unsigned)blob_ptr, blob_len)); + DBUG_PRINT("value", ("set blob ptr=%p len=%u", + blob_ptr, blob_len)); DBUG_DUMP("value", (char*)blob_ptr, min(blob_len, 26)); if (set_blob_value) @@ -5096,4 +5096,50 @@ int ha_ndbcluster::write_ndb_file() DBUG_RETURN(error); } +int +ndbcluster_show_status(THD* thd) +{ + Protocol *protocol= thd->protocol; + + DBUG_ENTER("ndbcluster_show_status"); + + if (have_ndbcluster != SHOW_OPTION_YES) + { + my_message(ER_NOT_SUPPORTED_YET, + "Cannot call SHOW NDBCLUSTER STATUS because skip-ndbcluster is defined", + MYF(0)); + DBUG_RETURN(TRUE); + } + + List<Item> field_list; + field_list.push_back(new Item_empty_string("free_list", 255)); + field_list.push_back(new Item_return_int("created", 10,MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("free", 10,MYSQL_TYPE_LONG)); + field_list.push_back(new Item_return_int("sizeof", 10,MYSQL_TYPE_LONG)); + + if (protocol->send_fields(&field_list, 1)) + DBUG_RETURN(TRUE); + + if (thd->transaction.thd_ndb && + ((Thd_ndb*)thd->transaction.thd_ndb)->ndb) + { + Ndb* ndb= ((Thd_ndb*)thd->transaction.thd_ndb)->ndb; + Ndb::Free_list_usage tmp; tmp.m_name= 0; + while (ndb->get_free_list_usage(&tmp)) + { + protocol->prepare_for_resend(); + + protocol->store(tmp.m_name, &my_charset_bin); + protocol->store((uint)tmp.m_created); + protocol->store((uint)tmp.m_free); + protocol->store((uint)tmp.m_sizeof); + if (protocol->write()) + DBUG_RETURN(TRUE); + } + } + send_eof(thd); + + DBUG_RETURN(FALSE); +} + #endif /* HAVE_NDBCLUSTER_DB */ diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 4b3a30fb9b9..90d5d59cabe 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -279,3 +279,5 @@ int ndbcluster_table_exists_in_engine(THD* thd, int ndbcluster_drop_database(const char* path); void ndbcluster_print_error(int error, const NdbOperation *error_op); + +int ndbcluster_show_status(THD*); diff --git a/sql/handler.h b/sql/handler.h index b69eec3edd5..d4bb19dd7b2 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -522,6 +522,7 @@ public: extern struct show_table_type_st sys_table_types[]; extern const char *ha_row_type[]; extern TYPELIB tx_isolation_typelib; +extern TYPELIB myisam_stats_method_typelib; /* Wrapper functions */ #define ha_commit_stmt(thd) (ha_commit_trans((thd), &((thd)->transaction.stmt))) 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.h b/sql/item.h index e683cda5786..b1aed733101 100644 --- a/sql/item.h +++ b/sql/item.h @@ -842,6 +842,7 @@ public: String *val_str(String*) { DBUG_ASSERT(fixed == 1); return &str_value; } int save_in_field(Field *field, bool no_conversions); enum Item_result result_type () const { return STRING_RESULT; } + enum Item_result cast_to_int_type() const { return INT_RESULT; } enum_field_types field_type() const { return MYSQL_TYPE_STRING; } // to prevent drop fixed flag (no need parent cleanup call) void cleanup() {} 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_sum.cc b/sql/item_sum.cc index 000dcdb4997..43468adea1a 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -552,8 +552,8 @@ void Item_sum_hybrid::cleanup() void Item_sum_hybrid::no_rows_in_result() { - Item_sum::no_rows_in_result(); was_values= FALSE; + clear(); } @@ -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 0d889aaf0b1..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)) @@ -464,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); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 8db4b27169a..1b931b25647 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -369,6 +369,7 @@ char *mysqld_unix_port, *opt_mysql_tmpdir; char *my_bind_addr_str; const char **errmesg; /* Error messages */ const char *myisam_recover_options_str="OFF"; +const char *myisam_stats_method_str="nulls_unequal"; const char *sql_mode_str="OFF"; /* name of reference on left espression in rewritten IN subquery */ const char *in_left_expr_name= "<left expr>"; @@ -4169,6 +4170,7 @@ enum options_mysqld OPT_MAX_ERROR_COUNT, OPT_MYISAM_DATA_POINTER_SIZE, OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE, + OPT_MYISAM_STATS_METHOD, OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT, OPT_NET_READ_TIMEOUT, OPT_NET_WRITE_TIMEOUT, OPT_OPEN_FILES_LIMIT, @@ -5208,6 +5210,11 @@ The minimum value for this variable is 4096.", (gptr*) &global_system_variables.myisam_sort_buff_size, (gptr*) &max_system_variables.myisam_sort_buff_size, 0, GET_ULONG, REQUIRED_ARG, 8192*1024, 4, ~0L, 0, 1, 0}, + {"myisam_stats_method", OPT_MYISAM_STATS_METHOD, + "Specifies how MyISAM index statistics collection code should threat NULLs. " + "Possible values of name are \"nulls_unequal\" (default behavior for 4.1/5.0), and \"nulls_equal\" (emulate 4.0 behavior).", + (gptr*) &myisam_stats_method_str, (gptr*) &myisam_stats_method_str, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"net_buffer_length", OPT_NET_BUFFER_LENGTH, "Buffer length for TCP/IP and socket communication.", (gptr*) &global_system_variables.net_buffer_length, @@ -5495,6 +5502,7 @@ struct show_var_st status_vars[]= { {"Com_show_keys", (char*) (com_stat+(uint) SQLCOM_SHOW_KEYS),SHOW_LONG}, {"Com_show_logs", (char*) (com_stat+(uint) SQLCOM_SHOW_LOGS),SHOW_LONG}, {"Com_show_master_status", (char*) (com_stat+(uint) SQLCOM_SHOW_MASTER_STAT),SHOW_LONG}, + {"Com_show_ndb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_NDBCLUSTER_STATUS),SHOW_LONG}, {"Com_show_new_master", (char*) (com_stat+(uint) SQLCOM_SHOW_NEW_MASTER),SHOW_LONG}, {"Com_show_open_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_OPEN_TABLES),SHOW_LONG}, {"Com_show_privileges", (char*) (com_stat+(uint) SQLCOM_SHOW_PRIVILEGES),SHOW_LONG}, @@ -5544,13 +5552,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}, @@ -5759,6 +5767,7 @@ static void mysql_init_variables(void) query_id= thread_id= 1L; strmov(server_version, MYSQL_SERVER_VERSION); myisam_recover_options_str= sql_mode_str= "OFF"; + myisam_stats_method_str= "nulls_unequal"; my_bind_addr = htonl(INADDR_ANY); threads.empty(); thread_cache.empty(); @@ -5807,6 +5816,12 @@ static void mysql_init_variables(void) global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; global_system_variables.old_passwords= 0; + + /* + Default behavior for 4.1 and 5.0 is to treat NULL values as unequal + when collecting index statistics for MyISAM tables. + */ + global_system_variables.myisam_stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL; /* Variables that depends on compile options */ #ifndef DBUG_OFF @@ -6388,6 +6403,20 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), ha_open_options|=HA_OPEN_ABORT_IF_CRASHED; break; } + case OPT_MYISAM_STATS_METHOD: + { + myisam_stats_method_str= argument; + int method; + if ((method=find_type(argument, &myisam_stats_method_typelib, 2)) <= 0) + { + fprintf(stderr, "Invalid value of myisam_stats_method: %s.\n", argument); + exit(1); + } + global_system_variables.myisam_stats_method= + test(method-1)? MI_STATS_METHOD_NULLS_EQUAL : + MI_STATS_METHOD_NULLS_NOT_EQUAL; + break; + } case OPT_SQL_MODE: { sql_mode_str= argument; 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..cfb5b3695a3 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -59,8 +59,8 @@ static int maxmin_in_range(bool max_fl, Field* field, COND *cond); SYNOPSIS opt_sum_query() - tables Tables in query - all_fields All fields to be returned + tables Tables in query + all_fields All fields to be returned conds WHERE clause NOTE: @@ -80,6 +80,8 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) List_iterator_fast<Item> it(all_fields); int const_result= 1; bool recalc_const_item= 0; + longlong count= 1; + bool is_exact_count= TRUE; table_map removed_tables= 0, outer_tables= 0, used_tables= 0; table_map where_tables= 0; Item *item; @@ -88,9 +90,13 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) if (conds) where_tables= conds->used_tables(); - /* Don't replace expression on a table that is part of an outer join */ + /* + Analyze outer join dependencies, and, if possible, compute the number + of returned rows. + */ for (TABLE_LIST *tl=tables; tl ; tl= tl->next) { + /* Don't replace expression on a table that is part of an outer join */ if (tl->on_expr) { outer_tables|= tl->table->map; @@ -106,11 +112,27 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) } else used_tables|= tl->table->map; + + /* + If the storage manager of 'tl' gives exact row count, compute the total + number of rows. If there are no outer table dependencies, this count + may be used as the real count. + */ + if (tl->table->file->table_flags() & HA_NOT_EXACT_COUNT) + { + is_exact_count= FALSE; + count= 1; // ensure count != 0 + } + else + { + tl->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); + count*= tl->table->file->records; + } } /* - Iterate through item is select part and replace COUNT(), MIN() and MAX() - with constants (if possible) + Iterate through all items in the SELECT clause and replace + COUNT(), MIN() and MAX() with constants (if possible). */ while ((item= it++)) @@ -122,28 +144,14 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) case Item_sum::COUNT_FUNC: /* If the expr in count(expr) can never be null we can change this - to the number of rows in the tables + to the number of rows in the tables if this number is exact and + there are no outer joins. */ - if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null) + if (!conds && !((Item_sum_count*) item)->args[0]->maybe_null && + !outer_tables && is_exact_count) { - longlong count= 1; - TABLE_LIST *table; - for (table=tables ; table ; table=table->next) - { - if (outer_tables || (table->table->file->table_flags() & - HA_NOT_EXACT_COUNT)) - { - const_result= 0; // Can't optimize left join - break; - } - tables->table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); - count*= table->table->file->records; - } - if (!table) - { - ((Item_sum_count*) item)->make_const(count); - recalc_const_item= 1; - } + ((Item_sum_count*) item)->make_const(count); + recalc_const_item= 1; } else const_result= 0; @@ -210,12 +218,27 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) } removed_tables|= table->map; } - else if (!expr->const_item()) // This is VERY seldom false + else if (!expr->const_item() || !is_exact_count) { + /* + The optimization is not applicable in both cases: + (a) 'expr' is a non-constant expression. Then we can't + replace 'expr' by a constant. + (b) 'expr' is a costant. According to ANSI, MIN/MAX must return + NULL if the query does not return any rows. Thus, if we are not + able to determine if the query returns any rows, we can't apply + the optimization and replace MIN/MAX with a constant. + */ const_result= 0; break; } - ((Item_sum_min*) item_sum)->reset(); + if (!count) + { + /* If count == 0, then we know that is_exact_count == TRUE. */ + ((Item_sum_min*) item_sum)->clear(); /* Set to NULL. */ + } + else + ((Item_sum_min*) item_sum)->reset(); /* Set to the constant value. */ ((Item_sum_min*) item_sum)->make_const(); recalc_const_item= 1; break; @@ -282,13 +305,28 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) } removed_tables|= table->map; } - else if (!expr->const_item()) // This is VERY seldom false + else if (!expr->const_item() || !is_exact_count) { + /* + The optimization is not applicable in both cases: + (a) 'expr' is a non-constant expression. Then we can't + replace 'expr' by a constant. + (b) 'expr' is a costant. According to ANSI, MIN/MAX must return + NULL if the query does not return any rows. Thus, if we are not + able to determine if the query returns any rows, we can't apply + the optimization and replace MIN/MAX with a constant. + */ const_result= 0; break; } - ((Item_sum_min*) item_sum)->reset(); - ((Item_sum_min*) item_sum)->make_const(); + if (!count) + { + /* If count != 1, then we know that is_exact_count == TRUE. */ + ((Item_sum_max*) item_sum)->clear(); /* Set to NULL. */ + } + else + ((Item_sum_max*) item_sum)->reset(); /* Set to the constant value. */ + ((Item_sum_max*) item_sum)->make_const(); recalc_const_item= 1; break; } @@ -661,7 +699,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/set_var.cc b/sql/set_var.cc index 94968f664fd..e10bfda62b7 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -256,6 +256,12 @@ sys_var_thd_ulonglong sys_myisam_max_extra_sort_file_size("myisam_max_extra_sort sys_var_thd_ulonglong sys_myisam_max_sort_file_size("myisam_max_sort_file_size", &SV::myisam_max_sort_file_size, fix_myisam_max_sort_file_size, 1); sys_var_thd_ulong sys_myisam_repair_threads("myisam_repair_threads", &SV::myisam_repair_threads); sys_var_thd_ulong sys_myisam_sort_buffer_size("myisam_sort_buffer_size", &SV::myisam_sort_buff_size); + +sys_var_thd_enum sys_myisam_stats_method("myisam_stats_method", + &SV::myisam_stats_method, + &myisam_stats_method_typelib, + NULL); + sys_var_thd_ulong sys_net_buffer_length("net_buffer_length", &SV::net_buffer_length); sys_var_thd_ulong sys_net_read_timeout("net_read_timeout", @@ -574,6 +580,7 @@ sys_var *sys_variables[]= &sys_myisam_max_sort_file_size, &sys_myisam_repair_threads, &sys_myisam_sort_buffer_size, + &sys_myisam_stats_method, &sys_net_buffer_length, &sys_net_read_timeout, &sys_net_retry_count, @@ -810,6 +817,9 @@ struct show_var_st init_vars[]= { {sys_myisam_repair_threads.name, (char*) &sys_myisam_repair_threads, SHOW_SYS}, {sys_myisam_sort_buffer_size.name, (char*) &sys_myisam_sort_buffer_size, SHOW_SYS}, + + {sys_myisam_stats_method.name, (char*) &sys_myisam_stats_method, SHOW_SYS}, + #ifdef __NT__ {"named_pipe", (char*) &opt_enable_named_pipe, SHOW_MY_BOOL}, #endif 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_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_class.h b/sql/sql_class.h index bc651b32d94..41170192892 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -363,6 +363,7 @@ struct system_variables ulong max_insert_delayed_threads; ulong myisam_repair_threads; ulong myisam_sort_buff_size; + ulong myisam_stats_method; ulong net_buffer_length; ulong net_interactive_timeout; ulong net_read_timeout; 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_delete.cc b/sql/sql_delete.cc index 7248adf6993..1dd52a2ba74 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -27,8 +27,8 @@ #include "ha_innodb.h" #include "sql_select.h" -int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order, - ha_rows limit, ulong options) +int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, + SQL_LIST *order, ha_rows limit, ulong options) { int error; TABLE *table; @@ -266,6 +266,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds) select_lex.table_list.first); DBUG_ENTER("mysql_prepare_delete"); + thd->allow_sum_func= 0; if (setup_conds(thd, delete_table_list, conds) || setup_ftfuncs(&thd->lex->select_lex)) DBUG_RETURN(-1); diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 07b5c9d8edf..8d919f12563 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -49,7 +49,7 @@ enum enum_sql_command { SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS, SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_LOGS, SQLCOM_SHOW_STATUS, - SQLCOM_SHOW_INNODB_STATUS, + SQLCOM_SHOW_INNODB_STATUS,SQLCOM_SHOW_NDBCLUSTER_STATUS, SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT, SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS, SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, diff --git a/sql/sql_load.cc b/sql/sql_load.cc index c4f5b1427af..4d09da70ef7 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 */ @@ -438,11 +441,13 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields, { uint length; byte save_chr; + if (field == table->next_number_field) + table->auto_increment_field_not_null= TRUE; if ((length=(uint) (read_info.row_end-pos)) > field->field_length) length=field->field_length; save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc - field->store((char*) pos,length,read_info.read_charset); + field->store((char*) pos,length,read_info.read_charset); pos[length]=save_chr; if ((pos+=length) > read_info.row_end) pos= read_info.row_end; /* Fills rest with space */ @@ -533,6 +538,8 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table, } continue; } + if (field == table->next_number_field) + table->auto_increment_field_not_null= TRUE; field->set_notnull(); read_info.row_end[0]=0; // Safe to change end marker field->store((char*) read_info.row_start,length,read_info.read_charset); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 76d4c5c27dc..5d233fd7be0 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -25,6 +25,10 @@ #include "ha_innodb.h" #endif +#ifdef HAVE_NDBCLUSTER_DB +#include "ha_ndbcluster.h" +#endif + #ifdef HAVE_OPENSSL /* Without SSL the handshake consists of one packet. This packet @@ -59,6 +63,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 +132,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 @@ -2386,6 +2390,13 @@ mysql_execute_command(THD *thd) res = load_master_data(thd); break; #endif /* HAVE_REPLICATION */ +#ifdef HAVE_NDBCLUSTER_DB + case SQLCOM_SHOW_NDBCLUSTER_STATUS: + { + res = ndbcluster_show_status(thd); + break; + } +#endif #ifdef HAVE_INNOBASE_DB case SQLCOM_SHOW_INNODB_STATUS: { @@ -3327,7 +3338,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 @@ -3363,7 +3373,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 @@ -3404,7 +3413,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 @@ -4248,6 +4256,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) { @@ -5570,13 +5612,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..0d9cab6a36b 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) @@ -2140,7 +2140,6 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end, field Field used in comparision eq_func True if we used =, <=> or IS NULL value Value used for comparison with field - Is NULL for BETWEEN and IN usable_tables Tables which can be used for key optimization NOTES @@ -2325,7 +2324,8 @@ add_key_fields(KEY_FIELD **key_fields,uint *and_level, add_key_field(key_fields,*and_level,cond_func, ((Item_field*)(cond_func->key_item()->real_item()))->field, cond_func->argument_count() == 2 && - cond_func->functype() == Item_func::IN_FUNC, + cond_func->functype() == Item_func::IN_FUNC && + !((Item_func_in*)cond_func)->negated, cond_func->arguments()+1, cond_func->argument_count()-1, usable_tables); break; @@ -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_update.cc b/sql/sql_update.cc index 6c12381b4bd..2857bce09ed 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -426,6 +426,7 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list, bzero((char*) &tables,sizeof(tables)); // For ORDER BY tables.table= table; tables.alias= table_list->alias; + thd->allow_sum_func= 0; if (setup_tables(update_table_list) || setup_conds(thd, update_table_list, conds) || diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index be8ead8e157..2ce419086a0 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -644,7 +644,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); NUM_literal %type <item_list> - expr_list udf_expr_list when_list ident_list ident_list_arg + expr_list udf_expr_list udf_sum_expr_list when_list ident_list + ident_list_arg %type <key_type> key_type opt_unique_or_fulltext constraint_key_type @@ -2598,7 +2599,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 +2614,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 +2666,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 +2718,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 +2733,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); } @@ -3115,21 +3138,21 @@ simple_expr: { $$= new Item_func_trim($5,$3); } | TRUNCATE_SYM '(' expr ',' expr ')' { $$= new Item_func_round($3,$5,1); } - | UDA_CHAR_SUM '(' udf_expr_list ')' + | UDA_CHAR_SUM '(' udf_sum_expr_list ')' { if ($3 != NULL) $$ = new Item_sum_udf_str($1, *$3); else $$ = new Item_sum_udf_str($1); } - | UDA_FLOAT_SUM '(' udf_expr_list ')' + | UDA_FLOAT_SUM '(' udf_sum_expr_list ')' { if ($3 != NULL) $$ = new Item_sum_udf_float($1, *$3); else $$ = new Item_sum_udf_float($1); } - | UDA_INT_SUM '(' udf_expr_list ')' + | UDA_INT_SUM '(' udf_sum_expr_list ')' { if ($3 != NULL) $$ = new Item_sum_udf_int($1, *$3); @@ -3267,6 +3290,21 @@ udf_expr_list: /* empty */ { $$= NULL; } | expr_list { $$= $1;}; +udf_sum_expr_list: + { + LEX *lex= Lex; + if (lex->current_select->inc_in_sum_expr()) + { + yyerror(ER(ER_SYNTAX_ERROR)); + YYABORT; + } + } + udf_expr_list + { + Select->in_sum_expr--; + $$= $2; + }; + sum_expr: AVG_SYM '(' in_sum_expr ')' { $$=new Item_sum_avg($3); } @@ -4273,12 +4311,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 {} ; @@ -4511,6 +4547,9 @@ show_engine_param: STATUS_SYM { switch (Lex->create_info.db_type) { + case DB_TYPE_NDBCLUSTER: + Lex->sql_command = SQLCOM_SHOW_NDBCLUSTER_STATUS; + break; case DB_TYPE_INNODB: Lex->sql_command = SQLCOM_SHOW_INNODB_STATUS; break; 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; diff --git a/zlib/ChangeLog b/zlib/ChangeLog index 1af7633d668..7f6869d3235 100644 --- a/zlib/ChangeLog +++ b/zlib/ChangeLog @@ -1,10 +1,96 @@ ChangeLog file for zlib -Changes in port for MySQL (19 July 2004) -- removed contrib, nt, os2, amiga, directories and some other files not used -in MySQL distribution. If you are working on porting MySQL to one of rare -platforms, you might find worth looking at the original zlib distribution -and using appropriate Makefiles/project files from it. + +Changes in 1.2.3 (18 July 2005) +- Apply security vulnerability fixes to contrib/infback9 as well +- Clean up some text files (carriage returns, trailing space) +- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] + +Changes in 1.2.2.4 (11 July 2005) +- Add inflatePrime() function for starting inflation at bit boundary +- Avoid some Visual C warnings in deflate.c +- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit + compile +- Fix some spelling errors in comments [Betts] +- Correct inflateInit2() error return documentation in zlib.h +- Added zran.c example of compressed data random access to examples + directory, shows use of inflatePrime() +- Fix cast for assignments to strm->state in inflate.c and infback.c +- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] +- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] +- Add cast in trees.c t avoid a warning [Oberhumer] +- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] +- Update make_vms.com [Zinser] +- Initialize state->write in inflateReset() since copied in inflate_fast() +- Be more strict on incomplete code sets in inflate_table() and increase + ENOUGH and MAXD -- this repairs a possible security vulnerability for + invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for + discovering the vulnerability and providing test cases. +- Add ia64 support to configure for HP-UX [Smith] +- Add error return to gzread() for format or i/o error [Levin] +- Use malloc.h for OS/2 [Necasek] + +Changes in 1.2.2.3 (27 May 2005) +- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile +- Typecast fread() return values in gzio.c [Vollant] +- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) +- Fix crc check bug in gzread() after gzungetc() [Heiner] +- Add the deflateTune() function to adjust internal compression parameters +- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) +- Remove an incorrect assertion in examples/zpipe.c +- Add C++ wrapper in infback9.h [Donais] +- Fix bug in inflateCopy() when decoding fixed codes +- Note in zlib.h how much deflateSetDictionary() actually uses +- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) +- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] +- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] +- Add gzdirect() function to indicate transparent reads +- Update contrib/minizip [Vollant] +- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] +- Add casts in crc32.c to avoid warnings [Oberhumer] +- Add contrib/masmx64 [Vollant] +- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] + +Changes in 1.2.2.2 (30 December 2004) +- Replace structure assignments in deflate.c and inflate.c with zmemcpy to + avoid implicit memcpy calls (portability for no-library compilation) +- Increase sprintf() buffer size in gzdopen() to allow for large numbers +- Add INFLATE_STRICT to check distances against zlib header +- Improve WinCE errno handling and comments [Chang] +- Remove comment about no gzip header processing in FAQ +- Add Z_FIXED strategy option to deflateInit2() to force fixed trees +- Add updated make_vms.com [Coghlan], update README +- Create a new "examples" directory, move gzappend.c there, add zpipe.c, + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. +- Add FAQ entry and comments in deflate.c on uninitialized memory access +- Add Solaris 9 make options in configure [Gilbert] +- Allow strerror() usage in gzio.c for STDC +- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] +- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] +- Use z_off_t for adler32_combine() and crc32_combine() lengths +- Make adler32() much faster for small len +- Use OS_CODE in deflate() default gzip header + +Changes in 1.2.2.1 (31 October 2004) +- Allow inflateSetDictionary() call for raw inflate +- Fix inflate header crc check bug for file names and comments +- Add deflateSetHeader() and gz_header structure for custom gzip headers +- Add inflateGetheader() to retrieve gzip headers +- Add crc32_combine() and adler32_combine() functions +- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list +- Use zstreamp consistently in zlib.h (inflate_back functions) +- Remove GUNZIP condition from definition of inflate_mode in inflate.h + and in contrib/inflate86/inffast.S [Truta, Anderson] +- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] +- Update projects/README.projects and projects/visualc6 [Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] +- Deprecate Z_ASCII; use Z_TEXT instead [Truta] +- Use a new algorithm for setting strm->data_type in trees.c [Truta] +- Do not define an exit() prototype in zutil.c unless DEBUG defined +- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] +- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() +- Fix Darwin build version identification [Peterson] Changes in 1.2.2 (3 October 2004) - Update zlib.h comments on gzip in-memory processing @@ -454,7 +540,7 @@ Changes in 1.0.7 (20 Jan 1998) Changes in 1.0.6 (19 Jan 1998) - add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) -- Fix a deflate bug occuring only with compression level 0 (thanks to +- Fix a deflate bug occurring only with compression level 0 (thanks to Andy Buckler for finding this one). - In minigzip, pass transparently also the first byte for .Z files. - return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() @@ -148,13 +148,6 @@ The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html format using deflateInit2(). You can also request that inflate decode the gzip format using inflateInit2(). Read zlib.h for more details. - Note that you cannot specify special gzip header contents (e.g. a file - name or modification date), nor will inflate tell you what was in the - gzip header. If you need to customize the header or see what's in it, - you can use the raw deflate and inflate operations and the crc32() - function and roll your own gzip encoding and decoding. Read the gzip - RFC 1952 for details of the header and trailer format. - 21. Is zlib thread-safe? Yes. However any library routines that zlib uses and any application- @@ -295,20 +288,29 @@ The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html were downright silly. So now, we simply make sure that the code always works. -36. Will zlib read the (insert any ancient or arcane format here) compressed +36. Valgrind (or some similar memory access checker) says that deflate is + performing a conditional jump that depends on an uninitialized value. + Isn't that a bug? + + No. That is intentional for performance reasons, and the output of + deflate is not affected. This only started showing up recently since + zlib 1.2.x uses malloc() by default for allocations, whereas earlier + versions used calloc(), which zeros out the allocated memory. + +37. Will zlib read the (insert any ancient or arcane format here) compressed data format? Probably not. Look in the comp.compression FAQ for pointers to various formats and associated software. -37. How can I encrypt/decrypt zip files with zlib? +38. How can I encrypt/decrypt zip files with zlib? zlib doesn't support encryption. The original PKZIP encryption is very weak and can be broken with freely available programs. To get strong encryption, use GnuPG, http://www.gnupg.org/ , which already includes zlib compression. For PKZIP compatible "encryption", look at http://www.info-zip.org/ -38. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? +39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? "gzip" is the gzip format, and "deflate" is the zlib format. They should probably have called the second one "zlib" instead to avoid confusion @@ -324,14 +326,14 @@ The lastest zlib FAQ is at http://www.gzip.org/zlib/zlib_faq.html Bottom line: use the gzip format for HTTP 1.1 encoding. -39. Does zlib support the new "Deflate64" format introduced by PKWare? +40. Does zlib support the new "Deflate64" format introduced by PKWare? No. PKWare has apparently decided to keep that format proprietary, since they have not documented it as they have previous compression formats. In any case, the compression improvements are so modest compared to other more modern approaches, that it's not worth the effort to implement. -40. Can you please sign these lengthy legal documents and fax them back to us +41. Can you please sign these lengthy legal documents and fax them back to us so that we can use your software in our product? No. Go away. Shoo. diff --git a/zlib/README b/zlib/README index df95ae13f54..758cc50020d 100644 --- a/zlib/README +++ b/zlib/README @@ -1,6 +1,6 @@ ZLIB DATA COMPRESSION LIBRARY -zlib 1.2.2 is a general purpose data compression library. All the code is +zlib 1.2.3 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) @@ -16,9 +16,8 @@ minigzip.c. To compile all files and run the test program, follow the instructions given at the top of Makefile. In short "make test; make install" should work for most -machines. For Unix: "./configure; make test; make install" For MSDOS, use one -of the special makefiles such as Makefile.msc. For VMS, use Make_vms.com or -descrip.mms. +machines. For Unix: "./configure; make test; make install". For MSDOS, use one +of the special makefiles such as Makefile.msc. For VMS, use make_vms.com. Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant <info@winimage.com> for the Windows DLL version. The zlib home page is @@ -34,7 +33,7 @@ Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available in http://dogma.net/markn/articles/zlibtool/zlibtool.htm -The changes made in version 1.2.2 are documented in the file ChangeLog. +The changes made in version 1.2.3 are documented in the file ChangeLog. Unsupported third party contributions are provided in directory "contrib". diff --git a/zlib/README.MySQL b/zlib/README.MySQL new file mode 100644 index 00000000000..355dfb62d71 --- /dev/null +++ b/zlib/README.MySQL @@ -0,0 +1,7 @@ +This an incomplete version of the zlib library -- it excludes some of the +platform-specific project files, contributed code, and examples from the +original zlib distribution. You can find the original distribution at + + http://www.gzip.org/zlib/ + or + http://www.zlib.net/ diff --git a/zlib/adler32.c b/zlib/adler32.c index 624a1696eb0..007ba26277c 100644 --- a/zlib/adler32.c +++ b/zlib/adler32.c @@ -1,5 +1,5 @@ /* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2003 Mark Adler + * Copyright (C) 1995-2004 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -12,12 +12,13 @@ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ -#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); +/* use NO_DIVIDE if your processor does not do division in hardware */ #ifdef NO_DIVIDE # define MOD(a) \ do { \ @@ -39,8 +40,17 @@ if (a >= (BASE << 1)) a -= (BASE << 1); \ if (a >= BASE) a -= BASE; \ } while (0) +# define MOD4(a) \ + do { \ + if (a >= (BASE << 4)) a -= (BASE << 4); \ + if (a >= (BASE << 3)) a -= (BASE << 3); \ + if (a >= (BASE << 2)) a -= (BASE << 2); \ + if (a >= (BASE << 1)) a -= (BASE << 1); \ + if (a >= BASE) a -= BASE; \ + } while (0) #else # define MOD(a) a %= BASE +# define MOD4(a) a %= BASE #endif /* ========================================================================= */ @@ -49,26 +59,91 @@ uLong ZEXPORT adler32(adler, buf, len) const Bytef *buf; uInt len; { - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } - if (buf == Z_NULL) return 1L; + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; - while (len > 0) { - k = len < NMAX ? (int)len : NMAX; - len -= k; - while (k >= 16) { + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD4(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; DO16(buf); buf += 16; - k -= 16; } - if (k != 0) do { - s1 += *buf++; - s2 += s1; - } while (--k); - MOD(s1); - MOD(s2); + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); } - return (s2 << 16) | s1; + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* the derivation of this formula is left as an exercise for the reader */ + rem = (unsigned)(len2 % BASE); + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 > BASE) sum1 -= BASE; + if (sum1 > BASE) sum1 -= BASE; + if (sum2 > (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 > BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); } diff --git a/zlib/compress.c b/zlib/compress.c index 24ef0291911..df04f0148e6 100644 --- a/zlib/compress.c +++ b/zlib/compress.c @@ -1,5 +1,5 @@ /* compress.c -- compress a memory buffer - * Copyright (C) 1995-2002 Jean-loup Gailly. + * Copyright (C) 1995-2003 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ diff --git a/zlib/crc32.c b/zlib/crc32.c index b39c7e1253e..f658a9ef55e 100644 --- a/zlib/crc32.c +++ b/zlib/crc32.c @@ -1,12 +1,12 @@ /* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2003 Mark Adler + * Copyright (C) 1995-2005 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing * tables for updating the shift register in one step with three exclusive-ors - * instead of four steps with four exclusive-ors. This results about a factor - * of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. */ /* @(#) $Id$ */ @@ -64,6 +64,11 @@ # define TBLS 1 #endif /* BYFOUR */ +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); + #ifdef DYNAMIC_CRC_TABLE local volatile int crc_table_empty = 1; @@ -72,7 +77,6 @@ local void make_crc_table OF((void)); #ifdef MAKECRCH local void write_table OF((FILE *, const unsigned long FAR *)); #endif /* MAKECRCH */ - /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. @@ -270,7 +274,7 @@ local unsigned long crc32_little(crc, buf, len) len--; } - buf4 = (const u4 FAR *)buf; + buf4 = (const u4 FAR *)(const void FAR *)buf; while (len >= 32) { DOLIT32; len -= 32; @@ -310,7 +314,7 @@ local unsigned long crc32_big(crc, buf, len) len--; } - buf4 = (const u4 FAR *)buf; + buf4 = (const u4 FAR *)(const void FAR *)buf; buf4--; while (len >= 32) { DOBIG32; @@ -331,3 +335,89 @@ local unsigned long crc32_big(crc, buf, len) } #endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case */ + if (len2 == 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320L; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} diff --git a/zlib/deflate.c b/zlib/deflate.c index 0fc53bc1e82..29ce1f64a57 100644 --- a/zlib/deflate.c +++ b/zlib/deflate.c @@ -1,5 +1,5 @@ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2004 Jean-loup Gailly. + * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.2.2 Copyright 1995-2004 Jean-loup Gailly "; + " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -264,7 +264,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, #endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_RLE) { + strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ @@ -274,6 +274,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, s->strm = strm; s->wrap = wrap; + s->gzhead = Z_NULL; s->w_bits = windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; @@ -333,9 +334,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) if (length < MIN_MATCH) return Z_OK; if (length > MAX_DIST(s)) { length = MAX_DIST(s); -#ifndef USE_DICT_HEAD dictionary += dictLength - length; /* use the tail of the dictionary */ -#endif } zmemcpy(s->window, dictionary, length); s->strstart = length; @@ -391,6 +390,17 @@ int ZEXPORT deflateReset (strm) } /* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ int ZEXPORT deflatePrime (strm, bits, value) z_streamp strm; int bits; @@ -420,7 +430,7 @@ int ZEXPORT deflateParams(strm, level, strategy) #else if (level == Z_DEFAULT_COMPRESSION) level = 6; #endif - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_RLE) { + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { return Z_STREAM_ERROR; } func = configuration_table[s->level].func; @@ -440,6 +450,25 @@ int ZEXPORT deflateParams(strm, level, strategy) return err; } +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + /* ========================================================================= * For the default windowBits of 15 and memLevel of 8, this function returns * a close to exact, as well as small, upper bound on the compressed size. @@ -548,20 +577,47 @@ int ZEXPORT deflate (strm, flush) if (s->status == INIT_STATE) { #ifdef GZIP if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); put_byte(s, 31); put_byte(s, 139); put_byte(s, 8); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, 255); - s->status = BUSY_STATE; - strm->adler = crc32(0L, Z_NULL, 0); + if (s->gzhead == NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } } else #endif @@ -592,6 +648,110 @@ int ZEXPORT deflate (strm, flush) strm->adler = adler32(0L, Z_NULL, 0); } } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif /* Flush as much pending output as possible */ if (s->pending != 0) { @@ -704,7 +864,12 @@ int ZEXPORT deflateEnd (strm) if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; status = strm->state->status; - if (status != INIT_STATE && status != BUSY_STATE && + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && status != FINISH_STATE) { return Z_STREAM_ERROR; } @@ -744,12 +909,12 @@ int ZEXPORT deflateCopy (dest, source) ss = source->state; - *dest = *source; + zmemcpy(dest, source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds; - *ds = *ss; + zmemcpy(ds, ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); @@ -838,9 +1003,11 @@ local void lm_init (s) s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0; +#ifndef FASTEST #ifdef ASMV match_init(); /* initialize the asm code */ #endif +#endif } #ifndef FASTEST @@ -909,7 +1076,12 @@ local uInt longest_match(s, cur_match) match = s->window + cur_match; /* Skip to next match if the match length cannot increase - * or if the match length is less than 2: + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. */ #if (defined(UNALIGNED_OK) && MAX_MATCH == 258) /* This code assumes sizeof(unsigned short) == 2. Do not use @@ -1131,6 +1303,7 @@ local void fill_window(s) later. (Using level 0 permanently is not an optimal usage of zlib, so we don't care about this pathological case.) */ + /* %%% avoid this when Z_RLE */ n = s->hash_size; p = &s->head[n]; do { @@ -1309,12 +1482,12 @@ local block_state deflate_fast(s, flush) * of the string with itself at the start of the input file). */ #ifdef FASTEST - if ((s->strategy < Z_HUFFMAN_ONLY) || + if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) || (s->strategy == Z_RLE && s->strstart - hash_head == 1)) { s->match_length = longest_match_fast (s, hash_head); } #else - if (s->strategy < Z_HUFFMAN_ONLY) { + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { s->match_length = longest_match (s, hash_head); } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { s->match_length = longest_match_fast (s, hash_head); @@ -1418,7 +1591,7 @@ local block_state deflate_slow(s, flush) * of window index 0 (in particular we have to avoid a match * of the string with itself at the start of the input file). */ - if (s->strategy < Z_HUFFMAN_ONLY) { + if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) { s->match_length = longest_match (s, hash_head); } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) { s->match_length = longest_match_fast (s, hash_head); @@ -1500,3 +1673,64 @@ local block_state deflate_slow(s, flush) return flush == Z_FINISH ? finish_done : block_done; } #endif /* FASTEST */ + +#if 0 +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt run; /* length of run */ + uInt max; /* maximum length of run */ + uInt prev; /* byte at distance one to match */ + Bytef *scan; /* scan for end of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest encodable run. + */ + if (s->lookahead < MAX_MATCH) { + fill_window(s); + if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + run = 0; + if (s->strstart > 0) { /* if there is a previous byte, that is */ + max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH; + scan = s->window + s->strstart - 1; + prev = *scan++; + do { + if (*scan++ != prev) + break; + } while (++run < max); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (run >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, run); + _tr_tally_dist(s, 1, run - MIN_MATCH, bflush); + s->lookahead -= run; + s->strstart += run; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} +#endif diff --git a/zlib/deflate.h b/zlib/deflate.h index 410681d18a4..05a5ab3a2c1 100644 --- a/zlib/deflate.h +++ b/zlib/deflate.h @@ -1,5 +1,5 @@ /* deflate.h -- internal compression state - * Copyright (C) 1995-2002 Jean-loup Gailly + * Copyright (C) 1995-2004 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -49,6 +49,10 @@ /* All codes must not exceed MAX_BITS bits */ #define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 #define BUSY_STATE 113 #define FINISH_STATE 666 /* Stream status */ @@ -93,8 +97,10 @@ typedef struct internal_state { Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ - int pending; /* nb of bytes in the pending buffer */ + uInt pending; /* nb of bytes in the pending buffer */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ Byte method; /* STORED (for zip only) or DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ diff --git a/zlib/gzio.c b/zlib/gzio.c index 5e71b0ab3ae..7e90f4928fc 100644 --- a/zlib/gzio.c +++ b/zlib/gzio.c @@ -1,5 +1,5 @@ /* gzio.c -- IO on .gz files - * Copyright (C) 1995-2003 Jean-loup Gailly. + * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h * * Compile this file with -DNO_GZCOMPRESS to avoid the compression code. @@ -11,7 +11,7 @@ #include "zutil.h" -#ifdef NO_DEFLATE /* for compatiblity with old definition */ +#ifdef NO_DEFLATE /* for compatibility with old definition */ # define NO_GZCOMPRESS #endif @@ -220,7 +220,7 @@ gzFile ZEXPORT gzdopen (fd, mode) int fd; const char *mode; { - char name[20]; + char name[46]; /* allow for up to 128-bit integers */ if (fd < 0) return (gzFile)Z_NULL; sprintf(name, "<fd:%d>", fd); /* for debugging */ @@ -264,7 +264,7 @@ local int get_byte(s) if (s->z_eof) return EOF; if (s->stream.avail_in == 0) { errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); if (s->stream.avail_in == 0) { s->z_eof = 1; if (ferror(s->file)) s->z_err = Z_ERRNO; @@ -300,7 +300,7 @@ local void check_header(s) if (len < 2) { if (len) s->inbuf[0] = s->stream.next_in[0]; errno = 0; - len = fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); + len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file); if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO; s->stream.avail_in += len; s->stream.next_in = s->inbuf; @@ -415,6 +415,7 @@ int ZEXPORT gzread (file, buf, len) s->stream.avail_out--; s->back = EOF; s->out++; + start++; if (s->last) { s->z_err = Z_STREAM_END; return 1; @@ -436,8 +437,8 @@ int ZEXPORT gzread (file, buf, len) s->stream.avail_in -= n; } if (s->stream.avail_out > 0) { - s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, - s->file); + s->stream.avail_out -= + (uInt)fread(next_out, 1, s->stream.avail_out, s->file); } len -= s->stream.avail_out; s->in += len; @@ -448,17 +449,13 @@ int ZEXPORT gzread (file, buf, len) if (s->stream.avail_in == 0 && !s->z_eof) { errno = 0; - s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file); if (s->stream.avail_in == 0) { s->z_eof = 1; if (ferror(s->file)) { s->z_err = Z_ERRNO; break; } - if (feof(s->file)) { /* avoid error for empty file */ - s->z_err = Z_STREAM_END; - break; - } } s->stream.next_in = s->inbuf; } @@ -492,6 +489,9 @@ int ZEXPORT gzread (file, buf, len) } s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + if (len == s->stream.avail_out && + (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) + return -1; return (int)(len - s->stream.avail_out); } @@ -903,6 +903,18 @@ int ZEXPORT gzeof (file) } /* =========================================================================== + Returns 1 if reading and doing so transparently, otherwise zero. +*/ +int ZEXPORT gzdirect (file) + gzFile file; +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'r') return 0; + return s->transparent; +} + +/* =========================================================================== Outputs a long in LSB order to the given file */ local void putLong (file, x) @@ -941,7 +953,6 @@ local uLong getLong (s) int ZEXPORT gzclose (file) gzFile file; { - int err; gz_stream *s = (gz_stream*)file; if (s == NULL) return Z_STREAM_ERROR; @@ -950,8 +961,8 @@ int ZEXPORT gzclose (file) #ifdef NO_GZCOMPRESS return Z_STREAM_ERROR; #else - err = do_flush (file, Z_FINISH); - if (err != Z_OK) return destroy((gz_stream*)file); + if (do_flush (file, Z_FINISH) != Z_OK) + return destroy((gz_stream*)file); putLong (s->file, s->crc); putLong (s->file, (uLong)(s->in & 0xffffffff)); @@ -960,10 +971,16 @@ int ZEXPORT gzclose (file) return destroy((gz_stream*)file); } +#ifdef STDC +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + /* =========================================================================== - Returns the error message for the last error which occured on the + Returns the error message for the last error which occurred on the given compressed file. errnum is set to zlib error number. If an - error occured in the file system and not in the compression library, + error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. */ diff --git a/zlib/infback.c b/zlib/infback.c index 262f97c73ac..455dbc9ee84 100644 --- a/zlib/infback.c +++ b/zlib/infback.c @@ -1,5 +1,5 @@ /* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2003 Mark Adler + * Copyright (C) 1995-2005 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -26,7 +26,7 @@ local void fixedtables OF((struct inflate_state FAR *state)); window and output buffer that is 2**windowBits bytes. */ int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) -z_stream FAR *strm; +z_streamp strm; int windowBits; unsigned char FAR *window; const char *version; @@ -50,7 +50,8 @@ int stream_size; sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); - strm->state = (voidpf)state; + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; state->wbits = windowBits; state->wsize = 1U << windowBits; state->window = window; @@ -238,7 +239,7 @@ struct inflate_state FAR *state; are not correct, i.e. strm is Z_NULL or the state was not initialized. */ int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) -z_stream FAR *strm; +z_streamp strm; in_func in; void FAR *in_desc; out_func out; @@ -611,7 +612,7 @@ void FAR *out_desc; } int ZEXPORT inflateBackEnd(strm) -z_stream FAR *strm; +z_streamp strm; { if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) return Z_STREAM_ERROR; diff --git a/zlib/inffast.c b/zlib/inffast.c index 8c02a178d04..bbee92ed1e6 100644 --- a/zlib/inffast.c +++ b/zlib/inffast.c @@ -74,6 +74,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ unsigned char FAR *out; /* local strm->next_out */ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned write; /* window write index */ @@ -98,6 +101,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ out = strm->next_out - OFF; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif wsize = state->wsize; whave = state->whave; write = state->write; @@ -167,6 +173,13 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ } } dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif hold >>= op; bits -= op; Tracevv((stderr, "inflate: distance %u\n", dist)); diff --git a/zlib/inflate.c b/zlib/inflate.c index c6d38266d07..792fdee8e9c 100644 --- a/zlib/inflate.c +++ b/zlib/inflate.c @@ -1,5 +1,5 @@ /* inflate.c -- zlib decompression - * Copyright (C) 1995-2003 Mark Adler + * Copyright (C) 1995-2005 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -113,8 +113,11 @@ z_streamp strm; state->mode = HEAD; state->last = 0; state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; state->wsize = 0; state->whave = 0; + state->write = 0; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; @@ -122,6 +125,22 @@ z_streamp strm; return Z_OK; } +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) z_streamp strm; int windowBits; @@ -144,7 +163,7 @@ int stream_size; ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); - strm->state = (voidpf)state; + strm->state = (struct internal_state FAR *)state; if (windowBits < 0) { state->wrap = 0; windowBits = -windowBits; @@ -582,6 +601,8 @@ int flush; break; } state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( @@ -597,11 +618,13 @@ int flush; break; } DROPBITS(4); - if (BITS(4) + 8 > state->wbits) { + len = BITS(4) + 8; + if (len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; } + state->dmax = 1U << len; Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; @@ -621,16 +644,24 @@ int flush; state->mode = BAD; break; } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = TIME; case TIME: NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; if (state->flags & 0x0200) CRC4(state->check, hold); INITBITS(); state->mode = OS; case OS: NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; @@ -638,15 +669,26 @@ int flush; if (state->flags & 0x0400) { NEEDBITS(16); state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; if (state->flags & 0x0200) CRC2(state->check, hold); INITBITS(); } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; state->mode = EXTRA; case EXTRA: if (state->flags & 0x0400) { copy = state->length; if (copy > have) copy = have; if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; @@ -655,6 +697,7 @@ int flush; } if (state->length) goto inf_leave; } + state->length = 0; state->mode = NAME; case NAME: if (state->flags & 0x0800) { @@ -662,13 +705,20 @@ int flush; copy = 0; do { len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; } while (len && copy < have); - if (state->flags & 0x02000) + if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; state->mode = COMMENT; case COMMENT: if (state->flags & 0x1000) { @@ -676,13 +726,19 @@ int flush; copy = 0; do { len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; } while (len && copy < have); - if (state->flags & 0x02000) + if (state->flags & 0x0200) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; state->mode = HCRC; case HCRC: if (state->flags & 0x0200) { @@ -694,6 +750,10 @@ int flush; } INITBITS(); } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } strm->adler = state->check = crc32(0L, Z_NULL, 0); state->mode = TYPE; break; @@ -969,6 +1029,13 @@ int flush; state->offset += BITS(state->extra); DROPBITS(state->extra); } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif if (state->offset > state->whave + out - left) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; @@ -1110,12 +1177,16 @@ uInt dictLength; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; - if (state->mode != DICT) return Z_STREAM_ERROR; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; /* check for correct dictionary id */ - id = adler32(0L, Z_NULL, 0); - id = adler32(id, dictionary, dictLength); - if (id != state->check) return Z_DATA_ERROR; + if (state->mode == DICT) { + id = adler32(0L, Z_NULL, 0); + id = adler32(id, dictionary, dictLength); + if (id != state->check) + return Z_DATA_ERROR; + } /* copy dictionary to window */ if (updatewindow(strm, strm->avail_out)) { @@ -1137,6 +1208,23 @@ uInt dictLength; return Z_OK; } +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + /* Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found or when out of input. When called, *have is the number of pattern bytes @@ -1239,6 +1327,7 @@ z_streamp source; struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; + unsigned wsize; /* check input */ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || @@ -1261,14 +1350,19 @@ z_streamp source; } /* copy state */ - *dest = *source; - *copy = *state; - copy->lencode = copy->codes + (state->lencode - state->codes); - copy->distcode = copy->codes + (state->distcode - state->codes); + zmemcpy(dest, source, sizeof(z_stream)); + zmemcpy(copy, state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } copy->next = copy->codes + (state->next - state->codes); - if (window != Z_NULL) - zmemcpy(window, state->window, 1U << state->wbits); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } copy->window = window; - dest->state = (voidpf)copy; + dest->state = (struct internal_state FAR *)copy; return Z_OK; } diff --git a/zlib/inflate.h b/zlib/inflate.h index 9a12c8fd296..07bd3e78a7c 100644 --- a/zlib/inflate.h +++ b/zlib/inflate.h @@ -1,5 +1,5 @@ /* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2003 Mark Adler + * Copyright (C) 1995-2004 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -19,7 +19,6 @@ /* Possible inflate modes between inflate() calls */ typedef enum { HEAD, /* i: waiting for magic header */ -#ifdef GUNZIP FLAGS, /* i: waiting for method and flags (gzip) */ TIME, /* i: waiting for modification time (gzip) */ OS, /* i: waiting for extra flags and operating system (gzip) */ @@ -28,7 +27,6 @@ typedef enum { NAME, /* i: waiting for end of file name (gzip) */ COMMENT, /* i: waiting for end of comment (gzip) */ HCRC, /* i: waiting for header crc (gzip) */ -#endif DICTID, /* i: waiting for dictionary check value */ DICT, /* waiting for inflateSetDictionary() call */ TYPE, /* i: waiting for type bits, including last-flag bit */ @@ -45,9 +43,7 @@ typedef enum { MATCH, /* o: waiting for output space to copy string */ LIT, /* o: waiting for output space to write literal */ CHECK, /* i: waiting for 32-bit check value */ -#ifdef GUNZIP LENGTH, /* i: waiting for 32-bit length (gzip) */ -#endif DONE, /* finished check, done -- remain here until reset */ BAD, /* got a data error -- remain here until reset */ MEM, /* got an inflate() memory error -- remain here until reset */ @@ -84,8 +80,10 @@ struct inflate_state { int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ int havedict; /* true if dictionary provided */ int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ /* sliding window */ unsigned wbits; /* log base 2 of requested window size */ unsigned wsize; /* window size or zero if not using window */ diff --git a/zlib/inftrees.c b/zlib/inftrees.c index 509461d9273..8a9c13ff03d 100644 --- a/zlib/inftrees.c +++ b/zlib/inftrees.c @@ -1,5 +1,5 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2004 Mark Adler + * Copyright (C) 1995-2005 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.2.2 Copyright 1995-2004 Mark Adler "; + " inflate 1.2.3 Copyright 1995-2005 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -62,7 +62,7 @@ unsigned short FAR *work; 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 199, 198}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, @@ -232,6 +232,7 @@ unsigned short FAR *work; /* replicate for those indices with low len bits equal to huff */ incr = 1U << (len - drop); fill = 1U << curr; + min = fill; /* save offset to next table */ do { fill -= incr; next[(huff >> drop) + fill] = this; @@ -262,7 +263,7 @@ unsigned short FAR *work; drop = root; /* increment past last table */ - next += 1U << curr; + next += min; /* here min is 1 << curr */ /* determine length of next table */ curr = len - drop; diff --git a/zlib/trees.c b/zlib/trees.c index 52c820fa2e9..395e4e16814 100644 --- a/zlib/trees.c +++ b/zlib/trees.c @@ -1,5 +1,5 @@ /* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2003 Jean-loup Gailly + * Copyright (C) 1995-2005 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -555,7 +555,7 @@ local void gen_bitlen(s, desc) while (n != 0) { m = s->heap[--h]; if (m > max_code) continue; - if (tree[m].Len != (unsigned) bits) { + if ((unsigned) tree[m].Len != (unsigned) bits) { Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); s->opt_len += ((long)bits - (long)tree[m].Len) *(long)tree[m].Freq; @@ -930,8 +930,9 @@ void _tr_flush_block(s, buf, stored_len, eof) /* Build the Huffman trees unless a stored block is forced */ if (s->level > 0) { - /* Check if the file is ascii or binary */ - if (s->strm->data_type == Z_UNKNOWN) set_data_type(s); + /* Check if the file is binary or text */ + if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN) + set_data_type(s); /* Construct the literal and distance trees */ build_tree(s, (tree_desc *)(&(s->l_desc))); @@ -982,7 +983,7 @@ void _tr_flush_block(s, buf, stored_len, eof) #ifdef FORCE_STATIC } else if (static_lenb >= 0) { /* force static trees */ #else - } else if (static_lenb == opt_lenb) { + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { #endif send_bits(s, (STATIC_TREES<<1)+eof, 3); compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); @@ -1117,21 +1118,24 @@ local void compress_block(s, ltree, dtree) } /* =========================================================================== - * Set the data type to ASCII or BINARY, using a crude approximation: - * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - * IN assertion: the fields freq of dyn_ltree are set and the total of all - * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + * Set the data type to BINARY or TEXT, using a crude approximation: + * set it to Z_TEXT if all symbols are either printable characters (33 to 255) + * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise. + * IN assertion: the fields Freq of dyn_ltree are set. */ local void set_data_type(s) deflate_state *s; { - int n = 0; - unsigned ascii_freq = 0; - unsigned bin_freq = 0; - while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; - while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; - while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; - s->strm->data_type = bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII; + int n; + + for (n = 0; n < 9; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + if (n == 9) + for (n = 14; n < 32; n++) + if (s->dyn_ltree[n].Freq != 0) + break; + s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY; } /* =========================================================================== diff --git a/zlib/zconf.h b/zlib/zconf.h index 3c21403fce6..03a9431c8be 100644 --- a/zlib/zconf.h +++ b/zlib/zconf.h @@ -1,5 +1,5 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2004 Jean-loup Gailly. + * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -43,6 +43,10 @@ # define get_crc_table z_get_crc_table # define zError z_zError +# define alloc_func z_alloc_func +# define free_func z_free_func +# define in_func z_in_func +# define out_func z_out_func # define Byte z_Byte # define uInt z_uInt # define uLong z_uLong @@ -64,8 +68,10 @@ #if defined(_WINDOWS) && !defined(WINDOWS) # define WINDOWS #endif -#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) -# define WIN32 +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif #endif #if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) # if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) diff --git a/zlib/zlib.3 b/zlib/zlib.3 index 3139e2467f2..90b8162870f 100644 --- a/zlib/zlib.3 +++ b/zlib/zlib.3 @@ -1,4 +1,4 @@ -.TH ZLIB 3 "3 October 2004" +.TH ZLIB 3 "18 July 2005" .SH NAME zlib \- compression/decompression library .SH SYNOPSIS @@ -133,8 +133,8 @@ before asking for help. Send questions and/or comments to zlib@gzip.org, or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). .SH AUTHORS -Version 1.2.2 -Copyright (C) 1995-2004 Jean-loup Gailly (jloup@gzip.org) +Version 1.2.3 +Copyright (C) 1995-2005 Jean-loup Gailly (jloup@gzip.org) and Mark Adler (madler@alumni.caltech.edu). .LP This software is provided "as-is," diff --git a/zlib/zlib.h b/zlib/zlib.h index b4ddd34395c..022817927ce 100644 --- a/zlib/zlib.h +++ b/zlib/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.2, October 3rd, 2004 + version 1.2.3, July 18th, 2005 - Copyright (C) 1995-2004 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -37,8 +37,8 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.2" -#define ZLIB_VERNUM 0x1220 +#define ZLIB_VERSION "1.2.3" +#define ZLIB_VERNUM 0x1230 /* The 'zlib' compression library provides in-memory compression and @@ -95,7 +95,7 @@ typedef struct z_stream_s { free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ - int data_type; /* best guess about the data type: ascii or binary */ + int data_type; /* best guess about the data type: binary or text */ uLong adler; /* adler32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; @@ -103,6 +103,29 @@ typedef struct z_stream_s { typedef z_stream FAR *z_streamp; /* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and @@ -166,11 +189,13 @@ typedef z_stream FAR *z_streamp; #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_RLE 3 +#define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 -#define Z_ASCII 1 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 /* Possible values of the data_type field (though see inflate()) */ @@ -244,6 +269,10 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumualte before producing output, in order to + maximize compression. + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular @@ -255,7 +284,7 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - the compression. + compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated @@ -280,8 +309,8 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); deflate() sets strm->adler to the adler32 checksum of all input read so far (that is, total_in bytes). - deflate() may update data_type if it can make a good guess about - the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. @@ -363,11 +392,11 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much output as possible to the output buffer. Z_BLOCK requests that inflate() stop - if and when it get to the next deflate block boundary. When decoding the zlib - or gzip format, this will cause inflate() to return immediately after the - header and before the first block. When doing a raw inflate, inflate() will - go ahead and process the first block, and will return when it gets to the end - of that block, or when it runs out of data. + if and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause inflate() to return immediately after + the header and before the first block. When doing a raw inflate, inflate() + will go ahead and process the first block, and will return when it gets to + the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. Also to assist in this, on return inflate() will set strm->data_type to the @@ -496,7 +525,9 @@ ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy parameter only affects the compression ratio but not the correctness of the - compressed output even if it is not set appropriately. + compressed output even if it is not set appropriately. Z_FIXED prevents the + use of dynamic Huffman codes, allowing for a simpler decoder for special + applications. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid @@ -525,7 +556,9 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size in deflate or deflate2. Thus the strings most likely to be useful should be - put at the end of the dictionary, not at the front. + put at the end of the dictionary, not at the front. In addition, the + current implementation of deflate will use at most the window size minus + 262 bytes of the provided dictionary. Upon return of this function, strm->adler is set to the adler32 value of the dictionary; the decompressor may later use this value to determine @@ -591,6 +624,23 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, if strm->avail_out was zero. */ +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, uLong sourceLen)); /* @@ -616,6 +666,30 @@ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, stream state was inconsistent. */ +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + /* ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, int windowBits)); @@ -648,15 +722,15 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR. If a gzip stream is being decoded, strm->adler is + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a crc32 instead of an adler32. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative - memLevel). msg is set to null if there is no error message. inflateInit2 - does not perform any decompression apart from reading the zlib header if - present: this will be done by inflate(). (So next_in and avail_in may be - modified, but next_out and avail_out are unchanged.) + memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg + is set to null if there is no error message. inflateInit2 does not perform + any decompression apart from reading the zlib header if present: this will + be done by inflate(). (So next_in and avail_in may be modified, but next_out + and avail_out are unchanged.) */ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, @@ -664,11 +738,14 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, uInt dictLength)); /* Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate - if this call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by this call of - inflate. The compressor and decompressor must use exactly the same - dictionary (see deflateSetDictionary). + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called + immediately after inflateInit2() or inflateReset() and before any call of + inflate() to set the dictionary. The application must insure that the + dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (such as NULL dictionary) or the stream state is @@ -719,8 +796,64 @@ ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); stream state was inconsistent (such as zalloc or state being NULL). */ +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK can be used to + force inflate() to return immediately after header processing is complete + and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When + any of extra, name, or comment are not Z_NULL and the respective field is + not present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + /* -ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, unsigned char FAR *window)); Initialize the internal stream state for decompression using inflateBack() @@ -744,7 +877,7 @@ ZEXTERN int ZEXPORT inflateBackInit OF((z_stream FAR *strm, int windowBits, typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); -ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)); /* @@ -813,7 +946,7 @@ ZEXTERN int ZEXPORT inflateBack OF((z_stream FAR *strm, that inflateBack() cannot return Z_OK. */ -ZEXTERN int ZEXPORT inflateBackEnd OF((z_stream FAR *strm)); +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); /* All memory allocated by inflateBackInit() is freed. @@ -1087,6 +1220,12 @@ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); input stream, otherwise zero. */ +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns 1 if file is being read directly without decompression, otherwise + zero. +*/ + ZEXTERN int ZEXPORT gzclose OF((gzFile file)); /* Flushes all pending output if necessary, closes the compressed file @@ -1119,7 +1258,6 @@ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); */ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); - /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is NULL, this function returns @@ -1135,12 +1273,21 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); if (adler != original_adler) error(); */ +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); +/* + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. +*/ + ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* - Update a running crc with the bytes buf[0..len-1] and return the updated - crc. If buf is NULL, this function returns the required initial value - for the crc. Pre- and post-conditioning (one's complement) is performed - within this function so it shouldn't be done by the application. + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is NULL, this function returns the required initial + value for the for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); @@ -1151,6 +1298,16 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); if (crc != original_crc) error(); */ +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + +/* + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + /* various hacks, don't look :) */ @@ -1167,7 +1324,7 @@ ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, int stream_size)); ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_stream FAR *strm, int windowBits, +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size)); diff --git a/zlib/zutil.c b/zlib/zutil.c index 0ef4f99f57e..d55f5948a37 100644 --- a/zlib/zutil.c +++ b/zlib/zutil.c @@ -1,5 +1,5 @@ /* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2003 Jean-loup Gailly. + * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -11,10 +11,6 @@ struct internal_state {int dummy;}; /* for buggy compilers */ #endif -#ifndef STDC -extern void exit OF((int)); -#endif - const char * const z_errmsg[10] = { "need dictionary", /* Z_NEED_DICT 2 */ "stream end", /* Z_STREAM_END 1 */ @@ -78,38 +74,38 @@ uLong ZEXPORT zlibCompileFlags() flags += 1 << 13; #endif #ifdef NO_GZCOMPRESS - flags += 1 << 16; + flags += 1L << 16; #endif #ifdef NO_GZIP - flags += 1 << 17; + flags += 1L << 17; #endif #ifdef PKZIP_BUG_WORKAROUND - flags += 1 << 20; + flags += 1L << 20; #endif #ifdef FASTEST - flags += 1 << 21; + flags += 1L << 21; #endif #ifdef STDC # ifdef NO_vsnprintf - flags += 1 << 25; + flags += 1L << 25; # ifdef HAS_vsprintf_void - flags += 1 << 26; + flags += 1L << 26; # endif # else # ifdef HAS_vsnprintf_void - flags += 1 << 26; + flags += 1L << 26; # endif # endif #else - flags += 1 << 24; + flags += 1L << 24; # ifdef NO_snprintf - flags += 1 << 25; + flags += 1L << 25; # ifdef HAS_sprintf_void - flags += 1 << 26; + flags += 1L << 26; # endif # else # ifdef HAS_snprintf_void - flags += 1 << 26; + flags += 1L << 26; # endif # endif #endif @@ -141,7 +137,10 @@ const char * ZEXPORT zError(err) } #if defined(_WIN32_WCE) - /* does not exist on WCE */ + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ int errno = 0; #endif diff --git a/zlib/zutil.h b/zlib/zutil.h index 7b42edcaa98..b7d5eff81b6 100644 --- a/zlib/zutil.h +++ b/zlib/zutil.h @@ -1,5 +1,5 @@ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2003 Jean-loup Gailly. + * Copyright (C) 1995-2005 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -17,14 +17,26 @@ #include "zlib.h" #ifdef STDC -# include <stddef.h> +# ifndef _WIN32_WCE +# include <stddef.h> +# endif # include <string.h> # include <stdlib.h> #endif #ifdef NO_ERRNO_H +# ifdef _WIN32_WCE + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. We rename it to + * avoid conflict with other libraries that use the same workaround. + */ +# define errno z_errno +# endif extern int errno; #else -# include <errno.h> +# ifndef _WIN32_WCE +# include <errno.h> +# endif #endif #ifndef local @@ -105,6 +117,9 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #ifdef OS2 # define OS_CODE 0x06 +# ifdef M_I86 + #include <malloc.h> +# endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) @@ -193,15 +208,6 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # define NO_vsnprintf #endif -#ifdef HAVE_STRERROR -# ifndef VMS - extern char *strerror OF((int)); -# endif -# define zstrerror(errnum) strerror(errnum) -#else -# define zstrerror(errnum) "" -#endif - #if defined(pyr) # define NO_MEMCPY #endif |