From 5ec2bfe94c28ad73a691d90b784138f38e9134cd Mon Sep 17 00:00:00 2001 From: "tsmith/tim@siva.hindu.god" <> Date: Thu, 14 Sep 2006 21:06:14 -0600 Subject: [PATCH 001/131] Bug #4053: too many of "error 1236: 'binlog truncated in the middle of event' from master" - Detect read failure in my_read_charset_file --- mysys/charset.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/mysys/charset.c b/mysys/charset.c index 665f2efecd8..6f2d4d3c347 100644 --- a/mysys/charset.c +++ b/mysys/charset.c @@ -312,7 +312,7 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) { char *buf; int fd; - uint len; + uint len, tmp_len; MY_STAT stat_info; if (!my_stat(filename, &stat_info, MYF(myflags)) || @@ -321,12 +321,11 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) return TRUE; if ((fd=my_open(filename,O_RDONLY,myflags)) < 0) - { - my_free(buf,myflags); - return TRUE; - } - len=read(fd,buf,len); + goto error; + tmp_len=my_read(fd, buf, len, myflags); my_close(fd,myflags); + if (tmp_len != len) + goto error; if (my_parse_charset_xml(buf,len,add_collation)) { @@ -340,6 +339,10 @@ static my_bool my_read_charset_file(const char *filename, myf myflags) my_free(buf, myflags); return FALSE; + +error: + my_free(buf, myflags); + return TRUE; } From 7b9f4086fa55b1e3414740d0a6e337134794ab05 Mon Sep 17 00:00:00 2001 From: "tsmith/tim@siva.hindu.god" <> Date: Thu, 14 Sep 2006 23:19:24 -0600 Subject: [PATCH 002/131] Bug #4053: too many of "error 1236: 'binlog truncated in the middle of event' from master" - Fix my_read/my_write to handle return values from read/write correctly - Add debugging 'deprecated function' warning to my_lread/my_lwrite - Add debugging 'error, read/write interrupt not handled' warning to my_quick_read/my_quick_write There is no test case associated with these changes. However, this is a conservative change, and no repeatable test case is available. --- mysys/my_lread.c | 2 ++ mysys/my_lwrite.c | 2 ++ mysys/my_pread.c | 12 ++++++++---- mysys/my_quick.c | 26 +++++++++++++++++++++++++- mysys/my_read.c | 8 ++++++-- mysys/my_write.c | 20 +++++++++++++------- 6 files changed, 56 insertions(+), 14 deletions(-) diff --git a/mysys/my_lread.c b/mysys/my_lread.c index 601d772b844..a96febe4474 100644 --- a/mysys/my_lread.c +++ b/mysys/my_lread.c @@ -30,6 +30,8 @@ uint32 my_lread(int Filedes, byte *Buffer, uint32 Count, myf MyFlags) DBUG_PRINT("my",("Fd: %d Buffer: %ld Count: %ld MyFlags: %d", Filedes, Buffer, Count, MyFlags)); + DBUG_PRINT("error", ("Deprecated my_lread() function should not be used.")); + /* Temp hack to get count to int32 while read wants int */ if ((readbytes = (uint32) read(Filedes, Buffer, (uint) Count)) != Count) { diff --git a/mysys/my_lwrite.c b/mysys/my_lwrite.c index e1a3decd053..cfdbd5d4576 100644 --- a/mysys/my_lwrite.c +++ b/mysys/my_lwrite.c @@ -26,6 +26,8 @@ uint32 my_lwrite(int Filedes, const byte *Buffer, uint32 Count, myf MyFlags) DBUG_PRINT("my",("Fd: %d Buffer: %lx Count: %ld MyFlags: %d", Filedes, Buffer, Count, MyFlags)); + DBUG_PRINT("error", ("Deprecated my_lwrite() function should not be used.")); + /* Temp hack to get count to int32 while write wants int */ if ((writenbytes = (uint32) write(Filedes, Buffer, (uint) Count)) != Count) { diff --git a/mysys/my_pread.c b/mysys/my_pread.c index f76233fc4cc..70990ad12a6 100644 --- a/mysys/my_pread.c +++ b/mysys/my_pread.c @@ -52,8 +52,12 @@ uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset, DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d", readbytes,Count,Filedes,my_errno)); #ifdef THREAD - if (readbytes == 0 && errno == EINTR) - continue; /* Interrupted */ + if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR) + { + DBUG_PRINT("debug", ("my_pread() was interrupted and returned %d", + (int) readbytes)); + continue; /* Interrupted */ + } #endif if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) { @@ -124,8 +128,8 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset, VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC)); continue; } - if ((writenbytes == 0 && my_errno == EINTR) || - (writenbytes > 0 && (uint) writenbytes != (uint) -1)) + if ((writenbytes > 0 && (uint) writenbytes != (uint) -1) || + my_errno == EINTR) continue; /* Retry */ #endif if (MyFlags & (MY_NABP | MY_FNABP)) diff --git a/mysys/my_quick.c b/mysys/my_quick.c index 44ed3fc0b2c..ffc8160c371 100644 --- a/mysys/my_quick.c +++ b/mysys/my_quick.c @@ -26,6 +26,14 @@ uint my_quick_read(File Filedes,byte *Buffer,uint Count,myf MyFlags) if ((readbytes = (uint) read(Filedes, Buffer, Count)) != Count) { +#ifndef DBUG_OFF + if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR) + { + DBUG_PRINT("error", ("my_quick_read() was interrupted and returned %d" + ". This function does not retry the read!", + (int) readbytes)); + } +#endif my_errno=errno; return readbytes; } @@ -35,8 +43,24 @@ uint my_quick_read(File Filedes,byte *Buffer,uint Count,myf MyFlags) uint my_quick_write(File Filedes,const byte *Buffer,uint Count) { - if ((uint) write(Filedes,Buffer,Count) != Count) +#ifndef DBUG_OFF + uint writtenbytes; +#endif + + if (( +#ifndef DBUG_OFF + writtenbytes = +#endif + (uint) write(Filedes,Buffer,Count)) != Count) { +#ifndef DBUG_OFF + if ((writtenbytes == 0 || (int) writtenbytes == -1) && errno == EINTR) + { + DBUG_PRINT("error", ("my_quick_write() was interrupted and returned %d" + ". This function does not retry the write!", + (int) writtenbytes)); + } +#endif my_errno=errno; return (uint) -1; } diff --git a/mysys/my_read.c b/mysys/my_read.c index b7621ac99eb..b59ada20977 100644 --- a/mysys/my_read.c +++ b/mysys/my_read.c @@ -51,8 +51,12 @@ uint my_read(File Filedes, byte *Buffer, uint Count, myf MyFlags) DBUG_PRINT("warning",("Read only %ld bytes off %ld from %d, errno: %d", readbytes,Count,Filedes,my_errno)); #ifdef THREAD - if (readbytes == 0 && errno == EINTR) - continue; /* Interrupted */ + if ((readbytes == 0 || (int) readbytes == -1) && errno == EINTR) + { + DBUG_PRINT("debug", ("my_read() was interrupted and returned %d", + (int) readbytes)); + continue; /* Interrupted */ + } #endif if (MyFlags & (MY_WME | MY_FAE | MY_FNABP)) { diff --git a/mysys/my_write.c b/mysys/my_write.c index 1d1a893090a..de762c16a07 100644 --- a/mysys/my_write.c +++ b/mysys/my_write.c @@ -57,18 +57,24 @@ uint my_write(int Filedes, const byte *Buffer, uint Count, myf MyFlags) VOID(sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC)); continue; } - if (!writenbytes) + + if ((writenbytes == 0 || (int) writenbytes == -1)) { - /* We may come here on an interrupt or if the file quote is exeeded */ if (my_errno == EINTR) - continue; - if (!errors++) /* Retry once */ { - errno=EFBIG; /* Assume this is the error */ - continue; + DBUG_PRINT("debug", ("my_write() was interrupted and returned %d", + (int) writenbytes)); + continue; /* Interrupted */ + } + + if (!writenbytes && !errors++) /* Retry once */ + { + /* We may come here if the file quota is exeeded */ + errno=EFBIG; /* Assume this is the error */ + continue; } } - else if ((uint) writenbytes != (uint) -1) + else continue; /* Retry */ #endif if (MyFlags & (MY_NABP | MY_FNABP)) From 2f33711f1db70c669791dd4a08f06b126a64f0d1 Mon Sep 17 00:00:00 2001 From: "Kristofer.Pettersson@naruto." <> Date: Fri, 22 Sep 2006 11:22:01 +0200 Subject: [PATCH 003/131] Bug#21811 Odd casting with date + INTERVAL arithmetic - The definition of the result type of a type_date function didn't include INTERVAL_WEEK - This patch adds an explicit test for INTERVAL_WEEK which results in the result type for an item_date_add_intervall operation being DATE rather than DATETIME when one parameter is INTERVAL_WEEK. --- sql/item_timefunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index febc92e34f6..3886af27158 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1876,7 +1876,7 @@ void Item_date_add_interval::fix_length_and_dec() cached_field_type= MYSQL_TYPE_DATETIME; else if (arg0_field_type == MYSQL_TYPE_DATE) { - if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH) + if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH || int_type == INTERVAL_WEEK ) cached_field_type= arg0_field_type; else cached_field_type= MYSQL_TYPE_DATETIME; From 2cea0e6b133d7e2c82735253a92ce4b976c82498 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Tue, 3 Oct 2006 15:33:44 +0200 Subject: [PATCH 004/131] Update mysqltest to latest version - ie. backport from 5.1 - also update testcase error dected by new version --- client/Makefile.am | 4 +- client/mysqltest.c | 7702 +++++++++++------- mysql-test/include/have_multi_ndb.inc | 12 +- mysql-test/include/master-slave.inc | 6 +- mysql-test/include/ps_query.inc | 1 - mysql-test/include/show_msg.inc | 25 + mysql-test/include/show_msg80.inc | 118 + mysql-test/r/check.result | 2 +- mysql-test/r/connect.result | 20 + mysql-test/r/flush.result | 4 +- mysql-test/r/flush_block_commit.result | 6 +- mysql-test/r/func_misc.result | 2 +- mysql-test/r/grant2.result | 8 +- mysql-test/r/handler.result | 2 +- mysql-test/r/kill.result | 2 +- mysql-test/r/lock_multi.result | 12 +- mysql-test/r/mix_innodb_myisam_binlog.result | 2 +- mysql-test/r/mysqltest.result | 194 +- mysql-test/r/ps_2myisam.result | 2 + mysql-test/r/ps_3innodb.result | 2 + mysql-test/r/ps_4heap.result | 2 + mysql-test/r/ps_5merge.result | 4 + mysql-test/r/ps_6bdb.result | 2 + mysql-test/r/ps_7ndb.result | 2 + mysql-test/r/rename.result | 2 +- mysql-test/r/rpl000001.result | 2 +- mysql-test/r/rpl000018.result | 14 - mysql-test/r/rpl_chain_temp_table.result | 30 - mysql-test/r/rpl_error_ignored_table.result | 2 +- mysql-test/r/rpl_failsafe.result | 34 - mysql-test/r/rpl_heap.result | 29 - mysql-test/r/rpl_master_pos_wait.result | 2 +- mysql-test/r/subselect.result | 3 +- mysql-test/r/synchronization.result | 40 +- mysql-test/r/type_blob.result | 3 +- mysql-test/t/connect.test | 83 +- mysql-test/t/init_file.test | 5 +- mysql-test/t/mysql_client_test.test | 6 +- mysql-test/t/mysqltest.test | 745 +- mysql-test/t/ps.test | 6 +- mysql-test/t/ps_1general.test | 2 +- mysql-test/t/ps_grant.test | 2 +- mysql-test/t/rpl000018.test | 29 - mysql-test/t/rpl_chain_temp_table.test | 101 - mysql-test/t/rpl_failsafe.test | 24 - mysql-test/t/rpl_flush_tables.test | 2 + mysql-test/t/rpl_heap.test | 51 - mysql-test/t/rpl_trunc_temp.test | 3 - mysql-test/t/subselect.test | 2 +- mysql-test/t/type_blob.test | 2 +- 50 files changed, 6023 insertions(+), 3337 deletions(-) create mode 100755 mysql-test/include/show_msg.inc create mode 100755 mysql-test/include/show_msg80.inc delete mode 100644 mysql-test/r/rpl000018.result delete mode 100644 mysql-test/r/rpl_chain_temp_table.result delete mode 100644 mysql-test/r/rpl_failsafe.result delete mode 100644 mysql-test/r/rpl_heap.result delete mode 100644 mysql-test/t/rpl000018.test delete mode 100644 mysql-test/t/rpl_chain_temp_table.test delete mode 100644 mysql-test/t/rpl_failsafe.test delete mode 100644 mysql-test/t/rpl_heap.test diff --git a/client/Makefile.am b/client/Makefile.am index c0569d5fa6f..fe150defe03 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -30,7 +30,9 @@ mysql_SOURCES = mysql.cc readline.cc sql_string.cc completion_hash.cc mysqladmin_SOURCES = mysqladmin.cc mysql_LDADD = @readline_link@ @TERMCAP_LIB@ $(LDADD) $(CXXLDFLAGS) mysqlbinlog_LDADD = $(LDADD) $(CXXLDFLAGS) -mysqltest_SOURCES= mysqltest.c $(top_srcdir)/mysys/my_getsystime.c +mysqltest_SOURCES= mysqltest.c \ + $(top_srcdir)/mysys/my_getsystime.c \ + $(top_srcdir)/mysys/my_copy.c mysqltest_LDADD = $(top_builddir)/regex/libregex.a $(LDADD) mysqlbinlog_SOURCES = mysqlbinlog.cc ../mysys/mf_tempdir.c mysqlmanagerc_SOURCES = mysqlmanagerc.c diff --git a/client/mysqltest.c b/client/mysqltest.c index ad0f9f857bb..623c33d0f4f 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -14,35 +14,22 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* mysqltest test tool - * See the manual for more information - * TODO: document better how mysqltest works - * - * Written by: - * Sasha Pachev - * Matt Wagner - * Monty - * Jani - **/ +/* + mysqltest -/********************************************************************** - TODO: + Tool used for executing a .test file -- Do comparison line by line, instead of doing a full comparison of - the text file. This will save space as we don't need to keep many - results in memory. It will also make it possible to do simple - 'comparison' fixes like accepting the result even if a float differed - in the last decimals. + See the "MySQL Test framework manual" for more information + http://dev.mysql.com/doc/mysqltest/en/index.html -- Don't buffer lines from the test that you don't expect to need - again. + Written by: + Sasha Pachev + Matt Wagner + Monty + Jani +*/ -- Change 'read_line' to be faster by using the readline.cc code; - We can do better than calling feof() for each character! - -**********************************************************************/ - -#define MTEST_VERSION "2.5" +#define MTEST_VERSION "3.0" #include #include @@ -51,18 +38,18 @@ #include #include #include +#include #include #include -#include /* Error codes */ #include #include #include -#include #include -#include "my_regex.h" /* Our own version of lib */ +#include "my_regex.h" /* Our own version of regex */ #ifdef HAVE_SYS_WAIT_H #include #endif + #ifndef WEXITSTATUS # ifdef __WIN__ # define WEXITSTATUS(stat_val) (stat_val) @@ -70,166 +57,144 @@ # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) # endif #endif -#define MAX_QUERY 131072 -#define MAX_VAR_NAME 256 -#define MAX_COLUMNS 256 -#define PAD_SIZE 128 -#define MAX_CONS 128 -#define MAX_INCLUDE_DEPTH 16 -#define LAZY_GUESS_BUF_SIZE 8192 -#define INIT_Q_LINES 1024 -#define MIN_VAR_ALLOC 32 -#define BLOCK_STACK_DEPTH 32 -#define MAX_EXPECTED_ERRORS 10 -#define QUERY_SEND 1 -#define QUERY_REAP 2 -#ifndef MYSQL_MANAGER_PORT -#define MYSQL_MANAGER_PORT 23546 -#endif -#define MAX_SERVER_ARGS 64 -/* - Sometimes in a test the client starts before - the server - to solve the problem, we try again - after some sleep if connection fails the first - time -*/ -#define CON_RETRY_SLEEP 2 -#define MAX_CON_TRIES 5 +#define MAX_VAR_NAME_LENGTH 256 +#define MAX_COLUMNS 256 +#define MAX_EMBEDDED_SERVER_ARGS 64 +#define MAX_DELIMITER_LENGTH 16 -#define SLAVE_POLL_INTERVAL 300000 /* 0.3 of a sec */ -#define DEFAULT_DELIMITER ";" -#define MAX_DELIMITER 16 +/* Flags controlling send and reap */ +#define QUERY_SEND_FLAG 1 +#define QUERY_REAP_FLAG 2 -#define RESULT_OK 0 -#define RESULT_CONTENT_MISMATCH 1 -#define RESULT_LENGTH_MISMATCH 2 + enum { + RESULT_OK= 0, + RESULT_CONTENT_MISMATCH= 1, + 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, - OPT_SSL_CIPHER,OPT_PS_PROTOCOL}; - -/* ************************************************************************ */ -/* - The list of error codes to --error are stored in an internal array of - structs. This struct can hold numeric SQL error codes or SQLSTATE codes - as strings. The element next to the last active element in the list is - set to type ERR_EMPTY. When an SQL statement returns an error, we use - this list to check if this is an expected error. -*/ - -enum match_err_type -{ - ERR_EMPTY= 0, - ERR_ERRNO, - ERR_SQLSTATE +enum { + OPT_SKIP_SAFEMALLOC=256, OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, + OPT_SSL_CA, OPT_SSL_CAPATH, OPT_SSL_CIPHER, OPT_PS_PROTOCOL, + OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL, + OPT_SSL_VERIFY_SERVER_CERT, OPT_MAX_CONNECT_RETRIES, + OPT_MARK_PROGRESS }; -typedef struct -{ - enum match_err_type type; - union - { - uint errnum; - char sqlstate[SQLSTATE_LENGTH+1]; /* \0 terminated string */ - } code; -} match_err; - -static match_err global_expected_errno[MAX_EXPECTED_ERRORS]; -static uint global_expected_errors; - -/* ************************************************************************ */ - -static int record = 0, opt_sleep=0; -static char *db = 0, *pass=0; -const char *user = 0, *host = 0, *unix_sock = 0, *opt_basedir="./"; -static int port = 0; -static my_bool opt_big_test= 0, opt_compress= 0, silent= 0, verbose = 0; -static my_bool tty_password= 0, ps_protocol= 0, ps_protocol_enabled= 0; -static uint start_lineno= 0, *lineno; -const char *manager_user="root",*manager_host=0; -char *manager_pass=0; -int manager_port=MYSQL_MANAGER_PORT; -int manager_wait_timeout=3; -MYSQL_MANAGER* manager=0; +static int record= 0, opt_sleep= -1; +static char *db= 0, *pass= 0; +const char *user= 0, *host= 0, *unix_sock= 0, *opt_basedir= "./"; +const char *opt_include= 0; +static int port= 0; +static int opt_max_connect_retries; +static my_bool opt_compress= 0, silent= 0, verbose= 0; +static my_bool tty_password= 0; +static my_bool opt_mark_progress= 0; +static my_bool ps_protocol= 0, ps_protocol_enabled= 0; +static my_bool sp_protocol= 0, sp_protocol_enabled= 0; +static my_bool view_protocol= 0, view_protocol_enabled= 0; +static my_bool cursor_protocol= 0, cursor_protocol_enabled= 0; +static my_bool parsing_disabled= 0; +static my_bool display_result_vertically= FALSE, display_metadata= FALSE; +static my_bool disable_query_log= 0, disable_result_log= 0; +static my_bool disable_warnings= 0, disable_ps_warnings= 0; +static my_bool disable_info= 1; +static my_bool abort_on_error= 1; static char **default_argv; -static const char *load_default_groups[]= { "mysqltest","client",0 }; -static char line_buffer[MAX_DELIMITER], *line_buffer_pos= line_buffer; +static const char *load_default_groups[]= { "mysqltest", "client", 0 }; +static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer; -typedef struct +static uint start_lineno= 0; /* Start line of current command */ + +static char delimiter[MAX_DELIMITER_LENGTH]= ";"; +static uint delimiter_length= 1; + +static char TMPDIR[FN_REFLEN]; + +/* Block stack */ +enum block_cmd { + cmd_none, + cmd_if, + cmd_while +}; + +struct st_block +{ + int line; /* Start line of block */ + my_bool ok; /* Should block be executed */ + enum block_cmd cmd; /* Command owning the block */ +}; + +static struct st_block block_stack[32]; +static struct st_block *cur_block, *block_stack_end; + +/* Open file stack */ +struct st_test_file { FILE* file; const char *file_name; -} test_file; + uint lineno; /* Current line in file */ +}; -static test_file file_stack[MAX_INCLUDE_DEPTH]; -static test_file* cur_file; -static test_file* file_stack_end; +static struct st_test_file file_stack[16]; +static struct st_test_file* cur_file; +static struct st_test_file* file_stack_end; -static uint lineno_stack[MAX_INCLUDE_DEPTH]; -static char TMPDIR[FN_REFLEN]; -static char delimiter[MAX_DELIMITER]= DEFAULT_DELIMITER; -static uint delimiter_length= 1; static CHARSET_INFO *charset_info= &my_charset_latin1; /* Default charset */ static const char *charset_name= "latin1"; /* Default character set name */ -static int embedded_server_arg_count=0; -static char *embedded_server_args[MAX_SERVER_ARGS]; - -static my_bool display_result_vertically= FALSE, display_metadata= FALSE; - -/* See the timer_output() definition for details */ -static char *timer_file = NULL; -static ulonglong timer_start; -static int got_end_timer= FALSE; -static void timer_output(void); -static ulonglong timer_now(void); - -static my_regex_t ps_re; /* Holds precompiled re for valid PS statements */ -static void ps_init_re(void); -static int ps_match_re(char *); -static char *ps_eprint(int); -static void ps_free_reg(void); - -static const char *embedded_server_groups[] = { +static const char *embedded_server_groups[]= +{ "server", "embedded", "mysqltest_SERVER", NullS }; +static int embedded_server_arg_count=0; +static char *embedded_server_args[MAX_EMBEDDED_SERVER_ARGS]; + +/* + Timer related variables + See the timer_output() definition for details +*/ +static char *timer_file = NULL; +static ulonglong timer_start; +static void timer_output(void); +static ulonglong timer_now(void); + +static ulonglong progress_start= 0; + +/* Precompiled re's */ +static my_regex_t ps_re; /* the query can be run using PS protocol */ +static my_regex_t sp_re; /* the query can be run as a SP */ +static my_regex_t view_re; /* the query can be run as a view*/ + +static void init_re(void); +static int match_re(my_regex_t *, char *); +static void free_re(void); + DYNAMIC_ARRAY q_lines; #include "sslopt-vars.h" -typedef struct +struct +{ + int read_lines,current_line; +} parser; + +struct { char file[FN_REFLEN]; ulong pos; -} MASTER_POS ; +} master_pos; -struct connection -{ - MYSQL mysql; - char *name; -}; - -typedef struct -{ - int read_lines,current_line; -} PARSER; - -MYSQL_RES *last_result=0; - -PARSER parser; -MASTER_POS master_pos; /* if set, all results are concated and compared against this file */ -const char *result_file = 0; +const char *result_file= 0; -typedef struct +typedef struct st_var { char *name; int name_len; @@ -239,81 +204,71 @@ typedef struct int alloced_len; int int_dirty; /* do not update string if int is updated until first read */ int alloced; + char *env_s; } VAR; -#if defined(__NETWARE__) || defined(__WIN__) -/* - Netware doesn't proved environment variable substitution that is done - by the shell in unix environments. We do this in the following function: -*/ - -static char *subst_env_var(const char *cmd); -static FILE *my_popen(const char *cmd, const char *mode); -#define popen(A,B) my_popen((A),(B)) -#endif /* __NETWARE__ */ - -VAR var_reg[10]; /*Perl/shell-like variable registers */ +VAR var_reg[10]; + HASH var_hash; -my_bool disable_query_log=0, disable_result_log=0, disable_warnings=0; -my_bool disable_info= 1; /* By default off */ -my_bool abort_on_error= 1; -struct connection cons[MAX_CONS]; -struct connection* cur_con, *next_con, *cons_end; - - /* Add new commands before Q_UNKNOWN !*/ - -enum enum_commands { -Q_CONNECTION=1, Q_QUERY, -Q_CONNECT, Q_SLEEP, Q_REAL_SLEEP, -Q_INC, Q_DEC, -Q_SOURCE, Q_DISCONNECT, -Q_LET, Q_ECHO, -Q_WHILE, Q_END_BLOCK, -Q_SYSTEM, Q_RESULT, -Q_REQUIRE, Q_SAVE_MASTER_POS, -Q_SYNC_WITH_MASTER, -Q_SYNC_SLAVE_WITH_MASTER, -Q_ERROR, -Q_SEND, Q_REAP, -Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN, -Q_PING, Q_EVAL, -Q_RPL_PROBE, Q_ENABLE_RPL_PARSE, -Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT, -Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG, -Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG, -Q_SERVER_START, Q_SERVER_STOP,Q_REQUIRE_MANAGER, -Q_WAIT_FOR_SLAVE_TO_STOP, -Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS, -Q_ENABLE_INFO, Q_DISABLE_INFO, -Q_ENABLE_METADATA, Q_DISABLE_METADATA, -Q_EXEC, Q_DELIMITER, -Q_DISABLE_ABORT_ON_ERROR, Q_ENABLE_ABORT_ON_ERROR, -Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS, -Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL, -Q_START_TIMER, Q_END_TIMER, -Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL, -Q_EXIT, -Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT, -Q_IF, - -Q_UNKNOWN, /* Unknown command. */ -Q_COMMENT, /* Comments, ignored. */ -Q_COMMENT_WITH_COMMAND -}; - -/* this should really be called command */ -struct st_query +struct st_connection { - char *query, *query_buf,*first_argument,*last_argument,*end; - int first_word_len; - my_bool abort_on_error, require_file; - match_err expected_errno[MAX_EXPECTED_ERRORS]; - uint expected_errors; - char record_file[FN_REFLEN]; - enum enum_commands type; + MYSQL mysql; + /* Used when creating views and sp, to avoid implicit commit */ + MYSQL* util_mysql; + char *name; + MYSQL_STMT* stmt; }; +struct st_connection connections[128]; +struct st_connection* cur_con, *next_con, *connections_end; + +/* + List of commands in mysqltest + Must match the "command_names" array + Add new commands before Q_UNKNOWN! +*/ +enum enum_commands { + Q_CONNECTION=1, Q_QUERY, + Q_CONNECT, Q_SLEEP, Q_REAL_SLEEP, + Q_INC, Q_DEC, + Q_SOURCE, Q_DISCONNECT, + Q_LET, Q_ECHO, + Q_WHILE, Q_END_BLOCK, + Q_SYSTEM, Q_RESULT, + Q_REQUIRE, Q_SAVE_MASTER_POS, + Q_SYNC_WITH_MASTER, + Q_SYNC_SLAVE_WITH_MASTER, + Q_ERROR, + Q_SEND, Q_REAP, + Q_DIRTY_CLOSE, Q_REPLACE, Q_REPLACE_COLUMN, + Q_PING, Q_EVAL, + Q_RPL_PROBE, Q_ENABLE_RPL_PARSE, + Q_DISABLE_RPL_PARSE, Q_EVAL_RESULT, + Q_ENABLE_QUERY_LOG, Q_DISABLE_QUERY_LOG, + Q_ENABLE_RESULT_LOG, Q_DISABLE_RESULT_LOG, + Q_WAIT_FOR_SLAVE_TO_STOP, + Q_ENABLE_WARNINGS, Q_DISABLE_WARNINGS, + Q_ENABLE_PS_WARNINGS, Q_DISABLE_PS_WARNINGS, + Q_ENABLE_INFO, Q_DISABLE_INFO, + Q_ENABLE_METADATA, Q_DISABLE_METADATA, + Q_EXEC, Q_DELIMITER, + Q_DISABLE_ABORT_ON_ERROR, Q_ENABLE_ABORT_ON_ERROR, + Q_DISPLAY_VERTICAL_RESULTS, Q_DISPLAY_HORIZONTAL_RESULTS, + Q_QUERY_VERTICAL, Q_QUERY_HORIZONTAL, + Q_START_TIMER, Q_END_TIMER, + Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL, + Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT, + Q_IF, + Q_DISABLE_PARSING, Q_ENABLE_PARSING, + Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST, + Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, + + Q_UNKNOWN, /* Unknown command. */ + Q_COMMENT, /* Comments, ignored. */ + Q_COMMENT_WITH_COMMAND +}; + const char *command_names[]= { @@ -348,16 +303,17 @@ const char *command_names[]= "enable_rpl_parse", "disable_rpl_parse", "eval_result", + /* Enable/disable that the _query_ is logged to result file */ "enable_query_log", "disable_query_log", + /* Enable/disable that the _result_ from a query is logged to result file */ "enable_result_log", "disable_result_log", - "server_start", - "server_stop", - "require_manager", "wait_for_slave_to_stop", "enable_warnings", "disable_warnings", + "enable_ps_warnings", + "disable_ps_warnings", "enable_info", "disable_info", "enable_metadata", @@ -375,80 +331,118 @@ const char *command_names[]= "character_set", "disable_ps_protocol", "enable_ps_protocol", - "exit", "disable_reconnect", "enable_reconnect", "if", + "disable_parsing", + "enable_parsing", + "replace_regex", + "remove_file", + "file_exists", + "write_file", + "copy_file", + "perl", + "die", 0 }; -/* Block stack */ -typedef struct + +/* + The list of error codes to --error are stored in an internal array of + structs. This struct can hold numeric SQL error codes, error names or + SQLSTATE codes as strings. The element next to the last active element + in the list is set to type ERR_EMPTY. When an SQL statement returns an + error, we use this list to check if this is an expected error. +*/ +enum match_err_type { - int line; /* Start line of block */ - my_bool ok; /* Should block be executed */ - enum enum_commands cmd; /* Command owning the block */ -} BLOCK; -static BLOCK block_stack[BLOCK_STACK_DEPTH]; -static BLOCK *cur_block, *block_stack_end; + ERR_EMPTY= 0, + ERR_ERRNO, + ERR_SQLSTATE +}; + +struct st_match_err +{ + enum match_err_type type; + union + { + uint errnum; + char sqlstate[SQLSTATE_LENGTH+1]; /* \0 terminated string */ + } code; +}; + +struct st_expected_errors +{ + struct st_match_err err[10]; + uint count; +}; +static struct st_expected_errors saved_expected_errors; + +struct st_command +{ + char *query, *query_buf,*first_argument,*last_argument,*end; + int first_word_len, query_len; + my_bool abort_on_error, require_file; + struct st_expected_errors expected_errors; + char record_file[FN_REFLEN]; + enum enum_commands type; +}; TYPELIB command_typelib= {array_elements(command_names),"", command_names, 0}; -DYNAMIC_STRING ds_res; -static void die(const char *fmt, ...); -static void init_var_hash(); -static VAR* var_from_env(const char *, const char *); -static byte* get_var_key(const byte* rec, uint* len, my_bool t); -static VAR* var_init(VAR* v, const char *name, int name_len, const char *val, - int val_len); +DYNAMIC_STRING ds_res, ds_progress; -static void var_free(void* v); +void die(const char *fmt, ...) + /* ATTRIBUTE_FORMAT(printf, 1, 2) */; +void abort_not_supported_test(const char *fmt, ...) + /* ATTRIBUTE_FORMAT(printf, 1, 2) */; +void verbose_msg(const char *fmt, ...) + /* ATTRIBUTE_FORMAT(printf, 1, 2) */; -int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname); -void reject_dump(const char *record_file, char *buf, int size); +VAR* var_from_env(const char *, const char *); +VAR* var_init(VAR* v, const char *name, int name_len, const char *val, + int val_len); +void var_free(void* v); +VAR* var_get(const char *var_name, const char** var_name_end, + my_bool raw, my_bool ignore_not_existing); +void eval_expr(VAR* v, const char *p, const char** p_end); +my_bool match_delimiter(int c, const char *delim, uint length); +void dump_result_to_reject_file(const char *record_file, char *buf, int size); +void dump_result_to_log_file(const char *record_file, char *buf, int size); -int close_connection(struct st_query*); -static void set_charset(struct st_query*); -VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, - my_bool ignore_not_existing); -int eval_expr(VAR* v, const char *p, const char** p_end); -static int read_server_arguments(const char *name); - -/* Definitions for replace result */ - -typedef struct st_pointer_array { /* when using array-strings */ - TYPELIB typelib; /* Pointer to strings */ - byte *str; /* Strings is here */ - int7 *flag; /* Flag about each var. */ - uint array_allocs,max_count,length,max_length; -} POINTER_ARRAY; - -struct st_replace; -struct st_replace *init_replace(my_string *from, my_string *to, uint count, - my_string word_end_chars); -uint replace_strings(struct st_replace *rep, my_string *start, - uint *max_length, const char *from); -void free_replace(); -static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name); -void free_pointer_array(POINTER_ARRAY *pa); -static int initialize_replace_buffer(void); -static void free_replace_buffer(void); -static void do_eval(DYNAMIC_STRING *query_eval, const char *query); +void do_eval(DYNAMIC_STRING *query_eval, const char *query, + const char *query_end, my_bool pass_through_escape_chars); void str_to_file(const char *fname, char *str, int size); -int do_server_op(struct st_query *q,const char *op); -struct st_replace *glob_replace; -static char *out_buff; -static uint out_length; +#ifdef __WIN__ +void free_tmp_sh_file(); +void free_win_path_patterns(); +#endif + static int eval_result = 0; -/* For column replace */ -char *replace_column[MAX_COLUMNS]; -uint max_replace_column= 0; +/* For replace_column */ +static char *replace_column[MAX_COLUMNS]; +static uint max_replace_column= 0; +void do_get_replace_column(struct st_command*); +void free_replace_column(); + +/* For replace */ +void do_get_replace(struct st_command *command); +void free_replace(); + +/* For replace_regex */ +void do_get_replace_regex(struct st_command *command); +void free_replace_regex(); + + +void free_all_replace(){ + free_replace(); + free_replace_regex(); + free_replace_column(); +} -static void get_replace_column(struct st_query *q); -static void free_replace_column(); /* Disable functions that only exist in MySQL 4.0 */ #if MYSQL_VERSION_ID < 40000 @@ -457,42 +451,64 @@ void mysql_disable_rpl_parse(MYSQL* mysql __attribute__((unused))) {} int mysql_rpl_parse_enabled(MYSQL* mysql __attribute__((unused))) { return 1; } my_bool mysql_rpl_probe(MYSQL *mysql __attribute__((unused))) { return 1; } #endif -static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, - int len); -static int handle_no_error(struct st_query *q); -static void do_eval(DYNAMIC_STRING* query_eval, const char *query) +void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, + int len); +void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val); +void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val); + +void handle_error(struct st_command*, + unsigned int err_errno, const char *err_error, + const char *err_sqlstate, DYNAMIC_STRING *ds); +void handle_no_error(struct st_command*); + + + +void do_eval(DYNAMIC_STRING *query_eval, const char *query, + const char *query_end, my_bool pass_through_escape_chars) { const char *p; - register char c; + register char c, next_c; register int escaped = 0; - VAR* v; + VAR *v; DBUG_ENTER("do_eval"); - for (p= query; (c = *p); ++p) + for (p= query; (c= *p) && p < query_end; ++p) { switch(c) { case '$': if (escaped) { - escaped = 0; + escaped= 0; dynstr_append_mem(query_eval, p, 1); } else { - if (!(v = var_get(p, &p, 0, 0))) + if (!(v= var_get(p, &p, 0, 0))) die("Bad variable in eval"); dynstr_append_mem(query_eval, v->str_val, v->str_val_len); } break; case '\\': + next_c= *(p+1); if (escaped) { - escaped = 0; + escaped= 0; dynstr_append_mem(query_eval, p, 1); } + else if (next_c == '\\' || next_c == '$' || next_c == '"') + { + /* Set escaped only if next char is \, " or $ */ + escaped= 1; + + if (pass_through_escape_chars) + { + /* The escape char should be added to the output string. */ + dynstr_append_mem(query_eval, p, 1); + } + } else - escaped = 1; + dynstr_append_mem(query_eval, p, 1); break; default: dynstr_append_mem(query_eval, p, 1); @@ -503,24 +519,148 @@ static void do_eval(DYNAMIC_STRING* query_eval, const char *query) } -static void close_cons() +enum arg_type { - DBUG_ENTER("close_cons"); - if (last_result) - mysql_free_result(last_result); - for (--next_con; next_con >= cons; --next_con) + ARG_STRING, + ARG_REST +}; + +struct command_arg { + const char *argname; /* Name of argument */ + enum arg_type type; /* Type of argument */ + my_bool required; /* Argument required */ + DYNAMIC_STRING *ds; /* Storage for argument */ + const char *description; /* Description of the argument */ +}; + + +void check_command_args(struct st_command *command, + const char *arguments, + const struct command_arg *args, + int num_args, const char delimiter_arg) +{ + int i; + const char *ptr= arguments; + const char *start; + + DBUG_ENTER("check_command_args"); + DBUG_PRINT("enter", ("num_args: %d", num_args)); + for (i= 0; i < num_args; i++) { + const struct command_arg *arg= &args[i]; + + switch (arg->type) + { + /* A string */ + case ARG_STRING: + /* Skip leading spaces */ + while (*ptr && *ptr == ' ') + ptr++; + start= ptr; + /* Find end of arg, terminated by "delimiter_arg" */ + while (*ptr && *ptr != delimiter_arg) + ptr++; + if (ptr > start) + { + init_dynamic_string(arg->ds, 0, ptr-start, 32); + do_eval(arg->ds, start, ptr, FALSE); + } + else + { + /* Empty string */ + init_dynamic_string(arg->ds, "", 0, 0); + } + command->last_argument= (char*)ptr; + + /* Step past the delimiter */ + if (*ptr && *ptr == delimiter_arg) + ptr++; + DBUG_PRINT("info", ("val: %s", arg->ds->str)); + break; + + /* Rest of line */ + case ARG_REST: + start= ptr; + init_dynamic_string(arg->ds, 0, command->query_len, 256); + do_eval(arg->ds, start, command->end, FALSE); + command->last_argument= command->end; + DBUG_PRINT("info", ("val: %s", arg->ds->str)); + break; + + default: + DBUG_ASSERT("Unknown argument type"); + break; + } + + /* Check required arg */ + if (arg->ds->length == 0 && arg->required) + die("Missing required argument '%s' to command '%.*s'", arg->argname, + command->first_word_len, command->query); + + } + DBUG_VOID_RETURN; +} + + +void handle_command_error(struct st_command *command, uint error) +{ + DBUG_ENTER("handle_command_error"); + DBUG_PRINT("enter", ("error: %d", error)); + if (error != 0) + { + uint i; + + if (command->abort_on_error) + die("command \"%.*s\" failed with error %d", + command->first_word_len, command->query, error); + for (i= 0; i < command->expected_errors.count; i++) + { + DBUG_PRINT("info", ("expected error: %d", + command->expected_errors.err[i].code.errnum)); + if ((command->expected_errors.err[i].type == ERR_ERRNO) && + (command->expected_errors.err[i].code.errnum == error)) + { + DBUG_PRINT("info", ("command \"%.*s\" failed with expected error: %d", + command->first_word_len, command->query, error)); + DBUG_VOID_RETURN; + } + } + die("command \"%.*s\" failed with wrong error: %d", + command->first_word_len, command->query, error); + } + else if (command->expected_errors.err[0].type == ERR_ERRNO && + command->expected_errors.err[0].code.errnum != 0) + { + /* Error code we wanted was != 0, i.e. not an expected success */ + die("command \"%.*s\" succeeded - should have failed with errno %d...", + command->first_word_len, command->query, + command->expected_errors.err[0].code.errnum); + } + DBUG_VOID_RETURN; +} + + +void close_connections() +{ + DBUG_ENTER("close_connections"); + for (--next_con; next_con >= connections; --next_con) + { + if (next_con->stmt) + mysql_stmt_close(next_con->stmt); + next_con->stmt= 0; mysql_close(&next_con->mysql); + if (next_con->util_mysql) + mysql_close(next_con->util_mysql); my_free(next_con->name, MYF(MY_ALLOW_ZERO_PTR)); } DBUG_VOID_RETURN; } -static void close_files() +void close_files() { DBUG_ENTER("close_files"); - for (; cur_file != (file_stack-1) ; cur_file--) + for (; cur_file >= file_stack; cur_file--) { DBUG_PRINT("info", ("file_name: %s", cur_file->file_name)); if (cur_file->file && cur_file->file != stdin) @@ -532,25 +672,22 @@ static void close_files() } -static void free_used_memory() +void free_used_memory() { uint i; DBUG_ENTER("free_used_memory"); -#ifndef EMBEDDED_LIBRARY - if (manager) - mysql_manager_close(manager); -#endif - close_cons(); + + close_connections(); close_files(); hash_free(&var_hash); - for (i=0 ; i < q_lines.elements ; i++) + for (i= 0 ; i < q_lines.elements ; i++) { - struct st_query **q= dynamic_element(&q_lines, i, struct st_query**); + struct st_command **q= dynamic_element(&q_lines, i, struct st_command**); my_free((gptr) (*q)->query_buf,MYF(MY_ALLOW_ZERO_PTR)); my_free((gptr) (*q),MYF(0)); } - for (i=0; i < 10; i++) + for (i= 0; i < 10; i++) { if (var_reg[i].alloced_len) my_free(var_reg[i].str_val, MYF(MY_WME)); @@ -559,23 +696,35 @@ static void free_used_memory() my_free(embedded_server_args[--embedded_server_arg_count],MYF(0)); delete_dynamic(&q_lines); dynstr_free(&ds_res); - free_replace(); - free_replace_column(); + dynstr_free(&ds_progress); + free_all_replace(); my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); free_defaults(default_argv); mysql_server_end(); - if (ps_protocol) - ps_free_reg(); + free_re(); +#ifdef __WIN__ + free_tmp_sh_file(); + free_win_path_patterns(); +#endif DBUG_VOID_RETURN; } -static void die(const char *fmt, ...) + +void die(const char *fmt, ...) { va_list args; DBUG_ENTER("die"); + DBUG_PRINT("enter", ("start_lineno: %d", start_lineno)); + + /* Print the error message */ va_start(args, fmt); if (fmt) { +#ifdef DBUG_ON + char buff[256]; + vsnprintf(buff, sizeof(buff), fmt, args); + DBUG_PRINT("error", ("%s", buff)); +#endif fprintf(stderr, "mysqltest: "); if (cur_file && cur_file != file_stack) fprintf(stderr, "In included file \"%s\": ", @@ -587,25 +736,69 @@ static void die(const char *fmt, ...) fflush(stderr); } va_end(args); + + /* Dump the result that has been accumulated so far to .log file */ + if (result_file && ds_res.length) + dump_result_to_log_file(result_file, ds_res.str, ds_res.length); + + /* Clean up and exit */ free_used_memory(); my_end(MY_CHECK_ERROR); + + if (!silent) + printf("not ok\n"); + exit(1); } -/* Note that we will get some memory leaks when calling this! */ -static void abort_not_supported_test() +void abort_not_supported_test(const char *fmt, ...) { + va_list args; + struct st_test_file* err_file= cur_file; DBUG_ENTER("abort_not_supported_test"); - fprintf(stderr, "This test is not supported by this installation\n"); - if (!silent) - printf("skipped\n"); + + /* Print include filestack */ + fprintf(stderr, "The test '%s' is not supported by this installation\n", + file_stack->file_name); + fprintf(stderr, "Detected in file %s at line %d\n", + err_file->file_name, err_file->lineno); + while (err_file != file_stack) + { + err_file--; + fprintf(stderr, "included from %s at line %d\n", + err_file->file_name, err_file->lineno); + } + + /* Print error message */ + va_start(args, fmt); + if (fmt) + { + fprintf(stderr, "reason: "); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + fflush(stderr); + } + va_end(args); + + /* Clean up and exit */ free_used_memory(); my_end(MY_CHECK_ERROR); + + if (!silent) + printf("skipped\n"); + exit(62); } -static void verbose_msg(const char *fmt, ...) + +void abort_not_in_this_version() +{ + die("Not available in mysqltest for MySQL %s", VERSION); +} + + +void verbose_msg(const char *fmt, ...) { va_list args; DBUG_ENTER("verbose_msg"); @@ -613,23 +806,20 @@ static void verbose_msg(const char *fmt, ...) DBUG_VOID_RETURN; va_start(args, fmt); - fprintf(stderr, "mysqltest: "); - if (start_lineno > 0) + if (start_lineno != 0) fprintf(stderr, "At line %u: ", start_lineno); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); va_end(args); + DBUG_VOID_RETURN; } -void init_parser() -{ - parser.current_line= parser.read_lines= 0; - memset(&var_reg, 0, sizeof(var_reg)); -} - +/* + Compare content of the string ds to content of file fname +*/ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) { @@ -645,10 +835,10 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) if (!test_if_hard_path(fname)) { strxmov(eval_file, opt_basedir, fname, NullS); - fn_format(eval_file, eval_file,"","",4); + fn_format(eval_file, eval_file, "", "", MY_UNPACK_FILENAME); } else - fn_format(eval_file, fname,"","",4); + fn_format(eval_file, fname, "", "", MY_UNPACK_FILENAME); if (!my_stat(eval_file, &stat_info, MYF(MY_WME))) die(NullS); @@ -656,22 +846,24 @@ 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_PRINT("info",("result: '%s'", ds->str)); DBUG_RETURN(RESULT_LENGTH_MISMATCH); } if (!(tmp = (char*) my_malloc(stat_info.st_size + 1, MYF(MY_WME)))) - die(NullS); + die("Out of memory"); if ((fd = my_open(eval_file, O_RDONLY, MYF(MY_WME))) < 0) - die(NullS); + die("Failed to open file %s", eval_file); if (my_read(fd, (byte*)tmp, stat_info.st_size, MYF(MY_WME|MY_NABP))) - die(NullS); + die("Failed to read from file %s, errno: %d", eval_file, errno); tmp[stat_info.st_size] = 0; - init_dynamic_string(&res_ds, "", 0, 65536); + init_dynamic_string(&res_ds, "", stat_info.st_size+256, 256); if (eval_result) { - do_eval(&res_ds, tmp); - res_ptr = res_ds.str; - if ((res_len = res_ds.length) != ds->length) + do_eval(&res_ds, tmp, tmp + stat_info.st_size, FALSE); + res_ptr= res_ds.str; + res_len= res_ds.length; + if (res_len != ds->length) { res= RESULT_LENGTH_MISMATCH; goto err; @@ -688,51 +880,138 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) err: if (res && eval_result) - str_to_file(fn_format(eval_file, fname, "", ".eval",2), res_ptr, - res_len); + str_to_file(fn_format(eval_file, fname, "", ".eval", + MY_REPLACE_EXT), + res_ptr, res_len); + dynstr_free(&res_ds); my_free((gptr) tmp, MYF(0)); my_close(fd, MYF(MY_WME)); - dynstr_free(&res_ds); DBUG_RETURN(res); } -static int check_result(DYNAMIC_STRING* ds, const char *fname, - my_bool require_option) + +/* + Check the content of ds against content of file fname + + SYNOPSIS + check_result + ds - content to be checked + fname - name of file to check against + require_option - if set and check fails, the test will be aborted + with the special exit code "not supported test" + + RETURN VALUES + error - the function will not return + +*/ + +void check_result(DYNAMIC_STRING* ds, const char *fname, + my_bool require_option) { - int error= RESULT_OK; int res= dyn_string_cmp(ds, fname); + DBUG_ENTER("check_result"); if (res && require_option) - abort_not_supported_test(); + { + char reason[FN_REFLEN]; + fn_format(reason, fname, "", "", MY_REPLACE_EXT | MY_REPLACE_DIR); + abort_not_supported_test("Test requires: '%s'", reason); + } switch (res) { case RESULT_OK: break; /* ok */ case RESULT_LENGTH_MISMATCH: - verbose_msg("Result length mismatch"); - error= RESULT_LENGTH_MISMATCH; + dump_result_to_reject_file(fname, ds->str, ds->length); + die("Result length mismatch"); break; case RESULT_CONTENT_MISMATCH: - verbose_msg("Result content mismatch"); - error= RESULT_CONTENT_MISMATCH; + dump_result_to_reject_file(fname, ds->str, ds->length); + die("Result content mismatch"); break; default: /* impossible */ die("Unknown error code from dyn_string_cmp()"); } - if (error) - reject_dump(fname, ds->str, ds->length); - return error; + + DBUG_VOID_RETURN; } -VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, +static byte *get_var_key(const byte* var, uint* len, + my_bool __attribute__((unused)) t) +{ + register char* key; + key = ((VAR*)var)->name; + *len = ((VAR*)var)->name_len; + return (byte*)key; +} + + +VAR *var_init(VAR *v, const char *name, int name_len, const char *val, + int val_len) +{ + int val_alloc_len; + VAR *tmp_var; + if (!name_len && name) + name_len = strlen(name); + if (!val_len && val) + val_len = strlen(val) ; + val_alloc_len = val_len + 16; /* room to grow */ + if (!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(sizeof(*tmp_var) + + name_len+1, MYF(MY_WME)))) + die("Out of memory"); + + tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0; + tmp_var->alloced = (v == 0); + + if (!(tmp_var->str_val = my_malloc(val_alloc_len+1, MYF(MY_WME)))) + die("Out of memory"); + + memcpy(tmp_var->name, name, name_len); + if (val) + { + memcpy(tmp_var->str_val, val, val_len); + tmp_var->str_val[val_len]= 0; + } + tmp_var->name_len = name_len; + tmp_var->str_val_len = val_len; + tmp_var->alloced_len = val_alloc_len; + tmp_var->int_val = (val) ? atoi(val) : 0; + tmp_var->int_dirty = 0; + tmp_var->env_s = 0; + return tmp_var; +} + + +void var_free(void *v) +{ + my_free(((VAR*) v)->str_val, MYF(MY_WME)); + if (((VAR*)v)->alloced) + my_free((char*) v, MYF(MY_WME)); +} + + +VAR* var_from_env(const char *name, const char *def_val) +{ + const char *tmp; + VAR *v; + if (!(tmp = getenv(name))) + tmp = def_val; + + v = var_init(0, name, strlen(name), tmp, strlen(tmp)); + my_hash_insert(&var_hash, (byte*)v); + return v; +} + + +VAR* var_get(const char *var_name, const char **var_name_end, my_bool raw, my_bool ignore_not_existing) { int digit; - VAR* v; + VAR *v; DBUG_ENTER("var_get"); - DBUG_PRINT("enter",("var_name: %s",var_name)); + DBUG_PRINT("enter", ("var_name: %s",var_name)); if (*var_name != '$') goto err; @@ -751,16 +1030,16 @@ VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, die("Empty variable"); } length= (uint) (var_name - save_var_name); - if (length >= MAX_VAR_NAME) + if (length >= MAX_VAR_NAME_LENGTH) die("Too long variable name: %s", save_var_name); if (!(v = (VAR*) hash_search(&var_hash, save_var_name, length))) { - char buff[MAX_VAR_NAME+1]; + char buff[MAX_VAR_NAME_LENGTH+1]; strmake(buff, save_var_name, length); v= var_from_env(buff, ""); } - var_name--; /* Point at last character */ + var_name--; /* Point at last character */ } else v = var_reg + digit; @@ -781,7 +1060,8 @@ err: DBUG_RETURN(0); } -static VAR *var_obtain(const char *name, int len) + +VAR *var_obtain(const char *name, int len) { VAR* v; if ((v = (VAR*)hash_search(&var_hash, name, len))) @@ -791,30 +1071,231 @@ static VAR *var_obtain(const char *name, int len) return v; } -int var_set(const char *var_name, const char *var_name_end, - const char *var_val, const char *var_val_end) + +/* + - if variable starts with a $ it is regarded as a local test varable + - if not it is treated as a environment variable, and the corresponding + environment variable will be updated +*/ + +void var_set(const char *var_name, const char *var_name_end, + const char *var_val, const char *var_val_end) { - int digit; - VAR* v; + int digit, env_var= 0; + VAR *v; DBUG_ENTER("var_set"); DBUG_PRINT("enter", ("var_name: '%.*s' = '%.*s' (length: %d)", (int) (var_name_end - var_name), var_name, (int) (var_val_end - var_val), var_val, (int) (var_val_end - var_val))); - if (*var_name++ != '$') - { - var_name--; - die("Variable name in %s does not start with '$'", var_name); - } - digit = *var_name - '0'; + if (*var_name != '$') + env_var= 1; + else + var_name++; + + digit= *var_name - '0'; if (!(digit < 10 && digit >= 0)) { - v = var_obtain(var_name, (uint) (var_name_end - var_name)); + v= var_obtain(var_name, (uint) (var_name_end - var_name)); } else - v = var_reg + digit; - DBUG_RETURN(eval_expr(v, var_val, (const char**)&var_val_end)); + v= var_reg + digit; + + eval_expr(v, var_val, (const char**) &var_val_end); + + if (env_var) + { + char buf[1024], *old_env_s= v->env_s; + if (v->int_dirty) + { + sprintf(v->str_val, "%d", v->int_val); + v->int_dirty= 0; + v->str_val_len= strlen(v->str_val); + } + strxmov(buf, v->name, "=", v->str_val, NullS); + if (!(v->env_s= my_strdup(buf, MYF(MY_WME)))) + die("Out of memory"); + putenv(v->env_s); + my_free((gptr)old_env_s, MYF(MY_ALLOW_ZERO_PTR)); + } + DBUG_VOID_RETURN; +} + +/* + Store an integer (typically the returncode of the last SQL) + statement in the mysqltest builtin variable $mysql_errno, by + simulating of a user statement "let $mysql_errno= " +*/ + +void var_set_errno(int sql_errno) +{ + /* TODO MASV make easier */ + const char *var_name= "$mysql_errno"; + char var_val[21]; + uint length= my_sprintf(var_val, (var_val, "%d", sql_errno)); + var_set(var_name, var_name + 12, var_val, var_val + length); + return; +} + + +/* + Set variable from the result of a query + + SYNOPSIS + var_query_set() + var variable to set from query + query start of query string to execute + query_end end of the query string to execute + + + DESCRIPTION + let @ = `` + + Execute the query and assign the first row of result to var as + a tab separated strings + + Also assign each column of the result set to + variable "$_" + Thus the tab separated output can be read from $ and + and each individual column can be read as $_ + +*/ + +void var_query_set(VAR *var, const char *query, const char** query_end) +{ + char* end = (char*)((query_end && *query_end) ? + *query_end : query + strlen(query)); + MYSQL_RES *res; + MYSQL_ROW row; + MYSQL* mysql = &cur_con->mysql; + DBUG_ENTER("var_query_set"); + LINT_INIT(res); + + while (end > query && *end != '`') + --end; + if (query == end) + die("Syntax error in query, missing '`'"); + ++query; + + if (mysql_real_query(mysql, query, (int)(end - query)) || + !(res = mysql_store_result(mysql))) + { + *end = 0; + die("Error running query '%s': %d %s", query, + mysql_errno(mysql), mysql_error(mysql)); + } + + if ((row = mysql_fetch_row(res)) && row[0]) + { + /* + Concatenate all row results with tab in between to allow us to work + with results from many columns (for example from SHOW VARIABLES) + */ + DYNAMIC_STRING result; + uint i; + ulong *lengths; + char *end; +#ifdef NOT_YET + MYSQL_FIELD *fields= mysql_fetch_fields(res); +#endif + + init_dynamic_string(&result, "", 2048, 2048); + lengths= mysql_fetch_lengths(res); + for (i=0; i < mysql_num_fields(res); i++) + { + if (row[0]) + { +#ifdef NOT_YET + /* Add to _ */ + uint j; + char var_col_name[MAX_VAR_NAME_LENGTH]; + uint length= snprintf(var_col_name, MAX_VAR_NAME_LENGTH, + "$%s_%s", var->name, fields[i].name); + /* Convert characters not allowed in variable names to '_' */ + for (j= 1; j < length; j++) + { + if (!my_isvar(charset_info,var_col_name[j])) + var_col_name[j]= '_'; + } + var_set(var_col_name, var_col_name + length, + row[i], row[i] + lengths[i]); +#endif + /* Add column to tab separated string */ + dynstr_append_mem(&result, row[i], lengths[i]); + } + dynstr_append_mem(&result, "\t", 1); + } + end= result.str + result.length-1; + eval_expr(var, result.str, (const char**) &end); + dynstr_free(&result); + } + else + eval_expr(var, "", 0); + + mysql_free_result(res); + DBUG_VOID_RETURN; +} + + +void var_copy(VAR *dest, VAR *src) +{ + dest->int_val= src->int_val; + dest->int_dirty= src->int_dirty; + + /* Alloc/realloc data for str_val in dest */ + if (dest->alloced_len < src->alloced_len && + !(dest->str_val= dest->str_val + ? my_realloc(dest->str_val, src->alloced_len, MYF(MY_WME)) + : my_malloc(src->alloced_len, MYF(MY_WME)))) + die("Out of memory"); + else + dest->alloced_len= src->alloced_len; + + /* Copy str_val data to dest */ + dest->str_val_len= src->str_val_len; + if (src->str_val_len) + memcpy(dest->str_val, src->str_val, src->str_val_len); +} + + +void eval_expr(VAR *v, const char *p, const char **p_end) +{ + static int MIN_VAR_ALLOC= 32; /* MASV why 32? */ + VAR *vp; + if (*p == '$') + { + if ((vp= var_get(p, p_end, 0, 0))) + { + var_copy(v, vp); + return; + } + } + else if (*p == '`') + { + var_query_set(v, p, p_end); + } + else + { + int new_val_len = (p_end && *p_end) ? + (int) (*p_end - p) : (int) strlen(p); + if (new_val_len + 1 >= v->alloced_len) + { + v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ? + MIN_VAR_ALLOC : new_val_len + 1; + if (!(v->str_val = + v->str_val ? my_realloc(v->str_val, v->alloced_len+1, + MYF(MY_WME)) : + my_malloc(v->alloced_len+1, MYF(MY_WME)))) + die("Out of memory"); + } + v->str_val_len = new_val_len; + memcpy(v->str_val, p, new_val_len); + v->str_val[new_val_len] = 0; + v->int_val=atoi(p); + v->int_dirty=0; + } + return; } @@ -828,7 +1309,7 @@ int open_file(const char *name) strxmov(buff, opt_basedir, name, NullS); name=buff; } - fn_format(buff,name,"","",4); + fn_format(buff, name, "", "", MY_UNPACK_FILENAME); if (cur_file == file_stack_end) die("Source directives are nesting too deep"); @@ -839,43 +1320,640 @@ int open_file(const char *name) die("Could not open file %s", buff); } cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); - *++lineno=1; + cur_file->lineno=1; DBUG_RETURN(0); } /* - Check for unexpected "junk" after the end of query - This is normally caused by missing delimiters + Source and execute the given file + + SYNOPSIS + do_source() + query called command + + DESCRIPTION + source + + Open the file and execute it + */ -int check_eol_junk(const char *eol) +void do_source(struct st_command *command) { - const char *p= eol; - DBUG_ENTER("check_eol_junk"); - DBUG_PRINT("enter", ("eol: %s", eol)); - /* Remove all spacing chars except new line */ - while (*p && my_isspace(charset_info, *p) && (*p != '\n')) - p++; + DYNAMIC_STRING ds_filename; + const struct command_arg source_args[] = { + "filename", ARG_STRING, TRUE, &ds_filename, "File to source" + }; + DBUG_ENTER("do_source"); - /* Check for extra delimiter */ - if (*p && !strncmp(p, delimiter, delimiter_length)) - die("Extra delimiter \"%s\" found", delimiter); + check_command_args(command, command->first_argument, source_args, + sizeof(source_args)/sizeof(struct command_arg), + ' '); - /* Allow trailing # comment */ - if (*p && *p != '#') + /* + If this file has already been sourced, don't source it again. + It's already available in the q_lines cache. + */ + if (parser.current_line < (parser.read_lines - 1)) + ; /* Do nothing */ + else { - if (*p == '\n') - die("Missing delimiter"); - die("End of line junk detected: \"%s\"", p); + DBUG_PRINT("info", ("sourcing file: %s", ds_filename.str)); + open_file(ds_filename.str); } - DBUG_RETURN(0); + + dynstr_free(&ds_filename); + return; } -/* ugly long name, but we are following the convention */ -int do_wait_for_slave_to_stop(struct st_query *q __attribute__((unused))) +#ifdef __WIN__ +/* Variables used for temuprary sh files used for emulating Unix on Windows */ +char tmp_sh_name[64], tmp_sh_cmd[70]; + +void init_tmp_sh_file() { + /* Format a name for the tmp sh file that is unique for this process */ + my_snprintf(tmp_sh_name, sizeof(tmp_sh_name), "tmp_%d.sh", getpid()); + /* Format the command to execute in order to run the script */ + my_snprintf(tmp_sh_cmd, sizeof(tmp_sh_cmd), "sh %s", tmp_sh_name); +} + + +void free_tmp_sh_file() +{ + my_delete(tmp_sh_name, MYF(0)); +} +#endif + + +FILE* my_popen(DYNAMIC_STRING *ds_cmd, const char *mode) +{ +#ifdef __WIN__ + /* Dump the command into a sh script file and execute with popen */ + str_to_file(tmp_sh_name, ds_cmd->str, ds_cmd->length); + return popen(tmp_sh_cmd, mode); +#else + return popen(ds_cmd->str, mode); +#endif +} + + +/* + Execute given command. + + SYNOPSIS + do_exec() + query called command + + DESCRIPTION + exec + + Execute the text between exec and end of line in a subprocess. + The error code returned from the subprocess is checked against the + expected error array, previously set with the --error command. + It can thus be used to execute a command that shall fail. + + NOTE + Although mysqltest is executed from cygwin shell, the command will be + executed in "cmd.exe". Thus commands like "rm" etc can NOT be used, use + system for those commands. +*/ + +void do_exec(struct st_command *command) +{ + int error; + char buf[1024]; + FILE *res_file; + char *cmd= command->first_argument; + DYNAMIC_STRING ds_cmd; + DBUG_ENTER("do_exec"); + DBUG_PRINT("enter", ("cmd: '%s'", cmd)); + + while (*cmd && my_isspace(charset_info, *cmd)) + cmd++; + if (!*cmd) + die("Missing argument in exec"); + command->last_argument= command->end; + + init_dynamic_string(&ds_cmd, 0, command->query_len+256, 256); + /* Eval the command, thus replacing all environment variables */ + do_eval(&ds_cmd, cmd, command->end, TRUE); + cmd= ds_cmd.str; + + DBUG_PRINT("info", ("Executing '%s' as '%s'", + command->first_argument, cmd)); + + if (!(res_file= my_popen(&ds_cmd, "r")) && command->abort_on_error) + die("popen(\"%s\", \"r\") failed", command->first_argument); + + while (fgets(buf, sizeof(buf), res_file)) + { + if (disable_result_log) + { + buf[strlen(buf)-1]=0; + DBUG_PRINT("exec_result",("%s", buf)); + } + else + { + replace_dynstr_append(&ds_res, buf); + } + } + error= pclose(res_file); + if (error > 0) + { + uint status= WEXITSTATUS(error), i; + my_bool ok= 0; + + if (command->abort_on_error) + die("command \"%s\" failed", command->first_argument); + + DBUG_PRINT("info", + ("error: %d, status: %d", error, status)); + for (i= 0; i < command->expected_errors.count; i++) + { + DBUG_PRINT("info", ("expected error: %d", + command->expected_errors.err[i].code.errnum)); + if ((command->expected_errors.err[i].type == ERR_ERRNO) && + (command->expected_errors.err[i].code.errnum == status)) + { + ok= 1; + DBUG_PRINT("info", ("command \"%s\" failed with expected error: %d", + command->first_argument, status)); + } + } + if (!ok) + die("command \"%s\" failed with wrong error: %d", + command->first_argument, status); + } + else if (command->expected_errors.err[0].type == ERR_ERRNO && + command->expected_errors.err[0].code.errnum != 0) + { + /* Error code we wanted was != 0, i.e. not an expected success */ + die("command \"%s\" succeeded - should have failed with errno %d...", + command->first_argument, command->expected_errors.err[0].code.errnum); + } + + dynstr_free(&ds_cmd); + DBUG_VOID_RETURN; +} + +enum enum_operator +{ + DO_DEC, + DO_INC +}; + + +/* + Decrease or increase the value of a variable + + SYNOPSIS + do_modify_var() + query called command + operator operation to perform on the var + + DESCRIPTION + dec $var_name + inc $var_name + +*/ + +int do_modify_var(struct st_command *command, + enum enum_operator operator) +{ + const char *p= command->first_argument; + VAR* v; + if (!*p) + die("Missing argument to %.*s", command->first_word_len, command->query); + if (*p != '$') + die("The argument to %.*s must be a variable (start with $)", + command->first_word_len, command->query); + v= var_get(p, &p, 1, 0); + switch (operator) { + case DO_DEC: + v->int_val--; + break; + case DO_INC: + v->int_val++; + break; + default: + die("Invalid operator to do_modify_var"); + break; + } + v->int_dirty= 1; + command->last_argument= (char*)++p; + return 0; +} + + +/* + Wrapper for 'system' function + + NOTE + If mysqltest is executed from cygwin shell, the command will be + executed in the "windows command interpreter" cmd.exe and we prepend "sh" + to make it be executed by cygwins "bash". Thus commands like "rm", + "mkdir" as well as shellscripts can executed by "system" in Windows. + +*/ + +int my_system(DYNAMIC_STRING* ds_cmd) +{ +#ifdef __WIN__ + /* Dump the command into a sh script file and execute with system */ + str_to_file(tmp_sh_name, ds_cmd->str, ds_cmd->length); + return system(tmp_sh_cmd); +#else + return system(ds_cmd->str); +#endif +} + + +/* + SYNOPSIS + do_system + command called command + + DESCRIPTION + system + + Eval the query to expand any $variables in the command. + Execute the command with the "system" command. + +*/ + +void do_system(struct st_command *command) +{ + DYNAMIC_STRING ds_cmd; + DBUG_ENTER("do_system"); + + if (strlen(command->first_argument) == 0) + die("Missing arguments to system, nothing to do!"); + + init_dynamic_string(&ds_cmd, 0, command->query_len + 64, 256); + + /* Eval the system command, thus replacing all environment variables */ + do_eval(&ds_cmd, command->first_argument, command->end, TRUE); + + DBUG_PRINT("info", ("running system command '%s' as '%s'", + command->first_argument, ds_cmd.str)); + if (my_system(&ds_cmd)) + { + if (command->abort_on_error) + die("system command '%s' failed", command->first_argument); + + /* If ! abort_on_error, log message and continue */ + dynstr_append(&ds_res, "system command '"); + replace_dynstr_append(&ds_res, command->first_argument); + dynstr_append(&ds_res, "' failed\n"); + } + + command->last_argument= command->end; + dynstr_free(&ds_cmd); + DBUG_VOID_RETURN; +} + + +/* + SYNOPSIS + do_remove_file + command called command + + DESCRIPTION + remove_file + Remove the file +*/ + +void do_remove_file(struct st_command *command) +{ + int error; + DYNAMIC_STRING ds_filename; + const struct command_arg rm_args[] = { + "filename", ARG_STRING, TRUE, &ds_filename, "File to delete" + }; + DBUG_ENTER("do_remove_file"); + + check_command_args(command, command->first_argument, + rm_args, sizeof(rm_args)/sizeof(struct command_arg), + ' '); + + DBUG_PRINT("info", ("removing file: %s", ds_filename.str)); + error= my_delete(ds_filename.str, MYF(0)) != 0; + handle_command_error(command, error); + dynstr_free(&ds_filename); + DBUG_VOID_RETURN; +} + + +/* + SYNOPSIS + do_copy_file + command command handle + + DESCRIPTION + copy_file + Copy to + + NOTE! Will fail if exists +*/ + +void do_copy_file(struct st_command *command) +{ + int error; + DYNAMIC_STRING ds_from_file; + DYNAMIC_STRING ds_to_file; + const struct command_arg copy_file_args[] = { + "from_file", ARG_STRING, TRUE, &ds_from_file, "Filename to copy from", + "to_file", ARG_STRING, TRUE, &ds_to_file, "Filename to copy to" + }; + DBUG_ENTER("do_copy_file"); + + check_command_args(command, command->first_argument, + copy_file_args, + sizeof(copy_file_args)/sizeof(struct command_arg), + ' '); + + DBUG_PRINT("info", ("Copy %s to %s", ds_from_file.str, ds_to_file.str)); + error= (my_copy(ds_from_file.str, ds_to_file.str, + MYF(MY_DONT_OVERWRITE_FILE)) != 0); + handle_command_error(command, error); + dynstr_free(&ds_from_file); + dynstr_free(&ds_to_file); + DBUG_VOID_RETURN; +} + + +/* + SYNOPSIS + do_file_exists + command called command + + DESCRIPTION + fiile_exist + Check if file exists +*/ + +void do_file_exist(struct st_command *command) +{ + int error; + DYNAMIC_STRING ds_filename; + const struct command_arg file_exist_args[] = { + "filename", ARG_STRING, TRUE, &ds_filename, "File to check if it exist" + }; + DBUG_ENTER("do_file_exist"); + + check_command_args(command, command->first_argument, + file_exist_args, + sizeof(file_exist_args)/sizeof(struct command_arg), + ' '); + + DBUG_PRINT("info", ("Checking for existence of file: %s", ds_filename.str)); + error= (access(ds_filename.str, F_OK) != 0); + handle_command_error(command, error); + dynstr_free(&ds_filename); + DBUG_VOID_RETURN; +} + + +/* + Read characters from line buffer or file. This is needed to allow + my_ungetc() to buffer MAX_DELIMITER_LENGTH characters for a file + + NOTE: + This works as long as one doesn't change files (with 'source file_name') + when there is things pushed into the buffer. This should however not + happen for any tests in the test suite. +*/ + +int my_getc(FILE *file) +{ + if (line_buffer_pos == line_buffer) + return fgetc(file); + return *--line_buffer_pos; +} + + +void my_ungetc(int c) +{ + *line_buffer_pos++= (char) c; +} + + +void read_until_delimiter(DYNAMIC_STRING *ds, + DYNAMIC_STRING *ds_delimiter) +{ + int c; + DBUG_ENTER("read_until_delimiter"); + DBUG_PRINT("enter", ("delimiter: %s, length: %d", + ds_delimiter->str, ds_delimiter->length)); + + if (ds_delimiter->length > MAX_DELIMITER_LENGTH) + die("Max delimiter length(%d) exceeded", MAX_DELIMITER_LENGTH); + + /* Read from file until delimiter is found */ + while (1) + { + c= my_getc(cur_file->file); + + if (c == '\n') + cur_file->lineno++; + + if (feof(cur_file->file)) + die("End of file encountered before '%s' delimiter was found", + ds_delimiter->str); + + if (match_delimiter(c, ds_delimiter->str, ds_delimiter->length)) + { + DBUG_PRINT("exit", ("Found delimiter '%s'", ds_delimiter->str)); + break; + } + dynstr_append_mem(ds, (const char*)&c, 1); + } + DBUG_PRINT("exit", ("ds: %s", ds->str)); + DBUG_VOID_RETURN; +} + + +/* + SYNOPSIS + do_write_file + command called command + + DESCRIPTION + write_file []; + + <...> + < what to write line n> + EOF + + --write_file ; + + <...> + < what to write line n> + EOF + + Write everything between the "write_file" command and 'delimiter' + to "file_name" + + NOTE! Overwrites existing file + + Default is EOF + +*/ + +void do_write_file(struct st_command *command) +{ + DYNAMIC_STRING ds_content; + DYNAMIC_STRING ds_filename; + DYNAMIC_STRING ds_delimiter; + const struct command_arg write_file_args[] = { + "filename", ARG_STRING, TRUE, &ds_filename, "File to write to", + "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" + }; + DBUG_ENTER("do_write_file"); + + check_command_args(command, + command->first_argument, + write_file_args, + sizeof(write_file_args)/sizeof(struct command_arg), + ' '); + + /* If no delimiter was provided, use EOF */ + if (ds_delimiter.length == 0) + dynstr_set(&ds_delimiter, "EOF"); + + init_dynamic_string(&ds_content, "", 1024, 1024); + read_until_delimiter(&ds_content, &ds_delimiter); + DBUG_PRINT("info", ("Writing to file: %s", ds_filename.str)); + str_to_file(ds_filename.str, ds_content.str, ds_content.length); + dynstr_free(&ds_content); + dynstr_free(&ds_filename); + dynstr_free(&ds_delimiter); + DBUG_VOID_RETURN; +} + + +/* + SYNOPSIS + do_perl + command command handle + + DESCRIPTION + perl []; + + <...> + + EOF + + Execute everything after "perl" until as perl. + Useful for doing more advanced things + but still being able to execute it on all platforms. + + Default is EOF +*/ + +void do_perl(struct st_command *command) +{ + int error; + char buf[FN_REFLEN]; + FILE *res_file; + DYNAMIC_STRING ds_script; + DYNAMIC_STRING ds_delimiter; + const struct command_arg perl_args[] = { + "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" + }; + DBUG_ENTER("do_perl"); + + check_command_args(command, + command->first_argument, + perl_args, + sizeof(perl_args)/sizeof(struct command_arg), + ' '); + + /* If no delimiter was provided, use EOF */ + if (ds_delimiter.length == 0) + dynstr_set(&ds_delimiter, "EOF"); + + init_dynamic_string(&ds_script, "", 1024, 1024); + read_until_delimiter(&ds_script, &ds_delimiter); + + DBUG_PRINT("info", ("Executing perl: %s", ds_script.str)); + + /* Format a name for a tmp .pl file that is unique for this process */ + my_snprintf(buf, sizeof(buf), "%s/tmp/tmp_%d.pl", + getenv("MYSQLTEST_VARDIR"), getpid()); + str_to_file(buf, ds_script.str, ds_script.length); + + /* Format the perl command */ + my_snprintf(buf, sizeof(buf), "perl %s/tmp/tmp_%d.pl", + getenv("MYSQLTEST_VARDIR"), getpid()); + + if (!(res_file= popen(buf, "r")) && command->abort_on_error) + die("popen(\"%s\", \"r\") failed", buf); + + while (fgets(buf, sizeof(buf), res_file)) + { + if (disable_result_log) + { + buf[strlen(buf)-1]=0; + DBUG_PRINT("exec_result",("%s", buf)); + } + else + { + replace_dynstr_append(&ds_res, buf); + } + } + error= pclose(res_file); + handle_command_error(command, WEXITSTATUS(error)); + dynstr_free(&ds_script); + dynstr_free(&ds_delimiter); + DBUG_VOID_RETURN; +} + + +/* + Print the content between echo and to result file. + Evaluate all variables in the string before printing, allow + for variable names to be escaped using \ + + SYNOPSIS + do_echo() + command called command + + DESCRIPTION + echo text + Print the text after echo until end of command to result file + + echo $ + Print the content of the variable to result file + + echo Some text $ + Print "Some text" plus the content of the variable to + result file + + echo Some text \$ + Print "Some text" plus $ to result file +*/ + +int do_echo(struct st_command *command) +{ + DYNAMIC_STRING ds_echo; + + init_dynamic_string(&ds_echo, "", command->query_len, 256); + do_eval(&ds_echo, command->first_argument, command->end, FALSE); + dynstr_append_mem(&ds_res, ds_echo.str, ds_echo.length); + dynstr_append_mem(&ds_res, "\n", 1); + dynstr_free(&ds_echo); + command->last_argument= command->end; + return(0); +} + + +void do_wait_for_slave_to_stop(struct st_command *c __attribute__((unused))) +{ + static int SLAVE_POLL_INTERVAL= 300000; MYSQL* mysql = &cur_con->mysql; for (;;) { @@ -899,454 +1977,15 @@ int do_wait_for_slave_to_stop(struct st_query *q __attribute__((unused))) break; my_sleep(SLAVE_POLL_INTERVAL); } - return 0; -} - -int do_require_manager(struct st_query *query __attribute__((unused)) ) -{ - if (!manager) - abort_not_supported_test(); - return 0; -} - -#ifndef EMBEDDED_LIBRARY -int do_server_start(struct st_query *q) -{ - return do_server_op(q, "start"); -} - -int do_server_stop(struct st_query *q) -{ - return do_server_op(q, "stop"); -} - -int do_server_op(struct st_query *q, const char *op) -{ - char *p= q->first_argument; - char com_buf[256], *com_p; - if (!manager) - { - die("Manager is not initialized, manager commands are not possible"); - } - com_p= strmov(com_buf,op); - com_p= strmov(com_p,"_exec "); - if (!*p) - die("Missing server name in server_%s", op); - while (*p && !my_isspace(charset_info, *p)) - *com_p++= *p++; - *com_p++= ' '; - com_p= int10_to_str(manager_wait_timeout, com_p, 10); - *com_p++= '\n'; - *com_p= 0; - if (mysql_manager_command(manager, com_buf, (int)(com_p-com_buf))) - die("Error in command: %s(%d)", manager->last_error, manager->last_errno); - while (!manager->eof) - { - if (mysql_manager_fetch_line(manager, com_buf, sizeof(com_buf))) - die("Error fetching result line: %s(%d)", manager->last_error, - manager->last_errno); - } - - q->last_argument= p; - return 0; -} -#endif - - -/* - Source and execute the given file - - SYNOPSIS - do_source() - query called command - - DESCRIPTION - source - - Open the file and execute it - -*/ - -int do_source(struct st_query *query) -{ - char *p= query->first_argument, *name; - if (!*p) - die("Missing file name in source"); - name= p; - while (*p && !my_isspace(charset_info,*p)) - p++; - if (*p) - *p++= 0; - query->last_argument= p; - /* - If this file has already been sourced, don't source it again. - It's already available in the q_lines cache. - */ - if (parser.current_line < (parser.read_lines - 1)) - return 0; - return open_file(name); + return; } -/* - Execute given command. - - SYNOPSIS - do_exec() - query called command - - DESCRIPTION - exec - - Execute the text between exec and end of line in a subprocess. - The error code returned from the subprocess is checked against the - expected error array, previously set with the --error command. - It can thus be used to execute a command that shall fail. - -*/ - -static void do_exec(struct st_query *query) +void do_sync_with_master2(long offset) { - int error; - DYNAMIC_STRING *ds= NULL; - DYNAMIC_STRING ds_tmp; - char buf[1024]; - FILE *res_file; - char *cmd= query->first_argument; - DBUG_ENTER("do_exec"); - - while (*cmd && my_isspace(charset_info, *cmd)) - cmd++; - if (!*cmd) - die("Missing argument in exec"); - query->last_argument= query->end; - - DBUG_PRINT("info", ("Executing '%s'", cmd)); - - if (!(res_file= popen(cmd, "r")) && query->abort_on_error) - die("popen(\"%s\", \"r\") failed", cmd); - - if (disable_result_log) - { - while (fgets(buf, sizeof(buf), res_file)) - { - buf[strlen(buf)-1]=0; - DBUG_PRINT("exec_result",("%s", buf)); - } - } - else - { - if (query->record_file[0]) - { - init_dynamic_string(&ds_tmp, "", 16384, 65536); - ds= &ds_tmp; - } - else - ds= &ds_res; - - while (fgets(buf, sizeof(buf), res_file)) - replace_dynstr_append_mem(ds, buf, strlen(buf)); - } - error= pclose(res_file); - if (error != 0) - { - uint status= WEXITSTATUS(error), i; - my_bool ok= 0; - - if (query->abort_on_error) - die("command \"%s\" failed", cmd); - - DBUG_PRINT("info", - ("error: %d, status: %d", error, status)); - for (i= 0; i < query->expected_errors; i++) - { - DBUG_PRINT("info", ("expected error: %d", - query->expected_errno[i].code.errnum)); - if ((query->expected_errno[i].type == ERR_ERRNO) && - (query->expected_errno[i].code.errnum == status)) - { - ok= 1; - DBUG_PRINT("info", ("command \"%s\" failed with expected error: %d", - cmd, status)); - } - } - if (!ok) - die("command \"%s\" failed with wrong error: %d", - cmd, status); - } - else if (query->expected_errno[0].type == ERR_ERRNO && - query->expected_errno[0].code.errnum != 0) - { - /* Error code we wanted was != 0, i.e. not an expected success */ - die("command \"%s\" succeeded - should have failed with errno %d...", - cmd, query->expected_errno[0].code.errnum); - } - - if (!disable_result_log) - { - if (glob_replace) - free_replace(); - - if (record) - { - if (!query->record_file[0] && !result_file) - die("Missing result file"); - if (!result_file) - str_to_file(query->record_file, ds->str, ds->length); - } - else if (query->record_file[0]) - { - error= check_result(ds, query->record_file, query->require_file); - } - if (ds == &ds_tmp) - dynstr_free(&ds_tmp); - } -} - - -int var_query_set(VAR* v, const char *p, const char** p_end) -{ - char* end = (char*)((p_end && *p_end) ? *p_end : p + strlen(p)); MYSQL_RES *res; MYSQL_ROW row; - MYSQL* mysql = &cur_con->mysql; - LINT_INIT(res); - - while (end > p && *end != '`') - --end; - if (p == end) - die("Syntax error in query, missing '`'"); - ++p; - - if (mysql_real_query(mysql, p, (int)(end - p)) || - !(res = mysql_store_result(mysql))) - { - *end = 0; - die("Error running query '%s': %s", p, mysql_error(mysql)); - } - - if ((row = mysql_fetch_row(res)) && row[0]) - { - /* - Concatenate all row results with tab in between to allow us to work - with results from many columns (for example from SHOW VARIABLES) - */ - DYNAMIC_STRING result; - uint i; - ulong *lengths; - char *end; - - init_dynamic_string(&result, "", 16384, 65536); - lengths= mysql_fetch_lengths(res); - for (i=0; i < mysql_num_fields(res); i++) - { - if (row[0]) - dynstr_append_mem(&result, row[i], lengths[i]); - dynstr_append_mem(&result, "\t", 1); - } - end= result.str + result.length-1; - eval_expr(v, result.str, (const char**) &end); - dynstr_free(&result); - } - else - eval_expr(v, "", 0); - - mysql_free_result(res); - return 0; -} - -void var_copy(VAR *dest, VAR *src) -{ - dest->int_val= src->int_val; - dest->int_dirty= src->int_dirty; - - /* Alloc/realloc data for str_val in dest */ - if (dest->alloced_len < src->alloced_len && - !(dest->str_val= dest->str_val - ? my_realloc(dest->str_val, src->alloced_len, MYF(MY_WME)) - : my_malloc(src->alloced_len, MYF(MY_WME)))) - die("Out of memory"); - else - dest->alloced_len= src->alloced_len; - - /* Copy str_val data to dest */ - dest->str_val_len= src->str_val_len; - if (src->str_val_len) - memcpy(dest->str_val, src->str_val, src->str_val_len); -} - -int eval_expr(VAR* v, const char *p, const char** p_end) -{ - VAR* vp; - if (*p == '$') - { - if ((vp = var_get(p,p_end,0,0))) - { - var_copy(v, vp); - return 0; - } - } - else if (*p == '`') - { - return var_query_set(v, p, p_end); - } - else - { - int new_val_len = (p_end && *p_end) ? - (int) (*p_end - p) : (int) strlen(p); - if (new_val_len + 1 >= v->alloced_len) - { - v->alloced_len = (new_val_len < MIN_VAR_ALLOC - 1) ? - MIN_VAR_ALLOC : new_val_len + 1; - if (!(v->str_val = - v->str_val ? my_realloc(v->str_val, v->alloced_len+1, - MYF(MY_WME)) : - my_malloc(v->alloced_len+1, MYF(MY_WME)))) - die("Out of memory"); - } - v->str_val_len = new_val_len; - memcpy(v->str_val, p, new_val_len); - v->str_val[new_val_len] = 0; - v->int_val=atoi(p); - v->int_dirty=0; - return 0; - } - - die("Invalid expr: %s", p); - return 1; -} - - -enum enum_operator -{ - DO_DEC, - DO_INC -}; - -/* - Decrease or increase the value of a variable - - SYNOPSIS - do_modify_var() - query called command - name human readable name of operator - operator operation to perform on the var - - DESCRIPTION - dec $var_name - inc $var_name - -*/ - -int do_modify_var(struct st_query *query, const char *name, - enum enum_operator operator) -{ - const char *p= query->first_argument; - VAR* v; - if (!*p) - die("Missing arguments to %s", name); - if (*p != '$') - die("First argument to %s must be a variable (start with $)", name); - v= var_get(p, &p, 1, 0); - switch (operator){ - case DO_DEC: - v->int_val--; - break; - case DO_INC: - v->int_val++; - break; - default: - die("Invalid operator to do_operator"); - break; - } - v->int_dirty= 1; - query->last_argument= (char*)++p; - return 0; -} - - -int do_system(struct st_query *q) -{ - char *p=q->first_argument; - VAR v; - var_init(&v, 0, 0, 0, 0); - eval_expr(&v, p, 0); /* NULL terminated */ - if (v.str_val_len) - { - char expr_buf[1024]; - if ((uint)v.str_val_len > sizeof(expr_buf) - 1) - v.str_val_len = sizeof(expr_buf) - 1; - memcpy(expr_buf, v.str_val, v.str_val_len); - expr_buf[v.str_val_len] = 0; - DBUG_PRINT("info", ("running system command '%s'", expr_buf)); - if (system(expr_buf)) - { - if (q->abort_on_error) - die("system command '%s' failed", expr_buf); - /* If ! abort_on_error, display message and continue */ - verbose_msg("system command '%s' failed", expr_buf); - } - } - else - die("Missing arguments to system, nothing to do!"); - var_free(&v); - q->last_argument= q->end; - return 0; -} - - -/* - Print the content between echo and to result file. - If content is a variable, the variable value will be retrieved - - SYNOPSIS - do_echo() - q called command - - DESCRIPTION - Usage 1: - echo text - Print the text after echo until end of command to result file - - Usage 2: - echo $ - Print the content of the variable to result file - -*/ - -int do_echo(struct st_query *q) -{ - char *p= q->first_argument; - DYNAMIC_STRING *ds; - DYNAMIC_STRING ds_tmp; - VAR v; - var_init(&v,0,0,0,0); - - if (q->record_file[0]) - { - init_dynamic_string(&ds_tmp, "", 256, 512); - ds= &ds_tmp; - } - else - ds= &ds_res; - - eval_expr(&v, p, 0); /* NULL terminated */ - if (v.str_val_len) - dynstr_append_mem(ds, v.str_val, v.str_val_len); - dynstr_append_mem(ds, "\n", 1); - var_free(&v); - if (ds == &ds_tmp) - dynstr_free(&ds_tmp); - q->last_argument= q->end; - return 0; -} - - -int do_sync_with_master2(long offset) -{ - MYSQL_RES* res; - MYSQL_ROW row; - MYSQL* mysql= &cur_con->mysql; + MYSQL *mysql= &cur_con->mysql; char query_buf[FN_REFLEN+128]; int tries= 0; int rpl_parse; @@ -1362,10 +2001,10 @@ int do_sync_with_master2(long offset) wait_for_position: if (mysql_query(mysql, query_buf)) - die("failed in %s: %d: %s", query_buf, mysql_errno(mysql), + die("failed in '%s': %d: %s", query_buf, mysql_errno(mysql), mysql_error(mysql)); - if (!(last_result= res= mysql_store_result(mysql))) + if (!(res= mysql_store_result(mysql))) die("mysql_store_result() returned NULL for '%s'", query_buf); if (!(row= mysql_fetch_row(res))) die("empty result in %s", query_buf); @@ -1375,24 +2014,24 @@ wait_for_position: It may be that the slave SQL thread has not started yet, though START SLAVE has been issued ? */ - if (tries++ == 3) + if (tries++ == 30) die("could not sync with master ('%s' returned NULL)", query_buf); - sleep(1); /* So at most we will wait 3 seconds and make 4 tries */ + sleep(1); /* So at most we will wait 30 seconds and make 31 tries */ mysql_free_result(res); goto wait_for_position; } mysql_free_result(res); - last_result=0; if (rpl_parse) mysql_enable_rpl_parse(mysql); - return 0; + return; } -int do_sync_with_master(struct st_query *query) + +void do_sync_with_master(struct st_command *command) { long offset= 0; - char *p= query->first_argument; + char *p= command->first_argument; const char *offset_start= p; if (*offset_start) { @@ -1401,33 +2040,177 @@ int do_sync_with_master(struct st_query *query) if(*p && !my_isspace(charset_info, *p)) die("Invalid integer argument \"%s\"", offset_start); - query->last_argument= p; + command->last_argument= p; } - return do_sync_with_master2(offset); + do_sync_with_master2(offset); + return; } + +/* + when ndb binlog is on, this call will wait until last updated epoch + (locally in the mysqld) has been received into the binlog +*/ int do_save_master_pos() { - MYSQL_RES* res; + MYSQL_RES *res; MYSQL_ROW row; - MYSQL* mysql = &cur_con->mysql; + MYSQL *mysql = &cur_con->mysql; const char *query; int rpl_parse; rpl_parse = mysql_rpl_parse_enabled(mysql); mysql_disable_rpl_parse(mysql); +#ifdef HAVE_NDB_BINLOG + /* + Wait for ndb binlog to be up-to-date with all changes + done on the local mysql server + */ + { + ulong have_ndbcluster; + if (mysql_query(mysql, query= "show variables like 'have_ndbcluster'")) + die("'%s' failed: %d %s", query, + mysql_errno(mysql), mysql_error(mysql)); + if (!(res= mysql_store_result(mysql))) + die("mysql_store_result() returned NULL for '%s'", query); + if (!(row= mysql_fetch_row(res))) + die("Query '%s' returned empty result", query); + + have_ndbcluster= strcmp("YES", row[1]) == 0; + mysql_free_result(res); + + if (have_ndbcluster) + { + ulonglong start_epoch= 0, applied_epoch= 0, + latest_epoch=0, latest_trans_epoch=0, + latest_handled_binlog_epoch= 0, latest_received_binlog_epoch= 0, + latest_applied_binlog_epoch= 0; + int count= 0; + int do_continue= 1; + while (do_continue) + { + const char binlog[]= "binlog"; + const char latest_epoch_str[]= + "latest_epoch="; + const char latest_trans_epoch_str[]= + "latest_trans_epoch="; + const char latest_received_binlog_epoch_str[]= + "latest_received_binlog_epoch"; + const char latest_handled_binlog_epoch_str[]= + "latest_handled_binlog_epoch="; + const char latest_applied_binlog_epoch_str[]= + "latest_applied_binlog_epoch="; + if (count) + sleep(1); + if (mysql_query(mysql, query= "show engine ndb status")) + die("failed in '%s': %d %s", query, + mysql_errno(mysql), mysql_error(mysql)); + if (!(res= mysql_store_result(mysql))) + die("mysql_store_result() returned NULL for '%s'", query); + while ((row= mysql_fetch_row(res))) + { + if (strcmp(row[1], binlog) == 0) + { + const char *status= row[2]; + + /* latest_epoch */ + while (*status && strncmp(status, latest_epoch_str, + sizeof(latest_epoch_str)-1)) + status++; + if (*status) + { + status+= sizeof(latest_epoch_str)-1; + latest_epoch= strtoull(status, (char**) 0, 10); + } + else + die("result does not contain '%s' in '%s'", + latest_epoch_str, query); + /* latest_trans_epoch */ + while (*status && strncmp(status, latest_trans_epoch_str, + sizeof(latest_trans_epoch_str)-1)) + status++; + if (*status) + { + status+= sizeof(latest_trans_epoch_str)-1; + latest_trans_epoch= strtoull(status, (char**) 0, 10); + } + else + die("result does not contain '%s' in '%s'", + latest_trans_epoch_str, query); + /* latest_received_binlog_epoch */ + while (*status && + strncmp(status, latest_received_binlog_epoch_str, + sizeof(latest_received_binlog_epoch_str)-1)) + status++; + if (*status) + { + status+= sizeof(latest_received_binlog_epoch_str)-1; + latest_received_binlog_epoch= strtoull(status, (char**) 0, 10); + } + else + die("result does not contain '%s' in '%s'", + latest_received_binlog_epoch_str, query); + /* latest_handled_binlog */ + while (*status && + strncmp(status, latest_handled_binlog_epoch_str, + sizeof(latest_handled_binlog_epoch_str)-1)) + status++; + if (*status) + { + status+= sizeof(latest_handled_binlog_epoch_str)-1; + latest_handled_binlog_epoch= strtoull(status, (char**) 0, 10); + } + else + die("result does not contain '%s' in '%s'", + latest_handled_binlog_epoch_str, query); + /* latest_applied_binlog_epoch */ + while (*status && + strncmp(status, latest_applied_binlog_epoch_str, + sizeof(latest_applied_binlog_epoch_str)-1)) + status++; + if (*status) + { + status+= sizeof(latest_applied_binlog_epoch_str)-1; + latest_applied_binlog_epoch= strtoull(status, (char**) 0, 10); + } + else + die("result does not contain '%s' in '%s'", + latest_applied_binlog_epoch_str, query); + if (count == 0) + start_epoch= latest_trans_epoch; + break; + } + } + if (!row) + die("result does not contain '%s' in '%s'", + binlog, query); + if (latest_applied_binlog_epoch > applied_epoch) + count= 0; + applied_epoch= latest_applied_binlog_epoch; + count++; + if (latest_handled_binlog_epoch >= start_epoch) + do_continue= 0; + else if (count > 30) + { + break; + } + mysql_free_result(res); + } + } + } +#endif if (mysql_query(mysql, query= "show master status")) - die("failed in show master status: %d: %s", + die("failed in 'show master status': %d %s", mysql_errno(mysql), mysql_error(mysql)); - if (!(last_result =res = mysql_store_result(mysql))) + if (!(res = mysql_store_result(mysql))) die("mysql_store_result() retuned NULL for '%s'", query); if (!(row = mysql_fetch_row(res))) die("empty result in show master status"); strnmov(master_pos.file, row[0], sizeof(master_pos.file)-1); master_pos.pos = strtoul(row[1], (char**) 0, 10); - mysql_free_result(res); last_result=0; + mysql_free_result(res); if (rpl_parse) mysql_enable_rpl_parse(mysql); @@ -1440,25 +2223,30 @@ int do_save_master_pos() Assign the variable with SYNOPSIS - do_let() - query called command + do_let() + query called command DESCRIPTION - let $= + let $= - - is the string string found between the $ and = - - is the content between the = and , it may span - multiple line and contain any characters except - - is a string containing of one or more chars, default is ; + - is the string string found between the $ and = + - is the content between the = and , it may span + multiple line and contain any characters except + - is a string containing of one or more chars, default is ; RETURN VALUES - Program will die if error detected + Program will die if error detected */ -int do_let(struct st_query *query) +void do_let(struct st_command *command) { - char *p= query->first_argument; - char *var_name, *var_name_end, *var_val_start; + char *p= command->first_argument; + char *var_name, *var_name_end; + DYNAMIC_STRING let_rhs_expr; + + DBUG_ENTER("do_let"); + + init_dynamic_string(&let_rhs_expr, "", 512, 2048); /* Find */ if (!*p) @@ -1467,7 +2255,8 @@ int do_let(struct st_query *query) while (*p && (*p != '=') && !my_isspace(charset_info,*p)) p++; var_name_end= p; - if (var_name+1 == var_name_end) + if (var_name == var_name_end || + (var_name+1 == var_name_end && *var_name == '$')) die("Missing variable name in let"); while (my_isspace(charset_info,*p)) p++; @@ -1477,29 +2266,19 @@ int do_let(struct st_query *query) /* Find start of */ while (*p && my_isspace(charset_info,*p)) p++; - var_val_start= p; - query->last_argument= query->end; + + do_eval(&let_rhs_expr, p, command->end, FALSE); + + command->last_argument= command->end; /* Assign var_val to var_name */ - return var_set(var_name, var_name_end, var_val_start, query->end); + var_set(var_name, var_name_end, let_rhs_expr.str, + (let_rhs_expr.str + let_rhs_expr.length)); + dynstr_free(&let_rhs_expr); + DBUG_VOID_RETURN; } -/* - Store an integer (typically the returncode of the last SQL) - statement in the mysqltest builtin variable $mysql_errno, by - simulating of a user statement "let $mysql_errno= " -*/ - -int var_set_errno(int sql_errno) -{ - const char *var_name= "$mysql_errno"; - char var_val[21]; - uint length= my_sprintf(var_val, (var_val, "%d", sql_errno)); - return var_set(var_name, var_name + 12, var_val, var_val + length); -} - - -int do_rpl_probe(struct st_query *query __attribute__((unused))) +int do_rpl_probe(struct st_command *command __attribute__((unused))) { DBUG_ENTER("do_rpl_probe"); if (mysql_rpl_probe(&cur_con->mysql)) @@ -1508,14 +2287,14 @@ int do_rpl_probe(struct st_query *query __attribute__((unused))) } -int do_enable_rpl_parse(struct st_query *query __attribute__((unused))) +int do_enable_rpl_parse(struct st_command *command __attribute__((unused))) { mysql_enable_rpl_parse(&cur_con->mysql); return 0; } -int do_disable_rpl_parse(struct st_query *query __attribute__((unused))) +int do_disable_rpl_parse(struct st_command *command __attribute__((unused))) { mysql_disable_rpl_parse(&cur_con->mysql); return 0; @@ -1523,17 +2302,17 @@ int do_disable_rpl_parse(struct st_query *query __attribute__((unused))) /* - Sleep the number of specifed seconds + Sleep the number of specified seconds SYNOPSIS - do_sleep() - q called command - real_sleep use the value from opt_sleep as number of seconds to sleep - if real_sleep is false + do_sleep() + q called command + real_sleep use the value from opt_sleep as number of seconds to sleep + if real_sleep is false DESCRIPTION - sleep - real_sleep + sleep + real_sleep The difference between the sleep and real_sleep commands is that sleep uses the delay from the --sleep command-line option if there is one. @@ -1544,39 +2323,42 @@ int do_disable_rpl_parse(struct st_query *query __attribute__((unused))) used for cpu-independent delays. */ -int do_sleep(struct st_query *query, my_bool real_sleep) +int do_sleep(struct st_command *command, my_bool real_sleep) { int error= 0; - char *p= query->first_argument; - char *sleep_start, *sleep_end= query->end; + char *p= command->first_argument; + char *sleep_start, *sleep_end= command->end; double sleep_val; while (my_isspace(charset_info, *p)) p++; if (!*p) - die("Missing argument to %.*s", query->first_word_len, query->query); + die("Missing argument to %.*s", command->first_word_len, command->query); sleep_start= p; /* Check that arg starts with a digit, not handled by my_strtod */ if (!my_isdigit(charset_info, *sleep_start)) - die("Invalid argument to %.*s \"%s\"", query->first_word_len, query->query, - query->first_argument); + die("Invalid argument to %.*s \"%s\"", command->first_word_len, + command->query,command->first_argument); sleep_val= my_strtod(sleep_start, &sleep_end, &error); if (error) - die("Invalid argument to %.*s \"%s\"", query->first_word_len, query->query, - query->first_argument); + die("Invalid argument to %.*s \"%s\"", command->first_word_len, + command->query, command->first_argument); /* Fixed sleep time selected by --sleep option */ - if (opt_sleep && !real_sleep) + if (opt_sleep >= 0 && !real_sleep) sleep_val= opt_sleep; - my_sleep((ulong) (sleep_val * 1000000L)); - query->last_argument= sleep_end; + DBUG_PRINT("info", ("sleep_val: %f", sleep_val)); + if (sleep_val) + my_sleep((ulong) (sleep_val * 1000000L)); + command->last_argument= sleep_end; return 0; } -static void get_file_name(char *filename, struct st_query *q) + +void do_get_file_name(char *filename, struct st_command *command) { - char *p= q->first_argument, *name; + char *p= command->first_argument, *name; if (!*p) die("Missing file name argument"); name= p; @@ -1584,13 +2366,14 @@ static void get_file_name(char *filename, struct st_query *q) p++; if (*p) *p++= 0; - q->last_argument= p; + command->last_argument= p; strmake(filename, name, FN_REFLEN); } -static void set_charset(struct st_query *q) + +void do_set_charset(struct st_command *command) { - char *charset_name= q->first_argument; + char *charset_name= command->first_argument; char *p; if (!charset_name || !*charset_name) @@ -1601,49 +2384,182 @@ static void set_charset(struct st_query *q) p++; if(*p) *p++= 0; - q->last_argument= p; + command->last_argument= p; charset_info= get_charset_by_csname(charset_name,MY_CS_PRIMARY,MYF(MY_WME)); if (!charset_info) - abort_not_supported_test(); + abort_not_supported_test("Test requires charset '%s'", charset_name); } -static uint get_errcodes(match_err *to,struct st_query *q) + +#if MYSQL_VERSION_ID >= 50000 +/* List of error names to error codes, available from 5.0 */ +typedef struct { - char *p= q->first_argument; + const char *name; + long code; +} st_error; + +static st_error global_error_names[] = +{ +#include + { 0, 0 } +}; +#define HAVE_MYSQLD_ERNAME +#endif + + +uint get_errcode_from_name(char *error_name, char *error_end) +{ +#ifdef HAVE_MYSQLD_ERNAME + DBUG_ENTER("get_errcode_from_name"); + + /* SQL error as string */ + st_error *e= global_error_names; + DBUG_PRINT("enter", ("error_name: %s", error_name)); + + /* Loop through the array of known error names */ + for (; e->name; e++) + { + /* + If we get a match, we need to check the length of the name we + matched against in case it was longer than what we are checking + (as in ER_WRONG_VALUE vs. ER_WRONG_VALUE_COUNT). + */ + if (!strncmp(error_name, e->name, (int) (error_end - error_name)) && + (uint) strlen(e->name) == (uint) (error_end - error_name)) + { + return (uint) e->code; + break; + } + } + if (!e->name) + die("Unknown SQL error name '%s'", error_name); +#else + LINT_INIT(error_name); + LINT_INIT(error_end); + abort_not_in_this_version(); +#endif + return 0; +} + + +void do_get_errcodes(struct st_command *command) +{ + struct st_match_err *to= saved_expected_errors.err; + char *p= command->first_argument; uint count= 0; - DBUG_ENTER("get_errcodes"); + + DBUG_ENTER("do_get_errcodes"); if (!*p) - die("Missing argument in %s", q->query); + die("Missing argument(s) to 'error'"); do { + char *end; + + /* Skip leading spaces */ + while (*p && *p == ' ') + p++; + + /* Find end */ + end= p; + while (*end && *end != ',' && *end != ' ') + end++; + if (*p == 'S') { - /* SQLSTATE string */ - int i; - p++; - for (i = 0; my_isalnum(charset_info, *p) && i < SQLSTATE_LENGTH; p++, i++) - to[count].code.sqlstate[i]= *p; - to[count].code.sqlstate[i]= '\0'; - to[count].type= ERR_SQLSTATE; + /* + SQLSTATE string + - Must be SQLSTATE_LENGTH long + - May contain only digits[0-9] and _uppercase_ letters + */ + p++; /* Step past the S */ + if (end - p != SQLSTATE_LENGTH) + die("The sqlstate must be exactly %d chars long", SQLSTATE_LENGTH); + + /* Check sqlstate string validity */ + char *to_ptr= to->code.sqlstate; + while (*p && p != end) + { + if (my_isdigit(charset_info, *p) || my_isupper(charset_info, *p)) + *to_ptr++= *p++; + else + die("The sqlstate may only consist of digits[0-9] " \ + "and _uppercase_ letters"); + } + + *to_ptr= 0; + to->type= ERR_SQLSTATE; + DBUG_PRINT("info", ("ERR_SQLSTATE: %d", to->code.sqlstate)); + } + else if (*p == 's') + { + die("The sqlstate definition must start with an uppercase S"); + } + else if (*p == 'E') + { + /* Error name string */ + + DBUG_PRINT("info", ("Error name: %s", p)); + to->code.errnum= get_errcode_from_name(p, end); + to->type= ERR_ERRNO; + DBUG_PRINT("info", ("ERR_ERRNO: %d", to->code.errnum)); + } + else if (*p == 'e') + { + die("The error name definition must start with an uppercase E"); } else { long val; - p=str2int(p,10,(long) INT_MIN, (long) INT_MAX, &val); - if (p == NULL) - die("Invalid argument in %s", q->query); - to[count].code.errnum= (uint) val; - to[count].type= ERR_ERRNO; + char *start= p; + /* Check that the string passed to str2int only contain digits */ + while (*p && p != end) + { + if (!my_isdigit(charset_info, *p)) + die("Invalid argument to error: '%s' - "\ + "the errno may only consist of digits[0-9]", + command->first_argument); + p++; + } + + /* Convert the sting to int */ + if (!str2int(start, 10, (long) INT_MIN, (long) INT_MAX, &val)) + die("Invalid argument to error: '%s'", command->first_argument); + + to->code.errnum= (uint) val; + to->type= ERR_ERRNO; + DBUG_PRINT("info", ("ERR_ERRNO: %d", to->code.errnum)); } + to++; count++; - } while (*(p++) == ','); - q->last_argument= (p - 1); - to[count].type= ERR_EMPTY; /* End of data */ - DBUG_RETURN(count); + + if (count >= (sizeof(saved_expected_errors.err) / + sizeof(struct st_match_err))) + die("Too many errorcodes specified"); + + /* Set pointer to the end of the last error code */ + p= end; + + /* Find next ',' */ + while (*p && *p != ',') + p++; + + if (*p) + p++; /* Step past ',' */ + + } while (*p); + + command->last_argument= p; + to->type= ERR_EMPTY; /* End of data */ + + DBUG_PRINT("info", ("Expected errors: %d", count)); + saved_expected_errors.count= count; + DBUG_VOID_RETURN; } + /* Get a string; Return ptr to end of string Strings may be surrounded by " or ' @@ -1651,11 +2567,10 @@ static uint get_errcodes(match_err *to,struct st_query *q) If string is a '$variable', return the value of the variable. */ - -static char *get_string(char **to_ptr, char **from_ptr, - struct st_query *q) +char *get_string(char **to_ptr, char **from_ptr, + struct st_command *command) { - reg1 char c,sep; + char c, sep; char *to= *to_ptr, *from= *from_ptr, *start=to; DBUG_ENTER("get_string"); @@ -1701,7 +2616,7 @@ static char *get_string(char **to_ptr, char **from_ptr, *to++=c; } if (*from != ' ' && *from) - die("Wrong string argument in %s", q->query); + die("Wrong string argument in %s", command->query); while (my_isspace(charset_info,*from)) /* Point to next string */ from++; @@ -1725,93 +2640,46 @@ static char *get_string(char **to_ptr, char **from_ptr, } -/* - Get arguments for replace. The syntax is: - replace from to [from to ...] - Where each argument may be quoted with ' or " - A argument may also be a variable, in which case the value of the - variable is replaced. -*/ - -static void get_replace(struct st_query *q) +void set_reconnect(MYSQL* mysql, int val) { - uint i; - char *from= q->first_argument; - char *buff,*start; - char word_end_chars[256],*pos; - POINTER_ARRAY to_array,from_array; - DBUG_ENTER("get_replace"); - - free_replace(); - - bzero((char*) &to_array,sizeof(to_array)); - bzero((char*) &from_array,sizeof(from_array)); - if (!*from) - die("Missing argument in %s", q->query); - start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); - while (*from) - { - char *to=buff; - to=get_string(&buff, &from, q); - if (!*from) - die("Wrong number of arguments to replace_result in '%s'", q->query); - insert_pointer_name(&from_array,to); - to=get_string(&buff, &from, q); - insert_pointer_name(&to_array,to); - } - for (i=1,pos=word_end_chars ; i < 256 ; i++) - if (my_isspace(charset_info,i)) - *pos++= i; - *pos=0; /* End pointer */ - if (!(glob_replace=init_replace((char**) from_array.typelib.type_names, - (char**) to_array.typelib.type_names, - (uint) from_array.typelib.count, - word_end_chars)) || - initialize_replace_buffer()) - die("Can't initialize replace from '%s'", q->query); - free_pointer_array(&from_array); - free_pointer_array(&to_array); - my_free(start, MYF(0)); - q->last_argument= q->end; - DBUG_VOID_RETURN; +#if MYSQL_VERSION_ID < 50000 + mysql->reconnect= val; +#else + int reconnect= val; + mysql_options(mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect); +#endif } -void free_replace() + +struct st_connection * find_connection_by_name(const char *name) { - DBUG_ENTER("free_replace"); - if (glob_replace) + struct st_connection *con; + for (con= connections; con < next_con; con++) { - my_free((char*) glob_replace,MYF(0)); - glob_replace=0; - free_replace_buffer(); + if (!strcmp(con->name, name)) + { + return con; + } } - DBUG_VOID_RETURN; + return 0; /* Connection not found */ } int select_connection_name(const char *name) { - struct connection *con; DBUG_ENTER("select_connection2"); DBUG_PRINT("enter",("name: '%s'", name)); - for (con= cons; con < next_con; con++) - { - if (!strcmp(con->name, name)) - { - cur_con= con; - DBUG_RETURN(0); - } - } - die("connection '%s' not found in connection pool", name); - DBUG_RETURN(1); /* Never reached */ + if (!(cur_con= find_connection_by_name(name))) + die("connection '%s' not found in connection pool", name); + DBUG_RETURN(0); } -int select_connection(struct st_query *query) +int select_connection(struct st_command *command) { char *name; - char *p= query->first_argument; + char *p= command->first_argument; DBUG_ENTER("select_connection"); if (!*p) @@ -1821,33 +2689,38 @@ int select_connection(struct st_query *query) p++; if (*p) *p++= 0; - query->last_argument= p; + command->last_argument= p; return select_connection_name(name); } -int close_connection(struct st_query *q) +void do_close_connection(struct st_command *command) { - char *p= q->first_argument, *name; - struct connection *con; + char *p= command->first_argument, *name; + struct st_connection *con; + DBUG_ENTER("close_connection"); DBUG_PRINT("enter",("name: '%s'",p)); if (!*p) - die("Missing connection name in connect"); + die("Missing connection name in disconnect"); name= p; while (*p && !my_isspace(charset_info,*p)) p++; if (*p) *p++= 0; - q->last_argument= p; - for (con= cons; con < next_con; con++) + command->last_argument= p; + + /* Loop through connection pool for connection to close */ + for (con= connections; con < next_con; con++) { + DBUG_PRINT("info", ("con->name: %s", con->name)); if (!strcmp(con->name, name)) { + DBUG_PRINT("info", ("Closing connection %s", con->name)); #ifndef EMBEDDED_LIBRARY - if (q->type == Q_DIRTY_CLOSE) + if (command->type == Q_DIRTY_CLOSE) { if (con->mysql.net.vio) { @@ -1857,172 +2730,353 @@ int close_connection(struct st_query *q) } #endif mysql_close(&con->mysql); - DBUG_RETURN(0); + if (con->util_mysql) + mysql_close(con->util_mysql); + con->util_mysql= 0; + my_free(con->name, MYF(0)); + + /* + When the connection is closed set name to "closed_connection" + to make it possible to reuse the connection name. + The connection slot will not be reused + */ + if (!(con->name = my_strdup("closed_connection", MYF(MY_WME)))) + die("Out of memory"); + + DBUG_VOID_RETURN; } } die("connection '%s' not found in connection pool", name); - DBUG_RETURN(1); /* Never reached */ } /* - This one now is a hack - we may want to improve in in the - future to handle quotes. For now we assume that anything that is not - a comma, a space or ) belongs to the argument. space is a chopper, comma or - ) are delimiters/terminators + Connect to a server doing several retries if needed. + + SYNOPSIS + safe_connect() + con - connection structure to be used + host, user, pass, - connection parameters + db, port, sock + + NOTE + + Sometimes in a test the client starts before + the server - to solve the problem, we try again + after some sleep if connection fails the first + time + + This function will try to connect to the given server + "opt_max_connect_retries" times and sleep "connection_retry_sleep" + seconds between attempts before finally giving up. + This helps in situation when the client starts + before the server (which happens sometimes). + It will only ignore connection errors during these retries. + */ -char* safe_get_param(char *str, char** arg, const char *msg) +void safe_connect(MYSQL* mysql, const char *name, const char *host, + const char *user, const char *pass, const char *db, + int port, const char *sock) { - DBUG_ENTER("safe_get_param"); - while (*str && my_isspace(charset_info,*str)) - str++; - *arg= str; - for (; *str && *str != ',' && *str != ')' ; str++) + int failed_attempts= 0; + static ulong connection_retry_sleep= 100000; /* Microseconds */ + + DBUG_ENTER("safe_connect"); + while(!mysql_real_connect(mysql, host,user, pass, db, port, sock, + CLIENT_MULTI_STATEMENTS | CLIENT_REMEMBER_OPTIONS)) { - if (my_isspace(charset_info,*str)) - *str= 0; - } - if (!*str) - die(msg); + /* + Connect failed - *str++= 0; - DBUG_RETURN(str); -} + Only allow retry if this was an error indicating the server + could not be contacted + */ -#ifndef EMBEDDED_LIBRARY -void init_manager() -{ - if (!(manager=mysql_manager_init(0))) - die("Failed in mysql_manager_init()"); - if (!mysql_manager_connect(manager,manager_host,manager_user, - manager_pass,manager_port)) - die("Could not connect to MySQL manager: %s(%d)",manager->last_error, - manager->last_errno); - -} -#endif - -int safe_connect(MYSQL* con, const char *host, const char *user, - const char *pass, - const char *db, int port, const char *sock) -{ - int con_error = 1; - int i; - for (i = 0; i < MAX_CON_TRIES; ++i) - { - if (mysql_real_connect(con, host,user, pass, db, port, sock, - CLIENT_MULTI_STATEMENTS)) + if (mysql_errno(mysql) == CR_CONNECTION_ERROR && + failed_attempts < opt_max_connect_retries) + my_sleep(connection_retry_sleep); + else { - con_error = 0; - break; + if (failed_attempts > 0) + die("Could not open connection '%s' after %d attempts: %d %s", name, + failed_attempts, mysql_errno(mysql), mysql_error(mysql)); + else + die("Could not open connection '%s': %d %s", name, + mysql_errno(mysql), mysql_error(mysql)); } - sleep(CON_RETRY_SLEEP); + failed_attempts++; } - return con_error; + DBUG_VOID_RETURN; } -int do_connect(struct st_query *q) +/* + Connect to a server and handle connection errors in case they occur. + + SYNOPSIS + connect_n_handle_errors() + q - context of connect "query" (command) + con - connection structure to be used + host, user, pass, - connection parameters + db, port, sock + + DESCRIPTION + This function will try to establish a connection to server and handle + possible errors in the same manner as if "connect" was usual SQL-statement + (If error is expected it will ignore it once it occurs and log the + "statement" to the query log). + Unlike safe_connect() it won't do several attempts. + + RETURN VALUES + 1 - Connected + 0 - Not connected + +*/ + +int connect_n_handle_errors(struct st_command *command, + MYSQL* con, const char* host, + const char* user, const char* pass, + const char* db, int port, const char* sock) { - char *con_name, *con_user,*con_pass, *con_host, *con_port_str, - *con_db, *con_sock; - char *p= q->first_argument; - char buff[FN_REFLEN]; - int con_port; - int free_con_sock= 0; + DYNAMIC_STRING *ds; + + ds= &ds_res; + + /* Only log if an error is expected */ + if (!command->abort_on_error && + !disable_query_log) + { + /* + Log the connect to result log + */ + dynstr_append_mem(ds, "connect(", 8); + replace_dynstr_append(ds, host); + dynstr_append_mem(ds, ",", 1); + replace_dynstr_append(ds, user); + dynstr_append_mem(ds, ",", 1); + replace_dynstr_append(ds, pass); + dynstr_append_mem(ds, ",", 1); + if (db) + replace_dynstr_append(ds, db); + dynstr_append_mem(ds, ",", 1); + replace_dynstr_append_uint(ds, port); + dynstr_append_mem(ds, ",", 1); + if (sock) + replace_dynstr_append(ds, sock); + dynstr_append_mem(ds, ")", 1); + dynstr_append_mem(ds, delimiter, delimiter_length); + dynstr_append_mem(ds, "\n", 1); + } + if (!mysql_real_connect(con, host, user, pass, db, port, sock ? sock: 0, + CLIENT_MULTI_STATEMENTS)) + { + handle_error(command, mysql_errno(con), mysql_error(con), + mysql_sqlstate(con), ds); + return 0; /* Not connected */ + } + + handle_no_error(command); + return 1; /* Connected */ +} + + +/* + Open a new connection to MySQL Server with the parameters + specified. Make the new connection the current connection. + + SYNOPSIS + do_connect() + q called command + + DESCRIPTION + connect(,,,[,[,[,[]]]]); + connect ,,,[,[,[,[]]]]; + + - name of the new connection + - hostname of server + - user to connect as + - password used when connecting + - initial db when connected + - server port + - server socket + - options to use for the connection + * SSL - use SSL if available + * COMPRESS - use compression if available + +*/ + +void do_connect(struct st_command *command) +{ + int con_port= port; + char *con_options; + bool con_ssl= 0, con_compress= 0; + char *ptr; + + DYNAMIC_STRING ds_connection_name; + DYNAMIC_STRING ds_host; + DYNAMIC_STRING ds_user; + DYNAMIC_STRING ds_password; + DYNAMIC_STRING ds_database; + DYNAMIC_STRING ds_port; + DYNAMIC_STRING ds_sock; + DYNAMIC_STRING ds_options; + const struct command_arg connect_args[] = { + "connection name", ARG_STRING, TRUE, &ds_connection_name, + "Name of the connection", + "host", ARG_STRING, TRUE, &ds_host, "Host to connect to", + "user", ARG_STRING, FALSE, &ds_user, "User to connect as", + "passsword", ARG_STRING, FALSE, &ds_password, + "Password used when connecting", + "database", ARG_STRING, FALSE, &ds_database, + "Dtabase to select after connect", + "port", ARG_STRING, FALSE, &ds_port, "Port to connect to", + "socket", ARG_STRING, FALSE, &ds_sock, "Socket to connect with", + "options", ARG_STRING, FALSE, &ds_options, + "Options to use while connecting" + }; DBUG_ENTER("do_connect"); - DBUG_PRINT("enter",("connect: %s",p)); + DBUG_PRINT("enter",("connect: %s", command->first_argument)); - if (*p != '(') - die("Syntax error in connect - expected '(' found '%c'", *p); - p++; - p= safe_get_param(p, &con_name, "missing connection name"); - p= safe_get_param(p, &con_host, "missing connection host"); - p= safe_get_param(p, &con_user, "missing connection user"); - p= safe_get_param(p, &con_pass, "missing connection password"); - p= safe_get_param(p, &con_db, "missing connection db"); - if (!*p || *p == ';') /* Default port and sock */ + /* Remove parenteses around connect arguments */ + if ((ptr= strstr(command->first_argument, "("))) { - con_port= port; - con_sock= (char*) unix_sock; + /* Replace it with a space */ + *ptr= ' '; + if ((ptr= strstr(command->first_argument, ")"))) + { + /* Replace it with \0 */ + *ptr= 0; + } + else + die("connect - argument list started with '(' must be ended with ')'"); + } + + check_command_args(command, command->first_argument, connect_args, + sizeof(connect_args)/sizeof(struct command_arg), + ','); + + /* Port */ + if (ds_port.length) + { + con_port= atoi(ds_port.str); + if (con_port == 0) + die("Illegal argument for port: '%s'", ds_port.str); + } + + /* Sock */ + if (ds_sock.length) + { + /* + If the socket is specified just as a name without path + append tmpdir in front + */ + if (*ds_sock.str != FN_LIBCHAR) + { + char buff[FN_REFLEN]; + fn_format(buff, ds_sock.str, TMPDIR, "", 0); + dynstr_set(&ds_sock, buff); + } } else { - VAR* var_port, *var_sock; - p= safe_get_param(p, &con_port_str, "missing connection port"); - if (*con_port_str == '$') - { - if (!(var_port= var_get(con_port_str, 0, 0, 0))) - die("Unknown variable '%s'", con_port_str+1); - con_port= var_port->int_val; - } - else - con_port= atoi(con_port_str); - p= safe_get_param(p, &con_sock, "missing connection socket"); - if (*con_sock == '$') - { - if (!(var_sock= var_get(con_sock, 0, 0, 0))) - die("Unknown variable '%s'", con_sock+1); - if (!(con_sock= (char*)my_malloc(var_sock->str_val_len+1, MYF(0)))) - die("Out of memory"); - free_con_sock= 1; - memcpy(con_sock, var_sock->str_val, var_sock->str_val_len); - con_sock[var_sock->str_val_len]= 0; - } + /* No socket specified, use default */ + dynstr_set(&ds_sock, unix_sock); } - q->last_argument= p; + DBUG_PRINT("info", ("socket: %s", ds_sock.str)); - if (next_con == cons_end) - die("Connection limit exhausted - increase MAX_CONS in mysqltest.c"); + + /* Options */ + con_options= ds_options.str; + while (*con_options) + { + char* end= con_options; + while (*end && !my_isspace(charset_info, *end)) + end++; + if (!strncmp(con_options, "SSL", 3)) + con_ssl= 1; + else if (!strncmp(con_options, "COMPRESS", 8)) + con_compress= 1; + else + die("Illegal option to connect: %.*s", end - con_options, con_options); + /* Process next option */ + con_options= end; + } + + if (next_con == connections_end) + die("Connection limit exhausted, you can have max %d connections", + (sizeof(connections)/sizeof(struct st_connection))); + + if (find_connection_by_name(ds_connection_name.str)) + die("Connection %s already exists", ds_connection_name.str); if (!mysql_init(&next_con->mysql)) die("Failed on mysql_init()"); - if (opt_compress) - mysql_options(&next_con->mysql,MYSQL_OPT_COMPRESS,NullS); + if (opt_compress || con_compress) + mysql_options(&next_con->mysql, MYSQL_OPT_COMPRESS, NullS); mysql_options(&next_con->mysql, MYSQL_OPT_LOCAL_INFILE, 0); mysql_options(&next_con->mysql, MYSQL_SET_CHARSET_NAME, charset_name); #ifdef HAVE_OPENSSL - if (opt_use_ssl) + if (opt_use_ssl || con_ssl) + { mysql_ssl_set(&next_con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); +#if MYSQL_VERSION_ID >= 50000 + /* Turn on ssl_verify_server_cert only if host is "localhost" */ + opt_ssl_verify_server_cert= !strcmp(con_host, "localhost"); + mysql_options(&next_con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, + &opt_ssl_verify_server_cert); +#endif + } #endif - if (con_sock && !free_con_sock && *con_sock && *con_sock != FN_LIBCHAR) - con_sock=fn_format(buff, con_sock, TMPDIR, "",0); - if (!con_db[0]) - con_db= db; - /* Special database to allow one to connect without a database name */ - if (con_db && !strcmp(con_db,"*NO-ONE*")) - con_db= 0; - if ((safe_connect(&next_con->mysql, con_host, - con_user, con_pass, - con_db, con_port, con_sock ? con_sock: 0))) - die("Could not open connection '%s': %s", con_name, - mysql_error(&next_con->mysql)); - if (!(next_con->name= my_strdup(con_name, MYF(MY_WME)))) - die(NullS); - cur_con= next_con++; - if (free_con_sock) - my_free(con_sock, MYF(MY_WME)); - DBUG_RETURN(0); + /* Use default db name */ + if (ds_database.length == 0) + dynstr_set(&ds_database, db); + + /* Special database to allow one to connect without a database name */ + if (ds_database.length && !strcmp(ds_database.str,"*NO-ONE*")) + dynstr_set(&ds_database, ""); + + + if (connect_n_handle_errors(command, &next_con->mysql, + ds_host.str,ds_user.str, + ds_password.str, ds_database.str, + con_port, ds_sock.str)) + { + DBUG_PRINT("info", ("Inserting connection %s in connection pool", + ds_connection_name.str)); + if (!(next_con->name= my_strdup(ds_connection_name.str, MYF(MY_WME)))) + die("Out of memory"); + cur_con= next_con++; + } + + dynstr_free(&ds_connection_name); + dynstr_free(&ds_host); + dynstr_free(&ds_user); + dynstr_free(&ds_password); + dynstr_free(&ds_database); + dynstr_free(&ds_port); + dynstr_free(&ds_sock); + dynstr_free(&ds_options); + DBUG_VOID_RETURN; } -int do_done(struct st_query *q) +int do_done(struct st_command *command) { /* Check if empty block stack */ if (cur_block == block_stack) { - if (*q->query != '}') + if (*command->query != '}') die("Stray 'end' command - end of block before beginning"); die("Stray '}' - end of block before beginning"); } /* Test if inner block has been executed */ - if (cur_block->ok && cur_block->cmd == Q_WHILE) + if (cur_block->ok && cur_block->cmd == cmd_while) { /* Pop block from stack, re-execute outer block */ cur_block--; @@ -2038,12 +3092,41 @@ int do_done(struct st_query *q) } -int do_block(enum enum_commands cmd, struct st_query *q) +/* + Process start of a "if" or "while" statement + + SYNOPSIS + do_block() + cmd Type of block + q called command + + DESCRIPTION + if ([!]) + { + + } + + while ([!]) + { + + } + + Evaluates the and if it evaluates to + greater than zero executes the following code block. + A '!' can be used before the to indicate it should + be executed if it evaluates to zero. + +*/ + +void do_block(enum block_cmd cmd, struct st_command* command) { - char *p= q->first_argument; + char *p= command->first_argument; const char *expr_start, *expr_end; VAR v; - const char *cmd_name= (cmd == Q_WHILE ? "while" : "if"); + const char *cmd_name= (cmd == cmd_while ? "while" : "if"); + my_bool not_expr= FALSE; + DBUG_ENTER("do_block"); + DBUG_PRINT("enter", ("%s", cmd_name)); /* Check stack overflow */ if (cur_block == block_stack_end) @@ -2059,13 +3142,21 @@ int do_block(enum enum_commands cmd, struct st_query *q) cur_block++; cur_block->cmd= cmd; cur_block->ok= FALSE; - return 0; + DBUG_VOID_RETURN; } /* Parse and evaluate test expression */ expr_start= strchr(p, '('); - if (!expr_start) + if (!expr_start++) die("missing '(' in %s", cmd_name); + + /* Check for ! */ + if (*expr_start == '!') + { + not_expr= TRUE; + expr_start++; /* Step past the '!' */ + } + /* Find ending ')' */ expr_end= strrchr(expr_start, ')'); if (!expr_end) die("missing ')' in %s", cmd_name); @@ -2073,61 +3164,62 @@ int do_block(enum enum_commands cmd, struct st_query *q) while (*p && my_isspace(charset_info, *p)) p++; - if (*p == '{') - die("Missing newline between %s and '{'", cmd_name); - if (*p) + if (*p && *p != '{') die("Missing '{' after %s. Found \"%s\"", cmd_name, p); var_init(&v,0,0,0,0); - eval_expr(&v, ++expr_start, &expr_end); + eval_expr(&v, expr_start, &expr_end); /* Define inner block */ cur_block++; cur_block->cmd= cmd; cur_block->ok= (v.int_val ? TRUE : FALSE); + if (not_expr) + cur_block->ok = !cur_block->ok; + + DBUG_PRINT("info", ("OK: %d", cur_block->ok)); + var_free(&v); - return 0; + DBUG_VOID_RETURN; } -/* - Read characters from line buffer or file. This is needed to allow - my_ungetc() to buffer MAX_DELIMITER characters for a file - - NOTE: - This works as long as one doesn't change files (with 'source file_name') - when there is things pushed into the buffer. This should however not - happen for any tests in the test suite. -*/ - -int my_getc(FILE *file) +void do_delimiter(struct st_command* command) { - if (line_buffer_pos == line_buffer) - return fgetc(file); - return *--line_buffer_pos; -} + char* p= command->first_argument; + DBUG_ENTER("do_delimiter"); + DBUG_PRINT("enter", ("first_argument: %s", command->first_argument)); -void my_ungetc(int c) -{ - *line_buffer_pos++= (char) c; + while (*p && my_isspace(charset_info, *p)) + p++; + + if (!(*p)) + die("Can't set empty delimiter"); + + strmake(delimiter, p, sizeof(delimiter) - 1); + delimiter_length= strlen(delimiter); + + DBUG_PRINT("exit", ("delimiter: %s", delimiter)); + command->last_argument= p + delimiter_length; + DBUG_VOID_RETURN; } -my_bool end_of_query(int c) +my_bool match_delimiter(int c, const char *delim, uint length) { uint i; - char tmp[MAX_DELIMITER]; + char tmp[MAX_DELIMITER_LENGTH]; - if (c != *delimiter) + if (c != *delim) return 0; - for (i= 1; i < delimiter_length && - (c= my_getc(cur_file->file)) == *(delimiter + i); + for (i= 1; i < length && + (c= my_getc(cur_file->file)) == *(delim + i); i++) tmp[i]= c; - if (i == delimiter_length) + if (i == length) return 1; /* Found delimiter */ /* didn't find delimiter, push back things that we read */ @@ -2138,44 +3230,51 @@ my_bool end_of_query(int c) } +my_bool end_of_query(int c) +{ + return match_delimiter(c, delimiter, delimiter_length); +} + + /* Read one "line" from the file SYNOPSIS - read_line - buf buffer for the read line - size size of the buffer i.e max size to read + read_line + buf buffer for the read line + size size of the buffer i.e max size to read DESCRIPTION - This function actually reads several lines an adds them to the - buffer buf. It will continue to read until it finds what it believes - is a complete query. + This function actually reads several lines and adds them to the + buffer buf. It continues to read until it finds what it believes + is a complete query. - Normally that means it will read lines until it reaches the - "delimiter" that marks end of query. Default delimiter is ';' - The function should be smart enough not to detect delimiter's - found inside strings surrounded with '"' and '\'' escaped strings. + Normally that means it will read lines until it reaches the + "delimiter" that marks end of query. Default delimiter is ';' + The function should be smart enough not to detect delimiter's + found inside strings surrounded with '"' and '\'' escaped strings. - If the first line in a query starts with '#' or '-' this line is treated - as a comment. A comment is always terminated when end of line '\n' is - reached. + If the first line in a query starts with '#' or '-' this line is treated + as a comment. A comment is always terminated when end of line '\n' is + reached. */ int read_line(char *buf, int size) { - int c; + char c, last_quote; char *p= buf, *buf_end= buf + size - 1; - int no_save= 0; - enum {R_NORMAL, R_Q1, R_ESC_Q_Q1, R_ESC_Q_Q2, - R_ESC_SLASH_Q1, R_ESC_SLASH_Q2, - R_Q2, R_COMMENT, R_LINE_START} state= R_LINE_START; + int skip_char= 0; + enum {R_NORMAL, R_Q, R_SLASH_IN_Q, + R_COMMENT, R_LINE_START} state= R_LINE_START; DBUG_ENTER("read_line"); + LINT_INIT(last_quote); - start_lineno= *lineno; + start_lineno= cur_file->lineno; + DBUG_PRINT("info", ("start_lineno: %d", start_lineno)); for (; p < buf_end ;) { - no_save= 0; + skip_char= 0; c= my_getc(cur_file->file); if (feof(cur_file->file)) { @@ -2187,127 +3286,118 @@ int read_line(char *buf, int size) } my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); cur_file->file_name= 0; - lineno--; - start_lineno= *lineno; if (cur_file == file_stack) { /* We're back at the first file, check if all { have matching } - */ + */ if (cur_block != block_stack) - { - start_lineno= *(lineno+1); die("Missing end of block"); - } - DBUG_RETURN(1); + + *p= 0; + DBUG_PRINT("info", ("end of file")); + DBUG_RETURN(1); } cur_file--; + start_lineno= cur_file->lineno; continue; } - /* Line counting is independent of state */ if (c == '\n') - (*lineno)++; + { + /* Line counting is independent of state */ + cur_file->lineno++; + + /* Convert cr/lf to lf */ + if (p != buf && *(p-1) == '\r') + p--; + } switch(state) { case R_NORMAL: - /* Only accept '{' in the beginning of a line */ if (end_of_query(c)) { *p= 0; + DBUG_PRINT("exit", ("Found delimiter '%s'", delimiter)); DBUG_RETURN(0); } - else if (c == '\'') - state = R_Q1; - else if (c == '"') - state = R_Q2; - else if (c == '\n') + else if ((c == '{' && + (!strncasecmp(buf, "while", min(5, p - buf)) || + !strncasecmp(buf, "if", min(2, p - buf))))) { - state = R_LINE_START; + /* Only if and while commands can be terminated by { */ + *p++= c; + *p= 0; + DBUG_PRINT("exit", ("Found '{' indicating begining of block")); + DBUG_RETURN(0); + } + else if (c == '\'' || c == '"' || c == '`') + { + last_quote= c; + state= R_Q; } break; + case R_COMMENT: if (c == '\n') { + /* Comments are terminated by newline */ *p= 0; + DBUG_PRINT("exit", ("Found newline in comment")); DBUG_RETURN(0); } break; + case R_LINE_START: - /* Only accept start of comment if this is the first line in query */ - if ((*lineno == start_lineno) && (c == '#' || c == '-')) + if (c == '#' || c == '-') { + /* A # or - in the first position of the line - this is a comment */ state = R_COMMENT; } else if (my_isspace(charset_info, c)) { + /* Skip all space at begining of line */ if (c == '\n') - start_lineno= *lineno; /* Query hasn't started yet */ - no_save= 1; + start_lineno= cur_file->lineno; /* Query hasn't started yet */ + skip_char= 1; + } + else if (end_of_query(c)) + { + *p= 0; + DBUG_PRINT("exit", ("Found delimiter '%s'", delimiter)); + DBUG_RETURN(0); } else if (c == '}') { - *buf++= '}'; - *buf= 0; - DBUG_RETURN(0); - } - else if (end_of_query(c) || c == '{') - { + /* A "}" need to be by itself in the begining of a line to terminate */ + *p++= c; *p= 0; + DBUG_PRINT("exit", ("Found '}' in begining of a line")); DBUG_RETURN(0); } - else if (c == '\'') - state= R_Q1; - else if (c == '"') - state= R_Q2; + else if (c == '\'' || c == '"' || c == '`') + { + last_quote= c; + state= R_Q; + } else state= R_NORMAL; break; - case R_Q1: - if (c == '\'') - state= R_ESC_Q_Q1; - else if (c == '\\') - state= R_ESC_SLASH_Q1; - break; - case R_ESC_Q_Q1: - if (end_of_query(c)) - { - *p= 0; - DBUG_RETURN(0); - } - if (c != '\'') + case R_Q: + if (c == last_quote) state= R_NORMAL; - else - state= R_Q1; - break; - case R_ESC_SLASH_Q1: - state= R_Q1; + else if (c == '\\') + state= R_SLASH_IN_Q; break; - case R_Q2: - if (c == '"') - state= R_ESC_Q_Q2; - else if (c == '\\') - state= R_ESC_SLASH_Q2; - break; - case R_ESC_Q_Q2: - if (end_of_query(c)) - { - *p= 0; - DBUG_RETURN(0); - } - if (c != '"') - state= R_NORMAL; - else - state= R_Q2; - break; - case R_ESC_SLASH_Q2: - state= R_Q2; + case R_SLASH_IN_Q: + state= R_Q; break; + } - if (!no_save) + if (!skip_char) { /* Could be a multibyte character */ /* This code is based on the code in "sql_load.cc" */ @@ -2325,7 +3415,7 @@ int read_line(char *buf, int size) for (i= 1; i < charlen; i++) { if (feof(cur_file->file)) - goto found_eof; /* FIXME: could we just break here?! */ + goto found_eof; c= my_getc(cur_file->file); *p++ = c; } @@ -2342,102 +3432,191 @@ int read_line(char *buf, int size) *p++= c; } } - *p= 0; /* Always end with \0 */ - DBUG_RETURN(feof(cur_file->file)); + die("The input buffer is too small for this query.x\n" \ + "check your query or increase MAX_QUERY and recompile"); + DBUG_RETURN(0); } + /* - Create a query from a set of lines + Convert the read query to result format version 1 - SYNOPSIS - read_query() - q_ptr pointer where to return the new query + That is: After newline, all spaces need to be skipped + unless the previous char was a quote - DESCRIPTION - Converts lines returned by read_line into a query, this involves - parsing the first word in the read line to find the query type. + This is due to an old bug that has now been fixed, but the + version 1 output format is preserved by using this function - - A -- comment may contain a valid query as the first word after the - comment start. Thus it's always checked to see if that is the case. - The advantage with this approach is to be able to execute commands - terminated by new line '\n' regardless how many "delimiter" it contain. - - If query starts with @ this will specify a file to .... */ -static char read_query_buf[MAX_QUERY]; - -int read_query(struct st_query** q_ptr) +void convert_to_format_v1(char* query) { - char *p= read_query_buf, *p1; - struct st_query* q; - DBUG_ENTER("read_query"); + int last_c_was_quote= 0; + char *p= query, *write= query; + char *end= strend(query); + char last_c; + + while (p <= end) + { + if (*p == '\n' && !last_c_was_quote) + { + *write++ = *p++; /* Save the newline */ + + /* Skip any spaces on next line */ + while (*p && my_isspace(charset_info, *p)) + p++; + + last_c_was_quote= 0; + } + else if (*p == '\'' || *p == '"' || *p == '`') + { + last_c= *p; + *write++ = *p++; + + /* Copy anything until the next quote of same type */ + while (*p && *p != last_c) + *write++ = *p++; + + *write++ = *p++; + + last_c_was_quote= 1; + } + else + { + *write++ = *p++; + last_c_was_quote= 0; + } + } +} + + +/* + Check for unexpected "junk" after the end of query + This is normally caused by missing delimiters +*/ + +void check_eol_junk(const char *eol) +{ + const char *p= eol; + DBUG_ENTER("check_eol_junk"); + DBUG_PRINT("enter", ("eol: %s", eol)); + /* Remove all spacing chars except new line */ + while (*p && my_isspace(charset_info, *p) && (*p != '\n')) + p++; + + /* Check for extra delimiter */ + if (*p && !strncmp(p, delimiter, delimiter_length)) + die("Extra delimiter \"%s\" found", delimiter); + + /* Allow trailing # comment */ + if (*p && *p != '#') + { + if (*p == '\n') + die("Missing delimiter"); + die("End of line junk detected: \"%s\"", p); + } + DBUG_VOID_RETURN; +} + + + +/* + Create a command from a set of lines + + SYNOPSIS + read_command() + command_ptr pointer where to return the new query + + DESCRIPTION + Converts lines returned by read_line into a command, this involves + parsing the first word in the read line to find the command type. + + + A -- comment may contain a valid query as the first word after the + comment start. Thus it's always checked to see if that is the case. + The advantage with this approach is to be able to execute commands + terminated by new line '\n' regardless how many "delimiter" it contain. + +*/ + +#define MAX_QUERY (256*1024) /* 256K -- a test in sp-big is >128K */ +static char read_command_buf[MAX_QUERY]; + +int read_command(struct st_command** command_ptr) +{ + char *p= read_command_buf; + struct st_command* command; + DBUG_ENTER("read_command"); if (parser.current_line < parser.read_lines) { - get_dynamic(&q_lines, (gptr) q_ptr, parser.current_line) ; + get_dynamic(&q_lines, (gptr) command_ptr, parser.current_line) ; DBUG_RETURN(0); } - if (!(*q_ptr= q= (struct st_query*) my_malloc(sizeof(*q), MYF(MY_WME))) || - insert_dynamic(&q_lines, (gptr) &q)) + if (!(*command_ptr= command= + (struct st_command*) my_malloc(sizeof(*command), MYF(MY_WME))) || + insert_dynamic(&q_lines, (gptr) &command)) die(NullS); - q->record_file[0]= 0; - q->require_file= 0; - q->first_word_len= 0; + command->record_file[0]= 0; + command->require_file= 0; + command->first_word_len= 0; + command->query_len= 0; - q->type= Q_UNKNOWN; - q->query_buf= q->query= 0; - if (read_line(read_query_buf, sizeof(read_query_buf))) + command->type= Q_UNKNOWN; + command->query_buf= command->query= 0; + read_command_buf[0]= 0; + if (read_line(read_command_buf, sizeof(read_command_buf))) { - DBUG_PRINT("warning",("too long query")); + check_eol_junk(read_command_buf); DBUG_RETURN(1); } - DBUG_PRINT("info", ("query: %s", read_query_buf)); + + convert_to_format_v1(read_command_buf); + + DBUG_PRINT("info", ("query: %s", read_command_buf)); if (*p == '#') { - q->type= Q_COMMENT; + command->type= Q_COMMENT; /* This goto is to avoid losing the "expected error" info. */ goto end; } - memcpy((gptr) q->expected_errno, (gptr) global_expected_errno, - sizeof(global_expected_errno)); - q->expected_errors= global_expected_errors; - q->abort_on_error= (global_expected_errors == 0 && abort_on_error); + if (!parsing_disabled) + { + memcpy(&command->expected_errors, &saved_expected_errors, + sizeof(saved_expected_errors)); + DBUG_PRINT("info", ("There are %d expected errors", + command->expected_errors.count)); + command->abort_on_error= (command->expected_errors.count == 0 && + abort_on_error); + } + if (p[0] == '-' && p[1] == '-') { - q->type= Q_COMMENT_WITH_COMMAND; + command->type= Q_COMMENT_WITH_COMMAND; p+= 2; /* To calculate first word */ } - else + else if (!parsing_disabled) { while (*p && my_isspace(charset_info, *p)) p++ ; - if (*p == '@') - { - p++; - p1 = q->record_file; - while (!my_isspace(charset_info, *p) && - p1 < q->record_file + sizeof(q->record_file) - 1) - *p1++ = *p++; - *p1 = 0; - } } end: while (*p && my_isspace(charset_info, *p)) p++; - if (!(q->query_buf= q->query= my_strdup(p, MYF(MY_WME)))) + + if (!(command->query_buf= command->query= my_strdup(p, MYF(MY_WME)))) die(NullS); /* Calculate first word and first argument */ - for (p= q->query; *p && !my_isspace(charset_info, *p) ; p++) ; - q->first_word_len= (uint) (p - q->query); + for (p= command->query; *p && !my_isspace(charset_info, *p) ; p++) ; + command->first_word_len= (uint) (p - command->query); while (*p && my_isspace(charset_info, *p)) p++; - q->first_argument= p; - q->end= strend(q->query); + command->first_argument= p; + command->end= strend(command->query); + command->query_len= (command->end - command->query); parser.read_lines++; DBUG_RETURN(0); } @@ -2445,39 +3624,41 @@ end: static struct my_option my_long_options[] = { - {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", - 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, - {"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0, - GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, + 0, 0, 0, 0, 0, 0}, {"basedir", 'b', "Basedir for tests.", (gptr*) &opt_basedir, (gptr*) &opt_basedir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"big-test", 'B', "Define BIG_TEST to 1.", (gptr*) &opt_big_test, - (gptr*) &opt_big_test, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"compress", 'C', "Use the compressed server/client protocol.", (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, - 0, 0, 0, 0, 0, 0}, + {"cursor-protocol", OPT_CURSOR_PROTOCOL, "Use cursors for prepared statements.", + (gptr*) &cursor_protocol, (gptr*) &cursor_protocol, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"database", 'D', "Database to use.", (gptr*) &db, (gptr*) &db, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef DBUG_OFF + {"debug", '#', "This is a non-debug version. Catch this and exit", + 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#else + {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"manager-user", OPT_MANAGER_USER, "Undocumented: Used for debugging.", - (gptr*) &manager_user, (gptr*) &manager_user, 0, GET_STR, REQUIRED_ARG, 0, - 0, 0, 0, 0, 0}, - {"manager-host", OPT_MANAGER_HOST, "Undocumented: Used for debugging.", - (gptr*) &manager_host, (gptr*) &manager_host, 0, GET_STR, REQUIRED_ARG, - 0, 0, 0, 0, 0, 0}, - {"manager-password", OPT_MANAGER_PASSWD, "Undocumented: Used for debugging.", - 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"manager-port", OPT_MANAGER_PORT, "Undocumented: Used for debugging.", - (gptr*) &manager_port, (gptr*) &manager_port, 0, GET_INT, REQUIRED_ARG, - MYSQL_MANAGER_PORT, 0, 0, 0, 0, 0}, - {"manager-wait-timeout", OPT_MANAGER_WAIT_TIMEOUT, - "Undocumented: Used for debugging.", (gptr*) &manager_wait_timeout, - (gptr*) &manager_wait_timeout, 0, GET_INT, REQUIRED_ARG, 3, 0, 0, 0, 0, 0}, + {"include", 'i', "Include SQL before each test case.", (gptr*) &opt_include, + (gptr*) &opt_include, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"mark-progress", OPT_MARK_PROGRESS, + "Write linenumber and elapsed time to .progress ", + (gptr*) &opt_mark_progress, (gptr*) &opt_mark_progress, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"max-connect-retries", OPT_MAX_CONNECT_RETRIES, + "Max number of connection attempts when connecting to server", + (gptr*) &opt_max_connect_retries, (gptr*) &opt_max_connect_retries, 0, + GET_INT, REQUIRED_ARG, 500, 1, 10000, 0, 0, 0}, {"password", 'p', "Password to use when connecting to server.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection.", (gptr*) &port, - (gptr*) &port, 0, GET_INT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, + (gptr*) &port, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"ps-protocol", OPT_PS_PROTOCOL, "Use prepared statements protocol for communication", (gptr*) &ps_protocol, (gptr*) &ps_protocol, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -2498,11 +3679,14 @@ static struct my_option my_long_options[] = "Don't use the memory allocation checking.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"sleep", 'T', "Sleep always this many seconds on sleep commands.", - (gptr*) &opt_sleep, (gptr*) &opt_sleep, 0, GET_INT, REQUIRED_ARG, 0, 0, 0, + (gptr*) &opt_sleep, (gptr*) &opt_sleep, 0, GET_INT, REQUIRED_ARG, -1, 0, 0, 0, 0, 0}, {"socket", 'S', "Socket file to use for connection.", (gptr*) &unix_sock, (gptr*) &unix_sock, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"sp-protocol", OPT_SP_PROTOCOL, "Use stored procedures for select", + (gptr*) &sp_protocol, (gptr*) &sp_protocol, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #include "sslopt-longopts.h" {"test-file", 'x', "Read test from/in this file (default stdin).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -2516,13 +3700,16 @@ static struct my_option my_long_options[] = GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"view-protocol", OPT_VIEW_PROTOCOL, "Use views for select", + (gptr*) &view_protocol, (gptr*) &view_protocol, 0, + GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; #include -static void print_version(void) +void print_version(void) { printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,MTEST_VERSION, MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); @@ -2543,6 +3730,52 @@ void usage() #include +/* + Read arguments for embedded server and put them into + embedded_server_args[] +*/ + +void read_embedded_server_arguments(const char *name) +{ + char argument[1024],buff[FN_REFLEN], *str=0; + FILE *file; + + if (!test_if_hard_path(name)) + { + strxmov(buff, opt_basedir, name, NullS); + name=buff; + } + fn_format(buff, name, "", "", MY_UNPACK_FILENAME); + + if (!embedded_server_arg_count) + { + embedded_server_arg_count=1; + embedded_server_args[0]= (char*) ""; /* Progname */ + } + if (!(file=my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME)))) + die("Failed to open file %s", buff); + + while (embedded_server_arg_count < MAX_EMBEDDED_SERVER_ARGS && + (str=fgets(argument,sizeof(argument), file))) + { + *(strend(str)-1)=0; /* Remove end newline */ + if (!(embedded_server_args[embedded_server_arg_count]= + (char*) my_strdup(str,MYF(MY_WME)))) + { + my_fclose(file,MYF(0)); + die("Out of memory"); + + } + embedded_server_arg_count++; + } + my_fclose(file,MYF(0)); + if (str) + die("Too many arguments in option file: %s",name); + + return; +} + + static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) @@ -2556,40 +3789,36 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case 'r': record = 1; break; - case (int)OPT_MANAGER_PASSWD: - my_free(manager_pass,MYF(MY_ALLOW_ZERO_PTR)); - manager_pass=my_strdup(argument, MYF(MY_FAE)); - while (*argument) *argument++= 'x'; /* Destroy argument */ - break; case 'x': + { + char buff[FN_REFLEN]; + if (!test_if_hard_path(argument)) { - char buff[FN_REFLEN]; - if (!test_if_hard_path(argument)) - { - strxmov(buff, opt_basedir, argument, NullS); - argument= buff; - } - fn_format(buff, argument, "", "", 4); - DBUG_ASSERT(cur_file == file_stack && cur_file->file == 0); - if (!(cur_file->file= - my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0)))) - die("Could not open %s: errno = %d", buff, errno); - cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); - break; + strxmov(buff, opt_basedir, argument, NullS); + argument= buff; } + fn_format(buff, argument, "", "", MY_UNPACK_FILENAME); + DBUG_ASSERT(cur_file == file_stack && cur_file->file == 0); + if (!(cur_file->file= + my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0)))) + die("Could not open %s: errno = %d", buff, errno); + cur_file->file_name= my_strdup(buff, MYF(MY_FAE)); + cur_file->lineno= 1; + break; + } case 'm': + { + static char buff[FN_REFLEN]; + if (!test_if_hard_path(argument)) { - static char buff[FN_REFLEN]; - if (!test_if_hard_path(argument)) - { - strxmov(buff, opt_basedir, argument, NullS); - argument= buff; - } - fn_format(buff, argument, "", "", 4); - timer_file= buff; - unlink(timer_file); /* Ignore error, may not exist */ - break; + strxmov(buff, opt_basedir, argument, NullS); + argument= buff; } + fn_format(buff, argument, "", "", MY_UNPACK_FILENAME); + timer_file= buff; + unlink(timer_file); /* Ignore error, may not exist */ + break; + } case 'p': if (argument) { @@ -2611,7 +3840,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), embedded_server_arg_count=1; embedded_server_args[0]= (char*) ""; } - if (embedded_server_arg_count == MAX_SERVER_ARGS-1 || + if (embedded_server_arg_count == MAX_EMBEDDED_SERVER_ARGS-1 || !(embedded_server_args[embedded_server_arg_count++]= my_strdup(argument, MYF(MY_FAE)))) { @@ -2619,8 +3848,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), } break; case 'F': - if (read_server_arguments(argument)) - die(NullS); + read_embedded_server_arguments(argument); break; case OPT_SKIP_SAFEMALLOC: #ifdef SAFEMALLOC @@ -2659,14 +3887,16 @@ int parse_args(int argc, char **argv) return 0; } -char* safe_str_append(char *buf, const char *str, int size) -{ - int i,c ; - for (i = 0; (c = *str++) && i < size - 1; i++) - *buf++ = c; - *buf = 0; - return buf; -} + +/* + Write the content of str into file + + SYNOPSIS + str_to_file + fname - name of file to truncate/create and write to + str - content to write to file + size - size of content witten to file +*/ void str_to_file(const char *fname, char *str, int size) { @@ -2675,38 +3905,213 @@ void str_to_file(const char *fname, char *str, int size) if (!test_if_hard_path(fname)) { strxmov(buff, opt_basedir, fname, NullS); - fname=buff; + fname= buff; } - fn_format(buff,fname,"","",4); - - if ((fd = my_open(buff, O_WRONLY | O_CREAT | O_TRUNC, - MYF(MY_WME | MY_FFNF))) < 0) + fn_format(buff, fname, "", "", MY_UNPACK_FILENAME); + + if ((fd= my_open(buff, O_WRONLY | O_CREAT | O_TRUNC, + MYF(MY_WME | MY_FFNF))) < 0) die("Could not open %s: errno = %d", buff, errno); if (my_write(fd, (byte*)str, size, MYF(MY_WME|MY_FNABP))) die("write failed"); my_close(fd, MYF(0)); } -void reject_dump(const char *record_file, char *buf, int size) + +void dump_result_to_reject_file(const char *record_file, char *buf, int size) { char reject_file[FN_REFLEN]; - str_to_file(fn_format(reject_file, record_file,"",".reject",2), buf, size); + str_to_file(fn_format(reject_file, record_file, "", ".reject", + MY_REPLACE_EXT), + buf, size); +} + +void dump_result_to_log_file(const char *record_file, char *buf, int size) +{ + char log_file[FN_REFLEN]; + str_to_file(fn_format(log_file, record_file, "", ".log", + MY_REPLACE_EXT), + buf, size); +} + +void dump_progress(const char *record_file) +{ + char log_file[FN_REFLEN]; + str_to_file(fn_format(log_file, record_file, "", ".progress", + MY_REPLACE_EXT), + ds_progress.str, ds_progress.length); +} + +void check_regerr(my_regex_t* r, int err) +{ + char err_buf[1024]; + + if (err) + { + my_regerror(err,r,err_buf,sizeof(err_buf)); + die("Regex error: %s\n", err_buf); + } } -/* Append the string to ds, with optional replace */ +#ifdef __WIN__ -static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, - int len) +DYNAMIC_ARRAY patterns; + +/* + init_win_path_patterns + + DESCRIPTION + Setup string patterns that will be used to detect filenames that + needs to be converted from Win to Unix format + +*/ + +void init_win_path_patterns() { - if (glob_replace) + /* List of string patterns to match in order to find paths */ + const char* paths[] = { "$MYSQL_TEST_DIR", + "$MYSQL_TMP_DIR", + "./test/", 0 }; + int num_paths= 3; + int i; + char* p; + + DBUG_ENTER("init_win_path_patterns"); + + my_init_dynamic_array(&patterns, sizeof(const char*), 16, 16); + + /* Loop through all paths in the array */ + for (i= 0; i < num_paths; i++) { - len=(int) replace_strings(glob_replace, &out_buff, &out_length, val); - if (len == -1) - die("Out of memory in replace"); - val=out_buff; + VAR* v; + if (*(paths[i]) == '$') + { + v= var_get(paths[i], 0, 0, 0); + p= my_strdup(v->str_val, MYF(MY_FAE)); + } + else + p= my_strdup(paths[i], MYF(MY_FAE)); + + if (insert_dynamic(&patterns, (gptr) &p)) + die(NullS); + + DBUG_PRINT("info", ("p: %s", p)); + while (*p) + { + if (*p == '/') + *p='\\'; + p++; + } + } + DBUG_VOID_RETURN; +} + +void free_win_path_patterns() +{ + uint i= 0; + for (i=0 ; i < patterns.elements ; i++) + { + const char** pattern= dynamic_element(&patterns, i, const char**); + my_free((gptr) *pattern, MYF(0)); + } + delete_dynamic(&patterns); +} + +/* + fix_win_paths + + DESCRIPTION + Search the string 'val' for the patterns that are known to be + strings that contain filenames. Convert all \ to / in the + filenames that are found. + + Ex: + val = 'Error "c:\mysql\mysql-test\var\test\t1.frm" didn't exist' + => $MYSQL_TEST_DIR is found by strstr + => all \ from c:\mysql\m... until next space is converted into / +*/ + +void fix_win_paths(const char *val, int len) +{ + uint i; + char *p; + + DBUG_ENTER("fix_win_paths"); + for (i= 0; i < patterns.elements; i++) + { + const char** pattern= dynamic_element(&patterns, i, const char**); + DBUG_PRINT("info", ("pattern: %s", *pattern)); + if (strlen(*pattern) == 0) continue; + /* Search for the path in string */ + while ((p= strstr(val, *pattern))) + { + DBUG_PRINT("info", ("Found %s in val p: %s", *pattern, p)); + + while (*p && !my_isspace(charset_info, *p)) + { + if (*p == '\\') + *p= '/'; + p++; + } + DBUG_PRINT("info", ("Converted \\ to /, p: %s", p)); + } + } + DBUG_PRINT("exit", (" val: %s, len: %d", val, len)); + DBUG_VOID_RETURN; +} +#endif + + + +/* + Append the result for one field to the dynamic string ds +*/ + +void append_field(DYNAMIC_STRING *ds, uint col_idx, MYSQL_FIELD* field, + const char* val, ulonglong len, bool is_null) +{ + if (col_idx < max_replace_column && replace_column[col_idx]) + { + val= replace_column[col_idx]; + len= strlen(val); + } + else if (is_null) + { + val= "NULL"; + len= 4; + } +#ifdef __WIN__ + else if ((field->type == MYSQL_TYPE_DOUBLE || + field->type == MYSQL_TYPE_FLOAT ) && + field->decimals >= 31) + { + /* Convert 1.2e+018 to 1.2e+18 and 1.2e-018 to 1.2e-18 */ + char *start= strchr(val, 'e'); + if (start && strlen(start) >= 5 && + (start[1] == '-' || start[1] == '+') && start[2] == '0') + { + start+=2; /* Now points at first '0' */ + /* Move all chars after the first '0' one step left */ + memmove(start, start + 1, strlen(start)); + len--; + } + } +#endif + + if (!display_result_vertically) + { + if (col_idx) + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append_mem(ds, val, (int)len); + } + else + { + dynstr_append(ds, field->name); + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append_mem(ds, val, (int)len); + dynstr_append_mem(ds, "\n", 1); } - dynstr_append_mem(ds, val, len); } @@ -2715,676 +4120,97 @@ static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val, Values may be converted with 'replace_column' */ -static void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) +void append_result(DYNAMIC_STRING *ds, MYSQL_RES *res) { MYSQL_ROW row; uint num_fields= mysql_num_fields(res); - MYSQL_FIELD *fields= !display_result_vertically ? 0 : mysql_fetch_fields(res); - unsigned long *lengths; + MYSQL_FIELD *fields= mysql_fetch_fields(res); + ulong *lengths; + while ((row = mysql_fetch_row(res))) { uint i; lengths = mysql_fetch_lengths(res); for (i = 0; i < num_fields; i++) - { - const char *val= row[i]; - ulonglong len= lengths[i]; - - if (i < max_replace_column && replace_column[i]) - { - val= replace_column[i]; - len= strlen(val); - } - if (!val) - { - val= "NULL"; - len= 4; - } - if (!display_result_vertically) - { - if (i) - dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append_mem(ds, val, len); - } - else - { - dynstr_append(ds, fields[i].name); - dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append_mem(ds, val, len); - dynstr_append_mem(ds, "\n", 1); - } - } + append_field(ds, i, &fields[i], + (const char*)row[i], lengths[i], !row[i]); if (!display_result_vertically) dynstr_append_mem(ds, "\n", 1); } - free_replace_column(); } /* -* flags control the phased/stages of query execution to be performed -* if QUERY_SEND bit is on, the query will be sent. If QUERY_REAP is on -* the result will be read - for regular query, both bits must be on + Append all results from ps execution to the dynamic string separated + with '\t'. Values may be converted with 'replace_column' */ -static int run_query_normal(MYSQL *mysql, struct st_query *q, int flags); -static int run_query_stmt (MYSQL *mysql, struct st_query *q, int flags); -static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds); -static int run_query_stmt_handle_error(char *query, struct st_query *q, - MYSQL_STMT *stmt, DYNAMIC_STRING *ds); -static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields, - DYNAMIC_STRING *ds); - -static int run_query(MYSQL *mysql, struct st_query *q, int flags) +void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, + MYSQL_FIELD *fields, uint num_fields) { - - /* - Try to find out if we can run this statement using the prepared - statement protocol. - - We don't have a mysql_stmt_send_execute() so we only handle - complete SEND+REAP. - - If it is a '?' in the query it may be a SQL level prepared - statement already and we can't do it twice - */ - - if (ps_protocol_enabled && disable_info && - (flags & QUERY_SEND) && (flags & QUERY_REAP) && ps_match_re(q->query)) - return run_query_stmt(mysql, q, flags); - return run_query_normal(mysql, q, flags); -} - - -static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags) -{ - MYSQL_RES* res= 0; + MYSQL_BIND *bind; + my_bool *is_null; + ulong *length; uint i; - int error= 0, err= 0, counter= 0; - DYNAMIC_STRING *ds; - DYNAMIC_STRING ds_tmp; - DYNAMIC_STRING eval_query; - char* query; - int query_len, got_error_on_send= 0; - DBUG_ENTER("run_query_normal"); - DBUG_PRINT("enter",("flags: %d", flags)); - - if (q->type != Q_EVAL) - { - query = q->query; - query_len = strlen(query); - } - else - { - init_dynamic_string(&eval_query, "", 16384, 65536); - do_eval(&eval_query, q->query); - query = eval_query.str; - query_len = eval_query.length; - } - DBUG_PRINT("enter", ("query: '%-.60s'", query)); - if (q->record_file[0]) - { - init_dynamic_string(&ds_tmp, "", 16384, 65536); - ds = &ds_tmp; - } - else - ds= &ds_res; + /* Allocate array with bind structs, lengths and NULL flags */ + bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND), + MYF(MY_WME | MY_FAE | MY_ZEROFILL)); + length= (ulong*) my_malloc(num_fields * sizeof(ulong), + MYF(MY_WME | MY_FAE)); + is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool), + MYF(MY_WME | MY_FAE)); - if (flags & QUERY_SEND) + /* Allocate data for the result of each field */ + for (i= 0; i < num_fields; i++) { - got_error_on_send= mysql_send_query(mysql, query, query_len); - if (got_error_on_send && q->expected_errno[0].type == ERR_EMPTY) - die("unable to send query '%s' (mysql_errno=%d , errno=%d)", - query, mysql_errno(mysql), errno); + uint max_length= fields[i].max_length + 1; + bind[i].buffer_type= MYSQL_TYPE_STRING; + bind[i].buffer= (char *)my_malloc(max_length, MYF(MY_WME | MY_FAE)); + bind[i].buffer_length= max_length; + bind[i].is_null= &is_null[i]; + bind[i].length= &length[i]; + + DBUG_PRINT("bind", ("col[%d]: buffer_type: %d, buffer_length: %d", + i, bind[i].buffer_type, bind[i].buffer_length)); } - do + if (mysql_stmt_bind_result(stmt, bind)) + die("mysql_stmt_bind_result failed: %d: %s", + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); + + while (mysql_stmt_fetch(stmt) == 0) { - if ((flags & QUERY_SEND) && !disable_query_log && !counter) - { - replace_dynstr_append_mem(ds,query, query_len); - dynstr_append_mem(ds, delimiter, delimiter_length); + for (i= 0; i < num_fields; i++) + append_field(ds, i, &fields[i], (const char *) bind[i].buffer, + *bind[i].length, *bind[i].is_null); + if (!display_result_vertically) dynstr_append_mem(ds, "\n", 1); - } - if (!(flags & QUERY_REAP)) - DBUG_RETURN(0); + } - if (got_error_on_send || - (!counter && (*mysql->methods->read_query_result)(mysql)) || - (!(last_result= res= mysql_store_result(mysql)) && - mysql_field_count(mysql))) - { - if (q->require_file) - { - abort_not_supported_test(); - } - if (q->abort_on_error) - die("query '%s' failed: %d: %s", query, - mysql_errno(mysql), mysql_error(mysql)); + if (mysql_stmt_fetch(stmt) != MYSQL_NO_DATA) + die("fetch didn't end with MYSQL_NO_DATA from statement: %d %s", + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); - for (i=0 ; (uint) i < q->expected_errors ; i++) - { - if (((q->expected_errno[i].type == ERR_ERRNO) && - (q->expected_errno[i].code.errnum == mysql_errno(mysql))) || - ((q->expected_errno[i].type == ERR_SQLSTATE) && - (strcmp(q->expected_errno[i].code.sqlstate,mysql_sqlstate(mysql)) == 0))) - { - if (i == 0 && q->expected_errors == 1) - { - /* Only log error if there is one possible error */ - dynstr_append_mem(ds,"ERROR ",6); - replace_dynstr_append_mem(ds, mysql_sqlstate(mysql), - strlen(mysql_sqlstate(mysql))); - dynstr_append_mem(ds, ": ", 2); - replace_dynstr_append_mem(ds,mysql_error(mysql), - strlen(mysql_error(mysql))); - dynstr_append_mem(ds,"\n",1); - } - /* Don't log error if we may not get an error */ - else if (q->expected_errno[0].type == ERR_SQLSTATE || - (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0)) - dynstr_append(ds,"Got one of the listed errors\n"); - goto end; /* Ok */ - } - } - DBUG_PRINT("info",("i: %d expected_errors: %d", i, - q->expected_errors)); - dynstr_append_mem(ds, "ERROR ",6); - replace_dynstr_append_mem(ds, mysql_sqlstate(mysql), - strlen(mysql_sqlstate(mysql))); - dynstr_append_mem(ds,": ",2); - replace_dynstr_append_mem(ds, mysql_error(mysql), - strlen(mysql_error(mysql))); - dynstr_append_mem(ds,"\n",1); - if (i) - { - if (q->expected_errno[0].type == ERR_ERRNO) - verbose_msg("query '%s' failed with wrong errno %d instead of %d...", - q->query, mysql_errno(mysql), q->expected_errno[0].code.errnum); - else - verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...", - q->query, mysql_sqlstate(mysql), q->expected_errno[0].code.sqlstate); - error= 1; - goto end; - } - verbose_msg("query '%s' failed: %d: %s", q->query, mysql_errno(mysql), - mysql_error(mysql)); - /* - if we do not abort on error, failure to run the query does - not fail the whole test case - */ - goto end; - - } - - if (handle_no_error(q)) - { - error= 1; - goto end; - } - - if (!disable_result_log) - { - ulong affected_rows; /* Ok to be undef if 'disable_info' is set */ - LINT_INIT(affected_rows); - - if (res) - { - MYSQL_FIELD *field= mysql_fetch_fields(res); - uint num_fields= mysql_num_fields(res); - - if (display_metadata) - run_query_display_metadata(field, num_fields, ds); - - if (!display_result_vertically) - { - for (i = 0; i < num_fields; i++) - { - if (i) - dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append_mem(ds, field[i].name, - strlen(field[i].name)); - } - dynstr_append_mem(ds, "\n", 1); - } - append_result(ds, res); - } - - /* - Need to call mysql_affected_rows() before the new - query to find the warnings - */ - if (!disable_info) - affected_rows= (ulong)mysql_affected_rows(mysql); - - /* Add all warnings to the result */ - if (!disable_warnings && mysql_warning_count(mysql)) - { - MYSQL_RES *warn_res=0; - uint count= mysql_warning_count(mysql); - if (!mysql_real_query(mysql, "SHOW WARNINGS", 13)) - { - warn_res= mysql_store_result(mysql); - } - if (!warn_res) - die("Warning count is %u but didn't get any warnings\n", - count); - else - { - dynstr_append_mem(ds, "Warnings:\n", 10); - append_result(ds, warn_res); - mysql_free_result(warn_res); - } - } - if (!disable_info) - { - char buf[40]; - sprintf(buf,"affected rows: %lu\n", affected_rows); - dynstr_append(ds, buf); - if (mysql_info(mysql)) - { - dynstr_append(ds, "info: "); - dynstr_append(ds, mysql_info(mysql)); - dynstr_append_mem(ds, "\n", 1); - } - } - } - - if (record) - { - if (!q->record_file[0] && !result_file) - die("Missing result file"); - if (!result_file) - str_to_file(q->record_file, ds->str, ds->length); - } - else if (q->record_file[0]) - { - error = check_result(ds, q->record_file, q->require_file); - } - if (res) - mysql_free_result(res); - last_result= 0; - counter++; - } while (!(err= mysql_next_result(mysql))); - if (err >= 1) - mysql_error(mysql); - -end: - free_replace(); - last_result=0; - if (ds == &ds_tmp) - dynstr_free(&ds_tmp); - if (q->type == Q_EVAL) - dynstr_free(&eval_query); - - /* - We save the return code (mysql_errno(mysql)) from the last call sent - to the server into the mysqltest builtin variable $mysql_errno. This - variable then can be used from the test case itself. - */ - var_set_errno(mysql_errno(mysql)); - DBUG_RETURN(error); + for (i= 0; i < num_fields; i++) + { + /* Free data for output */ + my_free((gptr)bind[i].buffer, MYF(MY_WME | MY_FAE)); + } + /* Free array with bind structs, lengths and NULL flags */ + my_free((gptr)bind , MYF(MY_WME | MY_FAE)); + my_free((gptr)length , MYF(MY_WME | MY_FAE)); + my_free((gptr)is_null , MYF(MY_WME | MY_FAE)); } -/****************************************************************************\ - * If --ps-protocol run ordinary statements using prepared statemnt C API -\****************************************************************************/ - /* - We don't have a mysql_stmt_send_execute() so we only handle - complete SEND+REAP + Append metadata for fields to output */ -static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags) -{ - int error= 0; /* Function return code if "goto end;" */ - int err; /* Temporary storage of return code from calls */ - int query_len, got_error_on_execute; - uint num_rows; - char *query; - MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */ - DYNAMIC_STRING *ds; - DYNAMIC_STRING ds_tmp; - DYNAMIC_STRING eval_query; - MYSQL_STMT *stmt; - DBUG_ENTER("run_query_stmt"); - - /* - We must allocate a new stmt for each query in this program becasue this - may be a new connection. - */ - if (!(stmt= mysql_stmt_init(mysql))) - die("unable init stmt structure"); - - if (q->type != Q_EVAL) - { - query= q->query; - query_len= strlen(query); - } - else - { - init_dynamic_string(&eval_query, "", 16384, 65536); - do_eval(&eval_query, q->query); - query= eval_query.str; - query_len= eval_query.length; - } - DBUG_PRINT("query", ("'%-.60s'", query)); - - if (q->record_file[0]) - { - init_dynamic_string(&ds_tmp, "", 16384, 65536); - ds= &ds_tmp; - } - else - ds= &ds_res; - - /* Store the query into the output buffer if not disabled */ - if (!disable_query_log) - { - replace_dynstr_append_mem(ds,query, query_len); - dynstr_append_mem(ds, delimiter, delimiter_length); - dynstr_append_mem(ds, "\n", 1); - } - - /* - We use the prepared statement interface but there is actually no - '?' in the query. If unpreparable we fall back to use normal - C API. - */ - if ((err= mysql_stmt_prepare(stmt, query, query_len)) == CR_NO_PREPARE_STMT) - return run_query_normal(mysql, q, flags); - - if (err != 0) - { - if (q->abort_on_error) - { - die("query '%s' failed: %d: %s", query, - mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); - } - else - { - /* - Preparing is part of normal execution and some errors may be expected - */ - error= run_query_stmt_handle_error(query, q, stmt, ds); - goto end; - } - } - - /* We may have got warnings already, collect them if any */ - /* FIXME we only want this if the statement succeeds I think */ - run_query_stmt_handle_warnings(mysql, ds); - - /* - No need to call mysql_stmt_bind_param() because we have no - parameter markers. - - To optimize performance we use a global 'stmt' that is initiated - once. A new prepare will implicitely close the old one. When we - terminate we will lose the connection, this also closes the last - prepared statement. - */ - - if ((got_error_on_execute= mysql_stmt_execute(stmt)) != 0) /* 0 == Success */ - { - if (q->abort_on_error) - { - /* We got an error, unexpected */ - die("unable to execute statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - query, mysql_stmt_error(stmt), - mysql_stmt_errno(stmt), got_error_on_execute); - } - else - { - /* We got an error, maybe expected */ - error= run_query_stmt_handle_error(query, q, stmt, ds); - goto end; - } - } - - /* - We instruct that we want to update the "max_length" field in - mysql_stmt_store_result(), this is our only way to know how much - buffer to allocate for result data - */ - { - my_bool one= 1; - if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, - (void*) &one) != 0) - die("unable to set stmt attribute " - "'STMT_ATTR_UPDATE_MAX_LENGTH': %s (returned=%d)", - query, err); - } - - /* - If we got here the statement succeeded and was expected to do so, - get data. Note that this can still give errors found during execution! - */ - if ((err= mysql_stmt_store_result(stmt)) != 0) - { - if (q->abort_on_error) - { - /* We got an error, unexpected */ - die("unable to execute statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - query, mysql_stmt_error(stmt), - mysql_stmt_errno(stmt), got_error_on_execute); - } - else - { - /* We got an error, maybe expected */ - error= run_query_stmt_handle_error(query, q, stmt, ds); - goto end; - } - } - - /* If we got here the statement was both executed and read succeesfully */ - if (handle_no_error(q)) - { - error= 1; - goto end; - } - - num_rows= mysql_stmt_num_rows(stmt); - - /* - Not all statements creates a result set. If there is one we can - now create another normal result set that contains the meta - data. This set can be handled almost like any other non prepared - statement result set. - */ - if (!disable_result_log && ((res= mysql_stmt_result_metadata(stmt)) != NULL)) - { - /* Take the column count from meta info */ - MYSQL_FIELD *field= mysql_fetch_fields(res); - uint num_fields= mysql_num_fields(res); - - /* FIXME check error from the above? */ - - if (display_metadata) - run_query_display_metadata(field, num_fields, ds); - - if (!display_result_vertically) - { - /* Display the table heading with the names tab separated */ - uint col_idx; - for (col_idx= 0; col_idx < num_fields; col_idx++) - { - if (col_idx) - dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append_mem(ds, field[col_idx].name, - strlen(field[col_idx].name)); - } - dynstr_append_mem(ds, "\n", 1); - } - - /* Now we are to put the real result into the output buffer */ - /* FIXME when it works, create function append_stmt_result() */ - { - MYSQL_BIND *bind; - my_bool *is_null; - unsigned long *length; - /* FIXME we don't handle vertical display ..... */ - uint col_idx, row_idx; - - /* Allocate array with bind structs, lengths and NULL flags */ - bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND), - MYF(MY_WME | MY_FAE)); - length= (unsigned long*) my_malloc(num_fields * sizeof(unsigned long), - MYF(MY_WME | MY_FAE)); - is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool), - MYF(MY_WME | MY_FAE)); - - for (col_idx= 0; col_idx < num_fields; col_idx++) - { - /* Allocate data for output */ - /* - FIXME it may be a bug that for non string/blob types - 'max_length' is 0, should try out 'length' in that case - */ - uint max_length= max(field[col_idx].max_length + 1, 1024); - char *str_data= (char *) my_malloc(max_length, MYF(MY_WME | MY_FAE)); - - bind[col_idx].buffer_type= MYSQL_TYPE_STRING; - bind[col_idx].buffer= (char *)str_data; - bind[col_idx].buffer_length= max_length; - bind[col_idx].is_null= &is_null[col_idx]; - bind[col_idx].length= &length[col_idx]; - } - - /* Fill in the data into the structures created above */ - if ((err= mysql_stmt_bind_result(stmt, bind)) != 0) - die("unable to bind result to statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - query, - mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); - - /* Read result from each row */ - for (row_idx= 0; row_idx < num_rows; row_idx++) - { - if ((err= mysql_stmt_fetch(stmt)) != 0) - die("unable to fetch all rows from statement '%s': " - "%s (mysql_stmt_errno=%d returned=%d)", - query, - mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); - - /* Read result from each column */ - for (col_idx= 0; col_idx < num_fields; col_idx++) - { - const char *val; - ulonglong len; - if (col_idx < max_replace_column && replace_column[col_idx]) - { - val= replace_column[col_idx]; - len= strlen(val); - } - else if (*bind[col_idx].is_null) - { - val= "NULL"; - len= 4; - } - else - { - /* FIXME is string terminated? */ - val= (const char *) bind[col_idx].buffer; - len= *bind[col_idx].length; - } - if (!display_result_vertically) - { - if (col_idx) /* No tab before first col */ - dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append_mem(ds, val, len); - } - else - { - dynstr_append(ds, field[col_idx].name); - dynstr_append_mem(ds, "\t", 1); - replace_dynstr_append_mem(ds, val, len); - dynstr_append_mem(ds, "\n", 1); - } - } - if (!display_result_vertically) - dynstr_append_mem(ds, "\n", 1); - } - - if ((err= mysql_stmt_fetch(stmt)) != MYSQL_NO_DATA) - die("fetch didn't end with MYSQL_NO_DATA from statement " - "'%s': %s (mysql_stmt_errno=%d returned=%d)", - query, - mysql_stmt_error(stmt), mysql_stmt_errno(stmt), err); - - free_replace_column(); - - for (col_idx= 0; col_idx < num_fields; col_idx++) - { - /* Free data for output */ - my_free((gptr)bind[col_idx].buffer, MYF(MY_WME | MY_FAE)); - } - /* Free array with bind structs, lengths and NULL flags */ - my_free((gptr)bind , MYF(MY_WME | MY_FAE)); - my_free((gptr)length , MYF(MY_WME | MY_FAE)); - my_free((gptr)is_null , MYF(MY_WME | MY_FAE)); - } - - /* Add all warnings to the result */ - run_query_stmt_handle_warnings(mysql, ds); - - if (!disable_info) - { - char buf[40]; - sprintf(buf,"affected rows: %lu\n",(ulong) mysql_affected_rows(mysql)); - dynstr_append(ds, buf); - if (mysql_info(mysql)) - { - dynstr_append(ds, "info: "); - dynstr_append(ds, mysql_info(mysql)); - dynstr_append_mem(ds, "\n", 1); - } - } - } - run_query_stmt_handle_warnings(mysql, ds); - - if (record) - { - if (!q->record_file[0] && !result_file) - die("Missing result file"); - if (!result_file) - str_to_file(q->record_file, ds->str, ds->length); - } - else if (q->record_file[0]) - { - error= check_result(ds, q->record_file, q->require_file); - } - if (res) - mysql_free_result(res); /* Free normal result set with meta data */ - last_result= 0; /* FIXME have no idea what this is about... */ - - if (err >= 1) - mysql_error(mysql); /* FIXME strange, has no effect... */ - -end: - free_replace(); - last_result=0; - if (ds == &ds_tmp) - dynstr_free(&ds_tmp); - if (q->type == Q_EVAL) - dynstr_free(&eval_query); - var_set_errno(mysql_stmt_errno(stmt)); - mysql_stmt_close(stmt); - DBUG_RETURN(error); -} - - -/****************************************************************************\ - * Broken out sub functions to run_query_stmt() -\****************************************************************************/ - -static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields, - DYNAMIC_STRING *ds) +void append_metadata(DYNAMIC_STRING *ds, + MYSQL_FIELD *field, + uint num_fields) { MYSQL_FIELD *field_end; dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t" @@ -3395,147 +4221,360 @@ static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields, field < field_end ; field++) { - char buff[22]; dynstr_append_mem(ds, field->catalog, - field->catalog_length); + field->catalog_length); dynstr_append_mem(ds, "\t", 1); dynstr_append_mem(ds, field->db, field->db_length); dynstr_append_mem(ds, "\t", 1); dynstr_append_mem(ds, field->org_table, - field->org_table_length); + field->org_table_length); dynstr_append_mem(ds, "\t", 1); dynstr_append_mem(ds, field->table, - field->table_length); + field->table_length); dynstr_append_mem(ds, "\t", 1); dynstr_append_mem(ds, field->org_name, - field->org_name_length); + field->org_name_length); dynstr_append_mem(ds, "\t", 1); dynstr_append_mem(ds, field->name, field->name_length); dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->type, buff, 10); - dynstr_append(ds, buff); + replace_dynstr_append_uint(ds, field->type); dynstr_append_mem(ds, "\t", 1); - longlong10_to_str((unsigned int) field->length, buff, 10); - dynstr_append(ds, buff); + replace_dynstr_append_uint(ds, field->length); dynstr_append_mem(ds, "\t", 1); - longlong10_to_str((unsigned int) field->max_length, buff, 10); - dynstr_append(ds, buff); + replace_dynstr_append_uint(ds, field->max_length); dynstr_append_mem(ds, "\t", 1); dynstr_append_mem(ds, (char*) (IS_NOT_NULL(field->flags) ? "N" : "Y"), 1); dynstr_append_mem(ds, "\t", 1); - - int10_to_str((int) field->flags, buff, 10); - dynstr_append(ds, buff); + replace_dynstr_append_uint(ds, field->flags); dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->decimals, buff, 10); - dynstr_append(ds, buff); + replace_dynstr_append_uint(ds, field->decimals); dynstr_append_mem(ds, "\t", 1); - int10_to_str((int) field->charsetnr, buff, 10); - dynstr_append(ds, buff); + replace_dynstr_append_uint(ds, field->charsetnr); dynstr_append_mem(ds, "\n", 1); } } -static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds) +/* + Append affected row count and other info to output +*/ + +void append_info(DYNAMIC_STRING *ds, ulonglong affected_rows, + const char *info) +{ + char buf[40], buff2[21]; + sprintf(buf,"affected rows: %s\n", llstr(affected_rows, buff2)); + dynstr_append(ds, buf); + if (info) + { + dynstr_append(ds, "info: "); + dynstr_append(ds, info); + dynstr_append_mem(ds, "\n", 1); + } +} + + +/* + Display the table headings with the names tab separated +*/ + +void append_table_headings(DYNAMIC_STRING *ds, + MYSQL_FIELD *field, + uint num_fields) +{ + uint col_idx; + for (col_idx= 0; col_idx < num_fields; col_idx++) + { + if (col_idx) + dynstr_append_mem(ds, "\t", 1); + replace_dynstr_append(ds, field[col_idx].name); + } + dynstr_append_mem(ds, "\n", 1); +} + +/* + Fetch warnings from server and append to ds + + RETURN VALUE + Number of warnings appended to ds +*/ + +int append_warnings(DYNAMIC_STRING *ds, MYSQL* mysql) { uint count; - DBUG_ENTER("run_query_stmt_handle_warnings"); + MYSQL_RES *warn_res; + DBUG_ENTER("append_warnings"); - if (!disable_warnings && (count= mysql_warning_count(mysql))) + if (!(count= mysql_warning_count(mysql))) + DBUG_RETURN(0); + + /* + If one day we will support execution of multi-statements + through PS API we should not issue SHOW WARNINGS until + we have not read all results... + */ + DBUG_ASSERT(!mysql_more_results(mysql)); + + if (mysql_real_query(mysql, "SHOW WARNINGS", 13)) + die("Error running query \"SHOW WARNINGS\": %s", mysql_error(mysql)); + + if (!(warn_res= mysql_store_result(mysql))) + die("Warning count is %u but didn't get any warnings", + count); + + append_result(ds, warn_res); + mysql_free_result(warn_res); + + DBUG_PRINT("warnings", ("%s", ds->str)); + + DBUG_RETURN(count); +} + + + +/* + Run query using MySQL C API + + SYNPOSIS + run_query_normal + mysql - mysql handle + command - currrent command pointer + flags -flags indicating wheter to SEND and/or REAP + query - query string to execute + query_len - length query string to execute + ds - output buffer wherte to store result form query + + RETURN VALUE + error - function will not return +*/ + +void run_query_normal(MYSQL *mysql, struct st_command *command, + int flags, char *query, int query_len, + DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_warnings) +{ + MYSQL_RES *res= 0; + int err= 0, counter= 0; + DBUG_ENTER("run_query_normal"); + DBUG_PRINT("enter",("flags: %d", flags)); + DBUG_PRINT("enter", ("query: '%-.60s'", query)); + + if (flags & QUERY_SEND_FLAG) { - if (mysql_real_query(mysql, "SHOW WARNINGS", 13) == 0) + /* + Send the query + */ + if (mysql_send_query(mysql, query, query_len)) { - MYSQL_RES *warn_res= mysql_store_result(mysql); - if (!warn_res) - die("Warning count is %u but didn't get any warnings\n", - count); - else - { - dynstr_append_mem(ds, "Warnings:\n", 10); - append_result(ds, warn_res); - mysql_free_result(warn_res); - } + handle_error(command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), ds); + goto end; } } + + if (!(flags & QUERY_REAP_FLAG)) + DBUG_VOID_RETURN; + + do + { + /* + When on first result set, call mysql_read_query_result to retrieve + answer to the query sent earlier + */ + if ((counter==0) && mysql_read_query_result(mysql)) + { + handle_error(command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), ds); + goto end; + + } + + /* + Store the result. If res is NULL, use mysql_field_count to + determine if that was expected + */ + if (!(res= mysql_store_result(mysql)) && mysql_field_count(mysql)) + { + handle_error(command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), ds); + goto end; + } + + if (!disable_result_log) + { + ulonglong affected_rows; /* Ok to be undef if 'disable_info' is set */ + LINT_INIT(affected_rows); + + if (res) + { + MYSQL_FIELD *fields= mysql_fetch_fields(res); + uint num_fields= mysql_num_fields(res); + + if (display_metadata) + append_metadata(ds, fields, num_fields); + + if (!display_result_vertically) + append_table_headings(ds, fields, num_fields); + + append_result(ds, res); + } + + /* + Need to call mysql_affected_rows() before the "new" + query to find the warnings + */ + if (!disable_info) + affected_rows= mysql_affected_rows(mysql); + + /* + Add all warnings to the result. We can't do this if we are in + the middle of processing results from multi-statement, because + this will break protocol. + */ + if (!disable_warnings && !mysql_more_results(mysql)) + { + if (append_warnings(ds_warnings, mysql) || ds_warnings->length) + { + dynstr_append_mem(ds, "Warnings:\n", 10); + dynstr_append_mem(ds, ds_warnings->str, ds_warnings->length); + } + } + + if (!disable_info) + append_info(ds, affected_rows, mysql_info(mysql)); + } + + if (res) + mysql_free_result(res); + counter++; + } while (!(err= mysql_next_result(mysql))); + if (err > 0) + { + /* We got an error from mysql_next_result, maybe expected */ + handle_error(command, mysql_errno(mysql), mysql_error(mysql), + mysql_sqlstate(mysql), ds); + goto end; + } + DBUG_ASSERT(err == -1); /* Successful and there are no more results */ + + /* If we come here the query is both executed and read successfully */ + handle_no_error(command); + +end: + + /* + We save the return code (mysql_errno(mysql)) from the last call sent + to the server into the mysqltest builtin variable $mysql_errno. This + variable then can be used from the test case itself. + */ + var_set_errno(mysql_errno(mysql)); DBUG_VOID_RETURN; } -static int run_query_stmt_handle_error(char *query, struct st_query *q, - MYSQL_STMT *stmt, DYNAMIC_STRING *ds) +/* + Handle errors which occurred during execution + + SYNOPSIS + handle_error() + q - query context + err_errno - error number + err_error - error message + err_sqlstate - sql state + ds - dynamic string which is used for output buffer + + NOTE + If there is an unexpected error this function will abort mysqltest + immediately. + + RETURN VALUE + error - function will not return +*/ + +void handle_error(struct st_command *command, + unsigned int err_errno, const char *err_error, + const char *err_sqlstate, DYNAMIC_STRING *ds) { - if (q->require_file) /* FIXME don't understand this one */ + uint i; + + DBUG_ENTER("handle_error"); + + if (command->require_file) { - abort_not_supported_test(); + /* + The query after a "--require" failed. This is fine as long the server + returned a valid reponse. Don't allow 2013 or 2006 to trigger an + abort_not_supported_test + */ + if (err_errno == CR_SERVER_LOST || + err_errno == CR_SERVER_GONE_ERROR) + die("require query '%s' failed: %d: %s", command->query, err_errno, err_error); + + /* Abort the run of this test, pass the failed query as reason */ + abort_not_supported_test("Query '%s' failed, required functionality" \ + "not supported", command->query); } - if (q->abort_on_error) - die("query '%s' failed: %d: %s", query, - mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); - else - { - int i; + if (command->abort_on_error) + die("query '%s' failed: %d: %s", command->query, err_errno, err_error); - for (i=0 ; (uint) i < q->expected_errors ; i++) + DBUG_PRINT("info", ("expected_errors.count: %d", + command->expected_errors.count)); + for (i= 0 ; (uint) i < command->expected_errors.count ; i++) + { + if (((command->expected_errors.err[i].type == ERR_ERRNO) && + (command->expected_errors.err[i].code.errnum == err_errno)) || + ((command->expected_errors.err[i].type == ERR_SQLSTATE) && + (strcmp(command->expected_errors.err[i].code.sqlstate, + err_sqlstate) == 0))) { - if (((q->expected_errno[i].type == ERR_ERRNO) && - (q->expected_errno[i].code.errnum == mysql_stmt_errno(stmt))) || - ((q->expected_errno[i].type == ERR_SQLSTATE) && - (strcmp(q->expected_errno[i].code.sqlstate, - mysql_stmt_sqlstate(stmt)) == 0))) + if (!disable_result_log) { - if (i == 0 && q->expected_errors == 1) + if (command->expected_errors.count == 1) { /* Only log error if there is one possible error */ - dynstr_append_mem(ds,"ERROR ",6); - replace_dynstr_append_mem(ds, mysql_stmt_sqlstate(stmt), - strlen(mysql_stmt_sqlstate(stmt))); + dynstr_append_mem(ds, "ERROR ", 6); + replace_dynstr_append(ds, err_sqlstate); dynstr_append_mem(ds, ": ", 2); - replace_dynstr_append_mem(ds,mysql_stmt_error(stmt), - strlen(mysql_stmt_error(stmt))); + replace_dynstr_append(ds, err_error); dynstr_append_mem(ds,"\n",1); } /* Don't log error if we may not get an error */ - else if (q->expected_errno[0].type == ERR_SQLSTATE || - (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0)) + else if (command->expected_errors.err[0].type == ERR_SQLSTATE || + (command->expected_errors.err[0].type == ERR_ERRNO && + command->expected_errors.err[0].code.errnum != 0)) dynstr_append(ds,"Got one of the listed errors\n"); - return 0; /* Ok */ } + /* OK */ + DBUG_VOID_RETURN; } - DBUG_PRINT("info",("i: %d expected_errors: %d", i, - q->expected_errors)); - dynstr_append_mem(ds, "ERROR ",6); - replace_dynstr_append_mem(ds, mysql_stmt_sqlstate(stmt), - strlen(mysql_stmt_sqlstate(stmt))); - dynstr_append_mem(ds,": ",2); - replace_dynstr_append_mem(ds, mysql_stmt_error(stmt), - strlen(mysql_stmt_error(stmt))); - dynstr_append_mem(ds,"\n",1); - if (i) - { - if (q->expected_errno[0].type == ERR_ERRNO) - verbose_msg("query '%s' failed with wrong errno %d instead of %d...", - q->query, mysql_stmt_errno(stmt), - q->expected_errno[0].code.errnum); - else - verbose_msg("query '%s' failed with wrong sqlstate %s instead of %s...", - q->query, mysql_stmt_sqlstate(stmt), - q->expected_errno[0].code.sqlstate); - return 1; /* Error */ - } - verbose_msg("query '%s' failed: %d: %s", q->query, mysql_stmt_errno(stmt), - mysql_stmt_error(stmt)); - /* - if we do not abort on error, failure to run the query does - not fail the whole test case - */ - return 0; } - return 0; + DBUG_PRINT("info",("i: %d expected_errors: %d", i, + command->expected_errors)); + + if (!disable_result_log) + { + dynstr_append_mem(ds, "ERROR ",6); + replace_dynstr_append(ds, err_sqlstate); + dynstr_append_mem(ds, ": ", 2); + replace_dynstr_append(ds, err_error); + dynstr_append_mem(ds, "\n", 1); + } + + if (i) + { + if (command->expected_errors.err[0].type == ERR_ERRNO) + die("query '%s' failed with wrong errno %d: '%s', instead of %d...", + command->query, err_errno, err_error, + command->expected_errors.err[0].code.errnum); + else + die("query '%s' failed with wrong sqlstate %s: '%s', instead of %s...", + command->query, err_sqlstate, err_error, + command->expected_errors.err[0].code.sqlstate); + } + + DBUG_VOID_RETURN; } @@ -3543,44 +4582,518 @@ static int run_query_stmt_handle_error(char *query, struct st_query *q, Handle absence of errors after execution SYNOPSIS - handle_no_error() - q - context of query + handle_no_error() + q - context of query RETURN VALUE - 0 - OK - 1 - Some error was expected from this query. + error - function will not return */ -static int handle_no_error(struct st_query *q) +void handle_no_error(struct st_command *command) { DBUG_ENTER("handle_no_error"); - if (q->expected_errno[0].type == ERR_ERRNO && - q->expected_errno[0].code.errnum != 0) + if (command->expected_errors.err[0].type == ERR_ERRNO && + command->expected_errors.err[0].code.errnum != 0) { /* Error code we wanted was != 0, i.e. not an expected success */ - verbose_msg("query '%s' succeeded - should have failed with errno %d...", - q->query, q->expected_errno[0].code.errnum); - DBUG_RETURN(1); + die("query '%s' succeeded - should have failed with errno %d...", + command->query, command->expected_errors.err[0].code.errnum); } - else if (q->expected_errno[0].type == ERR_SQLSTATE && - strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0) + else if (command->expected_errors.err[0].type == ERR_SQLSTATE && + strcmp(command->expected_errors.err[0].code.sqlstate,"00000") != 0) { /* SQLSTATE we wanted was != "00000", i.e. not an expected success */ - verbose_msg("query '%s' succeeded - should have failed with sqlstate %s...", - q->query, q->expected_errno[0].code.sqlstate); - DBUG_RETURN(1); + die("query '%s' succeeded - should have failed with sqlstate %s...", + command->query, command->expected_errors.err[0].code.sqlstate); } - DBUG_RETURN(0); + DBUG_VOID_RETURN; } -/****************************************************************************\ - * Functions to match SQL statements that can be prepared -\****************************************************************************/ -static void ps_init_re(void) +/* + Run query using prepared statement C API + + SYNPOSIS + run_query_stmt + mysql - mysql handle + command - currrent command pointer + query - query string to execute + query_len - length query string to execute + ds - output buffer where to store result form query + + RETURN VALUE + error - function will not return +*/ + +void run_query_stmt(MYSQL *mysql, struct st_command *command, + char *query, int query_len, DYNAMIC_STRING *ds, + DYNAMIC_STRING *ds_warnings) { + MYSQL_RES *res= NULL; /* Note that here 'res' is meta data result set */ + MYSQL_STMT *stmt; + DYNAMIC_STRING ds_prepare_warnings; + DYNAMIC_STRING ds_execute_warnings; + DBUG_ENTER("run_query_stmt"); + DBUG_PRINT("query", ("'%-.60s'", query)); + + /* + Init a new stmt if it's not already one created for this connection + */ + if(!(stmt= cur_con->stmt)) + { + if (!(stmt= mysql_stmt_init(mysql))) + die("unable to init stmt structure"); + cur_con->stmt= stmt; + } + + /* Init dynamic strings for warnings */ + if (!disable_warnings) + { + init_dynamic_string(&ds_prepare_warnings, NULL, 0, 256); + init_dynamic_string(&ds_execute_warnings, NULL, 0, 256); + } + + /* + Prepare the query + */ + if (mysql_stmt_prepare(stmt, query, query_len)) + { + handle_error(command, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); + goto end; + } + + /* + Get the warnings from mysql_stmt_prepare and keep them in a + separate string + */ + if (!disable_warnings) + append_warnings(&ds_prepare_warnings, mysql); + + /* + No need to call mysql_stmt_bind_param() because we have no + parameter markers. + */ + +#if MYSQL_VERSION_ID >= 50000 + if (cursor_protocol_enabled) + { + /* + Use cursor when retrieving result + */ + ulong type= CURSOR_TYPE_READ_ONLY; + if (mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void*) &type)) + die("mysql_stmt_attr_set(STMT_ATTR_CURSOR_TYPE) failed': %d %s", + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); + } +#endif + + /* + Execute the query + */ + if (mysql_stmt_execute(stmt)) + { + handle_error(command, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); + goto end; + } + + /* + When running in cursor_protocol get the warnings from execute here + and keep them in a separate string for later. + */ + if (cursor_protocol_enabled && !disable_warnings) + append_warnings(&ds_execute_warnings, mysql); + + /* + We instruct that we want to update the "max_length" field in + mysql_stmt_store_result(), this is our only way to know how much + buffer to allocate for result data + */ + { + my_bool one= 1; + if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (void*) &one)) + die("mysql_stmt_attr_set(STMT_ATTR_UPDATE_MAX_LENGTH) failed': %d %s", + mysql_stmt_errno(stmt), mysql_stmt_error(stmt)); + } + + /* + If we got here the statement succeeded and was expected to do so, + get data. Note that this can still give errors found during execution! + */ + if (mysql_stmt_store_result(stmt)) + { + handle_error(command, mysql_stmt_errno(stmt), + mysql_stmt_error(stmt), mysql_stmt_sqlstate(stmt), ds); + goto end; + } + + /* If we got here the statement was both executed and read successfully */ + handle_no_error(command); + if (!disable_result_log) + { + /* + Not all statements creates a result set. If there is one we can + now create another normal result set that contains the meta + data. This set can be handled almost like any other non prepared + statement result set. + */ + if ((res= mysql_stmt_result_metadata(stmt)) != NULL) + { + /* Take the column count from meta info */ + MYSQL_FIELD *fields= mysql_fetch_fields(res); + uint num_fields= mysql_num_fields(res); + + if (display_metadata) + append_metadata(ds, fields, num_fields); + + if (!display_result_vertically) + append_table_headings(ds, fields, num_fields); + + append_stmt_result(ds, stmt, fields, num_fields); + + mysql_free_result(res); /* Free normal result set with meta data */ + + /* Clear prepare warnings */ + dynstr_set(&ds_prepare_warnings, NULL); + } + else + { + /* + This is a query without resultset + */ + } + + if (!disable_warnings) + { + /* Get the warnings from execute */ + + /* Append warnings to ds - if there are any */ + if (append_warnings(&ds_execute_warnings, mysql) || + ds_execute_warnings.length || + ds_prepare_warnings.length || + ds_warnings->length) + { + dynstr_append_mem(ds, "Warnings:\n", 10); + if (ds_warnings->length) + dynstr_append_mem(ds, ds_warnings->str, + ds_warnings->length); + if (ds_prepare_warnings.length) + dynstr_append_mem(ds, ds_prepare_warnings.str, + ds_prepare_warnings.length); + if (ds_execute_warnings.length) + dynstr_append_mem(ds, ds_execute_warnings.str, + ds_execute_warnings.length); + } + } + + if (!disable_info) + append_info(ds, mysql_affected_rows(mysql), mysql_info(mysql)); + + } + +end: + if (!disable_warnings) + { + dynstr_free(&ds_prepare_warnings); + dynstr_free(&ds_execute_warnings); + } + + /* + We save the return code (mysql_stmt_errno(stmt)) from the last call sent + to the server into the mysqltest builtin variable $mysql_errno. This + variable then can be used from the test case itself. + */ + + var_set_errno(mysql_stmt_errno(stmt)); +#ifndef BUG15518_FIXED + mysql_stmt_close(stmt); + cur_con->stmt= NULL; +#endif + DBUG_VOID_RETURN; +} + + + +/* + Create a util connection if one does not already exists + and use that to run the query + This is done to avoid implict commit when creating/dropping objects such + as view, sp etc. +*/ + +int util_query(MYSQL* org_mysql, const char* query){ + + MYSQL* mysql; + DBUG_ENTER("util_query"); + + if(!(mysql= cur_con->util_mysql)) + { + DBUG_PRINT("info", ("Creating util_mysql")); + if (!(mysql= mysql_init(mysql))) + die("Failed in mysql_init()"); + + safe_connect(mysql, "util", org_mysql->host, org_mysql->user, + org_mysql->passwd, org_mysql->db, org_mysql->port, + org_mysql->unix_socket); + + cur_con->util_mysql= mysql; + } + + return mysql_query(mysql, query); +} + + + +/* + Run query + + flags control the phased/stages of query execution to be performed + if QUERY_SEND_FLAG bit is on, the query will be sent. If QUERY_REAP_FLAG + is on the result will be read - for regular query, both bits must be on + + SYNPOSIS + run_query + mysql - mysql handle + command - currrent command pointer + +*/ + +void run_query(MYSQL *mysql, struct st_command *command, int flags) +{ + DYNAMIC_STRING *ds; + DYNAMIC_STRING ds_result; + DYNAMIC_STRING ds_warnings; + DYNAMIC_STRING eval_query; + char *query; + int query_len; + my_bool view_created= 0, sp_created= 0; + my_bool complete_query= ((flags & QUERY_SEND_FLAG) && + (flags & QUERY_REAP_FLAG)); + + init_dynamic_string(&ds_warnings, NULL, 0, 256); + + /* + Evaluate query if this is an eval command + */ + if (command->type == Q_EVAL) + { + init_dynamic_string(&eval_query, "", command->query_len+256, 1024); + do_eval(&eval_query, command->query, command->end, FALSE); + query = eval_query.str; + query_len = eval_query.length; + } + else + { + query = command->query; + query_len = strlen(query); + } + + /* + When command->record_file is set the output of _this_ query + should be compared with an already existing file + Create a temporary dynamic string to contain the output from + this query. + */ + if (command->record_file[0]) + { + init_dynamic_string(&ds_result, "", 1024, 1024); + ds= &ds_result; + } + else + ds= &ds_res; + + /* + Log the query into the output buffer + */ + if (!disable_query_log && (flags & QUERY_SEND_FLAG)) + { + replace_dynstr_append_mem(ds, query, query_len); + dynstr_append_mem(ds, delimiter, delimiter_length); + dynstr_append_mem(ds, "\n", 1); + } + + if (view_protocol_enabled && + complete_query && + match_re(&view_re, query)) + { + /* + Create the query as a view. + Use replace since view can exist from a failed mysqltest run + */ + DYNAMIC_STRING query_str; + init_dynamic_string(&query_str, + "CREATE OR REPLACE VIEW mysqltest_tmp_v AS ", + query_len+64, 256); + dynstr_append_mem(&query_str, query, query_len); + if (util_query(mysql, query_str.str)) + { + /* + Failed to create the view, this is not fatal + just run the query the normal way + */ + DBUG_PRINT("view_create_error", + ("Failed to create view '%s': %d: %s", query_str.str, + mysql_errno(mysql), mysql_error(mysql))); + + /* Log error to create view */ + verbose_msg("Failed to create view '%s' %d: %s", query_str.str, + mysql_errno(mysql), mysql_error(mysql)); + } + else + { + /* + Yes, it was possible to create this query as a view + */ + view_created= 1; + query= (char*)"SELECT * FROM mysqltest_tmp_v"; + query_len = strlen(query); + + /* + Collect warnings from create of the view that should otherwise + have been produced when the SELECT was executed + */ + append_warnings(&ds_warnings, cur_con->util_mysql); + } + + dynstr_free(&query_str); + + } + + if (sp_protocol_enabled && + complete_query && + match_re(&sp_re, query)) + { + /* + Create the query as a stored procedure + Drop first since sp can exist from a failed mysqltest run + */ + DYNAMIC_STRING query_str; + init_dynamic_string(&query_str, + "DROP PROCEDURE IF EXISTS mysqltest_tmp_sp;", + query_len+64, 256); + util_query(mysql, query_str.str); + dynstr_set(&query_str, "CREATE PROCEDURE mysqltest_tmp_sp()\n"); + dynstr_append_mem(&query_str, query, query_len); + if (util_query(mysql, query_str.str)) + { + /* + Failed to create the stored procedure for this query, + this is not fatal just run the query the normal way + */ + DBUG_PRINT("sp_create_error", + ("Failed to create sp '%s': %d: %s", query_str.str, + mysql_errno(mysql), mysql_error(mysql))); + + /* Log error to create sp */ + verbose_msg("Failed to create sp '%s' %d: %s", query_str.str, + mysql_errno(mysql), mysql_error(mysql)); + + } + else + { + sp_created= 1; + + query= (char*)"CALL mysqltest_tmp_sp()"; + query_len = strlen(query); + } + dynstr_free(&query_str); + } + + /* + Find out how to run this query + + Always run with normal C API if it's not a complete + SEND + REAP + + If it is a '?' in the query it may be a SQL level prepared + statement already and we can't do it twice + */ + if (ps_protocol_enabled && + complete_query && + match_re(&ps_re, query)) + run_query_stmt(mysql, command, query, query_len, ds, &ds_warnings); + else + run_query_normal(mysql, command, flags, query, query_len, + ds, &ds_warnings); + + if (sp_created) + { + if (util_query(mysql, "DROP PROCEDURE mysqltest_tmp_sp ")) + die("Failed to drop sp: %d: %s", mysql_errno(mysql), mysql_error(mysql)); + } + + if (view_created) + { + if (util_query(mysql, "DROP VIEW mysqltest_tmp_v ")) + die("Failed to drop view: %d: %s", + mysql_errno(mysql), mysql_error(mysql)); + } + + if (command->record_file[0]) + { + + /* A result file was specified for _this_ query */ + if (record) + { + /* + Recording in progress + Dump the output from _this_ query to the specified record_file + */ + str_to_file(command->record_file, ds->str, ds->length); + + } else { + + /* + The output from _this_ query should be checked against an already + existing file which has been specified using --require or --result + */ + check_result(ds, command->record_file, command->require_file); + } + } + + dynstr_free(&ds_warnings); + if (ds == &ds_result) + dynstr_free(&ds_result); + if (command->type == Q_EVAL) + dynstr_free(&eval_query); +} + +/****************************************************************************/ +/* + Functions to detect different SQL statements +*/ + +char *re_eprint(int err) +{ + static char epbuf[100]; + size_t len= my_regerror(REG_ITOA|err, (my_regex_t *)NULL, + epbuf, sizeof(epbuf)); + assert(len <= sizeof(epbuf)); + return(epbuf); +} + +void init_re_comp(my_regex_t *re, const char* str) +{ + int err= my_regcomp(re, str, (REG_EXTENDED | REG_ICASE | REG_NOSUB), + &my_charset_latin1); + if (err) + { + char erbuf[100]; + int len= my_regerror(err, re, erbuf, sizeof(erbuf)); + die("error %s, %d/%d `%s'\n", + re_eprint(err), len, (int)sizeof(erbuf), erbuf); + } +} + +void init_re(void) +{ + /* + Filter for queries that can be run using the + MySQL Prepared Statements C API + */ const char *ps_re_str = "^(" "[[:space:]]*REPLACE[[:space:]]|" @@ -3595,199 +5108,210 @@ static void ps_init_re(void) "[[:space:]]*UPDATE[[:space:]]+MULTI[[:space:]]|" "[[:space:]]*INSERT[[:space:]]+SELECT[[:space:]])"; - int err= my_regcomp(&ps_re, ps_re_str, - (REG_EXTENDED | REG_ICASE | REG_NOSUB), - &my_charset_latin1); - if (err) - { - char erbuf[100]; - int len= my_regerror(err, &ps_re, erbuf, sizeof(erbuf)); - fprintf(stderr, "error %s, %d/%d `%s'\n", - ps_eprint(err), len, (int)sizeof(erbuf), erbuf); - exit(1); - } + /* + Filter for queries that can be run using the + Stored procedures + */ + const char *sp_re_str =ps_re_str; + + /* + Filter for queries that can be run as views + */ + const char *view_re_str = + "^(" + "[[:space:]]*SELECT[[:space:]])"; + + init_re_comp(&ps_re, ps_re_str); + init_re_comp(&sp_re, sp_re_str); + init_re_comp(&view_re, view_re_str); } -static int ps_match_re(char *stmt_str) +int match_re(my_regex_t *re, char *str) { - int err= my_regexec(&ps_re, stmt_str, (size_t)0, NULL, 0); + int err= my_regexec(re, str, (size_t)0, NULL, 0); if (err == 0) return 1; else if (err == REG_NOMATCH) return 0; - else + { char erbuf[100]; - int len= my_regerror(err, &ps_re, erbuf, sizeof(erbuf)); - fprintf(stderr, "error %s, %d/%d `%s'\n", - ps_eprint(err), len, (int)sizeof(erbuf), erbuf); - exit(1); + int len= my_regerror(err, re, erbuf, sizeof(erbuf)); + die("error %s, %d/%d `%s'\n", + re_eprint(err), len, (int)sizeof(erbuf), erbuf); } + return 0; } -static char *ps_eprint(int err) -{ - static char epbuf[100]; - size_t len= my_regerror(REG_ITOA|err, (my_regex_t *)NULL, epbuf, sizeof(epbuf)); - assert(len <= sizeof(epbuf)); - return(epbuf); -} - - -static void ps_free_reg(void) +void free_re(void) { my_regfree(&ps_re); + my_regfree(&sp_re); + my_regfree(&view_re); + my_regex_end(); } /****************************************************************************/ -void get_query_type(struct st_query* q) +void get_command_type(struct st_command* command) { char save; uint type; - DBUG_ENTER("get_query_type"); + DBUG_ENTER("get_command_type"); - if (*q->query == '}') + if (!parsing_disabled && *command->query == '}') { - q->type = Q_END_BLOCK; + command->type = Q_END_BLOCK; DBUG_VOID_RETURN; } - if (q->type != Q_COMMENT_WITH_COMMAND) - q->type = Q_QUERY; + if (command->type != Q_COMMENT_WITH_COMMAND) + command->type= parsing_disabled ? Q_COMMENT : Q_QUERY; - save=q->query[q->first_word_len]; - q->query[q->first_word_len]=0; - type=find_type(q->query, &command_typelib, 1+2); - q->query[q->first_word_len]=save; + save=command->query[command->first_word_len]; + command->query[command->first_word_len]=0; + type=find_type(command->query, &command_typelib, 1+2); + command->query[command->first_word_len]=save; if (type > 0) - q->type=(enum enum_commands) type; /* Found command */ - DBUG_VOID_RETURN; -} - - -static byte *get_var_key(const byte* var, uint* len, - my_bool __attribute__((unused)) t) -{ - register char* key; - key = ((VAR*)var)->name; - *len = ((VAR*)var)->name_len; - return (byte*)key; -} - -static VAR *var_init(VAR *v, const char *name, int name_len, const char *val, - int val_len) -{ - int val_alloc_len; - VAR *tmp_var; - if (!name_len && name) - name_len = strlen(name); - if (!val_len && val) - val_len = strlen(val) ; - val_alloc_len = val_len + 16; /* room to grow */ - if (!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(sizeof(*tmp_var) - + name_len, MYF(MY_WME)))) - die("Out of memory"); - - tmp_var->name = (name) ? (char*) tmp_var + sizeof(*tmp_var) : 0; - tmp_var->alloced = (v == 0); - - if (!(tmp_var->str_val = my_malloc(val_alloc_len+1, MYF(MY_WME)))) - die("Out of memory"); - - memcpy(tmp_var->name, name, name_len); - if (val) { - memcpy(tmp_var->str_val, val, val_len); - tmp_var->str_val[val_len]=0; + command->type=(enum enum_commands) type; /* Found command */ + /* + If queries are disabled, only recognize + --enable_parsing and --disable_parsing + */ + if (parsing_disabled && command->type != Q_ENABLE_PARSING && + command->type != Q_DISABLE_PARSING) + command->type= Q_COMMENT; + + /* + Look for case where "query" was explicitly specified to + force command being sent to server + */ + if (type == Q_QUERY) + { + /* Skip the "query" part */ + command->query= command->first_argument; + } + } + else if (command->type == Q_COMMENT_WITH_COMMAND && + command->first_word_len && + strcmp(command->query + command->first_word_len - 1, delimiter) == 0) + { + /* + Detect comment with command using extra delimiter + Ex --disable_query_log; + ^ Extra delimiter causing the command + to be skipped + */ + save= command->query[command->first_word_len-1]; + command->query[command->first_word_len-1]= 0; + type= find_type(command->query, &command_typelib, 1+2); + command->query[command->first_word_len-1]= save; + if (type > 0) + die("Extra delimiter \";\" found"); } - tmp_var->name_len = name_len; - tmp_var->str_val_len = val_len; - tmp_var->alloced_len = val_alloc_len; - tmp_var->int_val = (val) ? atoi(val) : 0; - tmp_var->int_dirty = 0; - return tmp_var; -} - -static void var_free(void *v) -{ - my_free(((VAR*) v)->str_val, MYF(MY_WME)); - if (((VAR*)v)->alloced) - my_free((char*) v, MYF(MY_WME)); -} - - -static VAR* var_from_env(const char *name, const char *def_val) -{ - const char *tmp; - VAR *v; - if (!(tmp = getenv(name))) - tmp = def_val; - - v = var_init(0, name, strlen(name), tmp, strlen(tmp)); - my_hash_insert(&var_hash, (byte*)v); - return v; -} - - -static void init_var_hash(MYSQL *mysql) -{ - VAR *v; - DBUG_ENTER("init_var_hash"); - if (hash_init(&var_hash, charset_info, - 1024, 0, 0, get_var_key, var_free, MYF(0))) - die("Variable hash initialization failed"); - if (opt_big_test) - my_hash_insert(&var_hash, (byte*) var_init(0,"BIG_TEST", 0, "1",0)); - v= var_init(0,"MAX_TABLES", 0, (sizeof(ulong) == 4) ? "31" : "62",0); - my_hash_insert(&var_hash, (byte*) v); - v= var_init(0,"SERVER_VERSION", 0, mysql_get_server_info(mysql), 0); - my_hash_insert(&var_hash, (byte*) v); - v= var_init(0,"DB", 2, db, 0); - my_hash_insert(&var_hash, (byte*) v); DBUG_VOID_RETURN; } + +/* + Record how many milliseconds it took to execute the test file + up until the current line and save it in the dynamic string ds_progress. + + The ds_progress will be dumped to .progress when + test run completes + +*/ + +void mark_progress(struct st_command* command __attribute__((unused)), + int line) +{ + char buf[32], *end; + ulonglong timer= timer_now(); + if (!progress_start) + progress_start= timer; + timer-= progress_start; + + /* Milliseconds since start */ + end= longlong2str(timer, buf, 10); + dynstr_append_mem(&ds_progress, buf, (int)(end-buf)); + dynstr_append_mem(&ds_progress, "\t", 1); + + /* Parser line number */ + end= int10_to_str(line, buf, 10); + dynstr_append_mem(&ds_progress, buf, (int)(end-buf)); + dynstr_append_mem(&ds_progress, "\t", 1); + + /* Filename */ + dynstr_append(&ds_progress, cur_file->file_name); + dynstr_append_mem(&ds_progress, ":", 1); + + /* Line in file */ + end= int10_to_str(cur_file->lineno, buf, 10); + dynstr_append_mem(&ds_progress, buf, (int)(end-buf)); + + + dynstr_append_mem(&ds_progress, "\n", 1); + +} + + int main(int argc, char **argv) { - int error = 0; - struct st_query *q; - my_bool require_file=0, q_send_flag=0, query_executed= 0, abort_flag= 0; + struct st_command *command; + my_bool require_file= 0, q_send_flag= 0; + uint command_executed= 0, last_command_executed= 0; char save_file[FN_REFLEN]; MY_STAT res_info; MY_INIT(argv[0]); - { - DBUG_ENTER("main"); - DBUG_PROCESS(argv[0]); - /* Use all time until exit if no explicit 'start_timer' */ - timer_start= timer_now(); + save_file[0]= 0; + TMPDIR[0]= 0; - save_file[0]=0; - TMPDIR[0]=0; - memset(cons, 0, sizeof(cons)); - cons_end = cons + MAX_CONS; - next_con = cons + 1; - cur_con = cons; + /* Init connections */ + memset(connections, 0, sizeof(connections)); + connections_end= connections + + (sizeof(connections)/sizeof(struct st_connection)) - 1; + next_con= connections + 1; + cur_con= connections; + /* Init file stack */ memset(file_stack, 0, sizeof(file_stack)); - memset(&master_pos, 0, sizeof(master_pos)); - file_stack_end= file_stack + MAX_INCLUDE_DEPTH - 1; + file_stack_end= + file_stack + (sizeof(file_stack)/sizeof(struct st_test_file)) - 1; cur_file= file_stack; - lineno = lineno_stack; - my_init_dynamic_array(&q_lines, sizeof(struct st_query*), INIT_Q_LINES, - INIT_Q_LINES); + /* Init block stack */ memset(block_stack, 0, sizeof(block_stack)); - block_stack_end= block_stack + BLOCK_STACK_DEPTH - 1; + block_stack_end= + block_stack + (sizeof(block_stack)/sizeof(struct st_block)) - 1; cur_block= block_stack; cur_block->ok= TRUE; /* Outer block should always be executed */ - cur_block->cmd= Q_UNKNOWN; + cur_block->cmd= cmd_none; - init_dynamic_string(&ds_res, "", 0, 65536); + my_init_dynamic_array(&q_lines, sizeof(struct st_command*), 1024, 1024); + + if (hash_init(&var_hash, charset_info, + 1024, 0, 0, get_var_key, var_free, MYF(0))) + die("Variable hash initialization failed"); + + memset(&master_pos, 0, sizeof(master_pos)); + + parser.current_line= parser.read_lines= 0; + memset(&var_reg, 0, sizeof(var_reg)); + +#ifdef __WIN__ + init_tmp_sh_file(); + init_win_path_patterns(); +#endif + + init_dynamic_string(&ds_res, "", 65536, 65536); + init_dynamic_string(&ds_progress, "", 0, 2048); parse_args(argc, argv); + + DBUG_PRINT("info",("result_file: '%s'", result_file ? result_file : "")); if (mysql_server_init(embedded_server_arg_count, embedded_server_args, (char**) embedded_server_groups)) @@ -3796,17 +5320,17 @@ int main(int argc, char **argv) { cur_file->file= stdin; cur_file->file_name= my_strdup("", MYF(MY_WME)); + cur_file->lineno= 1; } - *lineno=1; -#ifndef EMBEDDED_LIBRARY - if (manager_host) - init_manager(); -#endif - if (ps_protocol) - { + init_re(); + ps_protocol_enabled= ps_protocol; + sp_protocol_enabled= sp_protocol; + view_protocol_enabled= view_protocol; + cursor_protocol_enabled= cursor_protocol; + /* Cursor protcol implies ps protocol */ + if (cursor_protocol_enabled) ps_protocol_enabled= 1; - ps_init_re(); - } + if (!( mysql_init(&cur_con->mysql))) die("Failed in mysql_init()"); if (opt_compress) @@ -3815,18 +5339,30 @@ int main(int argc, char **argv) mysql_options(&cur_con->mysql, MYSQL_SET_CHARSET_NAME, charset_name); #ifdef HAVE_OPENSSL + +#if MYSQL_VERSION_ID >= 50000 + opt_ssl_verify_server_cert= TRUE; /* Always on in mysqltest */ +#endif + if (opt_use_ssl) + { mysql_ssl_set(&cur_con->mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); +#if MYSQL_VERSION_ID >= 50000 + mysql_options(&cur_con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, + &opt_ssl_verify_server_cert); +#endif + } #endif if (!(cur_con->name = my_strdup("default", MYF(MY_WME)))) die("Out of memory"); - if (safe_connect(&cur_con->mysql, host, user, pass, db, port, unix_sock)) - die("Failed in mysql_real_connect(): %s", mysql_error(&cur_con->mysql)); + safe_connect(&cur_con->mysql, cur_con->name, host, user, pass, + db, port, unix_sock); - init_var_hash(&cur_con->mysql); + /* Use all time until exit if no explicit 'start_timer' */ + timer_start= timer_now(); /* Initialize $mysql_errno with -1, so we can @@ -3835,24 +5371,31 @@ int main(int argc, char **argv) */ var_set_errno(-1); - while (!abort_flag && !read_query(&q)) + if (opt_include) + { + open_file(opt_include); + } + + while (!read_command(&command)) { int current_line_inc = 1, processed = 0; - if (q->type == Q_UNKNOWN || q->type == Q_COMMENT_WITH_COMMAND) - get_query_type(q); + if (command->type == Q_UNKNOWN || command->type == Q_COMMENT_WITH_COMMAND) + get_command_type(command); if (cur_block->ok) { - q->last_argument= q->first_argument; + command->last_argument= command->first_argument; processed = 1; - switch (q->type) { - case Q_CONNECT: do_connect(q); break; - case Q_CONNECTION: select_connection(q); break; + switch (command->type) { + case Q_CONNECT: + do_connect(command); + break; + case Q_CONNECTION: select_connection(command); break; case Q_DISCONNECT: case Q_DIRTY_CLOSE: - close_connection(q); break; - case Q_RPL_PROBE: do_rpl_probe(q); break; - case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(q); break; - case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(q); break; + do_close_connection(command); break; + case Q_RPL_PROBE: do_rpl_probe(command); break; + case Q_ENABLE_RPL_PARSE: do_enable_rpl_parse(command); break; + case Q_DISABLE_RPL_PARSE: do_disable_rpl_parse(command); break; case Q_ENABLE_QUERY_LOG: disable_query_log=0; break; case Q_DISABLE_QUERY_LOG: disable_query_log=1; break; case Q_ENABLE_ABORT_ON_ERROR: abort_on_error=1; break; @@ -3861,27 +5404,27 @@ int main(int argc, char **argv) case Q_DISABLE_RESULT_LOG: disable_result_log=1; break; case Q_ENABLE_WARNINGS: disable_warnings=0; break; case Q_DISABLE_WARNINGS: disable_warnings=1; break; + case Q_ENABLE_PS_WARNINGS: disable_ps_warnings=0; break; + case Q_DISABLE_PS_WARNINGS: disable_ps_warnings=1; break; case Q_ENABLE_INFO: disable_info=0; break; case Q_DISABLE_INFO: disable_info=1; break; case Q_ENABLE_METADATA: display_metadata=1; break; case Q_DISABLE_METADATA: display_metadata=0; break; - case Q_SOURCE: do_source(q); break; - case Q_SLEEP: do_sleep(q, 0); break; - case Q_REAL_SLEEP: do_sleep(q, 1); break; - case Q_WAIT_FOR_SLAVE_TO_STOP: do_wait_for_slave_to_stop(q); break; - case Q_REQUIRE_MANAGER: do_require_manager(q); break; -#ifndef EMBEDDED_LIBRARY - case Q_SERVER_START: do_server_start(q); break; - case Q_SERVER_STOP: do_server_stop(q); break; -#endif - case Q_INC: do_modify_var(q, "inc", DO_INC); break; - case Q_DEC: do_modify_var(q, "dec", DO_DEC); break; - case Q_ECHO: do_echo(q); break; - case Q_SYSTEM: do_system(q); break; + case Q_SOURCE: do_source(command); break; + case Q_SLEEP: do_sleep(command, 0); break; + case Q_REAL_SLEEP: do_sleep(command, 1); break; + case Q_WAIT_FOR_SLAVE_TO_STOP: do_wait_for_slave_to_stop(command); break; + case Q_INC: do_modify_var(command, DO_INC); break; + case Q_DEC: do_modify_var(command, DO_DEC); break; + case Q_ECHO: do_echo(command); command_executed++; break; + case Q_SYSTEM: do_system(command); break; + case Q_REMOVE_FILE: do_remove_file(command); break; + case Q_FILE_EXIST: do_file_exist(command); break; + case Q_WRITE_FILE: do_write_file(command); break; + case Q_COPY_FILE: do_copy_file(command); break; + case Q_PERL: do_perl(command); break; case Q_DELIMITER: - strmake(delimiter, q->first_argument, sizeof(delimiter) - 1); - delimiter_length= strlen(delimiter); - q->last_argument= q->first_argument+delimiter_length; + do_delimiter(command); break; case Q_DISPLAY_VERTICAL_RESULTS: display_result_vertically= TRUE; @@ -3889,115 +5432,121 @@ int main(int argc, char **argv) case Q_DISPLAY_HORIZONTAL_RESULTS: display_result_vertically= FALSE; break; - case Q_LET: do_let(q); break; + case Q_LET: do_let(command); break; case Q_EVAL_RESULT: eval_result = 1; break; case Q_EVAL: - if (q->query == q->query_buf) + if (command->query == command->query_buf) { - q->query= q->first_argument; - q->first_word_len= 0; + command->query= command->first_argument; + command->first_word_len= 0; } /* fall through */ case Q_QUERY_VERTICAL: case Q_QUERY_HORIZONTAL: { my_bool old_display_result_vertically= display_result_vertically; - if (!q->query[q->first_word_len]) - { - /* This happens when we use 'query_..' on it's own line */ - q_send_flag=1; - DBUG_PRINT("info", - ("query: '%s' first_word_len: %d send_flag=1", - q->query, q->first_word_len)); - break; - } - /* fix up query pointer if this is * first iteration for this line */ - if (q->query == q->query_buf) - q->query += q->first_word_len + 1; - display_result_vertically= (q->type==Q_QUERY_VERTICAL); + + /* Remove "query_*" if this is first iteration */ + if (command->query == command->query_buf) + command->query= command->first_argument; + + display_result_vertically= (command->type == Q_QUERY_VERTICAL); if (save_file[0]) { - strmov(q->record_file,save_file); - q->require_file=require_file; + strmov(command->record_file,save_file); + command->require_file=require_file; save_file[0]=0; } - error|= run_query(&cur_con->mysql, q, QUERY_REAP|QUERY_SEND); + run_query(&cur_con->mysql, command, QUERY_REAP_FLAG|QUERY_SEND_FLAG); display_result_vertically= old_display_result_vertically; - q->last_argument= q->end; - query_executed= 1; + command->last_argument= command->end; + command_executed++; break; } case Q_QUERY: case Q_REAP: { - /* - We read the result always regardless of the mode for both full - query and read-result only (reap) - */ - int flags = QUERY_REAP; - if (q->type != Q_REAP) /* for a full query, enable the send stage */ - flags |= QUERY_SEND; - if (q_send_flag) - { - flags= QUERY_SEND; - q_send_flag=0; - } + int flags; + if (q_send_flag) + { + /* Last command was an empty 'send' */ + flags= QUERY_SEND_FLAG; + q_send_flag= 0; + } + else if (command->type == Q_REAP) + { + flags= QUERY_REAP_FLAG; + } + else + { + /* full query, both reap and send */ + flags= QUERY_REAP_FLAG | QUERY_SEND_FLAG; + } + if (save_file[0]) { - strmov(q->record_file,save_file); - q->require_file=require_file; + strmov(command->record_file,save_file); + command->require_file=require_file; save_file[0]=0; } - error |= run_query(&cur_con->mysql, q, flags); - query_executed= 1; - q->last_argument= q->end; + run_query(&cur_con->mysql, command, flags); + command_executed++; + command->last_argument= command->end; break; } case Q_SEND: - if (!q->query[q->first_word_len]) - { - /* This happens when we use 'send' on it's own line */ - q_send_flag=1; - break; - } - /* fix up query pointer if this is * first iteration for this line */ - if (q->query == q->query_buf) - q->query += q->first_word_len; + if (!*command->first_argument) + { + /* + This is a send without arguments, it indicates that _next_ query + should be send only + */ + q_send_flag= 1; + break; + } + + /* Remove "send" if this is first iteration */ + if (command->query == command->query_buf) + command->query= command->first_argument; + /* - run_query() can execute a query partially, depending on the flags - QUERY_SEND flag without QUERY_REAP tells it to just send the - query and read the result some time later when reap instruction + run_query() can execute a query partially, depending on the flags. + QUERY_SEND_FLAG flag without QUERY_REAP_FLAG tells it to just send + the query and read the result some time later when reap instruction is given on this connection. - */ - error |= run_query(&cur_con->mysql, q, QUERY_SEND); - query_executed= 1; - q->last_argument= q->end; + */ + run_query(&cur_con->mysql, command, QUERY_SEND_FLAG); + command_executed++; + command->last_argument= command->end; break; case Q_RESULT: - get_file_name(save_file,q); + do_get_file_name(save_file, command); require_file=0; break; case Q_ERROR: - global_expected_errors=get_errcodes(global_expected_errno,q); + do_get_errcodes(command); break; case Q_REQUIRE: - get_file_name(save_file,q); + do_get_file_name(save_file, command); require_file=1; break; case Q_REPLACE: - get_replace(q); + do_get_replace(command); break; + case Q_REPLACE_REGEX: + do_get_replace_regex(command); + break; case Q_REPLACE_COLUMN: - get_replace_column(q); + do_get_replace_column(command); break; case Q_SAVE_MASTER_POS: do_save_master_pos(); break; - case Q_SYNC_WITH_MASTER: do_sync_with_master(q); break; + case Q_SYNC_WITH_MASTER: do_sync_with_master(command); break; case Q_SYNC_SLAVE_WITH_MASTER: { do_save_master_pos(); - if (*q->first_argument) - select_connection(q); + if (*command->first_argument) + select_connection(command); else select_connection_name("slave"); do_sync_with_master2(0); @@ -4005,14 +5554,14 @@ int main(int argc, char **argv) } case Q_COMMENT: /* Ignore row */ case Q_COMMENT_WITH_COMMAND: - q->last_argument= q->end; + command->last_argument= command->end; break; case Q_PING: (void) mysql_ping(&cur_con->mysql); break; case Q_EXEC: - do_exec(q); - query_executed= 1; + do_exec(command); + command_executed++; break; case Q_START_TIMER: /* Overwrite possible earlier start of timer */ @@ -4021,10 +5570,9 @@ int main(int argc, char **argv) case Q_END_TIMER: /* End timer before ending mysqltest */ timer_output(); - got_end_timer= TRUE; break; case Q_CHARACTER_SET: - set_charset(q); + do_set_charset(command); break; case Q_DISABLE_PS_PROTOCOL: ps_protocol_enabled= 0; @@ -4033,48 +5581,117 @@ int main(int argc, char **argv) ps_protocol_enabled= ps_protocol; break; case Q_DISABLE_RECONNECT: - cur_con->mysql.reconnect= 0; + set_reconnect(&cur_con->mysql, 0); break; case Q_ENABLE_RECONNECT: - cur_con->mysql.reconnect= 1; + set_reconnect(&cur_con->mysql, 1); break; - case Q_EXIT: - abort_flag= 1; + case Q_DISABLE_PARSING: + if (parsing_disabled == 0) + parsing_disabled= 1; + else + die("Parsing is already disabled"); + break; + case Q_ENABLE_PARSING: + /* + Ensure we don't get parsing_disabled < 0 as this would accidentally + disable code we don't want to have disabled + */ + if (parsing_disabled == 1) + parsing_disabled= 0; + else + die("Parsing is already enabled"); break; - default: processed = 0; break; + case Q_DIE: + die("%s", command->first_argument); + break; + + default: + processed= 0; + break; } } if (!processed) { - current_line_inc = 0; - switch (q->type) { - case Q_WHILE: do_block(Q_WHILE, q); break; - case Q_IF: do_block(Q_IF, q); break; - case Q_END_BLOCK: do_done(q); break; + current_line_inc= 0; + switch (command->type) { + case Q_WHILE: do_block(cmd_while, command); break; + case Q_IF: do_block(cmd_if, command); break; + case Q_END_BLOCK: do_done(command); break; default: current_line_inc = 1; break; } } else - check_eol_junk(q->last_argument); + check_eol_junk(command->last_argument); - if (q->type != Q_ERROR) + if (command->type != Q_ERROR) { /* As soon as any non "error" command has been executed, the array with expected errors should be cleared */ - global_expected_errors= 0; - bzero((gptr) global_expected_errno, sizeof(global_expected_errno)); + memset(&saved_expected_errors, 0, sizeof(saved_expected_errors)); } + if (command_executed != last_command_executed) + { + /* + As soon as any command has been executed, + the replace structures should be cleared + */ + free_all_replace(); + } + last_command_executed= command_executed; + + + parser.current_line += current_line_inc; + if ( opt_mark_progress ) + mark_progress(command, parser.current_line); } start_lineno= 0; - if (!query_executed && result_file && my_stat(result_file, &res_info, 0)) + if (parsing_disabled) + die("Test ended with parsing disabled"); + + /* + The whole test has been executed _sucessfully_. + Time to compare result or save it to record file. + The entire output from test is now kept in ds_res. + */ + if (ds_res.length) + { + if (result_file) + { + if (record) + { + /* Dump the output from test to result file */ + str_to_file(result_file, ds_res.str, ds_res.length); + } + else + { + /* Check that the output from test is equal to result file + - detect missing result file + - detect zero size result file + */ + check_result(&ds_res, result_file, 0); + } + } + else + { + /* No result_file specified to compare with, print to stdout */ + printf("%s", ds_res.str); + } + } + else + { + die("The test didn't produce any output"); + } + + if (!command_executed && result_file && my_stat(result_file, &res_info, 0)) { /* my_stat() successful on result file. Check if we have not run a @@ -4083,114 +5700,49 @@ int main(int argc, char **argv) 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) - { - if (!record) - error |= check_result(&ds_res, result_file, q->require_file); - else - str_to_file(result_file, ds_res.str, ds_res.length); - } - else - { - /* Print the result to stdout */ - printf("%s", ds_res.str); - } + die("No queries executed but result file found!"); } + + if ( opt_mark_progress ) + dump_progress(result_file); + dynstr_free(&ds_progress); + dynstr_free(&ds_res); - if (!silent) - { - if (error) - printf("not ok\n"); - else - printf("ok\n"); - } - - if (!got_end_timer) - timer_output(); /* No end_timer cmd, end it */ + timer_output(); free_used_memory(); my_end(MY_CHECK_ERROR); - exit(error ? 1 : 0); - return error ? 1 : 0; /* Keep compiler happy */ - } + + /* Yes, if we got this far the test has suceeded! Sakila smiles */ + if (!silent) + printf("ok\n"); + exit(0); + return 0; /* Keep compiler happy */ } /* - Read arguments for embedded server and put them into - embedded_server_args_count and embedded_server_args[] + A primitive timer that give results in milliseconds if the + --timer-file= is given. The timer result is written + to that file when the result is available. To not confuse + mysql-test-run with an old obsolete result, we remove the file + before executing any commands. The time we measure is + + - If no explicit 'start_timer' or 'end_timer' is given in the + test case, the timer measure how long we execute in mysqltest. + + - If only 'start_timer' is given we measure how long we execute + from that point until we terminate mysqltest. + + - If only 'end_timer' is given we measure how long we execute + from that we enter mysqltest to the 'end_timer' is command is + executed. + + - If both 'start_timer' and 'end_timer' are given we measure + the time between executing the two commands. */ - -static int read_server_arguments(const char *name) -{ - char argument[1024],buff[FN_REFLEN], *str=0; - FILE *file; - - if (!test_if_hard_path(name)) - { - strxmov(buff, opt_basedir, name, NullS); - name=buff; - } - fn_format(buff,name,"","",4); - - if (!embedded_server_arg_count) - { - embedded_server_arg_count=1; - embedded_server_args[0]= (char*) ""; /* Progname */ - } - if (!(file=my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(MY_WME)))) - return 1; - while (embedded_server_arg_count < MAX_SERVER_ARGS && - (str=fgets(argument,sizeof(argument), file))) - { - *(strend(str)-1)=0; /* Remove end newline */ - if (!(embedded_server_args[embedded_server_arg_count]= - (char*) my_strdup(str,MYF(MY_WME)))) - { - my_fclose(file,MYF(0)); - return 1; - } - embedded_server_arg_count++; - } - my_fclose(file,MYF(0)); - if (str) - { - fprintf(stderr,"Too many arguments in option file: %s\n",name); - return 1; - } - return 0; -} - -/****************************************************************************\ - * - * A primitive timer that give results in milliseconds if the - * --timer-file= is given. The timer result is written - * to that file when the result is available. To not confuse - * mysql-test-run with an old obsolete result, we remove the file - * before executing any commands. The time we measure is - * - * - If no explicit 'start_timer' or 'end_timer' is given in the - * test case, the timer measure how long we execute in mysqltest. - * - * - If only 'start_timer' is given we measure how long we execute - * from that point until we terminate mysqltest. - * - * - If only 'end_timer' is given we measure how long we execute - * from that we enter mysqltest to the 'end_timer' is command is - * executed. - * - * - If both 'start_timer' and 'end_timer' are given we measure - * the time between executing the two commands. - * -\****************************************************************************/ - -static void timer_output(void) +void timer_output(void) { if (timer_file) { @@ -4198,25 +5750,160 @@ static void timer_output(void) ulonglong timer= timer_now() - timer_start; end= longlong2str(timer, buf, 10); str_to_file(timer_file,buf, (int) (end-buf)); + /* Timer has been written to the file, don't use it anymore */ + timer_file= 0; } } -static ulonglong timer_now(void) + +ulonglong timer_now(void) { return my_getsystime() / 10000; } -/**************************************************************************** -* Handle replacement of strings -****************************************************************************/ -#define PC_MALLOC 256 /* Bytes for pointers */ -#define PS_MALLOC 512 /* Bytes for data */ +/* + Get arguments for replace_columns. The syntax is: + replace-column column_number to_string [column_number to_string ...] + Where each argument may be quoted with ' or " + A argument may also be a variable, in which case the value of the + variable is replaced. +*/ + +void do_get_replace_column(struct st_command *command) +{ + char *from= command->first_argument; + char *buff, *start; + DBUG_ENTER("get_replace_columns"); + + free_replace_column(); + if (!*from) + die("Missing argument in %s", command->query); + + /* Allocate a buffer for results */ + start= buff= my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); + while (*from) + { + char *to; + uint column_number; + + to= get_string(&buff, &from, command); + if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS) + die("Wrong column number to replace_column in '%s'", command->query); + if (!*from) + die("Wrong number of arguments to replace_column in '%s'", command->query); + to= get_string(&buff, &from, command); + my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR); + replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE)); + set_if_bigger(max_replace_column, column_number); + } + my_free(start, MYF(0)); + command->last_argument= command->end; +} + + +void free_replace_column() +{ + uint i; + for (i=0 ; i < max_replace_column ; i++) + { + if (replace_column[i]) + { + my_free(replace_column[i], 0); + replace_column[i]= 0; + } + } + max_replace_column= 0; +} + + +/****************************************************************************/ +/* + Replace functions +*/ + +/* Definitions for replace result */ + +typedef struct st_pointer_array { /* when using array-strings */ + TYPELIB typelib; /* Pointer to strings */ + byte *str; /* Strings is here */ + int7 *flag; /* Flag about each var. */ + uint array_allocs,max_count,length,max_length; +} POINTER_ARRAY; + +struct st_replace; +struct st_replace *init_replace(my_string *from, my_string *to, uint count, + my_string word_end_chars); +int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name); +void replace_strings_append(struct st_replace *rep, DYNAMIC_STRING* ds, + const char *from, int len); +void free_pointer_array(POINTER_ARRAY *pa); + +struct st_replace *glob_replace; + +/* + Get arguments for replace. The syntax is: + replace from to [from to ...] + Where each argument may be quoted with ' or " + A argument may also be a variable, in which case the value of the + variable is replaced. +*/ + +void do_get_replace(struct st_command *command) +{ + uint i; + char *from= command->first_argument; + char *buff, *start; + char word_end_chars[256], *pos; + POINTER_ARRAY to_array, from_array; + DBUG_ENTER("get_replace"); + + free_replace(); + + bzero((char*) &to_array,sizeof(to_array)); + bzero((char*) &from_array,sizeof(from_array)); + if (!*from) + die("Missing argument in %s", command->query); + start= buff= my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); + while (*from) + { + char *to= buff; + to= get_string(&buff, &from, command); + if (!*from) + die("Wrong number of arguments to replace_result in '%s'", + command->query); + insert_pointer_name(&from_array,to); + to= get_string(&buff, &from, command); + insert_pointer_name(&to_array,to); + } + for (i= 1,pos= word_end_chars ; i < 256 ; i++) + if (my_isspace(charset_info,i)) + *pos++= i; + *pos=0; /* End pointer */ + if (!(glob_replace= init_replace((char**) from_array.typelib.type_names, + (char**) to_array.typelib.type_names, + (uint) from_array.typelib.count, + word_end_chars))) + die("Can't initialize replace from '%s'", command->query); + free_pointer_array(&from_array); + free_pointer_array(&to_array); + my_free(start, MYF(0)); + command->last_argument= command->end; + DBUG_VOID_RETURN; +} + + +void free_replace() +{ + DBUG_ENTER("free_replace"); + if (glob_replace) + { + my_free((char*) glob_replace,MYF(0)); + glob_replace=0; + } + DBUG_VOID_RETURN; +} -#define SPACE_CHAR 256 -#define START_OF_LINE 257 -#define END_OF_LINE 258 -#define LAST_CHAR_CODE 259 typedef struct st_replace { bool found; @@ -4230,99 +5917,514 @@ typedef struct st_replace_found { int from_offset; } REPLACE_STRING; + +void replace_strings_append(REPLACE *rep, DYNAMIC_STRING* ds, + const char *str, int len) +{ + reg1 REPLACE *rep_pos; + reg2 REPLACE_STRING *rep_str; + const char *start, *from; + DBUG_ENTER("replace_strings_append"); + + start= from= str; + rep_pos=rep+1; + for (;;) + { + /* Loop through states */ + DBUG_PRINT("info", ("Looping through states")); + while (!rep_pos->found) + rep_pos= rep_pos->next[(uchar) *from++]; + + /* Does this state contain a string to be replaced */ + if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string) + { + /* No match found */ + dynstr_append_mem(ds, start, from - start - 1); + DBUG_PRINT("exit", ("Found no more string to replace, appended: %s", start)); + DBUG_VOID_RETURN; + } + + /* Found a string that needs to be replaced */ + DBUG_PRINT("info", ("found: %d, to_offset: %d, from_offset: %d, string: %s", + rep_str->found, rep_str->to_offset, + rep_str->from_offset, rep_str->replace_string)); + + /* Append part of original string before replace string */ + dynstr_append_mem(ds, start, (from - rep_str->to_offset) - start); + + /* Append replace string */ + dynstr_append_mem(ds, rep_str->replace_string, + strlen(rep_str->replace_string)); + + if (!*(from-=rep_str->from_offset) && rep_pos->found != 2) + { + /* End of from string */ + DBUG_PRINT("exit", ("Found end of from string")); + DBUG_VOID_RETURN; + } + DBUG_ASSERT(from <= str+len); + start= from; + rep_pos=rep; + } +} + + +/* + Regex replace functions +*/ + + +/* Stores regex substitutions */ + +struct st_regex +{ + char* pattern; /* Pattern to be replaced */ + char* replace; /* String or expression to replace the pattern with */ + int icase; /* true if the match is case insensitive */ +}; + +struct st_replace_regex +{ + DYNAMIC_ARRAY regex_arr; /* stores a list of st_regex subsitutions */ + + /* + Temporary storage areas for substitutions. To reduce unnessary copying + and memory freeing/allocation, we pre-allocate two buffers, and alternate + their use, one for input/one for output, the roles changing on the next + st_regex substition. At the end of substitutions buf points to the + one containing the final result. + */ + char* buf; + char* even_buf; + char* odd_buf; + int even_buf_len; + int odd_buf_len; +}; + +struct st_replace_regex *glob_replace_regex= 0; + +int reg_replace(char** buf_p, int* buf_len_p, char *pattern, char *replace, + char *string, int icase); + + + +/* + Finds the next (non-escaped) '/' in the expression. + (If the character '/' is needed, it can be escaped using '\'.) +*/ + +#define PARSE_REGEX_ARG \ + while (p < expr_end) \ + { \ + char c= *p; \ + if (c == '/') \ + { \ + if (last_c == '\\') \ + { \ + buf_p[-1]= '/'; \ + } \ + else \ + { \ + *buf_p++ = 0; \ + break; \ + } \ + } \ + else \ + *buf_p++ = c; \ + \ + last_c= c; \ + p++; \ + } \ + \ +/* + Initializes the regular substitution expression to be used in the + result output of test. + + Returns: st_replace_regex struct with pairs of substitutions +*/ + +struct st_replace_regex* init_replace_regex(char* expr) +{ + struct st_replace_regex* res; + char* buf,*expr_end; + char* p; + char* buf_p; + uint expr_len= strlen(expr); + char last_c = 0; + struct st_regex reg; + + /* my_malloc() will die on fail with MY_FAE */ + res=(struct st_replace_regex*)my_malloc( + sizeof(*res)+expr_len ,MYF(MY_FAE+MY_WME)); + my_init_dynamic_array(&res->regex_arr,sizeof(struct st_regex),128,128); + + buf= (char*)res + sizeof(*res); + expr_end= expr + expr_len; + p= expr; + buf_p= buf; + + /* for each regexp substitution statement */ + while (p < expr_end) + { + bzero(®,sizeof(reg)); + /* find the start of the statement */ + while (p < expr_end) + { + if (*p == '/') + break; + p++; + } + + if (p == expr_end || ++p == expr_end) + { + if (res->regex_arr.elements) + break; + else + goto err; + } + /* we found the start */ + reg.pattern= buf_p; + + /* Find first argument -- pattern string to be removed */ + PARSE_REGEX_ARG + + if (p == expr_end || ++p == expr_end) + goto err; + + /* buf_p now points to the replacement pattern terminated with \0 */ + reg.replace= buf_p; + + /* Find second argument -- replace string to replace pattern */ + PARSE_REGEX_ARG + + if (p == expr_end) + goto err; + + /* skip the ending '/' in the statement */ + p++; + + /* Check if we should do matching case insensitive */ + if (p < expr_end && *p == 'i') + reg.icase= 1; + + /* done parsing the statement, now place it in regex_arr */ + if (insert_dynamic(&res->regex_arr,(gptr) ®)) + die("Out of memory"); + } + res->odd_buf_len= res->even_buf_len= 8192; + res->even_buf= (char*)my_malloc(res->even_buf_len,MYF(MY_WME+MY_FAE)); + res->odd_buf= (char*)my_malloc(res->odd_buf_len,MYF(MY_WME+MY_FAE)); + res->buf= res->even_buf; + + return res; + +err: + my_free((gptr)res,0); + die("Error parsing replace_regex \"%s\"", expr); + return 0; +} + +/* + Execute all substitutions on val. + + Returns: true if substituition was made, false otherwise + Side-effect: Sets r->buf to be the buffer with all substitutions done. + + IN: + struct st_replace_regex* r + char* val + Out: + struct st_replace_regex* r + r->buf points at the resulting buffer + r->even_buf and r->odd_buf might have been reallocated + r->even_buf_len and r->odd_buf_len might have been changed + + TODO: at some point figure out if there is a way to do everything + in one pass +*/ + +int multi_reg_replace(struct st_replace_regex* r,char* val) +{ + uint i; + char* in_buf, *out_buf; + int* buf_len_p; + + in_buf= val; + out_buf= r->even_buf; + buf_len_p= &r->even_buf_len; + r->buf= 0; + + /* For each substitution, do the replace */ + for (i= 0; i < r->regex_arr.elements; i++) + { + struct st_regex re; + char* save_out_buf= out_buf; + + get_dynamic(&r->regex_arr,(gptr)&re,i); + + if (!reg_replace(&out_buf, buf_len_p, re.pattern, re.replace, + in_buf, re.icase)) + { + /* if the buffer has been reallocated, make adjustements */ + if (save_out_buf != out_buf) + { + if (save_out_buf == r->even_buf) + r->even_buf= out_buf; + else + r->odd_buf= out_buf; + } + + r->buf= out_buf; + if (in_buf == val) + in_buf= r->odd_buf; + + swap_variables(char*,in_buf,out_buf); + + buf_len_p= (out_buf == r->even_buf) ? &r->even_buf_len : + &r->odd_buf_len; + } + } + + return (r->buf == 0); +} + +/* + Parse the regular expression to be used in all result files + from now on. + + The syntax is --replace_regex /from/to/i /from/to/i ... + i means case-insensitive match. If omitted, the match is + case-sensitive + +*/ +void do_get_replace_regex(struct st_command *command) +{ + char *expr= command->first_argument; + free_replace_regex(); + if (!(glob_replace_regex=init_replace_regex(expr))) + die("Could not init replace_regex"); + command->last_argument= command->end; +} + +void free_replace_regex() +{ + if (glob_replace_regex) + { + delete_dynamic(&glob_replace_regex->regex_arr); + my_free(glob_replace_regex->even_buf,MYF(MY_ALLOW_ZERO_PTR)); + my_free(glob_replace_regex->odd_buf,MYF(MY_ALLOW_ZERO_PTR)); + my_free((char*) glob_replace_regex,MYF(0)); + glob_replace_regex=0; + } +} + + + +/* + auxiluary macro used by reg_replace + makes sure the result buffer has sufficient length +*/ +#define SECURE_REG_BUF if (buf_len < need_buf_len) \ + { \ + int off= res_p - buf; \ + buf= (char*)my_realloc(buf,need_buf_len,MYF(MY_WME+MY_FAE)); \ + res_p= buf + off; \ + buf_len= need_buf_len; \ + } \ + \ +/* + Performs a regex substitution + + IN: + + buf_p - result buffer pointer. Will change if reallocated + buf_len_p - result buffer length. Will change if the buffer is reallocated + pattern - regexp pattern to match + replace - replacement expression + string - the string to perform substituions in + icase - flag, if set to 1 the match is case insensitive +*/ +int reg_replace(char** buf_p, int* buf_len_p, char *pattern, + char *replace, char *string, int icase) +{ + my_regex_t r; + my_regmatch_t *subs; + char *buf_end, *replace_end; + char *buf= *buf_p; + int len; + int buf_len, need_buf_len; + int cflags= REG_EXTENDED; + int err_code; + char *res_p,*str_p,*str_end; + + buf_len= *buf_len_p; + len= strlen(string); + str_end= string + len; + + /* start with a buffer of a reasonable size that hopefully will not + need to be reallocated + */ + need_buf_len= len * 2 + 1; + res_p= buf; + + SECURE_REG_BUF + + buf_end= buf + buf_len; + + if (icase) + cflags|= REG_ICASE; + + if ((err_code= my_regcomp(&r,pattern,cflags,&my_charset_latin1))) + { + check_regerr(&r,err_code); + return 1; + } + + subs= (my_regmatch_t*)my_malloc(sizeof(my_regmatch_t) * (r.re_nsub+1), + MYF(MY_WME+MY_FAE)); + + *res_p= 0; + str_p= string; + replace_end= replace + strlen(replace); + + /* for each pattern match instance perform a replacement */ + while (!err_code) + { + /* find the match */ + err_code= my_regexec(&r,str_p, r.re_nsub+1, subs, + (str_p == string) ? REG_NOTBOL : 0); + + /* if regular expression error (eg. bad syntax, or out of memory) */ + if (err_code && err_code != REG_NOMATCH) + { + check_regerr(&r,err_code); + my_regfree(&r); + return 1; + } + + /* if match found */ + if (!err_code) + { + char* expr_p= replace; + int c; + + /* + we need at least what we have so far in the buffer + the part + before this match + */ + need_buf_len= (res_p - buf) + subs[0].rm_so; + + /* on this pass, calculate the memory for the result buffer */ + while (expr_p < replace_end) + { + int back_ref_num= -1; + c= *expr_p; + + if (c == '\\' && expr_p + 1 < replace_end) + { + back_ref_num= expr_p[1] - '0'; + } + + /* found a valid back_ref (eg. \1)*/ + if (back_ref_num >= 0 && back_ref_num <= (int)r.re_nsub) + { + int start_off,end_off; + if ((start_off=subs[back_ref_num].rm_so) > -1 && + (end_off=subs[back_ref_num].rm_eo) > -1) + { + need_buf_len += (end_off - start_off); + } + expr_p += 2; + } + else + { + expr_p++; + need_buf_len++; + } + } + need_buf_len++; + /* + now that we know the size of the buffer, + make sure it is big enough + */ + SECURE_REG_BUF + + /* copy the pre-match part */ + if (subs[0].rm_so) + { + memcpy(res_p, str_p, subs[0].rm_so); + res_p+= subs[0].rm_so; + } + + expr_p= replace; + + /* copy the match and expand back_refs */ + while (expr_p < replace_end) + { + int back_ref_num= -1; + c= *expr_p; + + if (c == '\\' && expr_p + 1 < replace_end) + { + back_ref_num= expr_p[1] - '0'; + } + + if (back_ref_num >= 0 && back_ref_num <= (int)r.re_nsub) + { + int start_off,end_off; + if ((start_off=subs[back_ref_num].rm_so) > -1 && + (end_off=subs[back_ref_num].rm_eo) > -1) + { + int block_len= end_off - start_off; + memcpy(res_p,str_p + start_off, block_len); + res_p += block_len; + } + expr_p += 2; + } + else + { + *res_p++ = *expr_p++; + } + } + + /* handle the post-match part */ + if (subs[0].rm_so == subs[0].rm_eo) + { + if (str_p + subs[0].rm_so >= str_end) + break; + str_p += subs[0].rm_eo ; + *res_p++ = *str_p++; + } + else + { + str_p += subs[0].rm_eo; + } + } + else /* no match this time, just copy the string as is */ + { + int left_in_str= str_end-str_p; + need_buf_len= (res_p-buf) + left_in_str; + SECURE_REG_BUF + memcpy(res_p,str_p,left_in_str); + res_p += left_in_str; + str_p= str_end; + } + } + my_free((gptr)subs, MYF(0)); + my_regfree(&r); + *res_p= 0; + *buf_p= buf; + *buf_len_p= buf_len; + return 0; +} + + #ifndef WORD_BIT #define WORD_BIT (8*sizeof(uint)) #endif - -static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name) -{ - uint i,length,old_count; - byte *new_pos; - const char **new_array; - DBUG_ENTER("insert_pointer_name"); - - if (! pa->typelib.count) - { - if (!(pa->typelib.type_names=(const char **) - my_malloc(((PC_MALLOC-MALLOC_OVERHEAD)/ - (sizeof(my_string)+sizeof(*pa->flag))* - (sizeof(my_string)+sizeof(*pa->flag))),MYF(MY_WME)))) - DBUG_RETURN(-1); - if (!(pa->str= (byte*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD), - MYF(MY_WME)))) - { - my_free((gptr) pa->typelib.type_names,MYF(0)); - DBUG_RETURN (-1); - } - pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(byte*)+ - sizeof(*pa->flag)); - pa->flag= (int7*) (pa->typelib.type_names+pa->max_count); - pa->length=0; - pa->max_length=PS_MALLOC-MALLOC_OVERHEAD; - pa->array_allocs=1; - } - length=(uint) strlen(name)+1; - if (pa->length+length >= pa->max_length) - { - if (!(new_pos= (byte*) my_realloc((gptr) pa->str, - (uint) (pa->max_length+PS_MALLOC), - MYF(MY_WME)))) - DBUG_RETURN(1); - if (new_pos != pa->str) - { - my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str); - for (i=0 ; i < pa->typelib.count ; i++) - pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff, - char*); - pa->str=new_pos; - } - pa->max_length+=PS_MALLOC; - } - if (pa->typelib.count >= pa->max_count-1) - { - int len; - pa->array_allocs++; - len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD); - if (!(new_array=(const char **) my_realloc((gptr) pa->typelib.type_names, - (uint) len/ - (sizeof(byte*)+sizeof(*pa->flag))* - (sizeof(byte*)+sizeof(*pa->flag)), - MYF(MY_WME)))) - DBUG_RETURN(1); - pa->typelib.type_names=new_array; - old_count=pa->max_count; - pa->max_count=len/(sizeof(byte*) + sizeof(*pa->flag)); - pa->flag= (int7*) (pa->typelib.type_names+pa->max_count); - memcpy((byte*) pa->flag,(my_string) (pa->typelib.type_names+old_count), - old_count*sizeof(*pa->flag)); - } - pa->flag[pa->typelib.count]=0; /* Reset flag */ - pa->typelib.type_names[pa->typelib.count++]= pa->str+pa->length; - pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */ - VOID(strmov(pa->str+pa->length,name)); - pa->length+=length; - DBUG_RETURN(0); -} /* insert_pointer_name */ - - - /* free pointer array */ - -void free_pointer_array(POINTER_ARRAY *pa) -{ - if (pa->typelib.count) - { - pa->typelib.count=0; - my_free((gptr) pa->typelib.type_names,MYF(0)); - pa->typelib.type_names=0; - my_free((gptr) pa->str,MYF(0)); - } -} /* free_pointer_array */ - - - /* Code for replace rutines */ - #define SET_MALLOC_HUNC 64 +#define LAST_CHAR_CODE 259 typedef struct st_rep_set { uint *bits; /* Pointer to used sets */ @@ -4354,32 +6456,48 @@ typedef struct st_follow { } FOLLOWS; -static int init_sets(REP_SETS *sets,uint states); -static REP_SET *make_new_set(REP_SETS *sets); -static void make_sets_invisible(REP_SETS *sets); -static void free_last_set(REP_SETS *sets); -static void free_sets(REP_SETS *sets); -static void internal_set_bit(REP_SET *set, uint bit); -static void internal_clear_bit(REP_SET *set, uint bit); -static void or_bits(REP_SET *to,REP_SET *from); -static void copy_bits(REP_SET *to,REP_SET *from); -static int cmp_bits(REP_SET *set1,REP_SET *set2); -static int get_next_bit(REP_SET *set,uint lastpos); -static int find_set(REP_SETS *sets,REP_SET *find); -static int find_found(FOUND_SET *found_set,uint table_offset, - int found_offset); -static uint start_at_word(my_string pos); -static uint end_of_word(my_string pos); -static uint replace_len(my_string pos); +int init_sets(REP_SETS *sets,uint states); +REP_SET *make_new_set(REP_SETS *sets); +void make_sets_invisible(REP_SETS *sets); +void free_last_set(REP_SETS *sets); +void free_sets(REP_SETS *sets); +void internal_set_bit(REP_SET *set, uint bit); +void internal_clear_bit(REP_SET *set, uint bit); +void or_bits(REP_SET *to,REP_SET *from); +void copy_bits(REP_SET *to,REP_SET *from); +int cmp_bits(REP_SET *set1,REP_SET *set2); +int get_next_bit(REP_SET *set,uint lastpos); +int find_set(REP_SETS *sets,REP_SET *find); +int find_found(FOUND_SET *found_set,uint table_offset, + int found_offset); +uint start_at_word(my_string pos); +uint end_of_word(my_string pos); static uint found_sets=0; - /* Init a replace structure for further calls */ +uint replace_len(my_string str) +{ + uint len=0; + while (*str) + { + if (str[0] == '\\' && str[1]) + str++; + str++; + len++; + } + return len; +} + +/* Init a replace structure for further calls */ REPLACE *init_replace(my_string *from, my_string *to,uint count, my_string word_end_chars) { + static const int SPACE_CHAR= 256; + static const int START_OF_LINE= 257; + static const int END_OF_LINE= 258; + uint i,j,states,set_nr,len,result_len,max_length,found_end,bits_set,bit_nr; int used_sets,chr,default_state; char used_chars[LAST_CHAR_CODE],is_word_end[256]; @@ -4432,7 +6550,7 @@ REPLACE *init_replace(my_string *from, my_string *to,uint count, DBUG_RETURN(0); } - /* Init follow_ptr[] */ + /* Init follow_ptr[] */ for (i=0, states=1, follow_ptr=follow+1 ; i < count ; i++) { if (from[i][0] == '\\' && from[i][1] == '^') @@ -4615,7 +6733,7 @@ REPLACE *init_replace(my_string *from, my_string *to,uint count, } } - /* Alloc replace structure for the replace-state-machine */ + /* Alloc replace structure for the replace-state-machine */ if ((replace=(REPLACE*) my_malloc(sizeof(REPLACE)*(sets.count)+ sizeof(REPLACE_STRING)*(found_sets+1)+ @@ -4658,7 +6776,7 @@ REPLACE *init_replace(my_string *from, my_string *to,uint count, } -static int init_sets(REP_SETS *sets,uint states) +int init_sets(REP_SETS *sets,uint states) { bzero((char*) sets,sizeof(*sets)); sets->size_of_bits=((states+7)/8); @@ -4674,16 +6792,16 @@ static int init_sets(REP_SETS *sets,uint states) return 0; } - /* Make help sets invisible for nicer codeing */ +/* Make help sets invisible for nicer codeing */ -static void make_sets_invisible(REP_SETS *sets) +void make_sets_invisible(REP_SETS *sets) { sets->invisible=sets->count; sets->set+=sets->count; sets->count=0; } -static REP_SET *make_new_set(REP_SETS *sets) +REP_SET *make_new_set(REP_SETS *sets) { uint i,count,*bit_buffer; REP_SET *set; @@ -4701,7 +6819,7 @@ static REP_SET *make_new_set(REP_SETS *sets) } count=sets->count+sets->invisible+SET_MALLOC_HUNC; if (!(set=(REP_SET*) my_realloc((gptr) sets->set_buffer, - sizeof(REP_SET)*count, + sizeof(REP_SET)*count, MYF(MY_WME)))) return 0; sets->set_buffer=set; @@ -4720,34 +6838,34 @@ static REP_SET *make_new_set(REP_SETS *sets) return make_new_set(sets); } -static void free_last_set(REP_SETS *sets) +void free_last_set(REP_SETS *sets) { sets->count--; sets->extra++; return; } -static void free_sets(REP_SETS *sets) +void free_sets(REP_SETS *sets) { my_free((gptr)sets->set_buffer,MYF(0)); my_free((gptr)sets->bit_buffer,MYF(0)); return; } -static void internal_set_bit(REP_SET *set, uint bit) +void internal_set_bit(REP_SET *set, uint bit) { set->bits[bit / WORD_BIT] |= 1 << (bit % WORD_BIT); return; } -static void internal_clear_bit(REP_SET *set, uint bit) +void internal_clear_bit(REP_SET *set, uint bit) { set->bits[bit / WORD_BIT] &= ~ (1 << (bit % WORD_BIT)); return; } -static void or_bits(REP_SET *to,REP_SET *from) +void or_bits(REP_SET *to,REP_SET *from) { reg1 uint i; for (i=0 ; i < to->size_of_bits ; i++) @@ -4755,22 +6873,22 @@ static void or_bits(REP_SET *to,REP_SET *from) return; } -static void copy_bits(REP_SET *to,REP_SET *from) +void copy_bits(REP_SET *to,REP_SET *from) { memcpy((byte*) to->bits,(byte*) from->bits, (size_t) (sizeof(uint) * to->size_of_bits)); } -static int cmp_bits(REP_SET *set1,REP_SET *set2) +int cmp_bits(REP_SET *set1,REP_SET *set2) { return bcmp((byte*) set1->bits,(byte*) set2->bits, sizeof(uint) * set1->size_of_bits); } - /* Get next set bit from set. */ +/* Get next set bit from set. */ -static int get_next_bit(REP_SET *set,uint lastpos) +int get_next_bit(REP_SET *set,uint lastpos) { uint pos,*start,*end,bits; @@ -4791,11 +6909,11 @@ static int get_next_bit(REP_SET *set,uint lastpos) return pos; } - /* find if there is a same set in sets. If there is, use it and - free given set, else put in given set in sets and return it's - position */ +/* find if there is a same set in sets. If there is, use it and + free given set, else put in given set in sets and return its + position */ -static int find_set(REP_SETS *sets,REP_SET *find) +int find_set(REP_SETS *sets,REP_SET *find) { uint i; for (i=0 ; i < sets->count-1 ; i++) @@ -4809,14 +6927,14 @@ static int find_set(REP_SETS *sets,REP_SET *find) return i; /* return new postion */ } - /* find if there is a found_set with same table_offset & found_offset - If there is return offset to it, else add new offset and return pos. - Pos returned is -offset-2 in found_set_structure because it's is - saved in set->next and set->next[] >= 0 points to next set and - set->next[] == -1 is reserved for end without replaces. - */ +/* find if there is a found_set with same table_offset & found_offset + If there is return offset to it, else add new offset and return pos. + Pos returned is -offset-2 in found_set_structure because it is + saved in set->next and set->next[] >= 0 points to next set and + set->next[] == -1 is reserved for end without replaces. +*/ -static int find_found(FOUND_SET *found_set,uint table_offset, int found_offset) +int find_found(FOUND_SET *found_set,uint table_offset, int found_offset) { int i; for (i=0 ; (uint) i < found_sets ; i++) @@ -4829,251 +6947,155 @@ static int find_found(FOUND_SET *found_set,uint table_offset, int found_offset) return -i-2; /* return new postion */ } - /* Return 1 if regexp starts with \b or ends with \b*/ +/* Return 1 if regexp starts with \b or ends with \b*/ -static uint start_at_word(my_string pos) +uint start_at_word(my_string pos) { return (((!bcmp(pos,"\\b",2) && pos[2]) || !bcmp(pos,"\\^",2)) ? 1 : 0); } -static uint end_of_word(my_string pos) +uint end_of_word(my_string pos) { my_string end=strend(pos); return ((end > pos+2 && !bcmp(end-2,"\\b",2)) || (end >= pos+2 && !bcmp(end-2,"\\$",2))) ? - 1 : 0; + 1 : 0; } - -static uint replace_len(my_string str) -{ - uint len=0; - while (*str) - { - if (str[0] == '\\' && str[1]) - str++; - str++; - len++; - } - return len; -} - - - /* Replace strings; Return length of result string */ - -uint replace_strings(REPLACE *rep, my_string *start,uint *max_length, - const char *from) -{ - reg1 REPLACE *rep_pos; - reg2 REPLACE_STRING *rep_str; - my_string to,end,pos,new_str; - - end=(to= *start) + *max_length-1; - rep_pos=rep+1; - for (;;) - { - while (!rep_pos->found) - { - rep_pos= rep_pos->next[(uchar) *from]; - if (to == end) - { - (*max_length)+=8192; - if (!(new_str=my_realloc(*start,*max_length,MYF(MY_WME)))) - return (uint) -1; - to=new_str+(to - *start); - end=(*start=new_str)+ *max_length-1; - } - *to++= *from++; - } - if (!(rep_str = ((REPLACE_STRING*) rep_pos))->replace_string) - return (uint) (to - *start)-1; - to-=rep_str->to_offset; - for (pos=rep_str->replace_string; *pos ; pos++) - { - if (to == end) - { - (*max_length)*=2; - if (!(new_str=my_realloc(*start,*max_length,MYF(MY_WME)))) - return (uint) -1; - to=new_str+(to - *start); - end=(*start=new_str)+ *max_length-1; - } - *to++= *pos; - } - if (!*(from-=rep_str->from_offset) && rep_pos->found != 2) - return (uint) (to - *start); - rep_pos=rep; - } -} - -static int initialize_replace_buffer(void) -{ - out_length=8192; - if (!(out_buff=my_malloc(out_length,MYF(MY_WME)))) - return(1); - return 0; -} - -static void free_replace_buffer(void) -{ - my_free(out_buff,MYF(MY_WME)); -} - - /**************************************************************************** - Replace results for a column -*****************************************************************************/ + * Handle replacement of strings + ****************************************************************************/ -static void free_replace_column() +#define PC_MALLOC 256 /* Bytes for pointers */ +#define PS_MALLOC 512 /* Bytes for data */ + +int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name) { - uint i; - for (i=0 ; i < max_replace_column ; i++) + uint i,length,old_count; + byte *new_pos; + const char **new_array; + DBUG_ENTER("insert_pointer_name"); + + if (! pa->typelib.count) { - if (replace_column[i]) + if (!(pa->typelib.type_names=(const char **) + my_malloc(((PC_MALLOC-MALLOC_OVERHEAD)/ + (sizeof(my_string)+sizeof(*pa->flag))* + (sizeof(my_string)+sizeof(*pa->flag))),MYF(MY_WME)))) + DBUG_RETURN(-1); + if (!(pa->str= (byte*) my_malloc((uint) (PS_MALLOC-MALLOC_OVERHEAD), + MYF(MY_WME)))) { - my_free(replace_column[i], 0); - replace_column[i]= 0; + my_free((gptr) pa->typelib.type_names,MYF(0)); + DBUG_RETURN (-1); } + pa->max_count=(PC_MALLOC-MALLOC_OVERHEAD)/(sizeof(byte*)+ + sizeof(*pa->flag)); + pa->flag= (int7*) (pa->typelib.type_names+pa->max_count); + pa->length=0; + pa->max_length=PS_MALLOC-MALLOC_OVERHEAD; + pa->array_allocs=1; } - max_replace_column= 0; -} - -/* - Get arguments for replace_columns. The syntax is: - replace-column column_number to_string [column_number to_string ...] - Where each argument may be quoted with ' or " - A argument may also be a variable, in which case the value of the - variable is replaced. -*/ - -static void get_replace_column(struct st_query *q) -{ - char *from=q->first_argument; - char *buff,*start; - DBUG_ENTER("get_replace_columns"); - - free_replace_column(); - if (!*from) - die("Missing argument in %s", q->query); - - /* Allocate a buffer for results */ - start=buff=my_malloc(strlen(from)+1,MYF(MY_WME | MY_FAE)); - while (*from) + length=(uint) strlen(name)+1; + if (pa->length+length >= pa->max_length) { - char *to; - uint column_number; - - to= get_string(&buff, &from, q); - if (!(column_number= atoi(to)) || column_number > MAX_COLUMNS) - die("Wrong column number to replace_column in '%s'", q->query); - if (!*from) - die("Wrong number of arguments to replace_column in '%s'", q->query); - to= get_string(&buff, &from, q); - my_free(replace_column[column_number-1], MY_ALLOW_ZERO_PTR); - replace_column[column_number-1]= my_strdup(to, MYF(MY_WME | MY_FAE)); - set_if_bigger(max_replace_column, column_number); - } - my_free(start, MYF(0)); - q->last_argument= q->end; -} - -#if defined(__NETWARE__) || defined(__WIN__) -/* - Substitute environment variables with text. - - SYNOPSIS - subst_env_var() - arg String that should be substitute - - DESCRIPTION - This function takes a string as an input and replaces the - environment variables, that starts with '$' character, with it value. - - NOTES - Return string must be freed with my_free() - - RETURN - String with environment variables replaced. -*/ - -static char *subst_env_var(const char *str) -{ - char *result; - char *pos; - - result= pos= my_malloc(MAX_QUERY, MYF(MY_FAE)); - while (*str) - { - /* - need this only when we want to provide the functionality of - escaping through \ 'backslash' - if ((result == pos && *str=='$') || - (result != pos && *str=='$' && str[-1] !='\\')) - */ - if (*str == '$') + if (!(new_pos= (byte*) my_realloc((gptr) pa->str, + (uint) (pa->max_length+PS_MALLOC), + MYF(MY_WME)))) + DBUG_RETURN(1); + if (new_pos != pa->str) { - char env_var[256], *env_pos= env_var, *subst; - - /* Search for end of environment variable */ - for (str++; - *str && !isspace(*str) && *str != '\\' && *str != '/' && - *str != '$'; - str++) - *env_pos++= *str; - *env_pos= 0; - - if (!(subst= getenv(env_var))) - { - my_free(result, MYF(0)); - die("MYSQLTEST.NLM: Environment variable %s is not defined", - env_var); - } - - /* get the string to be substitued for env_var */ - pos= strmov(pos, subst); - /* Process delimiter in *str again */ + my_ptrdiff_t diff=PTR_BYTE_DIFF(new_pos,pa->str); + for (i=0 ; i < pa->typelib.count ; i++) + pa->typelib.type_names[i]= ADD_TO_PTR(pa->typelib.type_names[i],diff, + char*); + pa->str=new_pos; } - else - *pos++= *str++; + pa->max_length+=PS_MALLOC; } - *pos= 0; - return result; -} + if (pa->typelib.count >= pa->max_count-1) + { + int len; + pa->array_allocs++; + len=(PC_MALLOC*pa->array_allocs - MALLOC_OVERHEAD); + if (!(new_array=(const char **) my_realloc((gptr) pa->typelib.type_names, + (uint) len/ + (sizeof(byte*)+sizeof(*pa->flag))* + (sizeof(byte*)+sizeof(*pa->flag)), + MYF(MY_WME)))) + DBUG_RETURN(1); + pa->typelib.type_names=new_array; + old_count=pa->max_count; + pa->max_count=len/(sizeof(byte*) + sizeof(*pa->flag)); + pa->flag= (int7*) (pa->typelib.type_names+pa->max_count); + memcpy((byte*) pa->flag,(my_string) (pa->typelib.type_names+old_count), + old_count*sizeof(*pa->flag)); + } + pa->flag[pa->typelib.count]=0; /* Reset flag */ + pa->typelib.type_names[pa->typelib.count++]= pa->str+pa->length; + pa->typelib.type_names[pa->typelib.count]= NullS; /* Put end-mark */ + VOID(strmov(pa->str+pa->length,name)); + pa->length+=length; + DBUG_RETURN(0); +} /* insert_pointer_name */ -/* - popen replacement for Netware +/* free pointer array */ - SYNPOSIS - my_popen() - name Command to execute (with possible env variables) - mode Mode for popen. +void free_pointer_array(POINTER_ARRAY *pa) +{ + if (pa->typelib.count) + { + pa->typelib.count=0; + my_free((gptr) pa->typelib.type_names,MYF(0)); + pa->typelib.type_names=0; + my_free((gptr) pa->str,MYF(0)); + } +} /* free_pointer_array */ - NOTES - Environment variable expansion does not take place for popen function - on NetWare, so we use this function to wrap around popen to do this. - For the moment we ignore 'mode' and always use 'r0' +/* Functions that uses replace and replace_regex */ - RETURN - # >= 0 File handle - -1 Error -*/ - -#undef popen /* Remove wrapper */ -#ifdef __WIN__ -#define popen _popen /* redefine for windows */ +/* Append the string to ds, with optional replace */ +void replace_dynstr_append_mem(DYNAMIC_STRING *ds, + const char *val, int len) +{ +#ifdef __WIN__ + fix_win_paths(val, len); #endif -FILE *my_popen(const char *cmd, const char *mode __attribute__((unused))) -{ - char *subst_cmd; - FILE *res_file; + if (glob_replace_regex) + { + /* Regex replace */ + if (!multi_reg_replace(glob_replace_regex, (char*)val)) + { + val= glob_replace_regex->buf; + len= strlen(val); + } + } - subst_cmd= subst_env_var(cmd); - res_file= popen(subst_cmd, "r0"); - my_free(subst_cmd, MYF(0)); - return res_file; + if (glob_replace) + { + /* Normal replace */ + replace_strings_append(glob_replace, ds, val, len); + } + else + dynstr_append_mem(ds, val, len); } -#endif /* __NETWARE__ or __WIN__*/ + +/* Append zero-terminated string to ds, with optional replace */ +void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val) +{ + replace_dynstr_append_mem(ds, val, strlen(val)); +} + +/* Append uint to ds, with optional replace */ +void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val) +{ + char buff[22]; /* This should be enough for any int */ + char *end= longlong10_to_str(val, buff, 10); + replace_dynstr_append_mem(ds, buff, end - buff); +} + + diff --git a/mysql-test/include/have_multi_ndb.inc b/mysql-test/include/have_multi_ndb.inc index ec1a93311fb..844c4d78774 100644 --- a/mysql-test/include/have_multi_ndb.inc +++ b/mysql-test/include/have_multi_ndb.inc @@ -9,8 +9,10 @@ disable_query_log; drop table if exists t1, t2; --enable_warnings flush tables; -@r/have_ndb.require show variables like "have_ndbcluster"; -# @r/server_id.require show variables like "server_id"; +--require r/have_ndb.require +show variables like "have_ndbcluster"; +#--require r/server_id.require +#show variables like "server_id"; enable_query_log; # Check that server2 has NDB support @@ -20,8 +22,10 @@ disable_query_log; drop table if exists t1, t2; --enable_warnings flush tables; -@r/have_ndb.require show variables like "have_ndbcluster"; -# @r/server_id1.require show variables like "server_id"; +--require r/have_ndb.require +show variables like "have_ndbcluster"; +#--require r@r/server_id1.require +#show variables like "server_id"; enable_query_log; # Set the default connection to 'server1' diff --git a/mysql-test/include/master-slave.inc b/mysql-test/include/master-slave.inc index 5ec4b4379f8..9ef5489f346 100644 --- a/mysql-test/include/master-slave.inc +++ b/mysql-test/include/master-slave.inc @@ -8,7 +8,8 @@ connection slave; --disable_warnings stop slave; --enable_warnings -@r/slave-stopped.result show status like 'Slave_running'; +--require r/slave-stopped.result +show status like 'Slave_running'; connection master; --disable_warnings drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; @@ -21,7 +22,8 @@ reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; --enable_warnings start slave; -@r/slave-running.result show status like 'Slave_running'; +--require r/slave-running.result +show status like 'Slave_running'; # Set the default connection to 'master' connection master; diff --git a/mysql-test/include/ps_query.inc b/mysql-test/include/ps_query.inc index 9a413bff2f3..a2eac09d121 100644 --- a/mysql-test/include/ps_query.inc +++ b/mysql-test/include/ps_query.inc @@ -52,7 +52,6 @@ execute stmt1; ##### parameter used for keyword like SELECT (must fail) set @arg00='SELECT' ; -# mysqltest gives no output for the next statement, Why ?? --error 1064 @arg00 a from t1 where a=1; --error 1064 diff --git a/mysql-test/include/show_msg.inc b/mysql-test/include/show_msg.inc new file mode 100755 index 00000000000..659dce14686 --- /dev/null +++ b/mysql-test/include/show_msg.inc @@ -0,0 +1,25 @@ +#### include/show_msg.inc +# +# This file writes the value set in @message into the +# a protocol file as part of executing a test sequence +# +# Usage: +# Add the following to any *.test file: +# : +# let $message= ; +# --source include/show_msg.inc +# : +# +# Attention: +# - Please do not write any spaces between $message and the "=", because the +# assignment will not work. +# - Be careful with single quotes. They must be escaped like "''" or "\'". +# +# "include/show_msg80.inc" contains a detailed description and examples. + +--disable_query_log +eval SET @utf8_message = CONVERT('$message' using utf8); +select @utf8_message as "" +union +select repeat(CONVERT('-' using utf8),char_length(@utf8_message)); +--enable_query_log diff --git a/mysql-test/include/show_msg80.inc b/mysql-test/include/show_msg80.inc new file mode 100755 index 00000000000..42fb35edbcc --- /dev/null +++ b/mysql-test/include/show_msg80.inc @@ -0,0 +1,118 @@ +#### include/show_msg80.inc +# +# This file writes the value set in @message into the a protocol file as part +# of executing a test sequence with a dash line that is fixed on 80 characters. +# +# This can be used in the case of long messages, multi line messages that +# exceed 80 or if an 80 char line is desired for short messages. +# +# Usage: +# Add the following to any *.test file: +# : +# let $message= ; +# --source include/show_msg80.inc +# : +# +# Attention: +# - Please do not write any spaces between $message and the "=", because the +# assignment will not work. +# - Be careful with single quotes within the value. They must be escaped like +# "''" or "\'". +# - Do not keep the value between single quotes. +# +# +# Content of "$message" and protocol output depending on the assignment: +# ---------------------------------------------------------------------- +# +# I is assumed, that the value is not kept between double quotes. +# +# first character after "$message=", +# where the content is not (space or tab) +# first character after beginning of the line, +# where the content is not (space or tab) +# last char before ";" +# | beginning or end of line +# +# script: let $message= | +# | | +# |................| +# | ; +# content: " +# ...." +# protocol output: || +# || +# |.....| +# || +# |--- 80 dashes ---| +# +# Attention: +# and set to characters like "-$#" which are also used +# to start comments, options and the names of mysqltest variables +# lead to syntax errors or mangled messages. +# +# +# Examples of messages: +# --------------------- +# +# Variant1 (ease of use): +# Several lines with indentation kept between double quotes +# script: |let $message= +# |" Testcase 3.1 : Ensure that Pi is not an| +# | integer number.| +# | Third line"; +# protocol: |" Testcase 3.1 : Ensure that Pi is not an| +# | integer number.| +# | Third line"| +# |------ 80 dashes ----| +# +# Please mention that +# - the '"' preserves the indentation. +# - it is easy to write the script lines to get a fine indentation, +# if the value starts at the beginning of a new line +# - the '"' is printed +# - there are the least or no problems with characters like "-#$" +# +# +# Variant 2 (grep the messages from the protocol is easy): +# Several lines with indentation + auxiliary character (".") +# at the (non tab or space) beginning of every message line +# script: |let $message= . Testcase 3.1 : Ensure that Pi is not an| +# | . integer number.| +# | . Third line; +# protocol: |. Testcase 3.1 : Ensure that Pi is not an| +# |. integer number.| +# |. Third line| +# |------ 80 dashes ----| +# Please mention that +# - the auxiliary character preserves the indentation. +# - it is easy to write the script lines to get a fine indentation +# - the auxiliary character is printed +# - it is recommended to use "." as auxiliary character +# - auxiliary characters like "-'$#" cause problems +# +# +# +# Bad variant1: Several lines with lost indentation +# script: |let $message= Here is message line 1 +# | message line 2; +# protocol: |Here is message line 1| +# |message line 2| +# |------ 80 dashes ----| +# Please mention, that the leading spaces of the message lines disappeared. +# +# Bad variant2: Several lines leading to a syntax error, because of "-" +# script: |let $message= - This is a message +# | - with a second and +# | - third line; +# protocol: | - third line;; +# |ERROR 42000: You have an error ... near '- third line' +# + several following errors +# +# + +--disable_query_log +eval SET @utf8_message = CONVERT('$message' using utf8); +select @utf8_message as "" +union +select repeat(CONVERT('-' using utf8),80); +--enable_query_log diff --git a/mysql-test/r/check.result b/mysql-test/r/check.result index ecaa13642bd..26dbc9e345c 100644 --- a/mysql-test/r/check.result +++ b/mysql-test/r/check.result @@ -1,6 +1,6 @@ drop table if exists t1; create table t1(n int not null, key(n), key(n), key(n), key(n)); - check table t1 extended; +check table t1 extended; insert into t1 values (200000); Table Op Msg_type Msg_text test.t1 check status OK diff --git a/mysql-test/r/connect.result b/mysql-test/r/connect.result index 68c86b80e60..b9c1e3e5542 100644 --- a/mysql-test/r/connect.result +++ b/mysql-test/r/connect.result @@ -18,6 +18,10 @@ time_zone_transition_type user show tables; Tables_in_test +connect(localhost,root,z,test2,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'root'@'localhost' (using password: YES) +connect(localhost,root,z,test,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'root'@'localhost' (using password: YES) grant ALL on *.* to test@localhost identified by "gambling"; grant ALL on *.* to test@127.0.0.1 identified by "gambling"; show tables; @@ -39,6 +43,14 @@ time_zone_transition_type user show tables; Tables_in_test +connect(localhost,test,,test2,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: NO) +connect(localhost,test,,"",MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: NO) +connect(localhost,test,zorro,test2,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: YES) +connect(localhost,test,zorro,test,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: YES) update mysql.user set password=old_password("gambling2") where user=_binary"test"; flush privileges; set password=""; @@ -64,6 +76,14 @@ time_zone_transition_type user show tables; Tables_in_test +connect(localhost,test,,test2,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: NO) +connect(localhost,test,,test,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: NO) +connect(localhost,test,zorro,test2,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: YES) +connect(localhost,test,zorro,test,MASTER_PORT,MASTER_SOCKET); +ERROR 28000: Access denied for user 'test'@'localhost' (using password: YES) delete from mysql.user where user=_binary"test"; flush privileges; create table t1 (id integer not null auto_increment primary key); diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result index 384bdc1214b..83b8b769f67 100644 --- a/mysql-test/r/flush.result +++ b/mysql-test/r/flush.result @@ -9,13 +9,13 @@ n flush tables with read lock; drop table t2; ERROR HY000: Table 't2' was locked with a READ lock and can't be updated - drop table t2; +drop table t2; unlock tables; create database mysqltest; create table mysqltest.t1(n int); insert into mysqltest.t1 values (23); flush tables with read lock; - drop database mysqltest; +drop database mysqltest; select * from mysqltest.t1; n 23 diff --git a/mysql-test/r/flush_block_commit.result b/mysql-test/r/flush_block_commit.result index 2e9f1920937..d5b10868358 100644 --- a/mysql-test/r/flush_block_commit.result +++ b/mysql-test/r/flush_block_commit.result @@ -5,7 +5,7 @@ insert into t1 values(1); flush tables with read lock; select * from t1; a - commit; +commit; select * from t1; a unlock tables; @@ -14,8 +14,8 @@ select * from t1 for update; a 1 begin; - select * from t1 for update; - flush tables with read lock; +select * from t1 for update; +flush tables with read lock; commit; a 1 diff --git a/mysql-test/r/func_misc.result b/mysql-test/r/func_misc.result index adf2035173f..246713489b4 100644 --- a/mysql-test/r/func_misc.result +++ b/mysql-test/r/func_misc.result @@ -69,7 +69,7 @@ FROM t1 WHERE conn = 'default'; IS_USED_LOCK('bug16501') = connection_id 1 - SELECT GET_LOCK('bug16501',600); +SELECT GET_LOCK('bug16501',600); SELECT IS_USED_LOCK('bug16501') = CONNECTION_ID(); IS_USED_LOCK('bug16501') = CONNECTION_ID() 1 diff --git a/mysql-test/r/grant2.result b/mysql-test/r/grant2.result index c047dc033c6..36d4e51119d 100644 --- a/mysql-test/r/grant2.result +++ b/mysql-test/r/grant2.result @@ -123,12 +123,12 @@ drop database mysqltest_1; set password = password("changed"); ERROR 42000: Access denied for user ''@'localhost' to database 'mysql' lock table mysql.user write; - flush privileges; - grant all on *.* to 'mysqltest_1'@'localhost'; +flush privileges; +grant all on *.* to 'mysqltest_1'@'localhost'; unlock tables; lock table mysql.user write; - set password for 'mysqltest_1'@'localhost' = password(''); - revoke all on *.* from 'mysqltest_1'@'localhost'; +set password for 'mysqltest_1'@'localhost' = password(''); +revoke all on *.* from 'mysqltest_1'@'localhost'; unlock tables; drop user 'mysqltest_1'@'localhost'; insert into mysql.user (user, host) values diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result index 9b0c6dbc263..e88d359e0ef 100644 --- a/mysql-test/r/handler.result +++ b/mysql-test/r/handler.result @@ -452,7 +452,7 @@ handler t1 read first; c1 1 send the below to another connection, do not wait for the result - optimize table t1; +optimize table t1; proceed with the normal connection handler t1 read next; c1 diff --git a/mysql-test/r/kill.result b/mysql-test/r/kill.result index eff59b102de..2a88f1ce3a8 100644 --- a/mysql-test/r/kill.result +++ b/mysql-test/r/kill.result @@ -24,7 +24,7 @@ create table t2 (id int unsigned not null); insert into t2 select id from t1; create table t3 (kill_id int); insert into t3 values(connection_id()); - select id from t1 where id in (select distinct id from t2); +select id from t1 where id in (select distinct id from t2); select ((@id := kill_id) - kill_id) from t3; ((@id := kill_id) - kill_id) 0 diff --git a/mysql-test/r/lock_multi.result b/mysql-test/r/lock_multi.result index 9eedbf50064..59b683b1917 100644 --- a/mysql-test/r/lock_multi.result +++ b/mysql-test/r/lock_multi.result @@ -2,8 +2,8 @@ drop table if exists t1,t2; create table t1(n int); insert into t1 values (1); lock tables t1 write; - update low_priority t1 set n = 4; - select n from t1; +update low_priority t1 set n = 4; +select n from t1; unlock tables; n 4 @@ -11,8 +11,8 @@ drop table t1; create table t1(n int); insert into t1 values (1); lock tables t1 read; - update low_priority t1 set n = 4; - select n from t1; +update low_priority t1 set n = 4; +select n from t1; unlock tables; n 1 @@ -23,7 +23,7 @@ insert into t1 values(1,1); insert into t1 values(2,2); insert into t2 values(1,2); lock table t1 read; - update t1,t2 set c=a where b=d; +update t1,t2 set c=a where b=d; select c from t2; c 2 @@ -32,7 +32,7 @@ drop table t2; create table t1 (a int); create table t2 (a int); lock table t1 write, t2 write; - insert t1 select * from t2; +insert t1 select * from t2; drop table t2; ERROR 42S02: Table 'test.t2' doesn't exist drop table t1; diff --git a/mysql-test/r/mix_innodb_myisam_binlog.result b/mysql-test/r/mix_innodb_myisam_binlog.result index 8cf99e8d623..f8de0336e63 100644 --- a/mysql-test/r/mix_innodb_myisam_binlog.result +++ b/mysql-test/r/mix_innodb_myisam_binlog.result @@ -193,7 +193,7 @@ select (@before:=unix_timestamp())*0; (@before:=unix_timestamp())*0 0 begin; - select * from t1 for update; +select * from t1 for update; insert into t2 values (20); ERROR HY000: Lock wait timeout exceeded; try restarting transaction select (@after:=unix_timestamp())*0; diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 091a3c0547d..7276397bdc7 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -16,7 +16,7 @@ otto mysqltest: At line 1: query 'select otto from (select 1 as otto) as t1' succeeded - should have failed with sqlstate 42S22... select friedrich from (select 1 as otto) as t1; ERROR 42S22: Unknown column 'friedrich' in 'field list' -mysqltest: At line 1: query 'select friedrich from (select 1 as otto) as t1' failed with wrong sqlstate 42S22 instead of 00000... +mysqltest: At line 1: query 'select friedrich from (select 1 as otto) as t1' failed with wrong sqlstate 42S22: 'Unknown column 'friedrich' in 'field list'', instead of 00000... select otto from (select 1 as otto) as t1; otto 1 @@ -133,8 +133,7 @@ ERROR 42S02: Table 'test.t1' doesn't exist select 1146 as "after_!errno_masked_error" ; after_!errno_masked_error 1146 -mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1000... -mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1000... +mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146: 'Table 'test.t1' doesn't exist', instead of 1000... garbage ; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 select 1064 as "after_--enable_abort_on_error" ; @@ -142,8 +141,7 @@ after_--enable_abort_on_error 1064 select 3 from t1 ; ERROR 42S02: Table 'test.t1' doesn't exist -mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146 instead of 1064... -mysqltest: At line 1: query 'select 3 from t1' failed: 1146: Table 'test.t1' doesn't exist +mysqltest: At line 1: query 'select 3 from t1' failed with wrong errno 1146: 'Table 'test.t1' doesn't exist', instead of 1064... hello hello ;;;;;;;; @@ -151,7 +149,24 @@ hello mysqltest: At line 1: End of line junk detected: "6" mysqltest: At line 1: End of line junk detected: "6" mysqltest: At line 1: Missing delimiter +mysqltest: At line 1: End of line junk detected: "sleep 7 +# Another comment +" mysqltest: At line 1: Extra delimiter ";" found +mysqltest: At line 1: Extra delimiter ";" found +mysqltest: At line 1: Missing argument(s) to 'error' +mysqltest: At line 1: Missing argument(s) to 'error' +mysqltest: At line 1: The sqlstate definition must start with an uppercase S +mysqltest: At line 1: The error name definition must start with an uppercase E +mysqltest: At line 1: Invalid argument to error: '9eeeee' - the errno may only consist of digits[0-9] +mysqltest: At line 1: Invalid argument to error: '1sssss' - the errno may only consist of digits[0-9] +mysqltest: At line 1: The sqlstate must be exactly 5 chars long +mysqltest: At line 1: The sqlstate may only consist of digits[0-9] and _uppercase_ letters +mysqltest: At line 1: The sqlstate must be exactly 5 chars long +mysqltest: At line 1: Not available in mysqltest for MySQL 4.1.22 +mysqltest: At line 1: Invalid argument to error: '999e9' - the errno may only consist of digits[0-9] +mysqltest: At line 1: Invalid argument to error: '9b' - the errno may only consist of digits[0-9] +mysqltest: At line 1: Too many errorcodes specified MySQL "MySQL" MySQL: The world''s most popular open source database @@ -166,8 +181,8 @@ source database - most popular open - source database - MySQL: The world''s --- most popular open --- source database +-- most popular +-- open source database # MySQL: The --world''s # most popular @@ -193,14 +208,20 @@ source database # source database -- MySQL: The -- world''s most --- popular open --- source database +-- popular +-- open source database # MySQL: The - world''s most -- popular open # source database -'$message' -"$message" +'# MySQL: The +- world''s most +-- popular open +# source database' +"# MySQL: The +- world''s most +-- popular open +# source database" hej hej hej @@ -209,21 +230,32 @@ hej a long variable content a long variable content -a long $where variable content +a long a long variable content variable content +a long \$where variable content +banana = banana +Not a banana: ba\$cat\$cat mysqltest: At line 1: Missing arguments to let mysqltest: At line 1: Missing variable name in let -mysqltest: At line 1: Variable name in hi=hi does not start with '$' mysqltest: At line 1: Missing assignment operator in let mysqltest: At line 1: Missing assignment operator in let -mysqltest: At line 1: Missing arguments to let +mysqltest: At line 1: Missing assignment operator in let +mysqltest: At line 1: Missing variable name in let mysqltest: At line 1: Missing variable name in let -mysqltest: At line 1: Variable name in =hi does not start with '$' mysqltest: At line 1: Missing assignment operator in let -mysqltest: At line 1: Missing file name in source +# Execute: --echo # success: $success +# success: 1 +# Execute: echo # success: $success ; +# success: 1 +# The next two variants work fine and expand the content of $success +# Execute: --echo $success +1 +# Execute: echo $success ; +1 +mysqltest: At line 1: Missing required argument 'filename' to command 'source' mysqltest: At line 1: Could not open file ./non_existingFile -mysqltest: In included file "./var/tmp/recursive.sql": At line 1: Source directives are nesting too deep -mysqltest: In included file "./var/tmp/error.sql": At line 1: query 'garbage ' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 +mysqltest: In included file "MYSQLTEST_VARDIR/tmp/recursive.sql": At line 1: Source directives are nesting too deep +mysqltest: In included file "MYSQLTEST_VARDIR/tmp/error.sql": At line 1: query 'garbage ' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'garbage' at line 1 2 = outer loop variable after while here is the sourced script @@ -288,8 +320,8 @@ mysqltest: At line 1: Invalid argument to real_sleep "abc" 101 hej 1 -mysqltest: At line 1: Missing arguments to inc -mysqltest: At line 1: First argument to inc must be a variable (start with $) +mysqltest: At line 1: Missing argument to inc +mysqltest: At line 1: The argument to inc must be a variable (start with $) mysqltest: At line 1: End of line junk detected: "1000" 4 4 @@ -298,27 +330,31 @@ mysqltest: At line 1: End of line junk detected: "1000" 99 hej -1 -mysqltest: At line 1: Missing arguments to dec -mysqltest: At line 1: First argument to dec must be a variable (start with $) +mysqltest: At line 1: Missing argument to dec +mysqltest: At line 1: The argument to dec must be a variable (start with $) mysqltest: At line 1: End of line junk detected: "1000" mysqltest: At line 1: Missing arguments to system, nothing to do! mysqltest: At line 1: Missing arguments to system, nothing to do! mysqltest: At line 1: system command 'false' failed +system command 'NonExistsinfComamdn 2> /dev/null' failed test test2 test3 test4 +Counter is greater than 0, (counter=10) +Counter is not 0, (counter=0) 1 -mysqltest: In included file "./include/mysqltest_while.inc": At line 64: Nesting too deeply +Testing while with not +mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest_while.inc": At line 64: Nesting too deeply mysqltest: At line 1: missing '(' in while mysqltest: At line 1: missing ')' in while mysqltest: At line 1: Missing '{' after while. Found "dec $i" mysqltest: At line 1: Stray '}' - end of block before beginning mysqltest: At line 1: Stray 'end' command - end of block before beginning -mysqltest: At line 1: query '' failed: 1065: Query was empty +mysqltest: At line 1: query '{' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '{' at line 1 mysqltest: At line 1: Missing '{' after while. Found "echo hej" mysqltest: At line 3: Missing end of block -mysqltest: At line 1: Missing newline between while and '{' +mysqltest: At line 3: Missing end of block mysqltest: At line 1: missing '(' in if mysqltest: At line 1: Stray 'end' command - end of block before beginning select "b" bs col1, "c" bs col2; @@ -331,6 +367,7 @@ mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_re mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a;' mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a' mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a ' +OK mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a b c' mysqltest: At line 1: Wrong number of arguments to replace_result in 'replace_result a b c ' select "a" as col1, "c" as col2; @@ -347,6 +384,18 @@ mysqltest: At line 1: Wrong column number to replace_column in 'replace_column 1 mysqltest: At line 1: Invalid integer argument "10!" mysqltest: At line 1: End of line junk detected: "!" mysqltest: At line 1: Invalid integer argument "a" +mysqltest: At line 1: Missing required argument 'connection name' to command 'connect' +mysqltest: At line 1: Missing required argument 'connection name' to command 'connect' +mysqltest: At line 1: Missing required argument 'host' to command 'connect' +mysqltest: At line 1: Missing required argument 'host' to command 'connect' +mysqltest: At line 1: query 'connect con2,localhost,root,,illegal_db' failed: 1049: Unknown database 'illegal_db' +mysqltest: At line 1: Illegal argument for port: 'illegal_port' +mysqltest: At line 1: Illegal option to connect: SMTP +OK +mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": At line 7: Connection limit exhausted, you can have max 128 connections +mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": At line 3: connection 'test_con1' not found in connection pool +mysqltest: In included file "MYSQLTEST_VARDIR/tmp/mysqltest.sql": At line 2: Connection test_con1 already exists +connect(localhost,root,,test,MASTER_PORT,MASTER_SOCKET); Output from mysqltest-x.inc Output from mysqltest-x.inc Output from mysqltest-x.inc @@ -358,3 +407,98 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp SELECT 1 as a; a 1 +select 1 as `a'b`, 2 as `a"b`; +a'b a"b +1 2 +select 'aaa\\','aa''a',"aa""a"; +aaa\ aa'a aa"a +aaa\ aa'a aa"a + +Here comes a message +-------------------- + +root@localhost +-------------- + +"Here comes a very very long message that + - is longer then 80 characters and + - consists of several lines" +-------------------------------------------------------------------------------- + +. Here comes a very very long message that +. - is longer then 80 characters and +. - consists of several lines +-------------------------------------------------------------------------------- +this will be executed +this will be executed +mysqltest: Result length mismatch +mysqltest: The test didn't produce any output +Failing multi statement query +mysqltest: At line 3: query 'create table t1 (a int primary key); +insert into t1 values (1); +select 'select-me'; +insertz 'error query'' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insertz 'error query'' at line 1 +drop table t1; +mysqltest: At line 3: query 'create table t1 (a int primary key); +insert into t1 values (1); +select 'select-me'; +insertz 'error query'' failed: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insertz 'error query'' at line 1 +drop table t1; +Multi statement using expected error +create table t1 (a int primary key); +insert into t1 values (1); +select 'select-me'; +insertz error query|||| +select-me +select-me +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insertz error query' at line 1 +drop table t1; +drop table t1; +sleep; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'sleep' at line 1 +sleep; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'sleep' at line 1 +; +ERROR 42000: Query was empty +select "b" as col1, "c" as col2; +col1 col2 +b c +select "b" as col1, "b" as col2, "c" as col3; +col1 col2 col3 +b b c +seled "b" bs col1, "d" bs col2; +col1 col2 +b d +select "raspberry and strawberry","blackberry","tomato"; +raspberry and strawberry blackberry tomato +raspberry and strawberry blackberry tomato +mysqltest: At line 1: Error parsing replace_regex "a" +mysqltest: At line 1: Error parsing replace_regex "a;" +mysqltest: At line 1: Error parsing replace_regex "a" +mysqltest: At line 1: Error parsing replace_regex "a " +mysqltest: At line 1: Error parsing replace_regex "a b" +mysqltest: At line 1: Error parsing replace_regex "/a b c" +mysqltest: At line 1: Error parsing replace_regex "/a /b c " +create table t1 (a int, b int); +insert into t1 values (1,3); +insert into t1 values (2,4); +select * from t1; +a D +1 1 +1 4 +drop table t1; +mysqltest: At line 1: Missing required argument 'filename' to command 'remove_file' +mysqltest: At line 1: Missing required argument 'filename' to command 'write_file' +mysqltest: At line 1: End of file encountered before 'EOF' delimiter was found +mysqltest: At line 1: End of line junk detected: "write_file filename "; +" +mysqltest: At line 1: Missing required argument 'filename' to command 'file_exists' +mysqltest: At line 1: Missing required argument 'from_file' to command 'copy_file' +mysqltest: At line 1: Missing required argument 'to_file' to command 'copy_file' +hello +hello +hello +mysqltest: At line 1: Max delimiter length(16) exceeded +hello +hello +End of tests diff --git a/mysql-test/r/ps_2myisam.result b/mysql-test/r/ps_2myisam.result index 4b655cfb854..771245c3713 100644 --- a/mysql-test/r/ps_2myisam.result +++ b/mysql-test/r/ps_2myisam.result @@ -85,6 +85,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? a from t1 where a=1' at line 1 set @arg00=1 ; diff --git a/mysql-test/r/ps_3innodb.result b/mysql-test/r/ps_3innodb.result index 4d2a62887d6..8435bb348f4 100644 --- a/mysql-test/r/ps_3innodb.result +++ b/mysql-test/r/ps_3innodb.result @@ -85,6 +85,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? a from t1 where a=1' at line 1 set @arg00=1 ; diff --git a/mysql-test/r/ps_4heap.result b/mysql-test/r/ps_4heap.result index a4919b664c4..d6876825aa9 100644 --- a/mysql-test/r/ps_4heap.result +++ b/mysql-test/r/ps_4heap.result @@ -86,6 +86,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? a from t1 where a=1' at line 1 set @arg00=1 ; diff --git a/mysql-test/r/ps_5merge.result b/mysql-test/r/ps_5merge.result index f98cc1b3cdf..f2d459c6769 100644 --- a/mysql-test/r/ps_5merge.result +++ b/mysql-test/r/ps_5merge.result @@ -128,6 +128,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? a from t1 where a=1' at line 1 set @arg00=1 ; @@ -3142,6 +3144,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? a from t1 where a=1' at line 1 set @arg00=1 ; diff --git a/mysql-test/r/ps_6bdb.result b/mysql-test/r/ps_6bdb.result index acd7f45de95..3e16923c46f 100644 --- a/mysql-test/r/ps_6bdb.result +++ b/mysql-test/r/ps_6bdb.result @@ -85,6 +85,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? a from t1 where a=1' at line 1 set @arg00=1 ; diff --git a/mysql-test/r/ps_7ndb.result b/mysql-test/r/ps_7ndb.result index 27a1ea0925d..baceb1e4a9e 100644 --- a/mysql-test/r/ps_7ndb.result +++ b/mysql-test/r/ps_7ndb.result @@ -85,6 +85,8 @@ c1 c2 c3 c4 c5 c6 c7 c8 c9 c10 c11 c12 c13 c14 c15 c16 c17 c18 c19 c20 c21 c22 c 1 1 1 1 1 1 1 1 1 1 1.0000 1.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 1 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext one monday 9 9 9 9 9 9 9 9 9 9 9.0000 9.0000 2004-02-29 2004-02-29 11:11:11 2004-02-29 11:11:11 11:11:11 2004 1 0 a 123456789a 123456789a123456789b123456789c tinyblob tinytext blob text mediumblob mediumtext longblob longtext two tuesday set @arg00='SELECT' ; +@arg00 a from t1 where a=1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '@arg00 a from t1 where a=1' at line 1 prepare stmt1 from ' ? a from t1 where a=1 '; ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '? a from t1 where a=1' at line 1 set @arg00=1 ; diff --git a/mysql-test/r/rename.result b/mysql-test/r/rename.result index 76c0f4422fe..964babb1228 100644 --- a/mysql-test/r/rename.result +++ b/mysql-test/r/rename.result @@ -43,7 +43,7 @@ Note 1051 Unknown table 't4' CREATE TABLE t1 (a int); CREATE TABLE t3 (a int); FLUSH TABLES WITH READ LOCK; - RENAME TABLE t1 TO t2, t3 to t4; +RENAME TABLE t1 TO t2, t3 to t4; show tables; Tables_in_test t1 diff --git a/mysql-test/r/rpl000001.result b/mysql-test/r/rpl000001.result index eef986d8f8c..1bce3b1b235 100644 --- a/mysql-test/r/rpl000001.result +++ b/mysql-test/r/rpl000001.result @@ -59,7 +59,7 @@ create table t2(id int); insert into t2 values(connection_id()); create temporary table t3(n int); insert into t3 select get_lock('crash_lock%20C', 1) from t2; - update t1 set n = n + get_lock('crash_lock%20C', 2); +update t1 set n = n + get_lock('crash_lock%20C', 2); select (@id := id) - id from t2; (@id := id) - id 0 diff --git a/mysql-test/r/rpl000018.result b/mysql-test/r/rpl000018.result deleted file mode 100644 index b71f6492b97..00000000000 --- a/mysql-test/r/rpl000018.result +++ /dev/null @@ -1,14 +0,0 @@ -reset master; -reset slave; -start slave; -show binary logs; -Log_name -master-bin.000001 -master-bin.000002 -drop table if exists t1; -create table t1(n int); -insert into t1 values (3351); -select * from t1; -n -3351 -drop table t1; diff --git a/mysql-test/r/rpl_chain_temp_table.result b/mysql-test/r/rpl_chain_temp_table.result deleted file mode 100644 index 5ece80565c7..00000000000 --- a/mysql-test/r/rpl_chain_temp_table.result +++ /dev/null @@ -1,30 +0,0 @@ -slave stop; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -reset master; -reset slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -slave start; -reset master; -change master to master_host='127.0.0.1',master_port=9307, master_user='root'; -start slave; -create temporary table t1 (a int); -create temporary table t1 (a int); -show status like 'slave_open_temp_tables'; -Variable_name Value -Slave_open_temp_tables 2 -create temporary table t1 (a int); -create temporary table t1 (a int); -show status like 'slave_open_temp_tables'; -Variable_name Value -Slave_open_temp_tables 4 -stop slave; -insert into t1 values(1); -create table t2 as select * from t1; -start slave; -show status like 'slave_open_temp_tables'; -Variable_name Value -Slave_open_temp_tables 4 -select * from t2; -a -1 -drop table t2; diff --git a/mysql-test/r/rpl_error_ignored_table.result b/mysql-test/r/rpl_error_ignored_table.result index 4a562dbfc70..789ca72cd61 100644 --- a/mysql-test/r/rpl_error_ignored_table.result +++ b/mysql-test/r/rpl_error_ignored_table.result @@ -20,7 +20,7 @@ create table t2 (a int primary key); insert into t2 values(1); create table t3 (id int); insert into t3 values(connection_id()); - update t2 set a = a + 1 + get_lock('crash_lock%20C', 10); +update t2 set a = a + 1 + get_lock('crash_lock%20C', 10); select (@id := id) - id from t3; (@id := id) - id 0 diff --git a/mysql-test/r/rpl_failsafe.result b/mysql-test/r/rpl_failsafe.result deleted file mode 100644 index 956555f9318..00000000000 --- a/mysql-test/r/rpl_failsafe.result +++ /dev/null @@ -1,34 +0,0 @@ -stop slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -reset master; -reset slave; -drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; -start slave; -show variables like 'rpl_recovery_rank'; -Variable_name Value -rpl_recovery_rank 1 -show status like 'Rpl_status'; -Variable_name Value -Rpl_status AUTH_MASTER -create table t1(n int); -drop table t1; -show variables like 'rpl_recovery_rank'; -Variable_name Value -rpl_recovery_rank 2 -show status like 'Rpl_status'; -Variable_name Value -Rpl_status ACTIVE_SLAVE -start slave; -show variables like 'rpl_recovery_rank'; -Variable_name Value -rpl_recovery_rank 3 -show status like 'Rpl_status'; -Variable_name Value -Rpl_status ACTIVE_SLAVE -start slave; -show variables like 'rpl_recovery_rank'; -Variable_name Value -rpl_recovery_rank 4 -show status like 'Rpl_status'; -Variable_name Value -Rpl_status ACTIVE_SLAVE diff --git a/mysql-test/r/rpl_heap.result b/mysql-test/r/rpl_heap.result deleted file mode 100644 index 1facbcb7676..00000000000 --- a/mysql-test/r/rpl_heap.result +++ /dev/null @@ -1,29 +0,0 @@ -reset master; -drop table if exists t1; -create table t1 type=HEAP select 10 as a; -insert into t1 values(11); -show binlog events from 79; -Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.001 79 Query 1 79 use `test`; create table t1 type=HEAP select 10 as a -master-bin.001 154 Query 1 154 use `test`; insert into t1 values(11) -reset slave; -start slave; -show create table t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `a` bigint(2) NOT NULL default '0' -) TYPE=HEAP -select * from t1; -a -10 -11 -select * from t1; -a -select * from t1 limit 10; -a -show binlog events in 'master-bin.002' from 79; -Log_name Pos Event_type Server_id Orig_log_pos Info -master-bin.002 79 Query 1 79 use `test`; DELETE FROM `test`.`t1` -select * from t1; -a -drop table t1; diff --git a/mysql-test/r/rpl_master_pos_wait.result b/mysql-test/r/rpl_master_pos_wait.result index e92d1ffa361..84f2b0bd91e 100644 --- a/mysql-test/r/rpl_master_pos_wait.result +++ b/mysql-test/r/rpl_master_pos_wait.result @@ -12,7 +12,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: Note 1003 select sql_no_cache master_pos_wait(_latin1'master-bin.999999',0,2) AS `master_pos_wait('master-bin.999999',0,2)` - select master_pos_wait('master-bin.999999',0); +select master_pos_wait('master-bin.999999',0); stop slave sql_thread; master_pos_wait('master-bin.999999',0) NULL diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index f5abc4ed42a..84b5a42d173 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -2697,8 +2697,7 @@ select (1,2,3) = (select * from t1); ERROR 21000: Operand should contain 3 column(s) select (select * from t1) = (1,2,3); ERROR 21000: Operand should contain 2 column(s) -drop table t1 -#; +drop table t1; CREATE TABLE `t1` ( `itemid` bigint(20) unsigned NOT NULL auto_increment, `sessionid` bigint(20) unsigned default NULL, diff --git a/mysql-test/r/synchronization.result b/mysql-test/r/synchronization.result index ad9443c86da..8b243fe29b2 100644 --- a/mysql-test/r/synchronization.result +++ b/mysql-test/r/synchronization.result @@ -1,5 +1,5 @@ CREATE TABLE t1 (x1 int); - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -7,7 +7,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -15,7 +15,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -23,7 +23,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -31,7 +31,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -39,7 +39,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -47,7 +47,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -55,7 +55,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -63,7 +63,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -71,7 +71,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -79,7 +79,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -87,7 +87,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -95,7 +95,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -103,7 +103,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -111,7 +111,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -119,7 +119,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -127,7 +127,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -135,7 +135,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -143,7 +143,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x1 x2 int; +ALTER TABLE t1 CHANGE x1 x2 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table @@ -151,7 +151,7 @@ t2 CREATE TABLE `t2` ( `xx` int(11) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t2; - ALTER TABLE t1 CHANGE x2 x1 int; +ALTER TABLE t1 CHANGE x2 x1 int; CREATE TABLE t2 LIKE t1; SHOW CREATE TABLE t2; Table Create Table diff --git a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result index 6b4b54fbb66..977377c0bc6 100644 --- a/mysql-test/r/type_blob.result +++ b/mysql-test/r/type_blob.result @@ -24,8 +24,7 @@ t3 CREATE TABLE `t3` ( `a` mediumtext, `b` mediumblob ) ENGINE=MyISAM DEFAULT CHARSET=latin1 -drop table t1,t2,t3 -#; +drop table t1,t2,t3; CREATE TABLE t1 (a char(257) default "hello"); ERROR 42000: Column length too big for column 'a' (max = 255); use BLOB or TEXT instead CREATE TABLE t2 (a blob default "hello"); diff --git a/mysql-test/t/connect.test b/mysql-test/t/connect.test index ff15d74e5ac..89e34f0c8e0 100644 --- a/mysql-test/t/connect.test +++ b/mysql-test/t/connect.test @@ -1,7 +1,6 @@ # This test is to check various cases of connections -# with right and wrong password, with and without database -# Unfortunately the check is incomplete as we can't handle errors on connect -# Also we can't connect without database +# with right and wrong password, with and without database +# Unfortunately the check is incomplete as we can't connect without database # This test makes no sense with the embedded server --source include/not_embedded.inc @@ -10,69 +9,73 @@ drop table if exists t1,t2; --enable_warnings + #connect (con1,localhost,root,,""); #show tables; connect (con1,localhost,root,,mysql); show tables; -connect (con1,localhost,root,,test); +connect (con2,localhost,root,,test); show tables; -# Re enable this one day if error handling on connect will take place - -#connect (con1,localhost,root,z,test2); -#--error 1045 -#connect (con1,localhost,root,z,); -#--error 1045 +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,root,z,test2); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,root,z,); grant ALL on *.* to test@localhost identified by "gambling"; grant ALL on *.* to test@127.0.0.1 identified by "gambling"; # Now check this user with different databases - #connect (con1,localhost,test,gambling,""); #show tables; -connect (con1,localhost,test,gambling,mysql); +connect (con3,localhost,test,gambling,mysql); show tables; -connect (con1,localhost,test,gambling,test); +connect (con4,localhost,test,gambling,test); show tables; -# Re enable this one day if error handling on connect will take place - -#connect (con1,localhost,test,,test2); -#--error 1045 -#connect (con1,localhost,test,,""); -#--error 1045 -#connect (con1,localhost,test,zorro,test2); -#--error 1045 -#connect (con1,localhost,test,zorro,); -#--error 1045 +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,,test2); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,,""); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,zorro,test2); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,zorro,); # check if old password version also works update mysql.user set password=old_password("gambling2") where user=_binary"test"; flush privileges; -#connect (con1,localhost,test,gambling2,""); -#show tables; -connect (con1,localhost,test,gambling2,mysql); +connect (con10,localhost,test,gambling2,); +connect (con5,localhost,test,gambling2,mysql); +connection con5; set password=""; --error 1105 set password='gambling3'; set password=old_password('gambling3'); show tables; -connect (con1,localhost,test,gambling3,test); +connect (con6,localhost,test,gambling3,test); show tables; -# Re enable this one day if error handling on connect will take place - -#connect (con1,localhost,test,,test2); -#--error 1045 -#connect (con1,localhost,test,,); -#--error 1045 -#connect (con1,localhost,test,zorro,test2); -#--error 1045 -#connect (con1,localhost,test,zorro,); -#--error 1045 +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,,test2); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,,); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,zorro,test2); +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--error 1045 +connect (fail_con,localhost,test,zorro,); # remove user 'test' so that other tests which may use 'test' @@ -84,13 +87,13 @@ flush privileges; # # Bug#12517: Clear user variables and replication events before # closing temp tables in thread cleanup. -connect (con2,localhost,root,,test); -connection con2; +connect (con7,localhost,root,,test); +connection con7; 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; +disconnect con7; --sleep 5 connection default; drop table t1; diff --git a/mysql-test/t/init_file.test b/mysql-test/t/init_file.test index de6aca455bd..bbe0c4ff884 100644 --- a/mysql-test/t/init_file.test +++ b/mysql-test/t/init_file.test @@ -4,6 +4,7 @@ # # See mysql-test/std_data/init_file.dat and # mysql-test/t/init_file-master.opt for the actual test -# +# -# End of 4.1 tests +--echo ok +--echo End of 4.1 tests diff --git a/mysql-test/t/mysql_client_test.test b/mysql-test/t/mysql_client_test.test index 1225bf73009..2677e470289 100644 --- a/mysql-test/t/mysql_client_test.test +++ b/mysql-test/t/mysql_client_test.test @@ -8,8 +8,8 @@ # server or run mysql-test-run --debug mysql_client_test and check # var/log/mysql_client_test.trace ---disable_result_log ---exec echo $MYSQL_CLIENT_TEST --getopt-ll-test=25600M ---exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M +--exec echo "$MYSQL_CLIENT_TEST --getopt-ll-test=25600M" > $MYSQLTEST_VARDIR/log/mysql_client_test.log 2>&1 +--exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >> $MYSQLTEST_VARDIR/log/mysql_client_test.log 2>&1 # End of 4.1 tests +echo ok; diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index a15a143e9f4..5b0df28981f 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -1,3 +1,4 @@ +# This test should work in embedded server after mysqltest is fixed -- source include/not_embedded.inc # ============================================================================ @@ -26,7 +27,7 @@ # ---------------------------------------------------------------------------- # $mysql_errno contains the return code of the last command -# send to the server. +# sent to the server. # ---------------------------------------------------------------------------- # get $mysql_errno before the first statement # $mysql_errno should be -1 @@ -49,7 +50,7 @@ select otto from (select 1 as otto) as t1; # ---------------------------------------------------------------------------- # Negative case(statement): -# The dervied table t1 does not contain a column named 'friedrich' . +# The derived table t1 does not contain a column named 'friedrich' . # --> ERROR 42S22: Unknown column 'friedrich' in 'field list and # --> 1054: Unknown column 'friedrich' in 'field list' # ---------------------------------------------------------------------------- @@ -67,7 +68,7 @@ select friedrich from (select 1 as otto) as t1; # The following unmasked unsuccessful statement must give # 1. mysqltest gives a 'failed' # 2. does not produce a r/.reject file !!! -# PLEASE uncomment it and check it's effect +# PLEASE uncomment it and check its effect #select friedrich from (select 1 as otto) as t1; @@ -113,7 +114,7 @@ select friedrich from (select 1 as otto) as t1; # test cases for $mysql_errno # # $mysql_errno is a builtin variable of mysqltest and contains the return code -# of the last command send to the server. +# of the last command sent to the server. # # The following test cases often initialize $mysql_errno to 1064 by # a command with wrong syntax. @@ -216,7 +217,7 @@ garbage ; execute stmt; eval select $mysql_errno as "after_successful_execute" ; -# failing execute (table dropped) +# failing execute (table has been dropped) drop table t1; --error 1064 garbage ; @@ -248,8 +249,8 @@ eval select $mysql_errno as "after_failing_deallocate" ; # ---------------------------------------------------------------------------- # test cases for "--disable_abort_on_error" # -# "--disable_abort_on_error" switches the abort of mysqltest -# after "unmasked" failing statements off. +# "--disable_abort_on_error" switches off the abort of mysqltest +# after "unmasked" failing statements. # # The default is "--enable_abort_on_error". # @@ -257,13 +258,13 @@ eval select $mysql_errno as "after_failing_deallocate" ; # --error and --error # in the line before the failing statement. # -# There are some additional test case for $mysql_errno +# There are some additional test cases for $mysql_errno # because "--disable_abort_on_error" enables a new situation. # Example: "unmasked" statement fails + analysis of $mysql_errno # ---------------------------------------------------------------------------- # ---------------------------------------------------------------------------- -# Switch the abort on error off and check the effect on $mysql_errno +# Switch off the abort on error and check the effect on $mysql_errno # ---------------------------------------------------------------------------- --error 1064 garbage ; @@ -316,7 +317,6 @@ select 3 from t1 ; # #select 3 from t1 ; -# End of 4.1 tests --error 1 --exec echo "disable_abort_on_error; enable_abort_on_error; error 1064; select 3 from t1; select 3 from t1;" | $MYSQL_TEST 2>&1 @@ -344,7 +344,7 @@ select 3 from t1 ; # ---------------------------------------------------------------------------- # Test detect end of line "junk" -# Most likely causes by a missing delimiter +# Most likely caused by a missing delimiter # ---------------------------------------------------------------------------- # Too many parameters to function @@ -359,23 +359,95 @@ select 3 from t1 ; # Missing delimiter # The comment will be "sucked into" the sleep command since # delimiter is missing until after "show status" ---system echo "sleep 4" > var/log/mysqltest.sql ---system echo "# A comment" >> var/log/mysqltest.sql ---system echo "show status;" >> var/log/mysqltest.sql +--system echo "sleep 4" > $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo "# A comment" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo "show status;" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql --error 1 ---exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 + +# +# Missing delimiter until eof +# The comment will be "sucked into" the sleep command since +# delimiter is missing +--system echo "sleep 7" > $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo "# Another comment" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--error 1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 # # Extra delimiter # --error 1 --exec echo "--sleep 4;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--disable_query_log;" | $MYSQL_TEST 2>&1 # Allow trailing # comment --sleep 1 # Wait for insert delayed to be executed. --sleep 1 # Wait for insert delayed to be executed. +# ---------------------------------------------------------------------------- +# Test error +# ---------------------------------------------------------------------------- + +# Missing argument +--error 1 +--exec echo "error;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--error" | $MYSQL_TEST 2>&1 + +# First char must be uppercase 'S' or 'E' or [0-9] +--error 1 +--exec echo "--error s99999" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--error e99999" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--error 9eeeee" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--error 1sssss" | $MYSQL_TEST 2>&1 + +# First char 'S' but too long +--error 1 +--exec echo "--error S999999" | $MYSQL_TEST 2>&1 + +# First char 'S' but lowercase char found +--error 1 +--exec echo "--error S99a99" | $MYSQL_TEST 2>&1 + +# First char 'S' but too short +--error 1 +--exec echo "--error S9999" | $MYSQL_TEST 2>&1 + +# First char 'E' but not found in error array +--error 1 +--exec echo "--error E9999" | $MYSQL_TEST 2>&1 + +# First char [0-9] but contains chars +--error 1 +--exec echo "--error 999e9" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--error 9b" | $MYSQL_TEST 2>&1 + +# Multiple errorcodes separated by ',' +--error 1,1,1,1 +#--error 9,ER_PARSE_ERROR +#--error ER_PARSE_ERROR +#--error 9,ER_PARSE_ERROR,9,ER_PARSE_ERROR +#--error 9, ER_PARSE_ERROR, 9, ER_PARSE_ERROR +#--error 9,S00000,9,ER_PARSE_ERROR +#--error 9,S00000,9,ER_PARSE_ERROR,ER_PARSE_ERROR,ER_PARSE_ERROR,9,10,11,12 +--error 9,S00000,9 +--error 9,S00000,9,9,10,11,12 +--error 9 ,10 +--error 9 , 10 +--error 9 , 10 +--error 9 , 10 + +# Too many errorcodes specified +--error 1 +--exec echo "--error 1,2,3,4,5,6,7,8,9,10,11" | $MYSQL_TEST 2>&1 + # ---------------------------------------------------------------------------- # Test echo command @@ -399,8 +471,8 @@ echo - MySQL: The world''s - source database; echo - MySQL: The world''s --- most popular open --- source database; +-- most popular +-- open source database; echo # MySQL: The --world''s @@ -419,7 +491,7 @@ echo ; # Illegal use of echo --error 1 ---exec echo "echo $;" | $MYSQL_TEST 2>&1 +--exec echo "echo \$;" | $MYSQL_TEST 2>&1 # ---------------------------------------------------------------------------- @@ -457,8 +529,8 @@ echo $message; let $message= -- MySQL: The -- world''s most --- popular open --- source database; +-- popular +-- open source database; echo $message; let $message= # MySQL: The @@ -495,9 +567,21 @@ echo $where2; let $where3=a long $where variable content; echo $where3; +let $where3=a long \\\$where variable content; +echo $where3; + let $novar1= $novar2; echo $novar1; +let $cat=na; +let $cat=ba$cat$cat; +echo banana = $cat; + +# ba\$cat\$cat should have been sufficient. +# ba\\\$cat\\\$cat -> ba\$cat\$cat -> ba$cat$cat -> banana +# Magnus' upcoming patch will fix the missing second interpretation. +let $cat=ba\\\$cat\\\$cat; +echo Not a banana: $cat; # Test illegal uses of let @@ -506,22 +590,19 @@ echo $novar1; --exec echo "let ;" | $MYSQL_TEST 2>&1 --error 1 ---exec echo "let $=hi;" | $MYSQL_TEST 2>&1 +--exec echo "let \$=hi;" | $MYSQL_TEST 2>&1 --error 1 ---exec echo "let hi=hi;" | $MYSQL_TEST 2>&1 +--exec echo "let \$1 hi;" | $MYSQL_TEST 2>&1 --error 1 ---exec echo "let $1 hi;" | $MYSQL_TEST 2>&1 +--exec echo "let \$m hi;" | $MYSQL_TEST 2>&1 --error 1 ---exec echo "let $m hi;" | $MYSQL_TEST 2>&1 +--exec echo "let \$hi;" | $MYSQL_TEST 2>&1 --error 1 ---exec echo "let $hi;" | $MYSQL_TEST 2>&1 - ---error 1 ---exec echo "let $ hi;" | $MYSQL_TEST 2>&1 +--exec echo "let \$ hi;" | $MYSQL_TEST 2>&1 --error 1 --exec echo "let =hi;" | $MYSQL_TEST 2>&1 @@ -529,6 +610,55 @@ echo $novar1; --error 1 --exec echo "let hi;" | $MYSQL_TEST 2>&1 +# More advanced test for bug#17280 +let $success= 1; +--echo # Execute: --echo # success: \$success +--echo # success: $success +--echo # Execute: echo # success: \$success ; +echo # success: $success ; + +--echo # The next two variants work fine and expand the content of \$success +--echo # Execute: --echo \$success +--echo $success +--echo # Execute: echo \$success ; +echo $success ; + +# ---------------------------------------------------------------------------- +# Test to assign let from query +# let $=``; +# ---------------------------------------------------------------------------- +--disable_parsing +echo var1; +let $var1= `select "hi" as "Col", 1 as "Column1", "hi there" as Col3`; +echo $var1; +echo $var1_Col; +echo $var1_Column1; +echo $var1_Col3; + +echo var2; +let $var2= `select 2 as "Column num 2"`; +echo $var2; +echo $var2_Column num 2; +echo $var2_Column; + +echo var2 again; +let $var2= `select 2 as "Column num 2"`; +echo $var2; +echo $var2_Column num 2; +echo $var2_Column_num_2; +echo $var2_Column; + +echo var3 two columns with same name; +let $var3= `select 1 as "Col", 2 as "Col", 3 as "var3"`; +echo $var3; +echo $var3_Col; +echo $var3_Col; +echo $var3_var3; + +#echo failing query in let; +#--error 1 +#--exec echo "let $var2= `failing query;`" | $MYSQL_TEST 2>&1 +--enable_parsing # ---------------------------------------------------------------------------- # Test source command # ---------------------------------------------------------------------------- @@ -538,29 +668,36 @@ echo $novar1; --error 1 --exec echo "source ;" | $MYSQL_TEST 2>&1 +# Fix win paths +--replace_result \\ / +# Source a nonexisting file --error 1 --exec echo "source non_existingFile;" | $MYSQL_TEST 2>&1 # Too many source ---exec echo "source var/tmp/recursive.sql;" > var/tmp/recursive.sql +--exec echo "source $MYSQLTEST_VARDIR/tmp/recursive.sql;" > $MYSQLTEST_VARDIR/tmp/recursive.sql +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --error 1 ---exec echo "source var/tmp/recursive.sql;" | $MYSQL_TEST 2>&1 +--exec echo "source $MYSQLTEST_VARDIR/tmp/recursive.sql;" | $MYSQL_TEST 2>&1 # Source a file with error ---exec echo "garbage ;" > var/tmp/error.sql +--exec echo "garbage ;" > $MYSQLTEST_VARDIR/tmp/error.sql +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --error 1 ---exec echo "source var/tmp/error.sql;" | $MYSQL_TEST 2>&1 +--exec echo "source $MYSQLTEST_VARDIR/tmp/error.sql;" | $MYSQL_TEST 2>&1 # Test execution of source in a while loop ---exec echo "echo here is the sourced script;" > var/tmp/sourced.sql +--write_file $MYSQLTEST_VARDIR/tmp/sourced.inc +echo here is the sourced script; +EOF --disable_query_log let $outer= 2; # Number of outer loops while ($outer) { eval SELECT '$outer = outer loop variable after while' AS ""; - --source var/tmp/sourced.sql + --source $MYSQLTEST_VARDIR/tmp/sourced.inc eval SELECT '$outer = outer loop variable before dec' AS ""; dec $outer; @@ -581,7 +718,6 @@ while ($outer) # Test execution of source in a while loop ---exec echo "--source var/tmp/sourced.sql" > var/tmp/sourced1.sql --disable_abort_on_error # Sourcing of a file within while loop, sourced file will # source other file @@ -589,11 +725,12 @@ let $num= 9; while ($num) { SELECT 'In loop' AS ""; - --source var/tmp/sourced1.sql + --source $MYSQLTEST_VARDIR/tmp/sourced.inc dec $num; } --enable_abort_on_error --enable_query_log +--remove_file $MYSQLTEST_VARDIR/tmp/sourced.inc # ---------------------------------------------------------------------------- # Test sleep command @@ -683,7 +820,7 @@ system echo "hej" > /dev/null; --exec echo "system false;" | $MYSQL_TEST 2>&1 --disable_abort_on_error -system NonExistsinfComamdn; +system NonExistsinfComamdn 2> /dev/null; --enable_abort_on_error @@ -700,6 +837,30 @@ echo test3stop --delimiter ; echo test4; + +# ---------------------------------------------------------------------------- +# Test if +# ---------------------------------------------------------------------------- + +let $counter=10; +if ($counter) +{ + echo Counter is greater than 0, (counter=10); +} +if (!$counter) +{ + echo Counter is not 0, (counter=10); +} +let $counter=0; +if ($counter) +{ + echo Counter is greater than 0, (counter=0); +} +if (!$counter) +{ + echo Counter is not 0, (counter=0); +} + # ---------------------------------------------------------------------------- # Test while, { and } # ---------------------------------------------------------------------------- @@ -713,11 +874,158 @@ while ($i) # One liner #let $i=1;while ($i){echo $i;dec $i;} - +let $i=0; +while (!$i) +{ + echo Testing while with not; + inc $i; +} # Exceed max nesting level +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest_while.inc +let $1 = 10; +while ($1) +{ +while ($1) +{ +while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + while ($1) +{ + echo $1; + dec $1; +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +} +EOF +# Fix win path +--replace_result \\ / $MYSQLTEST_VARDIR MYSQLTEST_VARDIR --error 1 ---exec echo "source include/mysqltest_while.inc;" | $MYSQL_TEST 2>&1 +--exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest_while.inc;" | $MYSQL_TEST 2>&1 +--remove_file $MYSQLTEST_VARDIR/tmp/mysqltest_while.inc --error 1 --exec echo "while \$i;" | $MYSQL_TEST 2>&1 --error 1 @@ -731,20 +1039,20 @@ while ($i) --error 1 --exec echo "{;" | $MYSQL_TEST 2>&1 ---system echo "while (0)" > var/log/mysqltest.sql ---system echo "echo hej;" >> var/log/mysqltest.sql +--system echo "while (0)" > $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo "echo hej;" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql --error 1 ---exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 ---system echo "while (0)" > var/log/mysqltest.sql ---system echo "{echo hej;" >> var/log/mysqltest.sql +--system echo "while (0)" > $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo "{echo hej;" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql --error 1 ---exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 ---system echo "while (0){" > var/log/mysqltest.sql ---system echo "echo hej;" >> var/log/mysqltest.sql +--system echo "while (0){" > $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo "echo hej;" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql --error 1 ---exec $MYSQL_TEST < var/log/mysqltest.sql 2>&1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 # ---------------------------------------------------------------------------- # Test error messages returned from comments starting with a command @@ -772,7 +1080,7 @@ select "a" as col1, "c" as col2; --exec echo "replace_result a;" | $MYSQL_TEST 2>&1 --error 1 --exec echo "replace_result a ;" | $MYSQL_TEST 2>&1 ---exec echo "replace_result a b;" | $MYSQL_TEST 2>&1 +--exec echo "replace_result a b; echo OK;" | $MYSQL_TEST 2>&1 --error 1 --exec echo "--replace_result a b c" | $MYSQL_TEST 2>&1 --error 1 @@ -809,6 +1117,71 @@ select "a" as col1, "c" as col2; --error 1 --exec echo "save_master_pos; sync_with_master a;" | $MYSQL_TEST 2>&1 +# ---------------------------------------------------------------------------- +# Test connect +# ---------------------------------------------------------------------------- + +--error 1 +--exec echo "connect;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "connect ();" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "connect (con2);" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "connect (con2,);" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "connect (con2,localhost,root,,illegal_db);" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "connect (con1,localhost,root,,,illegal_port,);" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "connect (con1,localhost,root,,,,,SMTP POP);" | $MYSQL_TEST 2>&1 + +# Repeat connect/disconnect +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +let $i=100; +while ($i) +{ + connect (test_con1,localhost,root,,); + disconnect test_con1; + dec $i; +} +EOF +--exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest.sql; echo OK;" | $MYSQL_TEST 2>&1 + +# Repeat connect/disconnect, exceed max number of connections +--system echo "let \$i=200;" > $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo "while (\$i)" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo "{" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo " connect (test_con1,localhost,root,,); " >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo " disconnect test_con1; " >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo " dec \$i; " >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo "}" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--error 1 +--exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest.sql;" | $MYSQL_TEST 2>&1 + +# Select disconnected connection +--system echo "connect (test_con1,localhost,root,,);" > $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo "disconnect test_con1; " >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo "connection test_con1;" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--error 1 +--exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest.sql;" | $MYSQL_TEST 2>&1 + +# Connection name already used +--system echo "connect (test_con1,localhost,root,,);" > $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--system echo "connect (test_con1,localhost,root,,);" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--error 1 +--exec echo "source $MYSQLTEST_VARDIR/tmp/mysqltest.sql;" | $MYSQL_TEST 2>&1 + +# connect when "disable_abort_on_error" caused "connection not found" +--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT +--disable_abort_on_error +connect (con1,localhost,root,,); +connection default; +connection con1; +--enable_abort_on_error # ---------------------------------------------------------------------------- # Test mysqltest arguments @@ -818,6 +1191,8 @@ select "a" as col1, "c" as col2; --exec $MYSQL_TEST < $MYSQL_TEST_DIR/include/mysqltest-x.inc --exec $MYSQL_TEST -x $MYSQL_TEST_DIR/include/mysqltest-x.inc --exec $MYSQL_TEST --test_file=$MYSQL_TEST_DIR/include/mysqltest-x.inc +# Fix Win paths +--replace_result \\ / --error 1 --exec $MYSQL_TEST -x non_existing_file.inc 2>&1 @@ -841,3 +1216,275 @@ while ($num) SELECT 1 as a; + +# +# Bug #10251: Identifiers containing quotes not handled correctly +# +select 1 as `a'b`, 2 as `a"b`; + +# Test escaping of quotes +select 'aaa\\','aa''a',"aa""a"; + +# +# Check of include/show_msg.inc and include/show_msg80.inc +# + +# The message contains in most cases a string with the default character set +let $message= Here comes a message; +--source include/show_msg.inc + +# The message could also contain a string with character set utf8 +let $message= `SELECT USER()`; +--source include/show_msg.inc + +# The message contains more then 80 characters on multiple lines +# and is kept between double quotes. +let $message= +"Here comes a very very long message that + - is longer then 80 characters and + - consists of several lines"; +--source include/show_msg80.inc + +# The message contains more then 80 characters on multiple lines +# and uses the auxiliary character "." at the beginning of the message lines. +let $message= . Here comes a very very long message that + . - is longer then 80 characters and + . - consists of several lines; +--source include/show_msg80.inc + +# +# Test --enable_parsing / disable_parsing +# +--disable_query_log +--disable_parsing +# The following will not enable query logging +--enable_query_log +select "this will not be executed"; +--enable_parsing +select "this will be executed"; +--enable_query_log + +# +# Test zero length result file. Should not pass +# +--exec touch $MYSQLTEST_VARDIR/tmp/zero_length_file.result +--exec echo "echo ok;" > $MYSQLTEST_VARDIR/tmp/query.sql +--error 1 +--exec $MYSQL_TEST -x $MYSQLTEST_VARDIR/tmp/query.sql -R $MYSQLTEST_VARDIR/tmp/zero_length_file.result 2>&1 +# +# Test that a test file that does not generate any output fails. +# +--exec echo "let \$i= 1;" > $MYSQLTEST_VARDIR/tmp/query.sql +--error 1 +--exec $MYSQL_TEST -x $MYSQLTEST_VARDIR/tmp/query.sql 2>&1 + +# +# Test that mysqltest fails when there are no queries executed +# but a result file exists +# NOTE! This will never happen as long as it's not allowed to have +# test files that produce no output +#--exec echo "something" > $MYSQLTEST_VARDIR/tmp/result_file.result +#--exec echo "let \$i= 1;" > $MYSQLTEST_VARDIR/tmp/query.sql +#--error 1 +#--exec $MYSQL_TEST -x $MYSQLTEST_VARDIR/tmp/query.sql -R $MYSQLTEST_VARDIR/tmp/result_file.result 2>&1 + +# +# Bug #11731 mysqltest in multi-statement queries ignores errors in +# non-1st queries +# + +echo Failing multi statement query; +# PS does not support multi statement +--exec echo "--disable_ps_protocol" > $MYSQLTEST_VARDIR/tmp/bug11731.sql +--exec echo "delimiter ||||;" >> $MYSQLTEST_VARDIR/tmp/bug11731.sql +--exec echo "create table t1 (a int primary key);" >> $MYSQLTEST_VARDIR/tmp/bug11731.sql +--exec echo "insert into t1 values (1);" >> $MYSQLTEST_VARDIR/tmp/bug11731.sql +--exec echo "select 'select-me';" >> $MYSQLTEST_VARDIR/tmp/bug11731.sql +--exec echo "insertz 'error query'||||" >> $MYSQLTEST_VARDIR/tmp/bug11731.sql +--exec echo "delimiter ;||||" >> $MYSQLTEST_VARDIR/tmp/bug11731.sql + +--error 1 +--exec $MYSQL_TEST -x $MYSQLTEST_VARDIR/tmp/bug11731.sql 2>&1 +drop table t1; + +--error 1 +--exec $MYSQL_TEST --record -x $MYSQLTEST_VARDIR/tmp/bug11731.sql -R $MYSQLTEST_VARDIR/tmp/bug11731.out 2>&1 +# The .out file should be non existent +--exec test ! -s $MYSQLTEST_VARDIR/tmp/bug11731.out +drop table t1; + + +echo Multi statement using expected error; +# PS does not support multi statement +--exec echo "--disable_ps_protocol" > $MYSQLTEST_VARDIR/tmp/bug11731.sql +--exec echo "delimiter ||||;" >> $MYSQLTEST_VARDIR/tmp/bug11731.sql +--exec echo "--error 1064" >> $MYSQLTEST_VARDIR/tmp/bug11731.sql +--exec echo "create table t1 (a int primary key);" >> $MYSQLTEST_VARDIR/tmp/bug11731.sql +--exec echo "insert into t1 values (1);" >> $MYSQLTEST_VARDIR/tmp/bug11731.sql +--exec echo "select 'select-me';" >> $MYSQLTEST_VARDIR/tmp/bug11731.sql +--exec echo "insertz "error query"||||" >> $MYSQLTEST_VARDIR/tmp/bug11731.sql +--exec echo "delimiter ;||||" >> $MYSQLTEST_VARDIR/tmp/bug11731.sql + +# These two should work since the error is expected +--exec $MYSQL_TEST -x $MYSQLTEST_VARDIR/tmp/bug11731.sql 2>&1 +drop table t1; + +--exec $MYSQL_TEST --record -x $MYSQLTEST_VARDIR/tmp/bug11731.sql -R $MYSQLTEST_VARDIR/tmp/bug11731.out 2>&1 +# The .out file should exist +--exec test -s $MYSQLTEST_VARDIR/tmp/bug11731.out +drop table t1; + +# +# Bug#19890 mysqltest: "query" command is broken +# + +# It should be possible to use the command "query" to force mysqltest to +# send the command to the server although it's a builtin mysqltest command. +--error 1064 +query sleep; + +--error 1064 +--query sleep + +# Just an empty query command +--error 1065 +query ; + +# test for replace_regex +--replace_regex /at/b/ +select "at" as col1, "c" as col2; + +--replace_regex /at/b/i +select "at" as col1, "AT" as col2, "c" as col3; + +--replace_regex /a/b/ /ct/d/ +select "a" as col1, "ct" as col2; + +--replace_regex /(strawberry)/raspberry and \1/ /blueberry/blackberry/ /potato/tomato/; +select "strawberry","blueberry","potato"; + +--error 1 +--exec echo "--replace_regex a" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--replace_regex a;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "replace_regex a;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "replace_regex a ;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "replace_regex a b; echo OK;" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "--replace_regex /a b c" | $MYSQL_TEST 2>&1 +--error 1 +--exec echo "replace_regex /a /b c ;" | $MYSQL_TEST 2>&1 + +# REQUIREMENT +# replace_regex should replace substitutions from left to right in output + +create table t1 (a int, b int); +insert into t1 values (1,3); +insert into t1 values (2,4); +--replace_regex /A/C/ /B/D/i /3/2/ /2/1/ +select * from t1; +drop table t1; + +# ---------------------------------------------------------------------------- +# test for remove_file +# ---------------------------------------------------------------------------- + +--error 1 +--exec echo "remove_file ;" | $MYSQL_TEST 2>&1 + +--error 1 +remove_file non_existing_file; + +# ---------------------------------------------------------------------------- +# test for write_file +# ---------------------------------------------------------------------------- +--error 1 +--exec echo "write_file ;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "write_file filename ;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "write_file filename \";" | $MYSQL_TEST 2>&1 + +write_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +Content for test_file1 +EOF +file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; + +write_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp END_DELIMITER; +Content for test_file1 contains EOF +END_DELIMITER +file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; + +# ---------------------------------------------------------------------------- +# test for file_exist +# ---------------------------------------------------------------------------- +--error 1 +--exec echo "file_exists ;" | $MYSQL_TEST 2>&1 + +--error 0,1 +remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +--error 1 +file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +write_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +Content for test_file1 +EOF +file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +remove_file $MYSQLTEST_VARDIR/tmp/test_file1.tmp; +--error 1 +file_exists $MYSQLTEST_VARDIR/tmp/test_file1.tmp; + + +# ---------------------------------------------------------------------------- +# test for copy_file +# ---------------------------------------------------------------------------- +--write_file $MYSQLTEST_VARDIR/tmp/file1.tmp +file1 +EOF + +copy_file $MYSQLTEST_VARDIR/tmp/file1.tmp $MYSQLTEST_VARDIR/tmp/file2.tmp; +file_exists $MYSQLTEST_VARDIR/tmp/file2.tmp; +remove_file $MYSQLTEST_VARDIR/tmp/file1.tmp; +remove_file $MYSQLTEST_VARDIR/tmp/file2.tmp; + +--error 1 +--exec echo "copy_file ;" | $MYSQL_TEST 2>&1 + +--error 1 +--exec echo "copy_file from_file;" | $MYSQL_TEST 2>&1 + +# ---------------------------------------------------------------------------- +# test for perl +# ---------------------------------------------------------------------------- +--perl +print "hello\n"; +EOF + +--perl EOF +print "hello\n"; +EOF + +--perl DELIMITER +print "hello\n"; +DELIMITER + +--error 1 +--exec echo "perl TOO_LONG_DELIMITER ;" | $MYSQL_TEST 2>&1 + +perl; +print "hello\n"; +EOF + +perl; + # Print "hello" + print "hello\n"; +EOF + + +--echo End of tests diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 0ca293eb1ba..5be56c59049 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -351,14 +351,14 @@ create table t1 (a int, b int); insert into t1 (a, b) values (1,1), (1,2), (2,1), (2,2); prepare stmt from "explain select * from t1 where t1.a=2 and t1.a=t1.b and t1.b > 1 + ?"; ---replace_column 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - set @v=5; -execute stmt using @v; --replace_column 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - +execute stmt using @v; set @v=0; -execute stmt using @v; --replace_column 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - +execute stmt using @v; set @v=5; +--replace_column 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - execute stmt using @v; drop table t1; deallocate prepare stmt; diff --git a/mysql-test/t/ps_1general.test b/mysql-test/t/ps_1general.test index 6f15ba8f673..ec4964d116a 100644 --- a/mysql-test/t/ps_1general.test +++ b/mysql-test/t/ps_1general.test @@ -305,8 +305,8 @@ prepare stmt4 from ' show table status from test like ''t9%'' '; --replace_result 2147483647 4294967295 # Bug#4288 execute stmt4; ---replace_column 2 # prepare stmt4 from ' show status like ''Threads_running'' '; +--replace_column 2 # execute stmt4; prepare stmt4 from ' show variables like ''sql_mode'' '; execute stmt4; diff --git a/mysql-test/t/ps_grant.test b/mysql-test/t/ps_grant.test index 4cb056db358..afd543caacc 100644 --- a/mysql-test/t/ps_grant.test +++ b/mysql-test/t/ps_grant.test @@ -35,7 +35,7 @@ use mysqltest; --source include/ps_create.inc --source include/ps_renew.inc --enable_query_log -eval use $DB; +use test; grant usage on mysqltest.* to second_user@localhost identified by 'looser' ; grant select on mysqltest.t9 to second_user@localhost diff --git a/mysql-test/t/rpl000018.test b/mysql-test/t/rpl000018.test deleted file mode 100644 index aee052ffd28..00000000000 --- a/mysql-test/t/rpl000018.test +++ /dev/null @@ -1,29 +0,0 @@ -# -# Running test with abort-slave-event-count=1 -# This will force slave to reconnect after every event -# - -require_manager; -connect (master,localhost,root,,test,0,master.sock); -connect (slave,localhost,root,,test,0,slave.sock); -connection master; -reset master; -server_stop master; -server_start master; -connection slave; -reset slave; -start slave; -connection master; -show binary logs; ---disable_warnings -drop table if exists t1; ---enable_warnings -create table t1(n int); -insert into t1 values (3351); -sync_slave_with_master; -select * from t1; -connection master; -drop table t1; -sync_slave_with_master; - -# End of 4.1 tests diff --git a/mysql-test/t/rpl_chain_temp_table.test b/mysql-test/t/rpl_chain_temp_table.test deleted file mode 100644 index 96e228a17a1..00000000000 --- a/mysql-test/t/rpl_chain_temp_table.test +++ /dev/null @@ -1,101 +0,0 @@ - # This test makes some assumptions about values of thread ids, which should be -# true if the servers have been restarted for this test. So we want to -# stop/restart servers. Note that if assumptions are wrong, the test will not -# fail; it will just fail to test the error-prone scenario. -# Using the manager is the only way to have more than one slave server. -# So you must run this test with --manager. - -require_manager; -server_stop master; -server_start master; -server_stop slave; -server_start slave; -# no need for slave_sec (no assumptions on thread ids for this server). - -source include/master-slave.inc; -connect (slave_sec,localhost,root,,test,0,slave.sock-1); -connection master; -save_master_pos; -connection slave; -sync_with_master; -reset master; -save_master_pos; -connection slave_sec; -eval change master to master_host='127.0.0.1',master_port=$SLAVE_MYPORT, master_user='root'; -start slave; -sync_with_master; - -# :P now we have a chain ready-to-test. - -connection master; -create temporary table t1 (a int); -save_master_pos; -connection slave; -sync_with_master; -connection master1; -create temporary table t1 (a int); -save_master_pos; -connection slave; -sync_with_master; -save_master_pos; - -# First test: - -connection slave_sec; -# Before BUG#1686 ("If 2 master threads with same-name temp table, slave makes -# bad binlog") was fixed, sync_with_master failed -sync_with_master; -show status like 'slave_open_temp_tables'; - -# 'master' and 'master1' usually have thread id 2-3 or 3-4. -# 'slave' and 'slave1' usually have thread id 2-3. -connection slave; -create temporary table t1 (a int); -connection slave1; -create temporary table t1 (a int); -# So it's likely that in the binlog of slave we get -# server_id=of_master thread_id=3 create temp... -# server_id=of_slave thread_id=3 create temp... -# which would confuse slave-sec unless slave-sec uses server id to distinguish -# between temp tables (here thread id is obviously not enough to distinguish). - -save_master_pos; - -# Second test: - -connection slave_sec; -# If we did not use the server id to distinguish between temp tables, -# sync_with_master would fail -sync_with_master; -show status like 'slave_open_temp_tables'; - -# Third test (BUG#1240 "slave of slave breaks when STOP SLAVE was issud on -# parent slave and temp tables"). -stop slave; -connection slave; -insert into t1 values(1); -create table t2 as select * from t1; -save_master_pos; -connection slave_sec; -start slave; -sync_with_master; -show status like 'slave_open_temp_tables'; -select * from t2; - -# clean up -connection slave; -drop table t2; -save_master_pos; -connection slave_sec; -sync_with_master; - -# On purpose, we don't delete the temporary tables explicitely. -# So temp tables remain on slave (remember they are not deleted when the slave -# SQL thread terminates). If you run this test with -# --valgrind --valgrind-options=--show-reachable=yes -# you will see if they get cleaned up at slave's shutdown (that is, if the -# memory they use is freed (it should) by mysqld before it terminates). -# If they wouldn't be cleaned up, you would see some "still reachable" blocks in -# Valgrind. - -# End of 4.1 tests diff --git a/mysql-test/t/rpl_failsafe.test b/mysql-test/t/rpl_failsafe.test deleted file mode 100644 index 4336d897fc0..00000000000 --- a/mysql-test/t/rpl_failsafe.test +++ /dev/null @@ -1,24 +0,0 @@ -require_manager; -source include/master-slave.inc; -connect (slave_sec,localhost,root,,test,0,slave.sock-1); -connect (slave_ter,localhost,root,,test,0,slave.sock-2); -connection master; -show variables like 'rpl_recovery_rank'; -show status like 'Rpl_status'; -create table t1(n int); -drop table t1; -sync_slave_with_master; -show variables like 'rpl_recovery_rank'; -show status like 'Rpl_status'; -connection slave_sec; -start slave; -sync_with_master; -show variables like 'rpl_recovery_rank'; -show status like 'Rpl_status'; -connection slave_ter; -start slave; -sync_with_master; -show variables like 'rpl_recovery_rank'; -show status like 'Rpl_status'; - -# End of 4.1 tests diff --git a/mysql-test/t/rpl_flush_tables.test b/mysql-test/t/rpl_flush_tables.test index 378fa479f09..aea8d7a5353 100644 --- a/mysql-test/t/rpl_flush_tables.test +++ b/mysql-test/t/rpl_flush_tables.test @@ -8,6 +8,8 @@ # merge table getting renamed. --source include/not_windows.inc +let $SERVER_VERSION=`select version()`; + create table t1 (a int); insert into t1 values (10); create table t2 (a int); diff --git a/mysql-test/t/rpl_heap.test b/mysql-test/t/rpl_heap.test deleted file mode 100644 index 66dac1d7926..00000000000 --- a/mysql-test/t/rpl_heap.test +++ /dev/null @@ -1,51 +0,0 @@ -# You must run this test with --manager. - -require_manager; - -# Don't know why, but using TCP/IP connections makes this test fail -# with "Lost connection to MySQL server during query" when we -# issue a query after the server restart. -# Maybe this is something awkward in mysqltest or in the manager? -# So we use sockets. -connect (master,localhost,root,,test,0,master.sock); -connect (slave,localhost,root,,test,0,slave.sock); - -connection master; -reset master; -drop table if exists t1; -# we use CREATE SELECT to verify that DELETE does not get into binlog -# before CREATE SELECT -create table t1 type=HEAP select 10 as a; -insert into t1 values(11); -save_master_pos; -show binlog events from 79; -connection slave; -reset slave; -start slave; -sync_with_master; -show create table t1; -select * from t1; # should be one row - -server_stop master; -server_start master; - -connection master; -select * from t1; -# to check that DELETE is not written twice -# (the LIMIT is to not use the query cache) -select * from t1 limit 10; -save_master_pos; -show binlog events in 'master-bin.002' from 79; - -connection slave; -sync_with_master; -select * from t1; # should be empty - -# clean up -connection master; -drop table t1; -save_master_pos; -connection slave; -sync_with_master; - -# End of 4.1 tests diff --git a/mysql-test/t/rpl_trunc_temp.test b/mysql-test/t/rpl_trunc_temp.test index be570a6f80c..b4ea3c318da 100644 --- a/mysql-test/t/rpl_trunc_temp.test +++ b/mysql-test/t/rpl_trunc_temp.test @@ -29,7 +29,4 @@ connection slave; show status like 'Slave_open_temp_tables'; -connection master; - - # End of 4.1 tests diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 10dfb788c10..d34da8eabe2 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -1721,7 +1721,7 @@ select (select a from t1) = (1,2); select (1,2,3) = (select * from t1); -- error 1241 select (select * from t1) = (1,2,3); -drop table t1 +drop table t1; # # Item_int_with_ref check (BUG#10020) diff --git a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test index 2ac55da7442..2c3f4e5efce 100644 --- a/mysql-test/t/type_blob.test +++ b/mysql-test/t/type_blob.test @@ -23,7 +23,7 @@ CREATE TABLE t2 (a char(257), b varbinary(70000), c varchar(70000000)); show columns from t2; create table t3 (a long, b long byte); show create TABLE t3; -drop table t1,t2,t3 +drop table t1,t2,t3; # # Check errors with blob From 8f3fbd26259462f2aeab158c5e9fa27b8a9f87e3 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Tue, 3 Oct 2006 15:48:41 +0200 Subject: [PATCH 005/131] Add two new result files --- mysql-test/r/init_file.result | 2 ++ mysql-test/r/mysql_client_test.result | 1 + 2 files changed, 3 insertions(+) create mode 100644 mysql-test/r/init_file.result create mode 100644 mysql-test/r/mysql_client_test.result diff --git a/mysql-test/r/init_file.result b/mysql-test/r/init_file.result new file mode 100644 index 00000000000..5404a7b2064 --- /dev/null +++ b/mysql-test/r/init_file.result @@ -0,0 +1,2 @@ +ok +End of 4.1 tests diff --git a/mysql-test/r/mysql_client_test.result b/mysql-test/r/mysql_client_test.result new file mode 100644 index 00000000000..9766475a418 --- /dev/null +++ b/mysql-test/r/mysql_client_test.result @@ -0,0 +1 @@ +ok From 538e1881ce90aba315ee1f994e3be9120f2769ae Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Tue, 3 Oct 2006 16:34:44 +0200 Subject: [PATCH 006/131] Fix typo - Change con_host to ds_connection_name.str --- client/mysqltest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 623c33d0f4f..d057e7ea4f0 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3025,7 +3025,7 @@ void do_connect(struct st_command *command) opt_ssl_capath, opt_ssl_cipher); #if MYSQL_VERSION_ID >= 50000 /* Turn on ssl_verify_server_cert only if host is "localhost" */ - opt_ssl_verify_server_cert= !strcmp(con_host, "localhost"); + opt_ssl_verify_server_cert= !strcmp(ds_connection_name.str, "localhost"); mysql_options(&next_con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, &opt_ssl_verify_server_cert); #endif From 728588da38b660d5c2cfc6e235623969e5332303 Mon Sep 17 00:00:00 2001 From: "iggy@rolltop.ignatz42.dyndns.org" <> Date: Tue, 3 Oct 2006 11:26:50 -0400 Subject: [PATCH 007/131] Bug#19660 mysqldump --single-transaction should be with CONSISTENT SNAPSHOT --- client/mysqldump.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 3445a23eb5e..c55e4157394 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -2407,7 +2407,7 @@ static int do_reset_master(MYSQL *mysql_con) } -static int start_transaction(MYSQL *mysql_con, my_bool consistent_read_now) +static int start_transaction(MYSQL *mysql_con) { /* We use BEGIN for old servers. --single-transaction --master-data will fail @@ -2422,10 +2422,8 @@ static int start_transaction(MYSQL *mysql_con, my_bool consistent_read_now) "SET SESSION TRANSACTION ISOLATION " "LEVEL REPEATABLE READ") || mysql_query_with_error_report(mysql_con, 0, - consistent_read_now ? "START TRANSACTION " - "WITH CONSISTENT SNAPSHOT" : - "BEGIN")); + "/*!40100 WITH CONSISTENT SNAPSHOT */")); } @@ -2652,7 +2650,7 @@ int main(int argc, char **argv) if ((opt_lock_all_tables || opt_master_data) && do_flush_tables_read_lock(sock)) goto err; - if (opt_single_transaction && start_transaction(sock, test(opt_master_data))) + if (opt_single_transaction && start_transaction(sock)) goto err; if (opt_delete_master_logs && do_reset_master(sock)) goto err; From 89a53ef37405af6e724e09fc6d078b59fb7f1e94 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 3 Oct 2006 23:11:47 +0200 Subject: [PATCH 008/131] Fix problem when both option SSL and COMPRESS specified --- client/mysqltest.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index d057e7ea4f0..f52b4eafe15 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2991,7 +2991,12 @@ void do_connect(struct st_command *command) con_options= ds_options.str; while (*con_options) { - char* end= con_options; + char* end; + /* Step past any spaces in beginning of option*/ + while (*con_options && my_isspace(charset_info, *con_options)) + con_options++; + /* Find end of this option */ + end= con_options; while (*end && !my_isspace(charset_info, *end)) end++; if (!strncmp(con_options, "SSL", 3)) From 54a76f49469cdc4c3c7cb5490bb8cebbf9046be2 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 4 Oct 2006 01:20:08 +0200 Subject: [PATCH 009/131] Add possibility to send warnings about suspicious commands in .test file to .warnings file Move detection of "parsing enabled" to after command has been read. Cleanup parsing enabled/disabled --- client/mysqltest.c | 225 +++++++++++++++++++++++++++++++++------------ 1 file changed, 167 insertions(+), 58 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index f52b4eafe15..a81854733de 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -391,7 +391,7 @@ struct st_command TYPELIB command_typelib= {array_elements(command_names),"", command_names, 0}; -DYNAMIC_STRING ds_res, ds_progress; +DYNAMIC_STRING ds_res, ds_progress, ds_warning_messages; void die(const char *fmt, ...) /* ATTRIBUTE_FORMAT(printf, 1, 2) */; @@ -399,6 +399,8 @@ void abort_not_supported_test(const char *fmt, ...) /* ATTRIBUTE_FORMAT(printf, 1, 2) */; void verbose_msg(const char *fmt, ...) /* ATTRIBUTE_FORMAT(printf, 1, 2) */; +void warning_msg(const char *fmt, ...) + /* ATTRIBUTE_FORMAT(printf, 1, 2) */; VAR* var_from_env(const char *, const char *); VAR* var_init(VAR* v, const char *name, int name_len, const char *val, @@ -410,6 +412,7 @@ void eval_expr(VAR* v, const char *p, const char** p_end); my_bool match_delimiter(int c, const char *delim, uint length); void dump_result_to_reject_file(const char *record_file, char *buf, int size); void dump_result_to_log_file(const char *record_file, char *buf, int size); +void dump_warning_messages(const char *record_file); void do_eval(DYNAMIC_STRING *query_eval, const char *query, const char *query_end, my_bool pass_through_escape_chars); @@ -697,6 +700,7 @@ void free_used_memory() delete_dynamic(&q_lines); dynstr_free(&ds_res); dynstr_free(&ds_progress); + dynstr_free(&ds_warning_messages); free_all_replace(); my_free(pass,MYF(MY_ALLOW_ZERO_PTR)); free_defaults(default_argv); @@ -741,6 +745,10 @@ void die(const char *fmt, ...) if (result_file && ds_res.length) dump_result_to_log_file(result_file, ds_res.str, ds_res.length); + /* Dump warning messages */ + if (result_file && ds_warning_messages.length) + dump_warning_messages(result_file); + /* Clean up and exit */ free_used_memory(); my_end(MY_CHECK_ERROR); @@ -817,6 +825,31 @@ void verbose_msg(const char *fmt, ...) } +void warning_msg(const char *fmt, ...) +{ + va_list args; + char buff[512]; + size_t len; + DBUG_ENTER("warning_msg"); + + va_start(args, fmt); + dynstr_append(&ds_warning_messages, "mysqltest: "); + if (start_lineno != 0) + { + len= my_snprintf(buff, sizeof(buff), "Warning detected at line %d: ", + start_lineno); + dynstr_append_mem(&ds_warning_messages, + buff, len); + } + len= vsnprintf(buff, sizeof(buff), fmt, args); + dynstr_append_mem(&ds_warning_messages, buff, len); + dynstr_append(&ds_warning_messages, "\n"); + va_end(args); + + DBUG_VOID_RETURN; +} + + /* Compare content of the string ds to content of file fname */ @@ -3495,6 +3528,55 @@ void convert_to_format_v1(char* query) } +/* + Check a command that is about to be sent (or should have been + sent if parsing was enabled) to mysql server for + suspicious things and generate warnings. +*/ + +void scan_command_for_warnings(struct st_command *command) +{ + const char *ptr= command->query; + DBUG_ENTER("scan_command_for_warnings"); + DBUG_PRINT("enter", ("query: %s", command->query)); + + while(*ptr) + { + /* + Look for query's that lines that start with a -- comment + and has a mysqltest command + */ + if (ptr[0] == '\n' && + ptr[1] && ptr[1] == '-' && + ptr[2] && ptr[2] == '-' && + ptr[3]) + { + uint type; + char save; + char *end, *start= (char*)ptr+3; + /* Skip leading spaces */ + while (*start && my_isspace(charset_info, *start)) + start++; + end= start; + /* Find end of command(next space) */ + while (*end && !my_isspace(charset_info, *end)) + end++; + save= *end; + *end= 0; + DBUG_PRINT("info", ("Checking '%s'", start)); + type= find_type(start, &command_typelib, 1+2); + if (type) + warning_msg("Embedded mysqltest command '--%s' detected in " + "query '%s' was this intentional? ", + start, command->query); + *end= save; + } + + *ptr++; + } + DBUG_VOID_RETURN; +} + /* Check for unexpected "junk" after the end of query This is normally caused by missing delimiters @@ -3583,43 +3665,29 @@ int read_command(struct st_command** command_ptr) if (*p == '#') { command->type= Q_COMMENT; - /* This goto is to avoid losing the "expected error" info. */ - goto end; } - if (!parsing_disabled) - { - memcpy(&command->expected_errors, &saved_expected_errors, - sizeof(saved_expected_errors)); - DBUG_PRINT("info", ("There are %d expected errors", - command->expected_errors.count)); - command->abort_on_error= (command->expected_errors.count == 0 && - abort_on_error); - } - - if (p[0] == '-' && p[1] == '-') + else if (p[0] == '-' && p[1] == '-') { command->type= Q_COMMENT_WITH_COMMAND; - p+= 2; /* To calculate first word */ - } - else if (!parsing_disabled) - { - while (*p && my_isspace(charset_info, *p)) - p++ ; + p+= 2; /* Skip past -- */ } -end: + /* Skip leading spaces */ while (*p && my_isspace(charset_info, *p)) p++; if (!(command->query_buf= command->query= my_strdup(p, MYF(MY_WME)))) - die(NullS); + die("Out of memory"); /* Calculate first word and first argument */ for (p= command->query; *p && !my_isspace(charset_info, *p) ; p++) ; command->first_word_len= (uint) (p - command->query); + + /* Skip spaces between command and first argument */ while (*p && my_isspace(charset_info, *p)) p++; command->first_argument= p; + command->end= strend(command->query); command->query_len= (command->end - command->query); parser.read_lines++; @@ -3947,6 +4015,15 @@ void dump_progress(const char *record_file) ds_progress.str, ds_progress.length); } +void dump_warning_messages(const char *record_file) +{ + char warn_file[FN_REFLEN]; + + str_to_file(fn_format(warn_file, record_file, "", ".warnings", + MY_REPLACE_EXT), + ds_warning_messages.str, ds_warning_messages.length); +} + void check_regerr(my_regex_t* r, int err) { char err_buf[1024]; @@ -4880,6 +4957,9 @@ void run_query(MYSQL *mysql, struct st_command *command, int flags) init_dynamic_string(&ds_warnings, NULL, 0, 256); + /* Scan for warning before sendign to server */ + scan_command_for_warnings(command); + /* Evaluate query if this is an eval command */ @@ -5166,28 +5246,19 @@ void get_command_type(struct st_command* command) uint type; DBUG_ENTER("get_command_type"); - if (!parsing_disabled && *command->query == '}') + if (*command->query == '}') { command->type = Q_END_BLOCK; DBUG_VOID_RETURN; } - if (command->type != Q_COMMENT_WITH_COMMAND) - command->type= parsing_disabled ? Q_COMMENT : Q_QUERY; - save=command->query[command->first_word_len]; - command->query[command->first_word_len]=0; - type=find_type(command->query, &command_typelib, 1+2); - command->query[command->first_word_len]=save; + save= command->query[command->first_word_len]; + command->query[command->first_word_len]= 0; + type= find_type(command->query, &command_typelib, 1+2); + command->query[command->first_word_len]= save; if (type > 0) { command->type=(enum enum_commands) type; /* Found command */ - /* - If queries are disabled, only recognize - --enable_parsing and --disable_parsing - */ - if (parsing_disabled && command->type != Q_ENABLE_PARSING && - command->type != Q_DISABLE_PARSING) - command->type= Q_COMMENT; /* Look for case where "query" was explicitly specified to @@ -5199,23 +5270,50 @@ void get_command_type(struct st_command* command) command->query= command->first_argument; } } - else if (command->type == Q_COMMENT_WITH_COMMAND && - command->first_word_len && - strcmp(command->query + command->first_word_len - 1, delimiter) == 0) + else { - /* - Detect comment with command using extra delimiter - Ex --disable_query_log; - ^ Extra delimiter causing the command - to be skipped - */ - save= command->query[command->first_word_len-1]; - command->query[command->first_word_len-1]= 0; - type= find_type(command->query, &command_typelib, 1+2); - command->query[command->first_word_len-1]= save; - if (type > 0) - die("Extra delimiter \";\" found"); + /* No mysqltest command matched */ + + if (command->type != Q_COMMENT_WITH_COMMAND) + { + /* A query that will sent to mysqld */ + command->type= Q_QUERY; + } + else + { + /* -- comment that didn't contain a mysqltest command */ + command->type= Q_COMMENT; + warning_msg("Suspicious command '--%s' detected, was this intentional? "\ + "Use # instead of -- to avoid this warning", + command->query); + + if (command->first_word_len && + strcmp(command->query + command->first_word_len - 1, delimiter) == 0) + { + /* + Detect comment with command using extra delimiter + Ex --disable_query_log; + ^ Extra delimiter causing the command + to be skipped + */ + save= command->query[command->first_word_len-1]; + command->query[command->first_word_len-1]= 0; + if (find_type(command->query, &command_typelib, 1+2) > 0) + die("Extra delimiter \";\" found"); + command->query[command->first_word_len-1]= save; + + } + } } + + /* Set expected error on command */ + memcpy(&command->expected_errors, &saved_expected_errors, + sizeof(saved_expected_errors)); + DBUG_PRINT("info", ("There are %d expected errors", + command->expected_errors.count)); + command->abort_on_error= (command->expected_errors.count == 0 && + abort_on_error); + DBUG_VOID_RETURN; } @@ -5314,6 +5412,7 @@ int main(int argc, char **argv) init_dynamic_string(&ds_res, "", 65536, 65536); init_dynamic_string(&ds_progress, "", 0, 2048); + init_dynamic_string(&ds_warning_messages, "", 0, 2048); parse_args(argc, argv); DBUG_PRINT("info",("result_file: '%s'", result_file ? result_file : "")); @@ -5386,6 +5485,15 @@ int main(int argc, char **argv) int current_line_inc = 1, processed = 0; if (command->type == Q_UNKNOWN || command->type == Q_COMMENT_WITH_COMMAND) get_command_type(command); + + if (parsing_disabled && + command->type != Q_ENABLE_PARSING && + command->type != Q_DISABLE_PARSING) + { + command->type= Q_COMMENT; + scan_command_for_warnings(command); + } + if (cur_block->ok) { command->last_argument= command->first_argument; @@ -5558,7 +5666,6 @@ int main(int argc, char **argv) break; } case Q_COMMENT: /* Ignore row */ - case Q_COMMENT_WITH_COMMAND: command->last_argument= command->end; break; case Q_PING: @@ -5631,10 +5738,11 @@ int main(int argc, char **argv) else check_eol_junk(command->last_argument); - if (command->type != Q_ERROR) + if (command->type != Q_ERROR && + command->type != Q_COMMENT) { /* - As soon as any non "error" command has been executed, + As soon as any non "error" command or comment has been executed, the array with expected errors should be cleared */ memset(&saved_expected_errors, 0, sizeof(saved_expected_errors)); @@ -5650,8 +5758,6 @@ int main(int argc, char **argv) } last_command_executed= command_executed; - - parser.current_line += current_line_inc; if ( opt_mark_progress ) mark_progress(command, parser.current_line); @@ -5708,9 +5814,12 @@ int main(int argc, char **argv) die("No queries executed but result file found!"); } - if ( opt_mark_progress ) + if ( opt_mark_progress && result_file ) dump_progress(result_file); - dynstr_free(&ds_progress); + + /* Dump warning messages */ + if (result_file && ds_warning_messages.length) + dump_warning_messages(result_file); dynstr_free(&ds_res); From 5aac9b58ebacff65cd739a3039e80bf62d0d0fc3 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Wed, 4 Oct 2006 12:27:05 +0200 Subject: [PATCH 010/131] Don't print version in error message, just too messy to test --- client/mysqltest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index a81854733de..d49693fa324 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -802,7 +802,7 @@ void abort_not_supported_test(const char *fmt, ...) void abort_not_in_this_version() { - die("Not available in mysqltest for MySQL %s", VERSION); + die("Not available in this version of mysqltest"); } From 3db774af45e437c2ec50b56dc42c18b02eccbeaf Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Wed, 4 Oct 2006 12:47:32 +0200 Subject: [PATCH 011/131] Backport from 5.1 -Add support for detecting version and features from mysqld binary - Autodetect netware - Disable some features not available below 5.0 - Cleanup executable_setup to look for one executable at a time, only llok for the ones that are needed based on the selected testcases and settings --- mysql-test/lib/mtr_cases.pl | 367 +++- mysql-test/lib/mtr_im.pl | 761 +++++++ mysql-test/lib/mtr_io.pl | 66 +- mysql-test/lib/mtr_misc.pl | 40 +- mysql-test/lib/mtr_process.pl | 709 +++--- mysql-test/lib/mtr_report.pl | 135 +- mysql-test/lib/mtr_stress.pl | 178 ++ mysql-test/mysql-test-run.pl | 3821 ++++++++++++++++++++++++--------- mysql-test/r/mysqltest.result | 2 +- 9 files changed, 4681 insertions(+), 1398 deletions(-) create mode 100644 mysql-test/lib/mtr_im.pl create mode 100644 mysql-test/lib/mtr_stress.pl diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 650fb79155d..bb92730444c 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -5,10 +5,13 @@ # same name. use File::Basename; +use IO::File(); use strict; sub collect_test_cases ($); -sub collect_one_test_case ($$$$$$); +sub collect_one_test_case ($$$$$$$); + +sub mtr_options_from_test_file($$); ############################################################################## # @@ -37,44 +40,114 @@ sub collect_test_cases ($) { opendir(TESTDIR, $testdir) or mtr_error("Can't open dir \"$testdir\": $!"); + # ---------------------------------------------------------------------- + # Disable some tests listed in disabled.def + # ---------------------------------------------------------------------- + my %disabled; + if ( open(DISABLED, "$testdir/disabled.def" ) ) + { + while ( ) + { + chomp; + if ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ ) + { + $disabled{$1}= $2; + } + } + close DISABLED; + } + if ( @::opt_cases ) { foreach my $tname ( @::opt_cases ) { # Run in specified order, no sort - $tname= basename($tname, ".test"); - my $elem= "$tname.test"; - if ( ! -f "$testdir/$elem") + my $elem= undef; + my $component_id= undef; + + # Get rid of directory part (path). Leave the extension since it is used + # to understand type of the test. + + $tname = basename($tname); + + # Check if the extenstion has been specified. + + if ( mtr_match_extension($tname, "test") ) { - mtr_error("Test case $tname ($testdir/$elem) is not found"); + $elem= $tname; + $tname=~ s/\.test$//; + $component_id= 'mysqld'; } - collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,{}); + elsif ( mtr_match_extension($tname, "imtest") ) + { + $elem= $tname; + $tname =~ s/\.imtest$//; + $component_id= 'im'; + } + + # If target component is known, check that the specified test case + # exists. + # + # Otherwise, try to guess the target component. + + if ( $component_id ) + { + if ( ! -f "$testdir/$elem") + { + mtr_error("Test case $tname ($testdir/$elem) is not found"); + } + } + else + { + my $mysqld_test_exists = -f "$testdir/$tname.test"; + my $im_test_exists = -f "$testdir/$tname.imtest"; + + if ( $mysqld_test_exists and $im_test_exists ) + { + mtr_error("Ambiguous test case name ($tname)"); + } + elsif ( ! $mysqld_test_exists and ! $im_test_exists ) + { + mtr_error("Test case $tname is not found"); + } + elsif ( $mysqld_test_exists ) + { + $elem= "$tname.test"; + $component_id= 'mysqld'; + } + elsif ( $im_test_exists ) + { + $elem= "$tname.imtest"; + $component_id= 'im'; + } + } + + collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,\%disabled, + $component_id); } closedir TESTDIR; } else { - # ---------------------------------------------------------------------- - # Disable some tests listed in disabled.def - # ---------------------------------------------------------------------- - my %disabled; - if ( open(DISABLED, "$testdir/disabled.def" ) ) - { - while ( ) - { - chomp; - if ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ ) - { - $disabled{$1}= $2; - } - } - close DISABLED; - } - foreach my $elem ( sort readdir(TESTDIR) ) { - my $tname= mtr_match_extension($elem,"test"); - next if ! defined $tname; + my $component_id= undef; + my $tname= undef; + + if ($tname= mtr_match_extension($elem, 'test')) + { + $component_id = 'mysqld'; + } + elsif ($tname= mtr_match_extension($elem, 'imtest')) + { + $component_id = 'im'; + } + else + { + next; + } + next if $::opt_do_test and ! defined mtr_match_prefix($elem,$::opt_do_test); - collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,\%disabled); + collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,\%disabled, + $component_id); } closedir TESTDIR; } @@ -84,34 +157,38 @@ sub collect_test_cases ($) { if ( $::opt_reorder ) { - @$cases = sort { - if ( ! $a->{'master_restart'} and ! $b->{'master_restart'} ) - { - return $a->{'name'} cmp $b->{'name'}; - } - if ( $a->{'master_restart'} and $b->{'master_restart'} ) - { - my $cmp= mtr_cmp_opts($a->{'master_opt'}, $b->{'master_opt'}); - if ( $cmp == 0 ) - { - return $a->{'name'} cmp $b->{'name'}; - } - else - { - return $cmp; - } - } + my %sort_criteria; + my $tinfo; - if ( $a->{'master_restart'} ) - { - return 1; # Is greater - } - else - { - return -1; # Is less - } - } @$cases; + # Make a mapping of test name to a string that represents how that test + # should be sorted among the other tests. Put the most important criterion + # first, then a sub-criterion, then sub-sub-criterion, et c. + foreach $tinfo (@$cases) + { + my @this_criteria = (); + + # Append the criteria for sorting, in order of importance. + push(@this_criteria, join("!", sort @{$tinfo->{'master_opt'}}) . "~"); # Ending with "~" makes empty sort later than filled + push(@this_criteria, "ndb=" . ($tinfo->{'ndb_test'} ? "1" : "0")); + push(@this_criteria, "restart=" . ($tinfo->{'master_restart'} ? "1" : "0")); + push(@this_criteria, "big_test=" . ($tinfo->{'big_test'} ? "1" : "0")); + push(@this_criteria, join("|", sort keys %{$tinfo})); # Group similar things together. The values may differ substantially. FIXME? + push(@this_criteria, $tinfo->{'name'}); # Finally, order by the name + + $sort_criteria{$tinfo->{"name"}} = join(" ", @this_criteria); + } + + @$cases = sort { $sort_criteria{$a->{"name"}} cmp $sort_criteria{$b->{"name"}}; } @$cases; + +### For debugging the sort-order +# foreach $tinfo (@$cases) +# { +# print $sort_criteria{$tinfo->{"name"}}; +# print " -> \t"; +# print $tinfo->{"name"}; +# print "\n"; +# } } return $cases; @@ -125,13 +202,14 @@ sub collect_test_cases ($) { ############################################################################## -sub collect_one_test_case($$$$$$) { +sub collect_one_test_case($$$$$$$) { my $testdir= shift; my $resdir= shift; my $tname= shift; my $elem= shift; my $cases= shift; my $disabled=shift; + my $component_id= shift; my $path= "$testdir/$elem"; @@ -151,6 +229,7 @@ sub collect_one_test_case($$$$$$) { my $tinfo= {}; $tinfo->{'name'}= $tname; $tinfo->{'result_file'}= "$resdir/$tname.result"; + $tinfo->{'component_id'} = $component_id; push(@$cases, $tinfo); if ( $::opt_skip_test and defined mtr_match_prefix($tname,$::opt_skip_test) ) @@ -171,48 +250,54 @@ sub collect_one_test_case($$$$$$) { if ( $::opt_skip_rpl ) { $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No replication tests(--skip-rpl)"; return; } $tinfo->{'slave_num'}= 1; # Default, use one slave - # FIXME currently we always restart slaves - $tinfo->{'slave_restart'}= 1; - if ( $tname eq 'rpl_failsafe' or $tname eq 'rpl_chain_temp_table' ) { -# $tinfo->{'slave_num'}= 3; # Not 3 ? Check old code, strange + # $tinfo->{'slave_num'}= 3; # Not 3 ? Check old code, strange } } if ( defined mtr_match_prefix($tname,"federated") ) { - $tinfo->{'slave_num'}= 1; # Default, use one slave - - # FIXME currently we always restart slaves - $tinfo->{'slave_restart'}= 1; + # Default, federated uses the first slave as it's federated database + $tinfo->{'slave_num'}= 1; } - # Cluster is needed by test case if testname contains ndb - if ( defined mtr_match_substring($tname,"ndb") ) + if ( $::opt_with_ndbcluster or defined mtr_match_substring($tname,"ndb") ) { + # This is an ndb test or all tests should be run with ndb cluster started $tinfo->{'ndb_test'}= 1; if ( $::opt_skip_ndbcluster ) { - # Skip all ndb tests + # All ndb test's should be skipped $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No ndbcluster test(--skip-ndbcluster)"; return; } - if ( ! $::opt_with_ndbcluster ) + if ( ! $::opt_ndbcluster_supported ) { # Ndb is not supported, skip them $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No ndbcluster support"; return; } } else { + # This is not a ndb test $tinfo->{'ndb_test'}= 0; + if ( $::opt_with_ndbcluster_only ) + { + # Only the ndb test should be run, all other should be skipped + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Only ndbcluster tests(--with-ndbcluster-only)"; + return; + } } # FIXME what about embedded_server + ndbcluster, skip ?! @@ -223,6 +308,7 @@ sub collect_one_test_case($$$$$$) { my $master_sh= "$testdir/$tname-master.sh"; my $slave_sh= "$testdir/$tname-slave.sh"; my $disabled_file= "$testdir/$tname.disabled"; + my $im_opt_file= "$testdir/$tname-im.opt"; $tinfo->{'master_opt'}= []; $tinfo->{'slave_opt'}= []; @@ -303,6 +389,8 @@ sub collect_one_test_case($$$$$$) { if ( $::glob_win32_perl ) { $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No tests with sh scripts on Windows"; + return; } else { @@ -316,6 +404,8 @@ sub collect_one_test_case($$$$$$) { if ( $::glob_win32_perl ) { $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No tests with sh scripts on Windows"; + return; } else { @@ -324,29 +414,166 @@ sub collect_one_test_case($$$$$$) { } } + if ( -f $im_opt_file ) + { + $tinfo->{'im_opts'} = mtr_get_opts_from_file($im_opt_file); + } + else + { + $tinfo->{'im_opts'} = []; + } + # FIXME why this late? + my $marked_as_disabled= 0; if ( $disabled->{$tname} ) { - $tinfo->{'skip'}= 1; - $tinfo->{'disable'}= 1; # Sub type of 'skip' - $tinfo->{'comment'}= $disabled->{$tname} if $disabled->{$tname}; + $marked_as_disabled= 1; + $tinfo->{'comment'}= $disabled->{$tname}; } if ( -f $disabled_file ) { - $tinfo->{'skip'}= 1; - $tinfo->{'disable'}= 1; # Sub type of 'skip' + $marked_as_disabled= 1; $tinfo->{'comment'}= mtr_fromfile($disabled_file); } + # If test was marked as disabled, either opt_enable_disabled is off and then + # we skip this test, or it is on and then we run this test but warn + + if ( $marked_as_disabled ) + { + if ( $::opt_enable_disabled ) + { + $tinfo->{'dont_skip_though_disabled'}= 1; + } + else + { + $tinfo->{'skip'}= 1; + $tinfo->{'disable'}= 1; # Sub type of 'skip' + return; + } + } + + if ( $component_id eq 'im' ) + { + if ( $::glob_use_embedded_server ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No IM with embedded server"; + return; + } + elsif ( $::opt_ps_protocol ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No IM with --ps-protocol"; + return; + } + elsif ( $::opt_skip_im ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No IM tests(--skip-im)"; + return; + } + } + else + { + mtr_options_from_test_file($tinfo,"$testdir/${tname}.test"); + + if ( $tinfo->{'big_test'} and ! $::opt_big_test ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Test need 'big-test' option"; + return; + } + + if ( $tinfo->{'ndb_extra'} and ! $::opt_ndb_extra_test ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Test need 'ndb_extra' option"; + return; + } + + if ( $tinfo->{'require_manager'} ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Test need the _old_ manager(to be removed)"; + return; + } + + if ( defined $tinfo->{'binlog_format'} and + ! ( $tinfo->{'binlog_format'} eq $::used_binlog_format ) ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Not running with binlog format '$tinfo->{'binlog_format'}'"; + return; + } + + if ( $tinfo->{'need_debug'} && ! $::debug_compiled_binaries ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Test need debug binaries"; + return; + } + } + # We can't restart a running server that may be in use if ( $::glob_use_running_server and ( $tinfo->{'master_restart'} or $tinfo->{'slave_restart'} ) ) { $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Can't restart a running server"; + return; } + } +# List of tags in the .test files that if found should set +# the specified value in "tinfo" +our @tags= +( + ["include/have_innodb.inc", "innodb_test", 1], + ["include/have_binlog_format_row.inc", "binlog_format", "row"], + ["include/have_binlog_format_statement.inc", "binlog_format", "stmt"], + ["include/big_test.inc", "big_test", 1], + ["include/have_debug.inc", "need_debug", 1], + ["include/have_ndb_extra.inc", "ndb_extra", 1], + ["require_manager", "require_manager", 1], +); + +sub mtr_options_from_test_file($$) { + my $tinfo= shift; + my $file= shift; + #mtr_verbose("$file"); + my $F= IO::File->new($file) or mtr_error("can't open file \"$file\": $!"); + + while ( my $line= <$F> ) + { + next if ( $line !~ /^--/ ); + + # Match this line against tag in "tags" array + foreach my $tag (@tags) + { + if ( index($line, $tag->[0]) >= 0 ) + { + # Tag matched, assign value to "tinfo" + $tinfo->{"$tag->[1]"}= $tag->[2]; + } + } + + # If test sources another file, open it as well + if ( $line =~ /^\-\-([[:space:]]*)source(.*)$/ ) + { + my $value= $2; + $value =~ s/^\s+//; # Remove leading space + $value =~ s/[[:space:]]+$//; # Remove ending space + + my $sourced_file= "$::glob_mysql_test_dir/$value"; + mtr_options_from_test_file($tinfo, $sourced_file); + } + + } +} + 1; diff --git a/mysql-test/lib/mtr_im.pl b/mysql-test/lib/mtr_im.pl new file mode 100644 index 00000000000..ca17516278e --- /dev/null +++ b/mysql-test/lib/mtr_im.pl @@ -0,0 +1,761 @@ +# -*- cperl -*- + +# This is a library file used by the Perl version of mysql-test-run, +# and is part of the translation of the Bourne shell script with the +# same name. + +use strict; + +# Private IM-related operations. + +sub mtr_im_kill_process ($$$$); +sub mtr_im_load_pids ($); +sub mtr_im_terminate ($); +sub mtr_im_check_alive ($); +sub mtr_im_check_main_alive ($); +sub mtr_im_check_angel_alive ($); +sub mtr_im_check_mysqlds_alive ($); +sub mtr_im_check_mysqld_alive ($); +sub mtr_im_cleanup ($); +sub mtr_im_rm_file ($); +sub mtr_im_errlog ($); +sub mtr_im_kill ($); +sub mtr_im_wait_for_connection ($$$); +sub mtr_im_wait_for_mysqld($$$); + +# Public IM-related operations. + +sub mtr_im_start ($$); +sub mtr_im_stop ($); + +############################################################################## +# +# Private operations. +# +############################################################################## + +sub mtr_im_kill_process ($$$$) { + my $pid_lst= shift; + my $signal= shift; + my $total_retries= shift; + my $timeout= shift; + + my %pids; + + foreach my $pid ( @{$pid_lst} ) + { + $pids{$pid}= 1; + } + + for ( my $cur_attempt= 1; $cur_attempt <= $total_retries; ++$cur_attempt ) + { + foreach my $pid ( keys %pids ) + { + mtr_debug("Sending $signal to $pid..."); + + kill($signal, $pid); + + unless ( kill (0, $pid) ) + { + mtr_debug("Process $pid died."); + delete $pids{$pid}; + } + } + + return if scalar keys %pids == 0; + + mtr_debug("Sleeping $timeout second(s) waiting for processes to die..."); + + sleep($timeout); + } + + mtr_debug("Process(es) " . + join(' ', keys %pids) . + " is still alive after $total_retries " . + "of sending signal $signal."); +} + +########################################################################### + +sub mtr_im_load_pids($) { + my $im= shift; + + mtr_debug("Loading PID files..."); + + # Obtain mysqld-process pids. + + my $instances = $im->{'instances'}; + + for ( my $idx= 0; $idx < 2; ++$idx ) + { + mtr_debug("IM-guarded mysqld[$idx] PID file: '" . + $instances->[$idx]->{'path_pid'} . "'."); + + my $mysqld_pid; + + if ( -r $instances->[$idx]->{'path_pid'} ) + { + $mysqld_pid= mtr_get_pid_from_file($instances->[$idx]->{'path_pid'}); + mtr_debug("IM-guarded mysqld[$idx] PID: $mysqld_pid."); + } + else + { + $mysqld_pid= undef; + mtr_debug("IM-guarded mysqld[$idx]: no PID file."); + } + + $instances->[$idx]->{'pid'}= $mysqld_pid; + } + + # Re-read Instance Manager PIDs from the file, since during tests Instance + # Manager could have been restarted, so its PIDs could have been changed. + + # - IM-main + + mtr_debug("IM-main PID file: '$im->{path_pid}'."); + + if ( -f $im->{'path_pid'} ) + { + $im->{'pid'} = + mtr_get_pid_from_file($im->{'path_pid'}); + + mtr_debug("IM-main PID: $im->{pid}."); + } + else + { + mtr_debug("IM-main: no PID file."); + $im->{'pid'}= undef; + } + + # - IM-angel + + mtr_debug("IM-angel PID file: '$im->{path_angel_pid}'."); + + if ( -f $im->{'path_angel_pid'} ) + { + $im->{'angel_pid'} = + mtr_get_pid_from_file($im->{'path_angel_pid'}); + + mtr_debug("IM-angel PID: $im->{'angel_pid'}."); + } + else + { + mtr_debug("IM-angel: no PID file."); + $im->{'angel_pid'} = undef; + } +} + +########################################################################### + +sub mtr_im_terminate($) { + my $im= shift; + + # Load pids from pid-files. We should do it first of all, because IM deletes + # them on shutdown. + + mtr_im_load_pids($im); + + mtr_debug("Shutting Instance Manager down..."); + + # Ignoring SIGCHLD so that all children could rest in peace. + + start_reap_all(); + + # Send SIGTERM to IM-main. + + if ( defined $im->{'pid'} ) + { + mtr_debug("IM-main pid: $im->{pid}."); + mtr_debug("Stopping IM-main..."); + + mtr_im_kill_process([ $im->{'pid'} ], 'TERM', 10, 1); + } + else + { + mtr_debug("IM-main pid: n/a."); + } + + # If IM-angel was alive, wait for it to die. + + if ( defined $im->{'angel_pid'} ) + { + mtr_debug("IM-angel pid: $im->{'angel_pid'}."); + mtr_debug("Waiting for IM-angel to die..."); + + my $total_attempts= 10; + + for ( my $cur_attempt=1; $cur_attempt <= $total_attempts; ++$cur_attempt ) + { + unless ( kill (0, $im->{'angel_pid'}) ) + { + mtr_debug("IM-angel died."); + last; + } + + sleep(1); + } + } + else + { + mtr_debug("IM-angel pid: n/a."); + } + + stop_reap_all(); + + # Re-load PIDs. + + mtr_im_load_pids($im); +} + +########################################################################### + +sub mtr_im_check_alive($) { + my $im= shift; + + mtr_debug("Checking whether IM-components are alive..."); + + return 1 if mtr_im_check_main_alive($im); + + return 1 if mtr_im_check_angel_alive($im); + + return 1 if mtr_im_check_mysqlds_alive($im); + + return 0; +} + +########################################################################### + +sub mtr_im_check_main_alive($) { + my $im= shift; + + # Check that the process, that we know to be IM's, is dead. + + if ( defined $im->{'pid'} ) + { + if ( kill (0, $im->{'pid'}) ) + { + mtr_debug("IM-main (PID: $im->{pid}) is alive."); + return 1; + } + else + { + mtr_debug("IM-main (PID: $im->{pid}) is dead."); + } + } + else + { + mtr_debug("No PID file for IM-main."); + } + + # Check that IM does not accept client connections. + + if ( mtr_ping_port($im->{'port'}) ) + { + mtr_debug("IM-main (port: $im->{port}) " . + "is accepting connections."); + + mtr_im_errlog("IM-main is accepting connections on port " . + "$im->{port}, but there is no " . + "process information."); + return 1; + } + else + { + mtr_debug("IM-main (port: $im->{port}) " . + "does not accept connections."); + return 0; + } +} + +########################################################################### + +sub mtr_im_check_angel_alive($) { + my $im= shift; + + # Check that the process, that we know to be the Angel, is dead. + + if ( defined $im->{'angel_pid'} ) + { + if ( kill (0, $im->{'angel_pid'}) ) + { + mtr_debug("IM-angel (PID: $im->{angel_pid}) is alive."); + return 1; + } + else + { + mtr_debug("IM-angel (PID: $im->{angel_pid}) is dead."); + return 0; + } + } + else + { + mtr_debug("No PID file for IM-angel."); + return 0; + } +} + +########################################################################### + +sub mtr_im_check_mysqlds_alive($) { + my $im= shift; + + mtr_debug("Checking for IM-guarded mysqld instances..."); + + my $instances = $im->{'instances'}; + + for ( my $idx= 0; $idx < 2; ++$idx ) + { + mtr_debug("Checking mysqld[$idx]..."); + + return 1 + if mtr_im_check_mysqld_alive($instances->[$idx]); + } +} + +########################################################################### + +sub mtr_im_check_mysqld_alive($) { + my $mysqld_instance= shift; + + # Check that the process is dead. + + if ( defined $mysqld_instance->{'pid'} ) + { + if ( kill (0, $mysqld_instance->{'pid'}) ) + { + mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is alive."); + return 1; + } + else + { + mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is dead."); + } + } + else + { + mtr_debug("No PID file for mysqld instance."); + } + + # Check that mysqld does not accept client connections. + + if ( mtr_ping_port($mysqld_instance->{'port'}) ) + { + mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " . + "is accepting connections."); + + mtr_im_errlog("Mysqld is accepting connections on port " . + "$mysqld_instance->{port}, but there is no " . + "process information."); + return 1; + } + else + { + mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " . + "does not accept connections."); + return 0; + } +} + +########################################################################### + +sub mtr_im_cleanup($) { + my $im= shift; + + mtr_im_rm_file($im->{'path_pid'}); + mtr_im_rm_file($im->{'path_sock'}); + + mtr_im_rm_file($im->{'path_angel_pid'}); + + for ( my $idx= 0; $idx < 2; ++$idx ) + { + mtr_im_rm_file($im->{'instances'}->[$idx]->{'path_pid'}); + mtr_im_rm_file($im->{'instances'}->[$idx]->{'path_sock'}); + } +} + +########################################################################### + +sub mtr_im_rm_file($) +{ + my $file_path= shift; + + if ( -f $file_path ) + { + mtr_debug("Removing '$file_path'..."); + + unless ( unlink($file_path) ) + { + mtr_warning("Can not remove '$file_path'.") + } + } + else + { + mtr_debug("File '$file_path' does not exist already."); + } +} + +########################################################################### + +sub mtr_im_errlog($) { + my $msg= shift; + + # Complain in error log so that a warning will be shown. + # + # TODO: unless BUG#20761 is fixed, we will print the warning to stdout, so + # that it can be seen on console and does not produce pushbuild error. + + # my $errlog= "$opt_vardir/log/mysql-test-run.pl.err"; + # + # open (ERRLOG, ">>$errlog") || + # mtr_error("Can not open error log ($errlog)"); + # + # my $ts= localtime(); + # print ERRLOG + # "Warning: [$ts] $msg\n"; + # + # close ERRLOG; + + my $ts= localtime(); + print "Warning: [$ts] $msg\n"; +} + +########################################################################### + +sub mtr_im_kill($) { + my $im= shift; + + # Re-load PIDs. That can be useful because some processes could have been + # restarted. + + mtr_im_load_pids($im); + + # Ignoring SIGCHLD so that all children could rest in peace. + + start_reap_all(); + + # Kill IM-angel first of all. + + if ( defined $im->{'angel_pid'} ) + { + mtr_debug("Killing IM-angel (PID: $im->{angel_pid})..."); + mtr_im_kill_process([ $im->{'angel_pid'} ], 'KILL', 10, 1) + } + else + { + mtr_debug("IM-angel is dead."); + } + + # Re-load PIDs again. + + mtr_im_load_pids($im); + + # Kill IM-main. + + if ( defined $im->{'pid'} ) + { + mtr_debug("Killing IM-main (PID: $im->pid})..."); + mtr_im_kill_process([ $im->{'pid'} ], 'KILL', 10, 1); + } + else + { + mtr_debug("IM-main is dead."); + } + + # Re-load PIDs again. + + mtr_im_load_pids($im); + + # Kill guarded mysqld instances. + + my @mysqld_pids; + + mtr_debug("Collecting PIDs of mysqld instances to kill..."); + + for ( my $idx= 0; $idx < 2; ++$idx ) + { + my $pid= $im->{'instances'}->[$idx]->{'pid'}; + + unless ( defined $pid ) + { + next; + } + + mtr_debug(" - IM-guarded mysqld[$idx] PID: $pid."); + + push (@mysqld_pids, $pid); + } + + if ( scalar @mysqld_pids > 0 ) + { + mtr_debug("Killing IM-guarded mysqld instances..."); + mtr_im_kill_process(\@mysqld_pids, 'KILL', 10, 1); + } + + # That's all. + + stop_reap_all(); +} + +############################################################################## + +sub mtr_im_wait_for_connection($$$) { + my $im= shift; + my $total_attempts= shift; + my $connect_timeout= shift; + + mtr_debug("Waiting for IM on port $im->{port} " . + "to start accepting connections..."); + + for ( my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt ) + { + mtr_debug("Trying to connect to IM ($cur_attempt of $total_attempts)..."); + + if ( mtr_ping_port($im->{'port'}) ) + { + mtr_debug("IM is accepting connections " . + "on port $im->{port}."); + return 1; + } + + mtr_debug("Sleeping $connect_timeout..."); + sleep($connect_timeout); + } + + mtr_debug("IM does not accept connections " . + "on port $im->{port} after " . + ($total_attempts * $connect_timeout) . " seconds."); + + return 0; +} + +############################################################################## + +sub mtr_im_wait_for_mysqld($$$) { + my $mysqld= shift; + my $total_attempts= shift; + my $connect_timeout= shift; + + mtr_debug("Waiting for IM-guarded mysqld on port $mysqld->{port} " . + "to start accepting connections..."); + + for ( my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt ) + { + mtr_debug("Trying to connect to mysqld " . + "($cur_attempt of $total_attempts)..."); + + if ( mtr_ping_port($mysqld->{'port'}) ) + { + mtr_debug("Mysqld is accepting connections " . + "on port $mysqld->{port}."); + return 1; + } + + mtr_debug("Sleeping $connect_timeout..."); + sleep($connect_timeout); + } + + mtr_debug("Mysqld does not accept connections " . + "on port $mysqld->{port} after " . + ($total_attempts * $connect_timeout) . " seconds."); + + return 0; +} + +############################################################################## +# +# Public operations. +# +############################################################################## + +sub mtr_im_start($$) { + my $im = shift; + my $opts = shift; + + mtr_debug("Starting Instance Manager..."); + + my $args; + mtr_init_args(\$args); + mtr_add_arg($args, "--defaults-file=%s", $im->{'defaults_file'}); + + foreach my $opt ( @{$opts} ) + { + mtr_add_arg($args, $opt); + } + + $im->{'pid'} = + mtr_spawn( + $::exe_im, # path to the executable + $args, # cmd-line args + '', # stdin + $im->{'path_log'}, # stdout + $im->{'path_err'}, # stderr + '', # pid file path (not used) + { append_log_file => 1 } # append log files + ); + + unless ( $im->{'pid'} ) + { + mtr_error('Could not start Instance Manager.') + } + + # Instance Manager can be run in daemon mode. In this case, it creates + # several processes and the parent process, created by mtr_spawn(), exits just + # after start. So, we have to obtain Instance Manager PID from the PID file. + + mtr_debug("Waiting for IM to create PID file (" . + "path: '$im->{path_pid}'; " . + "timeout: $im->{start_timeout})..."); + + unless ( sleep_until_file_created($im->{'path_pid'}, + $im->{'start_timeout'}, + -1) ) # real PID is still unknown + { + mtr_debug("IM has not created PID file in $im->{start_timeout} secs."); + mtr_debug("Aborting test suite..."); + + mtr_kill_leftovers(); + + mtr_report("IM has not created PID file in $im->{start_timeout} secs."); + return 0; + } + + $im->{'pid'}= mtr_get_pid_from_file($im->{'path_pid'}); + + mtr_debug("Instance Manager started. PID: $im->{pid}."); + + # Wait until we can connect to IM. + + my $IM_CONNECT_TIMEOUT= 30; + + unless ( mtr_im_wait_for_connection($im, + $IM_CONNECT_TIMEOUT, 1) ) + { + mtr_debug("Can not connect to Instance Manager " . + "in $IM_CONNECT_TIMEOUT seconds after start."); + mtr_debug("Aborting test suite..."); + + mtr_kill_leftovers(); + + mtr_report("Can not connect to Instance Manager " . + "in $IM_CONNECT_TIMEOUT seconds after start."); + return 0; + } + + # Wait for IM to start guarded instances: + # - wait for PID files; + + mtr_debug("Waiting for guarded mysqlds instances to create PID files..."); + + for ( my $idx= 0; $idx < 2; ++$idx ) + { + my $mysqld= $im->{'instances'}->[$idx]; + + if ( exists $mysqld->{'nonguarded'} ) + { + next; + } + + mtr_debug("Waiting for mysqld[$idx] to create PID file (" . + "path: '$mysqld->{path_pid}'; " . + "timeout: $mysqld->{start_timeout})..."); + + unless ( sleep_until_file_created($mysqld->{'path_pid'}, + $mysqld->{'start_timeout'}, + -1) ) # real PID is still unknown + { + mtr_debug("mysqld[$idx] has not created PID file in " . + "$mysqld->{start_timeout} secs."); + mtr_debug("Aborting test suite..."); + + mtr_kill_leftovers(); + + mtr_report("mysqld[$idx] has not created PID file in " . + "$mysqld->{start_timeout} secs."); + return 0; + } + + mtr_debug("PID file for mysqld[$idx] ($mysqld->{path_pid} created."); + } + + # Wait until we can connect to guarded mysqld-instances + # (in other words -- wait for IM to start guarded instances). + + mtr_debug("Waiting for guarded mysqlds to start accepting connections..."); + + for ( my $idx= 0; $idx < 2; ++$idx ) + { + my $mysqld= $im->{'instances'}->[$idx]; + + if ( exists $mysqld->{'nonguarded'} ) + { + next; + } + + mtr_debug("Waiting for mysqld[$idx] to accept connection..."); + + unless ( mtr_im_wait_for_mysqld($mysqld, 30, 1) ) + { + mtr_debug("Can not connect to mysqld[$idx] " . + "in $IM_CONNECT_TIMEOUT seconds after start."); + mtr_debug("Aborting test suite..."); + + mtr_kill_leftovers(); + + mtr_report("Can not connect to mysqld[$idx] " . + "in $IM_CONNECT_TIMEOUT seconds after start."); + return 0; + } + + mtr_debug("mysqld[$idx] started."); + } + + mtr_debug("Instance Manager and its components are up and running."); + + return 1; +} + +############################################################################## + +sub mtr_im_stop($) { + my $im= shift; + + mtr_debug("Stopping Instance Manager..."); + + # Try graceful shutdown. + + mtr_im_terminate($im); + + # Check that all processes died. + + unless ( mtr_im_check_alive($im) ) + { + mtr_debug("Instance Manager has been stopped successfully."); + mtr_im_cleanup($im); + return 1; + } + + # Instance Manager don't want to die. We should kill it. + + mtr_im_errlog("Instance Manager did not shutdown gracefully."); + + mtr_im_kill($im); + + # Check again that all IM-related processes have been killed. + + my $im_is_alive= mtr_im_check_alive($im); + + mtr_im_cleanup($im); + + if ( $im_is_alive ) + { + mtr_debug("Can not kill Instance Manager or its children."); + return 0; + } + + mtr_debug("Instance Manager has been killed successfully."); + return 1; +} + +########################################################################### + +1; diff --git a/mysql-test/lib/mtr_io.pl b/mysql-test/lib/mtr_io.pl index b3da6d97664..8a7fc56269c 100644 --- a/mysql-test/lib/mtr_io.pl +++ b/mysql-test/lib/mtr_io.pl @@ -11,6 +11,8 @@ sub mtr_get_opts_from_file ($); sub mtr_fromfile ($); sub mtr_tofile ($@); sub mtr_tonewfile($@); +sub mtr_lastlinefromfile($); +sub mtr_appendfile_to_file ($$); ############################################################################## # @@ -19,13 +21,39 @@ sub mtr_tonewfile($@); ############################################################################## sub mtr_get_pid_from_file ($) { - my $file= shift; + my $pid_file_path= shift; + my $TOTAL_ATTEMPTS= 30; + my $timeout= 1; - open(FILE,"<",$file) or mtr_error("can't open file \"$file\": $!"); - my $pid= ; - chomp($pid); - close FILE; - return $pid; + # We should read from the file until we get correct pid. As it is + # stated in BUG#21884, pid file can be empty at some moment. So, we should + # read it until we get valid data. + + for (my $cur_attempt= 1; $cur_attempt <= $TOTAL_ATTEMPTS; ++$cur_attempt) + { + mtr_debug("Reading pid file '$pid_file_path' " . + "($cur_attempt of $TOTAL_ATTEMPTS)..."); + + open(FILE, '<', $pid_file_path) + or mtr_error("can't open file \"$pid_file_path\": $!"); + + my $pid= ; + + chomp($pid) if defined $pid; + + close FILE; + + return $pid if defined $pid && $pid ne ''; + + mtr_debug("Pid file '$pid_file_path' is empty. " . + "Sleeping $timeout second(s)..."); + + sleep(1); + } + + mtr_error("Pid file '$pid_file_path' is corrupted. " . + "Can not retrieve PID in " . + ($timeout * $TOTAL_ATTEMPTS) . " seconds."); } sub mtr_get_opts_from_file ($) { @@ -113,6 +141,20 @@ sub mtr_fromfile ($) { return $text; } +sub mtr_lastlinefromfile ($) { + my $file= shift; + my $text; + + open(FILE,"<",$file) or mtr_error("can't open file \"$file\": $!"); + while (my $line= ) + { + $text= $line; + } + close FILE; + return $text; +} + + sub mtr_tofile ($@) { my $file= shift; @@ -129,5 +171,17 @@ sub mtr_tonewfile ($@) { close FILE; } +sub mtr_appendfile_to_file ($$) { + my $from_file= shift; + my $to_file= shift; + + open(TOFILE,">>",$to_file) or mtr_error("can't open file \"$to_file\": $!"); + open(FROMFILE,">>",$from_file) + or mtr_error("can't open file \"$from_file\": $!"); + print TOFILE while (); + close FROMFILE; + close TOFILE; +} + 1; diff --git a/mysql-test/lib/mtr_misc.pl b/mysql-test/lib/mtr_misc.pl index 08c99e90906..dd9d24ebc8e 100644 --- a/mysql-test/lib/mtr_misc.pl +++ b/mysql-test/lib/mtr_misc.pl @@ -9,9 +9,10 @@ use strict; sub mtr_full_hostname (); sub mtr_short_hostname (); sub mtr_init_args ($); -sub mtr_add_arg ($$); +sub mtr_add_arg ($$@); sub mtr_path_exists(@); sub mtr_script_exists(@); +sub mtr_file_exists(@); sub mtr_exe_exists(@); sub mtr_copy_dir($$); sub mtr_same_opts($$); @@ -54,7 +55,7 @@ sub mtr_init_args ($) { $$args = []; # Empty list } -sub mtr_add_arg ($$) { +sub mtr_add_arg ($$@) { my $args= shift; my $format= shift; my @fargs = @_; @@ -101,6 +102,14 @@ sub mtr_script_exists (@) { } } +sub mtr_file_exists (@) { + foreach my $path ( @_ ) + { + return $path if -e $path; + } + return ""; +} + sub mtr_exe_exists (@) { my @path= @_; map {$_.= ".exe"} @path if $::glob_win32; @@ -125,18 +134,29 @@ sub mtr_exe_exists (@) { } } + sub mtr_copy_dir($$) { - my $srcdir= shift; - my $dstdir= shift; + my $from_dir= shift; + my $to_dir= shift; + +# mtr_verbose("Copying from $from_dir to $to_dir"); + + mkpath("$to_dir"); + opendir(DIR, "$from_dir") + or mtr_error("Can't find $from_dir$!"); + for(readdir(DIR)) { + next if "$_" eq "." or "$_" eq ".."; + if ( -d "$from_dir/$_" ) + { + mtr_copy_dir("$from_dir/$_", "$to_dir/$_"); + next; + } + copy("$from_dir/$_", "$to_dir/$_"); + } + closedir(DIR); - # Create destination directory - mkpath($dstdir); - find(\&mtr_copy_one_file, $dstdir); } -sub mtr_copy_one_file { - print $File::Find::name, "\n"; -} sub mtr_same_opts ($$) { my $l1= shift; diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index 662b70a4fee..5e21248790e 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -4,7 +4,6 @@ # and is part of the translation of the Bourne shell script with the # same name. -#use Carp qw(cluck); use Socket; use Errno; use strict; @@ -14,12 +13,17 @@ use POSIX 'WNOHANG'; sub mtr_run ($$$$$$;$); sub mtr_spawn ($$$$$$;$); -sub mtr_stop_mysqld_servers ($); +sub mtr_check_stop_servers ($); sub mtr_kill_leftovers (); +sub mtr_wait_blocking ($); sub mtr_record_dead_children (); +sub mtr_ndbmgm_start($$); +sub mtr_mysqladmin_start($$$); sub mtr_exit ($); sub sleep_until_file_created ($$$); sub mtr_kill_processes ($); +sub mtr_ping_with_timeout($); +sub mtr_ping_port ($); # static in C sub spawn_impl ($$$$$$$$); @@ -31,7 +35,6 @@ sub spawn_impl ($$$$$$$$); ############################################################################## # This function try to mimic the C version used in "netware/mysql_test_run.c" -# FIXME learn it to handle append mode as well, a "new" flag or a "append" sub mtr_run ($$$$$$;$) { my $path= shift; @@ -112,6 +115,9 @@ sub spawn_impl ($$$$$$$$) { print STDERR "#### ", "-" x 78, "\n"; } + mtr_error("Can't spawn with empty \"path\"") unless defined $path; + + FORK: { my $pid= fork(); @@ -144,17 +150,6 @@ sub spawn_impl ($$$$$$$$) { $SIG{INT}= 'DEFAULT'; # Parent do some stuff, we don't - if ( $::glob_cygwin_shell and $mode eq 'test' ) - { - # Programs started from mysqltest under Cygwin, are to - # execute them within Cygwin. Else simple things in test - # files like - # --system "echo 1 > file" - # will fail. - # FIXME not working :-( -# $ENV{'COMSPEC'}= "$::glob_cygwin_shell -c"; - } - my $log_file_open_mode = '>'; if ($spawn_opts and $spawn_opts->{'append_log_file'}) @@ -164,7 +159,15 @@ sub spawn_impl ($$$$$$$$) { if ( $output ) { - if ( ! open(STDOUT,$log_file_open_mode,$output) ) + if ( $::glob_win32_perl ) + { + # Don't redirect stdout on ActiveState perl since this is + # just another thread in the same process. + # Should be fixed so that the thread that is created with fork + # executes the exe in another process and wait's for it to return. + # In the meanwhile, we get all the output from mysqld's to screen + } + elsif ( ! open(STDOUT,$log_file_open_mode,$output) ) { mtr_child_error("can't redirect STDOUT to \"$output\": $!"); } @@ -216,8 +219,7 @@ sub spawn_parent_impl { { # Simple run of command, we wait for it to return my $ret_pid= waitpid($pid,0); - - if ( $ret_pid <= 0 ) + if ( $ret_pid != $pid ) { mtr_error("$path ($pid) got lost somehow"); } @@ -245,7 +247,6 @@ sub spawn_parent_impl { # Someone terminated, don't know who. Collect # status info first before $? is lost, # but not $exit_value, this is flagged from - # my $timer_name= mtr_timer_timeout($::glob_timers, $ret_pid); if ( $timer_name ) @@ -272,45 +273,22 @@ sub spawn_parent_impl { last; } - # If one of the mysqld processes died, we want to - # mark this, and kill the mysqltest process. + # One of the child processes died, unless this was expected + # mysqltest should be killed and test aborted - foreach my $idx (0..1) - { - if ( $::master->[$idx]->{'pid'} eq $ret_pid ) - { - mtr_debug("child $ret_pid was master[$idx], " . - "exit during mysqltest run"); - $::master->[$idx]->{'pid'}= 0; - last; - } - } - - foreach my $idx (0..2) - { - if ( $::slave->[$idx]->{'pid'} eq $ret_pid ) - { - mtr_debug("child $ret_pid was slave[$idx], " . - "exit during mysqltest run"); - $::slave->[$idx]->{'pid'}= 0; - last; - } - } - - mtr_debug("waitpid() catched exit of unknown child $ret_pid, " . - "exit during mysqltest run"); + check_expected_crash_and_restart($ret_pid); } if ( $ret_pid != $pid ) { # We terminated the waiting because a "mysqld" process died. # Kill the mysqltest process. - + mtr_verbose("Kill mysqltest because another process died"); kill(9,$pid); $ret_pid= waitpid($pid,0); - if ( $ret_pid == -1 ) + if ( $ret_pid != $pid ) { mtr_error("$path ($pid) got lost somehow"); } @@ -351,39 +329,101 @@ sub mtr_process_exit_status { # ############################################################################## -# We just "ping" on the ports, and if we can't do a socket connect -# we assume the server is dead. So we don't *really* know a server -# is dead, we just hope that it after letting the listen port go, -# it is dead enough for us to start a new server. +# Kill all processes(mysqld, ndbd, ndb_mgmd and im) that would conflict with +# this run +# Make sure to remove the PID file, if any. +# kill IM manager first, else it will restart the servers sub mtr_kill_leftovers () { - # First, kill all masters and slaves that would conflict with - # this run. Make sure to remove the PID file, if any. + mtr_report("Killing Possible Leftover Processes"); + mtr_debug("mtr_kill_leftovers(): started."); - my @args; + mkpath("$::opt_vardir/log"); # Needed for mysqladmin log - for ( my $idx; $idx < 2; $idx++ ) + # Stop or kill Instance Manager and all its children. If we failed to do + # that, we can only abort -- there is nothing left to do. + +# mtr_error("Failed to stop Instance Manager.") +# unless mtr_im_stop($::instance_manager); + + # Start shutdown of masters and slaves. Don't touch IM-managed mysqld + # instances -- they should be stopped by mtr_im_stop(). + + mtr_debug("Shutting down mysqld-instances..."); + + my @kill_pids; + my %admin_pids; + + foreach my $srv (@{$::master}, @{$::slave}) { - push(@args,{ - pid => 0, # We don't know the PID - pidfile => $::master->[$idx]->{'path_mypid'}, - sockfile => $::master->[$idx]->{'path_mysock'}, - port => $::master->[$idx]->{'path_myport'}, - }); + mtr_debug(" - mysqld " . + "(pid: $srv->{pid}; " . + "pid file: '$srv->{path_pid}'; " . + "socket: '$srv->{path_sock}'; ". + "port: $srv->{port})"); + + my $pid= mtr_mysqladmin_start($srv, "shutdown", 70); + + # Save the pid of the mysqladmin process + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $srv->{'pid'}, + pidfile => $srv->{'path_pid'}, + sockfile => $srv->{'path_sock'}, + port => $srv->{'port'}, + }); + $srv->{'pid'}= 0; # Assume we are done with it } - for ( my $idx; $idx < 3; $idx++ ) + if ( ! $::opt_skip_ndbcluster ) { - push(@args,{ - pid => 0, # We don't know the PID - pidfile => $::slave->[$idx]->{'path_mypid'}, - sockfile => $::slave->[$idx]->{'path_mysock'}, - port => $::slave->[$idx]->{'path_myport'}, - }); + # Start shutdown of clusters. + mtr_debug("Shutting down cluster..."); + + foreach my $cluster (@{$::clusters}) + { + mtr_debug(" - cluster " . + "(pid: $cluster->{pid}; " . + "pid file: '$cluster->{path_pid})"); + + my $pid= mtr_ndbmgm_start($cluster, "shutdown"); + + # Save the pid of the ndb_mgm process + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $cluster->{'pid'}, + pidfile => $cluster->{'path_pid'} + }); + + $cluster->{'pid'}= 0; # Assume we are done with it + + foreach my $ndbd (@{$cluster->{'ndbds'}}) + { + mtr_debug(" - ndbd " . + "(pid: $ndbd->{pid}; " . + "pid file: '$ndbd->{path_pid})"); + + push(@kill_pids,{ + pid => $ndbd->{'pid'}, + pidfile => $ndbd->{'path_pid'}, + }); + $ndbd->{'pid'}= 0; # Assume we are done with it + } + } } - mtr_mysqladmin_shutdown(\@args, 20); + # Wait for all the admin processes to complete + mtr_wait_blocking(\%admin_pids); + + # If we trusted "mysqladmin --shutdown_timeout= ..." we could just + # terminate now, but we don't (FIXME should be debugged). + # So we try again to ping and at least wait the same amount of time + # mysqladmin would for all to die. + + mtr_ping_with_timeout(\@kill_pids); # We now have tried to terminate nice. We have waited for the listen # port to be free, but can't really tell if the mysqld process died @@ -401,6 +441,8 @@ sub mtr_kill_leftovers () { # FIXME $path_run_dir or something my $rundir= "$::opt_vardir/run"; + mtr_debug("Processing PID files in directory '$rundir'..."); + if ( -d $rundir ) { opendir(RUNDIR, $rundir) @@ -414,26 +456,32 @@ sub mtr_kill_leftovers () { if ( -f $pidfile ) { + mtr_debug("Processing PID file: '$pidfile'..."); + my $pid= mtr_get_pid_from_file($pidfile); - # Race, could have been removed between I tested with -f - # and the unlink() below, so I better check again with -f - - if ( ! unlink($pidfile) and -f $pidfile ) - { - mtr_error("can't remove $pidfile"); - } + mtr_debug("Got pid: $pid from file '$pidfile'"); if ( $::glob_cygwin_perl or kill(0, $pid) ) { + mtr_debug("There is process with pid $pid -- scheduling for kill."); push(@pids, $pid); # We know (cygwin guess) it exists } + else + { + mtr_debug("There is no process with pid $pid -- skipping."); + } } } closedir(RUNDIR); if ( @pids ) { + mtr_debug("Killing the following processes with PID files: " . + join(' ', @pids) . "..."); + + start_reap_all(); + if ( $::glob_cygwin_perl ) { # We have no (easy) way of knowing the Cygwin controlling @@ -447,8 +495,9 @@ sub mtr_kill_leftovers () { my $retries= 10; # 10 seconds do { + mtr_debug("Sending SIGKILL to pids: " . join(' ', @pids)); kill(9, @pids); - mtr_debug("Sleep 1 second waiting for processes to die"); + mtr_report("Sleep 1 second waiting for processes to die"); sleep(1) # Wait one second } while ( $retries-- and kill(0, @pids) ); @@ -457,56 +506,74 @@ sub mtr_kill_leftovers () { mtr_warning("can't kill process(es) " . join(" ", @pids)); } } + + stop_reap_all(); } } + else + { + mtr_debug("Directory for PID files ($rundir) does not exist."); + } - # We may have failed everything, bug we now check again if we have + # We may have failed everything, but we now check again if we have # the listen ports free to use, and if they are free, just go for it. - foreach my $srv ( @args ) + mtr_debug("Checking known mysqld servers..."); + + foreach my $srv ( @kill_pids ) { - if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) ) + if ( defined $srv->{'port'} and mtr_ping_port($srv->{'port'}) ) { - mtr_warning("can't kill old mysqld holding port $srv->{'port'}"); + mtr_warning("can't kill old process holding port $srv->{'port'}"); } } + + mtr_debug("mtr_kill_leftovers(): finished."); } -############################################################################## -# -# Shut down mysqld servers we have started from this run of this script -# -############################################################################## - -# To speed things we kill servers in parallel. The argument is a list -# of 'ports', 'pids', 'pidfiles' and 'socketfiles'. +# Check that all processes in list are killed +# The argument is a list of 'ports', 'pids', 'pidfiles' and 'socketfiles' +# for which shutdown has been started. Make sure they all get killed +# in one way or the other. +# # FIXME On Cygwin, and maybe some other platforms, $srv->{'pid'} and -# $srv->{'pidfile'} will not be the same PID. We need to try to kill +# the pid in $srv->{'pidfile'} will not be the same PID. We need to try to kill # both I think. -sub mtr_stop_mysqld_servers ($) { +sub mtr_check_stop_servers ($) { my $spec= shift; - # ---------------------------------------------------------------------- - # First try nice normal shutdown using 'mysqladmin' - # ---------------------------------------------------------------------- + # Return if no processes are defined + return if ! @$spec; - # Shutdown time must be high as slave may be in reconnect - mtr_mysqladmin_shutdown($spec, 70); + #mtr_report("mtr_check_stop_servers"); + + mtr_ping_with_timeout(\@$spec); # ---------------------------------------------------------------------- # We loop with waitpid() nonblocking to see how many of the ones we - # are to kill, actually got killed by mtr_mysqladmin_shutdown(). - # Note that we don't rely on this, the mysqld server might have stop + # are to kill, actually got killed by mysqladmin or ndb_mgm + # + # Note that we don't rely on this, the mysqld server might have stopped # listening to the port, but still be alive. But it is a start. # ---------------------------------------------------------------------- foreach my $srv ( @$spec ) { - if ( $srv->{'pid'} and (waitpid($srv->{'pid'},&WNOHANG) == $srv->{'pid'}) ) + my $ret_pid; + if ( $srv->{'pid'} ) { - $srv->{'pid'}= 0; + $ret_pid= waitpid($srv->{'pid'},&WNOHANG); + if ($ret_pid == $srv->{'pid'}) + { + mtr_verbose("Caught exit of process $ret_pid"); + $srv->{'pid'}= 0; + } + else + { + # mtr_warning("caught exit of unknown child $ret_pid"); + } } } @@ -540,13 +607,12 @@ sub mtr_stop_mysqld_servers ($) { } # ---------------------------------------------------------------------- - # If the processes where started from this script, and we had no PIDS + # If all the processes in list already have been killed, # then we don't have to do anything. # ---------------------------------------------------------------------- if ( ! keys %mysqld_pids ) { - # cluck "This is how we got here!"; return; } @@ -595,141 +661,290 @@ sub mtr_stop_mysqld_servers ($) { foreach my $file ($srv->{'pidfile'}, $srv->{'sockfile'}) { # Know it is dead so should be no race, careful anyway - if ( -f $file and ! unlink($file) and -f $file ) + if ( defined $file and -f $file and ! unlink($file) and -f $file ) { $errors++; mtr_warning("couldn't delete $file"); } } + $srv->{'pid'}= 0; } } } if ( $errors ) { - # We are in trouble, just die.... - mtr_error("we could not kill or clean up all processes"); + # There where errors killing processes + # do one last attempt to ping the servers + # and if they can't be pinged, assume they are dead + if ( ! mtr_ping_with_timeout( \@$spec ) ) + { + mtr_error("we could not kill or clean up all processes"); + } + else + { + mtr_verbose("All ports were free, continuing"); + } } } # FIXME We just assume they are all dead, for Cygwin we are not # really sure - + +} + +# Wait for all the process in the list to terminate +sub mtr_wait_blocking($) { + my $admin_pids= shift; + + + # Return if no processes defined + return if ! %$admin_pids; + + mtr_verbose("mtr_wait_blocking"); + + # Wait for all the started processes to exit + # As mysqladmin is such a simple program, we trust it to terminate itself. + # I.e. we wait blocking, and wait for them all before we go on. + foreach my $pid (keys %{$admin_pids}) + { + my $ret_pid= waitpid($pid,0); + + } +} + +# Start "mysqladmin shutdown" for a specific mysqld +sub mtr_mysqladmin_start($$$) { + my $srv= shift; + my $command= shift; + my $adm_shutdown_tmo= shift; + + my $args; + mtr_init_args(\$args); + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--user=%s", $::opt_user); + mtr_add_arg($args, "--password="); + mtr_add_arg($args, "--silent"); + if ( -e $srv->{'path_sock'} ) + { + mtr_add_arg($args, "--socket=%s", $srv->{'path_sock'}); + } + if ( $srv->{'port'} ) + { + mtr_add_arg($args, "--port=%s", $srv->{'port'}); + } + if ( $srv->{'port'} and ! -e $srv->{'path_sock'} ) + { + mtr_add_arg($args, "--protocol=tcp"); # Needed if no --socket + } + mtr_add_arg($args, "--connect_timeout=5"); + + # Shutdown time must be high as slave may be in reconnect + mtr_add_arg($args, "--shutdown_timeout=$adm_shutdown_tmo"); + mtr_add_arg($args, "$command"); + my $path_mysqladmin_log= "$::opt_vardir/log/mysqladmin.log"; + my $pid= mtr_spawn($::exe_mysqladmin, $args, + "", $path_mysqladmin_log, $path_mysqladmin_log, "", + { append_log_file => 1 }); + mtr_verbose("mtr_mysqladmin_start, pid: $pid"); + return $pid; + +} + +# Start "ndb_mgm shutdown" for a specific cluster, it will +# shutdown all data nodes and leave the ndb_mgmd running +sub mtr_ndbmgm_start($$) { + my $cluster= shift; + my $command= shift; + + my $args; + + mtr_init_args(\$args); + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--core"); + mtr_add_arg($args, "--try-reconnect=1"); + mtr_add_arg($args, "--ndb_connectstring=%s", $cluster->{'connect_string'}); + mtr_add_arg($args, "-e"); + mtr_add_arg($args, "$command"); + + my $pid= mtr_spawn($::exe_ndb_mgm, $args, + "", "/dev/null", "/dev/null", "", + {}); + mtr_verbose("mtr_ndbmgm_start, pid: $pid"); + return $pid; + } -############################################################################## -# -# Shut down mysqld servers using "mysqladmin ... shutdown". -# To speed this up, we start them in parallel and use waitpid() to -# catch their termination. Note that this doesn't say the servers -# are terminated, just that 'mysqladmin' is terminated. -# -# Note that mysqladmin will ask the server about what PID file it uses, -# and mysqladmin will wait for it to be removed before it terminates -# (unless passes timeout). -# -# This function will take at most about 20 seconds, and we still are not -# sure we killed them all. If none is responding to ping, we return 1, -# else we return 0. -# -############################################################################## - -sub mtr_mysqladmin_shutdown { +# Ping all servers in list, exit when none of them answers +# or when timeout has passed +sub mtr_ping_with_timeout($) { my $spec= shift; - my $adm_shutdown_tmo= shift; - - my %mysql_admin_pids; - my @to_kill_specs; - - foreach my $srv ( @$spec ) - { - if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) ) - { - push(@to_kill_specs, $srv); - } - } - - - foreach my $srv ( @to_kill_specs ) - { - # FIXME wrong log..... - # FIXME, stderr..... - # Shutdown time must be high as slave may be in reconnect - my $args; - - mtr_init_args(\$args); - - mtr_add_arg($args, "--no-defaults"); - mtr_add_arg($args, "--user=%s", $::opt_user); - mtr_add_arg($args, "--password="); - if ( -e $srv->{'sockfile'} ) - { - mtr_add_arg($args, "--socket=%s", $srv->{'sockfile'}); - } - if ( $srv->{'port'} ) - { - mtr_add_arg($args, "--port=%s", $srv->{'port'}); - } - if ( $srv->{'port'} and ! -e $srv->{'sockfile'} ) - { - mtr_add_arg($args, "--protocol=tcp"); # Needed if no --socket - } - mtr_add_arg($args, "--connect_timeout=5"); - mtr_add_arg($args, "--shutdown_timeout=$adm_shutdown_tmo"); - mtr_add_arg($args, "shutdown"); - # We don't wait for termination of mysqladmin - my $pid= mtr_spawn($::exe_mysqladmin, $args, - "", $::path_manager_log, $::path_manager_log, "", - { append_log_file => 1 }); - $mysql_admin_pids{$pid}= 1; - } - - # As mysqladmin is such a simple program, we trust it to terminate. - # I.e. we wait blocking, and wait wait for them all before we go on. - while (keys %mysql_admin_pids) - { - foreach my $pid (keys %mysql_admin_pids) - { - if ( waitpid($pid,0) > 0 ) - { - delete $mysql_admin_pids{$pid}; - } - } - } - - # If we trusted "mysqladmin --shutdown_timeout= ..." we could just - # terminate now, but we don't (FIXME should be debugged). - # So we try again to ping and at least wait the same amount of time - # mysqladmin would for all to die. - - my $timeout= 20; # 20 seconds max + my $timeout= 200; # 20 seconds max my $res= 1; # If we just fall through, we are done # in the sense that the servers don't # listen to their ports any longer + + mtr_debug("Waiting for mysqld servers to stop..."); + TIME: while ( $timeout-- ) { - foreach my $srv ( @to_kill_specs ) + foreach my $srv ( @$spec ) { $res= 1; # We are optimistic - if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) ) + if ( $srv->{'pid'} and defined $srv->{'port'} ) { - mtr_debug("Sleep 1 second waiting for processes to stop using port"); - sleep(1); # One second - $res= 0; - next TIME; + if ( mtr_ping_port($srv->{'port'}) ) + { + mtr_verbose("waiting for process $srv->{'pid'} to stop ". + "using port $srv->{'port'}"); + + # Millisceond sleep emulated with select + select(undef, undef, undef, (0.1)); + $res= 0; + next TIME; + } + else + { + # Process was not using port + } } } last; # If we got here, we are done } - $timeout or mtr_debug("At least one server is still listening to its port"); - - sleep(5) if $::glob_win32; # FIXME next startup fails if no sleep + if ($res) + { + mtr_debug("mtr_ping_with_timeout(): All mysqld instances are down."); + } + else + { + mtr_report("mtr_ping_with_timeout(): At least one server is alive."); + } return $res; } + +# +# Loop through our list of processes and look for and entry +# with the provided pid +# Set the pid of that process to 0 if found +# +sub mark_process_dead($) +{ + my $ret_pid= shift; + + foreach my $mysqld (@{$::master}, @{$::slave}) + { + if ( $mysqld->{'pid'} eq $ret_pid ) + { + mtr_verbose("$mysqld->{'type'} $mysqld->{'idx'} exited, pid: $ret_pid"); + $mysqld->{'pid'}= 0; + return; + } + } + + foreach my $cluster (@{$::clusters}) + { + if ( $cluster->{'pid'} eq $ret_pid ) + { + mtr_verbose("$cluster->{'name'} cluster ndb_mgmd exited, pid: $ret_pid"); + $cluster->{'pid'}= 0; + return; + } + + foreach my $ndbd (@{$cluster->{'ndbds'}}) + { + if ( $ndbd->{'pid'} eq $ret_pid ) + { + mtr_verbose("$cluster->{'name'} cluster ndbd exited, pid: $ret_pid"); + $ndbd->{'pid'}= 0; + return; + } + } + } + mtr_warning("mark_process_dead couldn't find an entry for pid: $ret_pid"); + +} + +# +# Loop through our list of processes and look for and entry +# with the provided pid, if found check for the file indicating +# expected crash and restart it. +# +sub check_expected_crash_and_restart($) +{ + my $ret_pid= shift; + + foreach my $mysqld (@{$::master}, @{$::slave}) + { + if ( $mysqld->{'pid'} eq $ret_pid ) + { + mtr_verbose("$mysqld->{'type'} $mysqld->{'idx'} exited, pid: $ret_pid"); + $mysqld->{'pid'}= 0; + + # Check if crash expected and restart if it was + my $expect_file= "$::opt_vardir/tmp/" . "$mysqld->{'type'}" . + "$mysqld->{'idx'}" . ".expect"; + if ( -f $expect_file ) + { + mtr_verbose("Crash was expected, file $expect_file exists"); + mysqld_start($mysqld, $mysqld->{'start_opts'}, + $mysqld->{'start_slave_master_info'}); + unlink($expect_file); + } + + return; + } + } + + foreach my $cluster (@{$::clusters}) + { + if ( $cluster->{'pid'} eq $ret_pid ) + { + mtr_verbose("$cluster->{'name'} cluster ndb_mgmd exited, pid: $ret_pid"); + $cluster->{'pid'}= 0; + + # Check if crash expected and restart if it was + my $expect_file= "$::opt_vardir/tmp/ndb_mgmd_" . "$cluster->{'type'}" . + ".expect"; + if ( -f $expect_file ) + { + mtr_verbose("Crash was expected, file $expect_file exists"); + ndbmgmd_start($cluster); + unlink($expect_file); + } + return; + } + + foreach my $ndbd (@{$cluster->{'ndbds'}}) + { + if ( $ndbd->{'pid'} eq $ret_pid ) + { + mtr_verbose("$cluster->{'name'} cluster ndbd exited, pid: $ret_pid"); + $ndbd->{'pid'}= 0; + + # Check if crash expected and restart if it was + my $expect_file= "$::opt_vardir/tmp/ndbd_" . "$cluster->{'type'}" . + "$ndbd->{'idx'}" . ".expect"; + if ( -f $expect_file ) + { + mtr_verbose("Crash was expected, file $expect_file exists"); + ndbd_start($cluster, $ndbd->{'idx'}, + $ndbd->{'start_extra_args'}); + unlink($expect_file); + } + return; + } + } + } + mtr_warning("check_expected_crash_and_restart couldn't find an entry for pid: $ret_pid"); + +} + ############################################################################## # # The operating system will keep information about dead children, @@ -740,32 +955,18 @@ sub mtr_mysqladmin_shutdown { sub mtr_record_dead_children () { + my $process_died= 0; my $ret_pid; - # FIXME the man page says to wait for -1 to terminate, - # but on OS X we get '0' all the time... - while ( ($ret_pid= waitpid(-1,&WNOHANG)) > 0 ) + # Wait without blockinng to see if any processes had died + # -1 or 0 means there are no more procesess to wait for + while ( ($ret_pid= waitpid(-1,&WNOHANG)) != 0 and $ret_pid != -1) { - mtr_debug("waitpid() catched exit of child $ret_pid"); - foreach my $idx (0..1) - { - if ( $::master->[$idx]->{'pid'} eq $ret_pid ) - { - mtr_debug("child $ret_pid was master[$idx]"); - $::master->[$idx]->{'pid'}= 0; - } - } - - foreach my $idx (0..2) - { - if ( $::slave->[$idx]->{'pid'} eq $ret_pid ) - { - mtr_debug("child $ret_pid was slave[$idx]"); - $::slave->[$idx]->{'pid'}= 0; - last; - } - } + mtr_warning("mtr_record_dead_children: $ret_pid"); + mark_process_dead($ret_pid); + $process_died= 1; } + return $process_died; } sub start_reap_all { @@ -777,16 +978,24 @@ sub start_reap_all { # here. If a process terminated before setting $SIG{CHLD} (but after # any attempt to waitpid() it), it will still be a zombie. So we # have to handle any such process here. - while(waitpid(-1, &WNOHANG) > 0) { }; + my $pid; + while(($pid= waitpid(-1, &WNOHANG)) != 0 and $pid != -1) + { + mtr_warning("start_reap_all pid: $pid"); + mark_process_dead($pid); + }; } sub stop_reap_all { $SIG{CHLD}= 'DEFAULT'; } -sub mtr_ping_mysqld_server () { + +sub mtr_ping_port ($) { my $port= shift; + mtr_verbose("mtr_ping_port: $port"); + my $remote= "localhost"; my $iaddr= inet_aton($remote); if ( ! $iaddr ) @@ -799,13 +1008,18 @@ sub mtr_ping_mysqld_server () { { mtr_error("can't create socket: $!"); } + + mtr_debug("Pinging server (port: $port)..."); + if ( connect(SOCK, $paddr) ) { close(SOCK); # FIXME check error? + mtr_verbose("USED"); return 1; } else { + mtr_verbose("FREE"); return 0; } } @@ -822,30 +1036,36 @@ sub sleep_until_file_created ($$$) { my $pidfile= shift; my $timeout= shift; my $pid= shift; + my $sleeptime= 100; # Milliseconds + my $loops= ($timeout * 1000) / $sleeptime; - for ( my $loop= 1; $loop <= $timeout; $loop++ ) + for ( my $loop= 1; $loop <= $loops; $loop++ ) { if ( -r $pidfile ) { return $pid; } - # Check if it died after the fork() was successful - if ( waitpid($pid,&WNOHANG) == $pid ) + # Check if it died after the fork() was successful + if ( $pid != 0 && waitpid($pid,&WNOHANG) == $pid ) { + mtr_warning("Process $pid died"); return 0; } - mtr_debug("Sleep 1 second waiting for creation of $pidfile"); + mtr_debug("Sleep $sleeptime milliseconds waiting for $pidfile"); - if ( $loop % 60 == 0 ) + # Print extra message every 60 seconds + my $seconds= ($loop * $sleeptime) / 1000; + if ( $seconds > 1 and int($seconds) % 60 == 0 ) { - my $left= $timeout - $loop; - mtr_warning("Waited $loop seconds for $pidfile to be created, " . + my $left= $timeout - $seconds; + mtr_warning("Waited $seconds seconds for $pidfile to be created, " . "still waiting for $left seconds..."); } - sleep(1); + # Millisceond sleep emulated with select + select(undef, undef, undef, ($sleeptime/1000)); } return 0; @@ -855,18 +1075,18 @@ sub sleep_until_file_created ($$$) { sub mtr_kill_processes ($) { my $pids = shift; - foreach my $sig (15,9) + mtr_verbose("mtr_kill_processes " . join(" ", @$pids)); + + foreach my $pid (@$pids) { - my $retries= 20; # FIXME 20 seconds, this is silly! - kill($sig, @{$pids}); - while ( $retries-- and kill(0, @{$pids}) ) + foreach my $sig (15, 9) { - mtr_debug("Sleep 1 second waiting for processes to die"); - sleep(1) # Wait one second + last if mtr_im_kill_process([ $pid ], $sig, 10, 1); } } } + ############################################################################## # # When we exit, we kill off all children @@ -876,7 +1096,7 @@ sub mtr_kill_processes ($) { # FIXME something is wrong, we sometimes terminate with "Hangup" written # to tty, and no STDERR output telling us why. -# FIXME for some readon, setting HUP to 'IGNORE' will cause exit() to +# FIXME for some reason, setting HUP to 'IGNORE' will cause exit() to # write out "Hangup", and maybe loose some output. We insert a sleep... sub mtr_exit ($) { @@ -884,9 +1104,18 @@ sub mtr_exit ($) { # cluck("Called mtr_exit()"); mtr_timer_stop_all($::glob_timers); local $SIG{HUP} = 'IGNORE'; - kill('HUP', -$$); - sleep 2; + # ToDo: Signalling -$$ will only work if we are the process group + # leader (in fact on QNX it will signal our session group leader, + # which might be Do-compile or Pushbuild, causing tests to be + # aborted). So we only do it if we are the group leader. We might + # set ourselves as the group leader at startup (with + # POSIX::setpgrp(0,0)), but then care must be needed to always do + # proper child process cleanup. + kill('HUP', -$$) if !$::glob_win32_perl and $$ == getpgrp(); + exit($code); } +########################################################################### + 1; diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index 515988ee5c7..6e3796133f2 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -10,6 +10,7 @@ sub mtr_report_test_name($); sub mtr_report_test_passed($); sub mtr_report_test_failed($); sub mtr_report_test_skipped($); +sub mtr_report_test_not_skipped_though_disabled($); sub mtr_show_failed_diff ($); sub mtr_report_stats ($); @@ -21,6 +22,7 @@ sub mtr_warning (@); sub mtr_error (@); sub mtr_child_error (@); sub mtr_debug (@); +sub mtr_verbose (@); ############################################################################## @@ -36,6 +38,7 @@ sub mtr_show_failed_diff ($) { my $reject_file= "r/$tname.reject"; my $result_file= "r/$tname.result"; + my $log_file= "r/$tname.log"; my $eval_file= "r/$tname.eval"; if ( $::opt_suite ne "main" ) @@ -43,10 +46,11 @@ sub mtr_show_failed_diff ($) { $reject_file= "$::glob_mysql_test_dir/suite/$::opt_suite/$reject_file"; $result_file= "$::glob_mysql_test_dir/suite/$::opt_suite/$result_file"; $eval_file= "$::glob_mysql_test_dir/suite/$::opt_suite/$eval_file"; + $log_file= "$::glob_mysql_test_dir/suite/$::opt_suite/$log_file"; } if ( -f $eval_file ) - { + { $result_file= $eval_file; } elsif ( $::opt_result_ext and @@ -70,6 +74,12 @@ sub mtr_show_failed_diff ($) { print "http://www.mysql.com/doc/en/Reporting_mysqltest_bugs.html\n"; print "to find the reason to this problem and how to report this.\n\n"; } + + if ( -f $log_file ) + { + print "Result from queries before failure can be found in $log_file\n"; + # FIXME Maybe a tail -f -n 10 $log_file here + } } sub mtr_report_test_name ($) { @@ -88,7 +98,24 @@ sub mtr_report_test_skipped ($) { } else { - print "[ skipped ]\n"; + print "[ skipped ] $tinfo->{'comment'}\n"; + } +} + +sub mtr_report_tests_not_skipped_though_disabled ($) { + my $tests= shift; + + if ( $::opt_enable_disabled ) + { + my @disabled_tests= grep {$_->{'dont_skip_though_disabled'}} @$tests; + if ( @disabled_tests ) + { + print "\nTest(s) which will be run though they are marked as disabled:\n"; + foreach my $tinfo ( sort {$a->{'name'} cmp $b->{'name'}} @disabled_tests ) + { + printf " %-20s : %s\n", $tinfo->{'name'}, $tinfo->{'comment'}; + } + } } } @@ -99,7 +126,7 @@ sub mtr_report_test_passed ($) { if ( $::opt_timer and -f "$::opt_vardir/log/timer" ) { $timer= mtr_fromfile("$::opt_vardir/log/timer"); - $::glob_tot_real_time += $timer; + $::glob_tot_real_time += ($timer/1000); $timer= sprintf "%12s", $timer; } $tinfo->{'result'}= 'MTR_RES_PASSED'; @@ -114,6 +141,11 @@ sub mtr_report_test_failed ($) { { print "[ fail ] timeout\n"; } + elsif ( $tinfo->{'ndb_test'} and $::cluster->[0]->{'installed_ok'} eq "NO") + { + print "[ fail ] ndbcluster start failure\n"; + return; + } else { print "[ fail ]\n"; @@ -144,6 +176,8 @@ sub mtr_report_stats ($) { my $tot_passed= 0; my $tot_failed= 0; my $tot_tests= 0; + my $tot_restarts= 0; + my $found_problems= 0; # Some warnings are errors... foreach my $tinfo (@$tests) { @@ -161,6 +195,10 @@ sub mtr_report_stats ($) { $tot_tests++; $tot_failed++; } + if ( $tinfo->{'restarted'} ) + { + $tot_restarts++; + } } # ---------------------------------------------------------------------- @@ -183,41 +221,69 @@ sub mtr_report_stats ($) { "the documentation at\n", "http://www.mysql.com/doc/en/MySQL_test_suite.html\n"; } + print + "The servers were restarted $tot_restarts times\n"; + + if ( $::opt_timer ) + { + print + "Spent $::glob_tot_real_time seconds actually executing testcases\n" + } # ---------------------------------------------------------------------- + # If a debug run, there might be interesting information inside + # the "var/log/*.err" files. We save this info in "var/log/warnings" # ---------------------------------------------------------------------- if ( ! $::glob_use_running_server ) { + # Save and report if there was any fatal warnings/errors in err logs - # Report if there was any fatal warnings/errors in the log files - # - unlink("$::opt_vardir/log/warnings"); - unlink("$::opt_vardir/log/warnings.tmp"); - # Remove some non fatal warnings from the log files + my $warnlog= "$::opt_vardir/log/warnings"; -# FIXME what is going on ????? ;-) -# sed -e 's!Warning: Table:.* on delete!!g' -e 's!Warning: Setting lower_case_table_names=2!!g' -e 's!Warning: One can only use the --user.*root!!g' \ -# var/log/*.err \ -# | sed -e 's!Warning: Table:.* on rename!!g' \ -# > var/log/warnings.tmp; -# -# found_error=0; -# # Find errors -# for i in "^Warning:" "^Error:" "^==.* at 0x" -# do -# if ( $GREP "$i" var/log/warnings.tmp >> var/log/warnings ) -# { -# found_error=1 -# } -# done -# unlink("$::opt_vardir/log/warnings.tmp"); -# if ( $found_error= "1" ) -# { -# print "WARNING: Got errors/warnings while running tests. Please examine\n" -# print "$::opt_vardir/log/warnings for details.\n" -# } -# } + unless ( open(WARN, ">$warnlog") ) + { + mtr_warning("can't write to the file \"$warnlog\": $!"); + } + else + { + # We report different types of problems in order + foreach my $pattern ( "^Warning:", "^Error:", "^==.* at 0x", + "InnoDB: Warning", "missing DBUG_RETURN", + "mysqld: Warning", + "Attempting backtrace", "Assertion .* failed" ) + { + foreach my $errlog ( sort glob("$::opt_vardir/log/*.err") ) + { + unless ( open(ERR, $errlog) ) + { + mtr_warning("can't read $errlog"); + next; + } + while ( ) + { + # Skip some non fatal warnings from the log files + if ( /Warning:\s+Table:.* on (delete|rename)/ or + /Warning:\s+Setting lower_case_table_names=2/ or + /Warning:\s+One can only use the --user.*root/ or + /InnoDB: Warning: we did not need to do crash recovery/) + { + next; # Skip these lines + } + if ( /$pattern/ ) + { + $found_problems= 1; + print WARN $_; + } + } + } + } + if ( $found_problems ) + { + mtr_warning("Got errors/warnings while running tests, please examine", + "\"$warnlog\" for details."); + } + } } print "\n"; @@ -235,6 +301,9 @@ sub mtr_report_stats ($) { } } print "\n"; + } + if ( $tot_failed != 0 || $found_problems) + { mtr_error("there where failing test cases"); } } @@ -298,5 +367,11 @@ sub mtr_debug (@) { print STDERR "####: ",join(" ", @_),"\n"; } } +sub mtr_verbose (@) { + if ( $::opt_verbose ) + { + print STDERR "> ",join(" ", @_),"\n"; + } +} 1; diff --git a/mysql-test/lib/mtr_stress.pl b/mysql-test/lib/mtr_stress.pl new file mode 100644 index 00000000000..a7d4b68b69d --- /dev/null +++ b/mysql-test/lib/mtr_stress.pl @@ -0,0 +1,178 @@ +# -*- cperl -*- + +# This is a library file used by the Perl version of mysql-test-run, +# and is part of the translation of the Bourne shell script with the +# same name. + +use strict; +use File::Spec; + +# These are not to be prefixed with "mtr_" + +sub run_stress_test (); + +############################################################################## +# +# Run tests in the stress mode +# +############################################################################## + +sub run_stress_test () +{ + + my $args; + my $stress_suitedir; + + mtr_report("Starting stress testing\n"); + + if ( ! $::glob_use_embedded_server ) + { + if ( ! mysqld_start($::master->[0],[],[]) ) + { + mtr_error("Can't start the mysqld server"); + } + } + + my $stress_basedir=File::Spec->catdir($::opt_vardir, "stress"); + + #Clean up stress dir + if ( -d $stress_basedir ) + { + rmtree($stress_basedir); + } + mkpath($stress_basedir); + + if ($::opt_stress_suite ne 'main' && $::opt_stress_suite ne 'default' ) + { + $stress_suitedir=File::Spec->catdir($::glob_mysql_test_dir, "suite", + $::opt_stress_suite); + } + else + { + $stress_suitedir=$::glob_mysql_test_dir; + } + + if ( -d $stress_suitedir ) + { + #$stress_suite_t_dir=File::Spec->catdir($stress_suitedir, "t"); + #$stress_suite_r_dir=File::Spec->catdir($stress_suitedir, "r"); + #FIXME: check dirs above for existence to ensure that test suite + # contains tests and results dirs + } + else + { + mtr_error("Specified test suite $::opt_stress_suite doesn't exist"); + } + + if ( @::opt_cases ) + { + $::opt_stress_test_file=File::Spec->catfile($stress_basedir, "stress_tests.txt"); + open(STRESS_FILE, ">$::opt_stress_test_file"); + print STRESS_FILE join("\n",@::opt_cases),"\n"; + close(STRESS_FILE); + } + elsif ( $::opt_stress_test_file ) + { + $::opt_stress_test_file=File::Spec->catfile($stress_suitedir, + $::opt_stress_test_file); + if ( ! -f $::opt_stress_test_file ) + { + mtr_error("Specified file $::opt_stress_test_file with list of tests does not exist\n", + "Please ensure that file exists and has proper permissions"); + } + } + else + { + $::opt_stress_test_file=File::Spec->catfile($stress_suitedir, + "stress_tests.txt"); + if ( ! -f $::opt_stress_test_file ) + { + mtr_error("Default file $::opt_stress_test_file with list of tests does not exist\n", + "Please use --stress-test-file option to specify custom one or you can\n", + "just specify name of test for testing as last argument in command line"); + + } + } + + if ( $::opt_stress_init_file ) + { + $::opt_stress_init_file=File::Spec->catfile($stress_suitedir, + $::opt_stress_init_file); + if ( ! -f $::opt_stress_init_file ) + { + mtr_error("Specified file $::opt_stress_init_file with list of tests does not exist\n", + "Please ensure that file exists and has proper permissions"); + } + } + else + { + $::opt_stress_init_file=File::Spec->catfile($stress_suitedir, + "stress_init.txt"); + if ( ! -f $::opt_stress_init_file ) + { + $::opt_stress_init_file=''; + } + } + + if ( $::opt_stress_mode ne 'random' && $::opt_stress_mode ne 'seq' ) + { + mtr_error("You specified wrong mode $::opt_stress_mode for stress test\n", + "Correct values are 'random' or 'seq'"); + } + + mtr_init_args(\$args); + + mtr_add_arg($args, "--server-socket=%s", $::master->[0]->{'path_mysock'}); + mtr_add_arg($args, "--server-user=%s", $::opt_user); + mtr_add_arg($args, "--server-database=%s", "test"); + mtr_add_arg($args, "--stress-suite-basedir=%s", $::glob_mysql_test_dir); + mtr_add_arg($args, "--suite=%s", $::opt_stress_suite); + mtr_add_arg($args, "--stress-tests-file=%s", $::opt_stress_test_file); + mtr_add_arg($args, "--stress-basedir=%s", $stress_basedir); + mtr_add_arg($args, "--server-logs-dir=%s", $stress_basedir); + mtr_add_arg($args, "--stress-mode=%s", $::opt_stress_mode); + mtr_add_arg($args, "--mysqltest=%s", $::exe_mysqltest); + mtr_add_arg($args, "--threads=%s", $::opt_stress_threads); + mtr_add_arg($args, "--verbose"); + mtr_add_arg($args, "--cleanup"); + mtr_add_arg($args, "--log-error-details"); + mtr_add_arg($args, "--abort-on-error"); + + if ( $::opt_stress_init_file ) + { + mtr_add_arg($args, "--stress-init-file=%", $::opt_stress_init_file); + } + + if ( !$::opt_stress_loop_count && !$::opt_stress_test_count && + !$::opt_stress_test_duration ) + { + #Limit stress testing with 20 loops in case when any limit parameter + #was specified + $::opt_stress_test_count=20; + } + + if ( $::opt_stress_loop_count ) + { + mtr_add_arg($args, "--loop-count=%s", $::opt_stress_loop_count); + } + + if ( $::opt_stress_test_count ) + { + mtr_add_arg($args, "--test-count=%s", $::opt_stress_test_count); + } + + if ( $::opt_stress_test_duration ) + { + mtr_add_arg($args, "--test-duration=%s", $::opt_stress_test_duration); + } + + #Run stress test + mtr_run("$::glob_mysql_test_dir/mysql-stress-test.pl", $args, "", "", "", ""); + + if ( ! $::glob_use_embedded_server ) + { + stop_masters(); + } +} + +1; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index d1e049ff883..39c116a3fcb 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -66,10 +66,6 @@ # "http://www.plover.com/~mjd/perl/Trace/" and run this script like # "perl -d:Trace mysql-test-run.pl" # -# FIXME Save a PID file from this code as well, to record the process -# id we think it has. In Cygwin, a fork creates one Cygwin process, -# and then the real Win32 process. Cygwin Perl can only kill Cygwin -# processes. And "mysqld --bootstrap ..." doesn't save a PID file. $Devel::Trace::TRACE= 0; # Don't trace boring init stuff @@ -80,14 +76,19 @@ use File::Copy; use Cwd; use Getopt::Long; use Sys::Hostname; -#use Carp; use IO::Socket; use IO::Socket::INET; use Data::Dumper; use strict; #use diagnostics; +our $glob_win32_perl= ($^O eq "MSWin32"); # ActiveState Win32 Perl +our $glob_cygwin_perl= ($^O eq "cygwin"); # Cygwin Perl +our $glob_win32= ($glob_win32_perl or $glob_cygwin_perl); +our $glob_netware= ($^O eq "NetWare"); # NetWare + require "lib/mtr_cases.pl"; +require "lib/mtr_im.pl"; require "lib/mtr_process.pl"; require "lib/mtr_timer.pl"; require "lib/mtr_io.pl"; @@ -97,6 +98,7 @@ require "lib/mtr_report.pl"; require "lib/mtr_diff.pl"; require "lib/mtr_match.pl"; require "lib/mtr_misc.pl"; +require "lib/mtr_stress.pl"; $Devel::Trace::TRACE= 1; @@ -128,11 +130,7 @@ our @mysqld_src_dirs= # structs. We let each struct be a separate hash. # Misc global variables - -our $glob_win32= 0; # OS and native Win32 executables -our $glob_win32_perl= 0; # ActiveState Win32 Perl -our $glob_cygwin_perl= 0; # Cygwin Perl -our $glob_cygwin_shell= undef; +our $mysql_version_id; our $glob_mysql_test_dir= undef; our $glob_mysql_bench_dir= undef; our $glob_hostname= undef; @@ -140,32 +138,30 @@ our $glob_scriptname= undef; our $glob_timers= undef; our $glob_use_running_server= 0; our $glob_use_running_ndbcluster= 0; +our $glob_use_running_ndbcluster_slave= 0; our $glob_use_embedded_server= 0; our @glob_test_mode; our $glob_basedir; -# The total result - our $path_charsetsdir; our $path_client_bindir; our $path_language; our $path_timefile; -our $path_manager_log; # Used by mysqldadmin -our $path_slave_load_tmpdir; # What is this?! +our $path_snapshot; our $path_mysqltest_log; +our $path_current_test_log; our $path_my_basedir; + our $opt_vardir; # A path but set directly on cmd line +our $path_vardir_trace; # unix formatted opt_vardir for trace files our $opt_tmpdir; # A path but set directly on cmd line our $opt_usage; our $opt_suite; -our $opt_netware; - our $opt_script_debug= 0; # Script debugging, enable with --script-debug - -# Options FIXME not all.... +our $opt_verbose= 0; # Verbose output, enable with --verbose our $exe_master_mysqld; our $exe_mysql; @@ -173,13 +169,21 @@ our $exe_mysqladmin; our $exe_mysqlbinlog; our $exe_mysql_client_test; our $exe_mysqld; -our $exe_mysqldump; # Called from test case -our $exe_mysqlimport; # Called from test case -our $exe_mysqlshow; # Called from test case +our $exe_mysqlcheck; +our $exe_mysqldump; +our $exe_mysqlslap; +our $exe_mysqlimport; +our $exe_mysqlshow; our $exe_mysql_fix_system_tables; our $exe_mysqltest; +our $exe_ndbd; +our $exe_ndb_mgmd; our $exe_slave_mysqld; +our $exe_im; our $exe_my_print_defaults; +our $exe_perror; +our $lib_udf_example; +our $exe_libtool; our $opt_bench= 0; our $opt_small_bench= 0; @@ -187,10 +191,15 @@ our $opt_big_test= 0; # Send --big-test to mysqltest our @opt_extra_mysqld_opt; -our $opt_comment; our $opt_compress; -our $opt_current_test; -our $opt_ddd; +our $opt_ssl; +our $opt_skip_ssl; +our $opt_ssl_supported; +our $opt_ps_protocol; +our $opt_sp_protocol; +our $opt_cursor_protocol; +our $opt_view_protocol; + our $opt_debug; our $opt_do_test; our @opt_cases; # The test cases names in argv @@ -198,53 +207,60 @@ our $opt_embedded_server; our $opt_extern; our $opt_fast; our $opt_force; -our $opt_reorder; +our $opt_reorder= 0; +our $opt_enable_disabled; our $opt_gcov; our $opt_gcov_err; our $opt_gcov_msg; +our $glob_debugger= 0; our $opt_gdb; our $opt_client_gdb; +our $opt_ddd; +our $opt_client_ddd; our $opt_manual_gdb; +our $opt_manual_ddd; +our $opt_manual_debug; +our $opt_debugger; +our $opt_client_debugger; our $opt_gprof; our $opt_gprof_dir; our $opt_gprof_master; our $opt_gprof_slave; -our $opt_local; -our $opt_local_master; - -our $master; # Will be struct in C +our $master; our $slave; +our $clusters; + +our $instance_manager; our $opt_ndbcluster_port; our $opt_ndbconnectstring; - -our $opt_no_manager; # Does nothing now, we never use manager -our $opt_manager_port; # Does nothing now, we never use manager - -our $opt_old_master; +our $opt_ndbcluster_port_slave; +our $opt_ndbconnectstring_slave; our $opt_record; +our $opt_check_testcases; our $opt_result_ext; our $opt_skip; our $opt_skip_rpl; -our $opt_skip_im; # --skip-im on command line will just be ignored +our $max_slave_num= 0; +our $use_innodb; our $opt_skip_test; +our $opt_skip_im; our $opt_sleep; -our $opt_ps_protocol; our $opt_sleep_time_after_restart= 1; our $opt_sleep_time_for_delete= 10; our $opt_testcase_timeout; our $opt_suite_timeout; my $default_testcase_timeout= 15; # 15 min max -my $default_suite_timeout= 120; # 2 hours max +my $default_suite_timeout= 180; # 3 hours max our $opt_socket; @@ -256,18 +272,28 @@ our $opt_start_from; our $opt_strace_client; -our $opt_timer; +our $opt_timer= 1; our $opt_user; our $opt_user_test; -our $opt_valgrind; -our $opt_valgrind_mysqld; -our $opt_valgrind_mysqltest; -our $opt_valgrind_all; +our $opt_valgrind= 0; +our $opt_valgrind_mysqld= 0; +our $opt_valgrind_mysqltest= 0; +our $default_valgrind_options= "--show-reachable=yes"; our $opt_valgrind_options; +our $opt_valgrind_path; +our $opt_callgrind; -our $opt_verbose; +our $opt_stress= ""; +our $opt_stress_suite= "main"; +our $opt_stress_mode= "random"; +our $opt_stress_threads= 5; +our $opt_stress_test_count= 0; +our $opt_stress_loop_count= 0; +our $opt_stress_test_duration= 0; +our $opt_stress_init_file= ""; +our $opt_stress_test_file= ""; our $opt_wait_for_master; our $opt_wait_for_slave; @@ -277,17 +303,30 @@ our $opt_warnings; our $opt_udiff; -our $opt_skip_ndbcluster; -our $opt_with_ndbcluster; -our $opt_with_ndbcluster_only= 0; # dummy, ignored - -our $opt_with_openssl; +our $opt_skip_ndbcluster= 0; +our $opt_skip_ndbcluster_slave= 0; +our $opt_with_ndbcluster= 0; +our $opt_with_ndbcluster_only= 0; +our $opt_ndbcluster_supported= 0; +our $opt_ndb_extra_test= 0; +our $opt_skip_master_binlog= 0; +our $opt_skip_slave_binlog= 0; our $exe_ndb_mgm; +our $exe_ndb_waiter; our $path_ndb_tools_dir; -our $path_ndb_backup_dir; -our $file_ndb_testrun_log; -our $flag_ndb_status_ok= 1; +our $path_ndb_examples_dir; +our $exe_ndb_example; +our $path_ndb_testrun_log; + +our @data_dir_lst; + +our $used_binlog_format; +our $debug_compiled_binaries; +our $glob_tot_real_time= 0; + +# Default values read from mysqld +our $default_mysqld_port; ###################################################################### # @@ -298,27 +337,36 @@ our $flag_ndb_status_ok= 1; sub main (); sub initial_setup (); sub command_line_setup (); +sub snapshot_setup (); sub executable_setup (); sub environment_setup (); sub kill_running_server (); -sub kill_and_cleanup (); -sub ndbcluster_support (); -sub ndbcluster_install (); -sub ndbcluster_start (); -sub ndbcluster_stop (); +sub cleanup_stale_files (); +sub check_ssl_support ($); +sub check_running_as_root(); +sub check_ndbcluster_support ($); +sub rm_ndbcluster_tables ($); +sub ndbcluster_start_install ($); +sub ndbcluster_start ($$); +sub ndbcluster_wait_started ($$); +sub mysqld_wait_started($); sub run_benchmarks ($); -sub run_tests (); +sub initialize_servers (); sub mysql_install_db (); sub install_db ($$); +sub copy_install_db ($$); sub run_testcase ($); +sub run_testcase_stop_servers ($$$); +sub run_testcase_start_servers ($); +sub run_testcase_check_skip_test($); sub report_failure_and_restart ($); sub do_before_start_master ($$); sub do_before_start_slave ($$); -sub mysqld_start ($$$$); +sub ndbd_start ($$$); +sub ndb_mgmd_start ($); +sub mysqld_start ($$$); sub mysqld_arguments ($$$$$); -sub stop_masters_slaves (); -sub stop_masters (); -sub stop_slaves (); +sub stop_all_servers (); sub run_mysqltest ($); sub usage ($); @@ -335,12 +383,6 @@ sub main () { initial_setup(); command_line_setup(); executable_setup(); - - if (! $opt_skip_ndbcluster and ! $opt_with_ndbcluster) - { - $opt_with_ndbcluster= ndbcluster_support(); - } - environment_setup(); signal_setup(); @@ -354,44 +396,44 @@ sub main () { gprof_prepare(); } - if ( ! $glob_use_running_server ) - { - if ( $opt_start_dirty ) - { - kill_running_server(); - } - else - { - kill_and_cleanup(); - mysql_install_db(); - -# mysql_loadstd(); FIXME copying from "std_data" .frm and -# .MGR but there are none?! - } - } - - if ( $opt_start_dirty ) - { - if ( ndbcluster_start() ) - { - mtr_error("Can't start ndbcluster"); - } - if ( mysqld_start('master',0,[],[]) ) - { - mtr_report("Servers started, exiting"); - } - else - { - mtr_error("Can't start the mysqld server"); - } - } - elsif ( $opt_bench ) + if ( $opt_bench ) { + initialize_servers(); run_benchmarks(shift); # Shift what? Extra arguments?! } + elsif ( $opt_stress ) + { + initialize_servers(); + run_stress_test() + } else { - run_tests(); + # Figure out which tests we are going to run + my $tests= collect_test_cases($opt_suite); + + # Turn off NDB and other similar options if no tests use it + my ($need_ndbcluster,$need_im); + foreach my $test (@$tests) + { + $need_ndbcluster||= $test->{ndb_test}; + $need_im||= $test->{component_id} eq 'im'; + + # Count max number of slaves used by a test case + if ( $test->{slave_num} > $max_slave_num) + { + $max_slave_num= $test->{slave_num}; + mtr_error("Too many slaves") if $max_slave_num > 3; + } + $use_innodb||= $test->{'innodb_test'}; + } + $opt_skip_ndbcluster= $opt_skip_ndbcluster_slave= 1 + unless $need_ndbcluster; + $opt_skip_im= 1 unless $need_im; + + snapshot_setup(); + initialize_servers(); + + run_suite($opt_suite, $tests); } mtr_exit(0); @@ -410,13 +452,8 @@ sub initial_setup () { $glob_scriptname= basename($0); - $glob_win32_perl= ($^O eq "MSWin32"); - $glob_cygwin_perl= ($^O eq "cygwin"); - $glob_win32= ($glob_win32_perl or $glob_cygwin_perl); - # We require that we are in the "mysql-test" directory # to run mysql-test-run - if (! -f $glob_scriptname) { mtr_error("Can't find the location for the mysql-test-run script\n" . @@ -437,16 +474,13 @@ sub initial_setup () { { # Windows programs like 'mysqld' needs Windows paths $glob_mysql_test_dir= `cygpath -m "$glob_mysql_test_dir"`; - my $shell= $ENV{'SHELL'} || "/bin/bash"; - $glob_cygwin_shell= `cygpath -w "$shell"`; # The Windows path c:\... chomp($glob_mysql_test_dir); - chomp($glob_cygwin_shell); } $glob_basedir= dirname($glob_mysql_test_dir); - $glob_mysql_bench_dir= "$glob_basedir/mysql-bench"; # FIXME make configurable - # needs to be same length to test logging (FIXME what???) - $path_slave_load_tmpdir= "../../var/tmp"; + # Expect mysql-bench to be located adjacent to the source tree, by default + $glob_mysql_bench_dir= "$glob_basedir/../mysql-bench" + unless defined $glob_mysql_bench_dir; $path_my_basedir= $opt_source_dist ? $glob_mysql_test_dir : $glob_basedir; @@ -467,9 +501,15 @@ sub command_line_setup () { # These are defaults for things that are set on the command line $opt_suite= "main"; # Special default suite - my $opt_master_myport= 9306; - my $opt_slave_myport= 9308; - $opt_ndbcluster_port= 9350; + my $opt_comment; + + my $opt_master_myport= 9306; + my $opt_slave_myport= 9308; + $opt_ndbcluster_port= 9310; + $opt_ndbcluster_port_slave= 9311; + my $im_port= 9312; + my $im_mysqld1_port= 9313; + my $im_mysqld2_port= 9314; # # To make it easier for different devs to work on the same host, @@ -488,9 +528,13 @@ sub command_line_setup () { if ( $ENV{'MTR_BUILD_THREAD'} ) { # Up to two masters, up to three slaves - $opt_master_myport= $ENV{'MTR_BUILD_THREAD'} * 10 + 10000; # and 1 - $opt_slave_myport= $opt_master_myport + 2; # and 3 4 - $opt_ndbcluster_port= $opt_master_myport + 5; + $opt_master_myport= $ENV{'MTR_BUILD_THREAD'} * 10 + 10000; # and 1 + $opt_slave_myport= $opt_master_myport + 2; # and 3 4 + $opt_ndbcluster_port= $opt_master_myport + 5; + $opt_ndbcluster_port_slave= $opt_master_myport + 6; + $im_port= $opt_master_myport + 7; + $im_mysqld1_port= $opt_master_myport + 8; + $im_mysqld2_port= $opt_master_myport + 9; } if ( $opt_master_myport < 5001 or $opt_master_myport + 10 >= 32767 ) @@ -500,6 +544,11 @@ sub command_line_setup () { "($opt_master_myport - $opt_master_myport + 10)"); } + # This is needed for test log evaluation in "gen-build-status-page" + # in all cases where the calling tool does not log the commands + # directly before it executes them, like "make test-force-pl" in RPM builds. + print "Logging: $0 ", join(" ", @ARGV), "\n"; + # Read the command line # Note: Keep list, and the order, in sync with usage at end of this file @@ -508,42 +557,63 @@ sub command_line_setup () { # Control what engine/variation to run 'embedded-server' => \$opt_embedded_server, 'ps-protocol' => \$opt_ps_protocol, + 'sp-protocol' => \$opt_sp_protocol, + 'view-protocol' => \$opt_view_protocol, + 'cursor-protocol' => \$opt_cursor_protocol, + 'ssl|with-openssl' => \$opt_ssl, + 'skip-ssl' => \$opt_skip_ssl, + 'compress' => \$opt_compress, 'bench' => \$opt_bench, 'small-bench' => \$opt_small_bench, - 'no-manager' => \$opt_no_manager, # Currently not used # Control what test suites or cases to run 'force' => \$opt_force, 'with-ndbcluster' => \$opt_with_ndbcluster, - 'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster, 'with-ndbcluster-only' => \$opt_with_ndbcluster_only, + 'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster, + 'skip-ndbcluster-slave|skip-ndb-slave' + => \$opt_skip_ndbcluster_slave, + 'ndb-extra-test' => \$opt_ndb_extra_test, + 'skip-master-binlog' => \$opt_skip_master_binlog, + 'skip-slave-binlog' => \$opt_skip_slave_binlog, 'do-test=s' => \$opt_do_test, + 'start-from=s' => \$opt_start_from, 'suite=s' => \$opt_suite, 'skip-rpl' => \$opt_skip_rpl, - 'skip-im' => \$opt_skip_im, + 'skip-im' => \$opt_skip_im, 'skip-test=s' => \$opt_skip_test, + 'big-test' => \$opt_big_test, # Specify ports 'master_port=i' => \$opt_master_myport, 'slave_port=i' => \$opt_slave_myport, - 'ndbcluster_port=i' => \$opt_ndbcluster_port, - 'manager-port=i' => \$opt_manager_port, # Currently not used + 'ndbcluster-port|ndbcluster_port=i' => \$opt_ndbcluster_port, + 'ndbcluster-port-slave=i' => \$opt_ndbcluster_port_slave, + 'im-port=i' => \$im_port, # Instance Manager port. + 'im-mysqld1-port=i' => \$im_mysqld1_port, # Port of mysqld, controlled by IM + 'im-mysqld2-port=i' => \$im_mysqld2_port, # Port of mysqld, controlled by IM # Test case authoring 'record' => \$opt_record, + 'check-testcases' => \$opt_check_testcases, - # ??? + # Extra options used when starting mysqld 'mysqld=s' => \@opt_extra_mysqld_opt, # Run test on running server 'extern' => \$opt_extern, - 'ndbconnectstring=s' => \$opt_ndbconnectstring, + 'ndb-connectstring=s' => \$opt_ndbconnectstring, + 'ndb-connectstring-slave=s' => \$opt_ndbconnectstring_slave, # Debugging 'gdb' => \$opt_gdb, - 'manual-gdb' => \$opt_manual_gdb, 'client-gdb' => \$opt_client_gdb, + 'manual-gdb' => \$opt_manual_gdb, + 'manual-debug' => \$opt_manual_debug, 'ddd' => \$opt_ddd, + 'client-ddd' => \$opt_client_ddd, + 'debugger=s' => \$opt_debugger, + 'client-debugger=s' => \$opt_client_debugger, 'strace-client' => \$opt_strace_client, 'master-binary=s' => \$exe_master_mysqld, 'slave-binary=s' => \$exe_slave_mysqld, @@ -551,48 +621,54 @@ sub command_line_setup () { # Coverage, profiling etc 'gcov' => \$opt_gcov, 'gprof' => \$opt_gprof, - 'valgrind:s' => \$opt_valgrind, - 'valgrind-mysqltest:s' => \$opt_valgrind_mysqltest, - 'valgrind-all:s' => \$opt_valgrind_all, + 'valgrind|valgrind-all' => \$opt_valgrind, + 'valgrind-mysqltest' => \$opt_valgrind_mysqltest, + 'valgrind-mysqld' => \$opt_valgrind_mysqld, 'valgrind-options=s' => \$opt_valgrind_options, + 'valgrind-path=s' => \$opt_valgrind_path, + 'callgrind' => \$opt_callgrind, + + # Stress testing + 'stress' => \$opt_stress, + 'stress-suite=s' => \$opt_stress_suite, + 'stress-threads=i' => \$opt_stress_threads, + 'stress-test-file=s' => \$opt_stress_test_file, + 'stress-init-file=s' => \$opt_stress_init_file, + 'stress-mode=s' => \$opt_stress_mode, + 'stress-loop-count=i' => \$opt_stress_loop_count, + 'stress-test-count=i' => \$opt_stress_test_count, + 'stress-test-duration=i' => \$opt_stress_test_duration, + + # Directories + 'tmpdir=s' => \$opt_tmpdir, + 'vardir=s' => \$opt_vardir, + 'benchdir=s' => \$glob_mysql_bench_dir, # Misc - 'big-test' => \$opt_big_test, 'comment=s' => \$opt_comment, - 'compress' => \$opt_compress, 'debug' => \$opt_debug, 'fast' => \$opt_fast, - 'local' => \$opt_local, - 'local-master' => \$opt_local_master, - 'netware' => \$opt_netware, - 'old-master' => \$opt_old_master, 'reorder' => \$opt_reorder, + 'enable-disabled' => \$opt_enable_disabled, 'script-debug' => \$opt_script_debug, + 'verbose' => \$opt_verbose, 'sleep=i' => \$opt_sleep, 'socket=s' => \$opt_socket, 'start-dirty' => \$opt_start_dirty, 'start-and-exit' => \$opt_start_and_exit, - 'start-from=s' => \$opt_start_from, - 'timer' => \$opt_timer, - 'tmpdir=s' => \$opt_tmpdir, + 'timer!' => \$opt_timer, 'unified-diff|udiff' => \$opt_udiff, 'user-test=s' => \$opt_user_test, 'user=s' => \$opt_user, - 'vardir=s' => \$opt_vardir, - 'verbose' => \$opt_verbose, 'wait-timeout=i' => \$opt_wait_timeout, 'testcase-timeout=i' => \$opt_testcase_timeout, 'suite-timeout=i' => \$opt_suite_timeout, 'warnings|log-warnings' => \$opt_warnings, - 'with-openssl' => \$opt_with_openssl, 'help|h' => \$opt_usage, ) or usage("Can't read options"); - if ( $opt_usage ) - { - usage(""); - } + usage("") if $opt_usage; if ( $opt_comment ) { @@ -602,11 +678,6 @@ sub command_line_setup () { print '#' x 78, "\n\n"; } - if ( $opt_with_ndbcluster_only ) - { - print "# Option '--with-ndbcluster-only' is ignored in this release.\n"; - } - foreach my $arg ( @ARGV ) { if ( $arg =~ /^--skip-/ ) @@ -629,6 +700,21 @@ sub command_line_setup () { } } + # -------------------------------------------------------------------------- + # Find out type of logging that are being used + # -------------------------------------------------------------------------- + + # NOTE if the default binlog format is changed, this has to be changed + $used_binlog_format= "stmt"; + foreach my $arg ( @opt_extra_mysqld_opt ) + { + if ( defined mtr_match_substring($arg,"binlog-format=row")) + { + $used_binlog_format= "row"; + } + } + mtr_report("Using binlog format '$used_binlog_format'"); + # -------------------------------------------------------------------------- # Set the "var/" directory, as it is the base for everything else # -------------------------------------------------------------------------- @@ -637,6 +723,15 @@ sub command_line_setup () { { $opt_vardir= "$glob_mysql_test_dir/var"; } + elsif ( $mysql_version_id < 50000 ) + { + # --vardir was specified + mtr_error("--vardir option not supported until MySQL 5.0"); + } + + $path_vardir_trace= $opt_vardir; + # Chop off any "c:", DBUG likes a unix path ex: c:/src/... => /src/... + $path_vardir_trace=~ s/^\w://; # We make the path absolute, as the server will do a chdir() before usage unless ( $opt_vardir =~ m,^/, or @@ -652,27 +747,11 @@ sub command_line_setup () { $opt_tmpdir= "$opt_vardir/tmp" unless $opt_tmpdir; $opt_tmpdir =~ s,/+$,,; # Remove ending slash if any - # FIXME maybe not needed? - $path_manager_log= "$opt_vardir/log/manager.log" - unless $path_manager_log; - $opt_current_test= "$opt_vardir/log/current_test" - unless $opt_current_test; # -------------------------------------------------------------------------- # Do sanity checks of command line arguments # -------------------------------------------------------------------------- - if ( $opt_extern and $opt_local ) - { - mtr_error("Can't use --extern and --local at the same time"); - } - - if ( ! $opt_socket ) - { # FIXME set default before reading options? -# $opt_socket= '@MYSQL_UNIX_ADDR@'; - $opt_socket= "/tmp/mysql.sock"; # FIXME - } - # -------------------------------------------------------------------------- # Look at the command line options and set script flags # -------------------------------------------------------------------------- @@ -687,7 +766,8 @@ sub command_line_setup () { $glob_use_embedded_server= 1; push(@glob_test_mode, "embedded"); $opt_skip_rpl= 1; # We never run replication with embedded - $opt_skip_ndbcluster= 1; + $opt_skip_ndbcluster= 1; # Turn off use of NDB cluster + $opt_skip_ssl= 1; # Turn off use of SSL if ( $opt_extern ) { @@ -700,11 +780,40 @@ sub command_line_setup () { push(@glob_test_mode, "ps-protocol"); } - # FIXME don't understand what this is -# if ( $opt_local_master ) -# { -# $opt_master_myport= 3306; -# } + if ( $opt_with_ndbcluster and $opt_skip_ndbcluster) + { + mtr_error("Can't specify both --with-ndbcluster and --skip-ndbcluster"); + } + + if ( $opt_ndbconnectstring ) + { + $glob_use_running_ndbcluster= 1; + mtr_error("Can't specify --ndb-connectstring and --skip-ndbcluster") + if $opt_skip_ndbcluster; + mtr_error("Can't specify --ndb-connectstring and --ndbcluster-port") + if $opt_ndbcluster_port; + } + else + { + # Set default connect string + $opt_ndbconnectstring= "host=localhost:$opt_ndbcluster_port"; + } + + if ( $opt_ndbconnectstring_slave ) + { + $glob_use_running_ndbcluster_slave= 1; + mtr_error("Can't specify ndb-connectstring_slave and " . + "--skip-ndbcluster-slave") + if $opt_skip_ndbcluster; + mtr_error("Can't specify --ndb-connectstring-slave and " . + "--ndbcluster-port-slave") + if $opt_ndbcluster_port_slave; + } + else + { + # Set default connect string + $opt_ndbconnectstring_slave= "host=localhost:$opt_ndbcluster_port_slave"; + } if ( $opt_small_bench ) { @@ -721,83 +830,83 @@ sub command_line_setup () { mtr_error("Coverage test needs the source - please use source dist"); } - if ( $opt_gdb ) + # Check debug related options + if ( $opt_gdb || $opt_client_gdb || $opt_ddd || $opt_client_ddd || + $opt_manual_gdb || $opt_manual_ddd || $opt_manual_debug || + $opt_debugger || $opt_client_debugger ) { + # Indicate that we are using debugger + $glob_debugger= 1; + # Increase timeouts $opt_wait_timeout= 300; if ( $opt_extern ) { - mtr_error("Can't use --extern with --gdb"); + mtr_error("Can't use --extern when using debugger"); } } - if ( $opt_manual_gdb ) + # Check IM arguments + if ( $glob_win32 ) { - $opt_gdb= 1; - if ( $opt_extern ) - { - mtr_error("Can't use --extern with --manual-gdb"); - } + mtr_report("Disable Instance manager - not supported on Windows"); + $opt_skip_im= 1; + } + # Check valgrind arguments + if ( $opt_valgrind or $opt_valgrind_path or defined $opt_valgrind_options) + { + mtr_report("Turning on valgrind for all executables"); + $opt_valgrind= 1; + $opt_valgrind_mysqld= 1; + $opt_valgrind_mysqltest= 1; + } + elsif ( $opt_valgrind_mysqld ) + { + mtr_report("Turning on valgrind for mysqld(s) only"); + $opt_valgrind= 1; + } + elsif ( $opt_valgrind_mysqltest ) + { + mtr_report("Turning on valgrind for mysqltest only"); + $opt_valgrind= 1; } - if ( $opt_ddd ) + if ( $opt_callgrind ) { - if ( $opt_extern ) - { - mtr_error("Can't use --extern with --ddd"); - } + mtr_report("Turning on valgrind with callgrind for mysqld(s)"); + $opt_valgrind= 1; + $opt_valgrind_mysqld= 1; + + # Set special valgrind options unless options passed on command line + $opt_valgrind_options="--trace-children=yes" + unless defined $opt_valgrind_options; } - if ( $opt_ndbconnectstring ) + if ( $opt_valgrind ) { - $glob_use_running_ndbcluster= 1; - $opt_with_ndbcluster= 1; - } - else - { - $opt_ndbconnectstring= "host=localhost:$opt_ndbcluster_port"; - } + # Set valgrind_options to default unless already defined + $opt_valgrind_options=$default_valgrind_options + unless defined $opt_valgrind_options; - if ( $opt_skip_ndbcluster ) - { - $opt_with_ndbcluster= 0; - } - - # 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_mysqld= $opt_valgrind; - $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; + mtr_report("Running valgrind with options \"$opt_valgrind_options\""); } if ( ! $opt_testcase_timeout ) { $opt_testcase_timeout= $default_testcase_timeout; - $opt_testcase_timeout*= 10 if defined $opt_valgrind; + $opt_testcase_timeout*= 10 if $opt_valgrind; } if ( ! $opt_suite_timeout ) { $opt_suite_timeout= $default_suite_timeout; - $opt_suite_timeout*= 4 if defined $opt_valgrind; + $opt_suite_timeout*= 6 if $opt_valgrind; } - if ( defined $opt_valgrind ) + # Increase times to wait for executables to start if using valgrind + if ( $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" } if ( ! $opt_user ) @@ -812,74 +921,210 @@ sub command_line_setup () { } } + # On QNX, /tmp/dir/master.sock and /tmp/dir//master.sock seem to be + # considered different, so avoid the extra slash (/) in the socket + # paths. + my $sockdir = $opt_tmpdir; + $sockdir =~ s|/+$||; + # Put this into a hash, will be a C struct $master->[0]= { + pid => 0, + type => "master", + idx => 0, path_myddir => "$opt_vardir/master-data", path_myerr => "$opt_vardir/log/master.err", path_mylog => "$opt_vardir/log/master.log", - path_mypid => "$opt_vardir/run/master.pid", - path_mysock => "$opt_tmpdir/master.sock", - path_myport => $opt_master_myport, + path_pid => "$opt_vardir/run/master.pid", + path_sock => "$sockdir/master.sock", + port => $opt_master_myport, start_timeout => 400, # enough time create innodb tables - - ndbcluster => 1, # ndbcluster not started + cluster => 0, # index in clusters list + start_opts => [], }; $master->[1]= { + pid => 0, + type => "master", + idx => 1, path_myddir => "$opt_vardir/master1-data", path_myerr => "$opt_vardir/log/master1.err", path_mylog => "$opt_vardir/log/master1.log", - path_mypid => "$opt_vardir/run/master1.pid", - path_mysock => "$opt_tmpdir/master1.sock", - path_myport => $opt_master_myport + 1, + path_pid => "$opt_vardir/run/master1.pid", + path_sock => "$sockdir/master1.sock", + port => $opt_master_myport + 1, start_timeout => 400, # enough time create innodb tables + cluster => 0, # index in clusters list + start_opts => [], }; $slave->[0]= { + pid => 0, + type => "slave", + idx => 0, path_myddir => "$opt_vardir/slave-data", path_myerr => "$opt_vardir/log/slave.err", path_mylog => "$opt_vardir/log/slave.log", - path_mypid => "$opt_vardir/run/slave.pid", - path_mysock => "$opt_tmpdir/slave.sock", - path_myport => $opt_slave_myport, + path_pid => "$opt_vardir/run/slave.pid", + path_sock => "$sockdir/slave.sock", + port => $opt_slave_myport, start_timeout => 400, + + cluster => 1, # index in clusters list + start_opts => [], }; $slave->[1]= { + pid => 0, + type => "slave", + idx => 1, path_myddir => "$opt_vardir/slave1-data", path_myerr => "$opt_vardir/log/slave1.err", path_mylog => "$opt_vardir/log/slave1.log", - path_mypid => "$opt_vardir/run/slave1.pid", - path_mysock => "$opt_tmpdir/slave1.sock", - path_myport => $opt_slave_myport + 1, + path_pid => "$opt_vardir/run/slave1.pid", + path_sock => "$sockdir/slave1.sock", + port => $opt_slave_myport + 1, start_timeout => 300, + cluster => -1, # index in clusters list + start_opts => [], }; $slave->[2]= { + pid => 0, + type => "slave", + idx => 2, path_myddir => "$opt_vardir/slave2-data", path_myerr => "$opt_vardir/log/slave2.err", path_mylog => "$opt_vardir/log/slave2.log", - path_mypid => "$opt_vardir/run/slave2.pid", - path_mysock => "$opt_tmpdir/slave2.sock", - path_myport => $opt_slave_myport + 2, + path_pid => "$opt_vardir/run/slave2.pid", + path_sock => "$sockdir/slave2.sock", + port => $opt_slave_myport + 2, start_timeout => 300, + cluster => -1, # index in clusters list + start_opts => [], }; + $instance_manager= + { + path_err => "$opt_vardir/log/im.err", + path_log => "$opt_vardir/log/im.log", + path_pid => "$opt_vardir/run/im.pid", + path_angel_pid => "$opt_vardir/run/im.angel.pid", + path_sock => "$sockdir/im.sock", + port => $im_port, + start_timeout => $master->[0]->{'start_timeout'}, + admin_login => 'im_admin', + admin_password => 'im_admin_secret', + admin_sha1 => '*598D51AD2DFF7792045D6DF3DDF9AA1AF737B295', + password_file => "$opt_vardir/im.passwd", + defaults_file => "$opt_vardir/im.cnf", + }; + + $instance_manager->{'instances'}->[0]= + { + server_id => 1, + port => $im_mysqld1_port, + path_datadir => "$opt_vardir/im_mysqld_1.data", + path_sock => "$sockdir/mysqld_1.sock", + path_pid => "$opt_vardir/run/mysqld_1.pid", + start_timeout => 400, # enough time create innodb tables + old_log_format => 1 + }; + + $instance_manager->{'instances'}->[1]= + { + server_id => 2, + port => $im_mysqld2_port, + path_datadir => "$opt_vardir/im_mysqld_2.data", + path_sock => "$sockdir/mysqld_2.sock", + path_pid => "$opt_vardir/run/mysqld_2.pid", + nonguarded => 1, + start_timeout => 400, # enough time create innodb tables + old_log_format => 1 + }; + + my $data_dir= "$opt_vardir/ndbcluster-$opt_ndbcluster_port"; + $clusters->[0]= + { + name => "Master", + nodes => 2, + port => "$opt_ndbcluster_port", + data_dir => "$data_dir", + connect_string => "$opt_ndbconnectstring", + path_pid => "$data_dir/ndb_3.pid", # Nodes + 1 + pid => 0, # pid of ndb_mgmd + installed_ok => 0, + }; + + $data_dir= "$opt_vardir/ndbcluster-$opt_ndbcluster_port_slave"; + $clusters->[1]= + { + name => "Slave", + nodes => 1, + port => "$opt_ndbcluster_port_slave", + data_dir => "$data_dir", + connect_string => "$opt_ndbconnectstring_slave", + path_pid => "$data_dir/ndb_2.pid", # Nodes + 1 + pid => 0, # pid of ndb_mgmd + installed_ok => 0, + }; + + # Init pids of ndbd's + foreach my $cluster ( @{$clusters} ) + { + for ( my $idx= 0; $idx < $cluster->{'nodes'}; $idx++ ) + { + my $nodeid= $idx+1; + $cluster->{'ndbds'}->[$idx]= + { + pid => 0, + nodeid => $nodeid, + path_pid => "$cluster->{'data_dir'}/ndb_${nodeid}.pid", + path_fs => "$cluster->{'data_dir'}/ndb_${nodeid}_fs", + }; + } + } + if ( $opt_extern ) { $glob_use_running_server= 1; $opt_skip_rpl= 1; # We don't run rpl test cases - $master->[0]->{'path_mysock'}= $opt_socket; + $master->[0]->{'path_sock'}= $opt_socket; } $path_timefile= "$opt_vardir/log/mysqltest-time"; $path_mysqltest_log= "$opt_vardir/log/mysqltest.log"; + $path_current_test_log= "$opt_vardir/log/current_test"; + $path_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log"; + + $path_snapshot= "$opt_tmpdir/snapshot_$opt_master_myport/"; +} + +sub snapshot_setup () { + + # Make a list of all data_dirs + @data_dir_lst = ( + $master->[0]->{'path_myddir'}, + $master->[1]->{'path_myddir'}); + + for (my $idx= 0; $idx < $max_slave_num; $idx++) + { + push(@data_dir_lst, $slave->[$idx]->{'path_myddir'}); + } + + unless ($opt_skip_im) + { + foreach my $instance (@{$instance_manager->{'instances'}}) + { + push(@data_dir_lst, $instance->{'path_datadir'}); + } + } } @@ -889,136 +1134,222 @@ sub command_line_setup () { # ############################################################################## + +sub check_mysqld_features () { + # + # Execute "mysqld --no-defaults --help --verbose", that will + # print out version and a list of all features and settings + # + my $found_variable_list_start= 0; + my $spec_file= "$opt_vardir/tmp/mysqld.spec"; + if ( mtr_run($exe_mysqld, + ["--no-defaults", + "--verbose", + "--help"], + "", "$spec_file", "$spec_file", "") != 0 ) + { + mtr_error("Failed to get version and list of features from %s", + $exe_mysqld); + } + + my %mysqld_variables; + my $F= IO::File->new($spec_file) or + mtr_error("can't open file \"$spec_file\": $!"); + + while ( my $line= <$F> ) + { + # First look for version + if ( !$mysql_version_id ) + { + # Look for version + if ( $line =~ /^$exe_mysqld\s\sVer\s([0-9]*)\.([0-9]*)\.([0-9]*)/ ) + { + print "Major: $1 Minor: $2 Build: $3\n"; + $mysql_version_id= $1*10000 + $2*100 + $3; + print "mysql_version_id: $mysql_version_id\n"; + } + } + else + { + if (!$found_variable_list_start) + { + # Look for start of variables list + if ( $line =~ /-*\s-*/ ) + { + $found_variable_list_start= 1; + } + } else { + # Put variables into hash + if ( $line =~ /^(\w*)[ \t]*(\w*)$/ ) + { + $mysqld_variables{$1}= $2; + } + } + } + } + mtr_error("Could not find version of MySQL") unless $mysql_version_id; + + check_ndbcluster_support(\%mysqld_variables); + check_ssl_support(\%mysqld_variables); + check_debug_support(\%mysqld_variables); + + if ( $mysql_version_id < 50000 ) + { + # Instance manager is not supported until 5.0 + $opt_skip_im= 1; + } + + # Set default values from mysqld_variables + $opt_socket= %mysqld_variables->{'socket'}; + $default_mysqld_port = %mysqld_variables->{'port'}; +} + + sub executable_setup () { - if ( $opt_source_dist ) + # + # Check if libtool is available in this distribution/clone + # we need it when valgrinding or debugging non installed binary + # Otherwise valgrind will valgrind the libtool wrapper or bash + # and gdb will not find the real executable to debug + # + if ( -x "../libtool") { - if ( $glob_win32 ) + $exe_libtool= "../libtool"; + if ($opt_valgrind or $glob_debugger) { - $path_client_bindir= mtr_path_exists("$glob_basedir/client_release", - "$glob_basedir/bin"); - $exe_mysqld= mtr_exe_exists ("$path_client_bindir/mysqld-nt", - "$path_client_bindir/mysqld", - "$path_client_bindir/mysqld-debug", - "$path_client_bindir/mysqld-max", - "$path_client_bindir/mysqld-max-nt"); - $path_language= mtr_path_exists("$glob_basedir/share/english/"); - $path_charsetsdir= mtr_path_exists("$glob_basedir/share/charsets"); - $exe_my_print_defaults= - mtr_exe_exists("$path_client_bindir/my_print_defaults"); + mtr_report("Using \"$exe_libtool\" when running valgrind or debugger"); } - else - { - $path_client_bindir= mtr_path_exists("$glob_basedir/client"); - $exe_mysqld= mtr_exe_exists ("$glob_basedir/sql/mysqld"); - $path_language= mtr_path_exists("$glob_basedir/sql/share/english/"); - $path_charsetsdir= mtr_path_exists("$glob_basedir/sql/share/charsets"); - $exe_my_print_defaults= - mtr_exe_exists("$glob_basedir/extra/my_print_defaults"); - } - - if ( $glob_use_embedded_server ) - { - my $path_examples= "$glob_basedir/libmysqld/examples"; - $exe_mysqltest= mtr_exe_exists("$path_examples/mysqltest_embedded"); - $exe_mysql_client_test= - mtr_exe_exists("$path_examples/mysql_client_test_embedded", - "/usr/bin/false"); - } - else - { - if ( $opt_valgrind_mysqltest ) - { - # client/mysqltest might be a libtool .sh script, so look for real exe - # to avoid valgrinding bash ;) - $exe_mysqltest= - mtr_exe_exists("$path_client_bindir/.libs/lt-mysqltest", - "$path_client_bindir/.libs/mysqltest", - "$path_client_bindir/mysqltest"); - } - else - { - $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); - } - $exe_mysql_client_test= - mtr_exe_exists("$glob_basedir/tests/mysql_client_test", - "/usr/bin/false"); - } - $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); - $exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport"); - $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); - $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); - $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); - $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); - $exe_mysql_fix_system_tables= - mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables"); - $path_ndb_tools_dir= mtr_path_exists("$glob_basedir/ndb/tools"); - $exe_ndb_mgm= "$glob_basedir/ndb/src/mgmclient/ndb_mgm"; } - else - { - $path_client_bindir= mtr_path_exists("$glob_basedir/bin"); - $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); - $exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport"); - $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); - $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); - $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); - $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); - $exe_mysql_fix_system_tables= - mtr_script_exists("$path_client_bindir/mysql_fix_privilege_tables", - "$glob_basedir/scripts/mysql_fix_privilege_tables"); - $exe_my_print_defaults= - mtr_exe_exists("$path_client_bindir/my_print_defaults"); - $path_language= mtr_path_exists("$glob_basedir/share/mysql/english/", - "$glob_basedir/share/english/"); - $path_charsetsdir= mtr_path_exists("$glob_basedir/share/mysql/charsets", - "$glob_basedir/share/charsets"); + # Look for the path where to find the client binaries + $path_client_bindir= mtr_path_exists("$glob_basedir/client", + "$glob_basedir/client_release", + "$glob_basedir/client_debug", + "$glob_basedir/client/release", + "$glob_basedir/client/debug", + "$glob_basedir/bin"); - if ( $glob_win32 ) - { - $exe_mysqld= mtr_exe_exists ("$glob_basedir/bin/mysqld-nt", - "$glob_basedir/bin/mysqld", - "$glob_basedir/bin/mysqld-debug",); - } - else - { - $exe_mysqld= mtr_exe_exists ("$glob_basedir/libexec/mysqld", - "$glob_basedir/bin/mysqld"); - } - - if ( $glob_use_embedded_server ) - { - $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest_embedded"); - $exe_mysql_client_test= - mtr_exe_exists("$glob_basedir/tests/mysql_client_test_embedded", - "$path_client_bindir/mysql_client_test_embedded", - "/usr/bin/false"); - } - else - { - $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); - $exe_mysql_client_test= - mtr_exe_exists("$path_client_bindir/mysql_client_test", - "/usr/bin/false"); # FIXME temporary - } - - $path_ndb_tools_dir= "$glob_basedir/bin"; - $exe_ndb_mgm= "$glob_basedir/bin/ndb_mgm"; - } + # Look for the mysqld executable + $exe_mysqld= mtr_exe_exists ("$glob_basedir/sql/mysqld", + "$path_client_bindir/mysqld-max-nt", + "$path_client_bindir/mysqld-max", + "$path_client_bindir/mysqld-nt", + "$path_client_bindir/mysqld", + "$path_client_bindir/mysqld-debug", + "$path_client_bindir/mysqld-max", + "$glob_basedir/libexec/mysqld", + "$glob_basedir/sql/release/mysqld", + "$glob_basedir/sql/debug/mysqld"); $exe_master_mysqld= $exe_master_mysqld || $exe_mysqld; $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld; - $path_ndb_backup_dir= - "$opt_vardir/ndbcluster-$opt_ndbcluster_port"; - $file_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log"; + # Use the mysqld found above to find out what features are available + check_mysqld_features(); + + # Look for language files and charsetsdir, use same share + my $path_share= mtr_path_exists("$glob_basedir/share", + "$glob_basedir/sql/share", + "$glob_basedir/share/mysql", + "$glob_basedir/share"); + + $path_language= mtr_path_exists("$path_share/english"); + $path_charsetsdir= mtr_path_exists("$path_share/charsets"); + + # Look for my_print_defaults + $exe_my_print_defaults= + mtr_exe_exists("$path_client_bindir/my_print_defaults", + "$glob_basedir/extra/my_print_defaults", + "$glob_basedir/extra/release/my_print_defaults", + "$glob_basedir/extra/debug/my_print_defaults"); + + # Look for perror + $exe_perror= mtr_exe_exists("$glob_basedir/extra/perror", + "$path_client_bindir/perror", + "$glob_basedir/extra/release/perror", + "$glob_basedir/extra/debug/perror"); + + + if ( ! $opt_skip_im ) + { + # Look for instance manager binary - mysqlmanager + $exe_im= + mtr_exe_exists( + "$glob_basedir/server-tools/instance-manager/mysqlmanager", + "$glob_basedir/libexec/mysqlmanager"); + } + + # Look for the client binaries + $exe_mysqlcheck= mtr_exe_exists("$path_client_bindir/mysqlcheck"); + $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); + $exe_mysqlimport= mtr_exe_exists("$path_client_bindir/mysqlimport"); + $exe_mysqlshow= mtr_exe_exists("$path_client_bindir/mysqlshow"); + $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); + $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); + $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); + + # Look for mysql_fix_system_table script + $exe_mysql_fix_system_tables= + mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables", + "$path_client_bindir/mysql_fix_privilege_tables"); + + if ( $opt_with_ndbcluster) + { + # Look for ndb tols and binaries + $path_ndb_tools_dir= mtr_path_exists("$glob_basedir/ndb/tools", + "$glob_basedir/bin"); + $exe_ndb_mgm= mtr_exe_exists("$glob_basedir/ndb/src/mgmclient/ndb_mgm", + "$glob_basedir/bin/ndb_mgm"); + } + + # Look for the udf_example library + $lib_udf_example= + mtr_file_exists("$glob_basedir/sql/.libs/udf_example.so"); + + + # Look for mysqltest executable + if ( $glob_use_embedded_server ) + { + $exe_mysqltest= + mtr_exe_exists("$glob_basedir/libmysqld/examples/mysqltest_embedded", + "$path_client_bindir/mysqltest_embedded"); + } + else + { + $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest"); + + + } + + # Look for mysql_client_test executable + if ( $glob_use_embedded_server ) + { + $exe_mysql_client_test= + mtr_exe_exists("$glob_basedir/libmysqld/examples/mysql_client_test_embedded", + "$glob_basedir/tests/mysqltest_embedded"); + } + else + { + $exe_mysql_client_test= + mtr_exe_exists("$glob_basedir/tests/mysql_client_test"); + } +} + + +sub generate_cmdline_mysqldump ($) { + my($mysqld) = @_; + return + "$exe_mysqldump --no-defaults -uroot " . + "--port=$mysqld->{'port'} " . + "--socket=$mysqld->{'path_sock'} --password="; } ############################################################################## # -# Set environment to be used by childs of this process +# Set environment to be used by childs of this process for +# things that are constant duting the whole lifetime of mysql-test-run.pl # ############################################################################## @@ -1026,65 +1357,320 @@ sub executable_setup () { sub environment_setup () { - # -------------------------------------------------------------------------- - # We might not use a standard installation directory, like /usr/lib. - # Set LD_LIBRARY_PATH to make sure we find our installed libraries. - # -------------------------------------------------------------------------- + umask(022); - unless ( $opt_source_dist ) + my @ld_library_paths; + + # -------------------------------------------------------------------------- + # Setup LD_LIBRARY_PATH so the libraries from this distro/clone + # are used in favor of the system installed ones + # -------------------------------------------------------------------------- + if ( $opt_source_dist ) { - $ENV{'LD_LIBRARY_PATH'}= - "$glob_basedir/lib" . - ($ENV{'LD_LIBRARY_PATH'} ? ":$ENV{'LD_LIBRARY_PATH'}" : ""); - $ENV{'DYLD_LIBRARY_PATH'}= - "$glob_basedir/lib" . - ($ENV{'DYLD_LIBRARY_PATH'} ? ":$ENV{'DYLD_LIBRARY_PATH'}" : ""); + push(@ld_library_paths, "$glob_basedir/libmysql/.libs/", + "$glob_basedir/libmysql_r/.libs/"); } + else + { + push(@ld_library_paths, "$glob_basedir/lib"); + } + + # -------------------------------------------------------------------------- + # Add the path where libndbclient can be found + # -------------------------------------------------------------------------- + if ( $opt_ndbcluster_supported ) + { + push(@ld_library_paths, "$glob_basedir/storage/ndb/src/.libs"); + } + + # -------------------------------------------------------------------------- + # Add the path where mysqld will find udf_example.so + # -------------------------------------------------------------------------- + if ( $lib_udf_example ) + { + push(@ld_library_paths, dirname($lib_udf_example)); + } + + # -------------------------------------------------------------------------- + # Valgrind need to be run with debug libraries otherwise it's almost + # impossible to add correct supressions, that means if "/usr/lib/debug" + # is available, it should be added to + # LD_LIBRARY_PATH + # -------------------------------------------------------------------------- + my $debug_libraries_path= "/usr/lib/debug"; + if ( $opt_valgrind and -d $debug_libraries_path ) + { + push(@ld_library_paths, $debug_libraries_path); + } + + $ENV{'LD_LIBRARY_PATH'}= join(":", @ld_library_paths, + split(':', $ENV{'LD_LIBRARY_PATH'})); + mtr_debug("LD_LIBRARY_PATH: $ENV{'LD_LIBRARY_PATH'}"); + + $ENV{'DYLD_LIBRARY_PATH'}= join(":", @ld_library_paths, + split(':', $ENV{'DYLD_LIBRARY_PATH'})); + mtr_debug("DYLD_LIBRARY_PATH: $ENV{'DYLD_LIBRARY_PATH'}"); + # -------------------------------------------------------------------------- # Also command lines in .opt files may contain env vars # -------------------------------------------------------------------------- + $ENV{'CHARSETSDIR'}= $path_charsetsdir; $ENV{'UMASK'}= "0660"; # The octal *string* $ENV{'UMASK_DIR'}= "0770"; # The octal *string* $ENV{'LC_COLLATE'}= "C"; $ENV{'USE_RUNNING_SERVER'}= $glob_use_running_server; $ENV{'MYSQL_TEST_DIR'}= $glob_mysql_test_dir; - $ENV{'MYSQL_TEST_WINDIR'}= $glob_mysql_test_dir; $ENV{'MYSQLTEST_VARDIR'}= $opt_vardir; - $ENV{'MASTER_WINMYSOCK'}= $master->[0]->{'path_mysock'}; - $ENV{'MASTER_MYSOCK'}= $master->[0]->{'path_mysock'}; - $ENV{'MASTER_MYSOCK1'}= $master->[1]->{'path_mysock'}; - $ENV{'MASTER_MYPORT'}= $master->[0]->{'path_myport'}; - $ENV{'MASTER_MYPORT1'}= $master->[1]->{'path_myport'}; - $ENV{'SLAVE_MYPORT'}= $slave->[0]->{'path_myport'}; - $ENV{'SLAVE_MYPORT1'}= $slave->[1]->{'path_myport'}; - $ENV{'SLAVE_MYPORT2'}= $slave->[2]->{'path_myport'}; -# $ENV{'MYSQL_TCP_PORT'}= '@MYSQL_TCP_PORT@'; # FIXME - $ENV{'MYSQL_TCP_PORT'}= 3306; - - $ENV{'NDBCLUSTER_PORT'}= $opt_ndbcluster_port; - - if ( $glob_cygwin_perl ) - { - foreach my $key ('MYSQL_TEST_WINDIR','MASTER_MYSOCK') - { - $ENV{$key}= `cygpath -w $ENV{$key}`; - $ENV{$key} =~ s,\\,\\\\,g; - chomp($ENV{$key}); - } - } + $ENV{'MYSQL_TMP_DIR'}= $opt_tmpdir; + $ENV{'MASTER_MYSOCK'}= $master->[0]->{'path_sock'}; + $ENV{'MASTER_MYSOCK1'}= $master->[1]->{'path_sock'}; + $ENV{'MASTER_MYPORT'}= $master->[0]->{'port'}; + $ENV{'MASTER_MYPORT1'}= $master->[1]->{'port'}; + $ENV{'SLAVE_MYSOCK'}= $slave->[0]->{'path_sock'}; + $ENV{'SLAVE_MYPORT'}= $slave->[0]->{'port'}; + $ENV{'SLAVE_MYPORT1'}= $slave->[1]->{'port'}; + $ENV{'SLAVE_MYPORT2'}= $slave->[2]->{'port'}; + $ENV{'MYSQL_TCP_PORT'}= $default_mysqld_port; $ENV{MTR_BUILD_THREAD}= 0 unless $ENV{MTR_BUILD_THREAD}; # Set if not set + # ---------------------------------------------------- + # Setup env for NDB + # ---------------------------------------------------- + $ENV{'NDB_MGM'}= $exe_ndb_mgm; + + $ENV{'NDBCLUSTER_PORT'}= $opt_ndbcluster_port; + $ENV{'NDBCLUSTER_PORT_SLAVE'}= $opt_ndbcluster_port_slave; + + $ENV{'NDB_EXTRA_TEST'}= $opt_ndb_extra_test; + + $ENV{'NDB_BACKUP_DIR'}= $clusters->[0]->{'data_dir'}; + $ENV{'NDB_DATA_DIR'}= $clusters->[0]->{'data_dir'}; + $ENV{'NDB_TOOLS_DIR'}= $path_ndb_tools_dir; + $ENV{'NDB_TOOLS_OUTPUT'}= $path_ndb_testrun_log; + $ENV{'NDB_CONNECTSTRING'}= $opt_ndbconnectstring; + + $ENV{'NDB_EXAMPLES_DIR'}= $path_ndb_examples_dir; + $ENV{'MY_NDB_EXAMPLES_BINARY'}= $exe_ndb_example; + $ENV{'NDB_EXAMPLES_OUTPUT'}= $path_ndb_testrun_log; + + # ---------------------------------------------------- + # Setup env for IM + # ---------------------------------------------------- + $ENV{'IM_EXE'}= $exe_im; + $ENV{'IM_PATH_PID'}= $instance_manager->{path_pid}; + $ENV{'IM_PATH_ANGEL_PID'}= $instance_manager->{path_angel_pid}; + $ENV{'IM_PORT'}= $instance_manager->{port}; + $ENV{'IM_DEFAULTS_PATH'}= $instance_manager->{defaults_file}; + $ENV{'IM_PASSWORD_PATH'}= $instance_manager->{password_file}; + + $ENV{'IM_MYSQLD1_SOCK'}= $instance_manager->{instances}->[0]->{path_sock}; + $ENV{'IM_MYSQLD1_PORT'}= $instance_manager->{instances}->[0]->{port}; + $ENV{'IM_MYSQLD1_PATH_PID'}=$instance_manager->{instances}->[0]->{path_pid}; + $ENV{'IM_MYSQLD2_SOCK'}= $instance_manager->{instances}->[1]->{path_sock}; + $ENV{'IM_MYSQLD2_PORT'}= $instance_manager->{instances}->[1]->{port}; + $ENV{'IM_MYSQLD2_PATH_PID'}=$instance_manager->{instances}->[1]->{path_pid}; + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlcheck + # ---------------------------------------------------- + my $cmdline_mysqlcheck= + "$exe_mysqlcheck --no-defaults -uroot " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password="; + + if ( $opt_debug ) + { + $cmdline_mysqlcheck .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlcheck.trace"; + } + $ENV{'MYSQL_CHECK'}= $cmdline_mysqlcheck; + + # ---------------------------------------------------- + # Setup env to childs can execute myqldump + # ---------------------------------------------------- + my $cmdline_mysqldump= generate_cmdline_mysqldump($master->[0]); + my $cmdline_mysqldumpslave= generate_cmdline_mysqldump($slave->[0]); + + if ( $opt_debug ) + { + $cmdline_mysqldump .= + " --debug=d:t:A,$path_vardir_trace/log/mysqldump-master.trace"; + $cmdline_mysqldumpslave .= + " --debug=d:t:A,$path_vardir_trace/log/mysqldump-slave.trace"; + } + $ENV{'MYSQL_DUMP'}= $cmdline_mysqldump; + $ENV{'MYSQL_DUMP_SLAVE'}= $cmdline_mysqldumpslave; + + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlslap + # ---------------------------------------------------- + unless ( $glob_win32 ) + { + my $cmdline_mysqlslap= + "$exe_mysqlslap -uroot " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password= " . + "--lock-directory=$opt_tmpdir"; + + if ( $opt_debug ) + { + $cmdline_mysqlslap .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlslap.trace"; + } + $ENV{'MYSQL_SLAP'}= $cmdline_mysqlslap; + } + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlimport + # ---------------------------------------------------- + my $cmdline_mysqlimport= + "$exe_mysqlimport -uroot " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password="; + + if ( $opt_debug ) + { + $cmdline_mysqlimport .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlimport.trace"; + } + $ENV{'MYSQL_IMPORT'}= $cmdline_mysqlimport; + + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlshow + # ---------------------------------------------------- + my $cmdline_mysqlshow= + "$exe_mysqlshow -uroot " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password="; + + if ( $opt_debug ) + { + $cmdline_mysqlshow .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlshow.trace"; + } + $ENV{'MYSQL_SHOW'}= $cmdline_mysqlshow; + + # ---------------------------------------------------- + # Setup env so childs can execute mysqlbinlog + # ---------------------------------------------------- + my $cmdline_mysqlbinlog= + "$exe_mysqlbinlog" . + " --no-defaults --local-load=$opt_tmpdir"; + if ( $mysql_version_id >= 50000 ) + { + $cmdline_mysqlbinlog .=" --character-sets-dir=$path_charsetsdir"; + } + + if ( $opt_debug ) + { + $cmdline_mysqlbinlog .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlbinlog.trace"; + } + $ENV{'MYSQL_BINLOG'}= $cmdline_mysqlbinlog; + + # ---------------------------------------------------- + # Setup env so childs can execute mysql + # ---------------------------------------------------- + my $cmdline_mysql= + "$exe_mysql --no-defaults --host=localhost --user=root --password= " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} ". + "--character-sets-dir=$path_charsetsdir"; + + $ENV{'MYSQL'}= $cmdline_mysql; + + # ---------------------------------------------------- + # Setup env so childs can execute mysql_client_test + # ---------------------------------------------------- + my $cmdline_mysql_client_test= + "$exe_mysql_client_test --no-defaults --testcase --user=root --silent " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'}"; + if ( $mysql_version_id >= 50000 ) + { + $cmdline_mysql_client_test .=" --vardir=$opt_vardir"; + } + + if ( $opt_debug ) + { + $cmdline_mysql_client_test .= + " --debug=d:t:A,$path_vardir_trace/log/mysql_client_test.trace"; + } + + if ( $glob_use_embedded_server ) + { + $cmdline_mysql_client_test.= + " -A --language=$path_language" . + " -A --datadir=$slave->[0]->{'path_myddir'}" . + " -A --character-sets-dir=$path_charsetsdir"; + } + $ENV{'MYSQL_CLIENT_TEST'}= $cmdline_mysql_client_test; + + + # ---------------------------------------------------- + # Setup env so childs can execute mysql_fix_system_tables + # ---------------------------------------------------- + my $cmdline_mysql_fix_system_tables= + "$exe_mysql_fix_system_tables --no-defaults --host=localhost --user=root --password= " . + "--basedir=$glob_basedir --bindir=$path_client_bindir --verbose " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'}"; + + $ENV{'MYSQL_FIX_SYSTEM_TABLES'}= $cmdline_mysql_fix_system_tables; + + # ---------------------------------------------------- + # Setup env so childs can execute my_print_defaults + # ---------------------------------------------------- + $ENV{'MYSQL_MY_PRINT_DEFAULTS'}= $exe_my_print_defaults; + + + # ---------------------------------------------------- + # Setup env so childs can execute perror + # ---------------------------------------------------- + $ENV{'MY_PERROR'}= $exe_perror; + + # ---------------------------------------------------- + # Add the path where mysqld will find udf_example.so + # ---------------------------------------------------- + $ENV{'UDF_EXAMPLE_LIB'}= + ($lib_udf_example ? basename($lib_udf_example) : ""); + + $ENV{'LD_LIBRARY_PATH'}= + ($lib_udf_example ? dirname($lib_udf_example) : "") . + ($ENV{'LD_LIBRARY_PATH'} ? ":$ENV{'LD_LIBRARY_PATH'}" : ""); + + + # ---------------------------------------------------- # We are nice and report a bit about our settings - print "Using MTR_BUILD_THREAD = $ENV{MTR_BUILD_THREAD}\n"; - print "Using MASTER_MYPORT = $ENV{MASTER_MYPORT}\n"; - print "Using MASTER_MYPORT1 = $ENV{MASTER_MYPORT1}\n"; - print "Using SLAVE_MYPORT = $ENV{SLAVE_MYPORT}\n"; - print "Using SLAVE_MYPORT1 = $ENV{SLAVE_MYPORT1}\n"; - print "Using SLAVE_MYPORT2 = $ENV{SLAVE_MYPORT2}\n"; - print "Using NDBCLUSTER_PORT = $ENV{NDBCLUSTER_PORT}\n"; + # ---------------------------------------------------- + if (!$opt_extern) + { + print "Using MTR_BUILD_THREAD = $ENV{MTR_BUILD_THREAD}\n"; + print "Using MASTER_MYPORT = $ENV{MASTER_MYPORT}\n"; + print "Using MASTER_MYPORT1 = $ENV{MASTER_MYPORT1}\n"; + print "Using SLAVE_MYPORT = $ENV{SLAVE_MYPORT}\n"; + print "Using SLAVE_MYPORT1 = $ENV{SLAVE_MYPORT1}\n"; + print "Using SLAVE_MYPORT2 = $ENV{SLAVE_MYPORT2}\n"; + if ( ! $opt_skip_ndbcluster ) + { + print "Using NDBCLUSTER_PORT = $ENV{NDBCLUSTER_PORT}\n"; + if ( ! $opt_skip_ndbcluster_slave ) + { + print "Using NDBCLUSTER_PORT_SLAVE = $ENV{NDBCLUSTER_PORT_SLAVE}\n"; + } + } + if ( ! $opt_skip_im ) + { + print "Using IM_PORT = $ENV{IM_PORT}\n"; + print "Using IM_MYSQLD1_PORT = $ENV{IM_MYSQLD1_PORT}\n"; + print "Using IM_MYSQLD2_PORT = $ENV{IM_MYSQLD2_PORT}\n"; + } + } } @@ -1099,10 +1685,11 @@ sub signal_setup () { $SIG{INT}= \&handle_int_signal; } + sub handle_int_signal () { $SIG{INT}= 'DEFAULT'; # If we get a ^C again, we die... mtr_warning("got INT signal, cleaning up....."); - stop_masters_slaves(); + stop_all_servers(); mtr_error("We die from ^C signal from user"); } @@ -1118,31 +1705,24 @@ sub kill_running_server () { if ( $opt_fast or $glob_use_embedded_server ) { # FIXME is embedded server really using PID files?! - unlink($master->[0]->{'path_mypid'}); - unlink($master->[1]->{'path_mypid'}); - unlink($slave->[0]->{'path_mypid'}); - unlink($slave->[1]->{'path_mypid'}); - unlink($slave->[2]->{'path_mypid'}); + unlink($master->[0]->{'path_pid'}); + unlink($master->[1]->{'path_pid'}); + unlink($slave->[0]->{'path_pid'}); + unlink($slave->[1]->{'path_pid'}); + unlink($slave->[2]->{'path_pid'}); } else { # Ensure that no old mysqld test servers are running # This is different from terminating processes we have - # started from ths run of the script, this is terminating + # started from this run of the script, this is terminating # leftovers from previous runs. - mtr_report("Killing Possible Leftover Processes"); - mkpath("$opt_vardir/log"); # Needed for mysqladmin log mtr_kill_leftovers(); - - ndbcluster_stop(); - $master->[0]->{'ndbcluster'}= 1; - } + } } -sub kill_and_cleanup () { - - kill_running_server (); +sub cleanup_stale_files () { mtr_report("Removing Stale Files"); @@ -1186,16 +1766,7 @@ sub kill_and_cleanup () { mkpath("$opt_vardir/tmp"); mkpath($opt_tmpdir) if $opt_tmpdir ne "$opt_vardir/tmp"; - # FIXME do we really need to create these all, or are they - # created for us when tables are created? - - my @data_dir_lst = ( - $master->[0]->{'path_myddir'}, - $master->[1]->{'path_myddir'}, - $slave->[0]->{'path_myddir'}, - $slave->[1]->{'path_myddir'}, - $slave->[2]->{'path_myddir'}); - + # Remove old and create new data dirs foreach my $data_dir (@data_dir_lst) { rmtree("$data_dir"); @@ -1214,104 +1785,353 @@ sub kill_and_cleanup () { mkpath("$opt_vardir/std_data_ln"); opendir(DIR, "$glob_mysql_test_dir/std_data") or mtr_error("Can't find the std_data directory: $!"); - for my $elem ( readdir(DIR) ) { - next if -d "$glob_mysql_test_dir/std_data/$elem"; - copy("$glob_mysql_test_dir/std_data/$elem", "$opt_vardir/std_data_ln/$elem"); + for(readdir(DIR)) { + next if -d "$glob_mysql_test_dir/std_data/$_"; + copy("$glob_mysql_test_dir/std_data/$_", "$opt_vardir/std_data_ln/$_"); } closedir(DIR); } } +sub check_running_as_root () { + # Check if running as root + # i.e a file can be read regardless what mode we set it to + my $test_file= "$opt_vardir/test_running_as_root.txt"; + mtr_tofile($test_file, "MySQL"); + chmod(oct("0000"), $test_file); + + my $result=""; + if (open(FILE,"<",$test_file)) + { + $result= join('', ); + close FILE; + } + + chmod(oct("0755"), $test_file); + unlink($test_file); + + $ENV{'MYSQL_TEST_ROOT'}= "NO"; + if ($result eq "MySQL") + { + mtr_warning("running this script as _root_ will cause some " . + "tests to be skipped"); + $ENV{'MYSQL_TEST_ROOT'}= "YES"; + } +} + + +sub check_ssl_support ($) { + my $mysqld_variables= shift; + + if ($opt_skip_ssl || $opt_extern) + { + mtr_report("Skipping SSL"); + $opt_ssl_supported= 0; + $opt_ssl= 0; + return; + } + + if ( $mysqld_variables->{'ssl'} eq "FALSE" ) + { + if ( $opt_ssl) + { + mtr_error("Couldn't find support for SSL"); + return; + } + mtr_report("Skipping SSL, mysqld not compiled with SSL"); + $opt_ssl_supported= 0; + $opt_ssl= 0; + return; + } + mtr_report("Setting mysqld to support SSL connections"); + $opt_ssl_supported= 1; +} + + +sub check_debug_support ($) { + my $mysqld_variables= shift; + + if ( $mysqld_variables->{'debug'} ) + { + #mtr_report("Binaries are not debug compiled"); + $debug_compiled_binaries= 0; + + if ( $opt_debug ) + { + mtr_error("Can't use --debug, binaries does not support it"); + } + return; + } + mtr_report("Binaries are debug compiled"); + $debug_compiled_binaries= 1; +} + ############################################################################## # # Start the ndb cluster # ############################################################################## -sub ndbcluster_support () { +sub check_ndbcluster_support ($) { + my $mysqld_variables= shift; - # check ndbcluster support by testing using a switch - # that is only available in that case - if ( mtr_run($exe_mysqld, - ["--no-defaults", - "--ndb-use-exact-count", - "--help"], - "", "/dev/null", "/dev/null", "") != 0 ) - { - mtr_report("No ndbcluster support"); - return 0; - } - mtr_report("Has ndbcluster support"); - return 1; -} - -# FIXME why is there a different start below?! - -sub ndbcluster_install () { - - if ( ! $opt_with_ndbcluster or $glob_use_running_ndbcluster ) - { - return 0; - } - mtr_report("Install ndbcluster"); - my $ndbcluster_opts= $opt_bench ? "" : "--small"; - my $ndbcluster_port_base= $opt_ndbcluster_port + 2; - if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", - ["--port=$opt_ndbcluster_port", - "--port-base=$ndbcluster_port_base", - "--data-dir=$opt_vardir", - $ndbcluster_opts, - "--initial"], - "", "", "", "") ) - { - mtr_error("Error ndbcluster_install"); - return 1; - } - - ndbcluster_stop(); - $master->[0]->{'ndbcluster'}= 1; - - return 0; -} - -sub ndbcluster_start () { - - if ( ! $opt_with_ndbcluster or $glob_use_running_ndbcluster ) - { - return 0; - } - # FIXME, we want to _append_ output to file $file_ndb_testrun_log instead of /dev/null - if ( mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", - ["--port=$opt_ndbcluster_port", - "--data-dir=$opt_vardir"], - "", "/dev/null", "", "") ) - { - mtr_error("Error ndbcluster_start"); - return 1; - } - - return 0; -} - -sub ndbcluster_stop () { - - if ( ! $opt_with_ndbcluster or $glob_use_running_ndbcluster ) + if ($opt_skip_ndbcluster) { + mtr_report("Skipping ndbcluster"); + $opt_skip_ndbcluster_slave= 1; return; } - my $ndbcluster_port_base= $opt_ndbcluster_port + 2; - # FIXME, we want to _append_ output to file $file_ndb_testrun_log instead of /dev/null - mtr_run("$glob_mysql_test_dir/ndb/ndbcluster", - ["--port=$opt_ndbcluster_port", - "--data-dir=$opt_vardir", - "--stop"], - "", "/dev/null", "", ""); + if ( $mysqld_variables->{'ndbcluster'} eq "FALSE") + { + mtr_report("Skipping ndbcluster, mysqld not compiled with ndbcluster"); + $opt_skip_ndbcluster= 1; + $opt_skip_ndbcluster_slave= 1; + return; + } + $opt_ndbcluster_supported= 1; + mtr_report("Using ndbcluster when necessary, mysqld supports it"); return; } +sub ndbcluster_start_install ($) { + my $cluster= shift; + + if ( $opt_skip_ndbcluster or $glob_use_running_ndbcluster ) + { + return 0; + } + + mtr_report("Installing $cluster->{'name'} Cluster"); + + mkdir($cluster->{'data_dir'}); + + # Create a config file from template + my $ndb_no_ord=512; + my $ndb_no_attr=2048; + my $ndb_con_op=105000; + my $ndb_dmem="80M"; + my $ndb_imem="24M"; + my $ndb_pbmem="32M"; + my $nodes= $cluster->{'nodes'}; + my $ndb_host= "localhost"; + my $ndb_diskless= 0; + + if (!$opt_bench) + { + # Use a smaller configuration + $ndb_no_ord=32; + $ndb_con_op=5000; + $ndb_dmem="20M"; + $ndb_imem="1M"; + $ndb_pbmem="4M"; + } + + my $config_file_template= "ndb/ndb_config_${nodes}_node.ini"; + my $config_file= "$cluster->{'data_dir'}/config.ini"; + + open(IN, $config_file_template) + or mtr_error("Can't open $config_file_template: $!"); + open(OUT, ">", $config_file) + or mtr_error("Can't write to $config_file: $!"); + while () + { + chomp; + + s/CHOOSE_MaxNoOfAttributes/$ndb_no_attr/; + s/CHOOSE_MaxNoOfOrderedIndexes/$ndb_no_ord/; + s/CHOOSE_MaxNoOfConcurrentOperations/$ndb_con_op/; + s/CHOOSE_DataMemory/$ndb_dmem/; + s/CHOOSE_IndexMemory/$ndb_imem/; + s/CHOOSE_Diskless/$ndb_diskless/; + s/CHOOSE_HOSTNAME_.*/$ndb_host/; + s/CHOOSE_FILESYSTEM/$cluster->{'data_dir'}/; + s/CHOOSE_PORT_MGM/$cluster->{'port'}/; + s/CHOOSE_DiskPageBufferMemory/$ndb_pbmem/; + + print OUT "$_ \n"; + } + close OUT; + close IN; + + + # Start cluster with "--initial" + + ndbcluster_start($cluster, "--initial"); + + return 0; +} + + +sub ndbcluster_wait_started($$){ + my $cluster= shift; + my $ndb_waiter_extra_opt= shift; + my $path_waiter_log= "$cluster->{'data_dir'}/ndb_waiter.log"; + my $args; + + mtr_init_args(\$args); + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--core"); + mtr_add_arg($args, "--ndb-connectstring=%s", $cluster->{'connect_string'}); + mtr_add_arg($args, "--timeout=60"); + + if ($ndb_waiter_extra_opt) + { + mtr_add_arg($args, "$ndb_waiter_extra_opt"); + } + + # Start the ndb_waiter which will connect to the ndb_mgmd + # and poll it for state of the ndbd's, will return when + # all nodes in the cluster is started + my $res= mtr_run($exe_ndb_waiter, $args, + "", $path_waiter_log, $path_waiter_log, ""); + mtr_verbose("ndbcluster_wait_started, returns: $res") if $res; + return $res; +} + + + +sub mysqld_wait_started($){ + my $mysqld= shift; + + my $res= sleep_until_file_created($mysqld->{'path_pid'}, + $mysqld->{'start_timeout'}, + $mysqld->{'pid'}); + return $res == 0; +} + + +sub ndb_mgmd_wait_started($) { + my ($cluster)= @_; + + my $retries= 100; + while (ndbcluster_wait_started($cluster, "--no-contact") and + $retries) + { + # Millisceond sleep emulated with select + select(undef, undef, undef, (0.1)); + + $retries--; + } + + return $retries == 0; + +} + +sub ndb_mgmd_start ($) { + my $cluster= shift; + + my $args; # Arg vector + my $pid= -1; + + mtr_init_args(\$args); + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--core"); + mtr_add_arg($args, "--nodaemon"); + mtr_add_arg($args, "--config-file=%s", "$cluster->{'data_dir'}/config.ini"); + + + my $path_ndb_mgmd_log= "$cluster->{'data_dir'}/\l$cluster->{'name'}_ndb_mgmd.log"; + $pid= mtr_spawn($exe_ndb_mgmd, $args, "", + $path_ndb_mgmd_log, + $path_ndb_mgmd_log, + "", + { append_log_file => 1 }); + + # FIXME Should not be needed + # Unfortunately the cluster nodes will fail to start + # if ndb_mgmd has not started properly + if (ndb_mgmd_wait_started($cluster)) + { + mtr_error("Failed to wait for start of ndb_mgmd"); + } + + # Remember pid of ndb_mgmd + $cluster->{'pid'}= $pid; + + mtr_verbose("ndb_mgmd_start, pid: $pid"); + + return $pid; +} + + +sub ndbd_start ($$$) { + my $cluster= shift; + my $idx= shift; + my $extra_args= shift; + + my $args; # Arg vector + my $pid= -1; + + mtr_init_args(\$args); + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--core"); + mtr_add_arg($args, "--ndb-connectstring=%s", "$cluster->{'connect_string'}"); + mtr_add_arg($args, "--character-sets-dir=%s", "$path_charsetsdir"); + mtr_add_arg($args, "--nodaemon"); + mtr_add_arg($args, "$extra_args"); + + my $nodeid= $cluster->{'ndbds'}->[$idx]->{'nodeid'}; + my $path_ndbd_log= "$cluster->{'data_dir'}/ndb_${nodeid}.log"; + $pid= mtr_spawn($exe_ndbd, $args, "", + $path_ndbd_log, + $path_ndbd_log, + "", + { append_log_file => 1 }); + + # Add pid to list of pids for this cluster + $cluster->{'ndbds'}->[$idx]->{'pid'}= $pid; + + # Rememeber options used when starting + $cluster->{'ndbds'}->[$idx]->{'start_extra_args'}= $extra_args; + $cluster->{'ndbds'}->[$idx]->{'idx'}= $idx; + + mtr_verbose("ndbd_start, pid: $pid"); + + return $pid; +} + + +sub ndbcluster_start ($$) { + my $cluster= shift; + my $extra_args= shift; + + mtr_verbose("ndbcluster_start '$cluster->{'name'}'"); + + if ( $glob_use_running_ndbcluster ) + { + return 0; + } + + if ( $cluster->{'pid'} ) + { + mtr_error("Cluster '$cluster->{'name'}' already started"); + } + + ndb_mgmd_start($cluster); + + for ( my $idx= 0; $idx < $cluster->{'nodes'}; $idx++ ) + { + ndbd_start($cluster, $idx, $extra_args); + } + + return 0; +} + + +sub rm_ndbcluster_tables ($) { + my $dir= shift; + foreach my $bin ( glob("$dir/cluster/apply_status*"), + glob("$dir/cluster/schema*") ) + { + unlink($bin); + } +} + + ############################################################################## # # Run the benchmark suite @@ -1323,9 +2143,9 @@ sub run_benchmarks ($) { my $args; - if ( ! $glob_use_embedded_server and ! $opt_local_master ) + if ( ! $glob_use_embedded_server ) { - $master->[0]->{'pid'}= mysqld_start('master',0,[],[]); + mysqld_start($master->[0],[],[]); if ( ! $master->[0]->{'pid'} ) { mtr_error("Can't start the mysqld server"); @@ -1334,7 +2154,7 @@ sub run_benchmarks ($) { mtr_init_args(\$args); - mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_mysock'}); + mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_sock'}); mtr_add_arg($args, "--user=%s", $opt_user); if ( $opt_small_bench ) @@ -1348,10 +2168,8 @@ sub run_benchmarks ($) { mtr_add_arg($args, "--create-options=TYPE=ndb"); } - my $benchdir= "$glob_basedir/sql-bench"; - chdir($benchdir); # FIXME check error - - # FIXME write shorter.... + chdir($glob_mysql_bench_dir) + or mtr_error("Couldn't chdir to '$glob_mysql_bench_dir': $!"); if ( ! $benchmark ) { @@ -1384,29 +2202,26 @@ sub run_benchmarks ($) { # ############################################################################## -# FIXME how to specify several suites to run? Comma separated list? - -sub run_tests () { - run_suite($opt_suite); -} - sub run_suite () { - my $suite= shift; + my ($suite, $tests)= @_; mtr_print_thick_line(); - mtr_report("Finding Tests in the '$suite' suite"); - mtr_timer_start($glob_timers,"suite", 60 * $opt_suite_timeout); - my $tests= collect_test_cases($suite); - mtr_report("Starting Tests in the '$suite' suite"); + mtr_report_tests_not_skipped_though_disabled($tests); + mtr_print_header(); foreach my $tinfo ( @$tests ) { + if (run_testcase_check_skip_test($tinfo)) + { + next; + } + mtr_timer_start($glob_timers,"testcase", 60 * $opt_testcase_timeout); run_testcase($tinfo); mtr_timer_stop($glob_timers,"testcase"); @@ -1414,10 +2229,11 @@ sub run_suite () { mtr_print_line(); - if ( ! $opt_gdb and ! $glob_use_running_server and - ! $opt_ddd and ! $glob_use_embedded_server ) + if ( ! $glob_debugger and + ! $glob_use_running_server and + ! $glob_use_embedded_server ) { - stop_masters_slaves(); + stop_all_servers(); } if ( $opt_gcov ) @@ -1431,6 +2247,8 @@ sub run_suite () { mtr_report_stats($tests); +# Look for testname.warning files if --do-test= + mtr_timer_stop($glob_timers,"suite"); } @@ -1441,26 +2259,99 @@ sub run_suite () { # ############################################################################## +sub initialize_servers () { + if ( ! $glob_use_running_server ) + { + kill_running_server(); + + unless ( $opt_start_dirty ) + { + cleanup_stale_files(); + mysql_install_db(); + if ( $opt_force ) + { + save_installed_db(); + } + } + check_running_as_root(); + } +} + sub mysql_install_db () { - # FIXME not exactly true I think, needs improvements install_db('master', $master->[0]->{'path_myddir'}); - install_db('master', $master->[1]->{'path_myddir'}); - install_db('slave', $slave->[0]->{'path_myddir'}); - install_db('slave', $slave->[1]->{'path_myddir'}); - install_db('slave', $slave->[2]->{'path_myddir'}); - if ( ndbcluster_install() ) + # FIXME check if testcase really is using second master + copy_install_db('master', $master->[1]->{'path_myddir'}); + + # Install the number of slave databses needed + for (my $idx= 0; $idx < $max_slave_num; $idx++) { - # failed to install, disable usage but flag that its no ok - $opt_with_ndbcluster= 0; - $flag_ndb_status_ok= 0; + copy_install_db("slave".($idx+1), $slave->[$idx]->{'path_myddir'}); } + if ( ! $opt_skip_im ) + { + im_prepare_env($instance_manager); + } + + my $cluster_started_ok= 1; # Assume it can be started + + if (ndbcluster_start_install($clusters->[0]) || + $max_slave_num && ndbcluster_start_install($clusters->[1])) + { + mtr_warning("Failed to start install of cluster"); + $cluster_started_ok= 0; + } + + foreach my $cluster (@{$clusters}) + { + + next if !$cluster->{'pid'}; + + $cluster->{'installed_ok'}= 1; # Assume install suceeds + + if (ndbcluster_wait_started($cluster, "")) + { + # failed to install, disable usage and flag that its no ok + mtr_report("ndbcluster_install of $cluster->{'name'} failed"); + $cluster->{"installed_ok"}= 0; + + $cluster_started_ok= 0; + } + } + + if ( ! $cluster_started_ok ) + { + if ( $opt_force) + { + # Continue without cluster + } + else + { + mtr_error("To continue, re-run with '--force'."); + } + } + + # Stop clusters... + stop_all_servers(); + return 0; } +sub copy_install_db ($$) { + my $type= shift; + my $data_dir= shift; + + mtr_report("Installing \u$type Database"); + + # Just copy the installed db from first master + mtr_copy_dir($master->[0]->{'path_myddir'}, $data_dir); + +} + + sub install_db ($$) { my $type= shift; my $data_dir= shift; @@ -1469,7 +2360,7 @@ sub install_db ($$) { my $init_db_sql_tmp= "/tmp/init_db.sql$$"; my $args; - mtr_report("Installing \u$type Databases"); + mtr_report("Installing \u$type Database"); open(IN, $init_db_sql) or mtr_error("Can't open $init_db_sql: $!"); @@ -1505,16 +2396,29 @@ sub install_db ($$) { mtr_add_arg($args, "--datadir=%s", $data_dir); mtr_add_arg($args, "--skip-innodb"); mtr_add_arg($args, "--skip-ndbcluster"); - mtr_add_arg($args, "--skip-bdb"); + mtr_add_arg($args, "--tmpdir=."); - if ( ! $opt_netware ) + if ( $opt_debug ) + { + mtr_add_arg($args, "--debug=d:t:i:A,%s/log/bootstrap_%s.trace", + $path_vardir_trace, $type); + } + + if ( ! $glob_netware ) { mtr_add_arg($args, "--language=%s", $path_language); mtr_add_arg($args, "--character-sets-dir=%s", $path_charsetsdir); } + # Log bootstrap command + my $path_bootstrap_log= "$opt_vardir/log/bootstrap.log"; + mtr_tofile($path_bootstrap_log, + "$exe_mysqld " . join(" ", @$args) . "\n"); + if ( mtr_run($exe_mysqld, $args, $init_db_sql_tmp, - $path_manager_log, $path_manager_log, "") != 0 ) + $path_bootstrap_log, $path_bootstrap_log, + "", { append_log_file => 1 }) != 0 ) + { unlink($init_db_sql_tmp); mtr_error("Error executing mysqld --bootstrap\n" . @@ -1524,6 +2428,196 @@ sub install_db ($$) { } +sub im_prepare_env($) { + my $instance_manager = shift; + + im_create_passwd_file($instance_manager); + im_prepare_data_dir($instance_manager); +} + + +sub im_create_passwd_file($) { + my $instance_manager = shift; + + my $pwd_file_path = $instance_manager->{'password_file'}; + + mtr_report("Creating IM password file ($pwd_file_path)"); + + open(OUT, ">", $pwd_file_path) + or mtr_error("Can't write to $pwd_file_path: $!"); + + print OUT $instance_manager->{'admin_login'}, ":", + $instance_manager->{'admin_sha1'}, "\n"; + + close(OUT); +} + + +sub im_create_defaults_file($) { + my $instance_manager = shift; + + my $defaults_file = $instance_manager->{'defaults_file'}; + + open(OUT, ">", $defaults_file) + or mtr_error("Can't write to $defaults_file: $!"); + + print OUT <{path_pid} +angel-pid-file = $instance_manager->{path_angel_pid} +socket = $instance_manager->{path_sock} +port = $instance_manager->{port} +password-file = $instance_manager->{password_file} +default-mysqld-path = $exe_mysqld + +EOF +; + + foreach my $instance (@{$instance_manager->{'instances'}}) + { + my $server_id = $instance->{'server_id'}; + + print OUT <{path_sock} +pid-file = $instance->{path_pid} +port = $instance->{port} +datadir = $instance->{path_datadir} +log = $instance->{path_datadir}/mysqld$server_id.log +log-error = $instance->{path_datadir}/mysqld$server_id.err.log +log-slow-queries = $instance->{path_datadir}/mysqld$server_id.slow.log +language = $path_language +character-sets-dir = $path_charsetsdir +basedir = $path_my_basedir +server_id = $server_id +skip-stack-trace +skip-innodb +skip-ndbcluster +EOF +; + + print OUT "nonguarded\n" if $instance->{'nonguarded'}; + print OUT "log-output=FILE\n" if $instance->{'old_log_format'}; + print OUT "\n"; + } + + close(OUT); +} + + +sub im_prepare_data_dir($) { + my $instance_manager = shift; + + foreach my $instance (@{$instance_manager->{'instances'}}) + { + copy_install_db( + 'im_mysqld_' . $instance->{'server_id'}, + $instance->{'path_datadir'}); + } +} + + + +# +# Restore snapshot of the installed slave databases +# if the snapshot exists +# +sub restore_slave_databases ($) { + my ($num_slaves)= @_; + + if ( -d $path_snapshot) + { + for (my $idx= 0; $idx < $num_slaves; $idx++) + { + my $data_dir= $slave->[$idx]->{'path_myddir'}; + my $name= basename($data_dir); + rmtree($data_dir); + mtr_copy_dir("$path_snapshot/$name", $data_dir); + } + } +} + + +sub run_testcase_check_skip_test($) +{ + my ($tinfo)= @_; + + # ---------------------------------------------------------------------- + # If marked to skip, just print out and return. + # Note that a test case not marked as 'skip' can still be + # skipped later, because of the test case itself in cooperation + # with the mysqltest program tells us so. + # ---------------------------------------------------------------------- + + if ( $tinfo->{'skip'} ) + { + mtr_report_test_name($tinfo); + mtr_report_test_skipped($tinfo); + return 1; + } + + # If test needs cluster, check that master installed ok + if ( $tinfo->{'ndb_test'} and !$clusters->[0]->{'installed_ok'} ) + { + mtr_report_test_name($tinfo); + mtr_report_test_failed($tinfo); + return 1; + } + + # If test needs slave cluster, check that it installed ok + if ( $tinfo->{'ndb_test'} and $tinfo->{'slave_num'} and + !$clusters->[1]->{'installed_ok'} ) + { + mtr_report_test_name($tinfo); + mtr_report_test_failed($tinfo); + return 1; + } + + return 0; +} + + +sub do_before_run_mysqltest($) +{ + my $tinfo= shift; + my $tname= $tinfo->{'name'}; + + # Remove old reject file + if ( $opt_suite eq "main" ) + { + unlink("r/$tname.reject"); + } + else + { + unlink("suite/$opt_suite/r/$tname.reject"); + } + + mtr_tonewfile($path_current_test_log,"$tname\n"); # Always tell where we are + + # output current test to ndbcluster log file to enable diagnostics + mtr_tofile($path_ndb_testrun_log,"CURRENT TEST $tname\n"); + + mtr_tofile($master->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n"); + if ( $master->[1]->{'pid'} ) + { + mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n"); + } +} + +sub do_after_run_mysqltest($) +{ + my $tinfo= shift; + my $tname= $tinfo->{'name'}; + + # Save info from this testcase run to mysqltest.log + mtr_appendfile_to_file($path_timefile, $path_mysqltest_log) + if -f $path_timefile; + mtr_tofile($path_mysqltest_log,"CURRENT TEST $tname\n"); +} + + ############################################################################## # # Run a single test case @@ -1543,231 +2637,34 @@ sub install_db ($$) { sub run_testcase ($) { my $tinfo= shift; - my $tname= $tinfo->{'name'}; + my $master_restart= run_testcase_need_master_restart($tinfo); + my $slave_restart= run_testcase_need_slave_restart($tinfo); - mtr_tonewfile($opt_current_test,"$tname\n"); # Always tell where we are - - # output current test to ndbcluster log file to enable diagnostics - mtr_tofile($file_ndb_testrun_log,"CURRENT TEST $tname\n"); - - # ---------------------------------------------------------------------- - # If marked to skip, just print out and return. - # Note that a test case not marked as 'skip' can still be - # skipped later, because of the test case itself in cooperation - # with the mysqltest program tells us so. - # ---------------------------------------------------------------------- - - if ( $tinfo->{'skip'} ) + if ($master_restart or $slave_restart) { - mtr_report_test_name($tinfo); - mtr_report_test_skipped($tinfo); - return; + run_testcase_stop_servers($tinfo, $master_restart, $slave_restart); + } + my $died= mtr_record_dead_children(); + if ($died or $master_restart or $slave_restart) + { + run_testcase_start_servers($tinfo); } # ---------------------------------------------------------------------- - # If not using a running servers we may need to stop and restart. - # We restart in the case we have initiation scripts, server options - # etc to run. But we also restart again after the test first restart - # and test is run, to get back to normal server settings. - # - # To make the code a bit more clean, we actually only stop servers - # here, and mark this to be done. Then a generic "start" part will - # start up the needed servers again. + # If --start-and-exit or --start-dirty given, stop here to let user manually + # run tests # ---------------------------------------------------------------------- - - if ( ! $glob_use_running_server and ! $glob_use_embedded_server ) - { - # We try to find out if we are to restart the server - my $do_restart= 0; # Assumes we don't have to - - if ( $tinfo->{'master_sh'} ) - { - $do_restart= 1; # Always restart if script to run - } - elsif ( $tinfo->{'ndb_test'} and $master->[0]->{'ndbcluster'} == 1 ) - { - $do_restart= 1; # Restart with cluster - # print "Restarting because cluster need to be enabled\n"; - } - elsif ($tinfo->{'ndb_test'} == 0 and $master->[0]->{'ndbcluster'} == 0) - { - $do_restart= 1; # Restart without cluster - # print "Restarting because cluster need to be disabled\n"; - } - elsif ( $master->[0]->{'running_master_is_special'} and - $master->[0]->{'running_master_is_special'}->{'timezone'} eq - $tinfo->{'timezone'} and - mtr_same_opts($master->[0]->{'running_master_is_special'}->{'master_opt'}, - $tinfo->{'master_opt'}) ) - { - # If running master was started with special settings, but - # the current test requuires the same ones, we *don't* restart. - $do_restart= 0; - } - elsif ( $tinfo->{'master_restart'} or - $master->[0]->{'running_master_is_special'} ) - { - $do_restart= 1; - } - - if ( $do_restart ) - { - stop_masters(); - delete $master->[0]->{'running_master_is_special'}; # Forget history - } - - # ---------------------------------------------------------------------- - # Always terminate all slaves, if any. Else we may have useless - # reconnection attempts and error messages in case the slave and - # master servers restart. - # ---------------------------------------------------------------------- - - stop_slaves(); - } - - # ---------------------------------------------------------------------- - # Prepare to start masters. Even if we use embedded, we want to run - # the preparation. - # ---------------------------------------------------------------------- - - $ENV{'TZ'}= $tinfo->{'timezone'}; - - mtr_report_test_name($tinfo); - - mtr_tofile($master->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n"); - -# FIXME test cases that depend on each other, prevent this from -# being at this location. -# do_before_start_master($tname,$tinfo->{'master_sh'}); - - # ---------------------------------------------------------------------- - # If any mysqld servers running died, we have to know - # ---------------------------------------------------------------------- - - mtr_record_dead_children(); - - # ---------------------------------------------------------------------- - # Start masters - # ---------------------------------------------------------------------- - - if ( ! $glob_use_running_server and ! $glob_use_embedded_server ) - { - # FIXME give the args to the embedded server?! - # FIXME what does $opt_local_master mean?! - # FIXME split up start and check that started so that can do - # starts in parallel, masters and slaves at the same time. - - if ( ! $opt_local_master ) - { - if ( $master->[0]->{'ndbcluster'} && $tinfo->{'ndb_test'}) - { - $master->[0]->{'ndbcluster'}= ndbcluster_start(); - if ( $master->[0]->{'ndbcluster'} ) - { - report_failure_and_restart($tinfo); - return; - } - } - if ( ! $master->[0]->{'pid'} ) - { - # FIXME not correct location for do_before_start_master() - do_before_start_master($tname,$tinfo->{'master_sh'}); - - # Save skip_ndbcluster - my $save_opt_skip_ndbcluster= $opt_skip_ndbcluster; - if (!$tinfo->{'ndb_test'}) - { - # Modify skip_ndbcluster so cluster is skipped for this - # and subsequent testcases(until we find one that does not cluster) - $opt_skip_ndbcluster= 1; - } - - $master->[0]->{'pid'}= - mysqld_start('master',0,$tinfo->{'master_opt'},[]); - - # Restore skip_ndbcluster - $opt_skip_ndbcluster= $save_opt_skip_ndbcluster; - - if ( ! $master->[0]->{'pid'} ) - { - report_failure_and_restart($tinfo); - return; - } - } - if ( $opt_with_ndbcluster and ! $master->[1]->{'pid'} ) - { - # Test needs cluster, start an extra mysqld connected to cluster - $master->[1]->{'pid'}= - mysqld_start('master',1,$tinfo->{'master_opt'},[]); - if ( ! $master->[1]->{'pid'} ) - { - report_failure_and_restart($tinfo); - return; - } - } - - if ( $tinfo->{'master_restart'} ) - { - # Save this test case information, so next can examine it - $master->[0]->{'running_master_is_special'}= $tinfo; - } - } - - # ---------------------------------------------------------------------- - # Start slaves - if needed - # ---------------------------------------------------------------------- - - if ( $tinfo->{'slave_num'} ) - { - mtr_tofile($slave->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n"); - - do_before_start_slave($tname,$tinfo->{'slave_sh'}); - - for ( my $idx= 0; $idx < $tinfo->{'slave_num'}; $idx++ ) - { - if ( ! $slave->[$idx]->{'pid'} ) - { - $slave->[$idx]->{'pid'}= - mysqld_start('slave',$idx, - $tinfo->{'slave_opt'}, $tinfo->{'slave_mi'}); - if ( ! $slave->[$idx]->{'pid'} ) - { - report_failure_and_restart($tinfo); - return; - } - } - } - } - } - - # ---------------------------------------------------------------------- - # If --start-and-exit given, stop here to let user manually run tests - # ---------------------------------------------------------------------- - - if ( $opt_start_and_exit ) + if ( $opt_start_and_exit or $opt_start_dirty ) { mtr_report("\nServers started, exiting"); exit(0); } - # ---------------------------------------------------------------------- - # Run the test case - # ---------------------------------------------------------------------- - { - # remove the old reject file - if ( $opt_suite eq "main" ) - { - unlink("r/$tname.reject"); - } - else - { - unlink("suite/$opt_suite/r/$tname.reject"); - } - unlink($path_timefile); + do_before_run_mysqltest($tinfo); my $res= run_mysqltest($tinfo); - + mtr_report_test_name($tinfo); if ( $res == 0 ) { mtr_report_test_passed($tinfo); @@ -1775,6 +2672,12 @@ sub run_testcase ($) { elsif ( $res == 62 ) { # Testcase itself tell us to skip this one + + # Try to get reason from mysqltest.log + my $last_line= mtr_lastlinefromfile($path_timefile) if -f $path_timefile; + my $reason= mtr_match_prefix($last_line, "reason: "); + $tinfo->{'comment'}= + defined $reason ? $reason : "Detected by testcase(reason unknown) "; mtr_report_test_skipped($tinfo); } elsif ( $res == 63 ) @@ -1791,38 +2694,128 @@ sub run_testcase ($) { "mysqltest returned unexpected code $res, " . "it has probably crashed"); } + report_failure_and_restart($tinfo); } + + do_after_run_mysqltest($tinfo); + } + + # ---------------------------------------------------------------------- + # Stop Instance Manager if we are processing an IM-test case. + # ---------------------------------------------------------------------- + + if ( ! $glob_use_running_server and $tinfo->{'component_id'} eq 'im' ) + { + unless ( mtr_im_stop($instance_manager, $tinfo->{'name'}) ) + { + mtr_error("Failed to stop Instance Manager.") + } } } +# +# Save a snapshot of the installed test db(s) +# I.e take a snapshot of the var/ dir +# +sub save_installed_db () { + + mtr_report("Saving snapshot of installed databases"); + rmtree($path_snapshot); + + foreach my $data_dir (@data_dir_lst) + { + my $name= basename($data_dir); + mtr_copy_dir("$data_dir", "$path_snapshot/$name"); + } +} + + +# +# Save any interesting files in the data_dir +# before the data dir is removed. +# +sub save_files_before_restore($$) { + my $test_name= shift; + my $data_dir= shift; + my $save_name= "$opt_vardir/log/$test_name"; + + # Look for core files + foreach my $core_file ( glob("$data_dir/core*") ) + { + my $core_name= basename($core_file); + mtr_report("Saving $core_name"); + mkdir($save_name) if ! -d $save_name; + rename("$core_file", "$save_name/$core_name"); + } +} + + +# +# Restore snapshot of the installed test db(s) +# if the snapshot exists +# +sub restore_installed_db ($) { + my $test_name= shift; + + if ( -d $path_snapshot) + { + mtr_report("Restoring snapshot of databases"); + + foreach my $data_dir (@data_dir_lst) + { + my $name= basename($data_dir); + save_files_before_restore($test_name, $data_dir); + rmtree("$data_dir"); + mtr_copy_dir("$path_snapshot/$name", "$data_dir"); + } + + # Remove the ndb_*_fs dirs for all ndbd nodes + # forcing a clean start of ndb + foreach my $cluster (@{$clusters}) + { + foreach my $ndbd (@{$cluster->{'ndbds'}}) + { + rmtree("$ndbd->{'path_fs'}" ); + } + } + } + else + { + # No snapshot existed + mtr_error("No snapshot existed"); + } +} + sub report_failure_and_restart ($) { my $tinfo= shift; mtr_report_test_failed($tinfo); mtr_show_failed_diff($tinfo->{'name'}); print "\n"; - if ( ! $opt_force ) + if ( $opt_force ) { - my $test_mode= join(" ", @::glob_test_mode) || "default"; - print "Aborting: $tinfo->{'name'} failed in $test_mode mode. "; - print "To continue, re-run with '--force'.\n"; - if ( ! $opt_gdb and ! $glob_use_running_server and - ! $opt_ddd and ! $glob_use_embedded_server ) - { - stop_masters_slaves(); - } - mtr_exit(1); + # Stop all servers that are known to be running + stop_all_servers(); + + # Restore the snapshot of the installed test db + restore_installed_db($tinfo->{'name'}); + print "Resuming Tests\n\n"; + return; } - # FIXME always terminate on failure?! - if ( ! $opt_gdb and ! $glob_use_running_server and - ! $opt_ddd and ! $glob_use_embedded_server ) + my $test_mode= join(" ", @::glob_test_mode) || "default"; + print "Aborting: $tinfo->{'name'} failed in $test_mode mode. "; + print "To continue, re-run with '--force'.\n"; + if ( ! $glob_debugger and + ! $glob_use_running_server and + ! $glob_use_embedded_server ) { - stop_masters_slaves(); + stop_all_servers(); } - print "Resuming Tests\n\n"; + mtr_exit(1); + } @@ -1832,9 +2825,9 @@ sub report_failure_and_restart ($) { # ############################################################################## + # The embedded server needs the cleanup so we do some of the start work # but stop before actually running mysqld or anything. - sub do_before_start_master ($$) { my $tname= shift; my $init_script= shift; @@ -1867,13 +2860,14 @@ sub do_before_start_master ($$) { if ( $ret != 0 ) { # FIXME rewrite those scripts to return 0 if successful -# mtr_warning("$init_script exited with code $ret"); + # mtr_warning("$init_script exited with code $ret"); } } # for gcov FIXME needed? If so we need more absolute paths -# chdir($glob_basedir); + # chdir($glob_basedir); } + sub do_before_start_slave ($$) { my $tname= shift; my $init_script= shift; @@ -1901,7 +2895,7 @@ sub do_before_start_slave ($$) { if ( $ret != 0 ) { # FIXME rewrite those scripts to return 0 if successful -# mtr_warning("$init_script exited with code $ret"); + # mtr_warning("$init_script exited with code $ret"); } } @@ -1911,9 +2905,10 @@ sub do_before_start_slave ($$) { } } + sub mysqld_arguments ($$$$$) { my $args= shift; - my $type= shift; # master/slave/bootstrap + my $type= shift; my $idx= shift; my $extra_opt= shift; my $slave_master_info= shift; @@ -1921,7 +2916,7 @@ sub mysqld_arguments ($$$$$) { my $sidx= ""; # Index as string, 0 is empty string if ( $idx > 0 ) { - $sidx= sprintf("%d", $idx); # sprintf not needed in Perl for this + $sidx= "$idx"; } my $prefix= ""; # If mysqltest server arg @@ -1937,15 +2932,19 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--console", $prefix); mtr_add_arg($args, "%s--basedir=%s", $prefix, $path_my_basedir); mtr_add_arg($args, "%s--character-sets-dir=%s", $prefix, $path_charsetsdir); - mtr_add_arg($args, "%s--core", $prefix); + + if ( $mysql_version_id >= 50000 ) + { + mtr_add_arg($args, "%s--log-bin-trust-function-creators", $prefix); + } + mtr_add_arg($args, "%s--default-character-set=latin1", $prefix); mtr_add_arg($args, "%s--language=%s", $prefix, $path_language); mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix); - if ( defined $opt_valgrind_mysqld ) + if ( $opt_valgrind_mysqld ) { mtr_add_arg($args, "%s--skip-safemalloc", $prefix); - mtr_add_arg($args, "%s--skip-bdb", $prefix); } my $pidfile; @@ -1954,29 +2953,41 @@ sub mysqld_arguments ($$$$$) { { my $id= $idx > 0 ? $idx + 101 : 1; - mtr_add_arg($args, "%s--log-bin=%s/log/master-bin%s", $prefix, - $opt_vardir, $sidx); + if (! $opt_skip_master_binlog) + { + mtr_add_arg($args, "%s--log-bin=%s/log/master-bin%s", $prefix, + $opt_vardir, $sidx); + } mtr_add_arg($args, "%s--pid-file=%s", $prefix, - $master->[$idx]->{'path_mypid'}); + $master->[$idx]->{'path_pid'}); mtr_add_arg($args, "%s--port=%d", $prefix, - $master->[$idx]->{'path_myport'}); + $master->[$idx]->{'port'}); mtr_add_arg($args, "%s--server-id=%d", $prefix, $id); mtr_add_arg($args, "%s--socket=%s", $prefix, - $master->[$idx]->{'path_mysock'}); - mtr_add_arg($args, "%s--innodb_data_file_path=ibdata1:50M", $prefix); + $master->[$idx]->{'path_sock'}); + mtr_add_arg($args, "%s--innodb_data_file_path=ibdata1:10M:autoextend", $prefix); mtr_add_arg($args, "%s--local-infile", $prefix); mtr_add_arg($args, "%s--datadir=%s", $prefix, $master->[$idx]->{'path_myddir'}); - if ( $idx > 0 ) + if ( $idx > 0 or !$use_innodb) { mtr_add_arg($args, "%s--skip-innodb", $prefix); } - if ( $opt_skip_ndbcluster ) + my $cluster= $clusters->[$master->[$idx]->{'cluster'}]; + if ( $opt_skip_ndbcluster || + !$cluster->{'pid'}) { mtr_add_arg($args, "%s--skip-ndbcluster", $prefix); } + else + { + mtr_add_arg($args, "%s--ndbcluster", $prefix); + mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, + $cluster->{'connect_string'}); + mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); + } } if ( $type eq 'slave' ) @@ -1986,25 +2997,26 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--datadir=%s", $prefix, $slave->[$idx]->{'path_myddir'}); - # FIXME slave get this option twice?! - mtr_add_arg($args, "%s--exit-info=256", $prefix); mtr_add_arg($args, "%s--init-rpl-role=slave", $prefix); - mtr_add_arg($args, "%s--log-bin=%s/log/slave%s-bin", $prefix, - $opt_vardir, $sidx); # FIXME use own dir for binlogs - mtr_add_arg($args, "%s--log-slave-updates", $prefix); - # FIXME option duplicated for slave + if (! $opt_skip_slave_binlog) + { + mtr_add_arg($args, "%s--log-bin=%s/log/slave%s-bin", $prefix, + $opt_vardir, $sidx); # FIXME use own dir for binlogs + mtr_add_arg($args, "%s--log-slave-updates", $prefix); + } + mtr_add_arg($args, "%s--log=%s", $prefix, $slave->[$idx]->{'path_mylog'}); mtr_add_arg($args, "%s--master-retry-count=10", $prefix); mtr_add_arg($args, "%s--pid-file=%s", $prefix, - $slave->[$idx]->{'path_mypid'}); + $slave->[$idx]->{'path_pid'}); mtr_add_arg($args, "%s--port=%d", $prefix, - $slave->[$idx]->{'path_myport'}); + $slave->[$idx]->{'port'}); mtr_add_arg($args, "%s--relay-log=%s/log/slave%s-relay-bin", $prefix, $opt_vardir, $sidx); mtr_add_arg($args, "%s--report-host=127.0.0.1", $prefix); mtr_add_arg($args, "%s--report-port=%d", $prefix, - $slave->[$idx]->{'path_myport'}); + $slave->[$idx]->{'port'}); mtr_add_arg($args, "%s--report-user=root", $prefix); mtr_add_arg($args, "%s--skip-innodb", $prefix); mtr_add_arg($args, "%s--skip-ndbcluster", $prefix); @@ -2014,9 +3026,9 @@ sub mysqld_arguments ($$$$$) { # on the server. The path need to have constant length otherwise # test results will vary, thus a relative path is used. mtr_add_arg($args, "%s--slave-load-tmpdir=%s", $prefix, - $path_slave_load_tmpdir); + "../tmp"); mtr_add_arg($args, "%s--socket=%s", $prefix, - $slave->[$idx]->{'path_mysock'}); + $slave->[$idx]->{'path_sock'}); mtr_add_arg($args, "%s--set-variable=slave_net_timeout=10", $prefix); if ( @$slave_master_info ) @@ -2033,10 +3045,24 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--master-host=127.0.0.1", $prefix); mtr_add_arg($args, "%s--master-password=", $prefix); mtr_add_arg($args, "%s--master-port=%d", $prefix, - $master->[0]->{'path_myport'}); # First master + $master->[0]->{'port'}); # First master mtr_add_arg($args, "%s--server-id=%d", $prefix, $slave_server_id); mtr_add_arg($args, "%s--rpl-recovery-rank=%d", $prefix, $slave_rpl_rank); } + + if ( $opt_skip_ndbcluster_slave || + $slave->[$idx]->{'cluster'} == -1 || + !$clusters->[$slave->[$idx]->{'cluster'}]->{'pid'} ) + { + mtr_add_arg($args, "%s--skip-ndbcluster", $prefix); + } + else + { + mtr_add_arg($args, "%s--ndbcluster", $prefix); + mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, + $clusters->[$slave->[$idx]->{'cluster'}]->{'connect_string'}); + mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); + } } # end slave if ( $opt_debug ) @@ -2044,28 +3070,21 @@ sub mysqld_arguments ($$$$$) { if ( $type eq 'master' ) { mtr_add_arg($args, "%s--debug=d:t:i:A,%s/log/master%s.trace", - $prefix, $opt_vardir, $sidx); + $prefix, $path_vardir_trace, $sidx); } if ( $type eq 'slave' ) { mtr_add_arg($args, "%s--debug=d:t:i:A,%s/log/slave%s.trace", - $prefix, $opt_vardir, $sidx); + $prefix, $path_vardir_trace, $sidx); } } - if ( $opt_with_ndbcluster && !$opt_skip_ndbcluster && $type eq 'master') - { - mtr_add_arg($args, "%s--ndbcluster", $prefix); - mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, - $opt_ndbconnectstring); - } - # FIXME always set nowdays??? SMALL_SERVER mtr_add_arg($args, "%s--key_buffer_size=1M", $prefix); mtr_add_arg($args, "%s--sort_buffer=256K", $prefix); mtr_add_arg($args, "%s--max_heap_table_size=1M", $prefix); - if ( $opt_with_openssl ) + if ( $opt_ssl_supported ) { mtr_add_arg($args, "%s--ssl-ca=%s/std_data/cacert.pem", $prefix, $glob_mysql_test_dir); @@ -2080,7 +3099,8 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--log-warnings", $prefix); } - if ( $opt_gdb or $opt_client_gdb or $opt_manual_gdb or $opt_ddd) + # Indicate to "mysqld" it will be debugged in debugger + if ( $glob_debugger ) { mtr_add_arg($args, "%s--gdb", $prefix); } @@ -2093,27 +3113,22 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--user=root", $prefix); } - if ( $type eq 'master' ) - { - - if ( ! $opt_old_master ) - { - mtr_add_arg($args, "%s--rpl-recovery-rank=1", $prefix); - mtr_add_arg($args, "%s--init-rpl-role=master", $prefix); - } - - # FIXME strange,..... - # FIXME MYSQL_MYPORT is not set anythere?! - if ( $opt_local_master ) - { - mtr_add_arg($args, "%s--host=127.0.0.1", $prefix); - mtr_add_arg($args, "%s--port=%s", $prefix, $ENV{'MYSQL_MYPORT'}); - } - } - + my $found_skip_core= 0; foreach my $arg ( @opt_extra_mysqld_opt, @$extra_opt ) { - mtr_add_arg($args, "%s%s", $prefix, $arg); + # Allow --skip-core-file to be set in master.opt file + if ($arg eq "--skip-core-file") + { + $found_skip_core= 1; + } + else + { + mtr_add_arg($args, "%s%s", $prefix, $arg); + } + } + if ( !$found_skip_core ) + { + mtr_add_arg($args, "%s%s", $prefix, "--core-file"); } if ( $opt_bench ) @@ -2123,7 +3138,6 @@ sub mysqld_arguments ($$$$$) { } elsif ( $type eq 'master' ) { - mtr_add_arg($args, "%s--exit-info=256", $prefix); mtr_add_arg($args, "%s--open-files-limit=1024", $prefix); mtr_add_arg($args, "%s--log=%s", $prefix, $master->[0]->{'path_mylog'}); } @@ -2131,14 +3145,6 @@ sub mysqld_arguments ($$$$$) { return $args; } -# FIXME -# if ( $type eq 'master' and $glob_use_embedded_server ) -# { -# # Add a -A to each argument to pass it to embedded server -# my @mysqltest_opt= map {("-A",$_)} @args; -# $opt_extra_mysqltest_opt= \@mysqltest_opt; -# return; -# } ############################################################################## # @@ -2146,15 +3152,18 @@ sub mysqld_arguments ($$$$$) { # ############################################################################## -sub mysqld_start ($$$$) { - my $type= shift; # master/slave/bootstrap - my $idx= shift; +sub mysqld_start ($$$) { + my $mysqld= shift; my $extra_opt= shift; my $slave_master_info= shift; my $args; # Arg vector my $exe; - my $pid; + my $pid= -1; + my $wait_for_pid_file= 1; + + my $type= $mysqld->{'type'}; + my $idx= $mysqld->{'idx'}; if ( $type eq 'master' ) { @@ -2166,214 +3175,682 @@ sub mysqld_start ($$$$) { } else { - $exe= $exe_mysqld; + mtr_error("Unknown 'type' \"$type\" passed to mysqld_start"); } mtr_init_args(\$args); - if ( defined $opt_valgrind_mysqld ) + if ( $opt_valgrind_mysqld ) { valgrind_arguments($args, \$exe); } mysqld_arguments($args,$type,$idx,$extra_opt,$slave_master_info); - if ( $type eq 'master' ) + if ( $opt_gdb || $opt_manual_gdb) { - if ( $pid= mtr_spawn($exe, $args, "", - $master->[$idx]->{'path_myerr'}, - $master->[$idx]->{'path_myerr'}, - "", - { append_log_file => 1 }) ) + gdb_arguments(\$args, \$exe, "$type"."_$idx"); + } + elsif ( $opt_ddd || $opt_manual_ddd ) + { + ddd_arguments(\$args, \$exe, "$type"."_$idx"); + } + elsif ( $opt_debugger ) + { + debugger_arguments(\$args, \$exe, "$type"."_$idx"); + } + elsif ( $opt_manual_debug ) + { + print "\nStart $type in your debugger\n" . + "dir: $glob_mysql_test_dir\n" . + "exe: $exe\n" . + "args: " . join(" ", @$args) . "\n\n" . + "Waiting ....\n"; + + # Indicate the exe should not be started + $exe= undef; + } + else + { + # Default to not wait until pid file has been created + $wait_for_pid_file= 0; + } + + if ($exe_libtool and $opt_valgrind) + { + # Add "libtool --mode-execute" + # if running in valgrind(to avoid valgrinding bash) + unshift(@$args, "--mode=execute", $exe); + $exe= $exe_libtool; + } + + + if ( defined $exe ) + { + $pid= mtr_spawn($exe, $args, "", + $mysqld->{'path_myerr'}, + $mysqld->{'path_myerr'}, + "", + { append_log_file => 1 }); + } + + + if ( $wait_for_pid_file && !sleep_until_file_created($mysqld->{'path_pid'}, + $mysqld->{'start_timeout'}, + $pid)) + { + + mtr_error("Failed to start mysqld $mysqld->{'type'}"); + } + + + # Remember pid of the started process + $mysqld->{'pid'}= $pid; + + # Remember options used when starting + $mysqld->{'start_opts'}= $extra_opt; + $mysqld->{'start_slave_master_info'}= $slave_master_info; + + mtr_verbose("mysqld pid: $pid"); + return $pid; +} + + +sub stop_all_servers () { + + print "Stopping All Servers\n"; + + if ( ! $opt_skip_im ) + { + print "Shutting-down Instance Manager\n"; + unless (mtr_im_stop($instance_manager, "stop_all_servers")) { - return sleep_until_file_created($master->[$idx]->{'path_mypid'}, - $master->[$idx]->{'start_timeout'}, $pid); + mtr_error("Failed to stop Instance Manager.") } } - if ( $type eq 'slave' ) + my %admin_pids; # hash of admin processes that requests shutdown + my @kill_pids; # list of processes to shutdown/kill + my $pid; + + # Start shutdown of all started masters + foreach my $mysqld (@{$master}, @{$slave}) { - if ( $pid= mtr_spawn($exe, $args, "", - $slave->[$idx]->{'path_myerr'}, - $slave->[$idx]->{'path_myerr'}, - "", - { append_log_file => 1 }) ) + if ( $mysqld->{'pid'} ) { - return sleep_until_file_created($slave->[$idx]->{'path_mypid'}, - $master->[$idx]->{'start_timeout'}, $pid); + $pid= mtr_mysqladmin_start($mysqld, "shutdown", 70); + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $mysqld->{'pid'}, + pidfile => $mysqld->{'path_pid'}, + sockfile => $mysqld->{'path_sock'}, + port => $mysqld->{'port'}, + }); + + $mysqld->{'pid'}= 0; # Assume we are done with it } } - return 0; -} - -sub stop_masters_slaves () { - - print "Ending Tests\n"; - print "Shutting-down MySQL daemon\n\n"; - stop_masters(); - print "Master(s) shutdown finished\n"; - stop_slaves(); - print "Slave(s) shutdown finished\n"; -} - -sub stop_masters () { - - my @args; - - for ( my $idx; $idx < 2; $idx++ ) + # Start shutdown of clusters + foreach my $cluster (@{$clusters}) { - # FIXME if we hit ^C before fully started, this test will prevent - # the mysqld process from being killed - if ( $master->[$idx]->{'pid'} ) + if ( $cluster->{'pid'} ) { - push(@args,{ - pid => $master->[$idx]->{'pid'}, - pidfile => $master->[$idx]->{'path_mypid'}, - sockfile => $master->[$idx]->{'path_mysock'}, - port => $master->[$idx]->{'path_myport'}, - }); - $master->[$idx]->{'pid'}= 0; # Assume we are done with it + $pid= mtr_ndbmgm_start($cluster, "shutdown"); + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $cluster->{'pid'}, + pidfile => $cluster->{'path_pid'} + }); + + $cluster->{'pid'}= 0; # Assume we are done with it + + foreach my $ndbd (@{$cluster->{'ndbds'}}) + { + if ( $ndbd->{'pid'} ) + { + push(@kill_pids,{ + pid => $ndbd->{'pid'}, + pidfile => $ndbd->{'path_pid'}, + }); + $ndbd->{'pid'}= 0; + } + } } } - if ( ! $master->[0]->{'ndbcluster'} ) - { - ndbcluster_stop(); - $master->[0]->{'ndbcluster'}= 1; - } + # Wait blocking until all shutdown processes has completed + mtr_wait_blocking(\%admin_pids); - mtr_stop_mysqld_servers(\@args); + # Make sure that process has shutdown else try to kill them + mtr_check_stop_servers(\@kill_pids); + + foreach my $mysqld (@{$master}, @{$slave}) + { + rm_ndbcluster_tables($mysqld->{'path_myddir'}); + } } -sub stop_slaves () { - my $force= shift; - my @args; +sub run_testcase_need_master_restart($) +{ + my ($tinfo)= @_; - for ( my $idx; $idx < 3; $idx++ ) + # We try to find out if we are to restart the master(s) + my $do_restart= 0; # Assumes we don't have to + + if ( $tinfo->{'master_sh'} ) { - if ( $slave->[$idx]->{'pid'} ) + $do_restart= 1; # Always restart if script to run + mtr_verbose("Restart because: Always restart if script to run"); + } + elsif ( ! $opt_skip_ndbcluster and + $tinfo->{'ndb_test'} == 0 and + $clusters->[0]->{'pid'} != 0 ) + { + $do_restart= 1; # Restart without cluster + mtr_verbose("Restart because: Test does not need cluster"); + } + elsif ( ! $opt_skip_ndbcluster and + $tinfo->{'ndb_test'} == 1 and + $clusters->[0]->{'pid'} == 0 ) + { + $do_restart= 1; # Restart with cluster + mtr_verbose("Restart because: Test need cluster"); + } + elsif ( $master->[0]->{'running_master_is_special'} and + $master->[0]->{'running_master_is_special'}->{'timezone'} eq + $tinfo->{'timezone'} and + mtr_same_opts($master->[0]->{'running_master_is_special'}->{'master_opt'}, + $tinfo->{'master_opt'}) ) + { + # If running master was started with special settings, but + # the current test requires the same ones, we *don't* restart. + $do_restart= 0; + mtr_verbose("Skip restart: options are equal " . + join(" ", @{$tinfo->{'master_opt'}})); + } + elsif ( $tinfo->{'master_restart'} ) + { + $do_restart= 1; + mtr_verbose("Restart because: master_restart"); + } + elsif ( $master->[0]->{'running_master_is_special'} ) + { + $do_restart= 1; + mtr_verbose("Restart because: running_master_is_special"); + } + # Check that running master was started with same options + # as the current test requires + elsif (! mtr_same_opts($master->[0]->{'start_opts'}, + $tinfo->{'master_opt'}) ) + { + $do_restart= 1; + mtr_verbose("Restart because: running with different options '" . + join(" ", @{$tinfo->{'master_opt'}}) . "' != '" . + join(" ", @{$master->[0]->{'start_opts'}}) . "'" ); + } + + return $do_restart; +} + +sub run_testcase_need_slave_restart($) +{ + my ($tinfo)= @_; + + # We try to find out if we are to restart the slaves + my $do_slave_restart= 0; # Assumes we don't have to + + # FIXME only restart slave when necessary + $do_slave_restart= 1; + +# if ( ! $slave->[0]->{'pid'} ) +# { +# # mtr_verbose("Slave not started, no need to check slave restart"); +# } +# elsif ( $do_restart ) +# { +# $do_slave_restart= 1; # Always restart if master restart +# mtr_verbose("Restart slave because: Master restart"); +# } +# elsif ( $tinfo->{'slave_sh'} ) +# { +# $do_slave_restart= 1; # Always restart if script to run +# mtr_verbose("Restart slave because: Always restart if script to run"); +# } +# elsif ( ! $opt_skip_ndbcluster_slave and +# $tinfo->{'ndb_test'} == 0 and +# $clusters->[1]->{'pid'} != 0 ) +# { +# $do_slave_restart= 1; # Restart without slave cluster +# mtr_verbose("Restart slave because: Test does not need slave cluster"); +# } +# elsif ( ! $opt_with_ndbcluster_slave and +# $tinfo->{'ndb_test'} == 1 and +# $clusters->[1]->{'pid'} == 0 ) +# { +# $do_slave_restart= 1; # Restart with slave cluster +# mtr_verbose("Restart slave because: Test need slave cluster"); +# } +# elsif ( $tinfo->{'slave_restart'} ) +# { +# $do_slave_restart= 1; +# mtr_verbose("Restart slave because: slave_restart"); +# } +# elsif ( $slave->[0]->{'running_slave_is_special'} ) +# { +# $do_slave_restart= 1; +# mtr_verbose("Restart slave because: running_slave_is_special"); +# } +# # Check that running slave was started with same options +# # as the current test requires +# elsif (! mtr_same_opts($slave->[0]->{'start_opts'}, +# $tinfo->{'slave_opt'}) ) +# { +# $do_slave_restart= 1; +# mtr_verbose("Restart slave because: running with different options '" . +# join(" ", @{$tinfo->{'slave_opt'}}) . "' != '" . +# join(" ", @{$slave->[0]->{'start_opts'}}) . "'" ); +# } + + return $do_slave_restart; + +} + +# ---------------------------------------------------------------------- +# If not using a running servers we may need to stop and restart. +# We restart in the case we have initiation scripts, server options +# etc to run. But we also restart again after the test first restart +# and test is run, to get back to normal server settings. +# +# To make the code a bit more clean, we actually only stop servers +# here, and mark this to be done. Then a generic "start" part will +# start up the needed servers again. +# ---------------------------------------------------------------------- + +sub run_testcase_stop_servers($$$) { + my ($tinfo, $do_restart, $do_slave_restart)= @_; + + if ( $glob_use_running_server || $glob_use_embedded_server ) + { + return; + } + + my $pid; + my %admin_pids; # hash of admin processes that requests shutdown + my @kill_pids; # list of processes to shutdown/kill + + # Remember if we restarted for this test case + $tinfo->{'restarted'}= $do_restart; + + if ( $do_restart ) + { + delete $master->[0]->{'running_master_is_special'}; # Forget history + + # Start shutdown of all started masters + foreach my $mysqld (@{$master}) { - push(@args,{ - pid => $slave->[$idx]->{'pid'}, - pidfile => $slave->[$idx]->{'path_mypid'}, - sockfile => $slave->[$idx]->{'path_mysock'}, - port => $slave->[$idx]->{'path_myport'}, - }); - $slave->[$idx]->{'pid'}= 0; # Assume we are done with it + if ( $mysqld->{'pid'} ) + { + $pid= mtr_mysqladmin_start($mysqld, "shutdown", 70); + + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $mysqld->{'pid'}, + pidfile => $mysqld->{'path_pid'}, + sockfile => $mysqld->{'path_sock'}, + port => $mysqld->{'port'}, + }); + + $mysqld->{'pid'}= 0; # Assume we are done with it + } + } + + # Start shutdown of master cluster + my $cluster= $clusters->[0]; + if ( $cluster->{'pid'} ) + { + $pid= mtr_ndbmgm_start($cluster, "shutdown"); + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $cluster->{'pid'}, + pidfile => $cluster->{'path_pid'} + }); + + $cluster->{'pid'}= 0; # Assume we are done with it + + foreach my $ndbd (@{$cluster->{'ndbds'}}) + { + push(@kill_pids,{ + pid => $ndbd->{'pid'}, + pidfile => $ndbd->{'path_pid'}, + }); + $ndbd->{'pid'}= 0; # Assume we are done with it + } } } - mtr_stop_mysqld_servers(\@args); + if ( $do_restart || $do_slave_restart ) + { + + delete $slave->[0]->{'running_slave_is_special'}; # Forget history + + # Start shutdown of all started slaves + foreach my $mysqld (@{$slave}) + { + if ( $mysqld->{'pid'} ) + { + $pid= mtr_mysqladmin_start($mysqld, "shutdown", 70); + + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $mysqld->{'pid'}, + pidfile => $mysqld->{'path_pid'}, + sockfile => $mysqld->{'path_sock'}, + port => $mysqld->{'port'}, + }); + + + $mysqld->{'pid'}= 0; # Assume we are done with it + } + } + + # Start shutdown of slave cluster + my $cluster= $clusters->[1]; + if ( $cluster->{'pid'} ) + { + $pid= mtr_ndbmgm_start($cluster, "shutdown"); + + $admin_pids{$pid}= 1; + + push(@kill_pids,{ + pid => $cluster->{'pid'}, + pidfile => $cluster->{'path_pid'} + }); + + $cluster->{'pid'}= 0; # Assume we are done with it + + foreach my $ndbd (@{$cluster->{'ndbds'}} ) + { + push(@kill_pids,{ + pid => $ndbd->{'pid'}, + pidfile => $ndbd->{'path_pid'}, + }); + $ndbd->{'pid'}= 0; # Assume we are done with it + } + } + } + + # ---------------------------------------------------------------------- + # Shutdown has now been started and lists for the shutdown processes + # and the processes to be killed has been created + # ---------------------------------------------------------------------- + + # Wait blocking until all shutdown processes has completed + mtr_wait_blocking(\%admin_pids); + + + # Make sure that process has shutdown else try to kill them + mtr_check_stop_servers(\@kill_pids); + + foreach my $mysqld (@{$master}, @{$slave}) + { + if ( ! $mysqld->{'pid'} ) + { + # Remove ndbcluster tables if server is stopped + rm_ndbcluster_tables($mysqld->{'path_myddir'}); + } + } } +sub run_testcase_start_servers($) { + my $tinfo= shift; + + my $tname= $tinfo->{'name'}; + + if ( $glob_use_running_server or $glob_use_embedded_server ) + { + return; + } + + # ------------------------------------------------------- + # Init variables that can change between server starts + # ------------------------------------------------------- + $ENV{'TZ'}= $tinfo->{'timezone'}; + + if ( $tinfo->{'component_id'} eq 'mysqld' ) + { + if ( ! $opt_skip_ndbcluster and + !$clusters->[0]->{'pid'} and + $tinfo->{'ndb_test'} ) + { + # Test need cluster, cluster is not started, start it + ndbcluster_start($clusters->[0], ""); + } + + if ( !$master->[0]->{'pid'} ) + { + # Master mysqld is not started + do_before_start_master($tname,$tinfo->{'master_sh'}); + + mysqld_start($master->[0],$tinfo->{'master_opt'},[]); + + } + + if ( $clusters->[0]->{'pid'} and ! $master->[1]->{'pid'} ) + { + # Test needs cluster, start an extra mysqld connected to cluster + + # First wait for first mysql server to have created ndb system tables ok + # FIXME This is a workaround so that only one mysqld creates the tables + if ( ! sleep_until_file_created( + "$master->[0]->{'path_myddir'}/cluster/apply_status.ndb", + $master->[0]->{'start_timeout'}, + $master->[0]->{'pid'})) + { + mtr_report("Failed to create 'cluster/apply_status' table"); + report_failure_and_restart($tinfo); + return; + } + mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n"); + + mysqld_start($master->[1],$tinfo->{'master_opt'},[]); + } + + if ( $tinfo->{'master_restart'} ) + { + # Save this test case information, so next can examine it + $master->[0]->{'running_master_is_special'}= $tinfo; + } + } + elsif ( ! $opt_skip_im and $tinfo->{'component_id'} eq 'im' ) + { + # We have to create defaults file every time, in order to ensure that it + # will be the same for each test. The problem is that test can change the + # file (by SET/UNSET commands), so w/o recreating the file, execution of + # one test can affect the other. + + im_create_defaults_file($instance_manager); + + unless ( mtr_im_start($instance_manager, $tinfo->{im_opts}) ) + { + report_failure_and_restart($tinfo); + mtr_report("Failed to start Instance Manager. " . + "The test '$tname' is marked as failed."); + return; + } + } + + # ---------------------------------------------------------------------- + # Start slaves - if needed + # ---------------------------------------------------------------------- + if ( $tinfo->{'slave_num'} ) + { + mtr_tofile($slave->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n"); + + restore_slave_databases($tinfo->{'slave_num'}); + + do_before_start_slave($tname,$tinfo->{'slave_sh'}); + + if ( ! $opt_skip_ndbcluster_slave and + !$clusters->[1]->{'pid'} and + $tinfo->{'ndb_test'} ) + { + # Test need slave cluster, cluster is not started, start it + ndbcluster_start($clusters->[1], ""); + } + + for ( my $idx= 0; $idx < $tinfo->{'slave_num'}; $idx++ ) + { + if ( ! $slave->[$idx]->{'pid'} ) + { + mysqld_start($slave->[$idx],$tinfo->{'slave_opt'}, + $tinfo->{'slave_mi'}); + + } + } + + if ( $tinfo->{'slave_restart'} ) + { + # Save this test case information, so next can examine it + $slave->[0]->{'running_slave_is_special'}= $tinfo; + } + + } + + # Wait for clusters to start + foreach my $cluster (@{$clusters}) + { + + next if !$cluster->{'pid'}; + + if (ndbcluster_wait_started($cluster, "")) + { + # failed to start + mtr_report("Start of $cluster->{'name'} cluster failed, "); + } + } + + # Wait for mysqld's to start + foreach my $mysqld (@{$master},@{$slave}) + { + + next if !$mysqld->{'pid'}; + + if (mysqld_wait_started($mysqld)) + { + mtr_warning("Failed to start $mysqld->{'type'} mysqld $mysqld->{'idx'}"); + } + } +} + +# +# Run include/check-testcase.test +# Before a testcase, run in record mode, save result file to var +# After testcase, run and compare with the recorded file, they should be equal! +# +sub run_check_testcase ($$) { + + my $mode= shift; + my $mysqld= shift; + + my $name= "check-" . $mysqld->{'type'} . $mysqld->{'idx'}; + + my $args; + mtr_init_args(\$args); + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--silent"); + mtr_add_arg($args, "-v"); + mtr_add_arg($args, "--skip-safemalloc"); + mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir); + + mtr_add_arg($args, "--socket=%s", $mysqld->{'path_sock'}); + mtr_add_arg($args, "--port=%d", $mysqld->{'port'}); + mtr_add_arg($args, "--database=test"); + mtr_add_arg($args, "--user=%s", $opt_user); + mtr_add_arg($args, "--password="); + + mtr_add_arg($args, "-R"); + mtr_add_arg($args, "$opt_vardir/tmp/$name.result"); + + if ( $mode eq "before" ) + { + mtr_add_arg($args, "--record"); + } + + my $res = mtr_run_test($exe_mysqltest,$args, + "include/check-testcase.test", "", "", ""); + + if ( $res == 1 and $mode = "after") + { + mtr_run("diff",["-u", + "$opt_vardir/tmp/$name.result", + "$opt_vardir/tmp/$name.reject"], + "", "", "", ""); + } + elsif ( $res ) + { + mtr_error("Could not execute 'check-testcase' $mode testcase"); + } +} + + sub run_mysqltest ($) { - my $tinfo= shift; - - my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " . - "--port=$master->[0]->{'path_myport'} " . - "--socket=$master->[0]->{'path_mysock'} --password="; - if ( $opt_debug ) - { - $cmdline_mysqldump .= - " --debug=d:t:A,$opt_vardir/log/mysqldump.trace"; - } - my $cmdline_mysqlimport= "$exe_mysqlimport -uroot " . - "--port=$master->[0]->{'path_myport'} " . - "--socket=$master->[0]->{'path_mysock'} --password="; - if ( $opt_debug ) - { - $cmdline_mysqlimport .= - " --debug=d:t:A,$opt_vardir/log/mysqlimport.trace"; - } - - my $cmdline_mysqlshow= "$exe_mysqlshow -uroot " . - "--port=$master->[0]->{'path_myport'} " . - "--socket=$master->[0]->{'path_mysock'} --password="; - if ( $opt_debug ) - { - $cmdline_mysqlshow .= - " --debug=d:t:A,$opt_vardir/log/mysqlshow.trace"; - } - - my $cmdline_mysqlbinlog= - "$exe_mysqlbinlog --no-defaults --local-load=$opt_tmpdir"; - - if ( $opt_debug ) - { - $cmdline_mysqlbinlog .= - " --debug=d:t:A,$opt_vardir/log/mysqlbinlog.trace"; - } - - my $cmdline_mysql= - "$exe_mysql --host=localhost --user=root --password= " . - "--port=$master->[0]->{'path_myport'} " . - "--socket=$master->[0]->{'path_mysock'}"; - - my $cmdline_mysql_client_test= - "$exe_mysql_client_test --no-defaults --testcase --user=root --silent " . - "--port=$master->[0]->{'path_myport'} " . - "--socket=$master->[0]->{'path_mysock'}"; - - if ( $glob_use_embedded_server ) - { - $cmdline_mysql_client_test.= - " -A --language=$path_language" . - " -A --datadir=$slave->[0]->{'path_myddir'}" . - " -A --character-sets-dir=$path_charsetsdir"; - } - - my $cmdline_mysql_fix_system_tables= - "$exe_mysql_fix_system_tables --no-defaults --host=localhost --user=root --password= " . - "--basedir=$glob_basedir --bindir=$path_client_bindir --verbose " . - "--port=$master->[0]->{'path_myport'} " . - "--socket=$master->[0]->{'path_mysock'}"; - - - - # FIXME really needing a PATH??? - # $ENV{'PATH'}= "/bin:/usr/bin:/usr/local/bin:/usr/bsd:/usr/X11R6/bin:/usr/openwin/bin:/usr/bin/X11:$ENV{'PATH'}"; - - $ENV{'MYSQL'}= $cmdline_mysql; - $ENV{'MYSQL_DUMP'}= $cmdline_mysqldump; - $ENV{'MYSQL_IMPORT'}= $cmdline_mysqlimport; - $ENV{'MYSQL_SHOW'}= $cmdline_mysqlshow; - $ENV{'MYSQL_BINLOG'}= $cmdline_mysqlbinlog; - $ENV{'MYSQL_FIX_SYSTEM_TABLES'}= $cmdline_mysql_fix_system_tables; - $ENV{'MYSQL_CLIENT_TEST'}= $cmdline_mysql_client_test; - $ENV{'CHARSETSDIR'}= $path_charsetsdir; - $ENV{'MYSQL_MY_PRINT_DEFAULTS'}= $exe_my_print_defaults; - - $ENV{'NDB_STATUS_OK'}= $flag_ndb_status_ok; - $ENV{'NDB_MGM'}= $exe_ndb_mgm; - $ENV{'NDB_BACKUP_DIR'}= $path_ndb_backup_dir; - $ENV{'NDB_TOOLS_DIR'}= $path_ndb_tools_dir; - $ENV{'NDB_TOOLS_OUTPUT'}= $file_ndb_testrun_log; - $ENV{'NDB_CONNECTSTRING'}= $opt_ndbconnectstring; - + my ($tinfo)= @_; my $exe= $exe_mysqltest; my $args; mtr_init_args(\$args); mtr_add_arg($args, "--no-defaults"); - mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_mysock'}); - mtr_add_arg($args, "--database=test"); - mtr_add_arg($args, "--user=%s", $opt_user); - mtr_add_arg($args, "--password="); mtr_add_arg($args, "--silent"); mtr_add_arg($args, "-v"); mtr_add_arg($args, "--skip-safemalloc"); mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir); - mtr_add_arg($args, "--port=%d", $master->[0]->{'path_myport'}); + + if ($tinfo->{'component_id'} eq 'im') + { + mtr_add_arg($args, "--socket=%s", $instance_manager->{'path_sock'}); + mtr_add_arg($args, "--port=%d", $instance_manager->{'port'}); + mtr_add_arg($args, "--user=%s", $instance_manager->{'admin_login'}); + mtr_add_arg($args, "--password=%s", $instance_manager->{'admin_password'}); + } + else # component_id == mysqld + { + mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_sock'}); + mtr_add_arg($args, "--port=%d", $master->[0]->{'port'}); + mtr_add_arg($args, "--database=test"); + mtr_add_arg($args, "--user=%s", $opt_user); + mtr_add_arg($args, "--password="); + } if ( $opt_ps_protocol ) { mtr_add_arg($args, "--ps-protocol"); } + if ( $opt_sp_protocol ) + { + mtr_add_arg($args, "--sp-protocol"); + } + + if ( $opt_view_protocol ) + { + mtr_add_arg($args, "--view-protocol"); + } + + if ( $opt_cursor_protocol ) + { + mtr_add_arg($args, "--cursor-protocol"); + } + if ( $opt_strace_client ) { $exe= "strace"; # FIXME there are ktrace, .... @@ -2392,6 +3869,11 @@ sub run_mysqltest ($) { mtr_add_arg($args, "--big-test"); } + if ( $opt_valgrind ) + { + mtr_add_arg($args, "--valgrind"); + } + if ( $opt_compress ) { mtr_add_arg($args, "--compress"); @@ -2404,17 +3886,30 @@ sub run_mysqltest ($) { if ( $opt_debug ) { - mtr_add_arg($args, "--debug=d:t:A,%s/log/mysqltest.trace", $opt_vardir); + mtr_add_arg($args, "--debug=d:t:A,%s/log/mysqltest.trace", + $path_vardir_trace); } - if ( $opt_with_openssl ) + if ( $opt_ssl_supported ) { mtr_add_arg($args, "--ssl-ca=%s/std_data/cacert.pem", - $glob_mysql_test_dir); + $glob_mysql_test_dir); mtr_add_arg($args, "--ssl-cert=%s/std_data/client-cert.pem", - $glob_mysql_test_dir); + $glob_mysql_test_dir); mtr_add_arg($args, "--ssl-key=%s/std_data/client-key.pem", - $glob_mysql_test_dir); + $glob_mysql_test_dir); + } + + if ( $opt_ssl ) + { + # Turn on SSL for _all_ test cases if option --ssl was used + mtr_add_arg($args, "--ssl", + $glob_mysql_test_dir); + } + elsif ( $opt_ssl_supported ) + { + mtr_add_arg($args, "--skip-ssl", + $glob_mysql_test_dir); } # ---------------------------------------------------------------------- @@ -2435,7 +3930,7 @@ sub run_mysqltest ($) { # Add arguments that should not go into the MYSQL_TEST env var # ---------------------------------------------------------------------- - if ( defined $opt_valgrind_mysqltest ) + if ( $opt_valgrind_mysqltest ) { # Prefix the Valgrind options to the argument list. # We do this here, since we do not want to Valgrind the nested invocations @@ -2446,7 +3941,10 @@ sub run_mysqltest ($) { mtr_add_arg($args, "%s", $_) for @args_saved; } - mtr_add_arg($args, "-R"); + mtr_add_arg($args, "--test-file"); + mtr_add_arg($args, $tinfo->{'path'}); + + mtr_add_arg($args, "--result-file"); mtr_add_arg($args, $tinfo->{'result_file'}); if ( $opt_record ) @@ -2454,36 +3952,248 @@ sub run_mysqltest ($) { mtr_add_arg($args, "--record"); } - return mtr_run_test($exe,$args,$tinfo->{'path'},"",$path_timefile,""); + if ( $opt_client_gdb ) + { + gdb_arguments(\$args, \$exe, "client"); + } + elsif ( $opt_client_ddd ) + { + ddd_arguments(\$args, \$exe, "client"); + } + elsif ( $opt_client_debugger ) + { + debugger_arguments(\$args, \$exe, "client"); + } + + if ($exe_libtool and $opt_valgrind) + { + # Add "libtool --mode-execute" before the test to execute + # if running in valgrind(to avoid valgrinding bash) + unshift(@$args, "--mode=execute", $exe); + $exe= $exe_libtool; + } + + if ( $opt_check_testcases ) + { + foreach my $mysqld (@{$master}, @{$slave}) + { + if ($mysqld->{'pid'}) + { + run_check_testcase("before", $mysqld); + } + } + } + + my $res = mtr_run_test($exe,$args,"","",$path_timefile,""); + + if ( $opt_check_testcases ) + { + foreach my $mysqld (@{$master}, @{$slave}) + { + if ($mysqld->{'pid'}) + { + run_check_testcase("after", $mysqld); + } + } + } + + return $res; + } +# +# Modify the exe and args so that program is run in gdb in xterm +# +sub gdb_arguments { + my $args= shift; + my $exe= shift; + my $type= shift; + + # Write $args to gdb init file + my $str= join(" ", @$$args); + my $gdb_init_file= "$opt_tmpdir/gdbinit.$type"; + + # Remove the old gdbinit file + unlink($gdb_init_file); + + if ( $type eq "client" ) + { + # write init file for client + mtr_tofile($gdb_init_file, + "set args $str\n" . + "break main\n"); + } + else + { + # write init file for mysqld + mtr_tofile($gdb_init_file, + "set args $str\n" . + "break mysql_parse\n" . + "commands 1\n" . + "disable 1\n" . + "end\n" . + "run"); + } + + if ( $opt_manual_gdb ) + { + print "\nTo start gdb for $type, type in another window:\n"; + print "cd $glob_mysql_test_dir;\n"; + print "gdb -x $gdb_init_file $$exe\n"; + + # Indicate the exe should not be started + $$exe= undef; + return; + } + + $$args= []; + mtr_add_arg($$args, "-title"); + mtr_add_arg($$args, "$type"); + mtr_add_arg($$args, "-e"); + + if ( $exe_libtool ) + { + mtr_add_arg($$args, $exe_libtool); + mtr_add_arg($$args, "--mode=execute"); + } + + mtr_add_arg($$args, "gdb"); + mtr_add_arg($$args, "-x"); + mtr_add_arg($$args, "$gdb_init_file"); + mtr_add_arg($$args, "$$exe"); + + $$exe= "xterm"; +} + + +# +# Modify the exe and args so that program is run in ddd +# +sub ddd_arguments { + my $args= shift; + my $exe= shift; + my $type= shift; + + # Write $args to ddd init file + my $str= join(" ", @$$args); + my $gdb_init_file= "$opt_tmpdir/gdbinit.$type"; + + # Remove the old gdbinit file + unlink($gdb_init_file); + + if ( $type eq "client" ) + { + # write init file for client + mtr_tofile($gdb_init_file, + "set args $str\n" . + "break main\n"); + } + else + { + # write init file for mysqld + mtr_tofile($gdb_init_file, + "file $$exe\n" . + "set args $str\n" . + "break mysql_parse\n" . + "commands 1\n" . + "disable 1\n" . + "end"); + } + + if ( $opt_manual_ddd ) + { + print "\nTo start ddd for $type, type in another window:\n"; + print "cd $glob_mysql_test_dir;\n"; + print "ddd -x $gdb_init_file $$exe\n"; + + # Indicate the exe should not be started + $$exe= undef; + return; + } + + my $save_exe= $$exe; + $$args= []; + if ( $exe_libtool ) + { + $$exe= $exe_libtool; + mtr_add_arg($$args, "--mode=execute"); + mtr_add_arg($$args, "ddd"); + } + else + { + $$exe= "ddd"; + } + mtr_add_arg($$args, "--command=$gdb_init_file"); + mtr_add_arg($$args, "$save_exe"); +} + + +# +# Modify the exe and args so that program is run in the selected debugger +# +sub debugger_arguments { + my $args= shift; + my $exe= shift; + my $debugger= $opt_debugger || $opt_client_debugger; + + # FIXME Need to change the below "eq"'s to + # "case unsensitive string contains" + if ( $debugger eq "vcexpress" or $debugger eq "vc") + { + # vc[express] /debugexe exe arg1 .. argn + + # Add /debugexe and name of the exe before args + unshift(@$$args, "/debugexe"); + unshift(@$$args, "$$exe"); + + } + elsif ( $debugger eq "windbg" ) + { + # windbg exe arg1 .. argn + + # Add name of the exe before args + unshift(@$$args, "$$exe"); + + } + else + { + mtr_error("Unknown argument \"$debugger\" passed to --debugger"); + } + + # Set exe to debuggername + $$exe= $debugger; +} + + +# +# Modify the exe and args so that program is run in valgrind +# 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 ) + if ( $opt_callgrind) { - mtr_add_arg($args, "-v"); - mtr_add_arg($args, "--show-reachable=yes"); + mtr_add_arg($args, "--tool=callgrind"); + mtr_add_arg($args, "--base=$opt_vardir/log"); + } + else + { + 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 ( $opt_valgrind_options ) - { - # FIXME split earlier and put into @glob_valgrind_* - mtr_add_arg($args, '%s', $_) for (split(' ', $opt_valgrind_options)); - } + # Add valgrind options, can be overriden by user + mtr_add_arg($args, '%s', $_) for (split(' ', $opt_valgrind_options)); mtr_add_arg($args, $$exe); - $$exe= $opt_valgrind || "valgrind"; + $$exe= $opt_valgrind_path || "valgrind"; } @@ -2503,38 +4213,60 @@ sub usage ($) { print STDERR < Date: Wed, 4 Oct 2006 17:13:32 +0400 Subject: [PATCH 012/131] Fixes a number of problems with time/datetime <-> string conversion functions: - bug #11655 "Wrong time is returning from nested selects - maximum time exists - input and output TIME values were not validated properly in several conversion functions - bug #20927 "sec_to_time treats big unsigned as signed" - integer overflows were not checked in several functions. As a result, input values like 2^32 or 3600*2^32 were treated as 0 - BIGINT UNSIGNED values were treated as SIGNED in several functions - in cases where both input string truncation and out-of-range TIME value occur, only 'truncated incorrect time value' warning was produced --- include/my_time.h | 14 +- mysql-test/r/func_sapdb.result | 15 ++- mysql-test/r/func_time.result | 92 +++++++++++++- mysql-test/t/func_time.test | 45 ++++++- sql-common/my_time.c | 91 +++++++++---- sql/field.cc | 35 +++-- sql/item_timefunc.cc | 226 ++++++++++++++++++++++++++------- sql/time.cc | 6 +- 8 files changed, 429 insertions(+), 95 deletions(-) diff --git a/include/my_time.h b/include/my_time.h index 94701e159c4..11c653f70d0 100644 --- a/include/my_time.h +++ b/include/my_time.h @@ -44,12 +44,24 @@ typedef long my_time_t; #define TIME_FUZZY_DATE 1 #define TIME_DATETIME_ONLY 2 +#define MYSQL_TIME_WARN_TRUNCATED 1 +#define MYSQL_TIME_WARN_OUT_OF_RANGE 2 + +/* Limits for the TIME data type */ +#define TIME_MAX_HOUR 838 +#define TIME_MAX_MINUTE 59 +#define TIME_MAX_SECOND 59 +#define TIME_MAX_VALUE (TIME_MAX_HOUR*10000 + TIME_MAX_MINUTE*100 + \ + TIME_MAX_SECOND) + enum enum_mysql_timestamp_type str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time, uint flags, int *was_cut); bool str_to_time(const char *str,uint length, MYSQL_TIME *l_time, - int *was_cut); + int *warning); + +int check_time_range(struct st_mysql_time *time, int *warning); long calc_daynr(uint year,uint month,uint day); diff --git a/mysql-test/r/func_sapdb.result b/mysql-test/r/func_sapdb.result index b18885e218a..447cadb9898 100644 --- a/mysql-test/r/func_sapdb.result +++ b/mysql-test/r/func_sapdb.result @@ -97,7 +97,9 @@ subtime("02:01:01.999999", "01:01:01.999999") 01:00:00.000000 select timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002"); timediff("1997-01-01 23:59:59.000001","1995-12-31 23:59:59.000002") -8807:59:59.999999 +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '8807:59:59.999999' select timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002"); timediff("1997-12-31 23:59:59.000001","1997-12-30 01:01:01.000002") 46:58:57.999999 @@ -208,13 +210,16 @@ NULL NULL SELECT TIMEDIFF(t1,t4) As ttt, TIMEDIFF(t2, t3) As qqq from test; ttt qqq -744:00:00 NULL -26305:01:02 22:58:58 --26305:01:02 -22:58:58 +838:59:59 22:58:58 +-838:59:59 -22:58:58 NULL 26:02:02 00:00:00 -26:02:02 NULL NULL NULL NULL 00:00:00 -24:00:00 +Warnings: +Warning 1292 Truncated incorrect time value: '26305:01:02' +Warning 1292 Truncated incorrect time value: '-26305:01:02' drop table t1, test; select addtime("-01:01:01.01", "-23:59:59.1") as a; a @@ -224,7 +229,9 @@ a 10000 select microsecond(19971231235959.01) as a; a -10000 +0 +Warnings: +Warning 1292 Truncated incorrect time value: '19971231235959.01' select date_add("1997-12-31",INTERVAL "10.09" SECOND_MICROSECOND) as a; a 1997-12-31 00:00:10.090000 diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index fab0bf01f58..381c147660a 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -330,7 +330,9 @@ extract(DAY_MINUTE FROM "02 10:11:12") 21011 select extract(DAY_SECOND FROM "225 10:11:12"); extract(DAY_SECOND FROM "225 10:11:12") -225101112 +8385959 +Warnings: +Warning 1292 Truncated incorrect time value: '225 10:11:12' select extract(HOUR FROM "1999-01-02 10:11:12"); extract(HOUR FROM "1999-01-02 10:11:12") 10 @@ -688,3 +690,91 @@ t1 CREATE TABLE `t1` ( `from_unixtime(1) + 0` double(23,6) default NULL ) ENGINE=MyISAM DEFAULT CHARSET=latin1 drop table t1; +SELECT SEC_TO_TIME(3300000); +SEC_TO_TIME(3300000) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '3300000' +SELECT SEC_TO_TIME(3300000)+0; +SEC_TO_TIME(3300000)+0 +8385959.000000 +Warnings: +Warning 1292 Truncated incorrect time value: '3300000' +SELECT SEC_TO_TIME(3600 * 4294967296); +SEC_TO_TIME(3600 * 4294967296) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '15461882265600' +SELECT TIME_TO_SEC('916:40:00'); +TIME_TO_SEC('916:40:00') +3020399 +Warnings: +Warning 1292 Truncated incorrect time value: '916:40:00' +SELECT ADDTIME('500:00:00', '416:40:00'); +ADDTIME('500:00:00', '416:40:00') +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '916:40:00' +SELECT ADDTIME('916:40:00', '416:40:00'); +ADDTIME('916:40:00', '416:40:00') +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '916:40:00' +Warning 1292 Truncated incorrect time value: '1255:39:59' +SELECT SUBTIME('916:40:00', '416:40:00'); +SUBTIME('916:40:00', '416:40:00') +422:19:59 +Warnings: +Warning 1292 Truncated incorrect time value: '916:40:00' +SELECT SUBTIME('-916:40:00', '416:40:00'); +SUBTIME('-916:40:00', '416:40:00') +-838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '-916:40:00' +Warning 1292 Truncated incorrect time value: '-1255:39:59' +SELECT MAKETIME(916,0,0); +MAKETIME(916,0,0) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '916:00:00' +SELECT MAKETIME(4294967296, 0, 0); +MAKETIME(4294967296, 0, 0) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '4294967296:00:00' +SELECT MAKETIME(-4294967296, 0, 0); +MAKETIME(-4294967296, 0, 0) +-838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '-4294967296:00:00' +SELECT MAKETIME(0, 4294967296, 0); +MAKETIME(0, 4294967296, 0) +NULL +SELECT MAKETIME(0, 0, 4294967296); +MAKETIME(0, 0, 4294967296) +NULL +SELECT MAKETIME(CAST(-1 AS UNSIGNED), 0, 0); +MAKETIME(CAST(-1 AS UNSIGNED), 0, 0) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '18446744073709551615:00:00' +SELECT EXTRACT(HOUR FROM '100000:02:03'); +EXTRACT(HOUR FROM '100000:02:03') +838 +Warnings: +Warning 1292 Truncated incorrect time value: '100000:02:03' +CREATE TABLE t1(f1 TIME); +INSERT INTO t1 VALUES('916:00:00 a'); +Warnings: +Warning 1265 Data truncated for column 'f1' at row 1 +Warning 1264 Data truncated; out of range for column 'f1' at row 1 +SELECT * FROM t1; +f1 +838:59:59 +DROP TABLE t1; +SELECT SEC_TO_TIME(CAST(-1 AS UNSIGNED)); +SEC_TO_TIME(CAST(-1 AS UNSIGNED)) +838:59:59 +Warnings: +Warning 1292 Truncated incorrect time value: '18446744073709551615' +End of 4.1 tests diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index b232fb14e1e..d15aa9c9516 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -358,4 +358,47 @@ create table t1 select now() - now(), curtime() - curtime(), show create table t1; drop table t1; -# End of 4.1 tests +# +# Bug #11655: Wrong time is returning from nested selects - maximum time exists +# +# check if SEC_TO_TIME() handles out-of-range values correctly +SELECT SEC_TO_TIME(3300000); +SELECT SEC_TO_TIME(3300000)+0; +SELECT SEC_TO_TIME(3600 * 4294967296); + +# check if TIME_TO_SEC() handles out-of-range values correctly +SELECT TIME_TO_SEC('916:40:00'); + +# check if ADDTIME() handles out-of-range values correctly +SELECT ADDTIME('500:00:00', '416:40:00'); +SELECT ADDTIME('916:40:00', '416:40:00'); + +# check if SUBTIME() handles out-of-range values correctly +SELECT SUBTIME('916:40:00', '416:40:00'); +SELECT SUBTIME('-916:40:00', '416:40:00'); + +# check if MAKETIME() handles out-of-range values correctly +SELECT MAKETIME(916,0,0); +SELECT MAKETIME(4294967296, 0, 0); +SELECT MAKETIME(-4294967296, 0, 0); +SELECT MAKETIME(0, 4294967296, 0); +SELECT MAKETIME(0, 0, 4294967296); +SELECT MAKETIME(CAST(-1 AS UNSIGNED), 0, 0); + +# check if EXTRACT() handles out-of-range values correctly +SELECT EXTRACT(HOUR FROM '100000:02:03'); + +# check if we get proper warnings if both input string truncation +# and out-of-range value occur +CREATE TABLE t1(f1 TIME); +INSERT INTO t1 VALUES('916:00:00 a'); +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug #20927: sec_to_time treats big unsigned as signed +# +# check if SEC_TO_TIME() handles BIGINT UNSIGNED values correctly +SELECT SEC_TO_TIME(CAST(-1 AS UNSIGNED)); + +--echo End of 4.1 tests diff --git a/sql-common/my_time.c b/sql-common/my_time.c index 3c46a944ba9..baf9a3902d9 100644 --- a/sql-common/my_time.c +++ b/sql-common/my_time.c @@ -402,8 +402,10 @@ err: There may be an optional [.second_part] after seconds length Length of str l_time Store result here - was_cut Set to 1 if value was cut during conversion or to 0 - otherwise. + warning Set MYSQL_TIME_WARN_TRUNCATED flag if the input string + was cut during conversion, and/or + MYSQL_TIME_WARN_OUT_OF_RANGE flag, if the value is + out of range. NOTES Because of the extra days argument, this function can only @@ -414,16 +416,16 @@ err: 1 error */ -bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time, - int *was_cut) +bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time, int *warning) { - long date[5],value; + ulong date[5]; + ulonglong value; const char *end=str+length, *end_of_days; bool found_days,found_hours; uint state; l_time->neg=0; - *was_cut= 0; + *warning= 0; for (; str != end && my_isspace(&my_charset_latin1,*str) ; str++) length--; if (str != end && *str == '-') @@ -438,13 +440,16 @@ bool str_to_time(const char *str, uint length, MYSQL_TIME *l_time, /* Check first if this is a full TIMESTAMP */ if (length >= 12) { /* Probably full timestamp */ + int was_cut; enum enum_mysql_timestamp_type res= str_to_datetime(str, length, l_time, - (TIME_FUZZY_DATE | TIME_DATETIME_ONLY), was_cut); + (TIME_FUZZY_DATE | TIME_DATETIME_ONLY), &was_cut); if ((int) res >= (int) MYSQL_TIMESTAMP_ERROR) + { + if (was_cut) + *warning|= MYSQL_TIME_WARN_TRUNCATED; return res == MYSQL_TIMESTAMP_ERROR; - /* We need to restore was_cut flag since str_to_datetime can modify it */ - *was_cut= 0; + } } /* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */ @@ -524,7 +529,7 @@ fractional: if (field_length > 0) value*= (long) log_10_int[field_length]; else if (field_length < 0) - *was_cut= 1; + *warning|= MYSQL_TIME_WARN_TRUNCATED; date[4]=value; } else @@ -538,10 +543,7 @@ fractional: ((str[1] == '-' || str[1] == '+') && (end - str) > 2 && my_isdigit(&my_charset_latin1, str[2])))) - { - *was_cut= 1; return 1; - } if (internal_format_positions[7] != 255) { @@ -560,12 +562,12 @@ fractional: } } - /* Some simple checks */ - if (date[2] >= 60 || date[3] >= 60) - { - *was_cut= 1; + /* Integer overflow checks */ + if (date[0] > UINT_MAX || date[1] > UINT_MAX || + date[2] > UINT_MAX || date[3] > UINT_MAX || + date[4] > UINT_MAX) return 1; - } + l_time->year= 0; /* For protocol::store_time */ l_time->month= 0; l_time->day= date[0]; @@ -575,6 +577,10 @@ fractional: l_time->second_part= date[4]; l_time->time_type= MYSQL_TIMESTAMP_TIME; + /* Check if the value is valid and fits into TIME range */ + if (check_time_range(l_time, warning)) + return 1; + /* Check if there is garbage at end of the TIME specification */ if (str != end) { @@ -582,7 +588,7 @@ fractional: { if (!my_isspace(&my_charset_latin1,*str)) { - *was_cut= 1; + *warning|= MYSQL_TIME_WARN_TRUNCATED; break; } } while (++str != end); @@ -591,6 +597,47 @@ fractional: } +/* + Check 'time' value to lie in the TIME range + + SYNOPSIS: + check_time_range() + time pointer to TIME value + warning set MYSQL_TIME_WARN_OUT_OF_RANGE flag if the value is out of range + + DESCRIPTION + If the time value lies outside of the range [-838:59:59, 838:59:59], + set it to the closest endpoint of the range and set + MYSQL_TIME_WARN_OUT_OF_RANGE flag in the 'warning' variable. + + RETURN + 0 time value is valid, but was possibly truncated + 1 time value is invalid +*/ + +int check_time_range(struct st_mysql_time *time, int *warning) +{ + longlong hour; + + if (time->minute >= 60 || time->second >= 60) + return 1; + + hour= time->hour + (24*time->day); + if (hour <= TIME_MAX_HOUR && + (hour != TIME_MAX_HOUR || time->minute != TIME_MAX_MINUTE || + time->second != TIME_MAX_SECOND || !time->second_part)) + return 0; + + time->day= 0; + time->hour= TIME_MAX_HOUR; + time->minute= TIME_MAX_MINUTE; + time->second= TIME_MAX_SECOND; + time->second_part= 0; + *warning|= MYSQL_TIME_WARN_OUT_OF_RANGE; + return 0; +} + + /* Prepare offset of system time zone from UTC for my_system_gmt_sec() func. @@ -776,7 +823,7 @@ void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type) int my_time_to_str(const MYSQL_TIME *l_time, char *to) { uint extra_hours= 0; - return my_sprintf(to, (to, "%s%02d:%02d:%02d", + return my_sprintf(to, (to, "%s%02u:%02u:%02u", (l_time->neg ? "-" : ""), extra_hours+ l_time->hour, l_time->minute, @@ -785,7 +832,7 @@ int my_time_to_str(const MYSQL_TIME *l_time, char *to) int my_date_to_str(const MYSQL_TIME *l_time, char *to) { - return my_sprintf(to, (to, "%04d-%02d-%02d", + return my_sprintf(to, (to, "%04u-%02u-%02u", l_time->year, l_time->month, l_time->day)); @@ -793,7 +840,7 @@ int my_date_to_str(const MYSQL_TIME *l_time, char *to) int my_datetime_to_str(const MYSQL_TIME *l_time, char *to) { - return my_sprintf(to, (to, "%04d-%02d-%02d %02d:%02d:%02d", + return my_sprintf(to, (to, "%04u-%02u-%02u %02u:%02u:%02u", l_time->year, l_time->month, l_time->day, diff --git a/sql/field.cc b/sql/field.cc index 3cb0c0d3a7c..484758fb0e7 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3961,9 +3961,10 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) { TIME ltime; long tmp; - int error; + int error= 0; + int warning; - if (str_to_time(from, len, <ime, &error)) + if (str_to_time(from, len, <ime, &warning)) { tmp=0L; error= 2; @@ -3972,29 +3973,27 @@ int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) } else { - if (error) + if (warning & MYSQL_TIME_WARN_TRUNCATED) set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED, from, len, MYSQL_TIMESTAMP_TIME, 1); - - if (ltime.month) - ltime.day=0; - tmp=(ltime.day*24L+ltime.hour)*10000L+(ltime.minute*100+ltime.second); - if (tmp > 8385959) + if (warning & MYSQL_TIME_WARN_OUT_OF_RANGE) { - tmp=8385959; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, from, len, MYSQL_TIMESTAMP_TIME, !error); error= 1; } + if (ltime.month) + ltime.day=0; + tmp=(ltime.day*24L+ltime.hour)*10000L+(ltime.minute*100+ltime.second); if (error > 1) error= 2; } if (ltime.neg) tmp= -tmp; - error |= Field_time::store((longlong) tmp); + int3store(ptr,tmp); return error; } @@ -4003,16 +4002,16 @@ int Field_time::store(double nr) { long tmp; int error= 0; - if (nr > 8385959.0) + if (nr > (double)TIME_MAX_VALUE) { - tmp=8385959L; + tmp= TIME_MAX_VALUE; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME); error= 1; } - else if (nr < -8385959.0) + else if (nr < (double)-TIME_MAX_VALUE) { - tmp= -8385959L; + tmp= -TIME_MAX_VALUE; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME); error= 1; @@ -4040,17 +4039,17 @@ int Field_time::store(longlong nr) { long tmp; int error= 0; - if (nr > (longlong) 8385959L) + if (nr > (longlong) TIME_MAX_VALUE) { - tmp=8385959L; + tmp= TIME_MAX_VALUE; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME, 1); error= 1; } - else if (nr < (longlong) -8385959L) + else if (nr < (longlong) -TIME_MAX_VALUE) { - tmp= -8385959L; + tmp= -TIME_MAX_VALUE; set_datetime_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, nr, MYSQL_TIMESTAMP_TIME, 1); diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 2da0e8956c2..80e4cf8d456 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -95,6 +95,124 @@ static bool make_datetime(date_time_format_types format, TIME *ltime, } +/* + Wrapper over make_datetime() with validation of the input TIME value + + NOTE + see make_datetime() for more information + + RETURN + 1 if there was an error during converion + 0 otherwise +*/ + +static bool make_datetime_with_warn(date_time_format_types format, TIME *ltime, + String *str) +{ + int warning= 0; + bool rc; + + if (make_datetime(format, ltime, str)) + return 1; + if (check_time_range(ltime, &warning)) + return 1; + if (!warning) + return 0; + + make_truncated_value_warning(current_thd, str->ptr(), str->length(), + MYSQL_TIMESTAMP_TIME); + return make_datetime(format, ltime, str); +} + + +/* + Wrapper over make_time() with validation of the input TIME value + + NOTE + see make_time() for more info + + RETURN + 1 if there was an error during conversion + 0 otherwise +*/ + +static bool make_time_with_warn(const DATE_TIME_FORMAT *format, + TIME *l_time, String *str) +{ + int warning= 0; + make_time(format, l_time, str); + if (check_time_range(l_time, &warning)) + return 1; + if (warning) + { + make_truncated_value_warning(current_thd, str->ptr(), str->length(), + MYSQL_TIMESTAMP_TIME); + make_time(format, l_time, str); + } + + return 0; +} + + +/* + Convert seconds to TIME value with overflow checking + + SYNOPSIS: + sec_to_time() + seconds number of seconds + unsigned_flag 1, if 'seconds' is unsigned, 0, otherwise + ltime output TIME value + + DESCRIPTION + If the 'seconds' argument is inside TIME data range, convert it to a + corresponding value. + Otherwise, truncate the resulting value to the nearest endpoint, and + produce a warning message. + + RETURN + 1 if the value was truncated during conversion + 0 otherwise +*/ + +static bool sec_to_time(longlong seconds, bool unsigned_flag, TIME *ltime) +{ + uint sec; + + bzero((char *)ltime, sizeof(*ltime)); + + if (seconds < 0) + { + if (unsigned_flag) + goto overflow; + ltime->neg= 1; + if (seconds < -3020399) + goto overflow; + seconds= -seconds; + } + else if (seconds > 3020399) + goto overflow; + + sec= (uint) ((ulonglong) seconds % 3600); + ltime->hour= (uint) (seconds/3600); + ltime->minute= sec/60; + ltime->second= sec % 60; + + return 0; + +overflow: + ltime->hour= TIME_MAX_HOUR; + ltime->minute= TIME_MAX_MINUTE; + ltime->second= TIME_MAX_SECOND; + + char buf[22]; + int len= (int)(longlong10_to_str(seconds, buf, unsigned_flag ? 10 : -10) + - buf); + make_truncated_value_warning(current_thd, buf, len, MYSQL_TIMESTAMP_TIME); + + return 1; +} + + /* Date formats corresponding to compound %r and %T conversion specifiers @@ -1487,8 +1605,6 @@ int Item_func_now::save_in_field(Field *to, bool no_conversions) String *Item_func_sec_to_time::val_str(String *str) { DBUG_ASSERT(fixed == 1); - longlong seconds=(longlong) args[0]->val_int(); - uint sec; TIME ltime; if ((null_value=args[0]->null_value) || str->alloc(19)) @@ -1497,19 +1613,8 @@ String *Item_func_sec_to_time::val_str(String *str) return (String*) 0; } - ltime.neg= 0; - if (seconds < 0) - { - seconds= -seconds; - ltime.neg= 1; - } - - sec= (uint) ((ulonglong) seconds % 3600); - ltime.day= 0; - ltime.hour= (uint) (seconds/3600); - ltime.minute= sec/60; - ltime.second= sec % 60; - + sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, <ime); + make_time((DATE_TIME_FORMAT *) 0, <ime, str); return str; } @@ -1518,16 +1623,15 @@ String *Item_func_sec_to_time::val_str(String *str) longlong Item_func_sec_to_time::val_int() { DBUG_ASSERT(fixed == 1); - longlong seconds=args[0]->val_int(); - longlong sign=1; + TIME ltime; + if ((null_value=args[0]->null_value)) return 0; - if (seconds < 0) - { - seconds= -seconds; - sign= -1; - } - return sign*((seconds / 3600)*10000+((seconds/60) % 60)*100+ (seconds % 60)); + + sec_to_time(args[0]->val_int(), args[0]->unsigned_flag, <ime); + + return (ltime.neg ? -1 : 1) * + ((ltime.hour)*10000 + ltime.minute*100 + ltime.second); } @@ -2531,7 +2635,9 @@ String *Item_func_add_time::val_str(String *str) } if (l_time1.neg != l_time2.neg) l_sign= -l_sign; - + + bzero((char *)&l_time3, sizeof(l_time3)); + l_time3.neg= calc_time_diff(&l_time1, &l_time2, -l_sign, &seconds, µseconds); @@ -2560,9 +2666,9 @@ String *Item_func_add_time::val_str(String *str) } l_time3.hour+= days*24; - if (!make_datetime(l_time1.second_part || l_time2.second_part ? - TIME_MICROSECOND : TIME_ONLY, - &l_time3, str)) + if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY, + &l_time3, str)) return str; null_date: @@ -2617,6 +2723,8 @@ String *Item_func_timediff::val_str(String *str) if (l_time1.neg != l_time2.neg) l_sign= -l_sign; + bzero((char *)&l_time3, sizeof(l_time3)); + l_time3.neg= calc_time_diff(&l_time1, &l_time2, l_sign, &seconds, µseconds); @@ -2630,9 +2738,9 @@ String *Item_func_timediff::val_str(String *str) calc_time_from_sec(&l_time3, (long) seconds, microseconds); - if (!make_datetime(l_time1.second_part || l_time2.second_part ? - TIME_MICROSECOND : TIME_ONLY, - &l_time3, str)) + if (!make_datetime_with_warn(l_time1.second_part || l_time2.second_part ? + TIME_MICROSECOND : TIME_ONLY, + &l_time3, str)) return str; null_date: @@ -2650,29 +2758,57 @@ String *Item_func_maketime::val_str(String *str) { DBUG_ASSERT(fixed == 1); TIME ltime; + bool overflow= 0; - long hour= (long) args[0]->val_int(); - long minute= (long) args[1]->val_int(); - long second= (long) args[2]->val_int(); + longlong hour= args[0]->val_int(); + longlong minute= args[1]->val_int(); + longlong second= args[2]->val_int(); if ((null_value=(args[0]->null_value || - args[1]->null_value || - args[2]->null_value || - minute > 59 || minute < 0 || - second > 59 || second < 0 || - str->alloc(19)))) + args[1]->null_value || + args[2]->null_value || + minute < 0 || minute > 59 || + second < 0 || second > 59 || + str->alloc(19)))) return 0; + bzero((char *)<ime, sizeof(ltime)); ltime.neg= 0; + + /* Check for integer overflows */ if (hour < 0) { - ltime.neg= 1; - hour= -hour; + if (args[0]->unsigned_flag) + overflow= 1; + else + ltime.neg= 1; + } + if (-hour > UINT_MAX || hour > UINT_MAX) + overflow= 1; + + if (!overflow) + { + ltime.hour= (uint) ((hour < 0 ? -hour : hour)); + ltime.minute= (uint) minute; + ltime.second= (uint) second; + } + else + { + ltime.hour= TIME_MAX_HOUR; + ltime.minute= TIME_MAX_MINUTE; + ltime.second= TIME_MAX_SECOND; + char buf[28]; + char *ptr= longlong10_to_str(hour, buf, args[0]->unsigned_flag ? 10 : -10); + int len = (int)(ptr - buf) + + my_sprintf(ptr, (ptr, ":%02u:%02u", (uint)minute, (uint)second)); + make_truncated_value_warning(current_thd, buf, len, MYSQL_TIMESTAMP_TIME); + } + + if (make_time_with_warn((DATE_TIME_FORMAT *) 0, <ime, str)) + { + null_value= 1; + return 0; } - ltime.hour= (ulong) hour; - ltime.minute= (ulong) minute; - ltime.second= (ulong) second; - make_time((DATE_TIME_FORMAT *) 0, <ime, str); return str; } @@ -2878,7 +3014,7 @@ bool Item_func_str_to_date::get_date(TIME *ltime, uint fuzzy_date) goto null_date; null_value= 0; - bzero((char*) ltime, sizeof(ltime)); + bzero((char*) ltime, sizeof(*ltime)); date_time_format.format.str= (char*) format->ptr(); date_time_format.format.length= format->length(); if (extract_date_time(&date_time_format, val->ptr(), val->length(), diff --git a/sql/time.cc b/sql/time.cc index ef832ac5a70..ddc5e6435be 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -255,9 +255,9 @@ my_time_t TIME_to_timestamp(THD *thd, const TIME *t, bool *in_dst_time_gap) bool str_to_time_with_warn(const char *str, uint length, TIME *l_time) { - int was_cut; - bool ret_val= str_to_time(str, length, l_time, &was_cut); - if (was_cut) + int warning; + bool ret_val= str_to_time(str, length, l_time, &warning); + if (ret_val || warning) make_truncated_value_warning(current_thd, str, length, MYSQL_TIMESTAMP_TIME); return ret_val; } From d8191af7ee29165385edb05a1e188fad4603e18d Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 4 Oct 2006 16:28:23 +0200 Subject: [PATCH 013/131] Fixup the regex's parsing the mysqld's version and variables Add paths for ndb binaries Some more backport issues --- mysql-test/include/have_ndb.inc | 1 - mysql-test/mysql-test-run.pl | 104 ++++++++++++++++++++++++-------- 2 files changed, 78 insertions(+), 27 deletions(-) diff --git a/mysql-test/include/have_ndb.inc b/mysql-test/include/have_ndb.inc index 9b85197abe8..84e60657876 100644 --- a/mysql-test/include/have_ndb.inc +++ b/mysql-test/include/have_ndb.inc @@ -1,4 +1,3 @@ ---exec test x$NDB_STATUS_OK = x1 -- require r/have_ndb.require disable_query_log; show variables like "have_ndbcluster"; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 39c116a3fcb..3ad083dbd0c 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1141,7 +1141,7 @@ sub check_mysqld_features () { # print out version and a list of all features and settings # my $found_variable_list_start= 0; - my $spec_file= "$opt_vardir/tmp/mysqld.spec"; + my $spec_file= "$opt_vardir/mysqld.spec"; if ( mtr_run($exe_mysqld, ["--no-defaults", "--verbose", @@ -1174,20 +1174,31 @@ sub check_mysqld_features () { if (!$found_variable_list_start) { # Look for start of variables list - if ( $line =~ /-*\s-*/ ) + if ( $line =~ /[\-]+\s[\-]+/ ) { $found_variable_list_start= 1; } - } else { + } + else + { # Put variables into hash - if ( $line =~ /^(\w*)[ \t]*(\w*)$/ ) + if ( $line =~ /^([\S]+)[ \t]+(.*)$/ ) { + # print "$1=$2\n"; $mysqld_variables{$1}= $2; } + else + { + # The variable list is ended with a blank line, so when a line + # doesn't match the above regex, break the loop + last; + } } } } + unlink($spec_file); mtr_error("Could not find version of MySQL") unless $mysql_version_id; + mtr_error("Could not find variabes list") unless $found_variable_list_start; check_ndbcluster_support(\%mysqld_variables); check_ssl_support(\%mysqld_variables); @@ -1197,6 +1208,14 @@ sub check_mysqld_features () { { # Instance manager is not supported until 5.0 $opt_skip_im= 1; + + } + + if ( $mysql_version_id < 50100 ) + { + # Slave cluster is not supported until 5.1 + $opt_skip_ndbcluster_slave= 1; + } # Set default values from mysqld_variables @@ -1294,13 +1313,26 @@ sub executable_setup () { mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables", "$path_client_bindir/mysql_fix_privilege_tables"); - if ( $opt_with_ndbcluster) + if ( ! $opt_skip_ndbcluster) { # Look for ndb tols and binaries - $path_ndb_tools_dir= mtr_path_exists("$glob_basedir/ndb/tools", + my $ndb_path= mtr_path_exists("$glob_basedir/ndb", + "$glob_basedir/storage/ndb"); + + $path_ndb_tools_dir= mtr_path_exists("$ndb_path/tools", "$glob_basedir/bin"); - $exe_ndb_mgm= mtr_exe_exists("$glob_basedir/ndb/src/mgmclient/ndb_mgm", - "$glob_basedir/bin/ndb_mgm"); + $exe_ndb_mgm= + mtr_exe_exists("$ndb_path/src/mgmclient/ndb_mgm", + "$glob_basedir/bin/ndb_mgm"); + $exe_ndb_mgmd= + mtr_exe_exists("$ndb_path/src/mgmsrv/ndb_mgmd", + "$glob_basedir/bin/ndb_mgmd"); + $exe_ndb_waiter= + mtr_exe_exists("$ndb_path/tools/ndb_waiter", + "$glob_basedir/bin/ndb_waiter"); + $exe_ndbd= + mtr_exe_exists("$ndb_path/src/kernel/ndbd", + "$glob_basedir/bin/ndbd"); } # Look for the udf_example library @@ -1616,7 +1648,8 @@ sub environment_setup () { # Setup env so childs can execute mysql_fix_system_tables # ---------------------------------------------------- my $cmdline_mysql_fix_system_tables= - "$exe_mysql_fix_system_tables --no-defaults --host=localhost --user=root --password= " . + "$exe_mysql_fix_system_tables --no-defaults --host=localhost " . + "--user=root --password= " . "--basedir=$glob_basedir --bindir=$path_client_bindir --verbose " . "--port=$master->[0]->{'port'} " . "--socket=$master->[0]->{'path_sock'}"; @@ -1832,7 +1865,7 @@ sub check_ssl_support ($) { return; } - if ( $mysqld_variables->{'ssl'} eq "FALSE" ) + if ( ! $mysqld_variables->{'ssl'} ) { if ( $opt_ssl) { @@ -1883,7 +1916,7 @@ sub check_ndbcluster_support ($) { return; } - if ( $mysqld_variables->{'ndbcluster'} eq "FALSE") + if ( ! $mysqld_variables->{'ndb-connectstring'} ) { mtr_report("Skipping ndbcluster, mysqld not compiled with ndbcluster"); $opt_skip_ndbcluster= 1; @@ -1949,6 +1982,11 @@ sub ndbcluster_start_install ($) { s/CHOOSE_HOSTNAME_.*/$ndb_host/; s/CHOOSE_FILESYSTEM/$cluster->{'data_dir'}/; s/CHOOSE_PORT_MGM/$cluster->{'port'}/; + if ( $mysql_version_id < 50000 ) + { + my $base_port= $cluster->{'port'} + 1; + s/CHOOSE_PORT_TRANSPORTER/$base_port/; + } s/CHOOSE_DiskPageBufferMemory/$ndb_pbmem/; print OUT "$_ \n"; @@ -2070,7 +2108,10 @@ sub ndbd_start ($$$) { mtr_add_arg($args, "--no-defaults"); mtr_add_arg($args, "--core"); mtr_add_arg($args, "--ndb-connectstring=%s", "$cluster->{'connect_string'}"); - mtr_add_arg($args, "--character-sets-dir=%s", "$path_charsetsdir"); + if ( $mysql_version_id >= 50000) + { + mtr_add_arg($args, "--character-sets-dir=%s", "$path_charsetsdir"); + } mtr_add_arg($args, "--nodaemon"); mtr_add_arg($args, "$extra_args"); @@ -2247,8 +2288,6 @@ sub run_suite () { mtr_report_stats($tests); -# Look for testname.warning files if --do-test= - mtr_timer_stop($glob_timers,"suite"); } @@ -2298,7 +2337,8 @@ sub mysql_install_db () { my $cluster_started_ok= 1; # Assume it can be started if (ndbcluster_start_install($clusters->[0]) || - $max_slave_num && ndbcluster_start_install($clusters->[1])) + ($max_slave_num && !$opt_skip_ndbcluster_slave && + ndbcluster_start_install($clusters->[1]))) { mtr_warning("Failed to start install of cluster"); $cluster_started_ok= 0; @@ -2986,7 +3026,10 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--ndbcluster", $prefix); mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, $cluster->{'connect_string'}); - mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); + if ( $mysql_version_id >= 50000 ) + { + mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); + } } } @@ -3061,7 +3104,10 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--ndbcluster", $prefix); mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, $clusters->[$slave->[$idx]->{'cluster'}]->{'connect_string'}); - mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); + if ( $mysql_version_id >= 50000 ) + { + mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); + } } } # end slave @@ -3646,16 +3692,21 @@ sub run_testcase_start_servers($) { { # Test needs cluster, start an extra mysqld connected to cluster - # First wait for first mysql server to have created ndb system tables ok - # FIXME This is a workaround so that only one mysqld creates the tables - if ( ! sleep_until_file_created( - "$master->[0]->{'path_myddir'}/cluster/apply_status.ndb", - $master->[0]->{'start_timeout'}, - $master->[0]->{'pid'})) + if ( $mysql_version_id >= 50100 ) { - mtr_report("Failed to create 'cluster/apply_status' table"); - report_failure_and_restart($tinfo); - return; + # First wait for first mysql server to have created ndb system + # tables ok FIXME This is a workaround so that only one mysqld + # create the tables + if ( ! sleep_until_file_created( + "$master->[0]->{'path_myddir'}/cluster/apply_status.ndb", + $master->[0]->{'start_timeout'}, + $master->[0]->{'pid'})) + { + mtr_report_test_name($tinfo); + mtr_report("Failed to create 'cluster/apply_status' table"); + report_failure_and_restart($tinfo); + return; + } } mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n"); @@ -3679,6 +3730,7 @@ sub run_testcase_start_servers($) { unless ( mtr_im_start($instance_manager, $tinfo->{im_opts}) ) { + mtr_report_test_name($tinfo); report_failure_and_restart($tinfo); mtr_report("Failed to start Instance Manager. " . "The test '$tname' is marked as failed."); From 0903a9f836a22de33d6b32d628180ebb4a32b836 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 4 Oct 2006 18:48:22 +0200 Subject: [PATCH 014/131] --ndb-extra-logging option to mysqld is not available until 5.1 --- mysql-test/mysql-test-run.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 3ad083dbd0c..91e2920ff19 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -3026,7 +3026,7 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--ndbcluster", $prefix); mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, $cluster->{'connect_string'}); - if ( $mysql_version_id >= 50000 ) + if ( $mysql_version_id >= 50100 ) { mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); } @@ -3104,7 +3104,7 @@ sub mysqld_arguments ($$$$$) { mtr_add_arg($args, "%s--ndbcluster", $prefix); mtr_add_arg($args, "%s--ndb-connectstring=%s", $prefix, $clusters->[$slave->[$idx]->{'cluster'}]->{'connect_string'}); - if ( $mysql_version_id >= 50000 ) + if ( $mysql_version_id >= 50100 ) { mtr_add_arg($args, "%s--ndb-extra-logging", $prefix); } From 914f2bbc2aa4cee5d6d108cf95af739f17507aa5 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 4 Oct 2006 19:21:22 +0200 Subject: [PATCH 015/131] Create the mysqld.spec file with a unique name in mysql-test dir, $opt_var_dir haven't been created yet --- mysql-test/mysql-test-run.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 91e2920ff19..1305d9d59e6 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1141,7 +1141,7 @@ sub check_mysqld_features () { # print out version and a list of all features and settings # my $found_variable_list_start= 0; - my $spec_file= "$opt_vardir/mysqld.spec"; + my $spec_file= "$glob_mysql_test_dir/mysqld.spec.$$"; if ( mtr_run($exe_mysqld, ["--no-defaults", "--verbose", From 6ac9c43e516688e3f411737688d3ea6b158fdde1 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 4 Oct 2006 22:50:34 +0200 Subject: [PATCH 016/131] Set slave_load_path to ../../var/tmp in version prior to 5.0 to be compatible with mysql-test-run.sh --- mysql-test/mysql-test-run.pl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 1305d9d59e6..108a97f03b4 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -3068,8 +3068,13 @@ sub mysqld_arguments ($$$$$) { # Directory where slaves find the dumps generated by "load data" # on the server. The path need to have constant length otherwise # test results will vary, thus a relative path is used. + my $slave_load_path= "../tmp"; + if ( $mysql_version_id < 50000 ) + { + $slave_load_path= "../../var/tmp"; + } mtr_add_arg($args, "%s--slave-load-tmpdir=%s", $prefix, - "../tmp"); + $slave_load_path); mtr_add_arg($args, "%s--socket=%s", $prefix, $slave->[$idx]->{'path_sock'}); mtr_add_arg($args, "%s--set-variable=slave_net_timeout=10", $prefix); From c29427ec3cb3ebfc7f2897fd6ed547647c969af5 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 4 Oct 2006 22:52:44 +0200 Subject: [PATCH 017/131] Use replace_regex to mask the output of file_id= in "show binlog events" that depends on previous tests What is this? replace_regex in 4.1! :) --- mysql-test/r/rpl_charset.result | 4 ++-- mysql-test/t/rpl_charset.test | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/rpl_charset.result b/mysql-test/r/rpl_charset.result index 292cfb19175..0ebd97d0b6a 100644 --- a/mysql-test/r/rpl_charset.result +++ b/mysql-test/r/rpl_charset.result @@ -147,10 +147,10 @@ master-bin.000001 3577 Intvar 1 3577 INSERT_ID=4 master-bin.000001 3605 Query 1 3605 use `mysqltest2`; insert into t1 (b) values(LEAST("Müller","Muffler")) master-bin.000001 3698 Query 1 3698 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 3839 Intvar 1 3839 INSERT_ID=74 -master-bin.000001 3867 Create_file 1 3867 db=mysqltest2;table=t1;file_id=1;block_len=581 +master-bin.000001 3867 Create_file 1 3867 db=mysqltest2;table=t1;file_id=x;block_len=581 master-bin.000001 4540 Query 1 4540 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 4681 Intvar 1 4681 INSERT_ID=5 -master-bin.000001 4709 Exec_load 1 4709 ;file_id=1 +master-bin.000001 4709 Exec_load 1 4709 ;file_id=x master-bin.000001 4732 Query 1 4732 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64 master-bin.000001 4873 Query 1 4873 use `mysqltest2`; truncate table t1 master-bin.000001 4931 Query 1 4931 use `mysqltest2`; SET ONE_SHOT CHARACTER_SET_CLIENT=8,COLLATION_CONNECTION=31,COLLATION_DATABASE=9,COLLATION_SERVER=64 diff --git a/mysql-test/t/rpl_charset.test b/mysql-test/t/rpl_charset.test index cf079048fc3..a6f4c2ba9be 100644 --- a/mysql-test/t/rpl_charset.test +++ b/mysql-test/t/rpl_charset.test @@ -106,6 +106,8 @@ select * from mysqltest2.t1 order by a; connection master; drop database mysqltest2; drop database mysqltest3; +# file_id: xx can vary depending on previous tests +--replace_regex /file_id=[0-9]/file_id=x/ show binlog events from 79; sync_slave_with_master; From c243c7d866821ba98bb62e3a1519cadda5027862 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 4 Oct 2006 23:05:12 +0200 Subject: [PATCH 018/131] Clean up de_before_start_master/slave --- mysql-test/mysql-test-run.pl | 57 +++++++++++++----------------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 108a97f03b4..1d3c0ff1dd4 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -360,8 +360,8 @@ sub run_testcase_stop_servers ($$$); sub run_testcase_start_servers ($); sub run_testcase_check_skip_test($); sub report_failure_and_restart ($); -sub do_before_start_master ($$); -sub do_before_start_slave ($$); +sub do_before_start_master ($); +sub do_before_start_slave ($); sub ndbd_start ($$$); sub ndb_mgmd_start ($); sub mysqld_start ($$$); @@ -2866,24 +2866,17 @@ sub report_failure_and_restart ($) { ############################################################################## -# The embedded server needs the cleanup so we do some of the start work -# but stop before actually running mysqld or anything. -sub do_before_start_master ($$) { - my $tname= shift; - my $init_script= shift; +sub do_before_start_master ($) { + my ($tinfo)= @_; + + my $tname= $tinfo->{'name'}; + my $init_script= $tinfo->{'master_sh'}; # FIXME what about second master..... - # Remove stale binary logs except for 2 tests which need them FIXME here???? - if ( $tname ne "rpl_crash_binlog_ib_1b" and - $tname ne "rpl_crash_binlog_ib_2b" and - $tname ne "rpl_crash_binlog_ib_3b") + foreach my $bin ( glob("$opt_vardir/log/master*-bin*") ) { - # FIXME we really want separate dir for binlogs - foreach my $bin ( glob("$opt_vardir/log/master*-bin*") ) - { - unlink($bin); - } + unlink($bin); } # FIXME only remove the ones that are tied to this master @@ -2903,31 +2896,23 @@ sub do_before_start_master ($$) { # mtr_warning("$init_script exited with code $ret"); } } - # for gcov FIXME needed? If so we need more absolute paths - # chdir($glob_basedir); } -sub do_before_start_slave ($$) { - my $tname= shift; - my $init_script= shift; +sub do_before_start_slave ($) { + my ($tinfo)= @_; - # Remove stale binary logs and old master.info files - # except for too tests which need them - if ( $tname ne "rpl_crash_binlog_ib_1b" and - $tname ne "rpl_crash_binlog_ib_2b" and - $tname ne "rpl_crash_binlog_ib_3b" ) + my $tname= $tinfo->{'name'}; + my $init_script= $tinfo->{'master_sh'}; + + foreach my $bin ( glob("$opt_vardir/log/slave*-bin*") ) { - # FIXME we really want separate dir for binlogs - foreach my $bin ( glob("$opt_vardir/log/slave*-bin*") ) - { - unlink($bin); - } - # FIXME really master?! - unlink("$slave->[0]->{'path_myddir'}/master.info"); - unlink("$slave->[0]->{'path_myddir'}/relay-log.info"); + unlink($bin); } + unlink("$slave->[0]->{'path_myddir'}/master.info"); + unlink("$slave->[0]->{'path_myddir'}/relay-log.info"); + # Run slave initialization shell script if one exists if ( $init_script ) { @@ -3687,7 +3672,7 @@ sub run_testcase_start_servers($) { if ( !$master->[0]->{'pid'} ) { # Master mysqld is not started - do_before_start_master($tname,$tinfo->{'master_sh'}); + do_before_start_master($tinfo); mysqld_start($master->[0],$tinfo->{'master_opt'},[]); @@ -3752,7 +3737,7 @@ sub run_testcase_start_servers($) { restore_slave_databases($tinfo->{'slave_num'}); - do_before_start_slave($tname,$tinfo->{'slave_sh'}); + do_before_start_slave($tinfo); if ( ! $opt_skip_ndbcluster_slave and !$clusters->[1]->{'pid'} and From 587754cab67b94ff9be1b780479f23cbcb0c2d30 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 4 Oct 2006 23:07:49 +0200 Subject: [PATCH 019/131] Use switch --old-log-format to mysqld started by im only in 5.1 and up --- mysql-test/mysql-test-run.pl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 1d3c0ff1dd4..a2a840208da 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2539,7 +2539,10 @@ EOF ; print OUT "nonguarded\n" if $instance->{'nonguarded'}; - print OUT "log-output=FILE\n" if $instance->{'old_log_format'}; + if ( $mysql_version_id >= 50100 ) + { + print OUT "log-output=FILE\n" if $instance->{'old_log_format'}; + } print OUT "\n"; } From 80184739ff67f018b15e2f94f23c75a44fa55740 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 4 Oct 2006 23:15:04 +0200 Subject: [PATCH 020/131] Look for mysqlslap from 5.1, it's also available on windows --- mysql-test/mysql-test-run.pl | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index a2a840208da..b5fdf01ada4 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1307,6 +1307,10 @@ sub executable_setup () { $exe_mysqlbinlog= mtr_exe_exists("$path_client_bindir/mysqlbinlog"); $exe_mysqladmin= mtr_exe_exists("$path_client_bindir/mysqladmin"); $exe_mysql= mtr_exe_exists("$path_client_bindir/mysql"); + if ( $mysql_version_id >= 50100 ) + { + $exe_mysqlslap= mtr_exe_exists("$path_client_bindir/mysqlslap"); + } # Look for mysql_fix_system_table script $exe_mysql_fix_system_tables= @@ -1540,21 +1544,18 @@ sub environment_setup () { # ---------------------------------------------------- # Setup env so childs can execute mysqlslap # ---------------------------------------------------- - unless ( $glob_win32 ) - { - my $cmdline_mysqlslap= - "$exe_mysqlslap -uroot " . - "--port=$master->[0]->{'port'} " . - "--socket=$master->[0]->{'path_sock'} --password= " . - "--lock-directory=$opt_tmpdir"; + my $cmdline_mysqlslap= + "$exe_mysqlslap -uroot " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password= " . + "--lock-directory=$opt_tmpdir"; - if ( $opt_debug ) - { - $cmdline_mysqlslap .= - " --debug=d:t:A,$path_vardir_trace/log/mysqlslap.trace"; - } - $ENV{'MYSQL_SLAP'}= $cmdline_mysqlslap; + if ( $opt_debug ) + { + $cmdline_mysqlslap .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlslap.trace"; } + $ENV{'MYSQL_SLAP'}= $cmdline_mysqlslap; # ---------------------------------------------------- # Setup env so childs can execute mysqlimport From 56ccee0f6c690239c762a88b3ccc2d8e7609d1bd Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 4 Oct 2006 23:19:06 +0200 Subject: [PATCH 021/131] Only setup cmdline_myslslap if exe_mysqlslap defined --- mysql-test/mysql-test-run.pl | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index b5fdf01ada4..7f2b61efb4c 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1544,18 +1544,21 @@ sub environment_setup () { # ---------------------------------------------------- # Setup env so childs can execute mysqlslap # ---------------------------------------------------- - my $cmdline_mysqlslap= - "$exe_mysqlslap -uroot " . - "--port=$master->[0]->{'port'} " . - "--socket=$master->[0]->{'path_sock'} --password= " . - "--lock-directory=$opt_tmpdir"; - - if ( $opt_debug ) + if ( $exe_mysqlslap ) { - $cmdline_mysqlslap .= - " --debug=d:t:A,$path_vardir_trace/log/mysqlslap.trace"; + my $cmdline_mysqlslap= + "$exe_mysqlslap -uroot " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'} --password= " . + "--lock-directory=$opt_tmpdir"; + + if ( $opt_debug ) + { + $cmdline_mysqlslap .= + " --debug=d:t:A,$path_vardir_trace/log/mysqlslap.trace"; + } + $ENV{'MYSQL_SLAP'}= $cmdline_mysqlslap; } - $ENV{'MYSQL_SLAP'}= $cmdline_mysqlslap; # ---------------------------------------------------- # Setup env so childs can execute mysqlimport From 2d5c7c42a31d5867070b85041b63d340bf1b7486 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 4 Oct 2006 23:34:05 +0200 Subject: [PATCH 022/131] Update "get_errcode_from_name" - add missing DBUG_RETURN - Change type of st_error->code to uint, that should be more than enough to hold the error numbers between 1000 and around 2000 --- client/mysqltest.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index d49693fa324..f4fa95afeb1 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2429,7 +2429,7 @@ void do_set_charset(struct st_command *command) typedef struct { const char *name; - long code; + uint code; } st_error; static st_error global_error_names[] = @@ -2443,8 +2443,8 @@ static st_error global_error_names[] = uint get_errcode_from_name(char *error_name, char *error_end) { -#ifdef HAVE_MYSQLD_ERNAME DBUG_ENTER("get_errcode_from_name"); +#ifdef HAVE_MYSQLD_ERNAME /* SQL error as string */ st_error *e= global_error_names; @@ -2461,8 +2461,7 @@ uint get_errcode_from_name(char *error_name, char *error_end) if (!strncmp(error_name, e->name, (int) (error_end - error_name)) && (uint) strlen(e->name) == (uint) (error_end - error_name)) { - return (uint) e->code; - break; + DBUG_RETURN(e->code); } } if (!e->name) @@ -2472,7 +2471,7 @@ uint get_errcode_from_name(char *error_name, char *error_end) LINT_INIT(error_end); abort_not_in_this_version(); #endif - return 0; + DBUG_RETURN(0);; } From b56d31eb05ec18e8a0f6be26c2464acda21897fd Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 4 Oct 2006 23:57:31 +0200 Subject: [PATCH 023/131] Add skip-bdb to im defaults file in 5.0 --- mysql-test/mysql-test-run.pl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 7f2b61efb4c..dac1a4b553e 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2541,7 +2541,10 @@ skip-innodb skip-ndbcluster EOF ; - + if ( $mysql_version_id < 50100 ) + { + print OUT "skip-bdb\n"; + } print OUT "nonguarded\n" if $instance->{'nonguarded'}; if ( $mysql_version_id >= 50100 ) { From dd2a184f69e3634ccbf2bc48e6f0b445d633f0d2 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 00:12:54 +0200 Subject: [PATCH 024/131] Set the small configuration a little bit larger for 4.1 --- mysql-test/mysql-test-run.pl | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index dac1a4b553e..f40077e53a1 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1959,11 +1959,22 @@ sub ndbcluster_start_install ($) { if (!$opt_bench) { # Use a smaller configuration - $ndb_no_ord=32; - $ndb_con_op=5000; - $ndb_dmem="20M"; - $ndb_imem="1M"; - $ndb_pbmem="4M"; + if ( $mysql_version_id < 50000 ) + { + # 4.1 is using a "larger" --small configuration + $ndb_no_ord=128; + $ndb_con_op=10000; + $ndb_dmem="40M"; + $ndb_imem="12M"; + } + else + { + $ndb_no_ord=32; + $ndb_con_op=5000; + $ndb_dmem="20M"; + $ndb_imem="1M"; + $ndb_pbmem="4M"; + } } my $config_file_template= "ndb/ndb_config_${nodes}_node.ini"; From 218034b7767c988eb4bb3c40039a113e729e5230 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 00:19:24 +0200 Subject: [PATCH 025/131] Fix detection of debug binaries. If mysqld ouputs "debug xx" in the variable list it's a debug binary --- mysql-test/mysql-test-run.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index f40077e53a1..1ff0b57687b 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1889,7 +1889,7 @@ sub check_ssl_support ($) { sub check_debug_support ($) { my $mysqld_variables= shift; - if ( $mysqld_variables->{'debug'} ) + if ( ! $mysqld_variables->{'debug'} ) { #mtr_report("Binaries are not debug compiled"); $debug_compiled_binaries= 0; From 6e405f58880577a2bb8b46437ea88f1a2547cbbd Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 12:25:24 +0200 Subject: [PATCH 026/131] Improve "check_eol_junk" to detect junk although there are multi line comments in the way. I.e take advantage of the fact that a # comment is always terminated by a new line Add tests for the above --- client/mysqltest.c | 44 +++++++++++++++++---- mysql-test/r/mysqltest.result | 17 ++++++++ mysql-test/t/mysqltest.test | 74 ++++++++++++++++++++++++++++++++--- 3 files changed, 121 insertions(+), 14 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index f4fa95afeb1..87d8484dbf8 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3578,17 +3578,15 @@ void scan_command_for_warnings(struct st_command *command) /* Check for unexpected "junk" after the end of query - This is normally caused by missing delimiters + This is normally caused by missing delimiters or when + switching between different delimiters */ -void check_eol_junk(const char *eol) +void check_eol_junk_line(const char *line) { - const char *p= eol; - DBUG_ENTER("check_eol_junk"); - DBUG_PRINT("enter", ("eol: %s", eol)); - /* Remove all spacing chars except new line */ - while (*p && my_isspace(charset_info, *p) && (*p != '\n')) - p++; + const char *p= line; + DBUG_ENTER("check_eol_junk_line"); + DBUG_PRINT("enter", ("line: %s", line)); /* Check for extra delimiter */ if (*p && !strncmp(p, delimiter, delimiter_length)) @@ -3604,6 +3602,36 @@ void check_eol_junk(const char *eol) DBUG_VOID_RETURN; } +void check_eol_junk(const char *eol) +{ + const char *p= eol; + DBUG_ENTER("check_eol_junk"); + DBUG_PRINT("enter", ("eol: %s", eol)); + + /* Skip past all spacing chars and comments */ + while (*p && (my_isspace(charset_info, *p) || *p == '#' || *p == '\n')) + { + /* Skip past comments started with # and ended with newline */ + if (*p && *p == '#') + { + p++; + while (*p && *p != '\n') + p++; + } + + /* Check this line */ + if (*p && *p == '\n') + check_eol_junk_line(p); + + if (*p) + p++; + } + + check_eol_junk_line(p); + + DBUG_VOID_RETURN; +} + /* diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index 4c243a64484..ed7267fb71d 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -152,6 +152,23 @@ mysqltest: At line 1: Missing delimiter mysqltest: At line 1: End of line junk detected: "sleep 7 # Another comment " +mysqltest: At line 1: Missing delimiter +mysqltest: At line 1: Missing delimiter +mysqltest: At line 1: End of line junk detected: "disconnect default + +# +# comment +# comment2 + +# comment 3 +--disable_query_log +" +mysqltest: At line 1: End of line junk detected: "disconnect default # comment +# comment part2 + +# comment 3 +--disable_query_log +" mysqltest: At line 1: Extra delimiter ";" found mysqltest: At line 1: Extra delimiter ";" found mysqltest: At line 1: Missing argument(s) to 'error' diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index 5b0df28981f..d98375ca746 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -359,18 +359,80 @@ select 3 from t1 ; # Missing delimiter # The comment will be "sucked into" the sleep command since # delimiter is missing until after "show status" ---system echo "sleep 4" > $MYSQLTEST_VARDIR/tmp/mysqltest.sql ---system echo "# A comment" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql ---system echo "show status;" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +sleep 4 +# A comment +show status; +EOF --error 1 --exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 # # Missing delimiter until eof # The comment will be "sucked into" the sleep command since -# delimiter is missing ---system echo "sleep 7" > $MYSQLTEST_VARDIR/tmp/mysqltest.sql ---system echo "# Another comment" >> $MYSQLTEST_VARDIR/tmp/mysqltest.sql +# delimiter is missing +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +sleep 7 +# Another comment +EOF +--error 1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 + +# +# Missing delimiter until "disable_query_log" +# +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +disconnect default + +# +# comment +# comment 3 +disable_query_log; +EOF +--error 1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 + +# +# Missing delimiter until "disable_query_log" +# +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +disconnect default + +# +# comment + +# comment 3 +disable_query_log; +EOF +--error 1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 + +# +# Missing delimiter until eof +# +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +disconnect default + +# +# comment +# comment2 + +# comment 3 +--disable_query_log +EOF +--error 1 +--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 + +# +# Missing delimiter until eof +# +--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql +disconnect default # comment +# comment part2 + +# comment 3 +--disable_query_log +EOF --error 1 --exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.sql 2>&1 From bf120e18c8e1e4040265ec5a41bb8a15936eb4d1 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 12:28:23 +0200 Subject: [PATCH 027/131] Set the environment variable NDB_STATUS_OK to indicate that cluster is installed ok. This is actually not needed for this script as it will skip ndb tests if cluster install failed. But provided for compatibility --- mysql-test/include/have_ndb.inc | 1 + mysql-test/mysql-test-run.pl | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/mysql-test/include/have_ndb.inc b/mysql-test/include/have_ndb.inc index 84e60657876..9b85197abe8 100644 --- a/mysql-test/include/have_ndb.inc +++ b/mysql-test/include/have_ndb.inc @@ -1,3 +1,4 @@ +--exec test x$NDB_STATUS_OK = x1 -- require r/have_ndb.require disable_query_log; show variables like "have_ndbcluster"; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 1ff0b57687b..d74a4e6c3be 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2665,6 +2665,19 @@ sub do_before_run_mysqltest($) { mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n"); } + + if ( $mysql_version_id < 50000 ) + { + # Set envirnoment variable NDB_STATUS_OK to 1 + # if script decided to run mysqltest cluster _is_ installed ok + $ENV{'NDB_STATUS_OK'} = "1"; + } + elsif ( $mysql_version_id < 50100 ) + { + # Set envirnoment variable NDB_STATUS_OK to YES + # if script decided to run mysqltest cluster _is_ installed ok + $ENV{'NDB_STATUS_OK'} = "YES"; + } } sub do_after_run_mysqltest($) From 1764f4870ed25b7b35e2ee13c7634138b4444d55 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 13:09:06 +0200 Subject: [PATCH 028/131] Print warning message if test was failed becuase of cluster install failure Improve check of wheter test case need slave cluster --- mysql-test/mysql-test-run.pl | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index d74a4e6c3be..f680ed909b2 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2619,21 +2619,24 @@ sub run_testcase_check_skip_test($) return 1; } - # If test needs cluster, check that master installed ok - if ( $tinfo->{'ndb_test'} and !$clusters->[0]->{'installed_ok'} ) + if ($tinfo->{'ndb_test'}) { - mtr_report_test_name($tinfo); - mtr_report_test_failed($tinfo); - return 1; - } + foreach my $cluster (@{$clusters}) + { + last if ($opt_skip_ndbcluster_slave and + $cluster->{'name'} eq 'Slave'); - # If test needs slave cluster, check that it installed ok - if ( $tinfo->{'ndb_test'} and $tinfo->{'slave_num'} and - !$clusters->[1]->{'installed_ok'} ) - { - mtr_report_test_name($tinfo); - mtr_report_test_failed($tinfo); - return 1; + # If test needs this cluster, check it was installed ok + if ( !$cluster->{'installed_ok'} ) + { + mtr_tofile($path_timefile, + "Test marked as failed because $cluster->{'name'} " . + "was not installed ok!"); + mtr_report_test_name($tinfo); + mtr_report_test_failed($tinfo); + return 1; + } + } } return 0; From 46b33921717a9ec860aca5e77fcab6f94c7cfa20 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 13:38:08 +0200 Subject: [PATCH 029/131] Add regex to detect the empty line that end the variable list. Some variable names in 5.1 is soo long that there is no space inbetween name and value. Outputing a warning about it, as that should probably be fixed. At least one space should be put between the name and value. --- mysql-test/mysql-test-run.pl | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index f680ed909b2..5ae5684d14c 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1189,9 +1189,19 @@ sub check_mysqld_features () { } else { - # The variable list is ended with a blank line, so when a line - # doesn't match the above regex, break the loop - last; + # The variable list is ended with a blank line + if ( $line =~ /^[\s]*$/ ) + { + last; + } + else + { + # Send out a warning, we should fix the variables that has no + # space between variable name and it's value + # or should it be fixed width column parsing? It does not + # look like that in function my_print_variables in my_getopt.c + mtr_warning("Could not parse variable list line : $line"); + } } } } From 1fb0862f3ca2f3be46c94a06bd87e25db1ffaf0c Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 13:45:50 +0200 Subject: [PATCH 030/131] 5.0 is also using the somewhat larger config for cluster --- mysql-test/mysql-test-run.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 5ae5684d14c..04daeb11b02 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1969,9 +1969,9 @@ sub ndbcluster_start_install ($) { if (!$opt_bench) { # Use a smaller configuration - if ( $mysql_version_id < 50000 ) + if ( $mysql_version_id < 50100 ) { - # 4.1 is using a "larger" --small configuration + # 4.1 and 5.0 is using a "larger" --small configuration $ndb_no_ord=128; $ndb_con_op=10000; $ndb_dmem="40M"; From 5f1da07a78e2da3ae6615b3683d3600774ba48f4 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 14:37:46 +0200 Subject: [PATCH 031/131] Add new option --mem to mysql-test-run.pl. It will automatically setup a symlink from var/ to a tmpfs area and thereby speed up the execution of the testsuite significantly --- mysql-test/mysql-test-run.pl | 71 ++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 8 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 04daeb11b02..20123a68159 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -209,6 +209,7 @@ our $opt_fast; our $opt_force; our $opt_reorder= 0; our $opt_enable_disabled; +our $opt_mem; our $opt_gcov; our $opt_gcov_err; @@ -643,6 +644,7 @@ sub command_line_setup () { 'tmpdir=s' => \$opt_tmpdir, 'vardir=s' => \$opt_vardir, 'benchdir=s' => \$glob_mysql_bench_dir, + 'mem' => \$opt_mem, # Misc 'comment=s' => \$opt_comment, @@ -715,6 +717,32 @@ sub command_line_setup () { } mtr_report("Using binlog format '$used_binlog_format'"); + # -------------------------------------------------------------------------- + # Check if we should speed up tests by trying to run on tmpfs + # -------------------------------------------------------------------------- + if ( $opt_mem ) + { + mtr_error("Can't use --mem and --vardir at the same time ") + if $opt_vardir; + mtr_error("Can't use --mem and --tmpdir at the same time ") + if $opt_tmpdir; + + # Use /dev/shm as the preferred location for vardir and + # thus implicitly also tmpdir. Add other locations to list + my @tmpfs_locations= ("/dev/shm"); + # One could maybe use "mount" to find tmpfs location(s) + foreach my $fs (@tmpfs_locations) + { + if ( -d $fs ) + { + mtr_report("Using tmpfs in $fs"); + $opt_mem= "$fs/var"; + $opt_mem .= $ENV{'MTR_BUILD_THREAD'} if $ENV{'MTR_BUILD_THREAD'}; + last; + } + } + } + # -------------------------------------------------------------------------- # Set the "var/" directory, as it is the base for everything else # -------------------------------------------------------------------------- @@ -1771,6 +1799,8 @@ sub kill_running_server () { sub cleanup_stale_files () { + my $created_by_mem_file= "$glob_mysql_test_dir/var/created_by_mem"; + mtr_report("Removing Stale Files"); if ( $opt_vardir eq "$glob_mysql_test_dir/var" ) @@ -1778,15 +1808,26 @@ sub cleanup_stale_files () { # # Running with "var" in mysql-test dir # - if ( -l "$glob_mysql_test_dir/var" ) + if ( -l $opt_vardir) { - # Some users creates a soft link in mysql-test/var to another area - # - allow it - mtr_report("WARNING: Using the 'mysql-test/var' symlink"); - rmtree("$opt_vardir/log"); - rmtree("$opt_vardir/ndbcluster-$opt_ndbcluster_port"); - rmtree("$opt_vardir/run"); - rmtree("$opt_vardir/tmp"); + # var is a symlink + if (-f $created_by_mem_file) + { + # Remove the directory which the link points at + rmtree(readlink($opt_vardir)); + # Remove the entire "var" dir + rmtree("$opt_vardir/"); + } + else + { + # Some users creates a soft link in mysql-test/var to another area + # - allow it + mtr_report("WARNING: Using the 'mysql-test/var' symlink"); + rmtree("$opt_vardir/log"); + rmtree("$opt_vardir/ndbcluster-$opt_ndbcluster_port"); + rmtree("$opt_vardir/run"); + rmtree("$opt_vardir/tmp"); + } } else { @@ -1808,6 +1849,17 @@ sub cleanup_stale_files () { rmtree("$opt_vardir/"); } + if ( $opt_mem ) + { + # Runinng with var as a link to some "memory" location, normally tmpfs + rmtree($opt_mem); + mkpath($opt_mem); + mtr_verbose("Creating symlink from $opt_vardir to $opt_mem"); + symlink($opt_mem, $opt_vardir); + # Put a small file to recognize this dir was created by --mem + mtr_tofile($created_by_mem_file, $opt_mem); + } + mkpath("$opt_vardir/log"); mkpath("$opt_vardir/run"); mkpath("$opt_vardir/tmp"); @@ -4326,6 +4378,9 @@ Options to control directories to use vardir=DIR The directory where files generated from the test run is stored (default: ./var). Specifying a ramdisk or tmpfs will speed up tests. + mem=DIR Run testsuite in "memory" using tmpfs if + available(default: /dev/shm) + Options to control what test suites or cases to run From c5fba0a888d21861675caca924737745385875ac Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 18:00:20 +0200 Subject: [PATCH 032/131] Bug #20010 mysql-test-run.pl: --record and --require conflict (test fails) - When --record is passed to mysqltest the whole testcase should be executed as it normally is while the output form the test is acumulating in ds_res. When test has finished ds_res should simply be written to the specified result file(if any) instead of comapring it against the result file. Simplify handling of --require and also the cecking of result files by splitting check_result function into one function 'check_require' that is specialised in checking require's and leave 'check_result' to do just that. - "mysqltest --record" has been considered unsafe, but with this really simple logic, it should be safe to use. --- client/mysqltest.c | 181 ++++++++++++++++++++++++--------------------- 1 file changed, 95 insertions(+), 86 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 87d8484dbf8..96bb5d6b80b 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -192,7 +192,7 @@ struct } master_pos; /* if set, all results are concated and compared against this file */ -const char *result_file= 0; +const char *result_file_name= 0; typedef struct st_var { @@ -382,9 +382,9 @@ struct st_command { char *query, *query_buf,*first_argument,*last_argument,*end; int first_word_len, query_len; - my_bool abort_on_error, require_file; + my_bool abort_on_error; struct st_expected_errors expected_errors; - char record_file[FN_REFLEN]; + char require_file[FN_REFLEN]; enum enum_commands type; }; @@ -410,9 +410,10 @@ VAR* var_get(const char *var_name, const char** var_name_end, my_bool raw, my_bool ignore_not_existing); void eval_expr(VAR* v, const char *p, const char** p_end); my_bool match_delimiter(int c, const char *delim, uint length); -void dump_result_to_reject_file(const char *record_file, char *buf, int size); -void dump_result_to_log_file(const char *record_file, char *buf, int size); -void dump_warning_messages(const char *record_file); +void dump_result_to_reject_file(char *buf, int size); +void dump_result_to_log_file(char *buf, int size); +void dump_warning_messages(); +void dump_progress(); void do_eval(DYNAMIC_STRING *query_eval, const char *query, const char *query_end, my_bool pass_through_escape_chars); @@ -742,12 +743,12 @@ void die(const char *fmt, ...) va_end(args); /* Dump the result that has been accumulated so far to .log file */ - if (result_file && ds_res.length) - dump_result_to_log_file(result_file, ds_res.str, ds_res.length); + if (result_file_name && ds_res.length) + dump_result_to_log_file(ds_res.str, ds_res.length); /* Dump warning messages */ - if (result_file && ds_warning_messages.length) - dump_warning_messages(result_file); + if (result_file_name && ds_warning_messages.length) + dump_warning_messages(); /* Clean up and exit */ free_used_memory(); @@ -926,41 +927,32 @@ err: /* - Check the content of ds against content of file fname + Check the content of ds against result file SYNOPSIS check_result ds - content to be checked - fname - name of file to check against - require_option - if set and check fails, the test will be aborted - with the special exit code "not supported test" RETURN VALUES error - the function will not return */ -void check_result(DYNAMIC_STRING* ds, const char *fname, - my_bool require_option) +void check_result(DYNAMIC_STRING* ds) { - int res= dyn_string_cmp(ds, fname); + DBUG_ASSERT(result_file_name); DBUG_ENTER("check_result"); - if (res && require_option) + switch (dyn_string_cmp(ds, result_file_name)) { - char reason[FN_REFLEN]; - fn_format(reason, fname, "", "", MY_REPLACE_EXT | MY_REPLACE_DIR); - abort_not_supported_test("Test requires: '%s'", reason); - } - switch (res) { case RESULT_OK: break; /* ok */ case RESULT_LENGTH_MISMATCH: - dump_result_to_reject_file(fname, ds->str, ds->length); + dump_result_to_reject_file(ds->str, ds->length); die("Result length mismatch"); break; case RESULT_CONTENT_MISMATCH: - dump_result_to_reject_file(fname, ds->str, ds->length); + dump_result_to_reject_file(ds->str, ds->length); die("Result content mismatch"); break; default: /* impossible */ @@ -971,6 +963,35 @@ void check_result(DYNAMIC_STRING* ds, const char *fname, } +/* + Check the content of ds against a require file + If match fails, abort the test with special error code + indicating that test is not supported + + SYNOPSIS + check_result + ds - content to be checked + fname - name of file to check against + + RETURN VALUES + error - the function will not return + +*/ + +void check_require(DYNAMIC_STRING* ds, const char *fname) +{ + DBUG_ENTER("check_require"); + + if (dyn_string_cmp(ds, fname)) + { + char reason[FN_REFLEN]; + fn_format(reason, fname, "", "", MY_REPLACE_EXT | MY_REPLACE_DIR); + abort_not_supported_test("Test requires: '%s'", reason); + } + DBUG_VOID_RETURN; +} + + static byte *get_var_key(const byte* var, uint* len, my_bool __attribute__((unused)) t) { @@ -2389,7 +2410,8 @@ int do_sleep(struct st_command *command, my_bool real_sleep) } -void do_get_file_name(char *filename, struct st_command *command) +void do_get_file_name(struct st_command *command, + char* dest, uint dest_max_len) { char *p= command->first_argument, *name; if (!*p) @@ -2400,7 +2422,7 @@ void do_get_file_name(char *filename, struct st_command *command) if (*p) *p++= 0; command->last_argument= p; - strmake(filename, name, FN_REFLEN); + strmake(dest, name, dest_max_len); } @@ -3672,8 +3694,7 @@ int read_command(struct st_command** command_ptr) insert_dynamic(&q_lines, (gptr) &command)) die(NullS); - command->record_file[0]= 0; - command->require_file= 0; + command->require_file[0]= 0; command->first_word_len= 0; command->query_len= 0; @@ -3767,8 +3788,8 @@ static struct my_option my_long_options[] = {"record", 'r', "Record output of test_file into result file.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"result-file", 'R', "Read/Store result from/in this file.", - (gptr*) &result_file, (gptr*) &result_file, 0, GET_STR, REQUIRED_ARG, - 0, 0, 0, 0, 0, 0}, + (gptr*) &result_file_name, (gptr*) &result_file_name, 0, + GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"server-arg", 'A', "Send option value to embedded server as a parameter.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"server-file", 'F', "Read embedded server arguments from file.", @@ -4018,35 +4039,35 @@ void str_to_file(const char *fname, char *str, int size) } -void dump_result_to_reject_file(const char *record_file, char *buf, int size) +void dump_result_to_reject_file(char *buf, int size) { char reject_file[FN_REFLEN]; - str_to_file(fn_format(reject_file, record_file, "", ".reject", + str_to_file(fn_format(reject_file, result_file_name, "", ".reject", MY_REPLACE_EXT), buf, size); } -void dump_result_to_log_file(const char *record_file, char *buf, int size) +void dump_result_to_log_file(char *buf, int size) { char log_file[FN_REFLEN]; - str_to_file(fn_format(log_file, record_file, "", ".log", + str_to_file(fn_format(log_file, result_file_name, "", ".log", MY_REPLACE_EXT), buf, size); } -void dump_progress(const char *record_file) +void dump_progress(void) { char log_file[FN_REFLEN]; - str_to_file(fn_format(log_file, record_file, "", ".progress", + str_to_file(fn_format(log_file, result_file_name, "", ".progress", MY_REPLACE_EXT), ds_progress.str, ds_progress.length); } -void dump_warning_messages(const char *record_file) +void dump_warning_messages(void) { char warn_file[FN_REFLEN]; - str_to_file(fn_format(warn_file, record_file, "", ".warnings", + str_to_file(fn_format(warn_file, result_file_name, "", ".warnings", MY_REPLACE_EXT), ds_warning_messages.str, ds_warning_messages.length); } @@ -4608,7 +4629,7 @@ void handle_error(struct st_command *command, DBUG_ENTER("handle_error"); - if (command->require_file) + if (command->require_file[0]) { /* The query after a "--require" failed. This is fine as long the server @@ -5004,12 +5025,12 @@ void run_query(MYSQL *mysql, struct st_command *command, int flags) } /* - When command->record_file is set the output of _this_ query + When command->require_file is set the output of _this_ query should be compared with an already existing file Create a temporary dynamic string to contain the output from this query. */ - if (command->record_file[0]) + if (command->require_file[0]) { init_dynamic_string(&ds_result, "", 1024, 1024); ds= &ds_result; @@ -5144,26 +5165,14 @@ void run_query(MYSQL *mysql, struct st_command *command, int flags) mysql_errno(mysql), mysql_error(mysql)); } - if (command->record_file[0]) + if (command->require_file[0]) { - /* A result file was specified for _this_ query */ - if (record) - { - /* - Recording in progress - Dump the output from _this_ query to the specified record_file - */ - str_to_file(command->record_file, ds->str, ds->length); - - } else { - - /* - The output from _this_ query should be checked against an already - existing file which has been specified using --require or --result - */ - check_result(ds, command->record_file, command->require_file); - } + /* A result file was specified for _this_ query + and the output should be checked against an already + existing file which has been specified using --require or --result + */ + check_require(ds, command->require_file); } dynstr_free(&ds_warnings); @@ -5391,7 +5400,7 @@ void mark_progress(struct st_command* command __attribute__((unused)), int main(int argc, char **argv) { struct st_command *command; - my_bool require_file= 0, q_send_flag= 0; + my_bool q_send_flag= 0; uint command_executed= 0, last_command_executed= 0; char save_file[FN_REFLEN]; MY_STAT res_info; @@ -5442,7 +5451,8 @@ int main(int argc, char **argv) init_dynamic_string(&ds_warning_messages, "", 0, 2048); parse_args(argc, argv); - DBUG_PRINT("info",("result_file: '%s'", result_file ? result_file : "")); + DBUG_PRINT("info",("result_file: '%s'", + result_file_name ? result_file_name : "")); if (mysql_server_init(embedded_server_arg_count, embedded_server_args, (char**) embedded_server_groups)) @@ -5594,9 +5604,8 @@ int main(int argc, char **argv) display_result_vertically= (command->type == Q_QUERY_VERTICAL); if (save_file[0]) { - strmov(command->record_file,save_file); - command->require_file=require_file; - save_file[0]=0; + strmake(command->require_file, save_file, sizeof(save_file)); + save_file[0]= 0; } run_query(&cur_con->mysql, command, QUERY_REAP_FLAG|QUERY_SEND_FLAG); display_result_vertically= old_display_result_vertically; @@ -5626,9 +5635,8 @@ int main(int argc, char **argv) if (save_file[0]) { - strmov(command->record_file,save_file); - command->require_file=require_file; - save_file[0]=0; + strmake(command->require_file, save_file, sizeof(save_file)); + save_file[0]= 0; } run_query(&cur_con->mysql, command, flags); command_executed++; @@ -5660,17 +5668,12 @@ int main(int argc, char **argv) command_executed++; command->last_argument= command->end; break; - case Q_RESULT: - do_get_file_name(save_file, command); - require_file=0; + case Q_REQUIRE: + do_get_file_name(command, save_file, sizeof(save_file)); break; case Q_ERROR: do_get_errcodes(command); break; - case Q_REQUIRE: - do_get_file_name(save_file, command); - require_file=1; - break; case Q_REPLACE: do_get_replace(command); break; @@ -5741,11 +5744,14 @@ int main(int argc, char **argv) else die("Parsing is already enabled"); break; - case Q_DIE: die("%s", command->first_argument); break; + case Q_RESULT: + die("result, deprecated command"); + break; + default: processed= 0; break; @@ -5802,12 +5808,14 @@ int main(int argc, char **argv) */ if (ds_res.length) { - if (result_file) + if (result_file_name) { + /* A result file has been specified */ + if (record) { - /* Dump the output from test to result file */ - str_to_file(result_file, ds_res.str, ds_res.length); + /* Recording - dump the output from test to result file */ + str_to_file(result_file_name, ds_res.str, ds_res.length); } else { @@ -5815,12 +5823,12 @@ int main(int argc, char **argv) - detect missing result file - detect zero size result file */ - check_result(&ds_res, result_file, 0); + check_result(&ds_res); } } else { - /* No result_file specified to compare with, print to stdout */ + /* No result_file_name specified to compare with, print to stdout */ printf("%s", ds_res.str); } } @@ -5829,7 +5837,8 @@ int main(int argc, char **argv) die("The test didn't produce any output"); } - if (!command_executed && result_file && my_stat(result_file, &res_info, 0)) + if (!command_executed && + result_file_name && my_stat(result_file_name, &res_info, 0)) { /* my_stat() successful on result file. Check if we have not run a @@ -5841,12 +5850,12 @@ int main(int argc, char **argv) die("No queries executed but result file found!"); } - if ( opt_mark_progress && result_file ) - dump_progress(result_file); + if ( opt_mark_progress && result_file_name ) + dump_progress(); /* Dump warning messages */ - if (result_file && ds_warning_messages.length) - dump_warning_messages(result_file); + if (result_file_name && ds_warning_messages.length) + dump_warning_messages(); dynstr_free(&ds_res); From ab862ca2dc15eba9f4f08c44c814fefc306701be Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 18:29:59 +0200 Subject: [PATCH 033/131] Use same --slave-load-tmpdir in all versions(backport from 5.0) --- mysql-test/mysql-test-run.pl | 4 ---- mysql-test/mysql-test-run.sh | 2 +- mysql-test/r/rpl_loaddata.result | 2 +- mysql-test/r/rpl_loaddatalocal.result | 4 ++-- mysql-test/r/rpl_log.result | 12 ++++++------ mysql-test/t/rpl_loaddatalocal.test | 8 +++++--- 6 files changed, 15 insertions(+), 17 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 20123a68159..51989f02f0e 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -3153,10 +3153,6 @@ sub mysqld_arguments ($$$$$) { # on the server. The path need to have constant length otherwise # test results will vary, thus a relative path is used. my $slave_load_path= "../tmp"; - if ( $mysql_version_id < 50000 ) - { - $slave_load_path= "../../var/tmp"; - } mtr_add_arg($args, "%s--slave-load-tmpdir=%s", $prefix, $slave_load_path); mtr_add_arg($args, "%s--socket=%s", $prefix, diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 15c7470a74c..141a725db2e 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -188,7 +188,7 @@ SYST=0 REALT=0 FAST_START="" MYSQL_TMP_DIR=$MYSQL_TEST_DIR/var/tmp -SLAVE_LOAD_TMPDIR=../../var/tmp #needs to be same length to test logging +SLAVE_LOAD_TMPDIR=../tmp #needs to be same length to test logging RES_SPACE=" " MYSQLD_SRC_DIRS="strings mysys include extra regex isam merge myisam \ myisammrg heap sql" diff --git a/mysql-test/r/rpl_loaddata.result b/mysql-test/r/rpl_loaddata.result index 65fc9d1b415..d0f2a885dcd 100644 --- a/mysql-test/r/rpl_loaddata.result +++ b/mysql-test/r/rpl_loaddata.result @@ -22,7 +22,7 @@ day id category name 2003-03-22 2416 a bbbbb show master status; File Position Binlog_Do_DB Binlog_Ignore_DB -slave-bin.000001 964 +slave-bin.000001 950 drop table t1; drop table t2; drop table t3; diff --git a/mysql-test/r/rpl_loaddatalocal.result b/mysql-test/r/rpl_loaddatalocal.result index b49ea842485..b2ca868a094 100644 --- a/mysql-test/r/rpl_loaddatalocal.result +++ b/mysql-test/r/rpl_loaddatalocal.result @@ -5,9 +5,9 @@ reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; create table t1(a int); -select * into outfile '../../var/master-data/rpl_loaddatalocal.select_outfile' from t1; +select * into outfile 'MYSQLTEST_VARDIR/master-data/rpl_loaddatalocal.select_outfile' from t1; truncate table t1; -load data local infile './var/master-data/rpl_loaddatalocal.select_outfile' into table t1; +load data local infile 'MYSQLTEST_VARDIR/master-data/rpl_loaddatalocal.select_outfile' into table t1; select a,count(*) from t1 group by a; a count(*) 1 10000 diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result index 3833800bfeb..c496f3d540a 100644 --- a/mysql-test/r/rpl_log.result +++ b/mysql-test/r/rpl_log.result @@ -73,7 +73,7 @@ master-bin.000002 276 start slave; show binary logs; Log_name File_size -slave-bin.000001 1285 +slave-bin.000001 1278 slave-bin.000002 170 show binlog events in 'slave-bin.000001' from 4; Log_name Pos Event_type Server_id Orig_log_pos Info @@ -84,11 +84,11 @@ slave-bin.000001 200 Query 1 200 use `test`; insert into t1 values (NULL) slave-bin.000001 263 Query 1 263 use `test`; drop table t1 slave-bin.000001 311 Query 1 311 use `test`; create table t1 (word char(20) not null) slave-bin.000001 386 Create_file 1 386 db=test;table=t1;file_id=1;block_len=581 -slave-bin.000001 1065 Exec_load 1 1065 ;file_id=1 -slave-bin.000001 1088 Query 1 1088 use `test`; drop table t1 -slave-bin.000001 1136 Query 1 1136 use `test`; create table t5 (a int) -slave-bin.000001 1194 Query 1 1194 use `test`; drop table t5 -slave-bin.000001 1242 Rotate 2 1242 slave-bin.000002;pos=4 +slave-bin.000001 1058 Exec_load 1 1058 ;file_id=1 +slave-bin.000001 1081 Query 1 1081 use `test`; drop table t1 +slave-bin.000001 1129 Query 1 1129 use `test`; create table t5 (a int) +slave-bin.000001 1187 Query 1 1187 use `test`; drop table t5 +slave-bin.000001 1235 Rotate 2 1235 slave-bin.000002;pos=4 show binlog events in 'slave-bin.000002' from 4; Log_name Pos Event_type Server_id Orig_log_pos Info slave-bin.000002 4 Query 1 4 use `test`; create table t1 (n int) diff --git a/mysql-test/t/rpl_loaddatalocal.test b/mysql-test/t/rpl_loaddatalocal.test index 2ca142c3b64..fd91aba856a 100644 --- a/mysql-test/t/rpl_loaddatalocal.test +++ b/mysql-test/t/rpl_loaddatalocal.test @@ -20,11 +20,13 @@ while ($1) } set SQL_LOG_BIN=1; enable_query_log; -select * into outfile '../../var/master-data/rpl_loaddatalocal.select_outfile' from t1; +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval select * into outfile '$MYSQLTEST_VARDIR/master-data/rpl_loaddatalocal.select_outfile' from t1; #This will generate a 20KB file, now test LOAD DATA LOCAL truncate table t1; -load data local infile './var/master-data/rpl_loaddatalocal.select_outfile' into table t1; -system rm ./var/master-data/rpl_loaddatalocal.select_outfile ; +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +eval load data local infile '$MYSQLTEST_VARDIR/master-data/rpl_loaddatalocal.select_outfile' into table t1; +--remove_file $MYSQLTEST_VARDIR/master-data/rpl_loaddatalocal.select_outfile save_master_pos; connection slave; sync_with_master; From c03c618dd8ba41e60ffd5929c5cf78e28d7db9f5 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 20:21:11 +0200 Subject: [PATCH 034/131] Make use of $opt_mem" and let 4.1 allow --vardir to be set. Still relies on the var/ directory but having it on tmpfs gives a big speedup. --- mysql-test/mysql-test-run.pl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 51989f02f0e..7778b99ea65 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -754,7 +754,10 @@ sub command_line_setup () { elsif ( $mysql_version_id < 50000 ) { # --vardir was specified - mtr_error("--vardir option not supported until MySQL 5.0"); + # It's only supported in 4.1 as a symlink from var/ + # by setting up $opt_mem that will be created + $opt_mem= $opt_vardir; + $opt_vardir= undef; } $path_vardir_trace= $opt_vardir; From 42e60f5e9061d04f0ac2643307528d6511c01f5e Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 20:45:16 +0200 Subject: [PATCH 035/131] No need to pass --valgrind to mysqltest anymore, the simple task of creating an environment variable is handled directly from the perl code. --- mysql-test/mysql-test-run.pl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 7778b99ea65..995baf2c0dd 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1749,6 +1749,11 @@ sub environment_setup () { print "Using IM_MYSQLD2_PORT = $ENV{IM_MYSQLD2_PORT}\n"; } } + + # Create an environment variable to make it possible + # to detect that valgrind is being used from test cases + $ENV{'VALGRIND_TEST'}= $opt_valgrind; + } @@ -4009,11 +4014,6 @@ sub run_mysqltest ($) { mtr_add_arg($args, "--big-test"); } - if ( $opt_valgrind ) - { - mtr_add_arg($args, "--valgrind"); - } - if ( $opt_compress ) { mtr_add_arg($args, "--compress"); From 02693c37d9926d246badc9dd742603f0a91bab1d Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 22:05:42 +0200 Subject: [PATCH 036/131] Add policy directive about keeping mysqltest framework tools identical in all versions --- client/mysqltest.c | 2 ++ mysql-test/mysql-test-run.pl | 43 +++++++++++++----------------------- 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 96bb5d6b80b..cf3afced427 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -22,6 +22,8 @@ See the "MySQL Test framework manual" for more information http://dev.mysql.com/doc/mysqltest/en/index.html + Please keep the test framework tools identical in all versions! + Written by: Sasha Pachev Matt Wagner diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 995baf2c0dd..6c8befdafa6 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1,30 +1,24 @@ #!/usr/bin/perl # -*- cperl -*- -# This is a transformation of the "mysql-test-run" Bourne shell script -# to Perl. There are reasons this rewrite is not the prettiest Perl -# you have seen # -# - The original script is huge and for most part uncommented, -# not even a usage description of the flags. +############################################################################## # -# - There has been an attempt to write a replacement in C for the -# original Bourne shell script. It was kind of working but lacked -# lot of functionality to really be a replacement. Not to redo -# that mistake and catch all the obscure features of the original -# script, the rewrite in Perl is more close to the original script -# meaning it also share some of the ugly parts as well. +# mysql-test-run.pl # -# - The original intention was that this script was to be a prototype -# to be the base for a new C version with full functionality. Since -# then it was decided that the Perl version should replace the -# Bourne shell version, but the Perl style still reflects the wish -# to make the Perl to C step easy. +# Tool used for executing a suite of .test file # -# Some coding style from the original intent has been kept +# See the "MySQL Test framework manual" for more information +# http://dev.mysql.com/doc/mysqltest/en/index.html +# +# Please keep the test framework tools identical in all versions! +# +############################################################################## +# +# Coding style directions for this perl script # # - To make this Perl script easy to alter even for those that not -# code Perl that often, the coding style is as close as possible to +# code Perl that often, keeep the coding style as close as possible to # the C/C++ MySQL coding standard. # # - All lists of arguments to send to commands are Perl lists/arrays, @@ -42,15 +36,6 @@ # the information. This separates the "find information" from the # "do the work" and makes the program more easy to maintain. # -# - At the moment, there are tons of "global" variables that control -# this script, even accessed from the files in "lib/*.pl". This -# will change over time, for now global variables are used instead -# of using %opt, %path and %exe hashes, because I want more -# compile time checking, that hashes would not give me. Once this -# script is debugged, hashes will be used and passed as parameters -# to functions, to more closely mimic how it would be coded in C -# using structs. -# # - The rule when it comes to the logic of this program is # # command_line_setup() - is to handle the logic between flags @@ -2758,10 +2743,12 @@ sub do_after_run_mysqltest($) my $tinfo= shift; my $tname= $tinfo->{'name'}; + mtr_tofile($path_mysqltest_log,"CURRENT TEST $tname\n"); + # Save info from this testcase run to mysqltest.log mtr_appendfile_to_file($path_timefile, $path_mysqltest_log) if -f $path_timefile; - mtr_tofile($path_mysqltest_log,"CURRENT TEST $tname\n"); + } From 76c63e716f9ab0950efa43aea4f34d86e88f477a Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 22:06:29 +0200 Subject: [PATCH 037/131] Open input file with "<" not ">>" --- mysql-test/lib/mtr_io.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/lib/mtr_io.pl b/mysql-test/lib/mtr_io.pl index 8a7fc56269c..a1d7ffe87d8 100644 --- a/mysql-test/lib/mtr_io.pl +++ b/mysql-test/lib/mtr_io.pl @@ -176,7 +176,7 @@ sub mtr_appendfile_to_file ($$) { my $to_file= shift; open(TOFILE,">>",$to_file) or mtr_error("can't open file \"$to_file\": $!"); - open(FROMFILE,">>",$from_file) + open(FROMFILE,"<",$from_file) or mtr_error("can't open file \"$from_file\": $!"); print TOFILE while (); close FROMFILE; From babde331a44139d08e574cce9533621bcb58c31c Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 22:29:16 +0200 Subject: [PATCH 038/131] Print the newly found version number in human readable format --- mysql-test/mysql-test-run.pl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 6c8befdafa6..4162e8cf0ef 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1180,9 +1180,10 @@ sub check_mysqld_features () { # Look for version if ( $line =~ /^$exe_mysqld\s\sVer\s([0-9]*)\.([0-9]*)\.([0-9]*)/ ) { - print "Major: $1 Minor: $2 Build: $3\n"; + #print "Major: $1 Minor: $2 Build: $3\n"; $mysql_version_id= $1*10000 + $2*100 + $3; - print "mysql_version_id: $mysql_version_id\n"; + #print "mysql_version_id: $mysql_version_id\n"; + mtr_report("MySQL Version $1.$2.$3"); } } else From 15ffeaa093cdcb8da32dacbc1e1a49dc1d3b2dc5 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 5 Oct 2006 23:19:32 +0200 Subject: [PATCH 039/131] Add target to Makefile which uses the much faster --mem switch to mysql-test-run.pl --- Makefile.am | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Makefile.am b/Makefile.am index 2aefbd05283..8d0746e6a64 100644 --- a/Makefile.am +++ b/Makefile.am @@ -124,3 +124,8 @@ test-force-pl: cd mysql-test; \ ./mysql-test-run.pl --force && \ ./mysql-test-run.pl --ps-protocol --force + +test-force-pl-mem: + cd mysql-test; \ + ./mysql-test-run.pl --force --mem && \ + ./mysql-test-run.pl --ps-protocol --force --mem From ae4df31df49ba8055aa197d7c292abab9490a9d3 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 6 Oct 2006 00:57:10 +0200 Subject: [PATCH 040/131] Add printout of file in which warning was detected Cleanup .progress, .reject, .log and .warnings files produced by mysqltest --- client/mysqltest.c | 13 ++++++++++++- mysql-test/include/ctype_like_escape.inc | 4 ++-- mysql-test/mysql-test-run.pl | 15 ++++++++------- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index cf3afced427..8d8c20c3e8f 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -818,6 +818,9 @@ void verbose_msg(const char *fmt, ...) va_start(args, fmt); fprintf(stderr, "mysqltest: "); + if (cur_file && cur_file != file_stack) + fprintf(stderr, "In included file \"%s\": ", + cur_file->file_name); if (start_lineno != 0) fprintf(stderr, "At line %u: ", start_lineno); vfprintf(stderr, fmt, args); @@ -839,7 +842,15 @@ void warning_msg(const char *fmt, ...) dynstr_append(&ds_warning_messages, "mysqltest: "); if (start_lineno != 0) { - len= my_snprintf(buff, sizeof(buff), "Warning detected at line %d: ", + dynstr_append(&ds_warning_messages, "Warning detected "); + if (cur_file && cur_file != file_stack) + { + len= my_snprintf(buff, sizeof(buff), "in included file %s ", + cur_file->file_name); + dynstr_append_mem(&ds_warning_messages, + buff, len); + } + len= my_snprintf(buff, sizeof(buff), "at line %d: ", start_lineno); dynstr_append_mem(&ds_warning_messages, buff, len); diff --git a/mysql-test/include/ctype_like_escape.inc b/mysql-test/include/ctype_like_escape.inc index ac97fbaa1a0..d4abc33c178 100644 --- a/mysql-test/include/ctype_like_escape.inc +++ b/mysql-test/include/ctype_like_escape.inc @@ -11,8 +11,8 @@ insert into t1 values('ab_def'); insert into t1 values('abc_ef'); insert into t1 values('abcd_f'); insert into t1 values('abcde_'); --- should return ab_def +# should return ab_def select c1 as c1u from t1 where c1 like 'ab\_def'; --- should return ab_def +# should return ab_def select c1 as c2h from t1 where c1 like 'ab#_def' escape '#'; drop table t1; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 4162e8cf0ef..23a9b30d76b 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2704,15 +2704,16 @@ sub do_before_run_mysqltest($) my $tinfo= shift; my $tname= $tinfo->{'name'}; - # Remove old reject file - if ( $opt_suite eq "main" ) + # Remove old files produced by mysqltest + my $result_dir= "r"; + if ( ! $opt_suite eq "main" ) { - unlink("r/$tname.reject"); - } - else - { - unlink("suite/$opt_suite/r/$tname.reject"); + $result_dir= "suite/$opt_suite/r"; } + unlink("$result_dir/$tname.reject"); + unlink("$result_dir/$tname.progress"); + unlink("$result_dir/$tname.log"); + unlink("$result_dir/$tname.warnings"); mtr_tonewfile($path_current_test_log,"$tname\n"); # Always tell where we are From f638be87cbb74f971d713bfd008eb57a9985f10c Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 6 Oct 2006 01:22:33 +0200 Subject: [PATCH 041/131] Rename "snapshot_setup" to "datadir_setup" as that is what is done by it. Move call f dunction into "initialize_servers" so it's called also in stress and bench mode --- mysql-test/mysql-test-run.pl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 23a9b30d76b..21f64bc3cb6 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -323,7 +323,7 @@ our $default_mysqld_port; sub main (); sub initial_setup (); sub command_line_setup (); -sub snapshot_setup (); +sub datadir_setup (); sub executable_setup (); sub environment_setup (); sub kill_running_server (); @@ -416,7 +416,6 @@ sub main () { unless $need_ndbcluster; $opt_skip_im= 1 unless $need_im; - snapshot_setup(); initialize_servers(); run_suite($opt_suite, $tests); @@ -1122,7 +1121,7 @@ sub command_line_setup () { $path_snapshot= "$opt_tmpdir/snapshot_$opt_master_myport/"; } -sub snapshot_setup () { +sub datadir_setup () { # Make a list of all data_dirs @data_dir_lst = ( @@ -2370,6 +2369,9 @@ sub run_suite () { ############################################################################## sub initialize_servers () { + + datadir_setup(); + if ( ! $glob_use_running_server ) { kill_running_server(); From 22f1cc58c24cdeb6a460943695782ceca33100cf Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 6 Oct 2006 11:23:19 +0200 Subject: [PATCH 042/131] Improve 'run_testcase_need_master_restart' to require restart if master is not already started Improve 'run_testcase_need_slave_restart' to detect if a slave restart really is necessary. So far all rpl test requires a slave restart, but for all other tests it can be skipped Improve the sort order used by --reorder --- mysql-test/lib/mtr_cases.pl | 31 ++++++++------ mysql-test/mysql-test-run.pl | 83 ++++++++++++++---------------------- 2 files changed, 51 insertions(+), 63 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index bb92730444c..344c80ac0bf 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -164,31 +164,36 @@ sub collect_test_cases ($) { # Make a mapping of test name to a string that represents how that test # should be sorted among the other tests. Put the most important criterion # first, then a sub-criterion, then sub-sub-criterion, et c. - foreach $tinfo (@$cases) + foreach $tinfo (@$cases) { my @this_criteria = (); + # # Append the criteria for sorting, in order of importance. - push(@this_criteria, join("!", sort @{$tinfo->{'master_opt'}}) . "~"); # Ending with "~" makes empty sort later than filled + # + push(@this_criteria, "ndb=" . ($tinfo->{'ndb_test'} ? "1" : "0")); push(@this_criteria, "restart=" . ($tinfo->{'master_restart'} ? "1" : "0")); - push(@this_criteria, "big_test=" . ($tinfo->{'big_test'} ? "1" : "0")); - push(@this_criteria, join("|", sort keys %{$tinfo})); # Group similar things together. The values may differ substantially. FIXME? - push(@this_criteria, $tinfo->{'name'}); # Finally, order by the name - + # Group test with similar options together. + # Ending with "~" makes empty sort later than filled + push(@this_criteria, join("!", sort @{$tinfo->{'master_opt'}}) . "~"); + + # Finally, order by the name + push(@this_criteria, $tinfo->{'name'}); + $sort_criteria{$tinfo->{"name"}} = join(" ", @this_criteria); } @$cases = sort { $sort_criteria{$a->{"name"}} cmp $sort_criteria{$b->{"name"}}; } @$cases; ### For debugging the sort-order -# foreach $tinfo (@$cases) -# { -# print $sort_criteria{$tinfo->{"name"}}; -# print " -> \t"; -# print $tinfo->{"name"}; -# print "\n"; -# } + foreach $tinfo (@$cases) + { + print $sort_criteria{$tinfo->{"name"}}; + print " -> \t"; + print $tinfo->{"name"}; + print "\n"; + } } return $cases; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 21f64bc3cb6..31a2c1e32a3 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -3522,6 +3522,11 @@ sub run_testcase_need_master_restart($) join(" ", @{$tinfo->{'master_opt'}}) . "' != '" . join(" ", @{$master->[0]->{'start_opts'}}) . "'" ); } + elsif( ! $master->[0]->{'pid'} ) + { + $do_restart= 1; + mtr_verbose("Restart because: master is not started"); + } return $do_restart; } @@ -3533,57 +3538,35 @@ sub run_testcase_need_slave_restart($) # We try to find out if we are to restart the slaves my $do_slave_restart= 0; # Assumes we don't have to - # FIXME only restart slave when necessary - $do_slave_restart= 1; + if ( $max_slave_num == 0) + { + mtr_verbose("No testcase use slaves, no slave restarts"); + } + else + { -# if ( ! $slave->[0]->{'pid'} ) -# { -# # mtr_verbose("Slave not started, no need to check slave restart"); -# } -# elsif ( $do_restart ) -# { -# $do_slave_restart= 1; # Always restart if master restart -# mtr_verbose("Restart slave because: Master restart"); -# } -# elsif ( $tinfo->{'slave_sh'} ) -# { -# $do_slave_restart= 1; # Always restart if script to run -# mtr_verbose("Restart slave because: Always restart if script to run"); -# } -# elsif ( ! $opt_skip_ndbcluster_slave and -# $tinfo->{'ndb_test'} == 0 and -# $clusters->[1]->{'pid'} != 0 ) -# { -# $do_slave_restart= 1; # Restart without slave cluster -# mtr_verbose("Restart slave because: Test does not need slave cluster"); -# } -# elsif ( ! $opt_with_ndbcluster_slave and -# $tinfo->{'ndb_test'} == 1 and -# $clusters->[1]->{'pid'} == 0 ) -# { -# $do_slave_restart= 1; # Restart with slave cluster -# mtr_verbose("Restart slave because: Test need slave cluster"); -# } -# elsif ( $tinfo->{'slave_restart'} ) -# { -# $do_slave_restart= 1; -# mtr_verbose("Restart slave because: slave_restart"); -# } -# elsif ( $slave->[0]->{'running_slave_is_special'} ) -# { -# $do_slave_restart= 1; -# mtr_verbose("Restart slave because: running_slave_is_special"); -# } -# # Check that running slave was started with same options -# # as the current test requires -# elsif (! mtr_same_opts($slave->[0]->{'start_opts'}, -# $tinfo->{'slave_opt'}) ) -# { -# $do_slave_restart= 1; -# mtr_verbose("Restart slave because: running with different options '" . -# join(" ", @{$tinfo->{'slave_opt'}}) . "' != '" . -# join(" ", @{$slave->[0]->{'start_opts'}}) . "'" ); -# } + # Check if any slave is currently started + my $any_slave_started= 0; + foreach my $mysqld (@{$slave}) + { + if ( $mysqld->{'pid'} ) + { + $any_slave_started= 1; + last; + } + } + + if ($any_slave_started) + { + mtr_verbose("Any slave is started, need to restart"); + $do_slave_restart= 1; + } + elsif ( $tinfo->{'slave_num'} ) + { + mtr_verbose("Test need slave, check for restart"); + $do_slave_restart= 1; + } + } return $do_slave_restart; From a0fd2ad5d4d13b79463ae65849f72e6d12637736 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 6 Oct 2006 11:49:31 +0200 Subject: [PATCH 043/131] Only print thesort order debug printout if using script-debug --- mysql-test/lib/mtr_cases.pl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 344c80ac0bf..d73c7a83dca 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -186,13 +186,13 @@ sub collect_test_cases ($) { @$cases = sort { $sort_criteria{$a->{"name"}} cmp $sort_criteria{$b->{"name"}}; } @$cases; -### For debugging the sort-order - foreach $tinfo (@$cases) + if ( $::opt_script_debug ) { - print $sort_criteria{$tinfo->{"name"}}; - print " -> \t"; - print $tinfo->{"name"}; - print "\n"; + # For debugging the sort-order + foreach $tinfo (@$cases) + { + print("$sort_criteria{$tinfo->{'name'}} -> \t$tinfo->{'name'}\n"); + } } } From 9d5b871f166538bd8bf57fbb7aad60a101526abf Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 6 Oct 2006 12:46:21 +0200 Subject: [PATCH 044/131] Always need restart for im_* tests --- mysql-test/mysql-test-run.pl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 31a2c1e32a3..2226c62a262 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -3490,6 +3490,11 @@ sub run_testcase_need_master_restart($) $do_restart= 1; # Restart with cluster mtr_verbose("Restart because: Test need cluster"); } + elsif( $tinfo->{'component_id'} eq 'im' ) + { + $do_restart= 1; + mtr_verbose("Restart because: Always restart for im tests"); + } elsif ( $master->[0]->{'running_master_is_special'} and $master->[0]->{'running_master_is_special'}->{'timezone'} eq $tinfo->{'timezone'} and From d3bc5df83716c115d27e4aa09b8f6410f84a7fce Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 6 Oct 2006 13:33:12 +0200 Subject: [PATCH 045/131] Modify regex for parsing mysqld version as the mysqld is sometimes a libtool wrapper and the "mysqld --version" command will print "/path/.libs/lt-mysqld Ver x.x.x" --- mysql-test/mysql-test-run.pl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 2226c62a262..4eef16e0388 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1177,7 +1177,9 @@ sub check_mysqld_features () { if ( !$mysql_version_id ) { # Look for version - if ( $line =~ /^$exe_mysqld\s\sVer\s([0-9]*)\.([0-9]*)\.([0-9]*)/ ) + my $exe_name= basename($exe_mysqld); + mtr_verbose("exe_name: $exe_name"); + if ( $line =~ /^\S*$exe_name\s\sVer\s([0-9]*)\.([0-9]*)\.([0-9]*)/ ) { #print "Major: $1 Minor: $2 Build: $3\n"; $mysql_version_id= $1*10000 + $2*100 + $3; From 738ba624d3a408d50581e2c42582b7985f203d8c Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 6 Oct 2006 16:26:17 +0200 Subject: [PATCH 046/131] Fix problem with specifying vardir, mysql_version_id was not yet available when vardir arguments is checked Move the code to look for exe_mysqld earlier => to initial_setup Fix warnings detected by running with "diagnostics" Remove unused option "opt_result_ext" Init "path_ndb_examples_dir" --- mysql-test/lib/mtr_cases.pl | 9 +-- mysql-test/lib/mtr_report.pl | 7 --- mysql-test/mysql-test-run.pl | 108 +++++++++++++++++++++-------------- 3 files changed, 67 insertions(+), 57 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index d73c7a83dca..517a42d88c1 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -250,6 +250,7 @@ sub collect_one_test_case($$$$$$$) { $tinfo->{'path'}= $path; $tinfo->{'timezone'}= "GMT-3"; # for UNIX_TIMESTAMP tests to work + $tinfo->{'slave_num'}= 0; # Default, no slave if ( defined mtr_match_prefix($tname,"rpl") ) { if ( $::opt_skip_rpl ) @@ -259,7 +260,8 @@ sub collect_one_test_case($$$$$$$) { return; } - $tinfo->{'slave_num'}= 1; # Default, use one slave + + $tinfo->{'slave_num'}= 1; # Default for rpl* tests, use one slave if ( $tname eq 'rpl_failsafe' or $tname eq 'rpl_chain_temp_table' ) { @@ -346,11 +348,6 @@ sub collect_one_test_case($$$$$$$) { if ( defined $value ) { $tinfo->{'result_file'}= "r/$value.result"; - if ( $::opt_result_ext and $::opt_record or - -f "$tinfo->{'result_file'}$::opt_result_ext") - { - $tinfo->{'result_file'}.= $::opt_result_ext; - } $tinfo->{'master_restart'}= 0; last MASTER_OPT; } diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index 6e3796133f2..ab2940b3714 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -53,13 +53,6 @@ sub mtr_show_failed_diff ($) { { $result_file= $eval_file; } - elsif ( $::opt_result_ext and - ( $::opt_record or -f "$result_file$::opt_result_ext" )) - { - # If we have an special externsion for result files we use it if we are - # recording or a result file with that extension exists. - $result_file= "$result_file$::opt_result_ext"; - } my $diffopts= $::opt_udiff ? "-u" : "-c"; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 4eef16e0388..34968f5ebe5 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -142,6 +142,8 @@ our $opt_vardir; # A path but set directly on cmd line our $path_vardir_trace; # unix formatted opt_vardir for trace files our $opt_tmpdir; # A path but set directly on cmd line +our $default_vardir; + our $opt_usage; our $opt_suite; @@ -230,8 +232,6 @@ our $opt_ndbconnectstring_slave; our $opt_record; our $opt_check_testcases; -our $opt_result_ext; - our $opt_skip; our $opt_skip_rpl; our $max_slave_num= 0; @@ -471,6 +471,38 @@ sub initial_setup () { $opt_source_dist ? $glob_mysql_test_dir : $glob_basedir; $glob_timers= mtr_init_timers(); + + # + # Find the mysqld executable to be able to find the mysqld version + # number as early as possible + # + + # Look for the path where to find the client binaries + $path_client_bindir= mtr_path_exists("$glob_basedir/client", + "$glob_basedir/client_release", + "$glob_basedir/client_debug", + "$glob_basedir/client/release", + "$glob_basedir/client/debug", + "$glob_basedir/bin"); + + # Look for the mysqld executable + $exe_mysqld= mtr_exe_exists ("$glob_basedir/sql/mysqld", + "$path_client_bindir/mysqld-max-nt", + "$path_client_bindir/mysqld-max", + "$path_client_bindir/mysqld-nt", + "$path_client_bindir/mysqld", + "$path_client_bindir/mysqld-debug", + "$path_client_bindir/mysqld-max", + "$glob_basedir/libexec/mysqld", + "$glob_basedir/sql/release/mysqld", + "$glob_basedir/sql/debug/mysqld"); + + $exe_master_mysqld= $exe_master_mysqld || $exe_mysqld; + $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld; + + # Use the mysqld found above to find out what features are available + check_mysqld_features(); + } @@ -731,17 +763,20 @@ sub command_line_setup () { # Set the "var/" directory, as it is the base for everything else # -------------------------------------------------------------------------- + $default_vardir= "$glob_mysql_test_dir/var"; if ( ! $opt_vardir ) { - $opt_vardir= "$glob_mysql_test_dir/var"; + $opt_vardir= $default_vardir; } - elsif ( $mysql_version_id < 50000 ) + elsif ( $mysql_version_id < 50000 and + $opt_vardir ne $default_vardir ) { - # --vardir was specified - # It's only supported in 4.1 as a symlink from var/ - # by setting up $opt_mem that will be created + # Version 4.1 and --vardir was specified + # Only supported as a symlink from var/ + # by setting up $opt_mem that symlink will be created $opt_mem= $opt_vardir; - $opt_vardir= undef; + $opt_vardir= $default_vardir; + mtr_report("Using 4.1 vardir trick"); } $path_vardir_trace= $opt_vardir; @@ -1247,8 +1282,8 @@ sub check_mysqld_features () { } # Set default values from mysqld_variables - $opt_socket= %mysqld_variables->{'socket'}; - $default_mysqld_port = %mysqld_variables->{'port'}; + $opt_socket= $mysqld_variables{'socket'}; + $default_mysqld_port = $mysqld_variables{'port'}; } @@ -1269,32 +1304,6 @@ sub executable_setup () { } } - # Look for the path where to find the client binaries - $path_client_bindir= mtr_path_exists("$glob_basedir/client", - "$glob_basedir/client_release", - "$glob_basedir/client_debug", - "$glob_basedir/client/release", - "$glob_basedir/client/debug", - "$glob_basedir/bin"); - - # Look for the mysqld executable - $exe_mysqld= mtr_exe_exists ("$glob_basedir/sql/mysqld", - "$path_client_bindir/mysqld-max-nt", - "$path_client_bindir/mysqld-max", - "$path_client_bindir/mysqld-nt", - "$path_client_bindir/mysqld", - "$path_client_bindir/mysqld-debug", - "$path_client_bindir/mysqld-max", - "$glob_basedir/libexec/mysqld", - "$glob_basedir/sql/release/mysqld", - "$glob_basedir/sql/debug/mysqld"); - - $exe_master_mysqld= $exe_master_mysqld || $exe_mysqld; - $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld; - - # Use the mysqld found above to find out what features are available - check_mysqld_features(); - # Look for language files and charsetsdir, use same share my $path_share= mtr_path_exists("$glob_basedir/share", "$glob_basedir/sql/share", @@ -1326,6 +1335,10 @@ sub executable_setup () { "$glob_basedir/server-tools/instance-manager/mysqlmanager", "$glob_basedir/libexec/mysqlmanager"); } + else + { + $exe_im= "not_available"; + } # Look for the client binaries $exe_mysqlcheck= mtr_exe_exists("$path_client_bindir/mysqlcheck"); @@ -1365,12 +1378,19 @@ sub executable_setup () { $exe_ndbd= mtr_exe_exists("$ndb_path/src/kernel/ndbd", "$glob_basedir/bin/ndbd"); + + $path_ndb_examples_dir= + mtr_path_exists("$ndb_path/ndbapi-examples", + "$ndb_path/examples"); + $exe_ndb_example= + mtr_file_exists("$path_ndb_examples_dir/ndbapi_simple/ndbapi_simple"); } # Look for the udf_example library $lib_udf_example= - mtr_file_exists("$glob_basedir/sql/.libs/udf_example.so"); - + mtr_file_exists("$glob_basedir/sql/.libs/udf_example.so", + "$glob_basedir/sql/release/udf_example.dll", + "$glob_basedir/sql/debug/udf_example.dll"); # Look for mysqltest executable if ( $glob_use_embedded_server ) @@ -1468,11 +1488,11 @@ sub environment_setup () { } $ENV{'LD_LIBRARY_PATH'}= join(":", @ld_library_paths, - split(':', $ENV{'LD_LIBRARY_PATH'})); + split(':', qw($ENV{'LD_LIBRARY_PATH'}))); mtr_debug("LD_LIBRARY_PATH: $ENV{'LD_LIBRARY_PATH'}"); $ENV{'DYLD_LIBRARY_PATH'}= join(":", @ld_library_paths, - split(':', $ENV{'DYLD_LIBRARY_PATH'})); + split(':', qw($ENV{'DYLD_LIBRARY_PATH'}))); mtr_debug("DYLD_LIBRARY_PATH: $ENV{'DYLD_LIBRARY_PATH'}"); @@ -1798,7 +1818,7 @@ sub cleanup_stale_files () { mtr_report("Removing Stale Files"); - if ( $opt_vardir eq "$glob_mysql_test_dir/var" ) + if ( $opt_vardir eq $default_vardir ) { # # Running with "var" in mysql-test dir @@ -1838,7 +1858,7 @@ sub cleanup_stale_files () { # Remove the var/ dir in mysql-test dir if any # this could be an old symlink that shouldn't be there - rmtree("$glob_mysql_test_dir/var"); + rmtree($default_vardir); # Remove the "var" dir rmtree("$opt_vardir/"); @@ -1849,7 +1869,7 @@ sub cleanup_stale_files () { # Runinng with var as a link to some "memory" location, normally tmpfs rmtree($opt_mem); mkpath($opt_mem); - mtr_verbose("Creating symlink from $opt_vardir to $opt_mem"); + mtr_report("Creating symlink from $opt_vardir to $opt_mem"); symlink($opt_mem, $opt_vardir); # Put a small file to recognize this dir was created by --mem mtr_tofile($created_by_mem_file, $opt_mem); @@ -2710,7 +2730,7 @@ sub do_before_run_mysqltest($) # Remove old files produced by mysqltest my $result_dir= "r"; - if ( ! $opt_suite eq "main" ) + if ( $opt_suite ne "main" ) { $result_dir= "suite/$opt_suite/r"; } From 7ba1880369833c256e8989239478aebb5127a296 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 6 Oct 2006 17:15:26 +0200 Subject: [PATCH 047/131] Add error handling of failure to start server to "run_testcase_start_servers" --- mysql-test/lib/mtr_report.pl | 8 +++--- mysql-test/mysql-test-run.pl | 48 +++++++++++++++++++++++++----------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index ab2940b3714..4708de92e07 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -144,9 +144,11 @@ sub mtr_report_test_failed ($) { print "[ fail ]\n"; } - # FIXME Instead of this test, and meaningless error message in 'else' - # we should write out into $::path_timefile when the error occurs. - if ( -f $::path_timefile ) + if ( $tinfo->{'comment'} ) + { + print "\nERROR: $tinfo->{'comment'}\n"; + } + elsif ( -f $::path_timefile ) { print "\nErrors are (from $::path_timefile) :\n"; print mtr_fromfile($::path_timefile); # FIXME print_file() instead diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 34968f5ebe5..5ba42fb2c25 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2775,6 +2775,9 @@ sub do_after_run_mysqltest($) mtr_appendfile_to_file($path_timefile, $path_mysqltest_log) if -f $path_timefile; + # Remove the file that mysqltest writes info to + unlink($path_timefile); + } @@ -2807,7 +2810,12 @@ sub run_testcase ($) { my $died= mtr_record_dead_children(); if ($died or $master_restart or $slave_restart) { - run_testcase_start_servers($tinfo); + if (run_testcase_start_servers($tinfo)) + { + mtr_report_test_name($tinfo); + report_failure_and_restart($tinfo); + return 1; + } } # ---------------------------------------------------------------------- @@ -3748,6 +3756,17 @@ sub run_testcase_stop_servers($$$) { } } + +# +# run_testcase_start_servers +# +# Start the servers neede by this test case +# +# RETURN +# 0 OK +# 1 Start failed +# + sub run_testcase_start_servers($) { my $tinfo= shift; @@ -3755,7 +3774,7 @@ sub run_testcase_start_servers($) { if ( $glob_use_running_server or $glob_use_embedded_server ) { - return; + return 0; } # ------------------------------------------------------- @@ -3796,10 +3815,9 @@ sub run_testcase_start_servers($) { $master->[0]->{'start_timeout'}, $master->[0]->{'pid'})) { - mtr_report_test_name($tinfo); - mtr_report("Failed to create 'cluster/apply_status' table"); - report_failure_and_restart($tinfo); - return; + + $tinfo->{'comment'}= "Failed to create 'cluster/apply_status' table"; + return 1; } } mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n"); @@ -3822,13 +3840,10 @@ sub run_testcase_start_servers($) { im_create_defaults_file($instance_manager); - unless ( mtr_im_start($instance_manager, $tinfo->{im_opts}) ) + if ( ! mtr_im_start($instance_manager, $tinfo->{im_opts}) ) { - mtr_report_test_name($tinfo); - report_failure_and_restart($tinfo); - mtr_report("Failed to start Instance Manager. " . - "The test '$tname' is marked as failed."); - return; + $tinfo->{'comment'}= "Failed to start Instance Manager. "; + return 1; } } @@ -3878,7 +3893,8 @@ sub run_testcase_start_servers($) { if (ndbcluster_wait_started($cluster, "")) { # failed to start - mtr_report("Start of $cluster->{'name'} cluster failed, "); + $tinfo->{'comment'}= "Start of $cluster->{'name'} cluster failed"; + return 1; } } @@ -3890,9 +3906,13 @@ sub run_testcase_start_servers($) { if (mysqld_wait_started($mysqld)) { - mtr_warning("Failed to start $mysqld->{'type'} mysqld $mysqld->{'idx'}"); + # failed to start + $tinfo->{'comment'}= + "Failed to start $mysqld->{'type'} mysqld $mysqld->{'idx'}"; + return 1; } } + return 0; } # From 487e2506c02bfb248910f554b314d783ff026743 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Sat, 7 Oct 2006 19:09:40 +0200 Subject: [PATCH 048/131] Two implementations of "get_err_code_from_name", one use if mysqld_ername.h is available and oe if it's not Declare "to_ptr" first in block --- client/mysqltest.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 8d8c20c3e8f..a9ac286aa88 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2472,17 +2472,13 @@ static st_error global_error_names[] = #include { 0, 0 } }; -#define HAVE_MYSQLD_ERNAME -#endif - uint get_errcode_from_name(char *error_name, char *error_end) { - DBUG_ENTER("get_errcode_from_name"); -#ifdef HAVE_MYSQLD_ERNAME - /* SQL error as string */ st_error *e= global_error_names; + + DBUG_ENTER("get_errcode_from_name"); DBUG_PRINT("enter", ("error_name: %s", error_name)); /* Loop through the array of known error names */ @@ -2501,13 +2497,17 @@ uint get_errcode_from_name(char *error_name, char *error_end) } if (!e->name) die("Unknown SQL error name '%s'", error_name); -#else - LINT_INIT(error_name); - LINT_INIT(error_end); - abort_not_in_this_version(); -#endif - DBUG_RETURN(0);; + DBUG_RETURN(0); } +#else +uint get_errcode_from_name(char *error_name __attribute__((unused)), + char *error_end __attribute__((unused))) +{ + abort_not_in_this_version(); + return 0; /* Never reached */ +} +#endif + void do_get_errcodes(struct st_command *command) @@ -2536,6 +2536,8 @@ void do_get_errcodes(struct st_command *command) if (*p == 'S') { + char *to_ptr= to->code.sqlstate; + /* SQLSTATE string - Must be SQLSTATE_LENGTH long @@ -2546,7 +2548,6 @@ void do_get_errcodes(struct st_command *command) die("The sqlstate must be exactly %d chars long", SQLSTATE_LENGTH); /* Check sqlstate string validity */ - char *to_ptr= to->code.sqlstate; while (*p && p != end) { if (my_isdigit(charset_info, *p) || my_isupper(charset_info, *p)) From 804d2effa254415fce10993b97817215b76663ce Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Sat, 7 Oct 2006 19:11:37 +0200 Subject: [PATCH 049/131] Improve sort algorithm for reorder, all test with smae name except for ending digit should be run after each other. Example of that is ndb_autodiscover[1-3] --- mysql-test/lib/mtr_cases.pl | 68 +++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 517a42d88c1..435ea73e8a3 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -143,7 +143,7 @@ sub collect_test_cases ($) { { next; } - + next if $::opt_do_test and ! defined mtr_match_prefix($elem,$::opt_do_test); collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,\%disabled, @@ -159,37 +159,71 @@ sub collect_test_cases ($) { { my %sort_criteria; - my $tinfo; # Make a mapping of test name to a string that represents how that test # should be sorted among the other tests. Put the most important criterion # first, then a sub-criterion, then sub-sub-criterion, et c. - foreach $tinfo (@$cases) + foreach my $tinfo (@$cases) { - my @this_criteria = (); + my @criteria = (); - # - # Append the criteria for sorting, in order of importance. - # + # Look for tests that muct be in run in a defined order + # that is defined by test having the same name except for + # the ending digit - push(@this_criteria, "ndb=" . ($tinfo->{'ndb_test'} ? "1" : "0")); - push(@this_criteria, "restart=" . ($tinfo->{'master_restart'} ? "1" : "0")); - # Group test with similar options together. - # Ending with "~" makes empty sort later than filled - push(@this_criteria, join("!", sort @{$tinfo->{'master_opt'}}) . "~"); + # Put variables into hash + my $test_name= $tinfo->{'name'}; + my $depend_on_test_name; + if ( $test_name =~ /^([\D]+)([0-9]{1})$/ ) + { + my $base_name= $1; + my $idx= $2; + mtr_verbose("$test_name => $base_name idx=$idx"); + if ( $idx > 1 ) + { + $idx-= 1; + $base_name= "$base_name$idx"; + mtr_verbose("New basename $base_name"); + } - # Finally, order by the name - push(@this_criteria, $tinfo->{'name'}); + foreach my $tinfo2 (@$cases) + { + if ( $tinfo2->{'name'} eq $base_name ) + { + mtr_verbose("found dependent test $tinfo2->{'name'}"); + $depend_on_test_name=$base_name; + } + } + } - $sort_criteria{$tinfo->{"name"}} = join(" ", @this_criteria); + if ( defined $depend_on_test_name ) + { + mtr_verbose("Giving $test_name same critera as $depend_on_test_name"); + $sort_criteria{$test_name} = $sort_criteria{$depend_on_test_name}; + } + else + { + # + # Append the criteria for sorting, in order of importance. + # + push(@criteria, "ndb=" . ($tinfo->{'ndb_test'} ? "1" : "0")); + push(@criteria, "restart=" . ($tinfo->{'master_restart'} ? "1" : "0")); + # Group test with equal options together. + # Ending with "~" makes empty sort later than filled + push(@criteria, join("!", sort @{$tinfo->{'master_opt'}}) . "~"); + + $sort_criteria{$test_name} = join(" ", @criteria); + } } - @$cases = sort { $sort_criteria{$a->{"name"}} cmp $sort_criteria{$b->{"name"}}; } @$cases; + @$cases = sort { + $sort_criteria{$a->{'name'}} . $a->{'name'} cmp + $sort_criteria{$b->{'name'}} . $b->{'name'}; } @$cases; if ( $::opt_script_debug ) { # For debugging the sort-order - foreach $tinfo (@$cases) + foreach my $tinfo (@$cases) { print("$sort_criteria{$tinfo->{'name'}} -> \t$tinfo->{'name'}\n"); } From dedea59a6cd0184ab81beb232198c6f60ac42673 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Sat, 7 Oct 2006 19:47:42 +0200 Subject: [PATCH 050/131] Add comment and remove strange assignment in 'do_exec' --- client/mysqltest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index a9ac286aa88..b89c763de13 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1498,6 +1498,7 @@ void do_exec(struct st_command *command) DBUG_ENTER("do_exec"); DBUG_PRINT("enter", ("cmd: '%s'", cmd)); + /* Skip leading space */ while (*cmd && my_isspace(charset_info, *cmd)) cmd++; if (!*cmd) @@ -1507,7 +1508,6 @@ void do_exec(struct st_command *command) init_dynamic_string(&ds_cmd, 0, command->query_len+256, 256); /* Eval the command, thus replacing all environment variables */ do_eval(&ds_cmd, cmd, command->end, TRUE); - cmd= ds_cmd.str; DBUG_PRINT("info", ("Executing '%s' as '%s'", command->first_argument, cmd)); From 65d3205959be1dbff996e318d6c5e5cf2143e054 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Sat, 7 Oct 2006 20:14:21 +0200 Subject: [PATCH 051/131] Init "saved_expected_errors" at program start, avoids crash where --error is first command strcmp -> strncmp --- client/mysqltest.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index b89c763de13..3d457261980 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2544,11 +2544,11 @@ void do_get_errcodes(struct st_command *command) - May contain only digits[0-9] and _uppercase_ letters */ p++; /* Step past the S */ - if (end - p != SQLSTATE_LENGTH) + if ((end - p) != SQLSTATE_LENGTH) die("The sqlstate must be exactly %d chars long", SQLSTATE_LENGTH); /* Check sqlstate string validity */ - while (*p && p != end) + while (*p && p < end) { if (my_isdigit(charset_info, *p) || my_isupper(charset_info, *p)) *to_ptr++= *p++; @@ -4652,7 +4652,8 @@ void handle_error(struct st_command *command, */ if (err_errno == CR_SERVER_LOST || err_errno == CR_SERVER_GONE_ERROR) - die("require query '%s' failed: %d: %s", command->query, err_errno, err_error); + die("require query '%s' failed: %d: %s", command->query, + err_errno, err_error); /* Abort the run of this test, pass the failed query as reason */ abort_not_supported_test("Query '%s' failed, required functionality" \ @@ -4669,8 +4670,8 @@ void handle_error(struct st_command *command, if (((command->expected_errors.err[i].type == ERR_ERRNO) && (command->expected_errors.err[i].code.errnum == err_errno)) || ((command->expected_errors.err[i].type == ERR_SQLSTATE) && - (strcmp(command->expected_errors.err[i].code.sqlstate, - err_sqlstate) == 0))) + (strncmp(command->expected_errors.err[i].code.sqlstate, + err_sqlstate, SQLSTATE_LENGTH) == 0))) { if (!disable_result_log) { @@ -4695,7 +4696,7 @@ void handle_error(struct st_command *command, } DBUG_PRINT("info",("i: %d expected_errors: %d", i, - command->expected_errors)); + command->expected_errors.count)); if (!disable_result_log) { @@ -5423,6 +5424,9 @@ int main(int argc, char **argv) save_file[0]= 0; TMPDIR[0]= 0; + /* Init expected errors */ + memset(&saved_expected_errors, 0, sizeof(saved_expected_errors)); + /* Init connections */ memset(connections, 0, sizeof(connections)); connections_end= connections + From 6f3f15c7bba9926023f36b44f253413ffab5f221 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Sat, 7 Oct 2006 20:16:57 +0200 Subject: [PATCH 052/131] Fix spelling error --- mysql-test/t/rpl_slave_status.test | 2 +- mysql-test/t/system_mysql_db_fix.test | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mysql-test/t/rpl_slave_status.test b/mysql-test/t/rpl_slave_status.test index 67d3816f443..cb12198bae2 100644 --- a/mysql-test/t/rpl_slave_status.test +++ b/mysql-test/t/rpl_slave_status.test @@ -9,7 +9,7 @@ start slave; connection master; --disable_warnings drop table if exists t1; ---enable_warning +--enable_warnings create table t1 (n int); insert into t1 values (1); save_master_pos; diff --git a/mysql-test/t/system_mysql_db_fix.test b/mysql-test/t/system_mysql_db_fix.test index dc3047a8564..5e8822569b7 100644 --- a/mysql-test/t/system_mysql_db_fix.test +++ b/mysql-test/t/system_mysql_db_fix.test @@ -27,7 +27,7 @@ CREATE TABLE db ( KEY User (User) ) type=ISAM; ---enable-warnings +--enable_warnings INSERT INTO db VALUES ('%','test', '','Y','Y','Y','Y','Y','Y'); INSERT INTO db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y'); @@ -45,7 +45,7 @@ CREATE TABLE host ( PRIMARY KEY Host (Host,Db) ) type=ISAM; ---enable-warnings +--enable_warnings --disable_warnings CREATE TABLE user ( @@ -64,7 +64,7 @@ CREATE TABLE user ( PRIMARY KEY Host (Host,User) ) type=ISAM; ---enable-warnings +--enable_warnings INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y'); INSERT INTO user VALUES ('localhost','', '','N','N','N','N','N','N','N','N','N'); From 5fa22794fd8574f76e0427a6577e8ae9c33cae2b Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Sun, 8 Oct 2006 15:50:16 +0200 Subject: [PATCH 053/131] Reorder the order of feature checks a bit Make the mysqld_variables hash global so it can be used throughout the program --- mysql-test/mysql-test-run.pl | 103 ++++++++++++++++++++++------------- 1 file changed, 64 insertions(+), 39 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 5ba42fb2c25..309c82ef8f2 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -311,8 +311,8 @@ our $used_binlog_format; our $debug_compiled_binaries; our $glob_tot_real_time= 0; -# Default values read from mysqld -our $default_mysqld_port; +our %mysqld_variables; + ###################################################################### # @@ -368,7 +368,13 @@ sub main () { initial_setup(); command_line_setup(); + + check_ndbcluster_support(\%mysqld_variables); + check_ssl_support(\%mysqld_variables); + check_debug_support(\%mysqld_variables); + executable_setup(); + environment_setup(); signal_setup(); @@ -501,7 +507,7 @@ sub initial_setup () { $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld; # Use the mysqld found above to find out what features are available - check_mysqld_features(); + collect_mysqld_features(); } @@ -721,7 +727,6 @@ sub command_line_setup () { # -------------------------------------------------------------------------- # Find out type of logging that are being used # -------------------------------------------------------------------------- - # NOTE if the default binlog format is changed, this has to be changed $used_binlog_format= "stmt"; foreach my $arg ( @opt_extra_mysqld_opt ) @@ -762,7 +767,6 @@ sub command_line_setup () { # -------------------------------------------------------------------------- # Set the "var/" directory, as it is the base for everything else # -------------------------------------------------------------------------- - $default_vardir= "$glob_mysql_test_dir/var"; if ( ! $opt_vardir ) { @@ -792,25 +796,46 @@ sub command_line_setup () { } # -------------------------------------------------------------------------- - # If not set, set these to defaults + # Set tmpdir # -------------------------------------------------------------------------- - $opt_tmpdir= "$opt_vardir/tmp" unless $opt_tmpdir; $opt_tmpdir =~ s,/+$,,; # Remove ending slash if any # -------------------------------------------------------------------------- - # Do sanity checks of command line arguments + # Set socket # -------------------------------------------------------------------------- + if (!$opt_socket) + { + $opt_socket= $mysqld_variables{'socket'}; + } # -------------------------------------------------------------------------- - # Look at the command line options and set script flags + # Check im suport # -------------------------------------------------------------------------- + if ( $mysql_version_id < 50000 ) + { + # Instance manager is not supported until 5.0 + $opt_skip_im= 1; + } + + if ( $glob_win32 ) + { + mtr_report("Disable Instance manager - not supported on Windows"); + $opt_skip_im= 1; + } + + # -------------------------------------------------------------------------- + # Record flag + # -------------------------------------------------------------------------- if ( $opt_record and ! @opt_cases ) { mtr_error("Will not run in record mode without a specific test case"); } + # -------------------------------------------------------------------------- + # Embedded server flag + # -------------------------------------------------------------------------- if ( $opt_embedded_server ) { $glob_use_embedded_server= 1; @@ -825,11 +850,18 @@ sub command_line_setup () { } } + + # -------------------------------------------------------------------------- + # ps protcol flag + # -------------------------------------------------------------------------- if ( $opt_ps_protocol ) { push(@glob_test_mode, "ps-protocol"); } + # -------------------------------------------------------------------------- + # Ndb cluster flags + # -------------------------------------------------------------------------- if ( $opt_with_ndbcluster and $opt_skip_ndbcluster) { mtr_error("Can't specify both --with-ndbcluster and --skip-ndbcluster"); @@ -865,22 +897,33 @@ sub command_line_setup () { $opt_ndbconnectstring_slave= "host=localhost:$opt_ndbcluster_port_slave"; } + # -------------------------------------------------------------------------- + # Bench flags + # -------------------------------------------------------------------------- if ( $opt_small_bench ) { $opt_bench= 1; } + # -------------------------------------------------------------------------- + # Sleep flag + # -------------------------------------------------------------------------- if ( $opt_sleep ) { $opt_sleep_time_after_restart= $opt_sleep; } + # -------------------------------------------------------------------------- + # Gcov flag + # -------------------------------------------------------------------------- if ( $opt_gcov and ! $opt_source_dist ) { mtr_error("Coverage test needs the source - please use source dist"); } + # -------------------------------------------------------------------------- # Check debug related options + # -------------------------------------------------------------------------- if ( $opt_gdb || $opt_client_gdb || $opt_ddd || $opt_client_ddd || $opt_manual_gdb || $opt_manual_ddd || $opt_manual_debug || $opt_debugger || $opt_client_debugger ) @@ -895,13 +938,9 @@ sub command_line_setup () { } } - # Check IM arguments - if ( $glob_win32 ) - { - mtr_report("Disable Instance manager - not supported on Windows"); - $opt_skip_im= 1; - } + # -------------------------------------------------------------------------- # Check valgrind arguments + # -------------------------------------------------------------------------- if ( $opt_valgrind or $opt_valgrind_path or defined $opt_valgrind_options) { mtr_report("Turning on valgrind for all executables"); @@ -1185,7 +1224,7 @@ sub datadir_setup () { ############################################################################## -sub check_mysqld_features () { +sub collect_mysqld_features () { # # Execute "mysqld --no-defaults --help --verbose", that will # print out version and a list of all features and settings @@ -1202,7 +1241,6 @@ sub check_mysqld_features () { $exe_mysqld); } - my %mysqld_variables; my $F= IO::File->new($spec_file) or mtr_error("can't open file \"$spec_file\": $!"); @@ -1263,27 +1301,6 @@ sub check_mysqld_features () { mtr_error("Could not find version of MySQL") unless $mysql_version_id; mtr_error("Could not find variabes list") unless $found_variable_list_start; - check_ndbcluster_support(\%mysqld_variables); - check_ssl_support(\%mysqld_variables); - check_debug_support(\%mysqld_variables); - - if ( $mysql_version_id < 50000 ) - { - # Instance manager is not supported until 5.0 - $opt_skip_im= 1; - - } - - if ( $mysql_version_id < 50100 ) - { - # Slave cluster is not supported until 5.1 - $opt_skip_ndbcluster_slave= 1; - - } - - # Set default values from mysqld_variables - $opt_socket= $mysqld_variables{'socket'}; - $default_mysqld_port = $mysqld_variables{'port'}; } @@ -1516,7 +1533,7 @@ sub environment_setup () { $ENV{'SLAVE_MYPORT'}= $slave->[0]->{'port'}; $ENV{'SLAVE_MYPORT1'}= $slave->[1]->{'port'}; $ENV{'SLAVE_MYPORT2'}= $slave->[2]->{'port'}; - $ENV{'MYSQL_TCP_PORT'}= $default_mysqld_port; + $ENV{'MYSQL_TCP_PORT'}= $mysqld_variables{'port'}; $ENV{MTR_BUILD_THREAD}= 0 unless $ENV{MTR_BUILD_THREAD}; # Set if not set @@ -2006,6 +2023,14 @@ sub check_ndbcluster_support ($) { } $opt_ndbcluster_supported= 1; mtr_report("Using ndbcluster when necessary, mysqld supports it"); + + if ( $mysql_version_id < 50100 ) + { + # Slave cluster is not supported until 5.1 + $opt_skip_ndbcluster_slave= 1; + + } + return; } From b896bd0a6e93b9cebb5105234154bc6ae8eb9f92 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Sun, 8 Oct 2006 16:11:55 +0200 Subject: [PATCH 054/131] When looking for client binary directories it necessary to look for the one s that are "deep down" first. --- mysql-test/mysql-test-run.pl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 309c82ef8f2..7b9a55053f0 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -484,11 +484,11 @@ sub initial_setup () { # # Look for the path where to find the client binaries - $path_client_bindir= mtr_path_exists("$glob_basedir/client", + $path_client_bindir= mtr_path_exists("$glob_basedir/client/release", + "$glob_basedir/client/debug", + "$glob_basedir/client", "$glob_basedir/client_release", "$glob_basedir/client_debug", - "$glob_basedir/client/release", - "$glob_basedir/client/debug", "$glob_basedir/bin"); # Look for the mysqld executable From 8a84753acf9490218c209a7838ea4bf5970cf0f1 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Sun, 8 Oct 2006 16:19:23 +0200 Subject: [PATCH 055/131] vsnprintf is not available on win2003-x86 host, as this is just a debug functionality - disable it for now. --- client/mysqltest.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/mysqltest.c b/client/mysqltest.c index 3d457261980..3f8bc99bdf8 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -728,9 +728,11 @@ void die(const char *fmt, ...) if (fmt) { #ifdef DBUG_ON +#ifndef __WIN__ char buff[256]; vsnprintf(buff, sizeof(buff), fmt, args); DBUG_PRINT("error", ("%s", buff)); +#endif #endif fprintf(stderr, "mysqltest: "); if (cur_file && cur_file != file_stack) @@ -855,8 +857,10 @@ void warning_msg(const char *fmt, ...) dynstr_append_mem(&ds_warning_messages, buff, len); } +#ifndef __WIN__ len= vsnprintf(buff, sizeof(buff), fmt, args); dynstr_append_mem(&ds_warning_messages, buff, len); +#endif dynstr_append(&ds_warning_messages, "\n"); va_end(args); From ca611ed679e91eacd938884f0a0c496899a4d855 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Sun, 8 Oct 2006 17:05:17 +0200 Subject: [PATCH 056/131] Move list of mysqls src dirs into lib/mtr_gcov.pl as it's only used from there --- mysql-test/lib/mtr_gcov.pl | 18 +++++++++++++++++- mysql-test/mysql-test-run.pl | 16 ---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/mysql-test/lib/mtr_gcov.pl b/mysql-test/lib/mtr_gcov.pl index 07aac1d2017..71d3d6a2a43 100644 --- a/mysql-test/lib/mtr_gcov.pl +++ b/mysql-test/lib/mtr_gcov.pl @@ -23,12 +23,28 @@ sub gcov_prepare () { -or -name \*.da | xargs rm`; } +# Used by gcov +our @mysqld_src_dirs= + ( + "strings", + "mysys", + "include", + "extra", + "regex", + "isam", + "merge", + "myisam", + "myisammrg", + "heap", + "sql", + ); + sub gcov_collect () { print "Collecting source coverage info...\n"; -f $::opt_gcov_msg and unlink($::opt_gcov_msg); -f $::opt_gcov_err and unlink($::opt_gcov_err); - foreach my $d ( @::mysqld_src_dirs ) + foreach my $d ( @mysqld_src_dirs ) { chdir("$::glob_basedir/$d"); foreach my $f ( (glob("*.h"), glob("*.cc"), glob("*.c")) ) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 7b9a55053f0..6bb069a11f5 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -87,22 +87,6 @@ require "lib/mtr_stress.pl"; $Devel::Trace::TRACE= 1; -# Used by gcov -our @mysqld_src_dirs= - ( - "strings", - "mysys", - "include", - "extra", - "regex", - "isam", - "merge", - "myisam", - "myisammrg", - "heap", - "sql", - ); - ############################################################################## # # Default settings From 55e6f7452530e485252627ac0bcd39ed511d915a Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Sun, 8 Oct 2006 17:08:24 +0200 Subject: [PATCH 057/131] Do the check of special mysqld exe for master or slave after command line args have been parsed --- mysql-test/mysql-test-run.pl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 6bb069a11f5..40b0efd4971 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -487,9 +487,6 @@ sub initial_setup () { "$glob_basedir/sql/release/mysqld", "$glob_basedir/sql/debug/mysqld"); - $exe_master_mysqld= $exe_master_mysqld || $exe_mysqld; - $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld; - # Use the mysqld found above to find out what features are available collect_mysqld_features(); @@ -922,6 +919,12 @@ sub command_line_setup () { } } + # -------------------------------------------------------------------------- + # Check if special exe was selected for master or slave + # -------------------------------------------------------------------------- + $exe_master_mysqld= $exe_master_mysqld || $exe_mysqld; + $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld; + # -------------------------------------------------------------------------- # Check valgrind arguments # -------------------------------------------------------------------------- From bf762c2d9e989aed33905c3ad9b18ef02c207415 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Sun, 8 Oct 2006 17:48:01 +0200 Subject: [PATCH 058/131] Print names of testcases that failed check_testcase, this makes it easier to run the whole testcase to find wich testcases need to be checked more carefully and the just "copy and paste" the suspicious test case names to a new mysql-test-run.pl command. --- mysql-test/include/check-testcase.test | 49 ++++++++++++++++++++++++++ mysql-test/lib/mtr_report.pl | 26 +++++++++++++- mysql-test/mysql-test-run.pl | 11 +++++- 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 mysql-test/include/check-testcase.test diff --git a/mysql-test/include/check-testcase.test b/mysql-test/include/check-testcase.test new file mode 100644 index 00000000000..d67e73470b0 --- /dev/null +++ b/mysql-test/include/check-testcase.test @@ -0,0 +1,49 @@ +# +# This test is executed twice for each test case if mysql-test-run is passed +# the flag --check-testcase. +# Before every testcase it's run with mysqltest in record mode and will +# thus produce an output file +# that can be compared to output from after the tescase. +# In that way it's possible to check that a testcase does not have +# any unwanted side affects. +# + +# +# Dump all global variables +# +show global variables; + +# +# Dump all databases +# +show databases; + +# +# Dump the "test" database, all it's tables and their data +# +--exec $MYSQL_DUMP --skip-comments test + +# +# Dump the "mysql" database and it's tables +# Select data separately to add "order by" +# +--exec $MYSQL_DUMP --skip-comments --no-data mysql +use mysql; +select * from columns_priv; +select * from db order by host, db, user; +select * from func; +select * from help_category; +select * from help_keyword; +select * from help_relation; +select * from help_relation; +select * from host; +select * from tables_priv; +select * from time_zone; +select * from time_zone_leap_second; +select * from time_zone_name; +select * from time_zone_transition; +select * from time_zone_transition_type; +select * from user; + + + diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index 4708de92e07..ec1bed9671b 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -172,7 +172,7 @@ sub mtr_report_stats ($) { my $tot_failed= 0; my $tot_tests= 0; my $tot_restarts= 0; - my $found_problems= 0; # Some warnings are errors... + my $found_problems= 0; # Some warnings in the logfiles are errors... foreach my $tinfo (@$tests) { @@ -283,6 +283,7 @@ sub mtr_report_stats ($) { print "\n"; + # Print a list of testcases that failed if ( $tot_failed != 0 ) { my $test_mode= join(" ", @::glob_test_mode) || "default"; @@ -296,7 +297,30 @@ sub mtr_report_stats ($) { } } print "\n"; + } + + # Print a list of check_testcases that failed(if any) + if ( $::opt_check_testcases ) + { + my @check_testcases= (); + + foreach my $tinfo (@$tests) + { + if ( defined $tinfo->{'check_testcase_failed'} ) + { + push(@check_testcases, $tinfo->{'name'}); + } + } + + if ( @check_testcases ) + { + print "Check of testcase failed for: "; + print join(" ", @check_testcases); + print "\n\n"; + } + } + if ( $tot_failed != 0 || $found_problems) { mtr_error("there where failing test cases"); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 40b0efd4971..c53ca49a7e9 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -3932,6 +3932,10 @@ sub run_testcase_start_servers($) { # Before a testcase, run in record mode, save result file to var # After testcase, run and compare with the recorded file, they should be equal! # +# RETURN VALUE +# 0 OK +# 1 Check failed +# sub run_check_testcase ($$) { my $mode= shift; @@ -3976,6 +3980,7 @@ sub run_check_testcase ($$) { { mtr_error("Could not execute 'check-testcase' $mode testcase"); } + return $res; } @@ -4165,7 +4170,11 @@ sub run_mysqltest ($) { { if ($mysqld->{'pid'}) { - run_check_testcase("after", $mysqld); + if (run_check_testcase("after", $mysqld)) + { + # Check failed, mark the test case with that info + $tinfo->{'check_testcase_failed'}= 1; + } } } } From 4812d81eabe2c2eeb2818e78e35365a84a44763e Mon Sep 17 00:00:00 2001 From: "cmiller@zippy.cornsilk.net" <> Date: Mon, 9 Oct 2006 18:28:06 -0400 Subject: [PATCH 059/131] Bug#17583: mysql drops connection when stdout is not writable When the client program had its stdout file descriptor closed by the calling shell, after some amount of work (enough to fill a socket buffer) the server would complain about a packet error and then disconnect the client. This is a serious security problem. If stdout is closed before the mysql is exec()d, then the first socket() call allocates file number 1 to communicate with the server. Subsequent write()s to that file number (as when printing results that come back from the database) go back to the server instead in the command channel. So, one should be able to craft data which, upon being selected back from the server to the client, and injected into the command stream become valid MySQL protocol to do something nasty when sent /back/ to the server. The solution is to close explicitly the file descriptor that we *printf() to, so that the libc layer and the OS layer both agree that the file is closed. --- BitKeeper/etc/collapsed | 1 + client/mysql.cc | 15 +++++++++++++++ mysql-test/r/mysql_client.result | 14 ++++++++++++++ mysql-test/t/mysql_client.test | 19 +++++++++++++++++++ 4 files changed, 49 insertions(+) create mode 100644 BitKeeper/etc/collapsed diff --git a/BitKeeper/etc/collapsed b/BitKeeper/etc/collapsed new file mode 100644 index 00000000000..60be7fa5dc6 --- /dev/null +++ b/BitKeeper/etc/collapsed @@ -0,0 +1 @@ +452a92d0-31-8wSzSfZi165fcGcXPA diff --git a/client/mysql.cc b/client/mysql.cc index f9ca9d4f829..12fa2b56ebf 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -372,6 +372,21 @@ int main(int argc,char *argv[]) else status.add_to_history=1; status.exit_status=1; + + { + /* + The file descriptor-layer may be out-of-sync with the file-number layer, + so we make sure that "stdout" is really open. If its file is closed then + explicitly close the FD layer. + */ + int stdout_fileno_copy; + stdout_fileno_copy= dup(fileno(stdout)); /* Okay if fileno fails. */ + if (stdout_fileno_copy == -1) + fclose(stdout); + else + close(stdout_fileno_copy); /* Clean up dup(). */ + } + load_defaults("my",load_default_groups,&argc,&argv); defaults_argv=argv; if (get_options(argc, (char **) argv)) diff --git a/mysql-test/r/mysql_client.result b/mysql-test/r/mysql_client.result index 87d09428ff6..5375deb250d 100644 --- a/mysql-test/r/mysql_client.result +++ b/mysql-test/r/mysql_client.result @@ -2,3 +2,17 @@ 1 ERROR 1064 (42000) at line 3: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1 ERROR at line 1: USE must be followed by a database name +create table t17583 (a int); +insert into t17583 (a) values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +select count(*) from t17583; +count(*) +1280 +drop table t17583; +End of 4.1 tests. diff --git a/mysql-test/t/mysql_client.test b/mysql-test/t/mysql_client.test index b382357dacf..2a7f4a935bb 100644 --- a/mysql-test/t/mysql_client.test +++ b/mysql-test/t/mysql_client.test @@ -33,3 +33,22 @@ # --exec echo 'help' | $MYSQL > $MYSQLTEST_VARDIR/tmp/bug20328.tmp --exec echo 'help ' | $MYSQL > $MYSQLTEST_VARDIR/tmp/bug20328.tmp + +# +# Bug#17583: mysql drops connection when stdout is not writable +# +create table t17583 (a int); +insert into t17583 (a) values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +insert into t17583 select a from t17583; +# Close to the minimal data needed to exercise bug. +select count(*) from t17583; +--exec echo "select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; select count(*) from t17583; " |$MYSQL test >&- +drop table t17583; + +--echo End of 4.1 tests. From 456fe01d7efacdad6a7baf8764cacb943c07b830 Mon Sep 17 00:00:00 2001 From: "kaa@polly.local" <> Date: Wed, 11 Oct 2006 12:44:03 +0400 Subject: [PATCH 060/131] Fix for bug #22728 "Handler_rollback value is growing". The bug is present only in 4.1, will be null-merged to 5.0 For InnoDB, check value of thd->transaction.all.innodb_active_trans instead of thd->transaction.stmt.innobase_tid to see if we really need to rollback. --- mysql-test/r/innodb_mysql.result | 10 ++++++++++ mysql-test/t/innodb_mysql.test | 18 ++++++++++++++++++ sql/handler.cc | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/innodb_mysql.result b/mysql-test/r/innodb_mysql.result index 2a4e3555e3b..d1f34e681e9 100644 --- a/mysql-test/r/innodb_mysql.result +++ b/mysql-test/r/innodb_mysql.result @@ -54,3 +54,13 @@ c.c_id = 218 and expiredate is null; slai_id 12 drop table t1, t2; +flush status; +create table t1 (c1 int) engine=innodb; +handler t1 open; +handler t1 read first; +c1 +show /*!50002 GLOBAL */ status like 'Handler_rollback'; +Variable_name Value +Handler_rollback 0 +drop table t1; +End of 4.1 tests diff --git a/mysql-test/t/innodb_mysql.test b/mysql-test/t/innodb_mysql.test index f31e4d64789..ce8030d389d 100644 --- a/mysql-test/t/innodb_mysql.test +++ b/mysql-test/t/innodb_mysql.test @@ -57,3 +57,21 @@ where c.c_id = 218 and expiredate is null; drop table t1, t2; + +# +# Bug #22728 - Handler_rollback value is growing +# +flush status; +create table t1 (c1 int) engine=innodb; +connect (con1,localhost,root,,); +connect (con2,localhost,root,,); +connection con2; +handler t1 open; +handler t1 read first; +disconnect con2; +connection con1; +show /*!50002 GLOBAL */ status like 'Handler_rollback'; +connection default; +drop table t1; +disconnect con1; +--echo End of 4.1 tests diff --git a/sql/handler.cc b/sql/handler.cc index e166f9885fc..7dc72938f7a 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -648,7 +648,7 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans) } #endif #ifdef HAVE_INNOBASE_DB - if (trans->innobase_tid) + if (thd->transaction.all.innodb_active_trans) { if ((error=innobase_rollback(thd, trans->innobase_tid))) { From a846909e6a4bd726c1ec5cc6e9df467431285157 Mon Sep 17 00:00:00 2001 From: "andrey@example.com" <> Date: Wed, 11 Oct 2006 11:07:25 +0200 Subject: [PATCH 061/131] Fix a typo regarding checking whether HA_VAR_LENGTH_KEY is set. This has always worked because when flag is !=0 then HA_VAR_LENGTH_KEY is always set. Therefore, a test case cannot reveal a faulty behavior. Fix for bug#23074: typo in myisam/sort.c --- myisam/sort.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/myisam/sort.c b/myisam/sort.c index 1a3dc147cd9..364d860272c 100644 --- a/myisam/sort.c +++ b/myisam/sort.c @@ -324,7 +324,7 @@ pthread_handler_decl(thr_find_all_keys,arg) if (info->sort_info->got_error) goto err; - if (info->keyinfo->flag && HA_VAR_LENGTH_KEY) + if (info->keyinfo->flag & HA_VAR_LENGTH_KEY) { info->write_keys=write_keys_varlen; info->read_to_buffer=read_to_buffer_varlen; @@ -513,7 +513,7 @@ int thr_write_keys(MI_SORT_PARAM *sort_param) { if (got_error) continue; - if (sinfo->keyinfo->flag && HA_VAR_LENGTH_KEY) + if (sinfo->keyinfo->flag & HA_VAR_LENGTH_KEY) { sinfo->write_keys=write_keys_varlen; sinfo->read_to_buffer=read_to_buffer_varlen; From f807b6e89382f6356547c443e6e285f885fd6333 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Wed, 11 Oct 2006 11:21:44 +0200 Subject: [PATCH 062/131] Fix some bad code in mysqltest.c which cause segfault --- client/mysqltest.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 3f8bc99bdf8..0a9549acc47 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -727,13 +727,6 @@ void die(const char *fmt, ...) va_start(args, fmt); if (fmt) { -#ifdef DBUG_ON -#ifndef __WIN__ - char buff[256]; - vsnprintf(buff, sizeof(buff), fmt, args); - DBUG_PRINT("error", ("%s", buff)); -#endif -#endif fprintf(stderr, "mysqltest: "); if (cur_file && cur_file != file_stack) fprintf(stderr, "In included file \"%s\": ", From b62f0c7b93ef907796fbbe4b6c5f6c055b3591c9 Mon Sep 17 00:00:00 2001 From: "Kristofer.Pettersson@naruto." <> Date: Wed, 11 Oct 2006 13:42:48 +0200 Subject: [PATCH 063/131] Cset exclude: Kristofer.Pettersson@naruto.|ChangeSet|20060922092201|15946 --- sql/item_timefunc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index 0b65fdafe31..02c8ab19354 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -1876,7 +1876,7 @@ void Item_date_add_interval::fix_length_and_dec() cached_field_type= MYSQL_TYPE_DATETIME; else if (arg0_field_type == MYSQL_TYPE_DATE) { - if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH || int_type == INTERVAL_WEEK ) + if (int_type <= INTERVAL_DAY || int_type == INTERVAL_YEAR_MONTH) cached_field_type= arg0_field_type; else cached_field_type= MYSQL_TYPE_DATETIME; From 3e3776421674ed85ec00580f7f1b9be85087ce1f Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Wed, 11 Oct 2006 14:50:19 +0200 Subject: [PATCH 064/131] Improve restart logic all code to detect restart is now in the functions 'run_testcase_need_master/slave_restart' Remove the faulty qw Only look for mysql_fix_privilege_tables if not windows --- mysql-test/lib/mtr_cases.pl | 109 +++++++------- mysql-test/mysql-test-run.pl | 148 +++++++++----------- mysql-test/t/bdb-alter-table-2-master.opt | 2 +- mysql-test/t/not_embedded_server-master.opt | 2 +- 4 files changed, 119 insertions(+), 142 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 435ea73e8a3..e6980a0abb9 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -152,9 +152,7 @@ sub collect_test_cases ($) { closedir TESTDIR; } - # To speed things up, we sort first in if the test require a restart - # or not, second in alphanumeric order. - + # Reorder the test cases in an order that wil make them faster to run if ( $::opt_reorder ) { @@ -207,7 +205,6 @@ sub collect_test_cases ($) { # Append the criteria for sorting, in order of importance. # push(@criteria, "ndb=" . ($tinfo->{'ndb_test'} ? "1" : "0")); - push(@criteria, "restart=" . ($tinfo->{'master_restart'} ? "1" : "0")); # Group test with equal options together. # Ending with "~" makes empty sort later than filled push(@criteria, join("!", sort @{$tinfo->{'master_opt'}}) . "~"); @@ -313,13 +310,6 @@ sub collect_one_test_case($$$$$$$) { { # This is an ndb test or all tests should be run with ndb cluster started $tinfo->{'ndb_test'}= 1; - if ( $::opt_skip_ndbcluster ) - { - # All ndb test's should be skipped - $tinfo->{'skip'}= 1; - $tinfo->{'comment'}= "No ndbcluster test(--skip-ndbcluster)"; - return; - } if ( ! $::opt_ndbcluster_supported ) { # Ndb is not supported, skip them @@ -327,6 +317,13 @@ sub collect_one_test_case($$$$$$$) { $tinfo->{'comment'}= "No ndbcluster support"; return; } + elsif ( $::opt_skip_ndbcluster ) + { + # All ndb test's should be skipped + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No ndbcluster tests(--skip-ndbcluster)"; + return; + } } else { @@ -357,52 +354,58 @@ sub collect_one_test_case($$$$$$$) { if ( -f $master_opt_file ) { - $tinfo->{'master_restart'}= 1; # We think so for now - MASTER_OPT: + my $master_opt= mtr_get_opts_from_file($master_opt_file); + + foreach my $opt ( @$master_opt ) { - my $master_opt= mtr_get_opts_from_file($master_opt_file); + my $value; - foreach my $opt ( @$master_opt ) + # The opt file is used both to send special options to the mysqld + # as well as pass special test case specific options to this + # script + + $value= mtr_match_prefix($opt, "--timezone="); + if ( defined $value ) { - my $value; - - # This is a dirty hack from old mysql-test-run, we use the opt - # file to flag other things as well, it is not a opt list at - # all - - $value= mtr_match_prefix($opt, "--timezone="); - if ( defined $value ) - { - $tinfo->{'timezone'}= $value; - last MASTER_OPT; - } - - $value= mtr_match_prefix($opt, "--result-file="); - if ( defined $value ) - { - $tinfo->{'result_file'}= "r/$value.result"; - $tinfo->{'master_restart'}= 0; - last MASTER_OPT; - } - - # If we set default time zone, remove the one we have - $value= mtr_match_prefix($opt, "--default-time-zone="); - if ( defined $value ) - { - $tinfo->{'master_opt'}= []; - } - + $tinfo->{'timezone'}= $value; + next; } - # Ok, this was a real option list, add it - push(@{$tinfo->{'master_opt'}}, @$master_opt); + $value= mtr_match_prefix($opt, "--result-file="); + if ( defined $value ) + { + # Specifies the file mysqltest should compare + # output against + $tinfo->{'result_file'}= "r/$value.result"; + next; + } + + # If we set default time zone, remove the one we have + $value= mtr_match_prefix($opt, "--default-time-zone="); + if ( defined $value ) + { + $tinfo->{'timezone'}= ""; + # Fallthrough, add this option + } + + # The --restart option forces a restart even if no special + # option is set. If the options are the same as next testcase + # there is no need to restart after the testcase + # has completed + if ( $opt eq "--force-restart" ) + { + $tinfo->{'force_restart'}= 1; + next; + } + + # Ok, this was a real option, add it + push(@{$tinfo->{'master_opt'}}, $opt); } } if ( -f $slave_opt_file ) { - $tinfo->{'slave_restart'}= 1; my $slave_opt= mtr_get_opts_from_file($slave_opt_file); foreach my $opt ( @$slave_opt ) @@ -417,7 +420,6 @@ sub collect_one_test_case($$$$$$$) { if ( -f $slave_mi_file ) { $tinfo->{'slave_mi'}= mtr_get_opts_from_file($slave_mi_file); - $tinfo->{'slave_restart'}= 1; } if ( -f $master_sh ) @@ -431,7 +433,6 @@ sub collect_one_test_case($$$$$$$) { else { $tinfo->{'master_sh'}= $master_sh; - $tinfo->{'master_restart'}= 1; } } @@ -446,7 +447,6 @@ sub collect_one_test_case($$$$$$$) { else { $tinfo->{'slave_sh'}= $slave_sh; - $tinfo->{'slave_restart'}= 1; } } @@ -551,17 +551,6 @@ sub collect_one_test_case($$$$$$$) { return; } } - - # We can't restart a running server that may be in use - - if ( $::glob_use_running_server and - ( $tinfo->{'master_restart'} or $tinfo->{'slave_restart'} ) ) - { - $tinfo->{'skip'}= 1; - $tinfo->{'comment'}= "Can't restart a running server"; - return; - } - } diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index c53ca49a7e9..dd6e8dacbdc 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -65,7 +65,7 @@ use IO::Socket; use IO::Socket::INET; use Data::Dumper; use strict; -#use diagnostics; +use diagnostics; our $glob_win32_perl= ($^O eq "MSWin32"); # ActiveState Win32 Perl our $glob_cygwin_perl= ($^O eq "cygwin"); # Cygwin Perl @@ -1357,10 +1357,13 @@ sub executable_setup () { $exe_mysqlslap= mtr_exe_exists("$path_client_bindir/mysqlslap"); } - # Look for mysql_fix_system_table script - $exe_mysql_fix_system_tables= - mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables", - "$path_client_bindir/mysql_fix_privilege_tables"); + if ( ! $glob_win32 ) + { + # Look for mysql_fix_system_table script + $exe_mysql_fix_system_tables= + mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables", + "$path_client_bindir/mysql_fix_privilege_tables"); + } if ( ! $opt_skip_ndbcluster) { @@ -1492,11 +1495,13 @@ sub environment_setup () { } $ENV{'LD_LIBRARY_PATH'}= join(":", @ld_library_paths, - split(':', qw($ENV{'LD_LIBRARY_PATH'}))); + $ENV{'LD_LIBRARY_PATHS'} ? + split(':', $ENV{'LD_LIBRARY_PATH'}) : ()); mtr_debug("LD_LIBRARY_PATH: $ENV{'LD_LIBRARY_PATH'}"); $ENV{'DYLD_LIBRARY_PATH'}= join(":", @ld_library_paths, - split(':', qw($ENV{'DYLD_LIBRARY_PATH'}))); + $ENV{'DYLD_LIBRARY_PATH'} ? + split(':', $ENV{'DYLD_LIBRARY_PATH'}) : ()); mtr_debug("DYLD_LIBRARY_PATH: $ENV{'DYLD_LIBRARY_PATH'}"); @@ -1527,22 +1532,25 @@ sub environment_setup () { # ---------------------------------------------------- # Setup env for NDB # ---------------------------------------------------- - $ENV{'NDB_MGM'}= $exe_ndb_mgm; + if ( ! $opt_skip_ndbcluster ) + { + $ENV{'NDB_MGM'}= $exe_ndb_mgm; - $ENV{'NDBCLUSTER_PORT'}= $opt_ndbcluster_port; - $ENV{'NDBCLUSTER_PORT_SLAVE'}= $opt_ndbcluster_port_slave; + $ENV{'NDBCLUSTER_PORT'}= $opt_ndbcluster_port; + $ENV{'NDBCLUSTER_PORT_SLAVE'}= $opt_ndbcluster_port_slave; - $ENV{'NDB_EXTRA_TEST'}= $opt_ndb_extra_test; + $ENV{'NDB_EXTRA_TEST'}= $opt_ndb_extra_test; - $ENV{'NDB_BACKUP_DIR'}= $clusters->[0]->{'data_dir'}; - $ENV{'NDB_DATA_DIR'}= $clusters->[0]->{'data_dir'}; - $ENV{'NDB_TOOLS_DIR'}= $path_ndb_tools_dir; - $ENV{'NDB_TOOLS_OUTPUT'}= $path_ndb_testrun_log; - $ENV{'NDB_CONNECTSTRING'}= $opt_ndbconnectstring; + $ENV{'NDB_BACKUP_DIR'}= $clusters->[0]->{'data_dir'}; + $ENV{'NDB_DATA_DIR'}= $clusters->[0]->{'data_dir'}; + $ENV{'NDB_TOOLS_DIR'}= $path_ndb_tools_dir; + $ENV{'NDB_TOOLS_OUTPUT'}= $path_ndb_testrun_log; + $ENV{'NDB_CONNECTSTRING'}= $opt_ndbconnectstring; - $ENV{'NDB_EXAMPLES_DIR'}= $path_ndb_examples_dir; - $ENV{'MY_NDB_EXAMPLES_BINARY'}= $exe_ndb_example; - $ENV{'NDB_EXAMPLES_OUTPUT'}= $path_ndb_testrun_log; + $ENV{'NDB_EXAMPLES_DIR'}= $path_ndb_examples_dir; + $ENV{'MY_NDB_EXAMPLES_BINARY'}= $exe_ndb_example; + $ENV{'NDB_EXAMPLES_OUTPUT'}= $path_ndb_testrun_log; + } # ---------------------------------------------------- # Setup env for IM @@ -2817,6 +2825,17 @@ sub run_testcase ($) { if ($master_restart or $slave_restart) { + # Can't restart a running server that may be in use + if ( $glob_use_running_server ) + { + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Can't restart a running server"; + + mtr_report_test_name($tinfo); + mtr_report_test_skipped($tinfo); + return; + } + run_testcase_stop_servers($tinfo, $master_restart, $slave_restart); } my $died= mtr_record_dead_children(); @@ -2884,13 +2903,10 @@ sub run_testcase ($) { # ---------------------------------------------------------------------- # Stop Instance Manager if we are processing an IM-test case. # ---------------------------------------------------------------------- - - if ( ! $glob_use_running_server and $tinfo->{'component_id'} eq 'im' ) + if ( $tinfo->{'component_id'} eq 'im' and + mtr_im_stop($instance_manager, $tinfo->{'name'}) != 0 ) { - unless ( mtr_im_stop($instance_manager, $tinfo->{'name'}) ) - { - mtr_error("Failed to stop Instance Manager.") - } + mtr_error("Failed to stop Instance Manager.") } } @@ -3516,48 +3532,38 @@ sub run_testcase_need_master_restart($) if ( $tinfo->{'master_sh'} ) { $do_restart= 1; # Always restart if script to run - mtr_verbose("Restart because: Always restart if script to run"); + mtr_verbose("Restart master: Always restart if script to run"); + } + if ( $tinfo->{'force_restart'} ) + { + $do_restart= 1; # Always restart if --force-restart in -opt file + mtr_verbose("Restart master: Restart forced with --force-restart"); } elsif ( ! $opt_skip_ndbcluster and $tinfo->{'ndb_test'} == 0 and $clusters->[0]->{'pid'} != 0 ) { $do_restart= 1; # Restart without cluster - mtr_verbose("Restart because: Test does not need cluster"); + mtr_verbose("Restart master: Test does not need cluster"); } elsif ( ! $opt_skip_ndbcluster and $tinfo->{'ndb_test'} == 1 and $clusters->[0]->{'pid'} == 0 ) { $do_restart= 1; # Restart with cluster - mtr_verbose("Restart because: Test need cluster"); + mtr_verbose("Restart master: Test need cluster"); } elsif( $tinfo->{'component_id'} eq 'im' ) { $do_restart= 1; - mtr_verbose("Restart because: Always restart for im tests"); + mtr_verbose("Restart master: Always restart for im tests"); } - elsif ( $master->[0]->{'running_master_is_special'} and - $master->[0]->{'running_master_is_special'}->{'timezone'} eq - $tinfo->{'timezone'} and - mtr_same_opts($master->[0]->{'running_master_is_special'}->{'master_opt'}, - $tinfo->{'master_opt'}) ) - { - # If running master was started with special settings, but - # the current test requires the same ones, we *don't* restart. - $do_restart= 0; - mtr_verbose("Skip restart: options are equal " . - join(" ", @{$tinfo->{'master_opt'}})); - } - elsif ( $tinfo->{'master_restart'} ) + elsif ( $master->[0]->{'running_master_options'} and + $master->[0]->{'running_master_options'}->{'timezone'} ne + $tinfo->{'timezone'}) { $do_restart= 1; - mtr_verbose("Restart because: master_restart"); - } - elsif ( $master->[0]->{'running_master_is_special'} ) - { - $do_restart= 1; - mtr_verbose("Restart because: running_master_is_special"); + mtr_verbose("Restart master: Different timezone"); } # Check that running master was started with same options # as the current test requires @@ -3565,14 +3571,14 @@ sub run_testcase_need_master_restart($) $tinfo->{'master_opt'}) ) { $do_restart= 1; - mtr_verbose("Restart because: running with different options '" . + mtr_verbose("Restart master: running with different options '" . join(" ", @{$tinfo->{'master_opt'}}) . "' != '" . join(" ", @{$master->[0]->{'start_opts'}}) . "'" ); } elsif( ! $master->[0]->{'pid'} ) { $do_restart= 1; - mtr_verbose("Restart because: master is not started"); + mtr_verbose("Restart master: master is not started"); } return $do_restart; @@ -3587,7 +3593,7 @@ sub run_testcase_need_slave_restart($) if ( $max_slave_num == 0) { - mtr_verbose("No testcase use slaves, no slave restarts"); + mtr_verbose("Skip slave restart: No testcase use slaves"); } else { @@ -3605,12 +3611,12 @@ sub run_testcase_need_slave_restart($) if ($any_slave_started) { - mtr_verbose("Any slave is started, need to restart"); + mtr_verbose("Restart slave: Slave is started, always restart"); $do_slave_restart= 1; } elsif ( $tinfo->{'slave_num'} ) { - mtr_verbose("Test need slave, check for restart"); + mtr_verbose("Restart slave: Test need slave"); $do_slave_restart= 1; } } @@ -3632,22 +3638,16 @@ sub run_testcase_need_slave_restart($) sub run_testcase_stop_servers($$$) { my ($tinfo, $do_restart, $do_slave_restart)= @_; - - if ( $glob_use_running_server || $glob_use_embedded_server ) - { - return; - } - my $pid; my %admin_pids; # hash of admin processes that requests shutdown my @kill_pids; # list of processes to shutdown/kill - # Remember if we restarted for this test case + # Remember if we restarted for this test case (count restarts) $tinfo->{'restarted'}= $do_restart; if ( $do_restart ) { - delete $master->[0]->{'running_master_is_special'}; # Forget history + delete $master->[0]->{'running_master_options'}; # Forget history # Start shutdown of all started masters foreach my $mysqld (@{$master}) @@ -3697,7 +3697,7 @@ sub run_testcase_stop_servers($$$) { if ( $do_restart || $do_slave_restart ) { - delete $slave->[0]->{'running_slave_is_special'}; # Forget history + delete $slave->[0]->{'running_slave_options'}; # Forget history # Start shutdown of all started slaves foreach my $mysqld (@{$slave}) @@ -3781,18 +3781,13 @@ sub run_testcase_stop_servers($$$) { sub run_testcase_start_servers($) { my $tinfo= shift; - my $tname= $tinfo->{'name'}; - if ( $glob_use_running_server or $glob_use_embedded_server ) - { - return 0; - } - # ------------------------------------------------------- # Init variables that can change between server starts # ------------------------------------------------------- $ENV{'TZ'}= $tinfo->{'timezone'}; + mtr_verbose("Starting server with timezone: $tinfo->{'timezone'}"); if ( $tinfo->{'component_id'} eq 'mysqld' ) { @@ -3837,11 +3832,8 @@ sub run_testcase_start_servers($) { mysqld_start($master->[1],$tinfo->{'master_opt'},[]); } - if ( $tinfo->{'master_restart'} ) - { - # Save this test case information, so next can examine it - $master->[0]->{'running_master_is_special'}= $tinfo; - } + # Save this test case information, so next can examine it + $master->[0]->{'running_master_options'}= $tinfo; } elsif ( ! $opt_skip_im and $tinfo->{'component_id'} eq 'im' ) { @@ -3888,12 +3880,8 @@ sub run_testcase_start_servers($) { } } - if ( $tinfo->{'slave_restart'} ) - { - # Save this test case information, so next can examine it - $slave->[0]->{'running_slave_is_special'}= $tinfo; - } - + # Save this test case information, so next can examine it + $slave->[0]->{'running_slave_options'}= $tinfo; } # Wait for clusters to start @@ -3969,7 +3957,7 @@ sub run_check_testcase ($$) { my $res = mtr_run_test($exe_mysqltest,$args, "include/check-testcase.test", "", "", ""); - if ( $res == 1 and $mode = "after") + if ( $res == 1 and $mode eq "after") { mtr_run("diff",["-u", "$opt_vardir/tmp/$name.result", diff --git a/mysql-test/t/bdb-alter-table-2-master.opt b/mysql-test/t/bdb-alter-table-2-master.opt index 15ad73c500f..c2dca33445b 100644 --- a/mysql-test/t/bdb-alter-table-2-master.opt +++ b/mysql-test/t/bdb-alter-table-2-master.opt @@ -1,2 +1,2 @@ ---skip-external-locking +--force-restart diff --git a/mysql-test/t/not_embedded_server-master.opt b/mysql-test/t/not_embedded_server-master.opt index 35fcc5f30c6..cef79bc8585 100644 --- a/mysql-test/t/not_embedded_server-master.opt +++ b/mysql-test/t/not_embedded_server-master.opt @@ -1 +1 @@ ---loose-to-force-a-restart +--force-restart From d02909910baee70a7a20e3dce05dd1bdcaaf0f8a Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Wed, 11 Oct 2006 15:45:35 +0200 Subject: [PATCH 065/131] mtr_im_stop returns 1 if all is well --- mysql-test/mysql-test-run.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index dd6e8dacbdc..1759b357eb1 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2904,7 +2904,7 @@ sub run_testcase ($) { # Stop Instance Manager if we are processing an IM-test case. # ---------------------------------------------------------------------- if ( $tinfo->{'component_id'} eq 'im' and - mtr_im_stop($instance_manager, $tinfo->{'name'}) != 0 ) + !mtr_im_stop($instance_manager, $tinfo->{'name'}) ) { mtr_error("Failed to stop Instance Manager.") } From 5b8312986c8a0e055f42f4ab2e43164655503074 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Wed, 11 Oct 2006 21:53:43 +0200 Subject: [PATCH 066/131] Fixes for embedded server test --- client/mysqltest.c | 2 +- mysql-test/mysql-test-run.pl | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 0a9549acc47..b671147e1d7 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1433,7 +1433,7 @@ void do_source(struct st_command *command) #ifdef __WIN__ -/* Variables used for temuprary sh files used for emulating Unix on Windows */ +/* Variables used for temporary sh files used for emulating Unix on Windows */ char tmp_sh_name[64], tmp_sh_cmd[70]; void init_tmp_sh_file() diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 1759b357eb1..0e340e47ae8 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1418,7 +1418,7 @@ sub executable_setup () { { $exe_mysql_client_test= mtr_exe_exists("$glob_basedir/libmysqld/examples/mysql_client_test_embedded", - "$glob_basedir/tests/mysqltest_embedded"); + "$path_client_bindir/mysql_client_test_embedded"); } else { @@ -3107,7 +3107,7 @@ sub mysqld_arguments ($$$$$) { $prefix= "--server-arg="; } else { # We can't pass embedded server --no-defaults - mtr_add_arg($args, "%s--no-defaults", $prefix); + mtr_add_arg($args, "--no-defaults"); } mtr_add_arg($args, "%s--console", $prefix); @@ -3529,7 +3529,12 @@ sub run_testcase_need_master_restart($) # We try to find out if we are to restart the master(s) my $do_restart= 0; # Assumes we don't have to - if ( $tinfo->{'master_sh'} ) + if ( $glob_use_embedded_server ) + { + mtr_verbose("Never start or restart for embedded server"); + return $do_restart; + } + elsif ( $tinfo->{'master_sh'} ) { $do_restart= 1; # Always restart if script to run mtr_verbose("Restart master: Always restart if script to run"); @@ -3591,7 +3596,12 @@ sub run_testcase_need_slave_restart($) # We try to find out if we are to restart the slaves my $do_slave_restart= 0; # Assumes we don't have to - if ( $max_slave_num == 0) + if ( $glob_use_embedded_server ) + { + mtr_verbose("Never start or restart for embedded server"); + return $do_slave_restart; + } + elsif ( $max_slave_num == 0) { mtr_verbose("Skip slave restart: No testcase use slaves"); } From d534a6b905ebe7a744ed2b0b1f103f08f0dbd123 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Thu, 12 Oct 2006 10:27:44 +0200 Subject: [PATCH 067/131] Add DBUG_ASSERT to check that mysql is not null when mysql_reconnect is called Add DBUG_PRINT to show the value of mysql->reconnect --- sql-common/client.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sql-common/client.c b/sql-common/client.c index ff5f1ef150a..3acd763c054 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -2215,6 +2215,8 @@ my_bool mysql_reconnect(MYSQL *mysql) { MYSQL tmp_mysql; DBUG_ENTER("mysql_reconnect"); + DBUG_ASSERT(mysql); + DBUG_PRINT("enter", ("mysql->reconnect: %d", mysql->reconnect)); if (!mysql->reconnect || (mysql->server_status & SERVER_STATUS_IN_TRANS) || !mysql->host_info) From 71cb0e8dc547afcf5d728cc6b86caaea8f362351 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Thu, 12 Oct 2006 10:49:59 +0200 Subject: [PATCH 068/131] Only print cur_file->filename if cur_file->file is set MOve DBUG_ASSERT(result_file_name) to after DBUG_ENTER Change type of "reconnect" variable from int to my_bool, reconnect didn't work on Solaris without that --- client/mysqltest.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index b671147e1d7..db15c6c43dd 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -668,9 +668,11 @@ void close_files() DBUG_ENTER("close_files"); for (; cur_file >= file_stack; cur_file--) { - DBUG_PRINT("info", ("file_name: %s", cur_file->file_name)); if (cur_file->file && cur_file->file != stdin) + { + DBUG_PRINT("info", ("closing file: %s", cur_file->file_name)); my_fclose(cur_file->file, MYF(0)); + } my_free((gptr)cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR)); cur_file->file_name= 0; } @@ -950,8 +952,8 @@ err: void check_result(DYNAMIC_STRING* ds) { - DBUG_ASSERT(result_file_name); DBUG_ENTER("check_result"); + DBUG_ASSERT(result_file_name); switch (dyn_string_cmp(ds, result_file_name)) { @@ -2707,12 +2709,15 @@ char *get_string(char **to_ptr, char **from_ptr, void set_reconnect(MYSQL* mysql, int val) { + DBUG_ENTER("set_reconnect"); + DBUG_PRINT("info", ("val: %d", val)); #if MYSQL_VERSION_ID < 50000 mysql->reconnect= val; #else - int reconnect= val; + my_bool reconnect= val; mysql_options(mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect); #endif + DBUG_VOID_RETURN; } From 3c66250e84701be48145412f98ed6bce89e00c2d Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Thu, 12 Oct 2006 11:29:13 +0200 Subject: [PATCH 069/131] Fix unhandled exception in mysql-test-run.pl, creating a dir that already exist --- mysql-test/lib/mtr_process.pl | 13 ------------- mysql-test/mysql-test-run.pl | 17 ++++++++++++----- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index 5e21248790e..2831c179ea5 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -339,19 +339,6 @@ sub mtr_kill_leftovers () { mtr_report("Killing Possible Leftover Processes"); mtr_debug("mtr_kill_leftovers(): started."); - mkpath("$::opt_vardir/log"); # Needed for mysqladmin log - - # Stop or kill Instance Manager and all its children. If we failed to do - # that, we can only abort -- there is nothing left to do. - -# mtr_error("Failed to stop Instance Manager.") -# unless mtr_im_stop($::instance_manager); - - # Start shutdown of masters and slaves. Don't touch IM-managed mysqld - # instances -- they should be stopped by mtr_im_stop(). - - mtr_debug("Shutting down mysqld-instances..."); - my @kill_pids; my %admin_pids; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 0e340e47ae8..629ba00f8f1 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -310,7 +310,7 @@ sub command_line_setup (); sub datadir_setup (); sub executable_setup (); sub environment_setup (); -sub kill_running_server (); +sub kill_running_servers (); sub cleanup_stale_files (); sub check_ssl_support ($); sub check_running_as_root(); @@ -1802,7 +1802,7 @@ sub handle_int_signal () { # ############################################################################## -sub kill_running_server () { +sub kill_running_servers () { if ( $opt_fast or $glob_use_embedded_server ) { @@ -1820,6 +1820,13 @@ sub kill_running_server () { # started from this run of the script, this is terminating # leftovers from previous runs. + if ( ! -d $opt_vardir ) + { + # The "var" dir does not exist already + # the processes that mtr_kill_leftovers start will write + # their log files to var/log so it should be created + mkpath("$opt_vardir/log"); + } mtr_kill_leftovers(); } } @@ -2416,9 +2423,9 @@ sub initialize_servers () { if ( ! $glob_use_running_server ) { - kill_running_server(); + kill_running_servers(); - unless ( $opt_start_dirty ) + if ( ! $opt_start_dirty ) { cleanup_stale_files(); mysql_install_db(); @@ -3782,7 +3789,7 @@ sub run_testcase_stop_servers($$$) { # # run_testcase_start_servers # -# Start the servers neede by this test case +# Start the servers needed by this test case # # RETURN # 0 OK From d093b1029a544a00b3ca86e39cbce65fcf08e19f Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Thu, 12 Oct 2006 12:19:23 +0200 Subject: [PATCH 070/131] Look for mysql_client_test in $path_client_bindir --- mysql-test/mysql-test-run.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 629ba00f8f1..d4555e8ac00 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1423,7 +1423,7 @@ sub executable_setup () { else { $exe_mysql_client_test= - mtr_exe_exists("$glob_basedir/tests/mysql_client_test"); + mtr_exe_exists("$path_client_bindir/mysql_client_test"); } } From 2c4456d30f428b1708c066be2efe4549466ae6c9 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Thu, 12 Oct 2006 13:49:12 +0200 Subject: [PATCH 071/131] Add win paths for mysql_client_test --- mysql-test/mysql-test-run.pl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index d4555e8ac00..29acd25138f 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1417,13 +1417,14 @@ sub executable_setup () { if ( $glob_use_embedded_server ) { $exe_mysql_client_test= - mtr_exe_exists("$glob_basedir/libmysqld/examples/mysql_client_test_embedded", - "$path_client_bindir/mysql_client_test_embedded"); + mtr_exe_exists("$glob_basedir/libmysqld/examples/mysql_client_test_embedded"); } else { $exe_mysql_client_test= - mtr_exe_exists("$path_client_bindir/mysql_client_test"); + mtr_exe_exists("$glob_basedir/tests/mysql_client_test", + "$glob_basedir/tests/release/mysql_client_test" + "$glob_basedir/tests/debug/mysql_client_test"); } } From 6c31690bbd63266abc814935231262a65a557eed Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Thu, 12 Oct 2006 13:50:50 +0200 Subject: [PATCH 072/131] Move the reconnect variable to beginning of function Fix warning about value from "*ptr++" not being used. Changed it to ptr++ --- client/mysqltest.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index db15c6c43dd..e2317560404 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -2709,12 +2709,12 @@ char *get_string(char **to_ptr, char **from_ptr, void set_reconnect(MYSQL* mysql, int val) { + my_bool reconnect= val; DBUG_ENTER("set_reconnect"); DBUG_PRINT("info", ("val: %d", val)); #if MYSQL_VERSION_ID < 50000 - mysql->reconnect= val; + mysql->reconnect= reconnect; #else - my_bool reconnect= val; mysql_options(mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect); #endif DBUG_VOID_RETURN; @@ -3609,7 +3609,7 @@ void scan_command_for_warnings(struct st_command *command) *end= save; } - *ptr++; + ptr++; } DBUG_VOID_RETURN; } From 2db82814c4654b7e1c83378a01f66c6f97cee262 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Thu, 12 Oct 2006 16:17:09 +0200 Subject: [PATCH 073/131] Add missing semicolon --- mysql-test/mysql-test-run.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 29acd25138f..0c46bbeac79 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1423,7 +1423,7 @@ sub executable_setup () { { $exe_mysql_client_test= mtr_exe_exists("$glob_basedir/tests/mysql_client_test", - "$glob_basedir/tests/release/mysql_client_test" + "$glob_basedir/tests/release/mysql_client_test", "$glob_basedir/tests/debug/mysql_client_test"); } } From 889e7147f69368edbba4b713df684f0f6cd93555 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Thu, 12 Oct 2006 20:15:56 +0200 Subject: [PATCH 074/131] Add ATTRIBUTE_FORMAT specifier to _db_doprnt, which is used by DBUG_PRINT This will hopefully avoiid annoying crashes when running with --debug Fix warnings from the above in mysqltest.c --- client/mysqltest.c | 8 +++----- include/my_dbug.h | 3 ++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index e2317560404..4aa30ba3f1e 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -890,7 +890,7 @@ int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname) die(NullS); if (!eval_result && (uint) stat_info.st_size != ds->length) { - DBUG_PRINT("info",("Size differs: result size: %u file size: %u", + DBUG_PRINT("info",("Size differs: result size: %u file size: %llu", ds->length, stat_info.st_size)); DBUG_PRINT("info",("result: '%s'", ds->str)); DBUG_RETURN(RESULT_LENGTH_MISMATCH); @@ -2558,7 +2558,7 @@ void do_get_errcodes(struct st_command *command) *to_ptr= 0; to->type= ERR_SQLSTATE; - DBUG_PRINT("info", ("ERR_SQLSTATE: %d", to->code.sqlstate)); + DBUG_PRINT("info", ("ERR_SQLSTATE: %s", to->code.sqlstate)); } else if (*p == 's') { @@ -4317,7 +4317,7 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, bind[i].is_null= &is_null[i]; bind[i].length= &length[i]; - DBUG_PRINT("bind", ("col[%d]: buffer_type: %d, buffer_length: %d", + DBUG_PRINT("bind", ("col[%d]: buffer_type: %d, buffer_length: %lu", i, bind[i].buffer_type, bind[i].buffer_length)); } @@ -7267,5 +7267,3 @@ void replace_dynstr_append_uint(DYNAMIC_STRING *ds, uint val) char *end= longlong10_to_str(val, buff, 10); replace_dynstr_append_mem(ds, buff, end - buff); } - - diff --git a/include/my_dbug.h b/include/my_dbug.h index 711ece4335c..d2f6e40f3c6 100644 --- a/include/my_dbug.h +++ b/include/my_dbug.h @@ -35,7 +35,8 @@ extern void _db_enter_(const char *_func_,const char *_file_,uint _line_, extern void _db_return_(uint _line_,const char **_sfunc_,const char **_sfile_, uint *_slevel_); extern void _db_pargs_(uint _line_,const char *keyword); -extern void _db_doprnt_ _VARARGS((const char *format,...)); +extern void _db_doprnt_ _VARARGS((const char *format,...)) + ATTRIBUTE_FORMAT(printf, 1, 2); extern void _db_dump_(uint _line_,const char *keyword,const char *memory, uint length); extern void _db_output_(); From 31f4aaa5be627da5651fd3767edd1f699562ce86 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Thu, 12 Oct 2006 20:52:53 +0200 Subject: [PATCH 075/131] Skip looking for ndbapi-examples in 4.1, not part of dist --- mysql-test/mysql-test-run.pl | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 0c46bbeac79..dc2212f953b 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1386,11 +1386,14 @@ sub executable_setup () { mtr_exe_exists("$ndb_path/src/kernel/ndbd", "$glob_basedir/bin/ndbd"); - $path_ndb_examples_dir= - mtr_path_exists("$ndb_path/ndbapi-examples", - "$ndb_path/examples"); - $exe_ndb_example= - mtr_file_exists("$path_ndb_examples_dir/ndbapi_simple/ndbapi_simple"); + if ( $mysql_version_id >= 50000 ) + { + $path_ndb_examples_dir= + mtr_path_exists("$ndb_path/ndbapi-examples", + "$ndb_path/examples"); + $exe_ndb_example= + mtr_file_exists("$path_ndb_examples_dir/ndbapi_simple/ndbapi_simple"); + } } # Look for the udf_example library @@ -1548,8 +1551,11 @@ sub environment_setup () { $ENV{'NDB_TOOLS_OUTPUT'}= $path_ndb_testrun_log; $ENV{'NDB_CONNECTSTRING'}= $opt_ndbconnectstring; - $ENV{'NDB_EXAMPLES_DIR'}= $path_ndb_examples_dir; - $ENV{'MY_NDB_EXAMPLES_BINARY'}= $exe_ndb_example; + if ( $mysql_version_id >= 50000 ) + { + $ENV{'NDB_EXAMPLES_DIR'}= $path_ndb_examples_dir; + $ENV{'MY_NDB_EXAMPLES_BINARY'}= $exe_ndb_example; + } $ENV{'NDB_EXAMPLES_OUTPUT'}= $path_ndb_testrun_log; } From 6e3280fd3b94324e6cc57e7f3f57e6dc92dfd93a Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Fri, 13 Oct 2006 08:48:47 +0200 Subject: [PATCH 076/131] Add missing semicolon in test file --- mysql-test/r/csv.result | 3 +-- mysql-test/t/csv.test | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/csv.result b/mysql-test/r/csv.result index 2e3d11ad461..7c7bcc3440c 100644 --- a/mysql-test/r/csv.result +++ b/mysql-test/r/csv.result @@ -4913,8 +4913,7 @@ bonfire Colombo nondecreasing DROP TABLE t1; -ALTER TABLE t2 RENAME t1 -#; +ALTER TABLE t2 RENAME t1; DROP TABLE t1; CREATE TABLE t1 ( Period smallint(4) unsigned zerofill DEFAULT '0000' NOT NULL, diff --git a/mysql-test/t/csv.test b/mysql-test/t/csv.test index 5b693335a43..e78c2ccc578 100644 --- a/mysql-test/t/csv.test +++ b/mysql-test/t/csv.test @@ -1295,7 +1295,7 @@ SELECT fld3 FROM t2; # DROP TABLE t1; -ALTER TABLE t2 RENAME t1 +ALTER TABLE t2 RENAME t1; # # Drop and recreate From 927c20dd0fcbe221e03c4b5f4d210a93c315848f Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Fri, 13 Oct 2006 10:41:40 +0200 Subject: [PATCH 077/131] Improve function that finds the reason why test was skipped, the old version only looked at the ast line, but there might be some additional debug info there so it's better to scan the whole file. There should be only one line that says "reason: " --- mysql-test/mysql-test-run.pl | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index dc2212f953b..24cdedce712 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2815,6 +2815,33 @@ sub do_after_run_mysqltest($) } +sub find_testcase_skipped_reason($) +{ + my ($tinfo)= @_; + + # Open mysqltest.log + my $F= IO::File->new($path_timefile) or + mtr_error("can't open file \"$path_timefile\": $!"); + my $reason; + + while ( my $line= <$F> ) + { + # Look for "reason: " + if ( $line =~ /reason: (.*)/ ) + { + $reason= $1; + } + } + + if ( ! $reason ) + { + mtr_warning("Could not find reason for skipping test in $path_timefile"); + $reason= "Detected by testcase(reason unknown) "; + } + $tinfo->{'comment'}= $reason; +} + + ############################################################################## # # Run a single test case @@ -2887,10 +2914,7 @@ sub run_testcase ($) { # Testcase itself tell us to skip this one # Try to get reason from mysqltest.log - my $last_line= mtr_lastlinefromfile($path_timefile) if -f $path_timefile; - my $reason= mtr_match_prefix($last_line, "reason: "); - $tinfo->{'comment'}= - defined $reason ? $reason : "Detected by testcase(reason unknown) "; + find_testcase_skipped_reason($tinfo); mtr_report_test_skipped($tinfo); } elsif ( $res == 63 ) From c2574de306aefba0a88c7f58366cb4ac30c1c4e0 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Fri, 13 Oct 2006 11:05:46 +0200 Subject: [PATCH 078/131] Improve the function that parses test files looking for what features it uses Now also detects "source nnnn;" command, previous version only detected "--source" --- mysql-test/lib/mtr_cases.pl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index e6980a0abb9..42062b7ba24 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -575,8 +575,6 @@ sub mtr_options_from_test_file($$) { while ( my $line= <$F> ) { - next if ( $line !~ /^--/ ); - # Match this line against tag in "tags" array foreach my $tag (@tags) { @@ -588,14 +586,21 @@ sub mtr_options_from_test_file($$) { } # If test sources another file, open it as well - if ( $line =~ /^\-\-([[:space:]]*)source(.*)$/ ) + if ( $line =~ /^\-\-([[:space:]]*)source(.*)$/ or + $line =~ /^([[:space:]]*)source(.*);$/ ) { my $value= $2; $value =~ s/^\s+//; # Remove leading space $value =~ s/[[:space:]]+$//; # Remove ending space my $sourced_file= "$::glob_mysql_test_dir/$value"; - mtr_options_from_test_file($tinfo, $sourced_file); + if ( -f $sourced_file ) + { + # Only source the file if it exists, we may get + # false positives in the regexes above if someone + # writes "source nnnn;" in a test case(such as mysqltest.test) + mtr_options_from_test_file($tinfo, $sourced_file); + } } } From de3f217e10e5403db60c69eb2d5dc85d6d6d9709 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Fri, 13 Oct 2006 11:38:32 +0200 Subject: [PATCH 079/131] Use 'my_strnncoll_simple' instead of 'strncasecmp' --- client/mysqltest.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 4aa30ba3f1e..e46f22de4df 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3397,8 +3397,10 @@ int read_line(char *buf, int size) DBUG_RETURN(0); } else if ((c == '{' && - (!strncasecmp(buf, "while", min(5, p - buf)) || - !strncasecmp(buf, "if", min(2, p - buf))))) + (!my_strnncoll_simple(charset_info, "while", 5, + buf, min(5, p - buf), 0) || + !my_strnncoll_simple(charset_info, "if", 2, + buf, min(2, p - buf), 0)))) { /* Only if and while commands can be terminated by { */ *p++= c; From c31a028b9db0c4b7da781fa5c3b1bec594b3f751 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Fri, 13 Oct 2006 11:53:19 +0200 Subject: [PATCH 080/131] Optimize restarts by using --force-restart option --- mysql-test/t/rpl_dual_pos_advance-master.opt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/rpl_dual_pos_advance-master.opt b/mysql-test/t/rpl_dual_pos_advance-master.opt index 35fcc5f30c6..cef79bc8585 100644 --- a/mysql-test/t/rpl_dual_pos_advance-master.opt +++ b/mysql-test/t/rpl_dual_pos_advance-master.opt @@ -1 +1 @@ ---loose-to-force-a-restart +--force-restart From 31402835d4cef73dbe720f68dd79af0d6b68d1e8 Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/myoffice.izhnet.ru" <> Date: Fri, 13 Oct 2006 19:05:54 +0500 Subject: [PATCH 081/131] Fix for bug #23254: COMPRESS(NULL) makes all futher COMPRESS() calls on same Item return NULL We don't set null_value to 0 in the Item_func_compress::val_str() for not-NULL results. --- mysql-test/r/func_compress.result | 10 ++++++++++ mysql-test/t/func_compress.test | 14 +++++++++++++- sql/item_strfunc.cc | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/func_compress.result b/mysql-test/r/func_compress.result index 8d6fa9927ce..ed8d66e9327 100644 --- a/mysql-test/r/func_compress.result +++ b/mysql-test/r/func_compress.result @@ -79,3 +79,13 @@ uncompress(a) uncompressed_length(a) NULL NULL a 1 drop table t1; +create table t1(a blob); +insert into t1 values ('0'), (NULL), ('0'); +select compress(a), compress(a) from t1; +select compress(a) is null from t1; +compress(a) is null +0 +1 +0 +drop table t1; +End of 4.1 tests diff --git a/mysql-test/t/func_compress.test b/mysql-test/t/func_compress.test index 0f3c3cab307..223a5540f38 100644 --- a/mysql-test/t/func_compress.test +++ b/mysql-test/t/func_compress.test @@ -54,4 +54,16 @@ insert into t1 values(NULL), (compress('a')); select uncompress(a), uncompressed_length(a) from t1; drop table t1; -# End of 4.1 tests +# +# Bug #23254: problem with compress(NULL) +# + +create table t1(a blob); +insert into t1 values ('0'), (NULL), ('0'); +--disable_result_log +select compress(a), compress(a) from t1; +--enable_result_log +select compress(a) is null from t1; +drop table t1; + +--echo End of 4.1 tests diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 98888226e58..f7408cb5e9f 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2838,6 +2838,7 @@ String *Item_func_compress::val_str(String *str) null_value= 1; return 0; } + null_value= 0; if (res->is_empty()) return res; /* From 8c55cf8f9a9784bce6c20f2f1ef232bada48f114 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Fri, 13 Oct 2006 20:22:56 +0200 Subject: [PATCH 082/131] rpl_empty_master_crash need a master restart so that all log files are deleted --- mysql-test/t/rpl_empty_master_crash-master.opt | 1 + 1 file changed, 1 insertion(+) create mode 100644 mysql-test/t/rpl_empty_master_crash-master.opt diff --git a/mysql-test/t/rpl_empty_master_crash-master.opt b/mysql-test/t/rpl_empty_master_crash-master.opt new file mode 100644 index 00000000000..cef79bc8585 --- /dev/null +++ b/mysql-test/t/rpl_empty_master_crash-master.opt @@ -0,0 +1 @@ +--force-restart From 1c2113de4078b0ab3e46042ba819b84cf8f91feb Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Fri, 13 Oct 2006 20:29:27 +0200 Subject: [PATCH 083/131] Look for client bindirs client_release and client_debug before other directories. --- mysql-test/mysql-test-run.pl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 24cdedce712..3cc0110ed05 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -468,11 +468,11 @@ sub initial_setup () { # # Look for the path where to find the client binaries - $path_client_bindir= mtr_path_exists("$glob_basedir/client/release", + $path_client_bindir= mtr_path_exists("$glob_basedir/client_release", + "$glob_basedir/client_debug", + "$glob_basedir/client/release", "$glob_basedir/client/debug", "$glob_basedir/client", - "$glob_basedir/client_release", - "$glob_basedir/client_debug", "$glob_basedir/bin"); # Look for the mysqld executable @@ -484,6 +484,7 @@ sub initial_setup () { "$path_client_bindir/mysqld-debug", "$path_client_bindir/mysqld-max", "$glob_basedir/libexec/mysqld", + "$glob_basedir/bin/mysqld", "$glob_basedir/sql/release/mysqld", "$glob_basedir/sql/debug/mysqld"); From a9bd28307db529fdfde6204213aea6002ac8f3e7 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Sat, 14 Oct 2006 16:31:20 +0200 Subject: [PATCH 084/131] Skip looking for mysql_client_test in 4.1 on windows as it's not built by default --- mysql-test/mysql-test-run.pl | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 3cc0110ed05..79f01c3cb68 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1417,18 +1417,27 @@ sub executable_setup () { } - # Look for mysql_client_test executable - if ( $glob_use_embedded_server ) + if ( $glob_win32 and $mysql_version_id < 50000 ) { - $exe_mysql_client_test= - mtr_exe_exists("$glob_basedir/libmysqld/examples/mysql_client_test_embedded"); + # Skip looking for exe_mysql_client_test as its not built by default + # in 4.1 for windows. + exe_mysql_client_test= "unavailable"; } else { - $exe_mysql_client_test= - mtr_exe_exists("$glob_basedir/tests/mysql_client_test", - "$glob_basedir/tests/release/mysql_client_test", - "$glob_basedir/tests/debug/mysql_client_test"); + # Look for mysql_client_test executable + if ( $glob_use_embedded_server ) + { + $exe_mysql_client_test= + mtr_exe_exists("$glob_basedir/libmysqld/examples/mysql_client_test_embedded"); + } + else + { + $exe_mysql_client_test= + mtr_exe_exists("$glob_basedir/tests/mysql_client_test", + "$glob_basedir/tests/release/mysql_client_test", + "$glob_basedir/tests/debug/mysql_client_test"); + } } } From d8b9f7cb0eaa3be9fa5f71f2b0ab8c22d9d6b592 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Sat, 14 Oct 2006 17:02:43 +0200 Subject: [PATCH 085/131] Improving debugging support in 'read_line' function --- client/mysqltest.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index e46f22de4df..7029e0af3e1 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -3346,7 +3346,7 @@ int read_line(char *buf, int size) LINT_INIT(last_quote); start_lineno= cur_file->lineno; - DBUG_PRINT("info", ("start_lineno: %d", start_lineno)); + DBUG_PRINT("info", ("Starting to read at lineno: %d", start_lineno)); for (; p < buf_end ;) { skip_char= 0; @@ -3370,7 +3370,7 @@ int read_line(char *buf, int size) die("Missing end of block"); *p= 0; - DBUG_PRINT("info", ("end of file")); + DBUG_PRINT("info", ("end of file at line %d", cur_file->lineno)); DBUG_RETURN(1); } cur_file--; @@ -3393,7 +3393,8 @@ int read_line(char *buf, int size) if (end_of_query(c)) { *p= 0; - DBUG_PRINT("exit", ("Found delimiter '%s'", delimiter)); + DBUG_PRINT("exit", ("Found delimiter '%s' at line %d", + delimiter, cur_file->lineno)); DBUG_RETURN(0); } else if ((c == '{' && @@ -3405,7 +3406,8 @@ int read_line(char *buf, int size) /* Only if and while commands can be terminated by { */ *p++= c; *p= 0; - DBUG_PRINT("exit", ("Found '{' indicating begining of block")); + DBUG_PRINT("exit", ("Found '{' indicating start of block at line %d", + cur_file->lineno)); DBUG_RETURN(0); } else if (c == '\'' || c == '"' || c == '`') @@ -3420,7 +3422,8 @@ int read_line(char *buf, int size) { /* Comments are terminated by newline */ *p= 0; - DBUG_PRINT("exit", ("Found newline in comment")); + DBUG_PRINT("exit", ("Found newline in comment at line: %d", + cur_file->lineno)); DBUG_RETURN(0); } break; @@ -3435,13 +3438,19 @@ int read_line(char *buf, int size) { /* Skip all space at begining of line */ if (c == '\n') - start_lineno= cur_file->lineno; /* Query hasn't started yet */ + { + /* Query hasn't started yet */ + start_lineno= cur_file->lineno; + DBUG_PRINT("info", ("Query hasn't started yet, start_lineno: %d", + start_lineno)); + } skip_char= 1; } else if (end_of_query(c)) { *p= 0; - DBUG_PRINT("exit", ("Found delimiter '%s'", delimiter)); + DBUG_PRINT("exit", ("Found delimiter '%s' at line: %d", + delimiter, cur_file->lineno)); DBUG_RETURN(0); } else if (c == '}') @@ -3449,7 +3458,8 @@ int read_line(char *buf, int size) /* A "}" need to be by itself in the begining of a line to terminate */ *p++= c; *p= 0; - DBUG_PRINT("exit", ("Found '}' in begining of a line")); + DBUG_PRINT("exit", ("Found '}' in begining of a line at line: %d", + cur_file->lineno)); DBUG_RETURN(0); } else if (c == '\'' || c == '"' || c == '`') From a9e60bab2917d263db14f9543b4af9f230155b46 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Sat, 14 Oct 2006 17:09:06 +0200 Subject: [PATCH 086/131] Use char as datatype for the byte that are read with my_fgetc, fixes problem with mysqltest.test on Solaris and Mac. write_file produced nice files with all zeroes. --- client/mysqltest.c | 2 +- mysql-test/mysql-test-run.pl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 7029e0af3e1..efb5f1915f4 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1810,7 +1810,7 @@ void my_ungetc(int c) void read_until_delimiter(DYNAMIC_STRING *ds, DYNAMIC_STRING *ds_delimiter) { - int c; + char c; DBUG_ENTER("read_until_delimiter"); DBUG_PRINT("enter", ("delimiter: %s, length: %d", ds_delimiter->str, ds_delimiter->length)); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 79f01c3cb68..35782733b20 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1421,7 +1421,7 @@ sub executable_setup () { { # Skip looking for exe_mysql_client_test as its not built by default # in 4.1 for windows. - exe_mysql_client_test= "unavailable"; + $exe_mysql_client_test= "unavailable"; } else { From 88e11706c3491e83f359729d08aab362d36b4403 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Sat, 14 Oct 2006 17:14:03 +0200 Subject: [PATCH 087/131] No need to continue in 'mtr_report_test_failed' after timeout detected, return immediately after --- mysql-test/lib/mtr_report.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index ec1bed9671b..b173896d48a 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -133,6 +133,7 @@ sub mtr_report_test_failed ($) { if ( $tinfo->{'timeout'} ) { print "[ fail ] timeout\n"; + return; } elsif ( $tinfo->{'ndb_test'} and $::cluster->[0]->{'installed_ok'} eq "NO") { From 947d219d1bd5a6a8d8ea002b1f8614ad726b607c Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Sun, 15 Oct 2006 15:38:56 +0200 Subject: [PATCH 088/131] Cleanup mtr_timer Add verbose printouts making it possible to see what happens. Make it an error if trying to stop a non existing timer Print warning if fork fails. --- mysql-test/lib/mtr_timer.pl | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/mysql-test/lib/mtr_timer.pl b/mysql-test/lib/mtr_timer.pl index a85ab8c6122..4c71e41fa0a 100644 --- a/mysql-test/lib/mtr_timer.pl +++ b/mysql-test/lib/mtr_timer.pl @@ -4,23 +4,22 @@ # and is part of the translation of the Bourne shell script with the # same name. -use Carp qw(cluck); use Socket; use Errno; use strict; #use POSIX ":sys_wait_h"; -use POSIX 'WNOHANG'; +#use POSIX 'WNOHANG'; sub mtr_init_timers (); sub mtr_timer_start($$$); sub mtr_timer_stop($$); sub mtr_timer_stop_all($); -sub mtr_timer_waitpid($$$); + ############################################################################## # -# Initiate a structure shared by all timers +# Initiate the structure shared by all timers # ############################################################################## @@ -35,17 +34,19 @@ sub mtr_init_timers () { # Start, stop and poll a timer # # As alarm() isn't portable to Windows, we use separate processes to -# implement timers. That is why there is a mtr_timer_waitpid(), as this -# is where we catch a timeout. +# implement timers. # ############################################################################## sub mtr_timer_start($$$) { my ($timers,$name,$duration)= @_; + mtr_verbose("mtr_timer_start: $name, $duration"); + if ( exists $timers->{'timers'}->{$name} ) { # We have an old running timer, kill it + mtr_verbose("There is an old timer running"); mtr_timer_stop($timers,$name); } @@ -57,7 +58,7 @@ sub mtr_timer_start($$$) { { if ( $! == $!{EAGAIN} ) # See "perldoc Errno" { - mtr_debug("Got EAGAIN from fork(), sleep 1 second and redo"); + mtr_warning("Got EAGAIN from fork(), sleep 1 second and redo"); sleep(1); redo FORK; } @@ -70,6 +71,7 @@ sub mtr_timer_start($$$) { if ( $tpid ) { # Parent, record the information + mtr_verbose("timer parent, record info($name, $tpid, $duration)"); $timers->{'timers'}->{$name}->{'pid'}= $tpid; $timers->{'timers'}->{$name}->{'duration'}= $duration; $timers->{'pids'}->{$tpid}= $name; @@ -85,6 +87,7 @@ sub mtr_timer_start($$$) { $SIG{INT}= 'DEFAULT'; $0= "mtr_timer(timers,$name,$duration)"; + mtr_verbose("timer child $name, sleep $duration"); sleep($duration); exit(0); } @@ -95,9 +98,12 @@ sub mtr_timer_start($$$) { sub mtr_timer_stop ($$) { my ($timers,$name)= @_; + mtr_verbose("mtr_timer_stop: $name"); + if ( exists $timers->{'timers'}->{$name} ) { my $tpid= $timers->{'timers'}->{$name}->{'pid'}; + mtr_verbose("Stopping timer with pid $tpid"); # FIXME as Cygwin reuses pids fast, maybe check that is # the expected process somehow?! @@ -114,7 +120,7 @@ sub mtr_timer_stop ($$) { } else { - mtr_debug("Asked to stop timer \"$name\" not started"); + mtr_error("Asked to stop timer \"$name\" not started"); return 0; } } From 3f46c5cdbdda492e62941a74c41138404f703772 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Tue, 17 Oct 2006 08:10:51 +0200 Subject: [PATCH 089/131] When calculating what features to use for _this_ test run, don't look at test that already are deterined to be skipped --- mysql-test/mysql-test-run.pl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 35782733b20..5309e030c2c 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -391,6 +391,8 @@ sub main () { my ($need_ndbcluster,$need_im); foreach my $test (@$tests) { + next if $test->{skip}; + $need_ndbcluster||= $test->{ndb_test}; $need_im||= $test->{component_id} eq 'im'; From d45b61b1b5d6cbefe206e068a0b48ea128f0e636 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Tue, 17 Oct 2006 10:31:06 +0200 Subject: [PATCH 090/131] Remove warnings Set comment properly before calling mtr_report_test failed and report_failure_restart --- mysql-test/lib/mtr_report.pl | 7 +------ mysql-test/mysql-test-run.pl | 25 +++++++++++-------------- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index b173896d48a..e92cac5cfba 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -130,16 +130,11 @@ sub mtr_report_test_failed ($) { my $tinfo= shift; $tinfo->{'result'}= 'MTR_RES_FAILED'; - if ( $tinfo->{'timeout'} ) + if ( defined $tinfo->{'timeout'} ) { print "[ fail ] timeout\n"; return; } - elsif ( $tinfo->{'ndb_test'} and $::cluster->[0]->{'installed_ok'} eq "NO") - { - print "[ fail ] ndbcluster start failure\n"; - return; - } else { print "[ fail ]\n"; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 5309e030c2c..1d217bdef84 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2755,10 +2755,9 @@ sub run_testcase_check_skip_test($) # If test needs this cluster, check it was installed ok if ( !$cluster->{'installed_ok'} ) { - mtr_tofile($path_timefile, - "Test marked as failed because $cluster->{'name'} " . - "was not installed ok!"); mtr_report_test_name($tinfo); + $tinfo->{comment}= + "Cluster $cluster->{'name'} was not installed ok"; mtr_report_test_failed($tinfo); return 1; } @@ -2881,10 +2880,8 @@ sub run_testcase ($) { # Can't restart a running server that may be in use if ( $glob_use_running_server ) { - $tinfo->{'skip'}= 1; - $tinfo->{'comment'}= "Can't restart a running server"; - mtr_report_test_name($tinfo); + $tinfo->{comment}= "Can't restart a running server"; mtr_report_test_skipped($tinfo); return; } @@ -2934,16 +2931,16 @@ sub run_testcase ($) { $tinfo->{'timeout'}= 1; # Mark as timeout report_failure_and_restart($tinfo); } + elsif ( $res == 1 ) + { + # Test case failure reported by mysqltest + report_failure_and_restart($tinfo); + } else { - # Test case failed, if in control mysqltest returns 1 - if ( $res != 1 ) - { - mtr_tofile($path_timefile, - "mysqltest returned unexpected code $res, " . - "it has probably crashed"); - } - + # mysqltest failed, probably crashed + $tinfo->{comment}= + "mysqltest returned unexpected code $res, it has probably crashed"; report_failure_and_restart($tinfo); } From 8d72bf94487c0b700e20e6fed1ed8e6f59c3cce8 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Wed, 18 Oct 2006 13:24:06 +0200 Subject: [PATCH 091/131] Make --with-ndbcluster only be valid together with --bench Improve code that detects if ndb shuold be installed Remove call to stop_all_servers after install db, if any servers are still running and need to be stopped they will be stopped atuomatically --- mysql-test/lib/mtr_cases.pl | 81 +++++++++++++++++++----------------- mysql-test/mysql-test-run.pl | 50 ++++++++++++---------- 2 files changed, 71 insertions(+), 60 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 42062b7ba24..88c51728fb2 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -59,7 +59,9 @@ sub collect_test_cases ($) { if ( @::opt_cases ) { - foreach my $tname ( @::opt_cases ) { # Run in specified order, no sort + foreach my $tname ( @::opt_cases ) + { + # Run in specified order, no sort my $elem= undef; my $component_id= undef; @@ -85,7 +87,7 @@ sub collect_test_cases ($) { # If target component is known, check that the specified test case # exists. - # + # # Otherwise, try to guess the target component. if ( $component_id ) @@ -127,7 +129,8 @@ sub collect_test_cases ($) { } else { - foreach my $elem ( sort readdir(TESTDIR) ) { + foreach my $elem ( sort readdir(TESTDIR) ) + { my $component_id= undef; my $tname= undef; @@ -144,7 +147,9 @@ sub collect_test_cases ($) { next; } - next if $::opt_do_test and ! defined mtr_match_prefix($elem,$::opt_do_test); + # Skip tests that does not match the --do-test= filter + next if $::opt_do_test and + ! defined mtr_match_prefix($elem,$::opt_do_test); collect_one_test_case($testdir,$resdir,$tname,$elem,$cases,\%disabled, $component_id); @@ -152,7 +157,7 @@ sub collect_test_cases ($) { closedir TESTDIR; } - # Reorder the test cases in an order that wil make them faster to run + # Reorder the test cases in an order that will make them faster to run if ( $::opt_reorder ) { @@ -306,40 +311,6 @@ sub collect_one_test_case($$$$$$$) { $tinfo->{'slave_num'}= 1; } - if ( $::opt_with_ndbcluster or defined mtr_match_substring($tname,"ndb") ) - { - # This is an ndb test or all tests should be run with ndb cluster started - $tinfo->{'ndb_test'}= 1; - if ( ! $::opt_ndbcluster_supported ) - { - # Ndb is not supported, skip them - $tinfo->{'skip'}= 1; - $tinfo->{'comment'}= "No ndbcluster support"; - return; - } - elsif ( $::opt_skip_ndbcluster ) - { - # All ndb test's should be skipped - $tinfo->{'skip'}= 1; - $tinfo->{'comment'}= "No ndbcluster tests(--skip-ndbcluster)"; - return; - } - } - else - { - # This is not a ndb test - $tinfo->{'ndb_test'}= 0; - if ( $::opt_with_ndbcluster_only ) - { - # Only the ndb test should be run, all other should be skipped - $tinfo->{'skip'}= 1; - $tinfo->{'comment'}= "Only ndbcluster tests(--with-ndbcluster-only)"; - return; - } - } - - # FIXME what about embedded_server + ndbcluster, skip ?! - my $master_opt_file= "$testdir/$tname-master.opt"; my $slave_opt_file= "$testdir/$tname-slave.opt"; my $slave_mi_file= "$testdir/$tname.slave-mi"; @@ -550,6 +521,37 @@ sub collect_one_test_case($$$$$$$) { $tinfo->{'comment'}= "Test need debug binaries"; return; } + + if ( $tinfo->{'ndb_test'} ) + { + # This is a NDB test + if ( ! $::glob_ndbcluster_supported ) + { + # Ndb is not supported, skip it + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No ndbcluster support"; + return; + } + elsif ( $::opt_skip_ndbcluster ) + { + # All ndb test's should be skipped + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No ndbcluster tests(--skip-ndbcluster)"; + return; + } + } + else + { + # This is not a ndb test + if ( $::opt_with_ndbcluster_only ) + { + # Only the ndb test should be run, all other should be skipped + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "Only ndbcluster tests(--with-ndbcluster-only)"; + return; + } + } + } } @@ -563,6 +565,7 @@ our @tags= ["include/have_binlog_format_statement.inc", "binlog_format", "stmt"], ["include/big_test.inc", "big_test", 1], ["include/have_debug.inc", "need_debug", 1], + ["include/have_ndb.inc", "ndb_test", 1], ["include/have_ndb_extra.inc", "ndb_extra", 1], ["require_manager", "require_manager", 1], ); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 1d217bdef84..05baaaa6f2f 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -65,6 +65,7 @@ use IO::Socket; use IO::Socket::INET; use Data::Dumper; use strict; +use warnings; use diagnostics; our $glob_win32_perl= ($^O eq "MSWin32"); # ActiveState Win32 Perl @@ -277,7 +278,7 @@ our $opt_skip_ndbcluster= 0; our $opt_skip_ndbcluster_slave= 0; our $opt_with_ndbcluster= 0; our $opt_with_ndbcluster_only= 0; -our $opt_ndbcluster_supported= 0; +our $glob_ndbcluster_supported= 0; our $opt_ndb_extra_test= 0; our $opt_skip_master_binlog= 0; our $opt_skip_slave_binlog= 0; @@ -572,10 +573,10 @@ sub command_line_setup () { 'compress' => \$opt_compress, 'bench' => \$opt_bench, 'small-bench' => \$opt_small_bench, + 'with-ndbcluster' => \$opt_with_ndbcluster, # Control what test suites or cases to run 'force' => \$opt_force, - 'with-ndbcluster' => \$opt_with_ndbcluster, 'with-ndbcluster-only' => \$opt_with_ndbcluster_only, 'skip-ndbcluster|skip-ndb' => \$opt_skip_ndbcluster, 'skip-ndbcluster-slave|skip-ndb-slave' @@ -846,9 +847,9 @@ sub command_line_setup () { # -------------------------------------------------------------------------- # Ndb cluster flags # -------------------------------------------------------------------------- - if ( $opt_with_ndbcluster and $opt_skip_ndbcluster) + if ( $opt_with_ndbcluster and !$opt_bench) { - mtr_error("Can't specify both --with-ndbcluster and --skip-ndbcluster"); + mtr_error("Can only use --with-ndbcluster togheter with --bench"); } if ( $opt_ndbconnectstring ) @@ -1485,7 +1486,7 @@ sub environment_setup () { # -------------------------------------------------------------------------- # Add the path where libndbclient can be found # -------------------------------------------------------------------------- - if ( $opt_ndbcluster_supported ) + if ( $glob_ndbcluster_supported ) { push(@ld_library_paths, "$glob_basedir/storage/ndb/src/.libs"); } @@ -1870,6 +1871,8 @@ sub cleanup_stale_files () { rmtree(readlink($opt_vardir)); # Remove the entire "var" dir rmtree("$opt_vardir/"); + # Remove the "var" symlink + unlink($opt_vardir); } else { @@ -2042,7 +2045,7 @@ sub check_ndbcluster_support ($) { $opt_skip_ndbcluster_slave= 1; return; } - $opt_ndbcluster_supported= 1; + $glob_ndbcluster_supported= 1; mtr_report("Using ndbcluster when necessary, mysqld supports it"); if ( $mysql_version_id < 50100 ) @@ -2059,11 +2062,6 @@ sub check_ndbcluster_support ($) { sub ndbcluster_start_install ($) { my $cluster= shift; - if ( $opt_skip_ndbcluster or $glob_use_running_ndbcluster ) - { - return 0; - } - mtr_report("Installing $cluster->{'name'} Cluster"); mkdir($cluster->{'data_dir'}); @@ -2477,11 +2475,24 @@ sub mysql_install_db () { my $cluster_started_ok= 1; # Assume it can be started - if (ndbcluster_start_install($clusters->[0]) || - ($max_slave_num && !$opt_skip_ndbcluster_slave && - ndbcluster_start_install($clusters->[1]))) + if ($opt_skip_ndbcluster || $glob_use_running_ndbcluster) { - mtr_warning("Failed to start install of cluster"); + # Don't install master cluster + } + elsif (ndbcluster_start_install($clusters->[0])) + { + mtr_warning("Failed to start install of $clusters->[0]->{name}"); + $cluster_started_ok= 0; + } + + if ($max_slave_num == 0 || + $opt_skip_ndbcluster_slave || $glob_use_running_ndbcluster_slave) + { + # Don't install slave cluster + } + elsif (ndbcluster_start_install($clusters->[1])) + { + mtr_warning("Failed to start install of $clusters->[1]->{name}"); $cluster_started_ok= 0; } @@ -2514,9 +2525,6 @@ sub mysql_install_db () { } } - # Stop clusters... - stop_all_servers(); - return 0; } @@ -3592,14 +3600,14 @@ sub run_testcase_need_master_restart($) mtr_verbose("Restart master: Restart forced with --force-restart"); } elsif ( ! $opt_skip_ndbcluster and - $tinfo->{'ndb_test'} == 0 and + !$tinfo->{'ndb_test'} and $clusters->[0]->{'pid'} != 0 ) { $do_restart= 1; # Restart without cluster mtr_verbose("Restart master: Test does not need cluster"); } elsif ( ! $opt_skip_ndbcluster and - $tinfo->{'ndb_test'} == 1 and + $tinfo->{'ndb_test'} and $clusters->[0]->{'pid'} == 0 ) { $do_restart= 1; # Restart with cluster @@ -4455,6 +4463,7 @@ Options to control what engine/variation to run skip-ssl Dont start server with support for ssl connections bench Run the benchmark suite small-bench Run the benchmarks with --small-tests --small-tables + with-ndbcluster Use cluster as default table type for benchmark Options to control directories to use benchdir=DIR The directory where the benchmark suite is stored @@ -4471,7 +4480,6 @@ Options to control directories to use Options to control what test suites or cases to run force Continue to run the suite after failure - with-ndbcluster Use cluster in all tests with-ndbcluster-only Run only tests that include "ndb" in the filename skip-ndb[cluster] Skip all tests that need cluster skip-ndb[cluster]-slave Skip all tests that need a slave cluster From 4890ed261c78e7c3959a0f886138fd32d86e9aee Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Wed, 18 Oct 2006 16:30:51 +0200 Subject: [PATCH 092/131] Fix bug where a timer was stopped by calling mtr_timer_stop with a "timer" instead of it's name --- mysql-test/lib/mtr_timer.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/lib/mtr_timer.pl b/mysql-test/lib/mtr_timer.pl index 4c71e41fa0a..9bb37c7e3fc 100644 --- a/mysql-test/lib/mtr_timer.pl +++ b/mysql-test/lib/mtr_timer.pl @@ -144,7 +144,7 @@ sub mtr_timer_timeout ($$) { # We got a timeout my $name= $timers->{'pids'}->{$pid}; - mtr_timer_stop($timers, $timers->{'timers'}->{$name}); + mtr_timer_stop($timers, $name); return $name; } From 1feac4d44f816dffda953712bec62511b37afe42 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Wed, 18 Oct 2006 16:39:00 +0200 Subject: [PATCH 093/131] Stop all timers before exiting when --start-and-exit --- mysql-test/mysql-test-run.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 05baaaa6f2f..daa5b8aca96 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2913,6 +2913,7 @@ sub run_testcase ($) { # ---------------------------------------------------------------------- if ( $opt_start_and_exit or $opt_start_dirty ) { + mtr_timer_stop_all($glob_timers); mtr_report("\nServers started, exiting"); exit(0); } From dd6a9307f1307ce2041560a7253338b37f606c97 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Wed, 18 Oct 2006 16:40:22 +0200 Subject: [PATCH 094/131] Remove some junk --- mysql-test/lib/mtr_process.pl | 2 -- mysql-test/lib/mtr_timer.pl | 3 --- 2 files changed, 5 deletions(-) diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index 2831c179ea5..affe8278376 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -8,7 +8,6 @@ use Socket; use Errno; use strict; -#use POSIX ":sys_wait_h"; use POSIX 'WNOHANG'; sub mtr_run ($$$$$$;$); @@ -1088,7 +1087,6 @@ sub mtr_kill_processes ($) { sub mtr_exit ($) { my $code= shift; -# cluck("Called mtr_exit()"); mtr_timer_stop_all($::glob_timers); local $SIG{HUP} = 'IGNORE'; # ToDo: Signalling -$$ will only work if we are the process group diff --git a/mysql-test/lib/mtr_timer.pl b/mysql-test/lib/mtr_timer.pl index 9bb37c7e3fc..406692e35fa 100644 --- a/mysql-test/lib/mtr_timer.pl +++ b/mysql-test/lib/mtr_timer.pl @@ -8,9 +8,6 @@ use Socket; use Errno; use strict; -#use POSIX ":sys_wait_h"; -#use POSIX 'WNOHANG'; - sub mtr_init_timers (); sub mtr_timer_start($$$); sub mtr_timer_stop($$); From 770a1f919f5ea392084fde8eeffb998478f3fa56 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Wed, 18 Oct 2006 17:16:08 +0200 Subject: [PATCH 095/131] Don't stop the time in mtr_timer_timeout, that will be done after testcase or when program exit --- mysql-test/lib/mtr_timer.pl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mysql-test/lib/mtr_timer.pl b/mysql-test/lib/mtr_timer.pl index 406692e35fa..06374716c62 100644 --- a/mysql-test/lib/mtr_timer.pl +++ b/mysql-test/lib/mtr_timer.pl @@ -139,10 +139,8 @@ sub mtr_timer_timeout ($$) { return "" unless exists $timers->{'pids'}->{$pid}; - # We got a timeout - my $name= $timers->{'pids'}->{$pid}; - mtr_timer_stop($timers, $name); - return $name; + # We got a timeout, return the name ot the timer + return $timers->{'pids'}->{$pid}; } 1; From 4cefd49b81a4f07caf1931c97b65ecc4686a0fbd Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Wed, 18 Oct 2006 17:58:26 +0200 Subject: [PATCH 096/131] =?UTF-8?q?Put=20the=20printf=20of=20failed=20rati?= =?UTF-8?q?o=20on=20it=C3=A4s=20only=20line,=20printf=20was=20tricked=20in?= =?UTF-8?q?to=20thinking=20the=20escaped=20%=20+=20w=20was=20a=20format=20?= =?UTF-8?q?specifier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysql-test/lib/mtr_report.pl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mysql-test/lib/mtr_report.pl b/mysql-test/lib/mtr_report.pl index e92cac5cfba..8d7de9d1a4b 100644 --- a/mysql-test/lib/mtr_report.pl +++ b/mysql-test/lib/mtr_report.pl @@ -203,8 +203,9 @@ sub mtr_report_stats ($) { else { my $ratio= $tot_passed * 100 / $tot_tests; - printf "Failed $tot_failed/$tot_tests tests, " . - "%.2f\% were successful.\n\n", $ratio; + print "Failed $tot_failed/$tot_tests tests, "; + printf("%.2f", $ratio); + print "\% were successful.\n\n"; print "The log files in var/log may give you some hint\n", "of what went wrong.\n", From 9010a7952748254e47caeb3108d6d4bbcd98e300 Mon Sep 17 00:00:00 2001 From: "andrey@example.com" <> Date: Wed, 18 Oct 2006 18:17:41 +0200 Subject: [PATCH 097/131] Fix for bug#23379 "wrong time value in SHOW PROCESSLIST" The value taken to be shown in SHOW PROCESSLIST is not initialized when THD is created and will be random for unauthenticated connections. To the documentor: Random value, instead of NULL, was shown, in SHOW PROCESSLIST for still non-authenticated connections. --- sql/sql_class.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index da752977fcd..f18f2fb6b7c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -181,6 +181,7 @@ THD::THD() // Must be reset to handle error with THD's created for init of mysqld lex->current_select= 0; start_time=(time_t) 0; + time_after_lock=(time_t) 0; current_linfo = 0; slave_thread = 0; variables.pseudo_thread_id= 0; From 0027b6e4b772a6b90ed67048451f3455aacfbf5d Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/myoffice.izhnet.ru" <> Date: Thu, 19 Oct 2006 12:52:37 +0500 Subject: [PATCH 098/131] Fix for bug #20732: Partial index and long sjis search with '>' fails sometimes We miss some records sometimes using RANGE method if we have partial key segments. Example: Create table t1(a char(2), key(a(1))); insert into t1 values ('a'), ('xx'); select a from t1 where a > 'x'; We call index_read() passing 'x' key and HA_READ_AFTER_KEY flag in the handler::read_range_first() wich is wrong because we have a partial key segment for the field and might miss records like 'xx'. Fix: don't use open segments in such a case. --- mysql-test/r/range.result | 10 ++++++++++ mysql-test/t/range.test | 12 +++++++++++- sql/opt_range.cc | 6 +++++- sql/opt_range.h | 2 +- sql/sql_select.cc | 2 +- sql/table.cc | 2 +- 6 files changed, 29 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index b436519d967..f25d94f8066 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -649,3 +649,13 @@ OR ((pk4 =1) AND (((pk1 IN ( 7, 2, 1 ))) OR (pk1 =522)) AND ((pk2 IN ( 0, 2635)) pk1 pk2 pk3 pk4 filler 2621 2635 1000015 0 filler drop table t1, t2; +create table t1(a char(2), key(a(1))); +insert into t1 values ('x'), ('xx'); +explain select a from t1 where a > 'x'; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range a a 2 NULL 2 Using where +select a from t1 where a > 'x'; +a +xx +drop table t1; +End of 4.1 tests diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 9280911df2c..245178d7d4a 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -510,4 +510,14 @@ OR ((pk4 =1) AND (((pk1 IN ( 7, 2, 1 ))) OR (pk1 =522)) AND ((pk2 IN ( 0, 2635)) ) AND (pk3 >=1000000); drop table t1, t2; -# End of 4.1 tests +# +# Bug #20732: Partial index and long sjis search with '>' fails sometimes +# + +create table t1(a char(2), key(a(1))); +insert into t1 values ('x'), ('xx'); +explain select a from t1 where a > 'x'; +select a from t1 where a > 'x'; +drop table t1; + +--echo End of 4.1 tests diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 6b129997e47..06e42ff363f 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -885,6 +885,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, key_parts->null_bit= key_part_info->null_bit; key_parts->image_type = (key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW; + key_parts->flag= key_part_info->key_part_flag; } param.real_keynr[param.keys++]=idx; } @@ -1398,7 +1399,9 @@ get_mm_leaf(PARAM *param, COND *conf_func, Field *field, KEY_PART *key_part, } break; case Item_func::GT_FUNC: - if (field_is_equal_to_item(field,value)) + /* Don't use open ranges for partial key_segments */ + if (field_is_equal_to_item(field,value) && + !(key_part->flag & HA_PART_KEY_SEG)) tree->min_flag=NEAR_MIN; /* fall through */ case Item_func::GE_FUNC: @@ -2899,6 +2902,7 @@ QUICK_SELECT *get_quick_select_for_ref(THD *thd, TABLE *table, TABLE_REF *ref) key_part->length= key_info->key_part[part].length; key_part->store_length= key_info->key_part[part].store_length; key_part->null_bit= key_info->key_part[part].null_bit; + key_part->flag= key_info->key_part[part].key_part_flag; } if (quick->ranges.push_back(range)) goto err; diff --git a/sql/opt_range.h b/sql/opt_range.h index 367a85dc6f2..4d425604921 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -36,7 +36,7 @@ typedef struct st_key_part { uint16 key,part, store_length, length; - uint8 null_bit; + uint8 null_bit, flag; Field *field; Field::imagetype image_type; } KEY_PART; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 33e923e1553..009cd7ae283 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7337,7 +7337,7 @@ part_of_refkey(TABLE *table,Field *field) for (uint part=0 ; part < ref_parts ; part++,key_part++) if (field->eq(key_part->field) && - !(key_part->key_part_flag & HA_PART_KEY_SEG)) + !(key_part->key_part_flag & (HA_PART_KEY_SEG | HA_NULL_PART))) return table->reginfo.join_tab->ref.items[part]; } return (Item*) 0; diff --git a/sql/table.cc b/sql/table.cc index 0efed04c06e..f99afa61db9 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -676,7 +676,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, as we need to test for NULL = NULL. */ if (field->real_maybe_null()) - key_part->key_part_flag|= HA_PART_KEY_SEG; + key_part->key_part_flag|= HA_NULL_PART; } else { // Error: shorten key From b11dee73ca453388692d25c54da9e0dfbaab6167 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 19 Oct 2006 10:54:23 +0200 Subject: [PATCH 099/131] Backport test cases fixes from 5.0 --- client/mysqldump.c | 1 + mysql-test/include/have_lowercase0.inc | 4 +-- mysql-test/r/rpl000015.result | 6 ++-- mysql-test/r/rpl_change_master.result | 2 +- mysql-test/r/rpl_error_ignored_table.result | 2 +- mysql-test/r/rpl_loaddata.result | 6 ++-- mysql-test/r/rpl_log.result | 2 +- mysql-test/r/rpl_max_relay_size.result | 36 ++++++++++----------- mysql-test/r/rpl_replicate_do.result | 2 +- mysql-test/t/lowercase_table3.test | 8 ++--- mysql-test/t/mysql_protocols.test | 2 ++ mysql-test/t/rpl000015.test | 8 ++--- mysql-test/t/rpl_change_master.test | 3 +- mysql-test/t/rpl_drop_db.test | 2 ++ mysql-test/t/rpl_error_ignored_table.test | 2 +- mysql-test/t/rpl_loaddata.test | 6 ++-- mysql-test/t/rpl_log-master.opt | 2 +- mysql-test/t/rpl_log.test | 2 +- mysql-test/t/rpl_max_relay_size.test | 12 +++---- mysql-test/t/rpl_replicate_do.test | 2 +- 20 files changed, 56 insertions(+), 54 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 7e15a5dbbad..2d2fe439f76 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -785,6 +785,7 @@ static void DBerror(MYSQL *mysql, const char *when) DBUG_ENTER("DBerror"); fprintf(stderr, "%s: Got error: %d: %s %s\n", my_progname, mysql_errno(mysql), mysql_error(mysql), when); + fflush(stderr); safe_exit(EX_MYSQLERR); DBUG_VOID_RETURN; } /* DBerror */ diff --git a/mysql-test/include/have_lowercase0.inc b/mysql-test/include/have_lowercase0.inc index f967c18928b..8d3ae02f61e 100644 --- a/mysql-test/include/have_lowercase0.inc +++ b/mysql-test/include/have_lowercase0.inc @@ -1,4 +1,4 @@ --require r/lowercase0.require ---disable_query_log; +--disable_query_log show variables like "lower_case_%"; ---enable_query_log; +--enable_query_log diff --git a/mysql-test/r/rpl000015.result b/mysql-test/r/rpl000015.result index 8cbbe3ab0e8..b3e6ef71e45 100644 --- a/mysql-test/r/rpl000015.result +++ b/mysql-test/r/rpl000015.result @@ -8,16 +8,16 @@ Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File change master to master_host='127.0.0.1'; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 test MASTER_PORT 7 4 slave-relay-bin.000001 4 No No 0 0 0 4 None 0 No # +# 127.0.0.1 test MASTER_PORT 7 4 # # No No 0 0 0 # None 0 No # change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=MASTER_PORT; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_PORT 7 4 slave-relay-bin.000001 4 No No 0 0 0 4 None 0 No # +# 127.0.0.1 root MASTER_PORT 7 4 # # No No 0 0 0 # None 0 No # start slave; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_PORT 7 master-bin.000001 79 slave-relay-bin.000001 123 master-bin.000001 Yes Yes 0 0 79 123 None 0 No # +# 127.0.0.1 root MASTER_PORT 7 master-bin.000001 79 # # master-bin.000001 Yes Yes 0 0 79 # None 0 No # drop table if exists t1; create table t1 (n int); insert into t1 values (10),(45),(90); diff --git a/mysql-test/r/rpl_change_master.result b/mysql-test/r/rpl_change_master.result index a6342d47b49..16e14f5da2e 100644 --- a/mysql-test/r/rpl_change_master.result +++ b/mysql-test/r/rpl_change_master.result @@ -20,7 +20,7 @@ Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File change master to master_user='root'; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 214 slave-relay-bin.000001 4 master-bin.000001 No No 0 0 214 4 None 0 No # +# 127.0.0.1 root MASTER_MYPORT 1 master-bin.000001 214 # # master-bin.000001 No No 0 0 214 # None 0 No # select release_lock("a"); release_lock("a") 1 diff --git a/mysql-test/r/rpl_error_ignored_table.result b/mysql-test/r/rpl_error_ignored_table.result index 789ca72cd61..740d139b4c8 100644 --- a/mysql-test/r/rpl_error_ignored_table.result +++ b/mysql-test/r/rpl_error_ignored_table.result @@ -9,7 +9,7 @@ insert into t1 values (1),(1); ERROR 23000: Duplicate entry '1' for key 1 show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 213 slave-relay-bin.000002 257 master-bin.000001 Yes Yes test.t3,test.t1,test.t2 0 0 213 257 None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 213 # # master-bin.000001 Yes Yes test.t3,test.t1,test.t2 0 0 213 # None 0 No # show tables like 't1'; Tables_in_test (t1) drop table t1; diff --git a/mysql-test/r/rpl_loaddata.result b/mysql-test/r/rpl_loaddata.result index d0f2a885dcd..446b7961578 100644 --- a/mysql-test/r/rpl_loaddata.result +++ b/mysql-test/r/rpl_loaddata.result @@ -33,7 +33,7 @@ set global sql_slave_skip_counter=1; start slave; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1311 slave-relay-bin.000002 1355 master-bin.000001 Yes Yes 0 0 1311 1355 None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1311 # # master-bin.000001 Yes Yes 0 0 1311 # None 0 No # set sql_log_bin=0; delete from t1; set sql_log_bin=1; @@ -43,7 +43,7 @@ change master to master_user='test'; change master to master_user='root'; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1419 slave-relay-bin.000001 4 master-bin.000001 No No 0 0 1419 4 None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1419 # # master-bin.000001 No No 0 0 1419 # None 0 No # set global sql_slave_skip_counter=1; start slave; set sql_log_bin=0; @@ -54,7 +54,7 @@ stop slave; reset slave; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_PORT 1 4 slave-relay-bin.000001 4 No No 0 0 0 4 None 0 No # +# 127.0.0.1 root MASTER_PORT 1 4 # # No No 0 0 0 # None 0 No # reset master; create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60), unique(day)); diff --git a/mysql-test/r/rpl_log.result b/mysql-test/r/rpl_log.result index c496f3d540a..5a351ea693c 100644 --- a/mysql-test/r/rpl_log.result +++ b/mysql-test/r/rpl_log.result @@ -96,7 +96,7 @@ slave-bin.000002 62 Query 1 62 use `test`; insert into t1 values (1) slave-bin.000002 122 Query 1 122 use `test`; drop table t1 show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_PORT 1 master-bin.000002 276 slave-relay-bin.000003 214 master-bin.000002 Yes Yes 0 0 276 214 None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000002 276 # # master-bin.000002 Yes Yes 0 0 276 # None 0 No # show binlog events in 'slave-bin.000005' from 4; ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Could not find target log create table t1(a int auto_increment primary key, b int); diff --git a/mysql-test/r/rpl_max_relay_size.result b/mysql-test/r/rpl_max_relay_size.result index c0a7a0a5b00..eee655adea0 100644 --- a/mysql-test/r/rpl_max_relay_size.result +++ b/mysql-test/r/rpl_max_relay_size.result @@ -28,8 +28,8 @@ Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 Read_Master_Log_Pos 50477 -Relay_Log_File slave-relay-bin.000014 -Relay_Log_Pos 1221 +Relay_Log_File # +Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 Slave_IO_Running Yes Slave_SQL_Running Yes @@ -43,7 +43,7 @@ Last_Errno 0 Last_Error Skip_Counter 0 Exec_Master_Log_Pos 50477 -Relay_Log_Space 1221 +Relay_Log_Space # Until_Condition None Until_Log_File Until_Log_Pos 0 @@ -71,8 +71,8 @@ Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 Read_Master_Log_Pos 50477 -Relay_Log_File slave-relay-bin.000004 -Relay_Log_Pos 9457 +Relay_Log_File # +Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 Slave_IO_Running Yes Slave_SQL_Running Yes @@ -86,7 +86,7 @@ Last_Errno 0 Last_Error Skip_Counter 0 Exec_Master_Log_Pos 50477 -Relay_Log_Space 9457 +Relay_Log_Space # Until_Condition None Until_Log_File Until_Log_Pos 0 @@ -114,8 +114,8 @@ Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 Read_Master_Log_Pos 50477 -Relay_Log_File slave-relay-bin.000008 -Relay_Log_Pos 1283 +Relay_Log_File # +Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 Slave_IO_Running Yes Slave_SQL_Running Yes @@ -129,7 +129,7 @@ Last_Errno 0 Last_Error Skip_Counter 0 Exec_Master_Log_Pos 50477 -Relay_Log_Space 1283 +Relay_Log_Space # Until_Condition None Until_Log_File Until_Log_Pos 0 @@ -154,8 +154,8 @@ Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File Read_Master_Log_Pos 4 -Relay_Log_File slave-relay-bin.000001 -Relay_Log_Pos 4 +Relay_Log_File # +Relay_Log_Pos # Relay_Master_Log_File Slave_IO_Running No Slave_SQL_Running No @@ -169,7 +169,7 @@ Last_Errno 0 Last_Error Skip_Counter 0 Exec_Master_Log_Pos 0 -Relay_Log_Space 4 +Relay_Log_Space # Until_Condition None Until_Log_File Until_Log_Pos 0 @@ -195,8 +195,8 @@ Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 Read_Master_Log_Pos 50535 -Relay_Log_File slave-relay-bin.000009 -Relay_Log_Pos 62 +Relay_Log_File # +Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 Slave_IO_Running Yes Slave_SQL_Running Yes @@ -210,7 +210,7 @@ Last_Errno 0 Last_Error Skip_Counter 0 Exec_Master_Log_Pos 50535 -Relay_Log_Space 62 +Relay_Log_Space # Until_Condition None Until_Log_File Until_Log_Pos 0 @@ -234,8 +234,8 @@ Master_Port MASTER_PORT Connect_Retry 1 Master_Log_File master-bin.000001 Read_Master_Log_Pos 50583 -Relay_Log_File slave-relay-bin.000010 -Relay_Log_Pos 52 +Relay_Log_File # +Relay_Log_Pos # Relay_Master_Log_File master-bin.000001 Slave_IO_Running Yes Slave_SQL_Running Yes @@ -249,7 +249,7 @@ Last_Errno 0 Last_Error Skip_Counter 0 Exec_Master_Log_Pos 50583 -Relay_Log_Space 52 +Relay_Log_Space # Until_Condition None Until_Log_File Until_Log_Pos 0 diff --git a/mysql-test/r/rpl_replicate_do.result b/mysql-test/r/rpl_replicate_do.result index 45ef6cb9b7b..b9294c9c767 100644 --- a/mysql-test/r/rpl_replicate_do.result +++ b/mysql-test/r/rpl_replicate_do.result @@ -28,7 +28,7 @@ ERROR 42S02: Table 'test.t11' doesn't exist drop table if exists t1,t2,t11; show slave status; Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master -# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1340 slave-relay-bin.000002 1384 master-bin.000001 Yes Yes test.t1 0 0 1340 1384 None 0 No # +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1340 # # master-bin.000001 Yes Yes test.t1 0 0 1340 # None 0 No # create table t1 (ts timestamp); set one_shot time_zone='met'; insert into t1 values('2005-08-12 00:00:00'); diff --git a/mysql-test/t/lowercase_table3.test b/mysql-test/t/lowercase_table3.test index 549bd7d8045..bf48710d4a6 100644 --- a/mysql-test/t/lowercase_table3.test +++ b/mysql-test/t/lowercase_table3.test @@ -5,12 +5,8 @@ # --source include/have_innodb.inc ---require r/lowercase0.require -disable_query_log; -show variables like "lower_case_%"; ---require r/true.require -select convert(@@version_compile_os using latin1) NOT IN ("NT","WIN2000","Win95/Win98","XP") as "TRUE"; -enable_query_log; +--source include/have_lowercase0.inc +--source include/not_windows.inc --disable_warnings DROP TABLE IF EXISTS t1,T1; diff --git a/mysql-test/t/mysql_protocols.test b/mysql-test/t/mysql_protocols.test index 0253c2b5d17..5eba780420c 100644 --- a/mysql-test/t/mysql_protocols.test +++ b/mysql-test/t/mysql_protocols.test @@ -1,5 +1,7 @@ # Embedded server doesn't support external clients --source include/not_embedded.inc +# Windows does not have SOCKET, but will try to create a PIPE as well as MEMORY +--source include/not_windows.inc # test for Bug #4998 "--protocol doesn't reject bad values" diff --git a/mysql-test/t/rpl000015.test b/mysql-test/t/rpl000015.test index a9520676e1e..4e329fc87ea 100644 --- a/mysql-test/t/rpl000015.test +++ b/mysql-test/t/rpl000015.test @@ -7,24 +7,24 @@ save_master_pos; connection slave; reset slave; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # show slave status; change master to master_host='127.0.0.1'; # The following needs to be cleaned up when change master is fixed --replace_result $MASTER_MYPORT MASTER_PORT $MYSQL_TCP_PORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # show slave status; --replace_result $MASTER_MYPORT MASTER_PORT eval change master to master_host='127.0.0.1',master_user='root', master_password='',master_port=$MASTER_MYPORT; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # show slave status; start slave; sync_with_master; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # show slave status; connection master; --disable_warnings diff --git a/mysql-test/t/rpl_change_master.test b/mysql-test/t/rpl_change_master.test index befc469e7b5..e7ae798b1a7 100644 --- a/mysql-test/t/rpl_change_master.test +++ b/mysql-test/t/rpl_change_master.test @@ -12,11 +12,12 @@ connection slave; stop slave; select * from t1; --replace_result $MASTER_MYPORT MASTER_MYPORT +--replace_column 1 # 8 # 9 # 23 # 33 # --replace_column 1 # 33 # show slave status; change master to master_user='root'; --replace_result $MASTER_MYPORT MASTER_MYPORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # show slave status; # Will restart from after the values(2), which is bug select release_lock("a"); diff --git a/mysql-test/t/rpl_drop_db.test b/mysql-test/t/rpl_drop_db.test index 61354198c83..98afc6e3d02 100644 --- a/mysql-test/t/rpl_drop_db.test +++ b/mysql-test/t/rpl_drop_db.test @@ -13,6 +13,7 @@ insert into mysqltest1.t1 values (1); select * from mysqltest1.t1 into outfile 'mysqltest1/f1.txt'; create table mysqltest1.t2 (n int); create table mysqltest1.t3 (n int); +--replace_result \\ / --error 1010 drop database mysqltest1; use mysqltest1; @@ -29,6 +30,7 @@ while ($1) } --enable_query_log +--replace_result \\ / --error 1010 drop database mysqltest1; use mysqltest1; diff --git a/mysql-test/t/rpl_error_ignored_table.test b/mysql-test/t/rpl_error_ignored_table.test index 96900697d5b..8076d835ac0 100644 --- a/mysql-test/t/rpl_error_ignored_table.test +++ b/mysql-test/t/rpl_error_ignored_table.test @@ -15,7 +15,7 @@ sync_with_master; # The port number is different when doing the release build with # Do-compile, hence we have to replace the port number here accordingly --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # show slave status; # check that the table has been ignored, because otherwise the test is nonsense show tables like 't1'; diff --git a/mysql-test/t/rpl_loaddata.test b/mysql-test/t/rpl_loaddata.test index 21515080ca2..65855dd3ceb 100644 --- a/mysql-test/t/rpl_loaddata.test +++ b/mysql-test/t/rpl_loaddata.test @@ -72,7 +72,7 @@ set global sql_slave_skip_counter=1; start slave; sync_with_master; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # show slave status; # Trigger error again to test CHANGE MASTER @@ -92,7 +92,7 @@ stop slave; change master to master_user='test'; change master to master_user='root'; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # show slave status; # Trigger error again to test RESET SLAVE @@ -114,7 +114,7 @@ wait_for_slave_to_stop; stop slave; reset slave; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # show slave status; # Finally, see if logging is done ok on master for a failing LOAD DATA INFILE diff --git a/mysql-test/t/rpl_log-master.opt b/mysql-test/t/rpl_log-master.opt index e0d075c3fbd..cef79bc8585 100644 --- a/mysql-test/t/rpl_log-master.opt +++ b/mysql-test/t/rpl_log-master.opt @@ -1 +1 @@ ---skip-external-locking +--force-restart diff --git a/mysql-test/t/rpl_log.test b/mysql-test/t/rpl_log.test index 08aa3b28850..40fc36cad4a 100644 --- a/mysql-test/t/rpl_log.test +++ b/mysql-test/t/rpl_log.test @@ -94,7 +94,7 @@ show binlog events in 'slave-bin.000001' from 4; --replace_result $MASTER_MYPORT MASTER_PORT $VERSION VERSION show binlog events in 'slave-bin.000002' from 4; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # show slave status; # Need to recode the following diff --git a/mysql-test/t/rpl_max_relay_size.test b/mysql-test/t/rpl_max_relay_size.test index 63d7ef35413..003f60df28f 100644 --- a/mysql-test/t/rpl_max_relay_size.test +++ b/mysql-test/t/rpl_max_relay_size.test @@ -38,7 +38,7 @@ select @@global.max_relay_log_size; start slave; sync_with_master; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # --vertical_results show slave status; @@ -53,7 +53,7 @@ select @@global.max_relay_log_size; start slave; sync_with_master; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # --vertical_results show slave status; @@ -68,7 +68,7 @@ select @@global.max_relay_log_size; start slave; sync_with_master; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # --vertical_results show slave status; @@ -82,7 +82,7 @@ reset slave; # (to make sure it does not crash). flush logs; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # --vertical_results show slave status; @@ -103,7 +103,7 @@ save_master_pos; connection slave; sync_with_master; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # --vertical_results show slave status; @@ -118,7 +118,7 @@ save_master_pos; connection slave; sync_with_master; --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # --vertical_results show slave status; diff --git a/mysql-test/t/rpl_replicate_do.test b/mysql-test/t/rpl_replicate_do.test index 9bbaa9f0076..b8559af2394 100644 --- a/mysql-test/t/rpl_replicate_do.test +++ b/mysql-test/t/rpl_replicate_do.test @@ -33,7 +33,7 @@ connection slave; sync_with_master; # show slave status, just to see of it prints replicate-do-table --replace_result $MASTER_MYPORT MASTER_PORT ---replace_column 1 # 33 # +--replace_column 1 # 8 # 9 # 23 # 33 # show slave status; # From 102d36b7f6401d30049aca925020ab272d5b4d65 Mon Sep 17 00:00:00 2001 From: "andrey@example.com" <> Date: Thu, 19 Oct 2006 11:37:07 +0200 Subject: [PATCH 100/131] Fix for bug#23379 "wrong time value in SHOW PROCESSLIST" The value taken to be shown in SHOW PROCESSLIST is not initialized when THD is created and will be random for unauthenticated connections. To the documentor: Random value, instead of NULL, was shown, in SHOW PROCESSLIST for still non-authenticated connections. --- sql/sql_class.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index bd292814bfa..fc9597cba87 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -181,6 +181,7 @@ THD::THD() // Must be reset to handle error with THD's created for init of mysqld lex->current_select= 0; start_time=(time_t) 0; + time_after_lock=(time_t) 0; current_linfo = 0; slave_thread = 0; variables.pseudo_thread_id= 0; From 9a5b4a115100086815267c51ba12998b9e5e7d19 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 19 Oct 2006 13:34:09 +0200 Subject: [PATCH 101/131] Add command "exit" to mysqltest, it will stop processing any more commands and go directly to result file processing --- client/mysqltest.c | 13 ++++++++++--- mysql-test/r/mysqltest.result | 2 ++ mysql-test/t/mysqltest.test | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index efb5f1915f4..5bc132a874f 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -264,7 +264,7 @@ enum enum_commands { Q_IF, Q_DISABLE_PARSING, Q_ENABLE_PARSING, Q_REPLACE_REGEX, Q_REMOVE_FILE, Q_FILE_EXIST, - Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, + Q_WRITE_FILE, Q_COPY_FILE, Q_PERL, Q_DIE, Q_EXIT, Q_UNKNOWN, /* Unknown command. */ Q_COMMENT, /* Comments, ignored. */ @@ -345,6 +345,8 @@ const char *command_names[]= "copy_file", "perl", "die", + /* Don't execute any more commands, compare result */ + "exit", 0 }; @@ -5429,7 +5431,7 @@ void mark_progress(struct st_command* command __attribute__((unused)), int main(int argc, char **argv) { struct st_command *command; - my_bool q_send_flag= 0; + my_bool q_send_flag= 0, abort_flag= 0; uint command_executed= 0, last_command_executed= 0; char save_file[FN_REFLEN]; MY_STAT res_info; @@ -5549,7 +5551,7 @@ int main(int argc, char **argv) open_file(opt_include); } - while (!read_command(&command)) + while (!read_command(&command) && !abort_flag) { int current_line_inc = 1, processed = 0; if (command->type == Q_UNKNOWN || command->type == Q_COMMENT_WITH_COMMAND) @@ -5777,8 +5779,13 @@ int main(int argc, char **argv) die("Parsing is already enabled"); break; case Q_DIE: + /* Abort test with error code and error message */ die("%s", command->first_argument); break; + case Q_EXIT: + /* Stop processing any more commands */ + abort_flag= 1; + break; case Q_RESULT: die("result, deprecated command"); diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result index ed7267fb71d..a63863977b0 100644 --- a/mysql-test/r/mysqltest.result +++ b/mysql-test/r/mysqltest.result @@ -518,4 +518,6 @@ hello mysqltest: At line 1: Max delimiter length(16) exceeded hello hello +mysqltest: At line 1: test of die +Some output End of tests diff --git a/mysql-test/t/mysqltest.test b/mysql-test/t/mysqltest.test index d98375ca746..3c20b38722f 100644 --- a/mysql-test/t/mysqltest.test +++ b/mysql-test/t/mysqltest.test @@ -1548,5 +1548,19 @@ perl; print "hello\n"; EOF +# ---------------------------------------------------------------------------- +# test for die +# ---------------------------------------------------------------------------- + +--error 1 +--exec echo "die test of die;" | $MYSQL_TEST 2>&1 + + +# ---------------------------------------------------------------------------- +# test for exit +# ---------------------------------------------------------------------------- + +--exec echo "echo Some output; exit; echo Not this;" | $MYSQL_TEST 2>&1 + --echo End of tests From c950eee2175ddb94b6e7bab3cc0ae847aa2e511d Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 19 Oct 2006 20:29:33 +0200 Subject: [PATCH 102/131] Fix problem running rpl_timezone on powermacg5, it was not popular to set TZ to "" so now it's set to a value wich is not our default --- mysql-test/lib/mtr_cases.pl | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 88c51728fb2..7a01c66305b 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -263,9 +263,6 @@ sub collect_one_test_case($$$$$$$) { return; } - # ---------------------------------------------------------------------- - # Skip some tests but include in list, just mark them to skip - # ---------------------------------------------------------------------- my $tinfo= {}; $tinfo->{'name'}= $tname; @@ -273,6 +270,10 @@ sub collect_one_test_case($$$$$$$) { $tinfo->{'component_id'} = $component_id; push(@$cases, $tinfo); + # ---------------------------------------------------------------------- + # Skip some tests but include in list, just mark them to skip + # ---------------------------------------------------------------------- + if ( $::opt_skip_test and defined mtr_match_prefix($tname,$::opt_skip_test) ) { $tinfo->{'skip'}= 1; @@ -356,8 +357,9 @@ sub collect_one_test_case($$$$$$$) { $value= mtr_match_prefix($opt, "--default-time-zone="); if ( defined $value ) { - $tinfo->{'timezone'}= ""; - # Fallthrough, add this option + # Set timezone for this test case to something different + $tinfo->{'timezone'}= "GMT-8"; + # Fallthrough, add the --default-time-zone option } # The --restart option forces a restart even if no special From c4a570aa0018f837909a19ee8ee87720de3cf749 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Thu, 19 Oct 2006 20:33:32 +0200 Subject: [PATCH 103/131] Adapt to running from "binary dist" Add function mtr_exe_maybe_exists to look for binaries that is optional Skip ndb support if it's a binary dist where mysqld supports ndb but there is no ndbd --- mysql-test/lib/mtr_misc.pl | 14 +++++++- mysql-test/mysql-test-run.pl | 66 ++++++++++++++++++------------------ 2 files changed, 46 insertions(+), 34 deletions(-) diff --git a/mysql-test/lib/mtr_misc.pl b/mysql-test/lib/mtr_misc.pl index dd9d24ebc8e..5ac89aee62c 100644 --- a/mysql-test/lib/mtr_misc.pl +++ b/mysql-test/lib/mtr_misc.pl @@ -14,6 +14,7 @@ sub mtr_path_exists(@); sub mtr_script_exists(@); sub mtr_file_exists(@); sub mtr_exe_exists(@); +sub mtr_exe_maybe_exists(@); sub mtr_copy_dir($$); sub mtr_same_opts($$); sub mtr_cmp_opts($$); @@ -110,8 +111,9 @@ sub mtr_file_exists (@) { return ""; } -sub mtr_exe_exists (@) { +sub mtr_exe_maybe_exists (@) { my @path= @_; + map {$_.= ".exe"} @path if $::glob_win32; foreach my $path ( @path ) { @@ -124,6 +126,16 @@ sub mtr_exe_exists (@) { return $path if -x $path; } } + return ""; +} + +sub mtr_exe_exists (@) { + my @path= @_; + if (my $path= mtr_exe_maybe_exists(@path)) + { + return $path; + } + # Could not find exe, show error if ( @path == 1 ) { mtr_error("Could not find $path[0]"); diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index daa5b8aca96..286bb8a11c5 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1313,9 +1313,8 @@ sub executable_setup () { } # Look for language files and charsetsdir, use same share - my $path_share= mtr_path_exists("$glob_basedir/share", + my $path_share= mtr_path_exists("$glob_basedir/share/mysql", "$glob_basedir/sql/share", - "$glob_basedir/share/mysql", "$glob_basedir/share"); $path_language= mtr_path_exists("$path_share/english"); @@ -1373,31 +1372,31 @@ sub executable_setup () { { # Look for ndb tols and binaries my $ndb_path= mtr_path_exists("$glob_basedir/ndb", - "$glob_basedir/storage/ndb"); + "$glob_basedir/storage/ndb", + "$glob_basedir/bin"); $path_ndb_tools_dir= mtr_path_exists("$ndb_path/tools", - "$glob_basedir/bin"); + "$ndb_path"); $exe_ndb_mgm= mtr_exe_exists("$ndb_path/src/mgmclient/ndb_mgm", - "$glob_basedir/bin/ndb_mgm"); + "$ndb_path/ndb_mgm"); $exe_ndb_mgmd= mtr_exe_exists("$ndb_path/src/mgmsrv/ndb_mgmd", - "$glob_basedir/bin/ndb_mgmd"); + "$ndb_path/ndb_mgmd"); $exe_ndb_waiter= mtr_exe_exists("$ndb_path/tools/ndb_waiter", - "$glob_basedir/bin/ndb_waiter"); + "$ndb_path/ndb_waiter"); $exe_ndbd= mtr_exe_exists("$ndb_path/src/kernel/ndbd", - "$glob_basedir/bin/ndbd"); + "$ndb_path/ndbd"); - if ( $mysql_version_id >= 50000 ) - { - $path_ndb_examples_dir= - mtr_path_exists("$ndb_path/ndbapi-examples", - "$ndb_path/examples"); - $exe_ndb_example= - mtr_file_exists("$path_ndb_examples_dir/ndbapi_simple/ndbapi_simple"); - } + # May not exist + $path_ndb_examples_dir= + mtr_file_exists("$ndb_path/ndbapi-examples", + "$ndb_path/examples"); + # May not exist + $exe_ndb_example= + mtr_file_exists("$path_ndb_examples_dir/ndbapi_simple/ndbapi_simple"); } # Look for the udf_example library @@ -1420,27 +1419,20 @@ sub executable_setup () { } - if ( $glob_win32 and $mysql_version_id < 50000 ) + # Look for mysql_client_test executable which may _not_ exist in + # some versions, test using it should be skipped + if ( $glob_use_embedded_server ) { - # Skip looking for exe_mysql_client_test as its not built by default - # in 4.1 for windows. - $exe_mysql_client_test= "unavailable"; + $exe_mysql_client_test= + mtr_exe_maybe_exists("$glob_basedir/libmysqld/examples/mysql_client_test_embedded"); } else { - # Look for mysql_client_test executable - if ( $glob_use_embedded_server ) - { - $exe_mysql_client_test= - mtr_exe_exists("$glob_basedir/libmysqld/examples/mysql_client_test_embedded"); - } - else - { - $exe_mysql_client_test= - mtr_exe_exists("$glob_basedir/tests/mysql_client_test", - "$glob_basedir/tests/release/mysql_client_test", - "$glob_basedir/tests/debug/mysql_client_test"); - } + $exe_mysql_client_test= + mtr_exe_maybe_exists("$glob_basedir/tests/mysql_client_test", + "$glob_basedir/tests/release/mysql_client_test", + "$glob_basedir/tests/debug/mysql_client_test", + "$glob_basedir/bin"); } } @@ -2045,6 +2037,14 @@ sub check_ndbcluster_support ($) { $opt_skip_ndbcluster_slave= 1; return; } + elsif ( -e "$glob_basedir/bin" && ! -f "$glob_basedir/bin/ndbd") + { + # Binary dist with a mysqld that supports ndb, but no ndbd found + mtr_report("Skipping ndbcluster, can't fint binaries"); + $opt_skip_ndbcluster= 1; + $opt_skip_ndbcluster_slave= 1; + return; + } $glob_ndbcluster_supported= 1; mtr_report("Using ndbcluster when necessary, mysqld supports it"); From 4d93069773089c0a58ba01b6f4fde753c65ed0a6 Mon Sep 17 00:00:00 2001 From: "kaa@polly.local" <> Date: Fri, 20 Oct 2006 14:31:47 +0400 Subject: [PATCH 104/131] Fix for bug #23256 "doesn't build on alpha" - compilation on the Alpha platform was broken because the Alpha-specific code was not updated after replacing the SIGRETURN_FRAME_COUNT constant with a variable --- sql/stacktrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/stacktrace.c b/sql/stacktrace.c index 43f35c452f7..1b8267763a0 100644 --- a/sql/stacktrace.c +++ b/sql/stacktrace.c @@ -186,7 +186,7 @@ terribly wrong...\n"); #if defined(__alpha__) && defined(__GNUC__) uchar** new_fp = find_prev_fp(pc, fp); - if (frame_count == SIGRETURN_FRAME_COUNT - 1) + if (frame_count == sigreturn_frame_count - 1) { new_fp += 90; } From 125163c03b40f5ca2526f69a030c90760add53c5 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 20 Oct 2006 17:09:07 +0200 Subject: [PATCH 105/131] Init some variables that changes between test cases direclty in run_testcase This can not be done in run_testcase_start_servers as embedded never starts a server Add error if mysqld_start is called in embedded mode --- mysql-test/mysql-test-run.pl | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 286bb8a11c5..7dac63b5373 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2880,6 +2880,13 @@ sub find_testcase_skipped_reason($) sub run_testcase ($) { my $tinfo= shift; + # ------------------------------------------------------- + # Init variables that can change between each test case + # ------------------------------------------------------- + + $ENV{'TZ'}= $tinfo->{'timezone'}; + mtr_verbose("Starting server with timezone: $tinfo->{'timezone'}"); + my $master_restart= run_testcase_need_master_restart($tinfo); my $slave_restart= run_testcase_need_slave_restart($tinfo); @@ -3409,6 +3416,9 @@ sub mysqld_start ($$$) { my $type= $mysqld->{'type'}; my $idx= $mysqld->{'idx'}; + mtr_error("Internal error: mysqld should never be started for embedded") + if $glob_use_embedded_server; + if ( $type eq 'master' ) { $exe= $exe_master_mysqld; @@ -3849,12 +3859,6 @@ sub run_testcase_start_servers($) { my $tinfo= shift; my $tname= $tinfo->{'name'}; - # ------------------------------------------------------- - # Init variables that can change between server starts - # ------------------------------------------------------- - $ENV{'TZ'}= $tinfo->{'timezone'}; - mtr_verbose("Starting server with timezone: $tinfo->{'timezone'}"); - if ( $tinfo->{'component_id'} eq 'mysqld' ) { if ( ! $opt_skip_ndbcluster and From 2459dd55f579fd627f7f37da3b9fe3e0269334c0 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Mon, 23 Oct 2006 10:56:13 +0200 Subject: [PATCH 106/131] Copy *.cnf file from std_data/ when doing a binary distribution --- scripts/make_binary_distribution.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/make_binary_distribution.sh b/scripts/make_binary_distribution.sh index b2eb9f3b727..d05c4427627 100644 --- a/scripts/make_binary_distribution.sh +++ b/scripts/make_binary_distribution.sh @@ -225,6 +225,7 @@ $CP mysql-test/lib/*.sql $BASE/mysql-test/lib $CP mysql-test/t/*.def $BASE/mysql-test/t $CP mysql-test/include/*.inc $BASE/mysql-test/include $CP mysql-test/std_data/*.dat mysql-test/std_data/*.*001 \ + mysql-test/std_data/*.cnf \ $BASE/mysql-test/std_data $CP mysql-test/std_data/des_key_file $BASE/mysql-test/std_data $CP mysql-test/t/*test mysql-test/t/*.opt mysql-test/t/*.slave-mi \ From 962fe847848d19e67382385b5407be569bcdaf37 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Mon, 23 Oct 2006 12:02:56 +0200 Subject: [PATCH 107/131] As both ndb and im are components that may be disabled as well as the binaries may not exist. Look for their binaries in a separate function and produce test casea failures for the test thet needs these components --- mysql-test/mysql-test-run.pl | 178 ++++++++++++++++++++++------------- 1 file changed, 115 insertions(+), 63 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 7dac63b5373..acba4d843dd 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1295,6 +1295,54 @@ sub collect_mysqld_features () { } +sub executable_setup_im () { + + # Look for instance manager binary - mysqlmanager + $exe_im= + mtr_exe_maybe_exists( + "$glob_basedir/server-tools/instance-manager/mysqlmanager", + "$glob_basedir/libexec/mysqlmanager"); + + return ($exe_im eq ""); +} + +sub executable_setup_ndb () { + + # Look for ndb tols and binaries + my $ndb_path= mtr_file_exists("$glob_basedir/ndb", + "$glob_basedir/storage/ndb", + "$glob_basedir/bin"); + + $exe_ndbd= + mtr_exe_maybe_exists("$ndb_path/src/kernel/ndbd", + "$ndb_path/ndbd"); + $exe_ndb_mgm= + mtr_exe_maybe_exists("$ndb_path/src/mgmclient/ndb_mgm", + "$ndb_path/ndb_mgm"); + $exe_ndb_mgmd= + mtr_exe_maybe_exists("$ndb_path/src/mgmsrv/ndb_mgmd", + "$ndb_path/ndb_mgmd"); + $exe_ndb_waiter= + mtr_exe_maybe_exists("$ndb_path/tools/ndb_waiter", + "$ndb_path/ndb_waiter"); + + # May not exist + $path_ndb_tools_dir= mtr_file_exists("$ndb_path/tools", + "$ndb_path"); + # May not exist + $path_ndb_examples_dir= + mtr_file_exists("$ndb_path/ndbapi-examples", + "$ndb_path/examples"); + # May not exist + $exe_ndb_example= + mtr_file_exists("$path_ndb_examples_dir/ndbapi_simple/ndbapi_simple"); + + return ( $exe_ndbd eq "" or + $exe_ndb_mgm eq "" or + $exe_ndb_mgmd eq "" or + $exe_ndb_waiter eq ""); +} + sub executable_setup () { # @@ -1333,20 +1381,6 @@ sub executable_setup () { "$glob_basedir/extra/release/perror", "$glob_basedir/extra/debug/perror"); - - if ( ! $opt_skip_im ) - { - # Look for instance manager binary - mysqlmanager - $exe_im= - mtr_exe_exists( - "$glob_basedir/server-tools/instance-manager/mysqlmanager", - "$glob_basedir/libexec/mysqlmanager"); - } - else - { - $exe_im= "not_available"; - } - # Look for the client binaries $exe_mysqlcheck= mtr_exe_exists("$path_client_bindir/mysqlcheck"); $exe_mysqldump= mtr_exe_exists("$path_client_bindir/mysqldump"); @@ -1368,35 +1402,25 @@ sub executable_setup () { "$path_client_bindir/mysql_fix_privilege_tables"); } - if ( ! $opt_skip_ndbcluster) + + if ( ! $opt_skip_ndbcluster and executable_setup_ndb()) { - # Look for ndb tols and binaries - my $ndb_path= mtr_path_exists("$glob_basedir/ndb", - "$glob_basedir/storage/ndb", - "$glob_basedir/bin"); + mtr_warning("Could not find all required ndb binaries, " . + "all ndb tests will fail, use --skip-ndbcluster to " . + "skip testing it."); - $path_ndb_tools_dir= mtr_path_exists("$ndb_path/tools", - "$ndb_path"); - $exe_ndb_mgm= - mtr_exe_exists("$ndb_path/src/mgmclient/ndb_mgm", - "$ndb_path/ndb_mgm"); - $exe_ndb_mgmd= - mtr_exe_exists("$ndb_path/src/mgmsrv/ndb_mgmd", - "$ndb_path/ndb_mgmd"); - $exe_ndb_waiter= - mtr_exe_exists("$ndb_path/tools/ndb_waiter", - "$ndb_path/ndb_waiter"); - $exe_ndbd= - mtr_exe_exists("$ndb_path/src/kernel/ndbd", - "$ndb_path/ndbd"); + foreach my $cluster (@{$clusters}) + { + $cluster->{"executable_setup_failed"}= 1; + } + } - # May not exist - $path_ndb_examples_dir= - mtr_file_exists("$ndb_path/ndbapi-examples", - "$ndb_path/examples"); - # May not exist - $exe_ndb_example= - mtr_file_exists("$path_ndb_examples_dir/ndbapi_simple/ndbapi_simple"); + if ( ! $opt_skip_im and executable_setup_im()) + { + mtr_warning("Could not find all required instance manager binaries, " . + "all im tests will fail, use --skip-im to " . + "continue without instance manager"); + $instance_manager->{"executable_setup_failed"}= 1; } # Look for the udf_example library @@ -1424,7 +1448,8 @@ sub executable_setup () { if ( $glob_use_embedded_server ) { $exe_mysql_client_test= - mtr_exe_maybe_exists("$glob_basedir/libmysqld/examples/mysql_client_test_embedded"); + mtr_exe_maybe_exists( + "$glob_basedir/libmysqld/examples/mysql_client_test_embedded"); } else { @@ -1567,19 +1592,28 @@ sub environment_setup () { # ---------------------------------------------------- # Setup env for IM # ---------------------------------------------------- - $ENV{'IM_EXE'}= $exe_im; - $ENV{'IM_PATH_PID'}= $instance_manager->{path_pid}; - $ENV{'IM_PATH_ANGEL_PID'}= $instance_manager->{path_angel_pid}; - $ENV{'IM_PORT'}= $instance_manager->{port}; - $ENV{'IM_DEFAULTS_PATH'}= $instance_manager->{defaults_file}; - $ENV{'IM_PASSWORD_PATH'}= $instance_manager->{password_file}; + if ( ! $opt_skip_im ) + { + $ENV{'IM_EXE'}= $exe_im; + $ENV{'IM_PATH_PID'}= $instance_manager->{path_pid}; + $ENV{'IM_PATH_ANGEL_PID'}= $instance_manager->{path_angel_pid}; + $ENV{'IM_PORT'}= $instance_manager->{port}; + $ENV{'IM_DEFAULTS_PATH'}= $instance_manager->{defaults_file}; + $ENV{'IM_PASSWORD_PATH'}= $instance_manager->{password_file}; - $ENV{'IM_MYSQLD1_SOCK'}= $instance_manager->{instances}->[0]->{path_sock}; - $ENV{'IM_MYSQLD1_PORT'}= $instance_manager->{instances}->[0]->{port}; - $ENV{'IM_MYSQLD1_PATH_PID'}=$instance_manager->{instances}->[0]->{path_pid}; - $ENV{'IM_MYSQLD2_SOCK'}= $instance_manager->{instances}->[1]->{path_sock}; - $ENV{'IM_MYSQLD2_PORT'}= $instance_manager->{instances}->[1]->{port}; - $ENV{'IM_MYSQLD2_PATH_PID'}=$instance_manager->{instances}->[1]->{path_pid}; + $ENV{'IM_MYSQLD1_SOCK'}= + $instance_manager->{instances}->[0]->{path_sock}; + $ENV{'IM_MYSQLD1_PORT'}= + $instance_manager->{instances}->[0]->{port}; + $ENV{'IM_MYSQLD1_PATH_PID'}= + $instance_manager->{instances}->[0]->{path_pid}; + $ENV{'IM_MYSQLD2_SOCK'}= + $instance_manager->{instances}->[1]->{path_sock}; + $ENV{'IM_MYSQLD2_PORT'}= + $instance_manager->{instances}->[1]->{port}; + $ENV{'IM_MYSQLD2_PATH_PID'}= + $instance_manager->{instances}->[1]->{path_pid}; + } # ---------------------------------------------------- # Setup env so childs can execute mysqlcheck @@ -2037,14 +2071,6 @@ sub check_ndbcluster_support ($) { $opt_skip_ndbcluster_slave= 1; return; } - elsif ( -e "$glob_basedir/bin" && ! -f "$glob_basedir/bin/ndbd") - { - # Binary dist with a mysqld that supports ndb, but no ndbd found - mtr_report("Skipping ndbcluster, can't fint binaries"); - $opt_skip_ndbcluster= 1; - $opt_skip_ndbcluster_slave= 1; - return; - } $glob_ndbcluster_supported= 1; mtr_report("Using ndbcluster when necessary, mysqld supports it"); @@ -2475,7 +2501,8 @@ sub mysql_install_db () { my $cluster_started_ok= 1; # Assume it can be started - if ($opt_skip_ndbcluster || $glob_use_running_ndbcluster) + if ($opt_skip_ndbcluster || $glob_use_running_ndbcluster || + $clusters->[0]->{executable_setup_failed}) { # Don't install master cluster } @@ -2486,7 +2513,8 @@ sub mysql_install_db () { } if ($max_slave_num == 0 || - $opt_skip_ndbcluster_slave || $glob_use_running_ndbcluster_slave) + $opt_skip_ndbcluster_slave || $glob_use_running_ndbcluster_slave || + $clusters->[1]->{executable_setup_failed}) { # Don't install slave cluster } @@ -2760,6 +2788,16 @@ sub run_testcase_check_skip_test($) last if ($opt_skip_ndbcluster_slave and $cluster->{'name'} eq 'Slave'); + # If test needs this cluster, check binaries was found ok + if ( $cluster->{'executable_setup_failed'} ) + { + mtr_report_test_name($tinfo); + $tinfo->{comment}= + "Failed to find cluster binaries"; + mtr_report_test_failed($tinfo); + return 1; + } + # If test needs this cluster, check it was installed ok if ( !$cluster->{'installed_ok'} ) { @@ -2769,6 +2807,20 @@ sub run_testcase_check_skip_test($) mtr_report_test_failed($tinfo); return 1; } + + } + } + + if ( $tinfo->{'component_id'} eq 'im' ) + { + # If test needs im, check binaries was found ok + if ( $instance_manager->{'executable_setup_failed'} ) + { + mtr_report_test_name($tinfo); + $tinfo->{comment}= + "Failed to find MySQL manager binaries"; + mtr_report_test_failed($tinfo); + return 1; } } From 43aa130a388f9a683d9476ddf2cfd910777f96e0 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Mon, 23 Oct 2006 12:16:40 +0200 Subject: [PATCH 108/131] If "var" is a symlink which does not point to anything, remove it before creating real var --- mysql-test/mysql-test-run.pl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index acba4d843dd..f429bac850d 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1868,6 +1868,11 @@ sub kill_running_servers () { if ( ! -d $opt_vardir ) { + if ( -l $opt_vardir and ! -d readlink($opt_vardir) ) + { + mtr_report("Removing $opt_vardir symlink without destination"); + unlink($opt_vardir); + } # The "var" dir does not exist already # the processes that mtr_kill_leftovers start will write # their log files to var/log so it should be created From 6b5ec539625276fc5ae8be67966646efe779a6c6 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Mon, 23 Oct 2006 13:32:20 +0200 Subject: [PATCH 109/131] Don't use the "4.1 vardir trick" on OS that does not have native symlink(i.e windows) --- mysql-test/mysql-test-run.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index f429bac850d..c36a06f56ef 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -758,7 +758,8 @@ sub command_line_setup () { $opt_vardir= $default_vardir; } elsif ( $mysql_version_id < 50000 and - $opt_vardir ne $default_vardir ) + ! $glob_win32 and # No supported on platforms without native symlink + $opt_vardir ne $default_vardir) { # Version 4.1 and --vardir was specified # Only supported as a symlink from var/ From 792adb7ce39c1e3c3b9cc2a7bffad0d364211da1 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Mon, 23 Oct 2006 16:51:48 +0200 Subject: [PATCH 110/131] The vardir trick can only bge used on platforms with native symlinks - otherwise opt_vardir need to be set to default value. --- mysql-test/mysql-test-run.pl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index c36a06f56ef..84d84cf8f14 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -758,15 +758,19 @@ sub command_line_setup () { $opt_vardir= $default_vardir; } elsif ( $mysql_version_id < 50000 and - ! $glob_win32 and # No supported on platforms without native symlink $opt_vardir ne $default_vardir) { # Version 4.1 and --vardir was specified # Only supported as a symlink from var/ # by setting up $opt_mem that symlink will be created - $opt_mem= $opt_vardir; + if ( ! $glob_win32 ) + { + # Only platforms that have native symlinks can use the vardir trick + $opt_mem= $opt_vardir; + mtr_report("Using 4.1 vardir trick"); + } + $opt_vardir= $default_vardir; - mtr_report("Using 4.1 vardir trick"); } $path_vardir_trace= $opt_vardir; From e4df2aac0754a3d58cf9a2f7dff3064bca819654 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Mon, 23 Oct 2006 20:36:44 +0200 Subject: [PATCH 111/131] Avoid matching the trailing carriage return when parsing the mysqld.spec file This fixes problem where --replace_result failed in rpl000015 because the MYSQL_TCP_PORT variable was "3306\r" --- mysql-test/mysql-test-run.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 84d84cf8f14..7f1f7a43b10 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1269,9 +1269,9 @@ sub collect_mysqld_features () { else { # Put variables into hash - if ( $line =~ /^([\S]+)[ \t]+(.*)$/ ) + if ( $line =~ /^([\S]+)[ \t]+(.*?)\r?$/ ) { - # print "$1=$2\n"; + # print "$1=\"$2\"\n"; $mysqld_variables{$1}= $2; } else From c972edc663c46272e78d2959a41c0b3a2cbadcaa Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 24 Oct 2006 13:34:10 +0200 Subject: [PATCH 112/131] Enable the ATTRIBUTE_FORMAT macros to check format of variable arg parameters --- client/mysqltest.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 5bc132a874f..9f41586afae 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -398,13 +398,13 @@ TYPELIB command_typelib= {array_elements(command_names),"", DYNAMIC_STRING ds_res, ds_progress, ds_warning_messages; void die(const char *fmt, ...) - /* ATTRIBUTE_FORMAT(printf, 1, 2) */; + ATTRIBUTE_FORMAT(printf, 1, 2); void abort_not_supported_test(const char *fmt, ...) - /* ATTRIBUTE_FORMAT(printf, 1, 2) */; + ATTRIBUTE_FORMAT(printf, 1, 2); void verbose_msg(const char *fmt, ...) - /* ATTRIBUTE_FORMAT(printf, 1, 2) */; + ATTRIBUTE_FORMAT(printf, 1, 2); void warning_msg(const char *fmt, ...) - /* ATTRIBUTE_FORMAT(printf, 1, 2) */; + ATTRIBUTE_FORMAT(printf, 1, 2); VAR* var_from_env(const char *, const char *); VAR* var_init(VAR* v, const char *name, int name_len, const char *val, From 3df77e48af63b2854a739f90b489dc0adea038f1 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 24 Oct 2006 17:36:46 +0200 Subject: [PATCH 113/131] Add analyze_testcase_failure which is called when mysqltest has failed with error 1 and we are running with --force The specific "analyze" code is enclosed in a .test file fwich can easily be modified to be more advanced --- .../analyze_failure_sync_with_master.test | 15 +++++ mysql-test/mysql-test-run.pl | 56 +++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 mysql-test/include/analyze_failure_sync_with_master.test diff --git a/mysql-test/include/analyze_failure_sync_with_master.test b/mysql-test/include/analyze_failure_sync_with_master.test new file mode 100644 index 00000000000..e6fd32d2f46 --- /dev/null +++ b/mysql-test/include/analyze_failure_sync_with_master.test @@ -0,0 +1,15 @@ +# Connect to both master and slave +connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,); +connect (slave,127.0.0.1,root,,test,$SLAVE_MYPORT,); + +vertical_results; + +echo == MASTER ===========================================================; +connection master; +show master status; +show slave status; + +echo == SLAVE ===========================================================; +connection slave; +show master status; +show slave status; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 7f1f7a43b10..f88cd333b91 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2923,6 +2923,58 @@ sub find_testcase_skipped_reason($) } +sub analyze_testcase_failure_sync_with_master($) +{ + my ($tinfo)= @_; + mtr_verbose("analyze_testcase_failure_sync_with_master"); + print "analyze_testcase_failure_sync_with_master\n"; + + my $args; + mtr_init_args(\$args); + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--silent"); + mtr_add_arg($args, "-v"); + mtr_add_arg($args, "--skip-safemalloc"); + mtr_add_arg($args, "--tmpdir=%s", $opt_tmpdir); + + mtr_add_arg($args, "--socket=%s", $master->[0]->{'path_sock'}); + mtr_add_arg($args, "--port=%d", $master->[0]->{'port'}); + mtr_add_arg($args, "--database=test"); + mtr_add_arg($args, "--user=%s", $opt_user); + mtr_add_arg($args, "--password="); + + # Run the test file and append output to log file + mtr_run_test($exe_mysqltest,$args, + "include/analyze_failure_sync_with_master.test", + "$path_timefile", "$path_timefile","", + { append_log_file => 1 }); + +} + +sub analyze_testcase_failure($) +{ + my ($tinfo)= @_; + + # Open mysqltest.log + my $F= IO::File->new($path_timefile) or + mtr_error("can't open file \"$path_timefile\": $!"); + + while ( my $line= <$F> ) + { + # Look for "mysqltest: At line nnn: + if ( $line =~ /mysqltest: At line [0-9]*: (.*)/ ) + { + my $error= $1; + # Look for "could not sync with master" + if ( $error =~ /could not sync with master/ ) + { + analyze_testcase_failure_sync_with_master($tinfo); + } + } + } +} + ############################################################################## # # Run a single test case @@ -3011,6 +3063,10 @@ sub run_testcase ($) { } elsif ( $res == 1 ) { + if ( $opt_force ) + { + analyze_testcase_failure($tinfo); + } # Test case failure reported by mysqltest report_failure_and_restart($tinfo); } From a8d1c62e5f138392436b635f62e9dbf2b3e186b2 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 24 Oct 2006 18:49:19 +0200 Subject: [PATCH 114/131] Run mysql_client_test without --silent Flush both stdout and stderr before abort'ing mysql_client_test --- mysql-test/mysql-test-run.pl | 2 +- tests/mysql_client_test.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index f88cd333b91..731d07c86c5 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1735,7 +1735,7 @@ sub environment_setup () { # Setup env so childs can execute mysql_client_test # ---------------------------------------------------- my $cmdline_mysql_client_test= - "$exe_mysql_client_test --no-defaults --testcase --user=root --silent " . + "$exe_mysql_client_test --no-defaults --testcase --user=root " . "--port=$master->[0]->{'port'} " . "--socket=$master->[0]->{'path_sock'}"; if ( $mysql_version_id >= 50000 ) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 9fabde993b8..64c260666d3 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -113,7 +113,9 @@ static void client_disconnect(); void die(const char *file, int line, const char *expr) { + fflush(stdout); fprintf(stderr, "%s:%d: check failed: '%s'\n", file, line, expr); + fflush(stderr); abort(); } From 844369130ff3945abaef703cb8021cab64dcf104 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 24 Oct 2006 19:22:27 +0200 Subject: [PATCH 115/131] Remove debug printout --- mysql-test/mysql-test-run.pl | 2 -- 1 file changed, 2 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 731d07c86c5..3046e5ba2fe 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2926,8 +2926,6 @@ sub find_testcase_skipped_reason($) sub analyze_testcase_failure_sync_with_master($) { my ($tinfo)= @_; - mtr_verbose("analyze_testcase_failure_sync_with_master"); - print "analyze_testcase_failure_sync_with_master\n"; my $args; mtr_init_args(\$args); From 1a7676fa65ff509bd6f21175f334f6d73f47ce18 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 24 Oct 2006 20:32:07 +0200 Subject: [PATCH 116/131] WL#3462 Add testing of MySQL client ABI to prevent unintentional ABI breaks BUG#23427 incompatible ABI change in 5.0.26? - Use the icheck tool if avaliable and compare the current mysql.h to a version controlled reference file --- .bzrignore | 2 + configure.in | 4 + include/Makefile.am | 28 +- include/mysql.h | 11 + include/mysql_h_abi.ic | 1244 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1287 insertions(+), 2 deletions(-) create mode 100644 include/mysql_h_abi.ic diff --git a/.bzrignore b/.bzrignore index c4ae17ed95e..5e2aa892c28 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1064,3 +1064,5 @@ vio/test-ssl vio/test-sslclient vio/test-sslserver vio/viotest-ssl +include/check_abi +include/mysql_h.ic diff --git a/configure.in b/configure.in index 6cccb1bb90e..20dea3595de 100644 --- a/configure.in +++ b/configure.in @@ -508,6 +508,10 @@ AC_SUBST(DOXYGEN) AC_SUBST(PDFLATEX) AC_SUBST(MAKEINDEX) +# icheck, used for ABI check +AC_PATH_PROG(ICHECK, icheck, no) +AC_SUBST(ICHECK) + # Lock for PS AC_PATH_PROG(PS, ps, ps) AC_MSG_CHECKING("how to check if pid exists") diff --git a/include/Makefile.am b/include/Makefile.am index 3fa7b04d69a..dc30d40a352 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -15,7 +15,7 @@ # Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, # MA 02111-1307, USA -BUILT_SOURCES = mysql_version.h m_ctype.h my_config.h +BUILT_SOURCES = mysql_version.h m_ctype.h my_config.h mysql_h.ic pkginclude_HEADERS = my_dbug.h m_string.h my_sys.h my_list.h my_xml.h \ mysql.h mysql_com.h mysqld_error.h mysql_embed.h \ my_semaphore.h my_pthread.h my_no_pthread.h raid.h \ @@ -32,8 +32,10 @@ noinst_HEADERS = config-win.h config-os2.h config-netware.h \ thr_lock.h t_ctype.h violite.h md5.h \ mysql_version.h.in my_handler.h my_time.h +CLEANFILES = mysql_h.ic + # mysql_version.h are generated -SUPERCLEANFILES = mysql_version.h my_config.h +SUPERCLEANFILES = mysql_version.h my_config.h $(CLEANFILES) # Some include files that may be moved and patched by configure DISTCLEANFILES = sched.h $(SUPERCLEANFILES) @@ -55,5 +57,27 @@ link_sources: dist-hook: $(RM) -f $(distdir)/mysql_version.h $(distdir)/my_config.h +# +# Rules for checking that ABI has not changed +# + +# Create a icheck file for mysql.h +mysql_h.ic: mysql.h + @set -x; \ + if [ @ICHECK@ != no ] ; then \ + @ICHECK@ --canonify -o $@ mysql.h; \ + fi; + +# Compare the icheck file to the reference +check_abi: mysql_h.ic + @set -x; \ + if [ @ICHECK@ != no ] ; then \ + @ICHECK@ --compare mysql_h.ic mysql_h_abi.ic; \ + fi; \ + touch check_abi; + +all: check_abi + + # Don't update the files from bitkeeper %::SCCS/s.% diff --git a/include/mysql.h b/include/mysql.h index 143f6752c46..bc99b6f6ba1 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -14,6 +14,17 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* + This file defines the client API to MySQL and also the ABI of the + dynamically linked libmysqlclient. + + The ABI should never be changed in a released product of MySQL + thus you need to take great care when changing the file. In case + the file is changed so the ABI is broken, you must also + update the SHAREDLIB_MAJOR_VERSION in configure.in . + +*/ + #ifndef _mysql_h #define _mysql_h diff --git a/include/mysql_h_abi.ic b/include/mysql_h_abi.ic new file mode 100644 index 00000000000..80d13199a8d --- /dev/null +++ b/include/mysql_h_abi.ic @@ -0,0 +1,1244 @@ +struct __pthread_internal_slist; +struct __pthread_mutex_s; +struct rand_struct; +struct st_list; +struct st_mem_root; +struct st_mysql; +struct st_mysql_bind; +struct st_mysql_data; +struct st_mysql_field; +struct st_mysql_manager; +struct st_mysql_methods; +struct st_mysql_options; +struct st_mysql_parameters; +struct st_mysql_res; +struct st_mysql_rows; +struct st_mysql_stmt; +struct st_mysql_time; +struct st_net; +struct st_typelib; +struct st_udf_args; +struct st_udf_init; +struct st_used_mem; +struct timespec; +struct timeval; +enum Item_result; +enum enum_field_types; +enum enum_mysql_set_option; +enum enum_mysql_stmt_state; +enum enum_mysql_timestamp_type; +enum enum_server_command; +enum enum_stmt_attr_type; +enum mysql_enum_shutdown_level; +enum mysql_option; +enum mysql_protocol_type; +enum mysql_rpl_type; +enum mysql_status; +# 59 "/usr/include/bits/types.h" +typedef long long int __quad_t; +# 135 "mysql.h" +typedef struct st_mysql_rows MYSQL_ROWS; +# 55 "/usr/include/sys/select.h" +typedef long int __fd_mask; +# 145 "/usr/include/bits/types.h" +typedef __quad_t __off64_t; +# 60 "/usr/include/bits/types.h" +typedef unsigned long long int __u_quad_t; +# 24 "my_list.h" +typedef struct st_list LIST; +# 236 "mysql.h" +typedef struct st_mysql MYSQL; +# 575 "mysql.h" +typedef struct st_mysql_bind MYSQL_BIND; +# 97 "mysql.h" +typedef struct st_mysql_field MYSQL_FIELD; +# 121 "mysql.h" +typedef unsigned int MYSQL_FIELD_OFFSET; +# 327 "mysql.h" +typedef struct st_mysql_manager MYSQL_MANAGER; +# 341 "mysql.h" +typedef struct st_mysql_parameters MYSQL_PARAMETERS; +# 296 "mysql.h" +typedef struct st_mysql_res MYSQL_RES; +# 120 "mysql.h" +typedef char * * MYSQL_ROW; +# 141 "mysql.h" +typedef MYSQL_ROWS * MYSQL_ROW_OFFSET; +# 600 "mysql.h" +typedef struct st_mysql_stmt MYSQL_STMT; +# 151 "mysql_com.h" +typedef struct st_net NET; +# 21 "typelib.h" +typedef struct st_typelib TYPELIB; +# 141 "mysql_com.h" +typedef struct st_vio Vio; +# 172 "/usr/include/bits/types.h" +typedef long int __blkcnt_t; +# 189 "/usr/include/bits/types.h" +typedef char * __caddr_t; +# 161 "/usr/include/bits/types.h" +typedef int __clockid_t; +# 156 "/usr/include/bits/types.h" +typedef int __daddr_t; +# 137 "/usr/include/bits/types.h" +typedef __u_quad_t __dev_t; +# 176 "/usr/include/bits/types.h" +typedef unsigned long int __fsblkcnt_t; +# 180 "/usr/include/bits/types.h" +typedef unsigned long int __fsfilcnt_t; +# 147 "/usr/include/bits/types.h" +typedef struct __attribute__((aligned(__alignof__(int)))) + { + int __val[2]; + } __fsid_t; +# 139 "/usr/include/bits/types.h" +typedef unsigned int __gid_t; +# 151 "/usr/include/bits/types.h" +typedef unsigned int __id_t; +# 140 "/usr/include/bits/types.h" +typedef unsigned long int __ino_t; +# 158 "/usr/include/bits/types.h" +typedef int __key_t; +# 187 "/usr/include/bits/types.h" +typedef __off64_t __loff_t; +# 142 "/usr/include/bits/types.h" +typedef unsigned int __mode_t; +# 143 "/usr/include/bits/types.h" +typedef unsigned int __nlink_t; +# 144 "/usr/include/bits/types.h" +typedef long int __off_t; +# 146 "/usr/include/bits/types.h" +typedef int __pid_t; +# 28 "/usr/include/bits/sigset.h" +typedef struct __attribute__((aligned(__alignof__(unsigned long int)))) + { + unsigned long int __val[(1024 / (8 * sizeof(unsigned long int)))]; + } __sigset_t; +# 183 "/usr/include/bits/types.h" +typedef int __ssize_t; +# 154 "/usr/include/bits/types.h" +typedef long int __suseconds_t; +# 152 "/usr/include/bits/types.h" +typedef long int __time_t; +# 164 "/usr/include/bits/types.h" +typedef void * __timer_t; +# 34 "/usr/include/bits/types.h" +typedef unsigned char __u_char; +# 36 "/usr/include/bits/types.h" +typedef unsigned int __u_int; +# 37 "/usr/include/bits/types.h" +typedef unsigned long int __u_long; +# 35 "/usr/include/bits/types.h" +typedef unsigned short int __u_short; +# 138 "/usr/include/bits/types.h" +typedef unsigned int __uid_t; +# 67 "/usr/include/sys/select.h" +typedef struct __attribute__((aligned(__alignof__(long int)))) + { + __fd_mask __fds_bits[(1024 / (8 * sizeof(__fd_mask)))]; + } fd_set; +# 61 "mysql.h" +typedef char * gptr; +# 29 "my_list.h" +typedef int (* list_walk_action)(void *, void *); +# 52 "mysql.h" +typedef char my_bool; +# 67 "mysql.h" +typedef int my_socket; +# 129 "mysql.h" +typedef unsigned long long int my_ulonglong; +# 35 "my_alloc.h" +typedef struct st_mem_root MEM_ROOT; +# 145 "mysql.h" +typedef struct st_mysql_data MYSQL_DATA; +# 652 "mysql.h" +typedef struct st_mysql_methods MYSQL_METHODS; +# 48 "mysql_time.h" +typedef struct st_mysql_time MYSQL_TIME; +# 315 "mysql_com.h" +typedef struct st_udf_args UDF_ARGS; +# 326 "mysql_com.h" +typedef struct st_udf_init UDF_INIT; +# 27 "my_alloc.h" +typedef struct st_used_mem USED_MEM; +# 173 "/usr/include/bits/types.h" +typedef __quad_t __blkcnt64_t; +# 167 "/usr/include/bits/types.h" +typedef long int __blksize_t; +# 148 "/usr/include/bits/types.h" +typedef long int __clock_t; +# 177 "/usr/include/bits/types.h" +typedef __u_quad_t __fsblkcnt64_t; +# 181 "/usr/include/bits/types.h" +typedef __u_quad_t __fsfilcnt64_t; +# 141 "/usr/include/bits/types.h" +typedef __u_quad_t __ino64_t; +# 42 "/usr/include/bits/types.h" +typedef short int __int16_t; +# 44 "/usr/include/bits/types.h" +typedef int __int32_t; +# 50 "/usr/include/bits/types.h" +typedef long long int __int64_t; +# 40 "/usr/include/bits/types.h" +typedef signed char __int8_t; +# 192 "/usr/include/bits/types.h" +typedef int __intptr_t; +# 46 "/usr/include/bits/pthreadtypes.h" +typedef struct __pthread_internal_slist __pthread_slist_t; +# 188 "/usr/include/bits/types.h" +typedef __quad_t * __qaddr_t; +# 150 "/usr/include/bits/types.h" +typedef __u_quad_t __rlim64_t; +# 149 "/usr/include/bits/types.h" +typedef unsigned long int __rlim_t; +# 23 "/usr/include/bits/sigset.h" +typedef int __sig_atomic_t; +# 195 "/usr/include/bits/types.h" +typedef unsigned int __socklen_t; +# 157 "/usr/include/bits/types.h" +typedef long int __swblk_t; +# 43 "/usr/include/bits/types.h" +typedef unsigned short int __uint16_t; +# 45 "/usr/include/bits/types.h" +typedef unsigned int __uint32_t; +# 51 "/usr/include/bits/types.h" +typedef unsigned long long int __uint64_t; +# 41 "/usr/include/bits/types.h" +typedef unsigned char __uint8_t; +# 153 "/usr/include/bits/types.h" +typedef unsigned int __useconds_t; +# 235 "/usr/include/sys/types.h" +typedef __blkcnt_t blkcnt_t; +# 117 "/usr/include/sys/types.h" +typedef __caddr_t caddr_t; +# 93 "/usr/include/time.h" +typedef __clockid_t clockid_t; +# 116 "/usr/include/sys/types.h" +typedef __daddr_t daddr_t; +# 62 "/usr/include/sys/types.h" +typedef __dev_t dev_t; +# 85 "/usr/include/sys/select.h" +typedef __fd_mask fd_mask; +# 239 "/usr/include/sys/types.h" +typedef __fsblkcnt_t fsblkcnt_t; +# 243 "/usr/include/sys/types.h" +typedef __fsfilcnt_t fsfilcnt_t; +# 41 "/usr/include/sys/types.h" +typedef __fsid_t fsid_t; +# 67 "/usr/include/sys/types.h" +typedef __gid_t gid_t; +# 105 "/usr/include/sys/types.h" +typedef __id_t id_t; +# 50 "/usr/include/sys/types.h" +typedef __ino_t ino_t; +# 196 "/usr/include/sys/types.h" +typedef int int16_t; +# 197 "/usr/include/sys/types.h" +typedef int int32_t; +# 198 "/usr/include/sys/types.h" +typedef int int64_t; +# 195 "/usr/include/sys/types.h" +typedef int int8_t; +# 123 "/usr/include/sys/types.h" +typedef __key_t key_t; +# 46 "/usr/include/sys/types.h" +typedef __loff_t loff_t; +# 72 "/usr/include/sys/types.h" +typedef __mode_t mode_t; +# 77 "/usr/include/sys/types.h" +typedef __nlink_t nlink_t; +# 88 "/usr/include/sys/types.h" +typedef __off_t off_t; +# 100 "/usr/include/sys/types.h" +typedef __pid_t pid_t; +# 39 "/usr/include/bits/pthreadtypes.h" +typedef union __attribute__((aligned(__alignof__(long int)))) + { + char __size[36]; + long int __align; + } pthread_attr_t; +# 153 "/usr/include/bits/pthreadtypes.h" +typedef union __attribute__((aligned(__alignof__(long int)))) + { + char __size[20]; + long int __align; + } pthread_barrier_t; +# 159 "/usr/include/bits/pthreadtypes.h" +typedef union __attribute__((aligned(__alignof__(int)))) + { + char __size[4]; + int __align; + } pthread_barrierattr_t; +# 84 "/usr/include/bits/pthreadtypes.h" +typedef union __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__alignof__(void *)))) + { + struct __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__alignof__(void *)))) + { + int __lock; + unsigned int __futex; + unsigned long long int __total_seq; + unsigned long long int __wakeup_seq; + unsigned long long int __woken_seq; + void * __mutex; + unsigned int __nwaiters; + unsigned int __broadcast_seq; + } __data; + char __size[48]; + long long int __align; + } pthread_cond_t; +# 101 "/usr/include/bits/pthreadtypes.h" +typedef union __attribute__((aligned(__alignof__(long int)))) + { + char __size[4]; + long int __align; + } pthread_condattr_t; +# 109 "/usr/include/bits/pthreadtypes.h" +typedef unsigned int pthread_key_t; +# 54 "/usr/include/bits/pthreadtypes.h" +typedef union __attribute__((aligned(__alignof__(long int)))) + { + struct __pthread_mutex_s __data; + char __size[24]; + long int __align; + } pthread_mutex_t; +# 75 "/usr/include/bits/pthreadtypes.h" +typedef union __attribute__((aligned(__alignof__(long int)))) + { + char __size[4]; + long int __align; + } pthread_mutexattr_t; +# 113 "/usr/include/bits/pthreadtypes.h" +typedef int pthread_once_t; +# 119 "/usr/include/bits/pthreadtypes.h" +typedef union __attribute__((aligned(__alignof__(long int)))) + { + struct __attribute__((aligned(__alignof__(int)))) + { + int __lock; + unsigned int __nr_readers; + unsigned int __readers_wakeup; + unsigned int __writer_wakeup; + unsigned int __nr_readers_queued; + unsigned int __nr_writers_queued; + unsigned int __flags; + int __writer; + } __data; + char __size[32]; + long int __align; + } pthread_rwlock_t; +# 138 "/usr/include/bits/pthreadtypes.h" +typedef union __attribute__((aligned(__alignof__(long int)))) + { + char __size[8]; + long int __align; + } pthread_rwlockattr_t; +# 148 "/usr/include/bits/pthreadtypes.h" +typedef int volatile pthread_spinlock_t; +# 36 "/usr/include/bits/pthreadtypes.h" +typedef unsigned long int pthread_t; +# 39 "/usr/include/sys/types.h" +typedef __quad_t quad_t; +# 206 "/usr/include/sys/types.h" +typedef int register_t; +# 38 "/usr/include/sys/select.h" +typedef __sigset_t sigset_t; +# 214 "/usr/lib/gcc/i386-redhat-linux/4.0.2/include/stddef.h" +typedef unsigned int size_t; +# 110 "/usr/include/sys/types.h" +typedef __ssize_t ssize_t; +# 49 "/usr/include/sys/select.h" +typedef __suseconds_t suseconds_t; +# 77 "/usr/include/time.h" +typedef __time_t time_t; +# 105 "/usr/include/time.h" +typedef __timer_t timer_t; +# 35 "/usr/include/sys/types.h" +typedef __u_char u_char; +# 37 "/usr/include/sys/types.h" +typedef __u_int u_int; +# 202 "/usr/include/sys/types.h" +typedef unsigned int u_int16_t; +# 203 "/usr/include/sys/types.h" +typedef unsigned int u_int32_t; +# 204 "/usr/include/sys/types.h" +typedef unsigned int u_int64_t; +# 201 "/usr/include/sys/types.h" +typedef unsigned int u_int8_t; +# 38 "/usr/include/sys/types.h" +typedef __u_long u_long; +# 40 "/usr/include/sys/types.h" +typedef __u_quad_t u_quad_t; +# 36 "/usr/include/sys/types.h" +typedef __u_short u_short; +# 82 "/usr/include/sys/types.h" +typedef __uid_t uid_t; +# 153 "/usr/include/sys/types.h" +typedef unsigned int uint; +# 151 "/usr/include/sys/types.h" +typedef unsigned long int ulong; +# 152 "/usr/include/sys/types.h" +typedef unsigned short int ushort; +# 46 "/usr/include/bits/pthreadtypes.h" +struct __attribute__((aligned(__alignof__(void *)))) __pthread_internal_slist + { + struct __pthread_internal_slist * __next; + }; +# 54 "/usr/include/bits/pthreadtypes.h" +struct __attribute__((aligned(__alignof__(int)))) __pthread_mutex_s + { + int __lock; + unsigned int __count; + int __owner; + int __kind; + unsigned int __nusers; + }; +# 302 "mysql_com.h" +struct __attribute__((aligned(__alignof__(unsigned long int)), aligned(__alignof__(double)))) rand_struct + { + unsigned long int seed1; + unsigned long int seed2; + unsigned long int max_value; + double max_value_dbl; + }; +# 24 "my_list.h" +struct __attribute__((aligned(__alignof__(void *)))) st_list + { + struct st_list * prev; + struct st_list * next; + void * data; + }; +# 35 "my_alloc.h" +struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned int)))) st_mem_root + { + USED_MEM * free; + USED_MEM * used; + USED_MEM * pre_alloc; + unsigned int min_malloc; + unsigned int block_size; + unsigned int block_num; + unsigned int first_block_usage; + void (* error_handler)(void); + }; +# 236 "mysql.h" +struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long long int)))) st_mysql + { + NET net; + gptr connector_fd; + char * host; + char * user; + char * passwd; + char * unix_socket; + char * server_version; + char * host_info; + char * info; + char * db; + struct charset_info_st * charset; + MYSQL_FIELD * fields; + MEM_ROOT field_alloc; + my_ulonglong affected_rows; + my_ulonglong insert_id; + my_ulonglong extra_info; + unsigned long int thread_id; + unsigned long int packet_length; + unsigned int port; + unsigned long int client_flag; + unsigned long int server_capabilities; + unsigned int protocol_version; + unsigned int field_count; + unsigned int server_status; + unsigned int server_language; + unsigned int warning_count; + struct st_mysql_options options; + enum mysql_status status; + my_bool free_me; + my_bool reconnect; + char scramble[(20 + 1)]; + my_bool rpl_pivot; + struct st_mysql * master; + struct st_mysql * next_slave; + struct st_mysql * last_used_slave; + struct st_mysql * last_used_con; + LIST * stmts; + struct st_mysql_methods const * methods; + void * thd; + my_bool * unbuffered_fetch_owner; + struct st_mysql_stmt * current_stmt; + }; +# 575 "mysql.h" +struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_mysql_bind + { + unsigned long int * length; + my_bool * is_null; + void * buffer; + enum enum_field_types buffer_type; + unsigned long int buffer_length; + unsigned char * inter_buffer; + unsigned long int offset; + unsigned long int internal_length; + unsigned int param_number; + unsigned int pack_length; + my_bool is_unsigned; + my_bool long_data_used; + my_bool internal_is_null; + void (* store_param_func)(NET * net, struct st_mysql_bind * param); + void (* fetch_result)(struct st_mysql_bind *, unsigned char * * row); + void (* skip_result)(struct st_mysql_bind *, MYSQL_FIELD *, unsigned char * * row); + }; +# 145 "mysql.h" +struct __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__alignof__(void *)))) st_mysql_data + { + my_ulonglong rows; + unsigned int fields; + MYSQL_ROWS * data; + MEM_ROOT alloc; + MYSQL_ROWS * * prev_ptr; + }; +# 97 "mysql.h" +struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_mysql_field + { + char * name; + char * org_name; + char * table; + char * org_table; + char * db; + char * catalog; + char * def; + unsigned long int length; + unsigned long int max_length; + unsigned int name_length; + unsigned int org_name_length; + unsigned int table_length; + unsigned int org_table_length; + unsigned int db_length; + unsigned int catalog_length; + unsigned int def_length; + unsigned int flags; + unsigned int decimals; + unsigned int charsetnr; + enum enum_field_types type; + }; +# 327 "mysql.h" +struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_mysql_manager + { + NET net; + char * host; + char * user; + char * passwd; + unsigned int port; + my_bool free_me; + my_bool eof; + int cmd_status; + int last_errno; + char * net_buf; + char * net_buf_pos; + char * net_data_end; + int net_buf_size; + char last_error[256]; + }; +# 652 "mysql.h" +struct __attribute__((aligned(__alignof__(void *)))) st_mysql_methods + { + my_bool (* read_query_result)(MYSQL * mysql); + my_bool (* advanced_command)(MYSQL * mysql, enum enum_server_command, char const * header, unsigned long int, char const * arg, unsigned long int, my_bool, MYSQL_STMT * stmt); + MYSQL_DATA * (* read_rows)(MYSQL * mysql, MYSQL_FIELD * mysql_fields, unsigned int); + MYSQL_RES * (* use_result)(MYSQL * mysql); + void (* fetch_lengths)(unsigned long int * to, MYSQL_ROW, unsigned int); + void (* flush_use_result)(MYSQL * mysql); + MYSQL_FIELD * (* list_fields)(MYSQL * mysql); + my_bool (* read_prepare_result)(MYSQL * mysql, MYSQL_STMT * stmt); + int (* stmt_execute)(MYSQL_STMT * stmt); + int (* read_binary_rows)(MYSQL_STMT * stmt); + int (* unbuffered_fetch)(MYSQL * mysql, char * * row); + void (* free_embedded_thd)(MYSQL * mysql); + char const * (* read_statistics)(MYSQL * mysql); + my_bool (* next_result)(MYSQL * mysql); + int (* read_change_user_result)(MYSQL * mysql, char * buff, char const * passwd); + }; +# 166 "mysql.h" +struct __attribute__((aligned(__alignof__(unsigned long int)), aligned(__alignof__(void *)))) st_mysql_options + { + unsigned int connect_timeout; + unsigned int read_timeout; + unsigned int write_timeout; + unsigned int port; + unsigned int protocol; + unsigned long int client_flag; + char * host; + char * user; + char * password; + char * unix_socket; + char * db; + struct st_dynamic_array * init_commands; + char * my_cnf_file; + char * my_cnf_group; + char * charset_dir; + char * charset_name; + char * ssl_key; + char * ssl_cert; + char * ssl_ca; + char * ssl_capath; + char * ssl_cipher; + char * shared_memory_base_name; + unsigned long int max_allowed_packet; + my_bool use_ssl; + my_bool compress; + my_bool named_pipe; + my_bool rpl_probe; + my_bool rpl_parse; + my_bool no_master_reads; + my_bool separate_thread; + enum mysql_option methods_to_use; + char * client_ip; + my_bool secure_auth; + int (* local_infile_init)(void * *, char const *, void *); + int (* local_infile_read)(void *, char *, unsigned int); + void (* local_infile_end)(void); + int (* local_infile_error)(void *, char *, unsigned int); + void * local_infile_userdata; + }; +# 341 "mysql.h" +struct __attribute__((aligned(__alignof__(void *)))) st_mysql_parameters + { + unsigned long int * p_max_allowed_packet; + unsigned long int * p_net_buffer_length; + }; +# 296 "mysql.h" +struct __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__alignof__(void *)))) st_mysql_res + { + my_ulonglong row_count; + MYSQL_FIELD * fields; + MYSQL_DATA * data; + MYSQL_ROWS * data_cursor; + unsigned long int * lengths; + MYSQL * handle; + MEM_ROOT field_alloc; + unsigned int field_count; + unsigned int current_field; + MYSQL_ROW row; + MYSQL_ROW current_row; + my_bool eof; + my_bool unbuffered_fetch_cancelled; + struct st_mysql_methods const * methods; + }; +# 135 "mysql.h" +struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_mysql_rows + { + struct st_mysql_rows * next; + MYSQL_ROW data; + unsigned long int length; + }; +# 600 "mysql.h" +struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long long int)))) st_mysql_stmt + { + MEM_ROOT mem_root; + LIST list; + MYSQL * mysql; + MYSQL_BIND * params; + MYSQL_BIND * bind; + MYSQL_FIELD * fields; + MYSQL_DATA result; + MYSQL_ROWS * data_cursor; + my_ulonglong affected_rows; + my_ulonglong insert_id; + int (* read_row_func)(struct st_mysql_stmt * stmt, unsigned char * * row); + unsigned long int stmt_id; + unsigned int last_errno; + unsigned int param_count; + unsigned int field_count; + enum enum_mysql_stmt_state state; + char last_error[512]; + char sqlstate[(5 + 1)]; + my_bool send_types_to_server; + my_bool bind_param_done; + my_bool bind_result_done; + my_bool unbuffered_fetch_cancelled; + my_bool update_max_length; + }; +# 48 "mysql_time.h" +struct __attribute__((aligned(__alignof__(unsigned long int)))) st_mysql_time + { + unsigned int year; + unsigned int month; + unsigned int day; + unsigned int hour; + unsigned int minute; + unsigned int second; + unsigned long int second_part; + my_bool neg; + enum enum_mysql_timestamp_type time_type; + }; +# 151 "mysql_com.h" +struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_net + { + Vio * vio; + unsigned char * buff; + unsigned char * buff_end; + unsigned char * write_pos; + unsigned char * read_pos; + my_socket fd; + unsigned long int max_packet; + unsigned long int max_packet_size; + unsigned int pkt_nr; + unsigned int compress_pkt_nr; + unsigned int write_timeout; + unsigned int read_timeout; + unsigned int retry_count; + int fcntl; + my_bool compress; + unsigned long int remain_in_buf; + unsigned long int length; + unsigned long int buf_length; + unsigned long int where_b; + unsigned int * return_status; + unsigned char reading_or_writing; + char save_char; + my_bool no_send_ok; + char last_error[512]; + char sqlstate[(5 + 1)]; + unsigned int last_errno; + unsigned char error; + gptr query_cache_query; + my_bool report_error; + my_bool return_errno; + }; +# 21 "typelib.h" +struct __attribute__((aligned(__alignof__(unsigned int)), aligned(__alignof__(void *)))) st_typelib + { + unsigned int count; + char const * name; + char const * * type_names; + unsigned int * type_lengths; + }; +# 315 "mysql_com.h" +struct __attribute__((aligned(__alignof__(unsigned int)), aligned(__alignof__(void *)))) st_udf_args + { + unsigned int arg_count; + enum Item_result * arg_type; + char * * args; + unsigned long int * lengths; + char * maybe_null; + }; +# 326 "mysql_com.h" +struct __attribute__((aligned(__alignof__(unsigned long int)), aligned(__alignof__(void *)))) st_udf_init + { + my_bool maybe_null; + unsigned int decimals; + unsigned long int max_length; + char * ptr; + my_bool const_item; + }; +# 27 "my_alloc.h" +struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned int)))) st_used_mem + { + struct st_used_mem * next; + unsigned int left; + unsigned int size; + }; +# 121 "/usr/include/time.h" +struct __attribute__((aligned(__alignof__(long int)))) timespec + { + __time_t tv_sec; + long int tv_nsec; + }; +# 69 "/usr/include/bits/time.h" +struct __attribute__((aligned(__alignof__(long int)))) timeval + { + __time_t tv_sec; + __suseconds_t tv_usec; + }; +# 313 "mysql_com.h" +enum Item_result + { + STRING_RESULT = 0, + REAL_RESULT = 1, + INT_RESULT = 2, + ROW_RESULT = 3, + }; +# 186 "mysql_com.h" +enum enum_field_types + { + MYSQL_TYPE_DECIMAL = 0, + MYSQL_TYPE_TINY = 1, + MYSQL_TYPE_SHORT = 2, + MYSQL_TYPE_LONG = 3, + MYSQL_TYPE_FLOAT = 4, + MYSQL_TYPE_DOUBLE = 5, + MYSQL_TYPE_NULL = 6, + MYSQL_TYPE_TIMESTAMP = 7, + MYSQL_TYPE_LONGLONG = 8, + MYSQL_TYPE_INT24 = 9, + MYSQL_TYPE_DATE = 10, + MYSQL_TYPE_TIME = 11, + MYSQL_TYPE_DATETIME = 12, + MYSQL_TYPE_YEAR = 13, + MYSQL_TYPE_NEWDATE = 14, + MYSQL_TYPE_ENUM = 247, + MYSQL_TYPE_SET = 248, + MYSQL_TYPE_TINY_BLOB = 249, + MYSQL_TYPE_MEDIUM_BLOB = 250, + MYSQL_TYPE_LONG_BLOB = 251, + MYSQL_TYPE_BLOB = 252, + MYSQL_TYPE_VAR_STRING = 253, + MYSQL_TYPE_STRING = 254, + MYSQL_TYPE_GEOMETRY = 255, + }; +# 269 "mysql_com.h" +enum enum_mysql_set_option + { + MYSQL_OPTION_MULTI_STATEMENTS_ON = 0, + MYSQL_OPTION_MULTI_STATEMENTS_OFF = 1, + }; +# 567 "mysql.h" +enum enum_mysql_stmt_state + { + MYSQL_STMT_INIT_DONE = 1, + MYSQL_STMT_PREPARE_DONE = 2, + MYSQL_STMT_EXECUTE_DONE = 3, + MYSQL_STMT_FETCH_DONE = 4, + }; +# 29 "mysql_time.h" +enum enum_mysql_timestamp_type + { + MYSQL_TIMESTAMP_NONE = -(2), + MYSQL_TIMESTAMP_ERROR = -(1), + MYSQL_TIMESTAMP_DATE = 0, + MYSQL_TIMESTAMP_DATETIME = 1, + MYSQL_TIMESTAMP_TIME = 2, + }; +# 39 "mysql_com.h" +enum enum_server_command + { + COM_SLEEP = 0, + COM_QUIT = 1, + COM_INIT_DB = 2, + COM_QUERY = 3, + COM_FIELD_LIST = 4, + COM_CREATE_DB = 5, + COM_DROP_DB = 6, + COM_REFRESH = 7, + COM_SHUTDOWN = 8, + COM_STATISTICS = 9, + COM_PROCESS_INFO = 10, + COM_CONNECT = 11, + COM_PROCESS_KILL = 12, + COM_DEBUG = 13, + COM_PING = 14, + COM_TIME = 15, + COM_DELAYED_INSERT = 16, + COM_CHANGE_USER = 17, + COM_BINLOG_DUMP = 18, + COM_TABLE_DUMP = 19, + COM_CONNECT_OUT = 20, + COM_REGISTER_SLAVE = 21, + COM_PREPARE = 22, + COM_EXECUTE = 23, + COM_LONG_DATA = 24, + COM_CLOSE_STMT = 25, + COM_RESET_STMT = 26, + COM_SET_OPTION = 27, + COM_END = 28, + }; +# 639 "mysql.h" +enum enum_stmt_attr_type + { + STMT_ATTR_UPDATE_MAX_LENGTH = 0, + }; +# 244 "mysql_com.h" +enum mysql_enum_shutdown_level + { + SHUTDOWN_DEFAULT = 0, + SHUTDOWN_WAIT_CONNECTIONS = (unsigned char)((1 << 0)), + SHUTDOWN_WAIT_TRANSACTIONS = (unsigned char)((1 << 1)), + SHUTDOWN_WAIT_UPDATES = (unsigned char)((1 << 3)), + SHUTDOWN_WAIT_ALL_BUFFERS = ((unsigned char)((1 << 3)) << 1), + SHUTDOWN_WAIT_CRITICAL_BUFFERS = (((unsigned char)((1 << 3)) << 1) + 1), + KILL_CONNECTION = 255, + }; +# 155 "mysql.h" +enum mysql_option + { + MYSQL_OPT_CONNECT_TIMEOUT = 0, + MYSQL_OPT_COMPRESS = 1, + MYSQL_OPT_NAMED_PIPE = 2, + MYSQL_INIT_COMMAND = 3, + MYSQL_READ_DEFAULT_FILE = 4, + MYSQL_READ_DEFAULT_GROUP = 5, + MYSQL_SET_CHARSET_DIR = 6, + MYSQL_SET_CHARSET_NAME = 7, + MYSQL_OPT_LOCAL_INFILE = 8, + MYSQL_OPT_PROTOCOL = 9, + MYSQL_SHARED_MEMORY_BASE_NAME = 10, + MYSQL_OPT_READ_TIMEOUT = 11, + MYSQL_OPT_WRITE_TIMEOUT = 12, + MYSQL_OPT_USE_RESULT = 13, + MYSQL_OPT_USE_REMOTE_CONNECTION = 14, + MYSQL_OPT_USE_EMBEDDED_CONNECTION = 15, + MYSQL_OPT_GUESS_CONNECTION = 16, + MYSQL_SET_CLIENT_IP = 17, + MYSQL_SECURE_AUTH = 18, + }; +# 218 "mysql.h" +enum mysql_protocol_type + { + MYSQL_PROTOCOL_DEFAULT = 0, + MYSQL_PROTOCOL_TCP = 1, + MYSQL_PROTOCOL_SOCKET = 2, + MYSQL_PROTOCOL_PIPE = 3, + MYSQL_PROTOCOL_MEMORY = 4, + }; +# 228 "mysql.h" +enum mysql_rpl_type + { + MYSQL_RPL_MASTER = 0, + MYSQL_RPL_SLAVE = 1, + MYSQL_RPL_ADMIN = 2, + }; +# 213 "mysql.h" +enum mysql_status + { + MYSQL_STATUS_READY = 0, + MYSQL_STATUS_GET_RESULT = 1, + MYSQL_STATUS_USE_RESULT = 2, + }; +# 365 "mysql_com.h" +extern my_bool check_scramble(char const * reply, char const * message, unsigned char const * hash_stage2); +# 358 "mysql_com.h" +extern my_bool check_scramble_323(char const *, char const * message, unsigned long int * salt); +# 353 "mysql_com.h" +extern void create_random_string(char * to, unsigned int, struct rand_struct * rand_st); +# 28 "typelib.h" +extern int find_type(char * x, TYPELIB * typelib, unsigned int); +# 367 "mysql_com.h" +extern void get_salt_from_password(unsigned char * res, char const * password); +# 360 "mysql_com.h" +extern void get_salt_from_password_323(unsigned long int * res, char const * password); +# 372 "mysql_com.h" +extern char * get_tty_password(char * opt_message); +# 30 "typelib.h" +extern char const * get_type(TYPELIB * typelib, unsigned int); +# 41 "/usr/include/sys/sysmacros.h" +extern unsigned int gnu_dev_major(unsigned long long int); +# 53 "/usr/include/sys/sysmacros.h" +extern unsigned long long int gnu_dev_makedev(unsigned int, unsigned int); +# 47 "/usr/include/sys/sysmacros.h" +extern unsigned int gnu_dev_minor(unsigned long long int); +# 355 "mysql_com.h" +extern void hash_password(unsigned long int * to, char const * password, unsigned int); +# 31 "my_list.h" +extern LIST * list_add(LIST * root, LIST * element); +# 33 "my_list.h" +extern LIST * list_cons(void * data, LIST * root); +# 32 "my_list.h" +extern LIST * list_delete(LIST * root, LIST * element); +# 35 "my_list.h" +extern void list_free(LIST * root, unsigned int); +# 36 "my_list.h" +extern unsigned int list_length(LIST *); +# 34 "my_list.h" +extern LIST * list_reverse(LIST * root); +# 37 "my_list.h" +extern int list_walk(LIST *, list_walk_action, gptr); +# 378 "mysql_com.h" +extern int load_defaults(char const * conf_file, char const * * groups, int * argc, char * * * argv); +# 368 "mysql_com.h" +extern void make_password_from_salt(char * to, unsigned char const * hash_stage2); +# 361 "mysql_com.h" +extern void make_password_from_salt_323(char * to, unsigned long int const * salt); +# 363 "mysql_com.h" +extern void make_scrambled_password(char * to, char const * password); +# 356 "mysql_com.h" +extern void make_scrambled_password_323(char * to, char const * password); +# 29 "typelib.h" +extern void make_type(char * to, unsigned int, TYPELIB * typelib); +# 299 "mysql_com.h" +extern int my_connect(my_socket, struct sockaddr const * name, unsigned int, unsigned int); +# 377 "mysql_com.h" +extern my_bool my_init(void); +# 281 "mysql_com.h" +extern my_bool my_net_init(NET * net, Vio * vio); +# 282 "mysql_com.h" +extern void my_net_local_init(NET * net); +# 292 "mysql_com.h" +extern unsigned long int my_net_read(NET * net); +# 287 "mysql_com.h" +extern my_bool my_net_write(NET * net, char const * packet, unsigned long int); +# 352 "mysql_com.h" +extern double my_rnd(struct rand_struct *); +# 381 "mysql_com.h" +extern void my_thread_end(void); +# 380 "mysql_com.h" +extern my_bool my_thread_init(void); +# 543 "mysql.h" +extern void myodbc_remove_escape(MYSQL * mysql, char * name); +# 485 "mysql.h" +extern int mysql_add_slave(MYSQL * mysql, char const * host, unsigned int, char const * user, char const * passwd); +# 397 "mysql.h" +extern my_ulonglong mysql_affected_rows(MYSQL * mysql); +# 724 "mysql.h" +extern my_bool mysql_autocommit(MYSQL * mysql, my_bool); +# 412 "mysql.h" +extern my_bool mysql_change_user(MYSQL * mysql, char const * user, char const * passwd, char const * db); +# 405 "mysql.h" +extern char const * mysql_character_set_name(MYSQL * mysql); +# 727 "mysql.h" +extern void mysql_close(MYSQL * sock); +# 722 "mysql.h" +extern my_bool mysql_commit(MYSQL * mysql); +# 514 "mysql.h" +extern void mysql_data_seek(MYSQL_RES * result, my_ulonglong); +# 532 "mysql.h" +extern void mysql_debug(char const * debug); +# 471 "mysql.h" +extern void mysql_disable_reads_from_master(MYSQL * mysql); +# 465 "mysql.h" +extern void mysql_disable_rpl_parse(MYSQL * mysql); +# 493 "mysql.h" +extern int mysql_dump_debug_info(MYSQL * mysql); +# 545 "mysql.h" +extern my_bool mysql_embedded(void); +# 470 "mysql.h" +extern void mysql_enable_reads_from_master(MYSQL * mysql); +# 464 "mysql.h" +extern void mysql_enable_rpl_parse(MYSQL * mysql); +# 389 "mysql.h" +extern my_bool mysql_eof(MYSQL_RES * res); +# 399 "mysql.h" +extern unsigned int mysql_errno(MYSQL * mysql); +# 373 "mysql_com.h" +extern char const * mysql_errno_to_sqlstate(unsigned int); +# 400 "mysql.h" +extern char const * mysql_error(MYSQL * mysql); +# 525 "mysql.h" +extern unsigned long int mysql_escape_string(char * to, char const * from, unsigned long int); +# 522 "mysql.h" +extern MYSQL_FIELD * mysql_fetch_field(MYSQL_RES * result); +# 390 "mysql.h" +extern MYSQL_FIELD * mysql_fetch_field_direct(MYSQL_RES * res, unsigned int); +# 392 "mysql.h" +extern MYSQL_FIELD * mysql_fetch_fields(MYSQL_RES * res); +# 521 "mysql.h" +extern unsigned long int * mysql_fetch_lengths(MYSQL_RES * result); +# 520 "mysql.h" +extern MYSQL_ROW mysql_fetch_row(MYSQL_RES * result); +# 396 "mysql.h" +extern unsigned int mysql_field_count(MYSQL * mysql); +# 518 "mysql.h" +extern MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES * result, MYSQL_FIELD_OFFSET); +# 394 "mysql.h" +extern MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES * res); +# 513 "mysql.h" +extern void mysql_free_result(MYSQL_RES * result); +# 503 "mysql.h" +extern char const * mysql_get_client_info(void); +# 504 "mysql.h" +extern unsigned long int mysql_get_client_version(void); +# 505 "mysql.h" +extern char const * mysql_get_host_info(MYSQL * mysql); +# 371 "mysql.h" +extern MYSQL_PARAMETERS * mysql_get_parameters(void); +# 507 "mysql.h" +extern unsigned int mysql_get_proto_info(MYSQL * mysql); +# 502 "mysql.h" +extern char const * mysql_get_server_info(MYSQL * mysql); +# 506 "mysql.h" +extern unsigned long int mysql_get_server_version(MYSQL * mysql); +# 527 "mysql.h" +extern unsigned long int mysql_hex_string(char * to, char const * from, unsigned long int); +# 403 "mysql.h" +extern char const * mysql_info(MYSQL * mysql); +# 408 "mysql.h" +extern MYSQL * mysql_init(MYSQL * mysql); +# 398 "mysql.h" +extern my_ulonglong mysql_insert_id(MYSQL * mysql); +# 496 "mysql.h" +extern int mysql_kill(MYSQL * mysql, unsigned long int); +# 508 "mysql.h" +extern MYSQL_RES * mysql_list_dbs(MYSQL * mysql, char const * wild); +# 523 "mysql.h" +extern MYSQL_RES * mysql_list_fields(MYSQL * mysql, char const * table, char const * wild); +# 510 "mysql.h" +extern MYSQL_RES * mysql_list_processes(MYSQL * mysql); +# 509 "mysql.h" +extern MYSQL_RES * mysql_list_tables(MYSQL * mysql, char const * wild); +# 552 "mysql.h" +extern void mysql_manager_close(MYSQL_MANAGER * con); +# 553 "mysql.h" +extern int mysql_manager_command(MYSQL_MANAGER * con, char const * cmd, int); +# 547 "mysql.h" +extern MYSQL_MANAGER * mysql_manager_connect(MYSQL_MANAGER * con, char const * host, char const * user, char const * passwd, unsigned int); +# 555 "mysql.h" +extern int mysql_manager_fetch_line(MYSQL_MANAGER * con, char * res_buf, int); +# 546 "mysql.h" +extern MYSQL_MANAGER * mysql_manager_init(MYSQL_MANAGER * con); +# 431 "mysql.h" +extern my_bool mysql_master_query(MYSQL * mysql, char const * q, unsigned long int); +# 433 "mysql.h" +extern my_bool mysql_master_send_query(MYSQL * mysql, char const * q, unsigned long int); +# 725 "mysql.h" +extern my_bool mysql_more_results(MYSQL * mysql); +# 726 "mysql.h" +extern int mysql_next_result(MYSQL * mysql); +# 388 "mysql.h" +extern unsigned int mysql_num_fields(MYSQL_RES * res); +# 387 "mysql.h" +extern my_ulonglong mysql_num_rows(MYSQL_RES * res); +# 533 "mysql.h" +extern char * mysql_odbc_escape_string(MYSQL * mysql, char * to, unsigned long int, char const * from, unsigned long int, void * param, char * (* extend_buffer)(void *, char * to, unsigned long int * length)); +# 511 "mysql.h" +extern int mysql_options(MYSQL * mysql, enum mysql_option, char const * arg); +# 500 "mysql.h" +extern int mysql_ping(MYSQL * mysql); +# 79 "mysql.h" +extern unsigned int mysql_port; +# 422 "mysql.h" +extern int mysql_query(MYSQL * mysql, char const * q); +# 558 "mysql.h" +extern my_bool mysql_read_query_result(MYSQL * mysql); +# 473 "mysql.h" +extern my_bool mysql_reads_from_master_enabled(MYSQL * mysql); +# 414 "mysql.h" +extern MYSQL * mysql_real_connect(MYSQL * mysql, char const * host, char const * user, char const * passwd, char const * db, unsigned int, char const * unix_socket, unsigned long int); +# 529 "mysql.h" +extern unsigned long int mysql_real_escape_string(MYSQL * mysql, char * to, char const * from, unsigned long int); +# 425 "mysql.h" +extern int mysql_real_query(MYSQL * mysql, char const * q, unsigned long int); +# 494 "mysql.h" +extern int mysql_refresh(MYSQL * mysql, unsigned int); +# 723 "mysql.h" +extern my_bool mysql_rollback(MYSQL * mysql); +# 516 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES * result, MYSQL_ROW_OFFSET); +# 393 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES * res); +# 467 "mysql.h" +extern int mysql_rpl_parse_enabled(MYSQL * mysql); +# 478 "mysql.h" +extern my_bool mysql_rpl_probe(MYSQL * mysql); +# 475 "mysql.h" +extern enum mysql_rpl_type mysql_rpl_query_type(char const * q, int); +# 421 "mysql.h" +extern int mysql_select_db(MYSQL * mysql, char const * db); +# 423 "mysql.h" +extern int mysql_send_query(MYSQL * mysql, char const * q, unsigned long int); +# 358 "mysql.h" +extern void mysql_server_end(void); +# 357 "mysql.h" +extern int mysql_server_init(int, char * * argv, char * * groups); +# 406 "mysql.h" +extern int mysql_set_character_set(MYSQL * mysql, char const * csname); +# 456 "mysql.h" +extern void mysql_set_local_infile_default(MYSQL * mysql); +# 445 "mysql.h" +extern void mysql_set_local_infile_handler(MYSQL * mysql, int (* local_infile_init)(void * *, char const *, void *), int (* local_infile_read)(void *, char *, unsigned int), void (* local_infile_end)(void), int (* local_infile_error)(void *, char *, unsigned int), void *); +# 481 "mysql.h" +extern int mysql_set_master(MYSQL * mysql, char const * host, unsigned int, char const * user, char const * passwd); +# 497 "mysql.h" +extern int mysql_set_server_option(MYSQL * mysql, enum enum_mysql_set_option); +# 490 "mysql.h" +extern int mysql_shutdown(MYSQL * mysql, enum mysql_enum_shutdown_level); +# 436 "mysql.h" +extern my_bool mysql_slave_query(MYSQL * mysql, char const * q, unsigned long int); +# 438 "mysql.h" +extern my_bool mysql_slave_send_query(MYSQL * mysql, char const * q, unsigned long int); +# 401 "mysql.h" +extern char const * mysql_sqlstate(MYSQL * mysql); +# 409 "mysql.h" +extern my_bool mysql_ssl_set(MYSQL * mysql, char const * key, char const * cert, char const * ca, char const * capath, char const * cipher); +# 501 "mysql.h" +extern char const * mysql_stat(MYSQL * mysql); +# 718 "mysql.h" +extern my_ulonglong mysql_stmt_affected_rows(MYSQL_STMT * stmt); +# 696 "mysql.h" +extern my_bool mysql_stmt_attr_get(MYSQL_STMT * stmt, enum enum_stmt_attr_type, void * attr); +# 693 "mysql.h" +extern my_bool mysql_stmt_attr_set(MYSQL_STMT * stmt, enum enum_stmt_attr_type, void const * attr); +# 699 "mysql.h" +extern my_bool mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +# 700 "mysql.h" +extern my_bool mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +# 701 "mysql.h" +extern my_bool mysql_stmt_close(MYSQL_STMT * stmt); +# 716 "mysql.h" +extern void mysql_stmt_data_seek(MYSQL_STMT * stmt, my_ulonglong); +# 710 "mysql.h" +extern unsigned int mysql_stmt_errno(MYSQL_STMT * stmt); +# 711 "mysql.h" +extern char const * mysql_stmt_error(MYSQL_STMT * stmt); +# 686 "mysql.h" +extern int mysql_stmt_execute(MYSQL_STMT * stmt); +# 687 "mysql.h" +extern int mysql_stmt_fetch(MYSQL_STMT * stmt); +# 688 "mysql.h" +extern int mysql_stmt_fetch_column(MYSQL_STMT * stmt, MYSQL_BIND * bind, unsigned int, unsigned long int); +# 720 "mysql.h" +extern unsigned int mysql_stmt_field_count(MYSQL_STMT * stmt); +# 703 "mysql.h" +extern my_bool mysql_stmt_free_result(MYSQL_STMT * stmt); +# 683 "mysql.h" +extern MYSQL_STMT * mysql_stmt_init(MYSQL * mysql); +# 719 "mysql.h" +extern my_ulonglong mysql_stmt_insert_id(MYSQL_STMT * stmt); +# 717 "mysql.h" +extern my_ulonglong mysql_stmt_num_rows(MYSQL_STMT * stmt); +# 692 "mysql.h" +extern unsigned long int mysql_stmt_param_count(MYSQL_STMT * stmt); +# 709 "mysql.h" +extern MYSQL_RES * mysql_stmt_param_metadata(MYSQL_STMT * stmt); +# 684 "mysql.h" +extern int mysql_stmt_prepare(MYSQL_STMT * stmt, char const * query, unsigned long int); +# 702 "mysql.h" +extern my_bool mysql_stmt_reset(MYSQL_STMT * stmt); +# 708 "mysql.h" +extern MYSQL_RES * mysql_stmt_result_metadata(MYSQL_STMT * stmt); +# 713 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_stmt_row_seek(MYSQL_STMT * stmt, MYSQL_ROW_OFFSET); +# 715 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_stmt_row_tell(MYSQL_STMT * stmt); +# 704 "mysql.h" +extern my_bool mysql_stmt_send_long_data(MYSQL_STMT * stmt, unsigned int, char const * data, unsigned long int); +# 712 "mysql.h" +extern char const * mysql_stmt_sqlstate(MYSQL_STMT * stmt); +# 691 "mysql.h" +extern int mysql_stmt_store_result(MYSQL_STMT * stmt); +# 427 "mysql.h" +extern MYSQL_RES * mysql_store_result(MYSQL * mysql); +# 380 "mysql.h" +extern void mysql_thread_end(void); +# 404 "mysql.h" +extern unsigned long int mysql_thread_id(MYSQL * mysql); +# 379 "mysql.h" +extern my_bool mysql_thread_init(void); +# 544 "mysql.h" +extern unsigned int mysql_thread_safe(void); +# 80 "mysql.h" +extern char * mysql_unix_port; +# 428 "mysql.h" +extern MYSQL_RES * mysql_use_result(MYSQL * mysql); +# 402 "mysql.h" +extern unsigned int mysql_warning_count(MYSQL * mysql); +# 284 "mysql_com.h" +extern void net_clear(NET * net); +# 283 "mysql_com.h" +extern void net_end(NET * net); +# 286 "mysql_com.h" +extern my_bool net_flush(NET * net); +# 291 "mysql_com.h" +extern int net_real_write(NET * net, char const * packet, unsigned long int); +# 285 "mysql_com.h" +extern my_bool net_realloc(NET * net, unsigned long int); +# 755 "mysql.h" +extern unsigned long int net_safe_read(MYSQL * mysql); +# 288 "mysql_com.h" +extern my_bool net_write_command(NET * net, unsigned char, char const * header, unsigned long int, char const * packet, unsigned long int); +# 121 "/usr/include/sys/select.h" +extern int pselect(int, fd_set * restrict __readfds, fd_set * restrict __writefds, fd_set * restrict __exceptfds, struct timespec const * restrict __timeout, __sigset_t const * restrict __sigmask); +# 350 "mysql_com.h" +extern void randominit(struct rand_struct *, unsigned long int, unsigned long int); +# 364 "mysql_com.h" +extern void scramble(char * to, char const * message, char const * password); +# 357 "mysql_com.h" +extern void scramble_323(char * to, char const * message, char const * password); +# 109 "/usr/include/sys/select.h" +extern int select(int, fd_set * restrict __readfds, fd_set * restrict __writefds, fd_set * restrict __exceptfds, struct timeval * restrict __timeout); +# 32 "typelib.h" +extern TYPELIB sql_protocol_typelib; From ac5b37ef00205c48179f7d703e558f71eeaa0c9e Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 24 Oct 2006 21:02:04 +0200 Subject: [PATCH 117/131] Pass --core-file option to mysqld when bootstrapping --- .bzrignore | 1 + mysql-test/mysql-test-run.pl | 1 + 2 files changed, 2 insertions(+) diff --git a/.bzrignore b/.bzrignore index 5e2aa892c28..348093af390 100644 --- a/.bzrignore +++ b/.bzrignore @@ -1066,3 +1066,4 @@ vio/test-sslserver vio/viotest-ssl include/check_abi include/mysql_h.ic +mysql-test/r/blackhole.log diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 3046e5ba2fe..72b4fe95132 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -2624,6 +2624,7 @@ sub install_db ($$) { mtr_add_arg($args, "--skip-innodb"); mtr_add_arg($args, "--skip-ndbcluster"); mtr_add_arg($args, "--tmpdir=."); + mtr_add_arg($args, "--core-file"); if ( $opt_debug ) { From 1f780b77e758a8825c2387f4662b11747d4d040f Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Tue, 24 Oct 2006 23:39:46 +0200 Subject: [PATCH 118/131] Adapt mysql-test-run.pl to mysqld in 5.1 using "mixed" binlog format by default --- mysql-test/lib/mtr_cases.pl | 1 + mysql-test/mysql-test-run.pl | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 7a01c66305b..17019cfd351 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -565,6 +565,7 @@ our @tags= ["include/have_innodb.inc", "innodb_test", 1], ["include/have_binlog_format_row.inc", "binlog_format", "row"], ["include/have_binlog_format_statement.inc", "binlog_format", "stmt"], + ["include/have_binlog_format_mixed.inc", "binlog_format", "mixed"], ["include/big_test.inc", "big_test", 1], ["include/have_debug.inc", "need_debug", 1], ["include/have_ndb.inc", "ndb_test", 1], diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 72b4fe95132..9fc63e0462b 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -714,12 +714,20 @@ sub command_line_setup () { # -------------------------------------------------------------------------- # NOTE if the default binlog format is changed, this has to be changed $used_binlog_format= "stmt"; + if ( $mysql_version_id >= 50100 ) + { + $used_binlog_format= "mixed"; + } foreach my $arg ( @opt_extra_mysqld_opt ) { if ( defined mtr_match_substring($arg,"binlog-format=row")) { $used_binlog_format= "row"; } + elsif ( defined mtr_match_substring($arg,"binlog-format=stmt")) + { + $used_binlog_format= "stmt"; + } } mtr_report("Using binlog format '$used_binlog_format'"); From 49690815898c3f707e5d28d41d82c3295a7cf898 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 25 Oct 2006 12:40:33 +0200 Subject: [PATCH 119/131] Set flag opt_skip_ndbcluster_slave if no slaves are being used. Add comments Deperlify --- mysql-test/mysql-test-run.pl | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 9fc63e0462b..3549c13a2a5 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -405,9 +405,25 @@ sub main () { } $use_innodb||= $test->{'innodb_test'}; } - $opt_skip_ndbcluster= $opt_skip_ndbcluster_slave= 1 - unless $need_ndbcluster; - $opt_skip_im= 1 unless $need_im; + + # Check if cluster can be skipped + if ( !$need_ndbcluster ) + { + $opt_skip_ndbcluster= 1; + $opt_skip_ndbcluster_slave= 1; + } + + # Check if slave cluster can be skipped + if ($max_slave_num == 0) + { + $opt_skip_ndbcluster_slave= 1; + } + + # Check if im can be skipped + if ( ! $need_im ) + { + $opt_skip_im= 1; + } initialize_servers(); From a6d87b4c00c6d6f77ea1f88ba90c64d848c78472 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 25 Oct 2006 14:34:18 +0200 Subject: [PATCH 120/131] Add valgrinding support for mysql_client_test Fix two memory leaks in mysql_client_test --- mysql-test/mysql-test-run.pl | 98 ++++++++++++++++++++---------------- tests/mysql_client_test.c | 2 + 2 files changed, 56 insertions(+), 44 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 3549c13a2a5..dc2c4c1a6fa 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -975,7 +975,7 @@ sub command_line_setup () { } elsif ( $opt_valgrind_mysqltest ) { - mtr_report("Turning on valgrind for mysqltest only"); + mtr_report("Turning on valgrind for mysqltest and mysql_client_test only"); $opt_valgrind= 1; } @@ -1507,6 +1507,47 @@ sub generate_cmdline_mysqldump ($) { # ############################################################################## +sub mysql_client_test_arguments() +{ + my $exe= $exe_mysql_client_test; + + my $args; + mtr_init_args(\$args); + if ( $opt_valgrind_mysqltest ) + { + valgrind_arguments($args, \$exe); + } + + mtr_add_arg($args, "--no-defaults"); + mtr_add_arg($args, "--testcase"); + mtr_add_arg($args, "--user=root"); + mtr_add_arg($args, "--port=$master->[0]->{'port'}"); + mtr_add_arg($args, "--socket=$master->[0]->{'path_sock'}"); + + if ( $mysql_version_id >= 50000 ) + { + mtr_add_arg($args, "--vardir=$opt_vardir") + } + + if ( $opt_debug ) + { + mtr_add_arg($args, + "--debug=d:t:A,$path_vardir_trace/log/mysql_client_test.trace"); + } + + if ( $glob_use_embedded_server ) + { + mtr_add_arg($args, + " -A --language=$path_language"); + mtr_add_arg($args, + " -A --datadir=$slave->[0]->{'path_myddir'}"); + mtr_add_arg($args, + " -A --character-sets-dir=$path_charsetsdir"); + } + + return join(" ", $exe, @$args); +} + # Note that some env is setup in spawn/run, in "mtr_process.pl" sub environment_setup () { @@ -1688,7 +1729,7 @@ sub environment_setup () { "--lock-directory=$opt_tmpdir"; if ( $opt_debug ) - { + { $cmdline_mysqlslap .= " --debug=d:t:A,$path_vardir_trace/log/mysqlslap.trace"; } @@ -1758,30 +1799,7 @@ sub environment_setup () { # ---------------------------------------------------- # Setup env so childs can execute mysql_client_test # ---------------------------------------------------- - my $cmdline_mysql_client_test= - "$exe_mysql_client_test --no-defaults --testcase --user=root " . - "--port=$master->[0]->{'port'} " . - "--socket=$master->[0]->{'path_sock'}"; - if ( $mysql_version_id >= 50000 ) - { - $cmdline_mysql_client_test .=" --vardir=$opt_vardir"; - } - - if ( $opt_debug ) - { - $cmdline_mysql_client_test .= - " --debug=d:t:A,$path_vardir_trace/log/mysql_client_test.trace"; - } - - if ( $glob_use_embedded_server ) - { - $cmdline_mysql_client_test.= - " -A --language=$path_language" . - " -A --datadir=$slave->[0]->{'path_myddir'}" . - " -A --character-sets-dir=$path_charsetsdir"; - } - $ENV{'MYSQL_CLIENT_TEST'}= $cmdline_mysql_client_test; - + $ENV{'MYSQL_CLIENT_TEST'}= mysql_client_test_arguments(); # ---------------------------------------------------- # Setup env so childs can execute mysql_fix_system_tables @@ -3611,15 +3629,6 @@ sub mysqld_start ($$$) { $wait_for_pid_file= 0; } - if ($exe_libtool and $opt_valgrind) - { - # Add "libtool --mode-execute" - # if running in valgrind(to avoid valgrinding bash) - unshift(@$args, "--mode=execute", $exe); - $exe= $exe_libtool; - } - - if ( defined $exe ) { $pid= mtr_spawn($exe, $args, "", @@ -4342,14 +4351,6 @@ sub run_mysqltest ($) { debugger_arguments(\$args, \$exe, "client"); } - if ($exe_libtool and $opt_valgrind) - { - # Add "libtool --mode-execute" before the test to execute - # if running in valgrind(to avoid valgrinding bash) - unshift(@$args, "--mode=execute", $exe); - $exe= $exe_libtool; - } - if ( $opt_check_testcases ) { foreach my $mysqld (@{$master}, @{$slave}) @@ -4575,6 +4576,14 @@ sub valgrind_arguments { mtr_add_arg($args, $$exe); $$exe= $opt_valgrind_path || "valgrind"; + + if ($exe_libtool) + { + # Add "libtool --mode-execute" before the test to execute + # if running in valgrind(to avoid valgrinding bash) + unshift(@$args, "--mode=execute", $$exe); + $$exe= $exe_libtool; + } } @@ -4687,7 +4696,8 @@ Options for coverage, profiling etc valgrind Run the "mysqltest" and "mysqld" executables using valgrind with options($default_valgrind_options) valgrind-all Synonym for --valgrind - valgrind-mysqltest Run the "mysqltest" executable with valgrind + valgrind-mysqltest Run the "mysqltest" and "mysql_client_test" executable + with valgrind valgrind-mysqld Run the "mysqld" executable with valgrind valgrind-options=ARGS Options to give valgrind, replaces default options valgrind-path=[EXE] Path to the valgrind executable diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 64c260666d3..56ab4a63260 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -11778,6 +11778,7 @@ static void test_bug11718() printf("return type: %s", (res->fields[0].type == MYSQL_TYPE_DATE)?"DATE": "not DATE"); DIE_UNLESS(res->fields[0].type == MYSQL_TYPE_DATE); + mysql_free_result(res); rc= mysql_query(mysql, "drop table t1, t2"); myquery(rc); } @@ -11849,6 +11850,7 @@ static void test_bug15613() DIE_UNLESS(field[4].length == 255); DIE_UNLESS(field[5].length == 255); DIE_UNLESS(field[6].length == 255); + mysql_free_result(metadata); /* III. Cleanup */ rc= mysql_query(mysql, "drop table t1"); From de932f2a5f192e050df10429c6874598a6821079 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 25 Oct 2006 14:56:36 +0200 Subject: [PATCH 121/131] Update the binlog format parse routine to only be avaliable in 5.1 and allow for any binlog_format to be specified --- mysql-test/mysql-test-run.pl | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index dc2c4c1a6fa..3e25d6e933c 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -732,20 +732,17 @@ sub command_line_setup () { $used_binlog_format= "stmt"; if ( $mysql_version_id >= 50100 ) { - $used_binlog_format= "mixed"; - } - foreach my $arg ( @opt_extra_mysqld_opt ) - { - if ( defined mtr_match_substring($arg,"binlog-format=row")) + $used_binlog_format= "mixed"; # Default value for binlog format + + foreach my $arg ( @opt_extra_mysqld_opt ) { - $used_binlog_format= "row"; - } - elsif ( defined mtr_match_substring($arg,"binlog-format=stmt")) - { - $used_binlog_format= "stmt"; + if ( $arg =~ /binlog-format=(\S+)/ ) + { + $used_binlog_format= $1; + } } + mtr_report("Using binlog format '$used_binlog_format'"); } - mtr_report("Using binlog format '$used_binlog_format'"); # -------------------------------------------------------------------------- # Check if we should speed up tests by trying to run on tmpfs From 8f118827c431076dbb63a532c5caec346a79bfe7 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Wed, 25 Oct 2006 16:50:06 +0200 Subject: [PATCH 122/131] Skip innodb test if mysqld doesn't have innodb support --- mysql-test/lib/mtr_cases.pl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mysql-test/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl index 17019cfd351..d270d72d526 100644 --- a/mysql-test/lib/mtr_cases.pl +++ b/mysql-test/lib/mtr_cases.pl @@ -554,6 +554,18 @@ sub collect_one_test_case($$$$$$$) { } } + if ( $tinfo->{'innodb_test'} ) + { + # This is a test that need inndob + if ( $::mysqld_variables{'innodb'} eq "FALSE" ) + { + # innodb is not supported, skip it + $tinfo->{'skip'}= 1; + $tinfo->{'comment'}= "No innodb support"; + return; + } + } + } } From c6ee81f0ed159517771c93324b662022e4f421fa Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/myoffice.izhnet.ru" <> Date: Fri, 27 Oct 2006 18:08:50 +0500 Subject: [PATCH 123/131] Fix for bug #23412: delete rows with null date field Backport of the fix for bug #8143: A date with value 0 is treated as a NULL value --- mysql-test/r/delete.result | 11 +++++++++++ mysql-test/t/delete.test | 13 ++++++++++++- sql/sql_delete.cc | 8 ++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/delete.result b/mysql-test/r/delete.result index cb632fcd6c8..7a6af8fd905 100644 --- a/mysql-test/r/delete.result +++ b/mysql-test/r/delete.result @@ -176,3 +176,14 @@ create table t1 (a int); delete `4.t1` from t1 as `4.t1` where `4.t1`.a = 5; delete FROM `4.t1` USING t1 as `4.t1` where `4.t1`.a = 5; drop table t1; +create table t1(a date not null); +insert into t1 values (0); +select * from t1 where a is null; +a +0000-00-00 +delete from t1 where a is null; +select count(*) from t1; +count(*) +0 +drop table t1; +End of 4.1 tests diff --git a/mysql-test/t/delete.test b/mysql-test/t/delete.test index d4eb01cab23..2036b59d810 100644 --- a/mysql-test/t/delete.test +++ b/mysql-test/t/delete.test @@ -163,4 +163,15 @@ delete `4.t1` from t1 as `4.t1` where `4.t1`.a = 5; delete FROM `4.t1` USING t1 as `4.t1` where `4.t1`.a = 5; drop table t1; -# End of 4.1 tests +# +# Bug #8143: deleting '0000-00-00' values using IS NULL +# + +create table t1(a date not null); +insert into t1 values (0); +select * from t1 where a is null; +delete from t1 where a is null; +select count(*) from t1; +drop table t1; + +--echo End of 4.1 tests diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index b085d37be78..c1455c4b668 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -79,6 +79,14 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, /* Handler didn't support fast delete; Delete rows one by one */ } + if (conds) + { + Item::cond_result result; + conds= remove_eq_conds(thd, conds, &result); + if (result == Item::COND_FALSE) // Impossible where + limit= 0; + } + table->used_keys.clear_all(); table->quick_keys.clear_all(); // Can't use 'only index' select=make_select(table,0,0,conds,&error); From abc1c054497c5718379529e4d9d7a80bfc81e28e Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)" <> Date: Fri, 27 Oct 2006 15:57:00 +0200 Subject: [PATCH 124/131] Update the rules for abi_check --- include/Makefile.am | 28 +- include/{mysql_h_abi.ic => mysql_h.ic} | 840 ++++++++----------------- 2 files changed, 267 insertions(+), 601 deletions(-) rename include/{mysql_h_abi.ic => mysql_h.ic} (70%) diff --git a/include/Makefile.am b/include/Makefile.am index dc30d40a352..a17ef377e78 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -15,14 +15,14 @@ # Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, # MA 02111-1307, USA -BUILT_SOURCES = mysql_version.h m_ctype.h my_config.h mysql_h.ic +BUILT_SOURCES = mysql_version.h my_config.h abi_check pkginclude_HEADERS = my_dbug.h m_string.h my_sys.h my_list.h my_xml.h \ mysql.h mysql_com.h mysqld_error.h mysql_embed.h \ my_semaphore.h my_pthread.h my_no_pthread.h raid.h \ errmsg.h my_global.h my_net.h my_alloc.h \ my_getopt.h sslopt-longopts.h my_dir.h typelib.h \ sslopt-vars.h sslopt-case.h sql_common.h keycache.h \ - sql_state.h mysql_time.h $(BUILT_SOURCES) + sql_state.h mysql_time.h m_ctype.h $(BUILT_SOURCES) noinst_HEADERS = config-win.h config-os2.h config-netware.h \ nisam.h heap.h merge.h my_bitmap.h\ myisam.h myisampack.h myisammrg.h ft_global.h\ @@ -32,7 +32,8 @@ noinst_HEADERS = config-win.h config-os2.h config-netware.h \ thr_lock.h t_ctype.h violite.h md5.h \ mysql_version.h.in my_handler.h my_time.h -CLEANFILES = mysql_h.ic +CLEANFILES = abi_check +EXTRA_DIST = mysql_h.ic # mysql_version.h are generated SUPERCLEANFILES = mysql_version.h my_config.h $(CLEANFILES) @@ -61,22 +62,17 @@ dist-hook: # Rules for checking that ABI has not changed # -# Create a icheck file for mysql.h -mysql_h.ic: mysql.h - @set -x; \ +# Create a icheck file and compare it to the reference +abi_check: mysql.h mysql_version.h mysql_com.h mysql_time.h my_list.h \ + my_alloc.h typelib.h + @set -ex; \ if [ @ICHECK@ != no ] ; then \ - @ICHECK@ --canonify -o $@ mysql.h; \ - fi; - -# Compare the icheck file to the reference -check_abi: mysql_h.ic - @set -x; \ - if [ @ICHECK@ != no ] ; then \ - @ICHECK@ --compare mysql_h.ic mysql_h_abi.ic; \ + @ICHECK@ --canonify --skip-from-re /usr/ -o $@.ic mysql.h; \ + @ICHECK@ --compare mysql_h.ic $@.ic; \ fi; \ - touch check_abi; + touch abi_check; -all: check_abi +all: abi_check # Don't update the files from bitkeeper diff --git a/include/mysql_h_abi.ic b/include/mysql_h.ic similarity index 70% rename from include/mysql_h_abi.ic rename to include/mysql_h.ic index 80d13199a8d..30ef44a1ccb 100644 --- a/include/mysql_h_abi.ic +++ b/include/mysql_h.ic @@ -1,5 +1,3 @@ -struct __pthread_internal_slist; -struct __pthread_mutex_s; struct rand_struct; struct st_list; struct st_mem_root; @@ -20,8 +18,6 @@ struct st_typelib; struct st_udf_args; struct st_udf_init; struct st_used_mem; -struct timespec; -struct timeval; enum Item_result; enum enum_field_types; enum enum_mysql_set_option; @@ -34,37 +30,29 @@ enum mysql_option; enum mysql_protocol_type; enum mysql_rpl_type; enum mysql_status; -# 59 "/usr/include/bits/types.h" -typedef long long int __quad_t; -# 135 "mysql.h" +# 131 "mysql.h" typedef struct st_mysql_rows MYSQL_ROWS; -# 55 "/usr/include/sys/select.h" -typedef long int __fd_mask; -# 145 "/usr/include/bits/types.h" -typedef __quad_t __off64_t; -# 60 "/usr/include/bits/types.h" -typedef unsigned long long int __u_quad_t; # 24 "my_list.h" typedef struct st_list LIST; -# 236 "mysql.h" +# 232 "mysql.h" typedef struct st_mysql MYSQL; -# 575 "mysql.h" +# 571 "mysql.h" typedef struct st_mysql_bind MYSQL_BIND; -# 97 "mysql.h" +# 93 "mysql.h" typedef struct st_mysql_field MYSQL_FIELD; -# 121 "mysql.h" +# 117 "mysql.h" typedef unsigned int MYSQL_FIELD_OFFSET; -# 327 "mysql.h" +# 323 "mysql.h" typedef struct st_mysql_manager MYSQL_MANAGER; -# 341 "mysql.h" +# 337 "mysql.h" typedef struct st_mysql_parameters MYSQL_PARAMETERS; -# 296 "mysql.h" +# 292 "mysql.h" typedef struct st_mysql_res MYSQL_RES; -# 120 "mysql.h" +# 116 "mysql.h" typedef char * * MYSQL_ROW; -# 141 "mysql.h" +# 137 "mysql.h" typedef MYSQL_ROWS * MYSQL_ROW_OFFSET; -# 600 "mysql.h" +# 596 "mysql.h" typedef struct st_mysql_stmt MYSQL_STMT; # 151 "mysql_com.h" typedef struct st_net NET; @@ -72,86 +60,21 @@ typedef struct st_net NET; typedef struct st_typelib TYPELIB; # 141 "mysql_com.h" typedef struct st_vio Vio; -# 172 "/usr/include/bits/types.h" -typedef long int __blkcnt_t; -# 189 "/usr/include/bits/types.h" -typedef char * __caddr_t; -# 161 "/usr/include/bits/types.h" -typedef int __clockid_t; -# 156 "/usr/include/bits/types.h" -typedef int __daddr_t; -# 137 "/usr/include/bits/types.h" -typedef __u_quad_t __dev_t; -# 176 "/usr/include/bits/types.h" -typedef unsigned long int __fsblkcnt_t; -# 180 "/usr/include/bits/types.h" -typedef unsigned long int __fsfilcnt_t; -# 147 "/usr/include/bits/types.h" -typedef struct __attribute__((aligned(__alignof__(int)))) - { - int __val[2]; - } __fsid_t; -# 139 "/usr/include/bits/types.h" -typedef unsigned int __gid_t; -# 151 "/usr/include/bits/types.h" -typedef unsigned int __id_t; -# 140 "/usr/include/bits/types.h" -typedef unsigned long int __ino_t; -# 158 "/usr/include/bits/types.h" -typedef int __key_t; -# 187 "/usr/include/bits/types.h" -typedef __off64_t __loff_t; -# 142 "/usr/include/bits/types.h" -typedef unsigned int __mode_t; -# 143 "/usr/include/bits/types.h" -typedef unsigned int __nlink_t; -# 144 "/usr/include/bits/types.h" -typedef long int __off_t; -# 146 "/usr/include/bits/types.h" -typedef int __pid_t; -# 28 "/usr/include/bits/sigset.h" -typedef struct __attribute__((aligned(__alignof__(unsigned long int)))) - { - unsigned long int __val[(1024 / (8 * sizeof(unsigned long int)))]; - } __sigset_t; -# 183 "/usr/include/bits/types.h" -typedef int __ssize_t; -# 154 "/usr/include/bits/types.h" -typedef long int __suseconds_t; -# 152 "/usr/include/bits/types.h" -typedef long int __time_t; -# 164 "/usr/include/bits/types.h" -typedef void * __timer_t; -# 34 "/usr/include/bits/types.h" -typedef unsigned char __u_char; -# 36 "/usr/include/bits/types.h" -typedef unsigned int __u_int; -# 37 "/usr/include/bits/types.h" -typedef unsigned long int __u_long; -# 35 "/usr/include/bits/types.h" -typedef unsigned short int __u_short; -# 138 "/usr/include/bits/types.h" -typedef unsigned int __uid_t; -# 67 "/usr/include/sys/select.h" -typedef struct __attribute__((aligned(__alignof__(long int)))) - { - __fd_mask __fds_bits[(1024 / (8 * sizeof(__fd_mask)))]; - } fd_set; -# 61 "mysql.h" +# 57 "mysql.h" typedef char * gptr; # 29 "my_list.h" typedef int (* list_walk_action)(void *, void *); -# 52 "mysql.h" +# 48 "mysql.h" typedef char my_bool; -# 67 "mysql.h" +# 63 "mysql.h" typedef int my_socket; -# 129 "mysql.h" +# 125 "mysql.h" typedef unsigned long long int my_ulonglong; # 35 "my_alloc.h" typedef struct st_mem_root MEM_ROOT; -# 145 "mysql.h" +# 141 "mysql.h" typedef struct st_mysql_data MYSQL_DATA; -# 652 "mysql.h" +# 648 "mysql.h" typedef struct st_mysql_methods MYSQL_METHODS; # 48 "mysql_time.h" typedef struct st_mysql_time MYSQL_TIME; @@ -161,237 +84,6 @@ typedef struct st_udf_args UDF_ARGS; typedef struct st_udf_init UDF_INIT; # 27 "my_alloc.h" typedef struct st_used_mem USED_MEM; -# 173 "/usr/include/bits/types.h" -typedef __quad_t __blkcnt64_t; -# 167 "/usr/include/bits/types.h" -typedef long int __blksize_t; -# 148 "/usr/include/bits/types.h" -typedef long int __clock_t; -# 177 "/usr/include/bits/types.h" -typedef __u_quad_t __fsblkcnt64_t; -# 181 "/usr/include/bits/types.h" -typedef __u_quad_t __fsfilcnt64_t; -# 141 "/usr/include/bits/types.h" -typedef __u_quad_t __ino64_t; -# 42 "/usr/include/bits/types.h" -typedef short int __int16_t; -# 44 "/usr/include/bits/types.h" -typedef int __int32_t; -# 50 "/usr/include/bits/types.h" -typedef long long int __int64_t; -# 40 "/usr/include/bits/types.h" -typedef signed char __int8_t; -# 192 "/usr/include/bits/types.h" -typedef int __intptr_t; -# 46 "/usr/include/bits/pthreadtypes.h" -typedef struct __pthread_internal_slist __pthread_slist_t; -# 188 "/usr/include/bits/types.h" -typedef __quad_t * __qaddr_t; -# 150 "/usr/include/bits/types.h" -typedef __u_quad_t __rlim64_t; -# 149 "/usr/include/bits/types.h" -typedef unsigned long int __rlim_t; -# 23 "/usr/include/bits/sigset.h" -typedef int __sig_atomic_t; -# 195 "/usr/include/bits/types.h" -typedef unsigned int __socklen_t; -# 157 "/usr/include/bits/types.h" -typedef long int __swblk_t; -# 43 "/usr/include/bits/types.h" -typedef unsigned short int __uint16_t; -# 45 "/usr/include/bits/types.h" -typedef unsigned int __uint32_t; -# 51 "/usr/include/bits/types.h" -typedef unsigned long long int __uint64_t; -# 41 "/usr/include/bits/types.h" -typedef unsigned char __uint8_t; -# 153 "/usr/include/bits/types.h" -typedef unsigned int __useconds_t; -# 235 "/usr/include/sys/types.h" -typedef __blkcnt_t blkcnt_t; -# 117 "/usr/include/sys/types.h" -typedef __caddr_t caddr_t; -# 93 "/usr/include/time.h" -typedef __clockid_t clockid_t; -# 116 "/usr/include/sys/types.h" -typedef __daddr_t daddr_t; -# 62 "/usr/include/sys/types.h" -typedef __dev_t dev_t; -# 85 "/usr/include/sys/select.h" -typedef __fd_mask fd_mask; -# 239 "/usr/include/sys/types.h" -typedef __fsblkcnt_t fsblkcnt_t; -# 243 "/usr/include/sys/types.h" -typedef __fsfilcnt_t fsfilcnt_t; -# 41 "/usr/include/sys/types.h" -typedef __fsid_t fsid_t; -# 67 "/usr/include/sys/types.h" -typedef __gid_t gid_t; -# 105 "/usr/include/sys/types.h" -typedef __id_t id_t; -# 50 "/usr/include/sys/types.h" -typedef __ino_t ino_t; -# 196 "/usr/include/sys/types.h" -typedef int int16_t; -# 197 "/usr/include/sys/types.h" -typedef int int32_t; -# 198 "/usr/include/sys/types.h" -typedef int int64_t; -# 195 "/usr/include/sys/types.h" -typedef int int8_t; -# 123 "/usr/include/sys/types.h" -typedef __key_t key_t; -# 46 "/usr/include/sys/types.h" -typedef __loff_t loff_t; -# 72 "/usr/include/sys/types.h" -typedef __mode_t mode_t; -# 77 "/usr/include/sys/types.h" -typedef __nlink_t nlink_t; -# 88 "/usr/include/sys/types.h" -typedef __off_t off_t; -# 100 "/usr/include/sys/types.h" -typedef __pid_t pid_t; -# 39 "/usr/include/bits/pthreadtypes.h" -typedef union __attribute__((aligned(__alignof__(long int)))) - { - char __size[36]; - long int __align; - } pthread_attr_t; -# 153 "/usr/include/bits/pthreadtypes.h" -typedef union __attribute__((aligned(__alignof__(long int)))) - { - char __size[20]; - long int __align; - } pthread_barrier_t; -# 159 "/usr/include/bits/pthreadtypes.h" -typedef union __attribute__((aligned(__alignof__(int)))) - { - char __size[4]; - int __align; - } pthread_barrierattr_t; -# 84 "/usr/include/bits/pthreadtypes.h" -typedef union __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__alignof__(void *)))) - { - struct __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__alignof__(void *)))) - { - int __lock; - unsigned int __futex; - unsigned long long int __total_seq; - unsigned long long int __wakeup_seq; - unsigned long long int __woken_seq; - void * __mutex; - unsigned int __nwaiters; - unsigned int __broadcast_seq; - } __data; - char __size[48]; - long long int __align; - } pthread_cond_t; -# 101 "/usr/include/bits/pthreadtypes.h" -typedef union __attribute__((aligned(__alignof__(long int)))) - { - char __size[4]; - long int __align; - } pthread_condattr_t; -# 109 "/usr/include/bits/pthreadtypes.h" -typedef unsigned int pthread_key_t; -# 54 "/usr/include/bits/pthreadtypes.h" -typedef union __attribute__((aligned(__alignof__(long int)))) - { - struct __pthread_mutex_s __data; - char __size[24]; - long int __align; - } pthread_mutex_t; -# 75 "/usr/include/bits/pthreadtypes.h" -typedef union __attribute__((aligned(__alignof__(long int)))) - { - char __size[4]; - long int __align; - } pthread_mutexattr_t; -# 113 "/usr/include/bits/pthreadtypes.h" -typedef int pthread_once_t; -# 119 "/usr/include/bits/pthreadtypes.h" -typedef union __attribute__((aligned(__alignof__(long int)))) - { - struct __attribute__((aligned(__alignof__(int)))) - { - int __lock; - unsigned int __nr_readers; - unsigned int __readers_wakeup; - unsigned int __writer_wakeup; - unsigned int __nr_readers_queued; - unsigned int __nr_writers_queued; - unsigned int __flags; - int __writer; - } __data; - char __size[32]; - long int __align; - } pthread_rwlock_t; -# 138 "/usr/include/bits/pthreadtypes.h" -typedef union __attribute__((aligned(__alignof__(long int)))) - { - char __size[8]; - long int __align; - } pthread_rwlockattr_t; -# 148 "/usr/include/bits/pthreadtypes.h" -typedef int volatile pthread_spinlock_t; -# 36 "/usr/include/bits/pthreadtypes.h" -typedef unsigned long int pthread_t; -# 39 "/usr/include/sys/types.h" -typedef __quad_t quad_t; -# 206 "/usr/include/sys/types.h" -typedef int register_t; -# 38 "/usr/include/sys/select.h" -typedef __sigset_t sigset_t; -# 214 "/usr/lib/gcc/i386-redhat-linux/4.0.2/include/stddef.h" -typedef unsigned int size_t; -# 110 "/usr/include/sys/types.h" -typedef __ssize_t ssize_t; -# 49 "/usr/include/sys/select.h" -typedef __suseconds_t suseconds_t; -# 77 "/usr/include/time.h" -typedef __time_t time_t; -# 105 "/usr/include/time.h" -typedef __timer_t timer_t; -# 35 "/usr/include/sys/types.h" -typedef __u_char u_char; -# 37 "/usr/include/sys/types.h" -typedef __u_int u_int; -# 202 "/usr/include/sys/types.h" -typedef unsigned int u_int16_t; -# 203 "/usr/include/sys/types.h" -typedef unsigned int u_int32_t; -# 204 "/usr/include/sys/types.h" -typedef unsigned int u_int64_t; -# 201 "/usr/include/sys/types.h" -typedef unsigned int u_int8_t; -# 38 "/usr/include/sys/types.h" -typedef __u_long u_long; -# 40 "/usr/include/sys/types.h" -typedef __u_quad_t u_quad_t; -# 36 "/usr/include/sys/types.h" -typedef __u_short u_short; -# 82 "/usr/include/sys/types.h" -typedef __uid_t uid_t; -# 153 "/usr/include/sys/types.h" -typedef unsigned int uint; -# 151 "/usr/include/sys/types.h" -typedef unsigned long int ulong; -# 152 "/usr/include/sys/types.h" -typedef unsigned short int ushort; -# 46 "/usr/include/bits/pthreadtypes.h" -struct __attribute__((aligned(__alignof__(void *)))) __pthread_internal_slist - { - struct __pthread_internal_slist * __next; - }; -# 54 "/usr/include/bits/pthreadtypes.h" -struct __attribute__((aligned(__alignof__(int)))) __pthread_mutex_s - { - int __lock; - unsigned int __count; - int __owner; - int __kind; - unsigned int __nusers; - }; # 302 "mysql_com.h" struct __attribute__((aligned(__alignof__(unsigned long int)), aligned(__alignof__(double)))) rand_struct { @@ -419,7 +111,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned unsigned int first_block_usage; void (* error_handler)(void); }; -# 236 "mysql.h" +# 232 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long long int)))) st_mysql { NET net; @@ -464,7 +156,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned my_bool * unbuffered_fetch_owner; struct st_mysql_stmt * current_stmt; }; -# 575 "mysql.h" +# 571 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_mysql_bind { unsigned long int * length; @@ -484,7 +176,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned void (* fetch_result)(struct st_mysql_bind *, unsigned char * * row); void (* skip_result)(struct st_mysql_bind *, MYSQL_FIELD *, unsigned char * * row); }; -# 145 "mysql.h" +# 141 "mysql.h" struct __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__alignof__(void *)))) st_mysql_data { my_ulonglong rows; @@ -493,7 +185,7 @@ struct __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__al MEM_ROOT alloc; MYSQL_ROWS * * prev_ptr; }; -# 97 "mysql.h" +# 93 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_mysql_field { char * name; @@ -517,7 +209,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned unsigned int charsetnr; enum enum_field_types type; }; -# 327 "mysql.h" +# 323 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_mysql_manager { NET net; @@ -535,7 +227,7 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned int net_buf_size; char last_error[256]; }; -# 652 "mysql.h" +# 648 "mysql.h" struct __attribute__((aligned(__alignof__(void *)))) st_mysql_methods { my_bool (* read_query_result)(MYSQL * mysql); @@ -554,7 +246,7 @@ struct __attribute__((aligned(__alignof__(void *)))) st_mysql_methods my_bool (* next_result)(MYSQL * mysql); int (* read_change_user_result)(MYSQL * mysql, char * buff, char const * passwd); }; -# 166 "mysql.h" +# 162 "mysql.h" struct __attribute__((aligned(__alignof__(unsigned long int)), aligned(__alignof__(void *)))) st_mysql_options { unsigned int connect_timeout; @@ -596,13 +288,13 @@ struct __attribute__((aligned(__alignof__(unsigned long int)), aligned(__alignof int (* local_infile_error)(void *, char *, unsigned int); void * local_infile_userdata; }; -# 341 "mysql.h" +# 337 "mysql.h" struct __attribute__((aligned(__alignof__(void *)))) st_mysql_parameters { unsigned long int * p_max_allowed_packet; unsigned long int * p_net_buffer_length; }; -# 296 "mysql.h" +# 292 "mysql.h" struct __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__alignof__(void *)))) st_mysql_res { my_ulonglong row_count; @@ -620,14 +312,14 @@ struct __attribute__((aligned(__alignof__(unsigned long long int)), aligned(__al my_bool unbuffered_fetch_cancelled; struct st_mysql_methods const * methods; }; -# 135 "mysql.h" +# 131 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long int)))) st_mysql_rows { struct st_mysql_rows * next; MYSQL_ROW data; unsigned long int length; }; -# 600 "mysql.h" +# 596 "mysql.h" struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned long long int)))) st_mysql_stmt { MEM_ROOT mem_root; @@ -734,18 +426,6 @@ struct __attribute__((aligned(__alignof__(void *)), aligned(__alignof__(unsigned unsigned int left; unsigned int size; }; -# 121 "/usr/include/time.h" -struct __attribute__((aligned(__alignof__(long int)))) timespec - { - __time_t tv_sec; - long int tv_nsec; - }; -# 69 "/usr/include/bits/time.h" -struct __attribute__((aligned(__alignof__(long int)))) timeval - { - __time_t tv_sec; - __suseconds_t tv_usec; - }; # 313 "mysql_com.h" enum Item_result { @@ -788,7 +468,7 @@ enum enum_mysql_set_option MYSQL_OPTION_MULTI_STATEMENTS_ON = 0, MYSQL_OPTION_MULTI_STATEMENTS_OFF = 1, }; -# 567 "mysql.h" +# 563 "mysql.h" enum enum_mysql_stmt_state { MYSQL_STMT_INIT_DONE = 1, @@ -838,7 +518,7 @@ enum enum_server_command COM_SET_OPTION = 27, COM_END = 28, }; -# 639 "mysql.h" +# 635 "mysql.h" enum enum_stmt_attr_type { STMT_ATTR_UPDATE_MAX_LENGTH = 0, @@ -854,7 +534,7 @@ enum mysql_enum_shutdown_level SHUTDOWN_WAIT_CRITICAL_BUFFERS = (((unsigned char)((1 << 3)) << 1) + 1), KILL_CONNECTION = 255, }; -# 155 "mysql.h" +# 151 "mysql.h" enum mysql_option { MYSQL_OPT_CONNECT_TIMEOUT = 0, @@ -877,7 +557,7 @@ enum mysql_option MYSQL_SET_CLIENT_IP = 17, MYSQL_SECURE_AUTH = 18, }; -# 218 "mysql.h" +# 214 "mysql.h" enum mysql_protocol_type { MYSQL_PROTOCOL_DEFAULT = 0, @@ -886,14 +566,14 @@ enum mysql_protocol_type MYSQL_PROTOCOL_PIPE = 3, MYSQL_PROTOCOL_MEMORY = 4, }; -# 228 "mysql.h" +# 224 "mysql.h" enum mysql_rpl_type { MYSQL_RPL_MASTER = 0, MYSQL_RPL_SLAVE = 1, MYSQL_RPL_ADMIN = 2, }; -# 213 "mysql.h" +# 209 "mysql.h" enum mysql_status { MYSQL_STATUS_READY = 0, @@ -916,12 +596,6 @@ extern void get_salt_from_password_323(unsigned long int * res, char const * pas extern char * get_tty_password(char * opt_message); # 30 "typelib.h" extern char const * get_type(TYPELIB * typelib, unsigned int); -# 41 "/usr/include/sys/sysmacros.h" -extern unsigned int gnu_dev_major(unsigned long long int); -# 53 "/usr/include/sys/sysmacros.h" -extern unsigned long long int gnu_dev_makedev(unsigned int, unsigned int); -# 47 "/usr/include/sys/sysmacros.h" -extern unsigned int gnu_dev_minor(unsigned long long int); # 355 "mysql_com.h" extern void hash_password(unsigned long int * to, char const * password, unsigned int); # 31 "my_list.h" @@ -968,253 +642,253 @@ extern double my_rnd(struct rand_struct *); extern void my_thread_end(void); # 380 "mysql_com.h" extern my_bool my_thread_init(void); -# 543 "mysql.h" +# 539 "mysql.h" extern void myodbc_remove_escape(MYSQL * mysql, char * name); -# 485 "mysql.h" +# 481 "mysql.h" extern int mysql_add_slave(MYSQL * mysql, char const * host, unsigned int, char const * user, char const * passwd); -# 397 "mysql.h" +# 393 "mysql.h" extern my_ulonglong mysql_affected_rows(MYSQL * mysql); -# 724 "mysql.h" +# 720 "mysql.h" extern my_bool mysql_autocommit(MYSQL * mysql, my_bool); -# 412 "mysql.h" +# 408 "mysql.h" extern my_bool mysql_change_user(MYSQL * mysql, char const * user, char const * passwd, char const * db); -# 405 "mysql.h" +# 401 "mysql.h" extern char const * mysql_character_set_name(MYSQL * mysql); -# 727 "mysql.h" +# 723 "mysql.h" extern void mysql_close(MYSQL * sock); -# 722 "mysql.h" +# 718 "mysql.h" extern my_bool mysql_commit(MYSQL * mysql); -# 514 "mysql.h" +# 510 "mysql.h" extern void mysql_data_seek(MYSQL_RES * result, my_ulonglong); -# 532 "mysql.h" +# 528 "mysql.h" extern void mysql_debug(char const * debug); -# 471 "mysql.h" +# 467 "mysql.h" extern void mysql_disable_reads_from_master(MYSQL * mysql); -# 465 "mysql.h" +# 461 "mysql.h" extern void mysql_disable_rpl_parse(MYSQL * mysql); -# 493 "mysql.h" +# 489 "mysql.h" extern int mysql_dump_debug_info(MYSQL * mysql); -# 545 "mysql.h" +# 541 "mysql.h" extern my_bool mysql_embedded(void); -# 470 "mysql.h" +# 466 "mysql.h" extern void mysql_enable_reads_from_master(MYSQL * mysql); -# 464 "mysql.h" +# 460 "mysql.h" extern void mysql_enable_rpl_parse(MYSQL * mysql); -# 389 "mysql.h" +# 385 "mysql.h" extern my_bool mysql_eof(MYSQL_RES * res); -# 399 "mysql.h" +# 395 "mysql.h" extern unsigned int mysql_errno(MYSQL * mysql); # 373 "mysql_com.h" extern char const * mysql_errno_to_sqlstate(unsigned int); -# 400 "mysql.h" -extern char const * mysql_error(MYSQL * mysql); -# 525 "mysql.h" -extern unsigned long int mysql_escape_string(char * to, char const * from, unsigned long int); -# 522 "mysql.h" -extern MYSQL_FIELD * mysql_fetch_field(MYSQL_RES * result); -# 390 "mysql.h" -extern MYSQL_FIELD * mysql_fetch_field_direct(MYSQL_RES * res, unsigned int); -# 392 "mysql.h" -extern MYSQL_FIELD * mysql_fetch_fields(MYSQL_RES * res); -# 521 "mysql.h" -extern unsigned long int * mysql_fetch_lengths(MYSQL_RES * result); -# 520 "mysql.h" -extern MYSQL_ROW mysql_fetch_row(MYSQL_RES * result); # 396 "mysql.h" -extern unsigned int mysql_field_count(MYSQL * mysql); +extern char const * mysql_error(MYSQL * mysql); +# 521 "mysql.h" +extern unsigned long int mysql_escape_string(char * to, char const * from, unsigned long int); # 518 "mysql.h" -extern MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES * result, MYSQL_FIELD_OFFSET); -# 394 "mysql.h" -extern MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES * res); -# 513 "mysql.h" -extern void mysql_free_result(MYSQL_RES * result); -# 503 "mysql.h" -extern char const * mysql_get_client_info(void); -# 504 "mysql.h" -extern unsigned long int mysql_get_client_version(void); -# 505 "mysql.h" -extern char const * mysql_get_host_info(MYSQL * mysql); -# 371 "mysql.h" -extern MYSQL_PARAMETERS * mysql_get_parameters(void); -# 507 "mysql.h" -extern unsigned int mysql_get_proto_info(MYSQL * mysql); -# 502 "mysql.h" -extern char const * mysql_get_server_info(MYSQL * mysql); -# 506 "mysql.h" -extern unsigned long int mysql_get_server_version(MYSQL * mysql); -# 527 "mysql.h" -extern unsigned long int mysql_hex_string(char * to, char const * from, unsigned long int); -# 403 "mysql.h" -extern char const * mysql_info(MYSQL * mysql); -# 408 "mysql.h" -extern MYSQL * mysql_init(MYSQL * mysql); -# 398 "mysql.h" -extern my_ulonglong mysql_insert_id(MYSQL * mysql); -# 496 "mysql.h" -extern int mysql_kill(MYSQL * mysql, unsigned long int); -# 508 "mysql.h" -extern MYSQL_RES * mysql_list_dbs(MYSQL * mysql, char const * wild); -# 523 "mysql.h" -extern MYSQL_RES * mysql_list_fields(MYSQL * mysql, char const * table, char const * wild); -# 510 "mysql.h" -extern MYSQL_RES * mysql_list_processes(MYSQL * mysql); -# 509 "mysql.h" -extern MYSQL_RES * mysql_list_tables(MYSQL * mysql, char const * wild); -# 552 "mysql.h" -extern void mysql_manager_close(MYSQL_MANAGER * con); -# 553 "mysql.h" -extern int mysql_manager_command(MYSQL_MANAGER * con, char const * cmd, int); -# 547 "mysql.h" -extern MYSQL_MANAGER * mysql_manager_connect(MYSQL_MANAGER * con, char const * host, char const * user, char const * passwd, unsigned int); -# 555 "mysql.h" -extern int mysql_manager_fetch_line(MYSQL_MANAGER * con, char * res_buf, int); -# 546 "mysql.h" -extern MYSQL_MANAGER * mysql_manager_init(MYSQL_MANAGER * con); -# 431 "mysql.h" -extern my_bool mysql_master_query(MYSQL * mysql, char const * q, unsigned long int); -# 433 "mysql.h" -extern my_bool mysql_master_send_query(MYSQL * mysql, char const * q, unsigned long int); -# 725 "mysql.h" -extern my_bool mysql_more_results(MYSQL * mysql); -# 726 "mysql.h" -extern int mysql_next_result(MYSQL * mysql); +extern MYSQL_FIELD * mysql_fetch_field(MYSQL_RES * result); +# 386 "mysql.h" +extern MYSQL_FIELD * mysql_fetch_field_direct(MYSQL_RES * res, unsigned int); # 388 "mysql.h" -extern unsigned int mysql_num_fields(MYSQL_RES * res); -# 387 "mysql.h" -extern my_ulonglong mysql_num_rows(MYSQL_RES * res); -# 533 "mysql.h" -extern char * mysql_odbc_escape_string(MYSQL * mysql, char * to, unsigned long int, char const * from, unsigned long int, void * param, char * (* extend_buffer)(void *, char * to, unsigned long int * length)); -# 511 "mysql.h" -extern int mysql_options(MYSQL * mysql, enum mysql_option, char const * arg); -# 500 "mysql.h" -extern int mysql_ping(MYSQL * mysql); -# 79 "mysql.h" -extern unsigned int mysql_port; -# 422 "mysql.h" -extern int mysql_query(MYSQL * mysql, char const * q); -# 558 "mysql.h" -extern my_bool mysql_read_query_result(MYSQL * mysql); -# 473 "mysql.h" -extern my_bool mysql_reads_from_master_enabled(MYSQL * mysql); -# 414 "mysql.h" -extern MYSQL * mysql_real_connect(MYSQL * mysql, char const * host, char const * user, char const * passwd, char const * db, unsigned int, char const * unix_socket, unsigned long int); -# 529 "mysql.h" -extern unsigned long int mysql_real_escape_string(MYSQL * mysql, char * to, char const * from, unsigned long int); -# 425 "mysql.h" -extern int mysql_real_query(MYSQL * mysql, char const * q, unsigned long int); -# 494 "mysql.h" -extern int mysql_refresh(MYSQL * mysql, unsigned int); -# 723 "mysql.h" -extern my_bool mysql_rollback(MYSQL * mysql); +extern MYSQL_FIELD * mysql_fetch_fields(MYSQL_RES * res); +# 517 "mysql.h" +extern unsigned long int * mysql_fetch_lengths(MYSQL_RES * result); # 516 "mysql.h" -extern MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES * result, MYSQL_ROW_OFFSET); -# 393 "mysql.h" -extern MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES * res); -# 467 "mysql.h" -extern int mysql_rpl_parse_enabled(MYSQL * mysql); -# 478 "mysql.h" -extern my_bool mysql_rpl_probe(MYSQL * mysql); -# 475 "mysql.h" -extern enum mysql_rpl_type mysql_rpl_query_type(char const * q, int); -# 421 "mysql.h" -extern int mysql_select_db(MYSQL * mysql, char const * db); -# 423 "mysql.h" -extern int mysql_send_query(MYSQL * mysql, char const * q, unsigned long int); -# 358 "mysql.h" -extern void mysql_server_end(void); -# 357 "mysql.h" -extern int mysql_server_init(int, char * * argv, char * * groups); -# 406 "mysql.h" -extern int mysql_set_character_set(MYSQL * mysql, char const * csname); -# 456 "mysql.h" -extern void mysql_set_local_infile_default(MYSQL * mysql); -# 445 "mysql.h" -extern void mysql_set_local_infile_handler(MYSQL * mysql, int (* local_infile_init)(void * *, char const *, void *), int (* local_infile_read)(void *, char *, unsigned int), void (* local_infile_end)(void), int (* local_infile_error)(void *, char *, unsigned int), void *); -# 481 "mysql.h" -extern int mysql_set_master(MYSQL * mysql, char const * host, unsigned int, char const * user, char const * passwd); -# 497 "mysql.h" -extern int mysql_set_server_option(MYSQL * mysql, enum enum_mysql_set_option); -# 490 "mysql.h" -extern int mysql_shutdown(MYSQL * mysql, enum mysql_enum_shutdown_level); -# 436 "mysql.h" -extern my_bool mysql_slave_query(MYSQL * mysql, char const * q, unsigned long int); -# 438 "mysql.h" -extern my_bool mysql_slave_send_query(MYSQL * mysql, char const * q, unsigned long int); -# 401 "mysql.h" -extern char const * mysql_sqlstate(MYSQL * mysql); -# 409 "mysql.h" -extern my_bool mysql_ssl_set(MYSQL * mysql, char const * key, char const * cert, char const * ca, char const * capath, char const * cipher); +extern MYSQL_ROW mysql_fetch_row(MYSQL_RES * result); +# 392 "mysql.h" +extern unsigned int mysql_field_count(MYSQL * mysql); +# 514 "mysql.h" +extern MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES * result, MYSQL_FIELD_OFFSET); +# 390 "mysql.h" +extern MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES * res); +# 509 "mysql.h" +extern void mysql_free_result(MYSQL_RES * result); +# 499 "mysql.h" +extern char const * mysql_get_client_info(void); +# 500 "mysql.h" +extern unsigned long int mysql_get_client_version(void); # 501 "mysql.h" -extern char const * mysql_stat(MYSQL * mysql); -# 718 "mysql.h" -extern my_ulonglong mysql_stmt_affected_rows(MYSQL_STMT * stmt); -# 696 "mysql.h" -extern my_bool mysql_stmt_attr_get(MYSQL_STMT * stmt, enum enum_stmt_attr_type, void * attr); -# 693 "mysql.h" -extern my_bool mysql_stmt_attr_set(MYSQL_STMT * stmt, enum enum_stmt_attr_type, void const * attr); -# 699 "mysql.h" -extern my_bool mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); -# 700 "mysql.h" -extern my_bool mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); -# 701 "mysql.h" -extern my_bool mysql_stmt_close(MYSQL_STMT * stmt); -# 716 "mysql.h" -extern void mysql_stmt_data_seek(MYSQL_STMT * stmt, my_ulonglong); -# 710 "mysql.h" -extern unsigned int mysql_stmt_errno(MYSQL_STMT * stmt); -# 711 "mysql.h" -extern char const * mysql_stmt_error(MYSQL_STMT * stmt); -# 686 "mysql.h" -extern int mysql_stmt_execute(MYSQL_STMT * stmt); -# 687 "mysql.h" -extern int mysql_stmt_fetch(MYSQL_STMT * stmt); -# 688 "mysql.h" -extern int mysql_stmt_fetch_column(MYSQL_STMT * stmt, MYSQL_BIND * bind, unsigned int, unsigned long int); -# 720 "mysql.h" -extern unsigned int mysql_stmt_field_count(MYSQL_STMT * stmt); -# 703 "mysql.h" -extern my_bool mysql_stmt_free_result(MYSQL_STMT * stmt); -# 683 "mysql.h" -extern MYSQL_STMT * mysql_stmt_init(MYSQL * mysql); -# 719 "mysql.h" -extern my_ulonglong mysql_stmt_insert_id(MYSQL_STMT * stmt); -# 717 "mysql.h" -extern my_ulonglong mysql_stmt_num_rows(MYSQL_STMT * stmt); -# 692 "mysql.h" -extern unsigned long int mysql_stmt_param_count(MYSQL_STMT * stmt); -# 709 "mysql.h" -extern MYSQL_RES * mysql_stmt_param_metadata(MYSQL_STMT * stmt); -# 684 "mysql.h" -extern int mysql_stmt_prepare(MYSQL_STMT * stmt, char const * query, unsigned long int); -# 702 "mysql.h" -extern my_bool mysql_stmt_reset(MYSQL_STMT * stmt); -# 708 "mysql.h" -extern MYSQL_RES * mysql_stmt_result_metadata(MYSQL_STMT * stmt); -# 713 "mysql.h" -extern MYSQL_ROW_OFFSET mysql_stmt_row_seek(MYSQL_STMT * stmt, MYSQL_ROW_OFFSET); -# 715 "mysql.h" -extern MYSQL_ROW_OFFSET mysql_stmt_row_tell(MYSQL_STMT * stmt); -# 704 "mysql.h" -extern my_bool mysql_stmt_send_long_data(MYSQL_STMT * stmt, unsigned int, char const * data, unsigned long int); -# 712 "mysql.h" -extern char const * mysql_stmt_sqlstate(MYSQL_STMT * stmt); -# 691 "mysql.h" -extern int mysql_stmt_store_result(MYSQL_STMT * stmt); -# 427 "mysql.h" -extern MYSQL_RES * mysql_store_result(MYSQL * mysql); -# 380 "mysql.h" -extern void mysql_thread_end(void); +extern char const * mysql_get_host_info(MYSQL * mysql); +# 367 "mysql.h" +extern MYSQL_PARAMETERS * mysql_get_parameters(void); +# 503 "mysql.h" +extern unsigned int mysql_get_proto_info(MYSQL * mysql); +# 498 "mysql.h" +extern char const * mysql_get_server_info(MYSQL * mysql); +# 502 "mysql.h" +extern unsigned long int mysql_get_server_version(MYSQL * mysql); +# 523 "mysql.h" +extern unsigned long int mysql_hex_string(char * to, char const * from, unsigned long int); +# 399 "mysql.h" +extern char const * mysql_info(MYSQL * mysql); # 404 "mysql.h" -extern unsigned long int mysql_thread_id(MYSQL * mysql); -# 379 "mysql.h" -extern my_bool mysql_thread_init(void); -# 544 "mysql.h" -extern unsigned int mysql_thread_safe(void); -# 80 "mysql.h" -extern char * mysql_unix_port; -# 428 "mysql.h" -extern MYSQL_RES * mysql_use_result(MYSQL * mysql); +extern MYSQL * mysql_init(MYSQL * mysql); +# 394 "mysql.h" +extern my_ulonglong mysql_insert_id(MYSQL * mysql); +# 492 "mysql.h" +extern int mysql_kill(MYSQL * mysql, unsigned long int); +# 504 "mysql.h" +extern MYSQL_RES * mysql_list_dbs(MYSQL * mysql, char const * wild); +# 519 "mysql.h" +extern MYSQL_RES * mysql_list_fields(MYSQL * mysql, char const * table, char const * wild); +# 506 "mysql.h" +extern MYSQL_RES * mysql_list_processes(MYSQL * mysql); +# 505 "mysql.h" +extern MYSQL_RES * mysql_list_tables(MYSQL * mysql, char const * wild); +# 548 "mysql.h" +extern void mysql_manager_close(MYSQL_MANAGER * con); +# 549 "mysql.h" +extern int mysql_manager_command(MYSQL_MANAGER * con, char const * cmd, int); +# 543 "mysql.h" +extern MYSQL_MANAGER * mysql_manager_connect(MYSQL_MANAGER * con, char const * host, char const * user, char const * passwd, unsigned int); +# 551 "mysql.h" +extern int mysql_manager_fetch_line(MYSQL_MANAGER * con, char * res_buf, int); +# 542 "mysql.h" +extern MYSQL_MANAGER * mysql_manager_init(MYSQL_MANAGER * con); +# 427 "mysql.h" +extern my_bool mysql_master_query(MYSQL * mysql, char const * q, unsigned long int); +# 429 "mysql.h" +extern my_bool mysql_master_send_query(MYSQL * mysql, char const * q, unsigned long int); +# 721 "mysql.h" +extern my_bool mysql_more_results(MYSQL * mysql); +# 722 "mysql.h" +extern int mysql_next_result(MYSQL * mysql); +# 384 "mysql.h" +extern unsigned int mysql_num_fields(MYSQL_RES * res); +# 383 "mysql.h" +extern my_ulonglong mysql_num_rows(MYSQL_RES * res); +# 529 "mysql.h" +extern char * mysql_odbc_escape_string(MYSQL * mysql, char * to, unsigned long int, char const * from, unsigned long int, void * param, char * (* extend_buffer)(void *, char * to, unsigned long int * length)); +# 507 "mysql.h" +extern int mysql_options(MYSQL * mysql, enum mysql_option, char const * arg); +# 496 "mysql.h" +extern int mysql_ping(MYSQL * mysql); +# 75 "mysql.h" +extern unsigned int mysql_port; +# 418 "mysql.h" +extern int mysql_query(MYSQL * mysql, char const * q); +# 554 "mysql.h" +extern my_bool mysql_read_query_result(MYSQL * mysql); +# 469 "mysql.h" +extern my_bool mysql_reads_from_master_enabled(MYSQL * mysql); +# 410 "mysql.h" +extern MYSQL * mysql_real_connect(MYSQL * mysql, char const * host, char const * user, char const * passwd, char const * db, unsigned int, char const * unix_socket, unsigned long int); +# 525 "mysql.h" +extern unsigned long int mysql_real_escape_string(MYSQL * mysql, char * to, char const * from, unsigned long int); +# 421 "mysql.h" +extern int mysql_real_query(MYSQL * mysql, char const * q, unsigned long int); +# 490 "mysql.h" +extern int mysql_refresh(MYSQL * mysql, unsigned int); +# 719 "mysql.h" +extern my_bool mysql_rollback(MYSQL * mysql); +# 512 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES * result, MYSQL_ROW_OFFSET); +# 389 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES * res); +# 463 "mysql.h" +extern int mysql_rpl_parse_enabled(MYSQL * mysql); +# 474 "mysql.h" +extern my_bool mysql_rpl_probe(MYSQL * mysql); +# 471 "mysql.h" +extern enum mysql_rpl_type mysql_rpl_query_type(char const * q, int); +# 417 "mysql.h" +extern int mysql_select_db(MYSQL * mysql, char const * db); +# 419 "mysql.h" +extern int mysql_send_query(MYSQL * mysql, char const * q, unsigned long int); +# 354 "mysql.h" +extern void mysql_server_end(void); +# 353 "mysql.h" +extern int mysql_server_init(int, char * * argv, char * * groups); # 402 "mysql.h" +extern int mysql_set_character_set(MYSQL * mysql, char const * csname); +# 452 "mysql.h" +extern void mysql_set_local_infile_default(MYSQL * mysql); +# 441 "mysql.h" +extern void mysql_set_local_infile_handler(MYSQL * mysql, int (* local_infile_init)(void * *, char const *, void *), int (* local_infile_read)(void *, char *, unsigned int), void (* local_infile_end)(void), int (* local_infile_error)(void *, char *, unsigned int), void *); +# 477 "mysql.h" +extern int mysql_set_master(MYSQL * mysql, char const * host, unsigned int, char const * user, char const * passwd); +# 493 "mysql.h" +extern int mysql_set_server_option(MYSQL * mysql, enum enum_mysql_set_option); +# 486 "mysql.h" +extern int mysql_shutdown(MYSQL * mysql, enum mysql_enum_shutdown_level); +# 432 "mysql.h" +extern my_bool mysql_slave_query(MYSQL * mysql, char const * q, unsigned long int); +# 434 "mysql.h" +extern my_bool mysql_slave_send_query(MYSQL * mysql, char const * q, unsigned long int); +# 397 "mysql.h" +extern char const * mysql_sqlstate(MYSQL * mysql); +# 405 "mysql.h" +extern my_bool mysql_ssl_set(MYSQL * mysql, char const * key, char const * cert, char const * ca, char const * capath, char const * cipher); +# 497 "mysql.h" +extern char const * mysql_stat(MYSQL * mysql); +# 714 "mysql.h" +extern my_ulonglong mysql_stmt_affected_rows(MYSQL_STMT * stmt); +# 692 "mysql.h" +extern my_bool mysql_stmt_attr_get(MYSQL_STMT * stmt, enum enum_stmt_attr_type, void * attr); +# 689 "mysql.h" +extern my_bool mysql_stmt_attr_set(MYSQL_STMT * stmt, enum enum_stmt_attr_type, void const * attr); +# 695 "mysql.h" +extern my_bool mysql_stmt_bind_param(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +# 696 "mysql.h" +extern my_bool mysql_stmt_bind_result(MYSQL_STMT * stmt, MYSQL_BIND * bnd); +# 697 "mysql.h" +extern my_bool mysql_stmt_close(MYSQL_STMT * stmt); +# 712 "mysql.h" +extern void mysql_stmt_data_seek(MYSQL_STMT * stmt, my_ulonglong); +# 706 "mysql.h" +extern unsigned int mysql_stmt_errno(MYSQL_STMT * stmt); +# 707 "mysql.h" +extern char const * mysql_stmt_error(MYSQL_STMT * stmt); +# 682 "mysql.h" +extern int mysql_stmt_execute(MYSQL_STMT * stmt); +# 683 "mysql.h" +extern int mysql_stmt_fetch(MYSQL_STMT * stmt); +# 684 "mysql.h" +extern int mysql_stmt_fetch_column(MYSQL_STMT * stmt, MYSQL_BIND * bind, unsigned int, unsigned long int); +# 716 "mysql.h" +extern unsigned int mysql_stmt_field_count(MYSQL_STMT * stmt); +# 699 "mysql.h" +extern my_bool mysql_stmt_free_result(MYSQL_STMT * stmt); +# 679 "mysql.h" +extern MYSQL_STMT * mysql_stmt_init(MYSQL * mysql); +# 715 "mysql.h" +extern my_ulonglong mysql_stmt_insert_id(MYSQL_STMT * stmt); +# 713 "mysql.h" +extern my_ulonglong mysql_stmt_num_rows(MYSQL_STMT * stmt); +# 688 "mysql.h" +extern unsigned long int mysql_stmt_param_count(MYSQL_STMT * stmt); +# 705 "mysql.h" +extern MYSQL_RES * mysql_stmt_param_metadata(MYSQL_STMT * stmt); +# 680 "mysql.h" +extern int mysql_stmt_prepare(MYSQL_STMT * stmt, char const * query, unsigned long int); +# 698 "mysql.h" +extern my_bool mysql_stmt_reset(MYSQL_STMT * stmt); +# 704 "mysql.h" +extern MYSQL_RES * mysql_stmt_result_metadata(MYSQL_STMT * stmt); +# 709 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_stmt_row_seek(MYSQL_STMT * stmt, MYSQL_ROW_OFFSET); +# 711 "mysql.h" +extern MYSQL_ROW_OFFSET mysql_stmt_row_tell(MYSQL_STMT * stmt); +# 700 "mysql.h" +extern my_bool mysql_stmt_send_long_data(MYSQL_STMT * stmt, unsigned int, char const * data, unsigned long int); +# 708 "mysql.h" +extern char const * mysql_stmt_sqlstate(MYSQL_STMT * stmt); +# 687 "mysql.h" +extern int mysql_stmt_store_result(MYSQL_STMT * stmt); +# 423 "mysql.h" +extern MYSQL_RES * mysql_store_result(MYSQL * mysql); +# 376 "mysql.h" +extern void mysql_thread_end(void); +# 400 "mysql.h" +extern unsigned long int mysql_thread_id(MYSQL * mysql); +# 375 "mysql.h" +extern my_bool mysql_thread_init(void); +# 540 "mysql.h" +extern unsigned int mysql_thread_safe(void); +# 76 "mysql.h" +extern char * mysql_unix_port; +# 424 "mysql.h" +extern MYSQL_RES * mysql_use_result(MYSQL * mysql); +# 398 "mysql.h" extern unsigned int mysql_warning_count(MYSQL * mysql); # 284 "mysql_com.h" extern void net_clear(NET * net); @@ -1226,19 +900,15 @@ extern my_bool net_flush(NET * net); extern int net_real_write(NET * net, char const * packet, unsigned long int); # 285 "mysql_com.h" extern my_bool net_realloc(NET * net, unsigned long int); -# 755 "mysql.h" +# 751 "mysql.h" extern unsigned long int net_safe_read(MYSQL * mysql); # 288 "mysql_com.h" extern my_bool net_write_command(NET * net, unsigned char, char const * header, unsigned long int, char const * packet, unsigned long int); -# 121 "/usr/include/sys/select.h" -extern int pselect(int, fd_set * restrict __readfds, fd_set * restrict __writefds, fd_set * restrict __exceptfds, struct timespec const * restrict __timeout, __sigset_t const * restrict __sigmask); # 350 "mysql_com.h" extern void randominit(struct rand_struct *, unsigned long int, unsigned long int); # 364 "mysql_com.h" extern void scramble(char * to, char const * message, char const * password); # 357 "mysql_com.h" extern void scramble_323(char * to, char const * message, char const * password); -# 109 "/usr/include/sys/select.h" -extern int select(int, fd_set * restrict __readfds, fd_set * restrict __writefds, fd_set * restrict __exceptfds, struct timeval * restrict __timeout); # 32 "typelib.h" extern TYPELIB sql_protocol_typelib; From 9f223873cf85d21adcb3bac1efbebc52536dc327 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Mon, 30 Oct 2006 14:42:28 +0100 Subject: [PATCH 125/131] Bug#18654 Test is timing-dependent and fails from scheduling effects (?) - Wait in loop with small sleep until tables has been renamed --- .../include/wait_for_query_to_suceed.inc | 25 +++++++++++++++++++ mysql-test/t/rename.test | 12 ++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 mysql-test/include/wait_for_query_to_suceed.inc diff --git a/mysql-test/include/wait_for_query_to_suceed.inc b/mysql-test/include/wait_for_query_to_suceed.inc new file mode 100644 index 00000000000..6ac1144620e --- /dev/null +++ b/mysql-test/include/wait_for_query_to_suceed.inc @@ -0,0 +1,25 @@ +# +# Run a query over and over until it suceeds ot timeout occurs +# + + +let $counter= 100; + +disable_abort_on_error; +disable_query_log; +disable_result_log; +eval $query; +while ($mysql_errno) +{ + eval $query; + sleep 0.1; + dec $counter; + + if (!$counter) + { + die("Waited too long for query to suceed"); + } +} +enable_abort_on_error; +enable_query_log; +enable_result_log; diff --git a/mysql-test/t/rename.test b/mysql-test/t/rename.test index 5caecef176e..b0fb60c0ee4 100644 --- a/mysql-test/t/rename.test +++ b/mysql-test/t/rename.test @@ -43,8 +43,8 @@ select * from t3; drop table if exists t1,t2,t3,t4; # -# Test-case for Bug #2397 RENAME TABLES is not blocked by -# FLUSH TABLES WITH READ LOCK +# Bug #2397 RENAME TABLES is not blocked by +# FLUSH TABLES WITH READ LOCK # connect (con1,localhost,root,,); @@ -58,10 +58,14 @@ FLUSH TABLES WITH READ LOCK; connection con1; send RENAME TABLE t1 TO t2, t3 to t4; connection con2; -sleep 1; show tables; UNLOCK TABLES; -sleep 1; + +# Wait for the the tables to be renamed +# i.e the query below succeds +let $query= select * from t2, t4; +source include/wait_for_query_to_suceed.inc; + show tables; drop table t2, t4; From 12d8f2bf3122f23898e64d2eb37dd8dfc9a5f7b4 Mon Sep 17 00:00:00 2001 From: "thek@kpdesk.mysql.com" <> Date: Tue, 31 Oct 2006 09:26:16 +0100 Subject: [PATCH 126/131] Bug#22828 _my_b_read() ignores return values for my_seek() calls - Because my_seek actually is capable of returning an error code we should exploit that in the best possible way. - There might be kernel errors or other errors we can't predict and capturing the return value of all system calls gives us better understanding of possible errors. --- mysys/mf_iocache.c | 102 +++++++++++++++++++++++++++++++++++++++------ mysys/my_chsize.c | 6 ++- mysys/my_lock.c | 39 ++++++++++++++--- mysys/my_seek.c | 26 +++++++++++- 4 files changed, 153 insertions(+), 20 deletions(-) diff --git a/mysys/mf_iocache.c b/mysys/mf_iocache.c index 0007784c2b2..709a3250f39 100644 --- a/mysys/mf_iocache.c +++ b/mysys/mf_iocache.c @@ -440,11 +440,24 @@ int _my_b_read(register IO_CACHE *info, byte *Buffer, uint Count) /* pos_in_file always point on where info->buffer was read */ pos_in_file=info->pos_in_file+(uint) (info->read_end - info->buffer); + + /* + Whenever a function which operates on IO_CACHE flushes/writes + some part of the IO_CACHE to disk it will set the property + "seek_not_done" to indicate this to other functions operating + on the IO_CACHE. + */ if (info->seek_not_done) - { /* File touched, do seek */ - VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0))); + { + if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) + == MY_FILEPOS_ERROR) + { + info->error= -1; + DBUG_RETURN(1); + } info->seek_not_done=0; } + diff_length=(uint) (pos_in_file & (IO_SIZE-1)); if (Count >= (uint) (IO_SIZE+(IO_SIZE-diff_length))) { /* Fill first intern buffer */ @@ -633,8 +646,22 @@ int _my_b_read_r(register IO_CACHE *info, byte *Buffer, uint Count) if (lock_io_cache(info, pos_in_file)) { info->share->active=info; - if (info->seek_not_done) /* File touched, do seek */ - VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0))); + /* + Whenever a function which operates on IO_CACHE flushes/writes + some part of the IO_CACHE to disk it will set the property + "seek_not_done" to indicate this to other functions operating + on the IO_CACHE. + */ + if (info->seek_not_done) + { + if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) + == MY_FILEPOS_ERROR) + { + info->error= -1; + unlock_io_cache(info); + DBUG_RETURN(1); + } + } len=(int)my_read(info->file,info->buffer, length, info->myflags); info->read_end=info->buffer + (len == -1 ? 0 : len); info->error=(len == (int)length ? 0 : len); @@ -668,11 +695,16 @@ int _my_b_read_r(register IO_CACHE *info, byte *Buffer, uint Count) /* - Do sequential read from the SEQ_READ_APPEND cache - we do this in three stages: + Do sequential read from the SEQ_READ_APPEND cache. + + We do this in three stages: - first read from info->buffer - then if there are still data to read, try the file descriptor - afterwards, if there are still data to read, try append buffer + + RETURNS + 0 Success + 1 Failed to read */ int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count) @@ -700,7 +732,13 @@ int _my_b_seq_read(register IO_CACHE *info, byte *Buffer, uint Count) With read-append cache we must always do a seek before we read, because the write could have moved the file pointer astray */ - VOID(my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0))); + if (my_seek(info->file,pos_in_file,MY_SEEK_SET,MYF(0)) + == MY_FILEPOS_ERROR) + { + info->error= -1; + unlock_append_buffer(info); + return (1); + } info->seek_not_done=0; diff_length=(uint) (pos_in_file & (IO_SIZE-1)); @@ -816,6 +854,21 @@ read_append_buffer: #ifdef HAVE_AIOWAIT +/* + Read from the IO_CACHE into a buffer and feed asynchronously + from disk when needed. + + SYNOPSIS + _my_b_async_read() + info IO_CACHE pointer + Buffer Buffer to retrieve count bytes from file + Count Number of bytes to read into Buffer + + RETURN VALUE + -1 An error has occurred; my_errno is set. + 0 Success + 1 An error has occurred; IO_CACHE to error state. +*/ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count) { uint length,read_length,diff_length,left_length,use_length,org_Count; @@ -906,13 +959,20 @@ int _my_b_async_read(register IO_CACHE *info, byte *Buffer, uint Count) info->error=(int) (read_length+left_length); return 1; } - VOID(my_seek(info->file,next_pos_in_file,MY_SEEK_SET,MYF(0))); + + if (my_seek(info->file,next_pos_in_file,MY_SEEK_SET,MYF(0)) + == MY_FILEPOS_ERROR) + { + info->error= -1; + return (1); + } + read_length=IO_SIZE*2- (uint) (next_pos_in_file & (IO_SIZE-1)); if (Count < read_length) { /* Small block, read to cache */ if ((read_length=my_read(info->file,info->request_pos, read_length, info->myflags)) == (uint) -1) - return info->error= -1; + return info->error= -1; use_length=min(Count,read_length); memcpy(Buffer,info->request_pos,(size_t) use_length); info->read_pos=info->request_pos+Count; @@ -999,7 +1059,15 @@ int _my_b_get(IO_CACHE *info) return (int) (uchar) buff; } - /* Returns != 0 if error on write */ +/* + Write a byte buffer to IO_CACHE and flush to disk + if IO_CACHE is full. + + RETURN VALUE + 1 On error on write + 0 On success + -1 On error; my_errno contains error code. +*/ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count) { @@ -1022,8 +1090,18 @@ int _my_b_write(register IO_CACHE *info, const byte *Buffer, uint Count) { /* Fill first intern buffer */ length=Count & (uint) ~(IO_SIZE-1); if (info->seek_not_done) - { /* File touched, do seek */ - VOID(my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0))); + { + /* + Whenever a function which operates on IO_CACHE flushes/writes + some part of the IO_CACHE to disk it will set the property + "seek_not_done" to indicate this to other functions operating + on the IO_CACHE. + */ + if (my_seek(info->file,info->pos_in_file,MY_SEEK_SET,MYF(0))) + { + info->error= -1; + return (1); + } info->seek_not_done=0; } if (my_write(info->file,Buffer,(uint) length,info->myflags | MY_NABP)) diff --git a/mysys/my_chsize.c b/mysys/my_chsize.c index cf26428d65f..b925b52ac03 100644 --- a/mysys/my_chsize.c +++ b/mysys/my_chsize.c @@ -88,7 +88,11 @@ int my_chsize(File fd, my_off_t newlength, int filler, myf MyFlags) Fill space between requested length and true length with 'filler' We should never come here on any modern machine */ - VOID(my_seek(fd, newlength, MY_SEEK_SET, MYF(MY_WME+MY_FAE))); + if (my_seek(fd, newlength, MY_SEEK_SET, MYF(MY_WME+MY_FAE)) + == MY_FILEPOS_ERROR) + { + goto err; + } swap_variables(my_off_t, newlength, oldsize); } #endif diff --git a/mysys/my_lock.c b/mysys/my_lock.c index 8f915d6003a..c9641f46f5c 100644 --- a/mysys/my_lock.c +++ b/mysys/my_lock.c @@ -35,7 +35,14 @@ #include #endif - /* Lock a part of a file */ +/* + Lock a part of a file + + RETURN VALUE + 0 Success + -1 An error has occured and 'my_errno' is set + to indicate the actual error code. +*/ int my_lock(File fd, int locktype, my_off_t start, my_off_t length, myf MyFlags) @@ -104,10 +111,22 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length, #elif defined(HAVE_LOCKING) /* Windows */ { - my_bool error; + my_bool error= false; pthread_mutex_lock(&my_file_info[fd].mutex); - if (MyFlags & MY_SEEK_NOT_DONE) - VOID(my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE))); + if (MyFlags & MY_SEEK_NOT_DONE) + { + if( my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE)) + == MY_FILEPOS_ERROR ) + { + /* + If my_seek fails my_errno will already contain an error code; + just unlock and return error code. + */ + DBUG_PRINT("error",("my_errno: %d (%d)",my_errno,errno)); + pthread_mutex_unlock(&my_file_info[fd].mutex); + DBUG_RETURN(-1); + } + } error= locking(fd,locktype,(ulong) length) && errno != EINVAL; pthread_mutex_unlock(&my_file_info[fd].mutex); if (!error) @@ -145,7 +164,17 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length, } #else if (MyFlags & MY_SEEK_NOT_DONE) - VOID(my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE))); + { + if (my_seek(fd,start,MY_SEEK_SET,MYF(MyFlags & ~MY_SEEK_NOT_DONE)) + == MY_FILEPOS_ERROR) + { + /* + If an error has occured in my_seek then we will already + have an error code in my_errno; Just return error code. + */ + DBUG_RETURN(-1); + } + } if (lockf(fd,locktype,length) != -1) DBUG_RETURN(0); #endif /* HAVE_FCNTL */ diff --git a/mysys/my_seek.c b/mysys/my_seek.c index 6af65d70fd0..a9ae68cd5f0 100644 --- a/mysys/my_seek.c +++ b/mysys/my_seek.c @@ -16,8 +16,30 @@ #include "mysys_priv.h" - /* Seek to position in file */ - /*ARGSUSED*/ +/* + Seek to a position in a file. + + ARGUMENTS + File fd The file descriptor + my_off_t pos The expected position (absolute or relative) + int whence A direction parameter and one of + {SEEK_SET, SEEK_CUR, SEEK_END} + myf MyFlags Not used. + + DESCRIPTION + The my_seek function is a wrapper around the system call lseek and + repositions the offset of the file descriptor fd to the argument + offset according to the directive whence as follows: + SEEK_SET The offset is set to offset bytes. + SEEK_CUR The offset is set to its current location plus offset bytes + SEEK_END The offset is set to the size of the file plus offset bytes + + RETURN VALUE + my_off_t newpos The new position in the file. + MY_FILEPOS_ERROR An error was encountered while performing + the seek. my_errno is set to indicate the + actual error. +*/ my_off_t my_seek(File fd, my_off_t pos, int whence, myf MyFlags __attribute__((unused))) From c6c0dcdc0db3e50a30a3549f894f3eefa8159d2b Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Tue, 31 Oct 2006 17:16:07 +0100 Subject: [PATCH 127/131] Remove warning, exe_mysql_fix_system_tables are not available on windows --- mysql-test/mysql-test-run.pl | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 3e25d6e933c..de2498a7246 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -1801,14 +1801,16 @@ sub environment_setup () { # ---------------------------------------------------- # Setup env so childs can execute mysql_fix_system_tables # ---------------------------------------------------- - my $cmdline_mysql_fix_system_tables= - "$exe_mysql_fix_system_tables --no-defaults --host=localhost " . - "--user=root --password= " . - "--basedir=$glob_basedir --bindir=$path_client_bindir --verbose " . - "--port=$master->[0]->{'port'} " . - "--socket=$master->[0]->{'path_sock'}"; - - $ENV{'MYSQL_FIX_SYSTEM_TABLES'}= $cmdline_mysql_fix_system_tables; + if ( ! $glob_win32 ) + { + my $cmdline_mysql_fix_system_tables= + "$exe_mysql_fix_system_tables --no-defaults --host=localhost " . + "--user=root --password= " . + "--basedir=$glob_basedir --bindir=$path_client_bindir --verbose " . + "--port=$master->[0]->{'port'} " . + "--socket=$master->[0]->{'path_sock'}"; + $ENV{'MYSQL_FIX_SYSTEM_TABLES'}= $cmdline_mysql_fix_system_tables; + } # ---------------------------------------------------- # Setup env so childs can execute my_print_defaults From 64eb65533ee90f178812fecc85602aa55d5d0176 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Tue, 31 Oct 2006 18:51:23 +0100 Subject: [PATCH 128/131] Make variables static to please Netware compiler --- client/mysqltest.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/client/mysqltest.c b/client/mysqltest.c index 9f41586afae..7c1ce19283f 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -1409,7 +1409,7 @@ int open_file(const char *name) void do_source(struct st_command *command) { - DYNAMIC_STRING ds_filename; + static DYNAMIC_STRING ds_filename; const struct command_arg source_args[] = { "filename", ARG_STRING, TRUE, &ds_filename, "File to source" }; @@ -1697,7 +1697,7 @@ void do_system(struct st_command *command) void do_remove_file(struct st_command *command) { int error; - DYNAMIC_STRING ds_filename; + static DYNAMIC_STRING ds_filename; const struct command_arg rm_args[] = { "filename", ARG_STRING, TRUE, &ds_filename, "File to delete" }; @@ -1730,8 +1730,8 @@ void do_remove_file(struct st_command *command) void do_copy_file(struct st_command *command) { int error; - DYNAMIC_STRING ds_from_file; - DYNAMIC_STRING ds_to_file; + static DYNAMIC_STRING ds_from_file; + static DYNAMIC_STRING ds_to_file; const struct command_arg copy_file_args[] = { "from_file", ARG_STRING, TRUE, &ds_from_file, "Filename to copy from", "to_file", ARG_STRING, TRUE, &ds_to_file, "Filename to copy to" @@ -1766,7 +1766,7 @@ void do_copy_file(struct st_command *command) void do_file_exist(struct st_command *command) { int error; - DYNAMIC_STRING ds_filename; + static DYNAMIC_STRING ds_filename; const struct command_arg file_exist_args[] = { "filename", ARG_STRING, TRUE, &ds_filename, "File to check if it exist" }; @@ -1873,9 +1873,9 @@ void read_until_delimiter(DYNAMIC_STRING *ds, void do_write_file(struct st_command *command) { - DYNAMIC_STRING ds_content; - DYNAMIC_STRING ds_filename; - DYNAMIC_STRING ds_delimiter; + static DYNAMIC_STRING ds_content; + static DYNAMIC_STRING ds_filename; + static DYNAMIC_STRING ds_delimiter; const struct command_arg write_file_args[] = { "filename", ARG_STRING, TRUE, &ds_filename, "File to write to", "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" @@ -1927,8 +1927,8 @@ void do_perl(struct st_command *command) int error; char buf[FN_REFLEN]; FILE *res_file; - DYNAMIC_STRING ds_script; - DYNAMIC_STRING ds_delimiter; + static DYNAMIC_STRING ds_script; + static DYNAMIC_STRING ds_delimiter; const struct command_arg perl_args[] = { "delimiter", ARG_STRING, FALSE, &ds_delimiter, "Delimiter to read until" }; @@ -2985,14 +2985,14 @@ void do_connect(struct st_command *command) bool con_ssl= 0, con_compress= 0; char *ptr; - DYNAMIC_STRING ds_connection_name; - DYNAMIC_STRING ds_host; - DYNAMIC_STRING ds_user; - DYNAMIC_STRING ds_password; - DYNAMIC_STRING ds_database; - DYNAMIC_STRING ds_port; - DYNAMIC_STRING ds_sock; - DYNAMIC_STRING ds_options; + static DYNAMIC_STRING ds_connection_name; + static DYNAMIC_STRING ds_host; + static DYNAMIC_STRING ds_user; + static DYNAMIC_STRING ds_password; + static DYNAMIC_STRING ds_database; + static DYNAMIC_STRING ds_port; + static DYNAMIC_STRING ds_sock; + static DYNAMIC_STRING ds_options; const struct command_arg connect_args[] = { "connection name", ARG_STRING, TRUE, &ds_connection_name, "Name of the connection", From 2754edbaf30b23d126b0e147351ae7effe75e112 Mon Sep 17 00:00:00 2001 From: "msvensson@shellback.(none)" <> Date: Tue, 31 Oct 2006 19:02:33 +0100 Subject: [PATCH 129/131] Improve the reading of .pid files from var/run - Only read *.pid - Only allow it to contain a number --- mysql-test/lib/mtr_io.pl | 12 +++++------ mysql-test/lib/mtr_process.pl | 40 ++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/mysql-test/lib/mtr_io.pl b/mysql-test/lib/mtr_io.pl index a1d7ffe87d8..984d834486c 100644 --- a/mysql-test/lib/mtr_io.pl +++ b/mysql-test/lib/mtr_io.pl @@ -37,18 +37,16 @@ sub mtr_get_pid_from_file ($) { open(FILE, '<', $pid_file_path) or mtr_error("can't open file \"$pid_file_path\": $!"); + # Read pid number from file my $pid= ; - - chomp($pid) if defined $pid; - close FILE; - return $pid if defined $pid && $pid ne ''; + return $pid if $pid=~ /^(\d+)/; - mtr_debug("Pid file '$pid_file_path' is empty. " . - "Sleeping $timeout second(s)..."); + mtr_debug("Pid file '$pid_file_path' does not yet contain pid number.\n" . + "Sleeping $timeout second(s) more..."); - sleep(1); + sleep($timeout); } mtr_error("Pid file '$pid_file_path' is corrupted. " . diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl index affe8278376..048c336f8a3 100644 --- a/mysql-test/lib/mtr_process.pl +++ b/mysql-test/lib/mtr_process.pl @@ -438,25 +438,35 @@ sub mtr_kill_leftovers () { while ( my $elem= readdir(RUNDIR) ) { - my $pidfile= "$rundir/$elem"; - - if ( -f $pidfile ) + # Only read pid from files that end with .pid + if ( $elem =~ /.*[.]pid$/) { - mtr_debug("Processing PID file: '$pidfile'..."); - my $pid= mtr_get_pid_from_file($pidfile); + my $pidfile= "$rundir/$elem"; - mtr_debug("Got pid: $pid from file '$pidfile'"); + if ( -f $pidfile ) + { + mtr_debug("Processing PID file: '$pidfile'..."); - if ( $::glob_cygwin_perl or kill(0, $pid) ) - { - mtr_debug("There is process with pid $pid -- scheduling for kill."); - push(@pids, $pid); # We know (cygwin guess) it exists - } - else - { - mtr_debug("There is no process with pid $pid -- skipping."); - } + my $pid= mtr_get_pid_from_file($pidfile); + + mtr_debug("Got pid: $pid from file '$pidfile'"); + + if ( $::glob_cygwin_perl or kill(0, $pid) ) + { + mtr_debug("There is process with pid $pid -- scheduling for kill."); + push(@pids, $pid); # We know (cygwin guess) it exists + } + else + { + mtr_debug("There is no process with pid $pid -- skipping."); + } + } + } + else + { + mtr_warning("Found non pid file $elem in $rundir"); + next; } } closedir(RUNDIR); From a072688eea7dbc7fd6cb2b0ac60f72d04df4a7eb Mon Sep 17 00:00:00 2001 From: "ramil/ram@mysql.com/myoffice.izhnet.ru" <> Date: Thu, 2 Nov 2006 14:32:00 +0400 Subject: [PATCH 130/131] Fix for bug #22913: mysql --quick doesn't report some errors. We don't check for errors that may occur during data printing. --- client/mysql.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/mysql.cc b/client/mysql.cc index 2f9031b84b8..fcdd63b31e6 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1988,6 +1988,8 @@ com_go(String *buffer,char *line __attribute__((unused))) (long) mysql_num_rows(result), (long) mysql_num_rows(result) == 1 ? "row" : "rows"); end_pager(); + if (mysql_errno(&mysql)) + error= put_error(&mysql); } } else if (mysql_affected_rows(&mysql) == ~(ulonglong) 0) From 3f16931527ef007117095d00bc9bb3ce56df5d63 Mon Sep 17 00:00:00 2001 From: "thek@kpdesk.mysql.com" <> Date: Thu, 2 Nov 2006 13:33:26 +0100 Subject: [PATCH 131/131] Bug#22828 complementary patch: - 'false' not defined in C, use FALSE instead. --- mysys/my_lock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/my_lock.c b/mysys/my_lock.c index c9641f46f5c..b8307f366c0 100644 --- a/mysys/my_lock.c +++ b/mysys/my_lock.c @@ -111,7 +111,7 @@ int my_lock(File fd, int locktype, my_off_t start, my_off_t length, #elif defined(HAVE_LOCKING) /* Windows */ { - my_bool error= false; + my_bool error= FALSE; pthread_mutex_lock(&my_file_info[fd].mutex); if (MyFlags & MY_SEEK_NOT_DONE) {