summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am5
-rw-r--r--client/Makefile.am4
-rw-r--r--client/mysqltest.c7410
-rw-r--r--mysql-test/include/check-testcase.test49
-rw-r--r--mysql-test/include/ctype_like_escape.inc4
-rw-r--r--mysql-test/include/have_multi_ndb.inc12
-rw-r--r--mysql-test/include/master-slave.inc6
-rw-r--r--mysql-test/include/ps_query.inc1
-rwxr-xr-xmysql-test/include/show_msg.inc25
-rwxr-xr-xmysql-test/include/show_msg80.inc118
-rw-r--r--mysql-test/lib/mtr_cases.pl472
-rw-r--r--mysql-test/lib/mtr_gcov.pl18
-rw-r--r--mysql-test/lib/mtr_im.pl761
-rw-r--r--mysql-test/lib/mtr_io.pl66
-rw-r--r--mysql-test/lib/mtr_misc.pl40
-rw-r--r--mysql-test/lib/mtr_process.pl662
-rw-r--r--mysql-test/lib/mtr_report.pl176
-rw-r--r--mysql-test/lib/mtr_stress.pl178
-rwxr-xr-xmysql-test/mysql-test-run.pl3978
-rw-r--r--mysql-test/mysql-test-run.sh2
-rw-r--r--mysql-test/r/check.result2
-rw-r--r--mysql-test/r/connect.result20
-rw-r--r--mysql-test/r/flush.result4
-rw-r--r--mysql-test/r/flush_block_commit.result6
-rw-r--r--mysql-test/r/func_misc.result2
-rw-r--r--mysql-test/r/grant2.result8
-rw-r--r--mysql-test/r/handler.result2
-rw-r--r--mysql-test/r/init_file.result2
-rw-r--r--mysql-test/r/kill.result2
-rw-r--r--mysql-test/r/lock_multi.result12
-rw-r--r--mysql-test/r/mix_innodb_myisam_binlog.result2
-rw-r--r--mysql-test/r/mysql_client_test.result1
-rw-r--r--mysql-test/r/mysqltest.result211
-rw-r--r--mysql-test/r/ps_2myisam.result2
-rw-r--r--mysql-test/r/ps_3innodb.result2
-rw-r--r--mysql-test/r/ps_4heap.result2
-rw-r--r--mysql-test/r/ps_5merge.result4
-rw-r--r--mysql-test/r/ps_6bdb.result2
-rw-r--r--mysql-test/r/ps_7ndb.result2
-rw-r--r--mysql-test/r/rename.result2
-rw-r--r--mysql-test/r/rpl000001.result2
-rw-r--r--mysql-test/r/rpl000018.result14
-rw-r--r--mysql-test/r/rpl_chain_temp_table.result30
-rw-r--r--mysql-test/r/rpl_charset.result4
-rw-r--r--mysql-test/r/rpl_error_ignored_table.result2
-rw-r--r--mysql-test/r/rpl_failsafe.result34
-rw-r--r--mysql-test/r/rpl_heap.result29
-rw-r--r--mysql-test/r/rpl_loaddata.result2
-rw-r--r--mysql-test/r/rpl_loaddatalocal.result4
-rw-r--r--mysql-test/r/rpl_log.result12
-rw-r--r--mysql-test/r/rpl_master_pos_wait.result2
-rw-r--r--mysql-test/r/subselect.result3
-rw-r--r--mysql-test/r/synchronization.result40
-rw-r--r--mysql-test/r/type_blob.result3
-rw-r--r--mysql-test/t/bdb-alter-table-2-master.opt2
-rw-r--r--mysql-test/t/connect.test83
-rw-r--r--mysql-test/t/init_file.test5
-rw-r--r--mysql-test/t/mysql_client_test.test6
-rw-r--r--mysql-test/t/mysqltest.test807
-rw-r--r--mysql-test/t/not_embedded_server-master.opt2
-rw-r--r--mysql-test/t/ps.test6
-rw-r--r--mysql-test/t/ps_1general.test2
-rw-r--r--mysql-test/t/ps_grant.test2
-rw-r--r--mysql-test/t/rpl000018.test29
-rw-r--r--mysql-test/t/rpl_chain_temp_table.test101
-rw-r--r--mysql-test/t/rpl_charset.test2
-rw-r--r--mysql-test/t/rpl_failsafe.test24
-rw-r--r--mysql-test/t/rpl_flush_tables.test2
-rw-r--r--mysql-test/t/rpl_heap.test51
-rw-r--r--mysql-test/t/rpl_loaddatalocal.test8
-rw-r--r--mysql-test/t/rpl_slave_status.test2
-rw-r--r--mysql-test/t/rpl_trunc_temp.test3
-rw-r--r--mysql-test/t/subselect.test2
-rw-r--r--mysql-test/t/system_mysql_db_fix.test6
-rw-r--r--mysql-test/t/type_blob.test2
-rw-r--r--sql-common/client.c2
76 files changed, 11063 insertions, 4544 deletions
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
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..e2317560404 100644
--- a/client/mysqltest.c
+++ b/client/mysqltest.c
@@ -14,35 +14,24 @@
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 <sasha@mysql.com>
- * Matt Wagner <matt@mysql.com>
- * Monty
- * Jani
- **/
-
-/**********************************************************************
- TODO:
+/*
+ mysqltest
-- 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.
+ Tool used for executing a .test file
-- Don't buffer lines from the test that you don't expect to need
- again.
+ See the "MySQL Test framework manual" for more information
+ http://dev.mysql.com/doc/mysqltest/en/index.html
-- Change 'read_line' to be faster by using the readline.cc code;
- We can do better than calling feof() for each character!
+ Please keep the test framework tools identical in all versions!
-**********************************************************************/
+ Written by:
+ Sasha Pachev <sasha@mysql.com>
+ Matt Wagner <matt@mysql.com>
+ Monty
+ Jani
+*/
-#define MTEST_VERSION "2.5"
+#define MTEST_VERSION "3.0"
#include <my_global.h>
#include <mysql_embed.h>
@@ -51,18 +40,18 @@
#include <mysql.h>
#include <mysql_version.h>
#include <mysqld_error.h>
+#include <errmsg.h>
#include <m_ctype.h>
#include <my_dir.h>
-#include <errmsg.h> /* Error codes */
#include <hash.h>
#include <my_getopt.h>
#include <stdarg.h>
-#include <sys/stat.h>
#include <violite.h>
-#include "my_regex.h" /* Our own version of lib */
+#include "my_regex.h" /* Our own version of regex */
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
+
#ifndef WEXITSTATUS
# ifdef __WIN__
# define WEXITSTATUS(stat_val) (stat_val)
@@ -70,166 +59,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
+
+/* Flags controlling send and reap */
+#define QUERY_SEND_FLAG 1
+#define QUERY_REAP_FLAG 2
+
+ enum {
+ RESULT_OK= 0,
+ RESULT_CONTENT_MISMATCH= 1,
+ RESULT_LENGTH_MISMATCH= 2
+ };
+
+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
+};
-#define SLAVE_POLL_INTERVAL 300000 /* 0.3 of a sec */
-#define DEFAULT_DELIMITER ";"
-#define MAX_DELIMITER 16
+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;
-#define RESULT_OK 0
-#define RESULT_CONTENT_MISMATCH 1
-#define RESULT_LENGTH_MISMATCH 2
+static char **default_argv;
+static const char *load_default_groups[]= { "mysqltest", "client", 0 };
+static char line_buffer[MAX_DELIMITER_LENGTH], *line_buffer_pos= line_buffer;
-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};
+static uint start_lineno= 0; /* Start line of current command */
-/* ************************************************************************ */
-/*
- 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
+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
};
-typedef struct
+struct st_block
{
- 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;
+ int line; /* Start line of block */
+ my_bool ok; /* Should block be executed */
+ enum block_cmd cmd; /* Command owning the block */
+};
-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 struct st_block block_stack[32];
+static struct st_block *cur_block, *block_stack_end;
-typedef struct
+/* 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 const char *embedded_server_groups[]=
+{
+ "server",
+ "embedded",
+ "mysqltest_SERVER",
+ NullS
+};
-static my_bool display_result_vertically= FALSE, display_metadata= FALSE;
+static int embedded_server_arg_count=0;
+static char *embedded_server_args[MAX_EMBEDDED_SERVER_ARGS];
-/* See the timer_output() definition for details */
+/*
+ Timer related variables
+ 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 ulonglong progress_start= 0;
-static const char *embedded_server_groups[] = {
- "server",
- "embedded",
- "mysqltest_SERVER",
- NullS
-};
+/* 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
-{
- char file[FN_REFLEN];
- ulong pos;
-} MASTER_POS ;
-
-struct connection
-{
- MYSQL mysql;
- char *name;
-};
-
-typedef struct
+struct
{
int read_lines,current_line;
-} PARSER;
+} parser;
-MYSQL_RES *last_result=0;
+struct
+{
+ char file[FN_REFLEN];
+ ulong pos;
+} master_pos;
-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_name= 0;
-typedef struct
+typedef struct st_var
{
char *name;
int name_len;
@@ -239,81 +206,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 */
-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;
+VAR var_reg[10];
-struct connection cons[MAX_CONS];
-struct connection* cur_con, *next_con, *cons_end;
+HASH var_hash;
- /* Add new commands before Q_UNKNOWN !*/
+struct st_connection
+{
+ 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_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
+ 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
};
-/* this should really be called command */
-struct st_query
-{
- 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;
-};
const char *command_names[]=
{
@@ -348,16 +305,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 +333,122 @@ 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
+};
-TYPELIB command_typelib= {array_elements(command_names),"",
- command_names, 0};
+struct st_match_err
+{
+ enum match_err_type type;
+ union
+ {
+ uint errnum;
+ char sqlstate[SQLSTATE_LENGTH+1]; /* \0 terminated string */
+ } code;
+};
-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);
+struct st_expected_errors
+{
+ struct st_match_err err[10];
+ uint count;
+};
+static struct st_expected_errors saved_expected_errors;
-static void var_free(void* v);
+struct st_command
+{
+ char *query, *query_buf,*first_argument,*last_argument,*end;
+ int first_word_len, query_len;
+ my_bool abort_on_error;
+ struct st_expected_errors expected_errors;
+ char require_file[FN_REFLEN];
+ enum enum_commands type;
+};
-int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname);
-void reject_dump(const char *record_file, char *buf, int size);
+TYPELIB command_typelib= {array_elements(command_names),"",
+ command_names, 0};
-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);
+DYNAMIC_STRING ds_res, ds_progress, ds_warning_messages;
+
+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) */;
+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,
+ 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(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);
+void str_to_file(const char *fname, char *str, int size);
-/* Definitions for replace result */
+#ifdef __WIN__
+void free_tmp_sh_file();
+void free_win_path_patterns();
+#endif
-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;
+static int eval_result = 0;
-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);
+/* 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();
-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 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;
-static int eval_result = 0;
+/* For replace_regex */
+void do_get_replace_regex(struct st_command *command);
+void free_replace_regex();
-/* For column replace */
-char *replace_column[MAX_COLUMNS];
-uint max_replace_column= 0;
-static void get_replace_column(struct st_query *q);
-static void free_replace_column();
+void free_all_replace(){
+ free_replace();
+ free_replace_regex();
+ free_replace_column();
+}
+
/* Disable functions that only exist in MySQL 4.0 */
#if MYSQL_VERSION_ID < 40000
@@ -457,42 +457,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,28 +525,154 @@ 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)
+ {
+ 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;
}
@@ -532,25 +680,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,20 +704,28 @@ 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);
+ dynstr_free(&ds_warning_messages);
+ 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)
{
@@ -587,25 +740,73 @@ 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_name && ds_res.length)
+ dump_result_to_log_file(ds_res.str, ds_res.length);
+
+ /* Dump warning messages */
+ if (result_file_name && ds_warning_messages.length)
+ dump_warning_messages();
+
+ /* 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 this version of mysqltest");
+}
+
+
+void verbose_msg(const char *fmt, ...)
{
va_list args;
DBUG_ENTER("verbose_msg");
@@ -613,24 +814,59 @@ static void verbose_msg(const char *fmt, ...)
DBUG_VOID_RETURN;
va_start(args, fmt);
-
fprintf(stderr, "mysqltest: ");
- if (start_lineno > 0)
+ 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);
fprintf(stderr, "\n");
va_end(args);
+
DBUG_VOID_RETURN;
}
-void init_parser()
+void warning_msg(const char *fmt, ...)
{
- parser.current_line= parser.read_lines= 0;
- memset(&var_reg, 0, sizeof(var_reg));
+ 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)
+ {
+ 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);
+ }
+#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);
+
+ DBUG_VOID_RETURN;
}
+/*
+ Compare content of the string ds to content of file fname
+*/
+
int dyn_string_cmp(DYNAMIC_STRING* ds, const char *fname)
{
MY_STAT stat_info;
@@ -645,10 +881,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 +892,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 +926,158 @@ 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 result file
+
+ SYNOPSIS
+ check_result
+ ds - content to be checked
+
+ RETURN VALUES
+ error - the function will not return
+
+*/
+
+void check_result(DYNAMIC_STRING* ds)
{
- int error= RESULT_OK;
- int res= dyn_string_cmp(ds, fname);
+ DBUG_ENTER("check_result");
+ DBUG_ASSERT(result_file_name);
- if (res && require_option)
- abort_not_supported_test();
- switch (res) {
+ switch (dyn_string_cmp(ds, result_file_name))
+ {
case RESULT_OK:
break; /* ok */
case RESULT_LENGTH_MISMATCH:
- verbose_msg("Result length mismatch");
- error= RESULT_LENGTH_MISMATCH;
+ dump_result_to_reject_file(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(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;
+}
+
+
+/*
+ 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)
+{
+ 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,
+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 +1096,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 +1126,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,200 +1137,332 @@ 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);
-int open_file(const char *name)
-{
- char buff[FN_REFLEN];
- DBUG_ENTER("open_file");
- DBUG_PRINT("enter", ("name: %s", name));
- if (!test_if_hard_path(name))
+ if (env_var)
{
- strxmov(buff, opt_basedir, name, NullS);
- name=buff;
+ 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));
}
- fn_format(buff,name,"","",4);
+ DBUG_VOID_RETURN;
+}
- if (cur_file == file_stack_end)
- die("Source directives are nesting too deep");
- cur_file++;
- if (!(cur_file->file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0))))
- {
- cur_file--;
- die("Could not open file %s", buff);
- }
- cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
- *++lineno=1;
- DBUG_RETURN(0);
+/*
+ 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= <integer>"
+*/
+
+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;
}
/*
- Check for unexpected "junk" after the end of query
- This is normally caused by missing delimiters
+ 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 @<var_name> = `<query>`
+
+ 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 "$<var_name>_<column_name>"
+ Thus the tab separated output can be read from $<var_name> and
+ and each individual column can be read as $<var_name>_<col_name>
+
*/
-int check_eol_junk(const char *eol)
+void var_query_set(VAR *var, const char *query, const char** query_end)
{
- 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++;
+ 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);
- /* Check for extra delimiter */
- if (*p && !strncmp(p, delimiter, delimiter_length))
- die("Extra delimiter \"%s\" found", delimiter);
+ while (end > query && *end != '`')
+ --end;
+ if (query == end)
+ die("Syntax error in query, missing '`'");
+ ++query;
- /* Allow trailing # comment */
- if (*p && *p != '#')
+ if (mysql_real_query(mysql, query, (int)(end - query)) ||
+ !(res = mysql_store_result(mysql)))
{
- if (*p == '\n')
- die("Missing delimiter");
- die("End of line junk detected: \"%s\"", p);
+ *end = 0;
+ die("Error running query '%s': %d %s", query,
+ mysql_errno(mysql), mysql_error(mysql));
}
- DBUG_RETURN(0);
-}
-
-/* ugly long name, but we are following the convention */
-int do_wait_for_slave_to_stop(struct st_query *q __attribute__((unused)))
-{
- MYSQL* mysql = &cur_con->mysql;
- for (;;)
+ if ((row = mysql_fetch_row(res)) && row[0])
{
- MYSQL_RES *res;
- MYSQL_ROW row;
- int done;
- LINT_INIT(res);
+ /*
+ 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
- if (mysql_query(mysql,"show status like 'Slave_running'") ||
- !(res=mysql_store_result(mysql)))
- die("Query failed while probing slave for stop: %s",
- mysql_error(mysql));
- if (!(row=mysql_fetch_row(res)) || !row[1])
+ init_dynamic_string(&result, "", 2048, 2048);
+ lengths= mysql_fetch_lengths(res);
+ for (i=0; i < mysql_num_fields(res); i++)
{
- mysql_free_result(res);
- die("Strange result from query while probing slave for stop");
+ if (row[0])
+ {
+#ifdef NOT_YET
+ /* Add to <var_name>_<col_name> */
+ 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);
}
- done = !strcmp(row[1],"OFF");
- mysql_free_result(res);
- if (done)
- break;
- my_sleep(SLAVE_POLL_INTERVAL);
+ end= result.str + result.length-1;
+ eval_expr(var, result.str, (const char**) &end);
+ dynstr_free(&result);
}
- return 0;
-}
+ else
+ eval_expr(var, "", 0);
-int do_require_manager(struct st_query *query __attribute__((unused)) )
-{
- if (!manager)
- abort_not_supported_test();
- return 0;
+ mysql_free_result(res);
+ DBUG_VOID_RETURN;
}
-#ifndef EMBEDDED_LIBRARY
-int do_server_start(struct st_query *q)
+
+void var_copy(VAR *dest, VAR *src)
{
- return do_server_op(q, "start");
+ 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 do_server_stop(struct st_query *q)
+
+void eval_expr(VAR *v, const char *p, const char **p_end)
{
- return do_server_op(q, "stop");
+ 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;
}
-int do_server_op(struct st_query *q, const char *op)
+
+int open_file(const char *name)
{
- char *p= q->first_argument;
- char com_buf[256], *com_p;
- if (!manager)
+ char buff[FN_REFLEN];
+ DBUG_ENTER("open_file");
+ DBUG_PRINT("enter", ("name: %s", name));
+ if (!test_if_hard_path(name))
{
- die("Manager is not initialized, manager commands are not possible");
+ strxmov(buff, opt_basedir, name, NullS);
+ name=buff;
}
- 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;
+ fn_format(buff, name, "", "", MY_UNPACK_FILENAME);
+
+ if (cur_file == file_stack_end)
+ die("Source directives are nesting too deep");
+ cur_file++;
+ if (!(cur_file->file = my_fopen(buff, O_RDONLY | FILE_BINARY, MYF(0))))
+ {
+ cur_file--;
+ die("Could not open file %s", buff);
+ }
+ cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
+ cur_file->lineno=1;
+ DBUG_RETURN(0);
}
-#endif
/*
Source and execute the given file
SYNOPSIS
- do_source()
- query called command
+ do_source()
+ query called command
DESCRIPTION
- source <file_name>
+ source <file_name>
- Open the file <file_name> and execute it
+ Open the file <file_name> and execute it
*/
-int do_source(struct st_query *query)
+void do_source(struct st_command *command)
{
- 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;
+ DYNAMIC_STRING ds_filename;
+ const struct command_arg source_args[] = {
+ "filename", ARG_STRING, TRUE, &ds_filename, "File to source"
+ };
+ DBUG_ENTER("do_source");
+
+ check_command_args(command, command->first_argument, source_args,
+ sizeof(source_args)/sizeof(struct command_arg),
+ ' ');
+
/*
- If this file has already been sourced, don't source it again.
- It's already available in the q_lines cache.
+ 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);
+ ; /* Do nothing */
+ else
+ {
+ DBUG_PRINT("info", ("sourcing file: %s", ds_filename.str));
+ open_file(ds_filename.str);
+ }
+
+ dynstr_free(&ds_filename);
+ return;
+}
+
+
+#ifdef __WIN__
+/* 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()
+{
+ /* 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
}
@@ -992,361 +1470,588 @@ int do_source(struct st_query *query)
Execute given command.
SYNOPSIS
- do_exec()
- query called command
+ do_exec()
+ query called command
DESCRIPTION
- exec <command>
+ exec <command>
- 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.
+ 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.
*/
-static void do_exec(struct st_query *query)
+void do_exec(struct st_command *command)
{
int error;
- DYNAMIC_STRING *ds= NULL;
- DYNAMIC_STRING ds_tmp;
char buf[1024];
FILE *res_file;
- char *cmd= query->first_argument;
+ char *cmd= command->first_argument;
+ DYNAMIC_STRING ds_cmd;
DBUG_ENTER("do_exec");
+ DBUG_PRINT("enter", ("cmd: '%s'", cmd));
+ /* Skip leading space */
while (*cmd && my_isspace(charset_info, *cmd))
cmd++;
if (!*cmd)
die("Missing argument in exec");
- query->last_argument= query->end;
+ command->last_argument= command->end;
- DBUG_PRINT("info", ("Executing '%s'", cmd));
+ 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);
- if (!(res_file= popen(cmd, "r")) && query->abort_on_error)
- die("popen(\"%s\", \"r\") failed", cmd);
+ DBUG_PRINT("info", ("Executing '%s' as '%s'",
+ command->first_argument, cmd));
- if (disable_result_log)
+ 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))
{
- while (fgets(buf, sizeof(buf), res_file))
+ if (disable_result_log)
{
buf[strlen(buf)-1]=0;
DBUG_PRINT("exec_result",("%s", buf));
}
- }
- else
- {
- if (query->record_file[0])
+ else
{
- init_dynamic_string(&ds_tmp, "", 16384, 65536);
- ds= &ds_tmp;
+ replace_dynstr_append(&ds_res, buf);
}
- 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)
+ if (error > 0)
{
uint status= WEXITSTATUS(error), i;
my_bool ok= 0;
- if (query->abort_on_error)
- die("command \"%s\" failed", cmd);
+ 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 < query->expected_errors; i++)
+ for (i= 0; i < command->expected_errors.count; 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))
+ 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",
- cmd, status));
+ command->first_argument, status));
}
}
if (!ok)
die("command \"%s\" failed with wrong error: %d",
- cmd, status);
+ command->first_argument, status);
}
- else if (query->expected_errno[0].type == ERR_ERRNO &&
- query->expected_errno[0].code.errnum != 0)
+ 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...",
- cmd, query->expected_errno[0].code.errnum);
+ command->first_argument, command->expected_errors.err[0].code.errnum);
}
- if (!disable_result_log)
- {
- if (glob_replace)
- free_replace();
+ dynstr_free(&ds_cmd);
+ DBUG_VOID_RETURN;
+}
- 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);
+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;
}
-int var_query_set(VAR* v, const char *p, const char** p_end)
+/*
+ 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)
{
- 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);
+#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
+}
- 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));
- }
+/*
+ SYNOPSIS
+ do_system
+ command called command
- if ((row = mysql_fetch_row(res)) && row[0])
+ DESCRIPTION
+ system <command>
+
+ 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))
{
- /*
- 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;
+ if (command->abort_on_error)
+ die("system command '%s' failed", command->first_argument);
- 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);
+ /* 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");
}
- else
- eval_expr(v, "", 0);
- mysql_free_result(res);
- return 0;
+ command->last_argument= command->end;
+ dynstr_free(&ds_cmd);
+ DBUG_VOID_RETURN;
}
-void var_copy(VAR *dest, VAR *src)
+
+/*
+ SYNOPSIS
+ do_remove_file
+ command called command
+
+ DESCRIPTION
+ remove_file <file_name>
+ Remove the file <file_name>
+*/
+
+void do_remove_file(struct st_command *command)
{
- dest->int_val= src->int_val;
- dest->int_dirty= src->int_dirty;
+ 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;
+}
- /* 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);
+/*
+ SYNOPSIS
+ do_copy_file
+ command command handle
+
+ DESCRIPTION
+ copy_file <from_file> <to_file>
+ Copy <from_file> to <to_file>
+
+ NOTE! Will fail if <to_file> 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;
}
-int eval_expr(VAR* v, const char *p, const char** p_end)
+
+/*
+ SYNOPSIS
+ do_file_exists
+ command called command
+
+ DESCRIPTION
+ fiile_exist <file_name>
+ Check if file <file_name> exists
+*/
+
+void do_file_exist(struct st_command *command)
{
- VAR* vp;
- if (*p == '$')
+ 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)
{
- if ((vp = var_get(p,p_end,0,0)))
+ 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))
{
- var_copy(v, vp);
- return 0;
+ DBUG_PRINT("exit", ("Found delimiter '%s'", ds_delimiter->str));
+ break;
}
+ dynstr_append_mem(ds, (const char*)&c, 1);
}
- 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;
+ DBUG_PRINT("exit", ("ds: %s", ds->str));
+ 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
- name human readable name of operator
- operator operation to perform on the var
+ do_write_file
+ command called command
DESCRIPTION
- dec $var_name
- inc $var_name
+ write_file <file_name> [<delimiter>];
+ <what to write line 1>
+ <...>
+ < what to write line n>
+ EOF
+
+ --write_file <file_name>;
+ <what to write line 1>
+ <...>
+ < what to write line n>
+ EOF
+
+ Write everything between the "write_file" command and 'delimiter'
+ to "file_name"
+
+ NOTE! Overwrites existing file
+
+ Default <delimiter> is EOF
*/
-int do_modify_var(struct st_query *query, const char *name,
- enum enum_operator operator)
+void do_write_file(struct st_command *command)
{
- 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;
+ 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;
}
-int do_system(struct st_query *q)
+/*
+ SYNOPSIS
+ do_perl
+ command command handle
+
+ DESCRIPTION
+ perl [<delimiter>];
+ <perlscript line 1>
+ <...>
+ <perlscript line n>
+ EOF
+
+ Execute everything after "perl" until <delimiter> as perl.
+ Useful for doing more advanced things
+ but still being able to execute it on all platforms.
+
+ Default <delimiter> is EOF
+*/
+
+void do_perl(struct st_command *command)
{
- 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))
+ 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 <filename> 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
{
- 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);
+ replace_dynstr_append(&ds_res, buf);
}
}
- else
- die("Missing arguments to system, nothing to do!");
- var_free(&v);
- q->last_argument= q->end;
- return 0;
+ 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 <delimiter> to result file.
- If content is a variable, the variable value will be retrieved
+ Evaluate all variables in the string before printing, allow
+ for variable names to be escaped using \
SYNOPSIS
- do_echo()
- q called command
+ do_echo()
+ command called command
DESCRIPTION
- Usage 1:
- echo text
- Print the text after echo until end of command to result file
+ echo text
+ Print the text after echo until end of command to result file
+
+ echo $<var_name>
+ Print the content of the variable <var_name> to result file
- Usage 2:
- echo $<var_name>
- Print the content of the variable <var_name> to result file
+ echo Some text $<var_name>
+ Print "Some text" plus the content of the variable <var_name> to
+ result file
+ echo Some text \$<var_name>
+ Print "Some text" plus $<var_name> to result file
*/
-int do_echo(struct st_query *q)
+int do_echo(struct st_command *command)
{
- char *p= q->first_argument;
- DYNAMIC_STRING *ds;
- DYNAMIC_STRING ds_tmp;
- VAR v;
- var_init(&v,0,0,0,0);
+ 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);
+}
- if (q->record_file[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 (;;)
{
- init_dynamic_string(&ds_tmp, "", 256, 512);
- ds= &ds_tmp;
- }
- else
- ds= &ds_res;
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ int done;
+ LINT_INIT(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;
+ if (mysql_query(mysql,"show status like 'Slave_running'") ||
+ !(res=mysql_store_result(mysql)))
+ die("Query failed while probing slave for stop: %s",
+ mysql_error(mysql));
+ if (!(row=mysql_fetch_row(res)) || !row[1])
+ {
+ mysql_free_result(res);
+ die("Strange result from query while probing slave for stop");
+ }
+ done = !strcmp(row[1],"OFF");
+ mysql_free_result(res);
+ if (done)
+ break;
+ my_sleep(SLAVE_POLL_INTERVAL);
+ }
+ return;
}
-int do_sync_with_master2(long offset)
+void do_sync_with_master2(long offset)
{
- MYSQL_RES* res;
+ 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 +2067,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 +2080,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 +2106,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 +2289,30 @@ int do_save_master_pos()
Assign the variable <var_name> with <var_val>
SYNOPSIS
- do_let()
- query called command
+ do_let()
+ query called command
DESCRIPTION
- let $<var_name>=<var_val><delimiter>
+ let $<var_name>=<var_val><delimiter>
- <var_name> - is the string string found between the $ and =
- <var_val> - is the content between the = and <delimiter>, it may span
- multiple line and contain any characters except <delimiter>
- <delimiter> - is a string containing of one or more chars, default is ;
+ <var_name> - is the string string found between the $ and =
+ <var_val> - is the content between the = and <delimiter>, it may span
+ multiple line and contain any characters except <delimiter>
+ <delimiter> - 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 <var_name> */
if (!*p)
@@ -1467,7 +2321,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 +2332,19 @@ int do_let(struct st_query *query)
/* Find start of <var_val> */
while (*p && my_isspace(charset_info,*p))
p++;
- var_val_start= p;
- query->last_argument= query->end;
- /* Assign var_val to var_name */
- return var_set(var_name, var_name_end, var_val_start, query->end);
-}
+ do_eval(&let_rhs_expr, p, command->end, FALSE);
-/*
- 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= <integer>"
-*/
-
-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);
+ command->last_argument= command->end;
+ /* Assign var_val to var_name */
+ 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;
}
-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 +2353,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 +2368,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 <seconds>
- real_sleep <seconds>
+ sleep <seconds>
+ real_sleep <seconds>
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 +2389,43 @@ 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(struct st_command *command,
+ char* dest, uint dest_max_len)
{
- char *p= q->first_argument, *name;
+ char *p= command->first_argument, *name;
if (!*p)
die("Missing file name argument");
name= p;
@@ -1584,13 +2433,14 @@ static void get_file_name(char *filename, struct st_query *q)
p++;
if (*p)
*p++= 0;
- q->last_argument= p;
- strmake(filename, name, FN_REFLEN);
+ command->last_argument= p;
+ strmake(dest, name, dest_max_len);
}
-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 +2451,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);
+}
+
+
+#if MYSQL_VERSION_ID >= 50000
+/* List of error names to error codes, available from 5.0 */
+typedef struct
+{
+ const char *name;
+ uint code;
+} st_error;
+
+static st_error global_error_names[] =
+{
+#include <mysqld_ername.h>
+ { 0, 0 }
+};
+
+uint get_errcode_from_name(char *error_name, char *error_end)
+{
+ /* 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 */
+ 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))
+ {
+ DBUG_RETURN(e->code);
+ }
+ }
+ if (!e->name)
+ die("Unknown SQL error name '%s'", error_name);
+ 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
+
+
-static uint get_errcodes(match_err *to,struct st_query *q)
+void do_get_errcodes(struct st_command *command)
{
- char *p= q->first_argument;
+ 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;
+ char *to_ptr= to->code.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 */
+ 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 +2634,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 +2683,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 +2707,49 @@ 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;
+ my_bool reconnect= val;
+ DBUG_ENTER("set_reconnect");
+ DBUG_PRINT("info", ("val: %d", val));
+#if MYSQL_VERSION_ID < 50000
+ mysql->reconnect= reconnect;
+#else
+ mysql_options(mysql, MYSQL_OPT_RECONNECT, (char *)&reconnect);
+#endif
DBUG_VOID_RETURN;
}
-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 +2759,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 +2800,358 @@ 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
+ */
+
+ if (mysql_errno(mysql) == CR_CONNECTION_ERROR &&
+ failed_attempts < opt_max_connect_retries)
+ my_sleep(connection_retry_sleep);
+ else
+ {
+ 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));
+ }
+ failed_attempts++;
+ }
+ DBUG_VOID_RETURN;
}
-#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
+/*
+ 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.
-int safe_connect(MYSQL* con, const char *host, const char *user,
- const char *pass,
- const char *db, int port, const char *sock)
+ 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)
{
- int con_error = 1;
- int i;
- for (i = 0; i < MAX_CON_TRIES; ++i)
+ DYNAMIC_STRING *ds;
+
+ ds= &ds_res;
+
+ /* Only log if an error is expected */
+ if (!command->abort_on_error &&
+ !disable_query_log)
{
- if (mysql_real_connect(con, host,user, pass, db, port, sock,
- CLIENT_MULTI_STATEMENTS))
- {
- con_error = 0;
- break;
- }
- sleep(CON_RETRY_SLEEP);
+ /*
+ 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 */
}
- return con_error;
+
+ handle_no_error(command);
+ return 1; /* Connected */
}
-int do_connect(struct st_query *q)
+/*
+ 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(<name>,<host>,<user>,[<pass>,[<db>,[<port>,<sock>[<opts>]]]]);
+ connect <name>,<host>,<user>,[<pass>,[<db>,[<port>,<sock>[<opts>]]]];
+
+ <name> - name of the new connection
+ <host> - hostname of server
+ <user> - user to connect as
+ <pass> - password used when connecting
+ <db> - initial db when connected
+ <port> - server port
+ <sock> - server socket
+ <opts> - options to use for the connection
+ * SSL - use SSL if available
+ * COMPRESS - use compression if available
+
+*/
+
+void do_connect(struct st_command *command)
{
- 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;
+ 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;
- }
- else
- {
- VAR* var_port, *var_sock;
- p= safe_get_param(p, &con_port_str, "missing connection port");
- if (*con_port_str == '$')
+ /* Replace it with a space */
+ *ptr= ' ';
+ if ((ptr= strstr(command->first_argument, ")")))
{
- 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;
+ /* Replace it with \0 */
+ *ptr= 0;
}
else
- con_port= atoi(con_port_str);
- p= safe_get_param(p, &con_sock, "missing connection socket");
- if (*con_sock == '$')
+ 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)
{
- 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;
+ char buff[FN_REFLEN];
+ fn_format(buff, ds_sock.str, TMPDIR, "", 0);
+ dynstr_set(&ds_sock, buff);
}
}
- q->last_argument= p;
+ else
+ {
+ /* No socket specified, use default */
+ dynstr_set(&ds_sock, unix_sock);
+ }
+ DBUG_PRINT("info", ("socket: %s", ds_sock.str));
+
+
+ /* Options */
+ con_options= ds_options.str;
+ while (*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))
+ 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 (next_con == cons_end)
- die("Connection limit exhausted - increase MAX_CONS in mysqltest.c");
+ 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(ds_connection_name.str, "localhost");
+ mysql_options(&next_con->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
+ &opt_ssl_verify_server_cert);
#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;
+ }
+#endif
+
+ /* 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 (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);
+ 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 +3167,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 ([!]<expr>)
+ {
+ <block statements>
+ }
+
+ while ([!]<expr>)
+ {
+ <block statements>
+ }
+
+ Evaluates the <expr> and if it evaluates to
+ greater than zero executes the following code block.
+ A '!' can be used before the <expr> 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 +3217,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 !<expr> */
+ 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 +3239,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
+void do_delimiter(struct st_command* command)
+{
+ char* p= command->first_argument;
+ DBUG_ENTER("do_delimiter");
+ DBUG_PRINT("enter", ("first_argument: %s", command->first_argument));
- 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.
-*/
+ while (*p && my_isspace(charset_info, *p))
+ p++;
-int my_getc(FILE *file)
-{
- if (line_buffer_pos == line_buffer)
- return fgetc(file);
- return *--line_buffer_pos;
-}
+ if (!(*p))
+ die("Can't set empty delimiter");
-void my_ungetc(int c)
-{
- *line_buffer_pos++= (char) c;
+ 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 +3305,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 +3361,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 (c == '}')
+ else if (end_of_query(c))
{
- *buf++= '}';
- *buf= 0;
+ *p= 0;
+ DBUG_PRINT("exit", ("Found delimiter '%s'", delimiter));
DBUG_RETURN(0);
}
- else if (end_of_query(c) || c == '{')
+ else if (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
- 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))
+ else if (c == '\'' || c == '"' || c == '`')
{
- *p= 0;
- DBUG_RETURN(0);
+ last_quote= c;
+ state= R_Q;
}
- if (c != '\'')
- state= R_NORMAL;
else
- state= R_Q1;
- break;
- case R_ESC_SLASH_Q1:
- state= R_Q1;
+ state= R_NORMAL;
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 != '"')
+ case R_Q:
+ if (c == last_quote)
state= R_NORMAL;
- else
- state= R_Q2;
+ else if (c == '\\')
+ state= R_SLASH_IN_Q;
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 +3490,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 +3507,253 @@ 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
+
+ That is: After newline, all spaces need to be skipped
+ unless the previous char was a quote
+
+ This is due to an old bug that has now been fixed, but the
+ version 1 output format is preserved by using this function
+
+*/
+
+void convert_to_format_v1(char* 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 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 or when
+ switching between different delimiters
+*/
+
+void check_eol_junk_line(const char *line)
+{
+ 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))
+ 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;
+}
+
+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;
+}
+
+
+
+/*
+ Create a command from a set of lines
SYNOPSIS
- read_query()
- q_ptr pointer where to return the new query
+ read_command()
+ command_ptr pointer where to return the new query
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.
+ 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.
+ 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 @<file_name> this will specify a file to ....
*/
-static char read_query_buf[MAX_QUERY];
+#define MAX_QUERY (256*1024) /* 256K -- a test in sp-big is >128K */
+static char read_command_buf[MAX_QUERY];
-int read_query(struct st_query** q_ptr)
+int read_command(struct st_command** command_ptr)
{
- char *p= read_query_buf, *p1;
- struct st_query* q;
- DBUG_ENTER("read_query");
+ 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->require_file[0]= 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;
- /* This goto is to avoid losing the "expected error" info. */
- goto end;
+ command->type= Q_COMMENT;
}
- 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 (p[0] == '-' && p[1] == '-')
+ else if (p[0] == '-' && p[1] == '-')
{
- q->type= Q_COMMENT_WITH_COMMAND;
- p+= 2; /* To calculate first word */
- }
- else
- {
- 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;
- }
+ command->type= Q_COMMENT_WITH_COMMAND;
+ p+= 2; /* Skip past -- */
}
-end:
+ /* Skip leading spaces */
while (*p && my_isspace(charset_info, *p))
p++;
- if (!(q->query_buf= q->query= my_strdup(p, MYF(MY_WME))))
- die(NullS);
+
+ if (!(command->query_buf= command->query= my_strdup(p, MYF(MY_WME))))
+ die("Out of memory");
/* 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);
+
+ /* Skip spaces between command and first argument */
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 +3761,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 <testname>.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},
@@ -2486,8 +3804,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.",
@@ -2498,11 +3816,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 +3837,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 <help_start.h>
-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 +3867,52 @@ void usage()
#include <help_end.h>
+/*
+ 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 +3926,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 +3977,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 +3985,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 +4024,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 +4042,222 @@ 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(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, result_file_name, "", ".reject",
+ MY_REPLACE_EXT),
+ buf, size);
}
+void dump_result_to_log_file(char *buf, int size)
+{
+ char log_file[FN_REFLEN];
+ str_to_file(fn_format(log_file, result_file_name, "", ".log",
+ MY_REPLACE_EXT),
+ buf, size);
+}
-/* Append the string to ds, with optional replace */
+void dump_progress(void)
+{
+ char log_file[FN_REFLEN];
+ str_to_file(fn_format(log_file, result_file_name, "", ".progress",
+ MY_REPLACE_EXT),
+ ds_progress.str, ds_progress.length);
+}
-static void replace_dynstr_append_mem(DYNAMIC_STRING *ds, const char *val,
- int len)
+void dump_warning_messages(void)
{
- if (glob_replace)
+ char warn_file[FN_REFLEN];
+
+ str_to_file(fn_format(warn_file, result_file_name, "", ".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];
+
+ if (err)
+ {
+ my_regerror(err,r,err_buf,sizeof(err_buf));
+ die("Regex error: %s\n", err_buf);
+ }
+}
+
+
+#ifdef __WIN__
+
+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()
+{
+ /* 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++)
+ {
+ 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++)
{
- len=(int) replace_strings(glob_replace, &out_buff, &out_length, val);
- if (len == -1)
- die("Out of memory in replace");
- val=out_buff;
+ 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,309 +4266,347 @@ 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)
{
+ MYSQL_BIND *bind;
+ my_bool *is_null;
+ ulong *length;
+ uint i;
- /*
- Try to find out if we can run this statement using the prepared
- statement protocol.
+ /* 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));
- We don't have a mysql_stmt_send_execute() so we only handle
- complete SEND+REAP.
+ /* Allocate data for the result of each field */
+ for (i= 0; i < num_fields; i++)
+ {
+ 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));
+ }
- If it is a '?' in the query it may be a SQL level prepared
- statement already and we can't do it twice
- */
+ if (mysql_stmt_bind_result(stmt, bind))
+ die("mysql_stmt_bind_result failed: %d: %s",
+ mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
- 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);
-}
+ while (mysql_stmt_fetch(stmt) == 0)
+ {
+ 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 (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));
-static int run_query_normal(MYSQL* mysql, struct st_query* q, int flags)
-{
- MYSQL_RES* res= 0;
- 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)
+ for (i= 0; i < num_fields; i++)
{
- query = q->query;
- query_len = strlen(query);
+ /* Free data for output */
+ my_free((gptr)bind[i].buffer, MYF(MY_WME | MY_FAE));
}
- else
+ /* 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));
+}
+
+
+/*
+ Append metadata for fields to output
+*/
+
+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"
+ "Column_alias\tType\tLength\tMax length\tIs_null\t"
+ "Flags\tDecimals\tCharsetnr\n");
+
+ for (field_end= field+num_fields ;
+ field < field_end ;
+ field++)
{
- init_dynamic_string(&eval_query, "", 16384, 65536);
- do_eval(&eval_query, q->query);
- query = eval_query.str;
- query_len = eval_query.length;
+ dynstr_append_mem(ds, field->catalog,
+ 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);
+ dynstr_append_mem(ds, "\t", 1);
+ dynstr_append_mem(ds, field->table,
+ field->table_length);
+ dynstr_append_mem(ds, "\t", 1);
+ dynstr_append_mem(ds, field->org_name,
+ 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);
+ replace_dynstr_append_uint(ds, field->type);
+ dynstr_append_mem(ds, "\t", 1);
+ replace_dynstr_append_uint(ds, field->length);
+ dynstr_append_mem(ds, "\t", 1);
+ 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);
+ replace_dynstr_append_uint(ds, field->flags);
+ dynstr_append_mem(ds, "\t", 1);
+ replace_dynstr_append_uint(ds, field->decimals);
+ dynstr_append_mem(ds, "\t", 1);
+ replace_dynstr_append_uint(ds, field->charsetnr);
+ dynstr_append_mem(ds, "\n", 1);
}
- DBUG_PRINT("enter", ("query: '%-.60s'", query));
+}
+
- if (q->record_file[0])
+/*
+ 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)
{
- init_dynamic_string(&ds_tmp, "", 16384, 65536);
- ds = &ds_tmp;
+ dynstr_append(ds, "info: ");
+ dynstr_append(ds, info);
+ dynstr_append_mem(ds, "\n", 1);
}
- else
- ds= &ds_res;
+}
+
- if (flags & QUERY_SEND)
+/*
+ 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++)
{
- 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);
+ if (col_idx)
+ dynstr_append_mem(ds, "\t", 1);
+ replace_dynstr_append(ds, field[col_idx].name);
}
+ dynstr_append_mem(ds, "\n", 1);
+}
- do
+/*
+ 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;
+ MYSQL_RES *warn_res;
+ DBUG_ENTER("append_warnings");
+
+ 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 ((flags & QUERY_SEND) && !disable_query_log && !counter)
+ /*
+ Send the query
+ */
+ if (mysql_send_query(mysql, query, query_len))
{
- replace_dynstr_append_mem(ds,query, query_len);
- dynstr_append_mem(ds, delimiter, delimiter_length);
- dynstr_append_mem(ds, "\n", 1);
+ handle_error(command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), ds);
+ goto end;
}
- 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 (!(flags & QUERY_REAP_FLAG))
+ DBUG_VOID_RETURN;
- 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
- */
+ 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;
}
- if (handle_no_error(q))
+ /*
+ 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))
{
- error= 1;
+ handle_error(command, mysql_errno(mysql), mysql_error(mysql),
+ mysql_sqlstate(mysql), ds);
goto end;
}
if (!disable_result_log)
{
- ulong affected_rows; /* Ok to be undef if 'disable_info' is set */
+ ulonglong affected_rows; /* Ok to be undef if 'disable_info' is set */
LINT_INIT(affected_rows);
if (res)
{
- MYSQL_FIELD *field= mysql_fetch_fields(res);
+ MYSQL_FIELD *fields= mysql_fetch_fields(res);
uint num_fields= mysql_num_fields(res);
if (display_metadata)
- run_query_display_metadata(field, num_fields, ds);
+ append_metadata(ds, fields, num_fields);
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_table_headings(ds, fields, num_fields);
+
append_result(ds, res);
}
/*
- Need to call mysql_affected_rows() before the new
+ Need to call mysql_affected_rows() before the "new"
query to find the warnings
*/
if (!disable_info)
- affected_rows= (ulong)mysql_affected_rows(mysql);
+ affected_rows= mysql_affected_rows(mysql);
- /* Add all warnings to the result */
- if (!disable_warnings && mysql_warning_count(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))
{
- 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
+ if (append_warnings(ds_warnings, mysql) || ds_warnings->length)
{
dynstr_append_mem(ds, "Warnings:\n", 10);
- append_result(ds, warn_res);
- mysql_free_result(warn_res);
+ dynstr_append_mem(ds, ds_warnings->str, ds_warnings->length);
}
}
+
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);
- }
- }
+ append_info(ds, affected_rows, mysql_info(mysql));
}
- 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);
+ 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:
- 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
@@ -3025,562 +4614,624 @@ end:
variable then can be used from the test case itself.
*/
var_set_errno(mysql_errno(mysql));
- DBUG_RETURN(error);
+ DBUG_VOID_RETURN;
}
-/****************************************************************************\
- * If --ps-protocol run ordinary statements using prepared statemnt C API
-\****************************************************************************/
+/*
+ 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)
+{
+ uint i;
+
+ DBUG_ENTER("handle_error");
+
+ if (command->require_file[0])
+ {
+ /*
+ 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 (command->abort_on_error)
+ die("query '%s' failed: %d: %s", command->query, err_errno, err_error);
+
+ 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) &&
+ (strncmp(command->expected_errors.err[i].code.sqlstate,
+ err_sqlstate, SQLSTATE_LENGTH) == 0)))
+ {
+ if (!disable_result_log)
+ {
+ if (command->expected_errors.count == 1)
+ {
+ /* Only log error if there is one possible error */
+ 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);
+ }
+ /* Don't log error if we may not get an error */
+ 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");
+ }
+ /* OK */
+ DBUG_VOID_RETURN;
+ }
+ }
+
+ DBUG_PRINT("info",("i: %d expected_errors: %d", i,
+ command->expected_errors.count));
+
+ 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;
+}
+
/*
- We don't have a mysql_stmt_send_execute() so we only handle
- complete SEND+REAP
+ Handle absence of errors after execution
+
+ SYNOPSIS
+ handle_no_error()
+ q - context of query
+
+ RETURN VALUE
+ error - function will not return
*/
-static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
+void handle_no_error(struct st_command *command)
{
- 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");
+ DBUG_ENTER("handle_no_error");
- /*
- 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)
+ if (command->expected_errors.err[0].type == ERR_ERRNO &&
+ command->expected_errors.err[0].code.errnum != 0)
{
- query= q->query;
- query_len= strlen(query);
+ /* Error code we wanted was != 0, i.e. not an expected success */
+ die("query '%s' succeeded - should have failed with errno %d...",
+ command->query, command->expected_errors.err[0].code.errnum);
}
- else
+ else if (command->expected_errors.err[0].type == ERR_SQLSTATE &&
+ strcmp(command->expected_errors.err[0].code.sqlstate,"00000") != 0)
{
- init_dynamic_string(&eval_query, "", 16384, 65536);
- do_eval(&eval_query, q->query);
- query= eval_query.str;
- query_len= eval_query.length;
+ /* SQLSTATE we wanted was != "00000", i.e. not an expected success */
+ die("query '%s' succeeded - should have failed with sqlstate %s...",
+ command->query, command->expected_errors.err[0].code.sqlstate);
}
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ 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));
- if (q->record_file[0])
+ /*
+ Init a new stmt if it's not already one created for this connection
+ */
+ if(!(stmt= cur_con->stmt))
{
- init_dynamic_string(&ds_tmp, "", 16384, 65536);
- ds= &ds_tmp;
+ if (!(stmt= mysql_stmt_init(mysql)))
+ die("unable to init stmt structure");
+ cur_con->stmt= stmt;
}
- else
- ds= &ds_res;
- /* Store the query into the output buffer if not disabled */
- if (!disable_query_log)
+ /* Init dynamic strings for warnings */
+ if (!disable_warnings)
{
- replace_dynstr_append_mem(ds,query, query_len);
- dynstr_append_mem(ds, delimiter, delimiter_length);
- dynstr_append_mem(ds, "\n", 1);
+ init_dynamic_string(&ds_prepare_warnings, NULL, 0, 256);
+ init_dynamic_string(&ds_execute_warnings, NULL, 0, 256);
}
/*
- We use the prepared statement interface but there is actually no
- '?' in the query. If unpreparable we fall back to use normal
- C API.
+ Prepare the query
*/
- if ((err= mysql_stmt_prepare(stmt, query, query_len)) == CR_NO_PREPARE_STMT)
- return run_query_normal(mysql, q, flags);
-
- if (err != 0)
+ if (mysql_stmt_prepare(stmt, query, query_len))
{
- 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;
- }
+ handle_error(command, mysql_stmt_errno(stmt),
+ mysql_stmt_error(stmt), mysql_stmt_sqlstate(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);
+ /*
+ 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
+ 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 MYSQL_VERSION_ID >= 50000
+ if (cursor_protocol_enabled)
{
- 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;
- }
+ /*
+ 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
+ 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 (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 ((err= mysql_stmt_store_result(stmt)) != 0)
+ if (mysql_stmt_store_result(stmt))
{
- 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;
- }
+ 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 succeesfully */
- if (handle_no_error(q))
+ /* If we got here the statement was both executed and read successfully */
+ handle_no_error(command);
+ if (!disable_result_log)
{
- error= 1;
- goto end;
- }
+ /*
+ 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);
- num_rows= mysql_stmt_num_rows(stmt);
+ if (display_metadata)
+ append_metadata(ds, fields, num_fields);
- /*
- 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);
+ if (!display_result_vertically)
+ append_table_headings(ds, fields, num_fields);
- /* FIXME check error from the above? */
+ append_stmt_result(ds, stmt, fields, num_fields);
- if (display_metadata)
- run_query_display_metadata(field, num_fields, ds);
+ mysql_free_result(res); /* Free normal result set with meta data */
- if (!display_result_vertically)
+ /* Clear prepare warnings */
+ dynstr_set(&ds_prepare_warnings, NULL);
+ }
+ else
{
- /* 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);
+ /*
+ This is a query without resultset
+ */
}
- /* Now we are to put the real result into the output buffer */
- /* FIXME when it works, create function append_stmt_result() */
+ if (!disable_warnings)
{
- 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);
+ /* Get the warnings from execute */
- free_replace_column();
-
- for (col_idx= 0; col_idx < num_fields; col_idx++)
+ /* 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)
{
- /* Free data for output */
- my_free((gptr)bind[col_idx].buffer, MYF(MY_WME | MY_FAE));
+ 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);
}
- /* 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);
+ append_info(ds, mysql_affected_rows(mysql), mysql_info(mysql));
- 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])
+
+end:
+ if (!disable_warnings)
{
- error= check_result(ds, q->record_file, q->require_file);
+ dynstr_free(&ds_prepare_warnings);
+ dynstr_free(&ds_execute_warnings);
}
- 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... */
+ /*
+ 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.
+ */
-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));
+#ifndef BUG15518_FIXED
mysql_stmt_close(stmt);
- DBUG_RETURN(error);
+ cur_con->stmt= NULL;
+#endif
+ DBUG_VOID_RETURN;
}
-/****************************************************************************\
- * Broken out sub functions to run_query_stmt()
-\****************************************************************************/
-static void run_query_display_metadata(MYSQL_FIELD *field, uint num_fields,
- DYNAMIC_STRING *ds)
-{
- MYSQL_FIELD *field_end;
- dynstr_append(ds,"Catalog\tDatabase\tTable\tTable_alias\tColumn\t"
- "Column_alias\tType\tLength\tMax length\tIs_null\t"
- "Flags\tDecimals\tCharsetnr\n");
+/*
+ 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.
+*/
- for (field_end= field+num_fields ;
- field < field_end ;
- field++)
+int util_query(MYSQL* org_mysql, const char* query){
+
+ MYSQL* mysql;
+ DBUG_ENTER("util_query");
+
+ if(!(mysql= cur_con->util_mysql))
{
- char buff[22];
- dynstr_append_mem(ds, field->catalog,
- 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);
- dynstr_append_mem(ds, "\t", 1);
- dynstr_append_mem(ds, field->table,
- field->table_length);
- dynstr_append_mem(ds, "\t", 1);
- dynstr_append_mem(ds, field->org_name,
- 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);
- dynstr_append_mem(ds, "\t", 1);
- longlong10_to_str((unsigned int) field->length, buff, 10);
- dynstr_append(ds, buff);
- dynstr_append_mem(ds, "\t", 1);
- longlong10_to_str((unsigned int) field->max_length, buff, 10);
- dynstr_append(ds, buff);
- 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);
+ DBUG_PRINT("info", ("Creating util_mysql"));
+ if (!(mysql= mysql_init(mysql)))
+ die("Failed in mysql_init()");
- int10_to_str((int) field->flags, buff, 10);
- dynstr_append(ds, buff);
- dynstr_append_mem(ds, "\t", 1);
- int10_to_str((int) field->decimals, buff, 10);
- dynstr_append(ds, buff);
- dynstr_append_mem(ds, "\t", 1);
- int10_to_str((int) field->charsetnr, buff, 10);
- dynstr_append(ds, buff);
- dynstr_append_mem(ds, "\n", 1);
+ 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);
}
-static void run_query_stmt_handle_warnings(MYSQL *mysql, DYNAMIC_STRING *ds)
-{
- uint count;
- DBUG_ENTER("run_query_stmt_handle_warnings");
- if (!disable_warnings && (count= mysql_warning_count(mysql)))
- {
- if (mysql_real_query(mysql, "SHOW WARNINGS", 13) == 0)
- {
- 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);
- }
- }
- }
- DBUG_VOID_RETURN;
-}
+/*
+ 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
-static int run_query_stmt_handle_error(char *query, struct st_query *q,
- MYSQL_STMT *stmt, DYNAMIC_STRING *ds)
+ SYNPOSIS
+ run_query
+ mysql - mysql handle
+ command - currrent command pointer
+
+*/
+
+void run_query(MYSQL *mysql, struct st_command *command, int flags)
{
- if (q->require_file) /* FIXME don't understand this one */
+ 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);
+
+ /* Scan for warning before sendign to server */
+ scan_command_for_warnings(command);
+
+ /*
+ 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
{
- abort_not_supported_test();
+ query = command->query;
+ query_len = strlen(query);
}
- if (q->abort_on_error)
- die("query '%s' failed: %d: %s", query,
- mysql_stmt_errno(stmt), mysql_stmt_error(stmt));
+ /*
+ 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->require_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))
{
- int i;
+ replace_dynstr_append_mem(ds, query, query_len);
+ dynstr_append_mem(ds, delimiter, delimiter_length);
+ dynstr_append_mem(ds, "\n", 1);
+ }
- for (i=0 ; (uint) i < q->expected_errors ; i++)
+ 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))
{
- 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 (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_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);
- }
- /* 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");
- return 0; /* Ok */
- }
+ /*
+ 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));
}
- 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)
+ else
{
- 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 */
+ /*
+ 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);
}
- verbose_msg("query '%s' failed: %d: %s", q->query, mysql_stmt_errno(stmt),
- mysql_stmt_error(stmt));
+
+ dynstr_free(&query_str);
+
+ }
+
+ if (sp_protocol_enabled &&
+ complete_query &&
+ match_re(&sp_re, query))
+ {
/*
- if we do not abort on error, failure to run the query does
- not fail the whole test case
+ Create the query as a stored procedure
+ Drop first since sp can exist from a failed mysqltest run
*/
- return 0;
- }
+ 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)));
- return 0;
-}
+ /* 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;
-/*
- Handle absence of errors after execution
+ query= (char*)"CALL mysqltest_tmp_sp()";
+ query_len = strlen(query);
+ }
+ dynstr_free(&query_str);
+ }
- SYNOPSIS
- handle_no_error()
- q - context of query
+ /*
+ Find out how to run this query
- RETURN VALUE
- 0 - OK
- 1 - Some error was expected from this query.
-*/
+ Always run with normal C API if it's not a complete
+ SEND + REAP
-static int handle_no_error(struct st_query *q)
-{
- DBUG_ENTER("handle_no_error");
+ 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 (q->expected_errno[0].type == ERR_ERRNO &&
- q->expected_errno[0].code.errnum != 0)
+ if (sp_created)
{
- /* 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);
+ 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));
}
- else if (q->expected_errno[0].type == ERR_SQLSTATE &&
- strcmp(q->expected_errno[0].code.sqlstate,"00000") != 0)
+
+ if (command->require_file[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);
+
+ /* 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);
}
- DBUG_RETURN(0);
+ 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);
}
-/****************************************************************************\
- * Functions to match SQL statements that can be prepared
-\****************************************************************************/
+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);
+ }
+}
-static void ps_init_re(void)
+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 +5246,233 @@ 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 (*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;
- 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;
-}
+ {
+ command->type=(enum enum_commands) type; /* Found command */
+ /*
+ 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
+ {
+ /* No mysqltest command matched */
-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;
+ 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;
}
-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");
+/*
+ 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.
- 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;
- return tmp_var;
-}
+ The ds_progress will be dumped to <test_name>.progress when
+ test run completes
-static void var_free(void *v)
+*/
+
+void mark_progress(struct st_command* command __attribute__((unused)),
+ int line)
{
- my_free(((VAR*) v)->str_val, MYF(MY_WME));
- if (((VAR*)v)->alloced)
- my_free((char*) v, MYF(MY_WME));
-}
+ 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);
-static VAR* var_from_env(const char *name, const char *def_val)
-{
- const char *tmp;
- VAR *v;
- if (!(tmp = getenv(name)))
- tmp = def_val;
+ /* 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);
- v = var_init(0, name, strlen(name), tmp, strlen(tmp));
- my_hash_insert(&var_hash, (byte*)v);
- return v;
-}
+ /* 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);
-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;
}
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 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;
+
+ /* Init expected errors */
+ memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
- 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;
+
+ 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, "", 0, 65536);
+ 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_name ? result_file_name : ""));
if (mysql_server_init(embedded_server_arg_count,
embedded_server_args,
(char**) embedded_server_groups))
@@ -3796,17 +5481,17 @@ int main(int argc, char **argv)
{
cur_file->file= stdin;
cur_file->file_name= my_strdup("<stdin>", 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 +5500,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 +5532,40 @@ 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 (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)
{
- 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 +5574,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,130 +5602,128 @@ 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;
- save_file[0]=0;
+ strmake(command->require_file, save_file, sizeof(save_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;
- save_file[0]=0;
+ strmake(command->require_file, save_file, sizeof(save_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);
- require_file=0;
+ case Q_REQUIRE:
+ do_get_file_name(command, save_file, sizeof(save_file));
break;
case Q_ERROR:
- global_expected_errors=get_errcodes(global_expected_errno,q);
- break;
- case Q_REQUIRE:
- get_file_name(save_file,q);
- require_file=1;
+ do_get_errcodes(command);
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);
break;
}
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 +5732,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,190 +5743,337 @@ 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_DISABLE_PARSING:
+ if (parsing_disabled == 0)
+ parsing_disabled= 1;
+ else
+ die("Parsing is already disabled");
break;
- case Q_EXIT:
- abort_flag= 1;
+ 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;
+ case Q_DIE:
+ die("%s", command->first_argument);
+ break;
+
+ case Q_RESULT:
+ die("result, deprecated command");
break;
- default: processed = 0; 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 &&
+ 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
*/
- 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))
- {
- /*
- my_stat() successful on result file. Check if we have not run a
- single query, but we do have a result file that contains data.
- Note that we don't care, if my_stat() fails. For example, for a
- 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 (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 (result_file_name)
{
- if (!record)
- error |= check_result(&ds_res, result_file, q->require_file);
+ /* A result file has been specified */
+
+ if (record)
+ {
+ /* Recording - dump the output from test to result file */
+ str_to_file(result_file_name, ds_res.str, ds_res.length);
+ }
else
- str_to_file(result_file, ds_res.str, ds_res.length);
+ {
+ /* Check that the output from test is equal to result file
+ - detect missing result file
+ - detect zero size result file
+ */
+ check_result(&ds_res);
+ }
}
else
{
- /* Print the result to stdout */
+ /* No result_file_name specified to compare with, print to stdout */
printf("%s", ds_res.str);
}
}
- dynstr_free(&ds_res);
+ else
+ {
+ die("The test didn't produce any output");
+ }
- if (!silent)
+ if (!command_executed &&
+ result_file_name && my_stat(result_file_name, &res_info, 0))
{
- if (error)
- printf("not ok\n");
- else
- printf("ok\n");
+ /*
+ my_stat() successful on result file. Check if we have not run a
+ single query, but we do have a result file that contains data.
+ Note that we don't care, if my_stat() fails. For example, for a
+ 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.
+ */
+ die("No queries executed but result file found!");
}
- if (!got_end_timer)
- timer_output(); /* No end_timer cmd, end it */
+ if ( opt_mark_progress && result_file_name )
+ dump_progress();
+
+ /* Dump warning messages */
+ if (result_file_name && ds_warning_messages.length)
+ dump_warning_messages();
+
+ dynstr_free(&ds_res);
+
+ 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=<filename> 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.
-static int read_server_arguments(const char *name)
-{
- char argument[1024],buff[FN_REFLEN], *str=0;
- FILE *file;
+ - If only 'start_timer' is given we measure how long we execute
+ from that point until we terminate mysqltest.
- if (!test_if_hard_path(name))
+ - 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.
+*/
+
+void timer_output(void)
+{
+ if (timer_file)
{
- strxmov(buff, opt_basedir, name, NullS);
- name=buff;
+ char buf[32], *end;
+ 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;
}
- fn_format(buff,name,"","",4);
+}
- if (!embedded_server_arg_count)
+
+ulonglong timer_now(void)
+{
+ return my_getsystime() / 10000;
+}
+
+
+/*
+ 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)
{
- embedded_server_arg_count=1;
- embedded_server_args[0]= (char*) ""; /* Progname */
+ 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);
}
- 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)))
+ my_free(start, MYF(0));
+ command->last_argument= command->end;
+}
+
+
+void free_replace_column()
+{
+ uint i;
+ for (i=0 ; i < max_replace_column ; i++)
{
- *(strend(str)-1)=0; /* Remove end newline */
- if (!(embedded_server_args[embedded_server_arg_count]=
- (char*) my_strdup(str,MYF(MY_WME))))
+ if (replace_column[i])
{
- my_fclose(file,MYF(0));
- return 1;
+ my_free(replace_column[i], 0);
+ replace_column[i]= 0;
}
- 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;
+ max_replace_column= 0;
}
-/****************************************************************************\
- *
- * A primitive timer that give results in milliseconds if the
- * --timer-file=<filename> 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)
+
+/****************************************************************************/
+/*
+ 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)
{
- if (timer_file)
+ 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 buf[32], *end;
- ulonglong timer= timer_now() - timer_start;
- end= longlong2str(timer, buf, 10);
- str_to_file(timer_file,buf, (int) (end-buf));
+ 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;
}
-static ulonglong timer_now(void)
+
+void free_replace()
{
- return my_getsystime() / 10000;
+ DBUG_ENTER("free_replace");
+ if (glob_replace)
+ {
+ my_free((char*) glob_replace,MYF(0));
+ glob_replace=0;
+ }
+ DBUG_VOID_RETURN;
}
-/****************************************************************************
-* Handle replacement of strings
-****************************************************************************/
-
-#define PC_MALLOC 256 /* Bytes for pointers */
-#define PS_MALLOC 512 /* Bytes for data */
-
-#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 +6087,514 @@ typedef struct st_replace_found {
int from_offset;
} REPLACE_STRING;
-#ifndef WORD_BIT
-#define WORD_BIT (8*sizeof(uint))
-#endif
+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);
-static int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name)
+ /* 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
{
- uint i,length,old_count;
- byte *new_pos;
- const char **new_array;
- DBUG_ENTER("insert_pointer_name");
+ 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 */
+};
- if (! pa->typelib.count)
+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)
{
- 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))))
+ bzero(&reg,sizeof(reg));
+ /* find the start of the statement */
+ while (p < expr_end)
{
- my_free((gptr) pa->typelib.type_names,MYF(0));
- DBUG_RETURN (-1);
+ if (*p == '/')
+ break;
+ p++;
}
- 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;
+
+ 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) &reg))
+ die("Out of memory");
}
- length=(uint) strlen(name)+1;
- if (pa->length+length >= pa->max_length)
+ 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++)
{
- 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)
+ 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))
{
- 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;
+ /* 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;
}
- pa->max_length+=PS_MALLOC;
}
- if (pa->typelib.count >= pa->max_count-1)
+
+ 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)
{
- 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));
+ 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;
}
- 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)
+/*
+ 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)
{
- if (pa->typelib.count)
+ 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)))
{
- 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));
+ check_regerr(&r,err_code);
+ return 1;
}
-} /* free_pointer_array */
+ 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
- /* Code for replace rutines */
+ /* 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
#define SET_MALLOC_HUNC 64
+#define LAST_CHAR_CODE 259
typedef struct st_rep_set {
uint *bits; /* Pointer to used sets */
@@ -4354,32 +6626,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 +6720,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 +6903,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 +6946,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 +6962,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 +6989,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 +7008,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 +7043,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 +7079,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 +7097,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 +7117,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;
-}
-
-
-static uint replace_len(my_string str)
-{
- uint len=0;
- while (*str)
- {
- if (str[0] == '\\' && str[1])
- str++;
- str++;
- len++;
- }
- return len;
+ 1 : 0;
}
+/****************************************************************************
+ * Handle replacement of strings
+ ****************************************************************************/
- /* Replace strings; Return length of result string */
+#define PC_MALLOC 256 /* Bytes for pointers */
+#define PS_MALLOC 512 /* Bytes for data */
-uint replace_strings(REPLACE *rep, my_string *start,uint *max_length,
- const char *from)
+int insert_pointer_name(reg1 POINTER_ARRAY *pa,my_string name)
{
- reg1 REPLACE *rep_pos;
- reg2 REPLACE_STRING *rep_str;
- my_string to,end,pos,new_str;
+ uint i,length,old_count;
+ byte *new_pos;
+ const char **new_array;
+ DBUG_ENTER("insert_pointer_name");
- end=(to= *start) + *max_length-1;
- rep_pos=rep+1;
- for (;;)
+ if (! pa->typelib.count)
{
- 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 (!(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))))
{
- 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;
+ my_free((gptr) pa->typelib.type_names,MYF(0));
+ DBUG_RETURN (-1);
}
- if (!*(from-=rep_str->from_offset) && rep_pos->found != 2)
- return (uint) (to - *start);
- rep_pos=rep;
+ 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;
}
-}
-
-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
-*****************************************************************************/
-
-static void free_replace_column()
-{
- uint i;
- for (i=0 ; i < max_replace_column ; i++)
+ length=(uint) strlen(name)+1;
+ if (pa->length+length >= pa->max_length)
{
- if (replace_column[i])
+ 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_free(replace_column[i], 0);
- replace_column[i]= 0;
+ 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;
}
- 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)
+ if (pa->typelib.count >= pa->max_count-1)
{
- 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);
+ 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));
}
- my_free(start, MYF(0));
- q->last_argument= q->end;
-}
+ 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 */
-#if defined(__NETWARE__) || defined(__WIN__)
-/*
- Substitute environment variables with text.
- SYNOPSIS
- subst_env_var()
- arg String that should be substitute
+/* free pointer array */
- DESCRIPTION
- This function takes a string as an input and replaces the
- environment variables, that starts with '$' character, with it value.
+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
- Return string must be freed with my_free()
- RETURN
- String with environment variables replaced.
-*/
+/* Functions that uses replace and replace_regex */
-static char *subst_env_var(const char *str)
+/* Append the string to ds, with optional replace */
+void replace_dynstr_append_mem(DYNAMIC_STRING *ds,
+ const char *val, int len)
{
- char *result;
- char *pos;
+#ifdef __WIN__
+ fix_win_paths(val, len);
+#endif
- result= pos= my_malloc(MAX_QUERY, MYF(MY_FAE));
- while (*str)
+ if (glob_replace_regex)
{
- /*
- 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 == '$')
+ /* Regex replace */
+ if (!multi_reg_replace(glob_replace_regex, (char*)val))
{
- 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 */
+ val= glob_replace_regex->buf;
+ len= strlen(val);
}
- else
- *pos++= *str++;
}
- *pos= 0;
- return result;
-}
-
-
-/*
- popen replacement for Netware
- SYNPOSIS
- my_popen()
- name Command to execute (with possible env variables)
- mode Mode for popen.
-
- 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'
-
- RETURN
- # >= 0 File handle
- -1 Error
-*/
+ if (glob_replace)
+ {
+ /* Normal replace */
+ replace_strings_append(glob_replace, ds, val, len);
+ }
+ else
+ dynstr_append_mem(ds, val, len);
+}
-#undef popen /* Remove wrapper */
-#ifdef __WIN__
-#define popen _popen /* redefine for windows */
-#endif
-FILE *my_popen(const char *cmd, const char *mode __attribute__((unused)))
+/* Append zero-terminated string to ds, with optional replace */
+void replace_dynstr_append(DYNAMIC_STRING *ds, const char *val)
{
- char *subst_cmd;
- FILE *res_file;
+ replace_dynstr_append_mem(ds, val, strlen(val));
+}
- subst_cmd= subst_env_var(cmd);
- res_file= popen(subst_cmd, "r0");
- my_free(subst_cmd, MYF(0));
- return res_file;
+/* 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);
}
-#endif /* __NETWARE__ or __WIN__*/
+
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/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/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= <value>;
+# --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= <value>;
+# --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.
+#
+# <x> first character after "$message=",
+# where the content is not (space or tab)
+# <y*> first character after beginning of the line,
+# where the content is not (space or tab)
+# <z> last char before ";"
+# | beginning or end of line
+#
+# script: let $message= <x><whatever0>|
+# | <y1><whatever1>|
+# |................|
+# | <yn><whatevern><z>;
+# content: "<x><whatever0><new line><y1><whatever1><new line>
+# ....<new line><yn><whatevern><z>"
+# protocol output: |<x><whatever0>|
+# |<y1><whatever1>|
+# |.....|
+# |<yn><whatevern><z>|
+# |--- 80 dashes ---|
+#
+# Attention:
+# <x> and <y*> 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/lib/mtr_cases.pl b/mysql-test/lib/mtr_cases.pl
index 650fb79155d..e6980a0abb9 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,81 +40,191 @@ 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 ( <DISABLED> )
+ {
+ 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 ( <DISABLED> )
+ foreach my $elem ( sort readdir(TESTDIR) ) {
+ my $component_id= undef;
+ my $tname= undef;
+
+ if ($tname= mtr_match_extension($elem, 'test'))
{
- chomp;
- if ( /^\s*(\S+)\s*:\s*(.*?)\s*$/ )
- {
- $disabled{$1}= $2;
- }
+ $component_id = 'mysqld';
+ }
+ elsif ($tname= mtr_match_extension($elem, 'imtest'))
+ {
+ $component_id = 'im';
+ }
+ else
+ {
+ next;
}
- close DISABLED;
- }
- foreach my $elem ( sort readdir(TESTDIR) ) {
- my $tname= mtr_match_extension($elem,"test");
- next if ! defined $tname;
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;
}
- # 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 )
{
- @$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 %sort_criteria;
+
+ # 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 my $tinfo (@$cases)
+ {
+ my @criteria = ();
+
+ # 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
+
+ # Put variables into hash
+ my $test_name= $tinfo->{'name'};
+ my $depend_on_test_name;
+ if ( $test_name =~ /^([\D]+)([0-9]{1})$/ )
{
- my $cmp= mtr_cmp_opts($a->{'master_opt'}, $b->{'master_opt'});
- if ( $cmp == 0 )
- {
- return $a->{'name'} cmp $b->{'name'};
- }
- else
- {
- return $cmp;
- }
+ 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");
+ }
+
+ foreach my $tinfo2 (@$cases)
+ {
+ if ( $tinfo2->{'name'} eq $base_name )
+ {
+ mtr_verbose("found dependent test $tinfo2->{'name'}");
+ $depend_on_test_name=$base_name;
+ }
+ }
}
- if ( $a->{'master_restart'} )
+ if ( defined $depend_on_test_name )
{
- return 1; # Is greater
+ mtr_verbose("Giving $test_name same critera as $depend_on_test_name");
+ $sort_criteria{$test_name} = $sort_criteria{$depend_on_test_name};
}
else
{
- return -1; # Is less
+ #
+ # Append the criteria for sorting, in order of importance.
+ #
+ push(@criteria, "ndb=" . ($tinfo->{'ndb_test'} ? "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;
+ }
+
+ @$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 my $tinfo (@$cases)
+ {
+ print("$sort_criteria{$tinfo->{'name'}} -> \t$tinfo->{'name'}\n");
+ }
+ }
}
return $cases;
@@ -125,13 +238,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 +265,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) )
@@ -166,53 +281,61 @@ 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 )
{
$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;
+ $tinfo->{'slave_num'}= 1; # Default for rpl* tests, use one slave
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 )
+ if ( ! $::opt_ndbcluster_supported )
{
- # Skip all ndb tests
+ # Ndb is not supported, skip them
$tinfo->{'skip'}= 1;
+ $tinfo->{'comment'}= "No ndbcluster support";
return;
}
- if ( ! $::opt_with_ndbcluster )
+ elsif ( $::opt_skip_ndbcluster )
{
- # Ndb is not supported, skip them
+ # 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 ?!
@@ -223,6 +346,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'}= [];
@@ -230,57 +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);
+ my $master_opt= mtr_get_opts_from_file($master_opt_file);
- foreach my $opt ( @$master_opt )
- {
- my $value;
+ foreach my $opt ( @$master_opt )
+ {
+ 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
+ # 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 )
- {
- $tinfo->{'timezone'}= $value;
- last MASTER_OPT;
- }
+ $value= mtr_match_prefix($opt, "--timezone=");
+ if ( defined $value )
+ {
+ $tinfo->{'timezone'}= $value;
+ next;
+ }
- $value= mtr_match_prefix($opt, "--result-file=");
- 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;
- }
+ $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->{'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->{'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 list, add it
- push(@{$tinfo->{'master_opt'}}, @$master_opt);
+ # 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 )
@@ -295,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 )
@@ -303,11 +427,12 @@ sub collect_one_test_case($$$$$$) {
if ( $::glob_win32_perl )
{
$tinfo->{'skip'}= 1;
+ $tinfo->{'comment'}= "No tests with sh scripts on Windows";
+ return;
}
else
{
$tinfo->{'master_sh'}= $master_sh;
- $tinfo->{'master_restart'}= 1;
}
}
@@ -316,37 +441,164 @@ sub collect_one_test_case($$$$$$) {
if ( $::glob_win32_perl )
{
$tinfo->{'skip'}= 1;
+ $tinfo->{'comment'}= "No tests with sh scripts on Windows";
+ return;
}
else
{
$tinfo->{'slave_sh'}= $slave_sh;
- $tinfo->{'slave_restart'}= 1;
}
}
+ 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);
}
- # We can't restart a running server that may be in use
+ # 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 ( $::glob_use_running_server and
- ( $tinfo->{'master_restart'} or $tinfo->{'slave_restart'} ) )
+ if ( $marked_as_disabled )
{
- $tinfo->{'skip'}= 1;
+ 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;
+ }
}
}
+# 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_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/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..a1d7ffe87d8 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= <FILE>;
- 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= <FILE>;
+
+ 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= <FILE>)
+ {
+ $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 (<FROMFILE>);
+ 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,19 +134,30 @@ sub mtr_exe_exists (@) {
}
}
+
sub mtr_copy_dir($$) {
- my $srcdir= shift;
- my $dstdir= shift;
+ my $from_dir= shift;
+ my $to_dir= shift;
- # Create destination directory
- mkpath($dstdir);
- find(\&mtr_copy_one_file, $dstdir);
-}
+# 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);
-sub mtr_copy_one_file {
- print $File::Find::name, "\n";
}
+
sub mtr_same_opts ($$) {
my $l1= shift;
my $l2= shift;
diff --git a/mysql-test/lib/mtr_process.pl b/mysql-test/lib/mtr_process.pl
index 662b70a4fee..2831c179ea5 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.
-
- 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;
- }
- }
+ # One of the child processes died, unless this was expected
+ # mysqltest should be killed and test aborted
- 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,88 @@ 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;
+ my @kill_pids;
+ my %admin_pids;
- for ( my $idx; $idx < 2; $idx++ )
+ 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 +428,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 +443,32 @@ sub mtr_kill_leftovers () {
if ( -f $pidfile )
{
- my $pid= mtr_get_pid_from_file($pidfile);
+ mtr_debug("Processing PID file: '$pidfile'...");
- # Race, could have been removed between I tested with -f
- # and the unlink() below, so I better check again with -f
+ my $pid= mtr_get_pid_from_file($pidfile);
- 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 +482,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 +493,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'}");
}
}
-}
-##############################################################################
-#
-# Shut down mysqld servers we have started from this run of this script
-#
-##############################################################################
+ mtr_debug("mtr_kill_leftovers(): finished.");
+}
-# 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 +594,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,139 +648,288 @@ 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;
-##############################################################################
-#
-# 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 {
- my $spec= 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 %mysql_admin_pids;
- my @to_kill_specs;
+ my $args;
+ mtr_init_args(\$args);
- foreach my $srv ( @$spec )
+ 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'} )
{
- if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) )
+ 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;
+
+}
+
+
+# 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 $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 ( @$spec )
{
- push(@to_kill_specs, $srv);
+ $res= 1; # We are optimistic
+ if ( $srv->{'pid'} and defined $srv->{'port'} )
+ {
+ 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
}
-
- foreach my $srv ( @to_kill_specs )
+ if ($res)
{
- # FIXME wrong log.....
- # FIXME, stderr.....
- # Shutdown time must be high as slave may be in reconnect
- my $args;
+ mtr_debug("mtr_ping_with_timeout(): All mysqld instances are down.");
+ }
+ else
+ {
+ mtr_report("mtr_ping_with_timeout(): At least one server is alive.");
+ }
- mtr_init_args(\$args);
+ return $res;
+}
- mtr_add_arg($args, "--no-defaults");
- mtr_add_arg($args, "--user=%s", $::opt_user);
- mtr_add_arg($args, "--password=");
- if ( -e $srv->{'sockfile'} )
+
+#
+# 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_add_arg($args, "--socket=%s", $srv->{'sockfile'});
+ mtr_verbose("$mysqld->{'type'} $mysqld->{'idx'} exited, pid: $ret_pid");
+ $mysqld->{'pid'}= 0;
+ return;
}
- if ( $srv->{'port'} )
+ }
+
+ foreach my $cluster (@{$::clusters})
+ {
+ if ( $cluster->{'pid'} eq $ret_pid )
{
- mtr_add_arg($args, "--port=%s", $srv->{'port'});
+ mtr_verbose("$cluster->{'name'} cluster ndb_mgmd exited, pid: $ret_pid");
+ $cluster->{'pid'}= 0;
+ return;
}
- if ( $srv->{'port'} and ! -e $srv->{'sockfile'} )
+
+ foreach my $ndbd (@{$cluster->{'ndbds'}})
{
- mtr_add_arg($args, "--protocol=tcp"); # Needed if no --socket
+ if ( $ndbd->{'pid'} eq $ret_pid )
+ {
+ mtr_verbose("$cluster->{'name'} cluster ndbd exited, pid: $ret_pid");
+ $ndbd->{'pid'}= 0;
+ return;
+ }
}
- 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;
}
+ mtr_warning("mark_process_dead couldn't find an entry for pid: $ret_pid");
- # 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)
+}
+
+#
+# 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})
{
- foreach my $pid (keys %mysql_admin_pids)
+ if ( $mysqld->{'pid'} eq $ret_pid )
{
- if ( waitpid($pid,0) > 0 )
+ 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 )
{
- delete $mysql_admin_pids{$pid};
+ mtr_verbose("Crash was expected, file $expect_file exists");
+ mysqld_start($mysqld, $mysqld->{'start_opts'},
+ $mysqld->{'start_slave_master_info'});
+ unlink($expect_file);
}
+
+ return;
}
}
- # 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 $res= 1; # If we just fall through, we are done
- # in the sense that the servers don't
- # listen to their ports any longer
- TIME:
- while ( $timeout-- )
+ foreach my $cluster (@{$::clusters})
{
- foreach my $srv ( @to_kill_specs )
+ if ( $cluster->{'pid'} eq $ret_pid )
{
- $res= 1; # We are optimistic
- if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) )
+ 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_debug("Sleep 1 second waiting for processes to stop using port");
- sleep(1); # One second
- $res= 0;
- next TIME;
+ mtr_verbose("Crash was expected, file $expect_file exists");
+ ndbmgmd_start($cluster);
+ unlink($expect_file);
}
+ return;
}
- 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
+ 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");
- return $res;
}
##############################################################################
@@ -740,32 +942,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 +965,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 +995,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 +1023,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 +1062,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 +1083,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 +1091,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..ec1bed9671b 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,18 +46,12 @@ 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
- ( $::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";
+ $result_file= $eval_file;
}
my $diffopts= $::opt_udiff ? "-u" : "-c";
@@ -70,6 +67,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 +91,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 +119,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,14 +134,21 @@ 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";
}
- # 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
@@ -144,6 +171,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 in the logfiles are errors...
foreach my $tinfo (@$tests)
{
@@ -161,6 +190,10 @@ sub mtr_report_stats ($) {
$tot_tests++;
$tot_failed++;
}
+ if ( $tinfo->{'restarted'} )
+ {
+ $tot_restarts++;
+ }
}
# ----------------------------------------------------------------------
@@ -183,45 +216,74 @@ 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
-
-# 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"
-# }
-# }
+ my $warnlog= "$::opt_vardir/log/warnings";
+
+ 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 ( <ERR> )
+ {
+ # 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";
+ # Print a list of testcases that failed
if ( $tot_failed != 0 )
{
my $test_mode= join(" ", @::glob_test_mode) || "default";
@@ -235,6 +297,32 @@ 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");
}
}
@@ -298,5 +386,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..0c46bbeac79 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.
+##############################################################################
+#
+# mysql-test-run.pl
+#
+# Tool used for executing a suite of .test file
#
-# - 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.
+# See the "MySQL Test framework manual" for more information
+# http://dev.mysql.com/doc/mysqltest/en/index.html
#
-# - 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.
+# Please keep the test framework tools identical in all versions!
+#
+##############################################################################
#
-# Some coding style from the original intent has been kept
+# 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
@@ -66,10 +51,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 +61,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;
+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,25 +83,10 @@ 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;
-# Used by gcov
-our @mysqld_src_dirs=
- (
- "strings",
- "mysys",
- "include",
- "extra",
- "regex",
- "isam",
- "merge",
- "myisam",
- "myisammrg",
- "heap",
- "sql",
- );
-
##############################################################################
#
# Default settings
@@ -128,11 +99,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 +107,32 @@ 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 $default_vardir;
+
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 +140,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 +162,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 +178,59 @@ 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_mem;
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_result_ext;
+our $opt_check_testcases;
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 +242,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_verbose;
+our $opt_valgrind_path;
+our $opt_callgrind;
+
+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 +273,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;
+
+our %mysqld_variables;
+
######################################################################
#
@@ -298,27 +307,36 @@ our $flag_ndb_status_ok= 1;
sub main ();
sub initial_setup ();
sub command_line_setup ();
+sub datadir_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 kill_running_servers ();
+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 do_before_start_master ($);
+sub do_before_start_slave ($);
+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 ($);
@@ -334,12 +352,12 @@ sub main () {
initial_setup();
command_line_setup();
+
+ check_ndbcluster_support(\%mysqld_variables);
+ check_ssl_support(\%mysqld_variables);
+ check_debug_support(\%mysqld_variables);
+
executable_setup();
-
- if (! $opt_skip_ndbcluster and ! $opt_with_ndbcluster)
- {
- $opt_with_ndbcluster= ndbcluster_support();
- }
environment_setup();
signal_setup();
@@ -354,44 +372,43 @@ 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 ( $opt_bench )
{
- 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");
- }
+ initialize_servers();
+ run_benchmarks(shift); # Shift what? Extra arguments?!
}
- elsif ( $opt_bench )
+ elsif ( $opt_stress )
{
- run_benchmarks(shift); # Shift what? Extra arguments?!
+ 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;
+
+ initialize_servers();
+
+ run_suite($opt_suite, $tests);
}
mtr_exit(0);
@@ -410,13 +427,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,21 +449,47 @@ 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;
$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/release",
+ "$glob_basedir/client/debug",
+ "$glob_basedir/client",
+ "$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");
+
+ # Use the mysqld found above to find out what features are available
+ collect_mysqld_features();
+
}
@@ -467,9 +505,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 +532,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 +548,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 +561,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 +625,55 @@ 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,
+ 'mem' => \$opt_mem,
# 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 +683,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-/ )
@@ -630,14 +706,68 @@ sub command_line_setup () {
}
# --------------------------------------------------------------------------
- # Set the "var/" directory, as it is the base for everything else
+ # 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'");
+ # --------------------------------------------------------------------------
+ # 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
+ # --------------------------------------------------------------------------
+ $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 and
+ $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;
+ $opt_vardir= $default_vardir;
+ mtr_report("Using 4.1 vardir trick");
}
+ $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
($glob_win32 and $opt_vardir =~ m,^[a-z]:/,i) )
@@ -647,47 +777,53 @@ 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
- # 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
+ # Set socket
# --------------------------------------------------------------------------
+ if (!$opt_socket)
+ {
+ $opt_socket= $mysqld_variables{'socket'};
+ }
- if ( $opt_extern and $opt_local )
+ # --------------------------------------------------------------------------
+ # Check im suport
+ # --------------------------------------------------------------------------
+ if ( $mysql_version_id < 50000 )
{
- mtr_error("Can't use --extern and --local at the same time");
+ # Instance manager is not supported until 5.0
+ $opt_skip_im= 1;
+
}
- if ( ! $opt_socket )
- { # FIXME set default before reading options?
-# $opt_socket= '@MYSQL_UNIX_ADDR@';
- $opt_socket= "/tmp/mysql.sock"; # FIXME
+ if ( $glob_win32 )
+ {
+ mtr_report("Disable Instance manager - not supported on Windows");
+ $opt_skip_im= 1;
}
# --------------------------------------------------------------------------
- # Look at the command line options and set script flags
+ # 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;
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 )
{
@@ -695,109 +831,158 @@ sub command_line_setup () {
}
}
+
+ # --------------------------------------------------------------------------
+ # ps protcol flag
+ # --------------------------------------------------------------------------
if ( $opt_ps_protocol )
{
push(@glob_test_mode, "ps-protocol");
}
- # FIXME don't understand what this is
-# if ( $opt_local_master )
-# {
-# $opt_master_myport= 3306;
-# }
+ # --------------------------------------------------------------------------
+ # Ndb cluster flags
+ # --------------------------------------------------------------------------
+ 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";
+ }
+
+ # --------------------------------------------------------------------------
+ # 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");
}
- 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 )
- {
- $opt_gdb= 1;
- if ( $opt_extern )
- {
- mtr_error("Can't use --extern with --manual-gdb");
- }
- }
+ # --------------------------------------------------------------------------
+ # 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;
- if ( $opt_ddd )
+ # --------------------------------------------------------------------------
+ # Check valgrind arguments
+ # --------------------------------------------------------------------------
+ if ( $opt_valgrind or $opt_valgrind_path or defined $opt_valgrind_options)
{
- if ( $opt_extern )
- {
- mtr_error("Can't use --extern with --ddd");
- }
+ mtr_report("Turning on valgrind for all executables");
+ $opt_valgrind= 1;
+ $opt_valgrind_mysqld= 1;
+ $opt_valgrind_mysqltest= 1;
}
-
- if ( $opt_ndbconnectstring )
+ elsif ( $opt_valgrind_mysqld )
{
- $glob_use_running_ndbcluster= 1;
- $opt_with_ndbcluster= 1;
+ mtr_report("Turning on valgrind for mysqld(s) only");
+ $opt_valgrind= 1;
}
- else
+ elsif ( $opt_valgrind_mysqltest )
{
- $opt_ndbconnectstring= "host=localhost:$opt_ndbcluster_port";
+ mtr_report("Turning on valgrind for mysqltest only");
+ $opt_valgrind= 1;
}
- if ( $opt_skip_ndbcluster )
+ if ( $opt_callgrind )
{
- $opt_with_ndbcluster= 0;
- }
+ mtr_report("Turning on valgrind with callgrind for mysqld(s)");
+ $opt_valgrind= 1;
+ $opt_valgrind_mysqld= 1;
- # 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;
+ # Set special valgrind options unless options passed on command line
+ $opt_valgrind_options="--trace-children=yes"
+ unless defined $opt_valgrind_options;
+ }
- # If valgrind flag not defined, define if other valgrind flags are
- unless ( defined $opt_valgrind )
+ if ( $opt_valgrind )
{
- $opt_valgrind= ""
- if defined $opt_valgrind_mysqltest or defined $opt_valgrind_all;
+ # Set valgrind_options to default unless already defined
+ $opt_valgrind_options=$default_valgrind_options
+ unless defined $opt_valgrind_options;
+
+ 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 +997,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 datadir_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 +1210,238 @@ sub command_line_setup () {
#
##############################################################################
-sub executable_setup () {
- if ( $opt_source_dist )
+sub collect_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= "$glob_mysql_test_dir/mysqld.spec.$$";
+ if ( mtr_run($exe_mysqld,
+ ["--no-defaults",
+ "--verbose",
+ "--help"],
+ "", "$spec_file", "$spec_file", "") != 0 )
{
- if ( $glob_win32 )
- {
- $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");
- }
- 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");
- }
+ mtr_error("Failed to get version and list of features from %s",
+ $exe_mysqld);
+ }
+
+ my $F= IO::File->new($spec_file) or
+ mtr_error("can't open file \"$spec_file\": $!");
- if ( $glob_use_embedded_server )
+ while ( my $line= <$F> )
+ {
+ # First look for version
+ if ( !$mysql_version_id )
{
- 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");
+ # Look for version
+ 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;
+ #print "mysql_version_id: $mysql_version_id\n";
+ mtr_report("MySQL Version $1.$2.$3");
+ }
}
else
{
- if ( $opt_valgrind_mysqltest )
+ if (!$found_variable_list_start)
{
- # 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");
+ # Look for start of variables list
+ if ( $line =~ /[\-]+\s[\-]+/ )
+ {
+ $found_variable_list_start= 1;
+ }
}
else
{
- $exe_mysqltest= mtr_exe_exists("$path_client_bindir/mysqltest");
+ # Put variables into hash
+ if ( $line =~ /^([\S]+)[ \t]+(.*)$/ )
+ {
+ # print "$1=$2\n";
+ $mysqld_variables{$1}= $2;
+ }
+ else
+ {
+ # 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");
+ }
+ }
}
- $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";
+ }
+ }
+ 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;
+
+}
+
+
+sub executable_setup () {
+
+ #
+ # 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")
+ {
+ $exe_libtool= "../libtool";
+ if ($opt_valgrind or $glob_debugger)
+ {
+ mtr_report("Using \"$exe_libtool\" when running valgrind or debugger");
+ }
+ }
+
+ # 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");
}
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_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");
+ $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");
+ if ( $mysql_version_id >= 50100 )
+ {
+ $exe_mysqlslap= mtr_exe_exists("$path_client_bindir/mysqlslap");
+ }
+
+ if ( ! $glob_win32 )
+ {
+ # Look for mysql_fix_system_table script
$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");
+ mtr_script_exists("$glob_basedir/scripts/mysql_fix_privilege_tables",
+ "$path_client_bindir/mysql_fix_privilege_tables");
+ }
- $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");
+ if ( ! $opt_skip_ndbcluster)
+ {
+ # Look for ndb tols and binaries
+ 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("$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");
+
+ $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 ( $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");
- }
+ # Look for the udf_example library
+ $lib_udf_example=
+ mtr_file_exists("$glob_basedir/sql/.libs/udf_example.so",
+ "$glob_basedir/sql/release/udf_example.dll",
+ "$glob_basedir/sql/debug/udf_example.dll");
- 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
- {
+ # 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");
- $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";
+
}
- $exe_master_mysqld= $exe_master_mysqld || $exe_mysqld;
- $exe_slave_mysqld= $exe_slave_mysqld || $exe_mysqld;
+ # 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");
+ }
+}
+
- $path_ndb_backup_dir=
- "$opt_vardir/ndbcluster-$opt_ndbcluster_port";
- $file_ndb_testrun_log= "$opt_vardir/log/ndb_testrun.log";
+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 +1449,331 @@ sub executable_setup () {
sub environment_setup () {
+ umask(022);
+
+ my @ld_library_paths;
+
# --------------------------------------------------------------------------
- # We might not use a standard installation directory, like /usr/lib.
- # Set LD_LIBRARY_PATH to make sure we find our installed libraries.
+ # Setup LD_LIBRARY_PATH so the libraries from this distro/clone
+ # are used in favor of the system installed ones
# --------------------------------------------------------------------------
+ if ( $opt_source_dist )
+ {
+ push(@ld_library_paths, "$glob_basedir/libmysql/.libs/",
+ "$glob_basedir/libmysql_r/.libs/");
+ }
+ else
+ {
+ push(@ld_library_paths, "$glob_basedir/lib");
+ }
- unless ( $opt_source_dist )
+ # --------------------------------------------------------------------------
+ # Add the path where libndbclient can be found
+ # --------------------------------------------------------------------------
+ if ( $opt_ndbcluster_supported )
{
- $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/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,
+ $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,
+ $ENV{'DYLD_LIBRARY_PATH'} ?
+ 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;
+ $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'}= $mysqld_variables{'port'};
- if ( $glob_cygwin_perl )
+ $ENV{MTR_BUILD_THREAD}= 0 unless $ENV{MTR_BUILD_THREAD}; # Set if not set
+
+ # ----------------------------------------------------
+ # Setup env for NDB
+ # ----------------------------------------------------
+ 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{'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 )
{
- foreach my $key ('MYSQL_TEST_WINDIR','MASTER_MYSOCK')
+ $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
+ # ----------------------------------------------------
+ if ( $exe_mysqlslap )
+ {
+ my $cmdline_mysqlslap=
+ "$exe_mysqlslap -uroot " .
+ "--port=$master->[0]->{'port'} " .
+ "--socket=$master->[0]->{'path_sock'} --password= " .
+ "--lock-directory=$opt_tmpdir";
+
+ if ( $opt_debug )
{
- $ENV{$key}= `cygpath -w $ENV{$key}`;
- $ENV{$key} =~ s,\\,\\\\,g;
- chomp($ENV{$key});
+ $cmdline_mysqlslap .=
+ " --debug=d:t:A,$path_vardir_trace/log/mysqlslap.trace";
}
+ $ENV{'MYSQL_SLAP'}= $cmdline_mysqlslap;
}
- $ENV{MTR_BUILD_THREAD}= 0 unless $ENV{MTR_BUILD_THREAD}; # Set if not set
+ # ----------------------------------------------------
+ # 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";
+ }
+ }
+
+ # Create an environment variable to make it possible
+ # to detect that valgrind is being used from test cases
+ $ENV{'VALGRIND_TEST'}= $opt_valgrind;
+
}
@@ -1099,10 +1788,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");
}
@@ -1113,53 +1803,66 @@ sub handle_int_signal () {
#
##############################################################################
-sub kill_running_server () {
+sub kill_running_servers () {
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
+ 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();
-
- ndbcluster_stop();
- $master->[0]->{'ndbcluster'}= 1;
- }
+ }
}
-sub kill_and_cleanup () {
+sub cleanup_stale_files () {
- kill_running_server ();
+ 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" )
+ if ( $opt_vardir eq $default_vardir )
{
#
# 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
{
@@ -1175,27 +1878,29 @@ sub kill_and_cleanup () {
# 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/");
}
+ if ( $opt_mem )
+ {
+ # Runinng with var as a link to some "memory" location, normally tmpfs
+ rmtree($opt_mem);
+ mkpath($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);
+ }
+
mkpath("$opt_vardir/log");
mkpath("$opt_vardir/run");
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,101 +1919,377 @@ 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('', <FILE>);
+ 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'} )
+ {
+ 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 )
+ if ($opt_skip_ndbcluster)
{
- mtr_report("No ndbcluster support");
- return 0;
+ mtr_report("Skipping ndbcluster");
+ $opt_skip_ndbcluster_slave= 1;
+ return;
+ }
+
+ if ( ! $mysqld_variables->{'ndb-connectstring'} )
+ {
+ mtr_report("Skipping ndbcluster, mysqld not compiled with ndbcluster");
+ $opt_skip_ndbcluster= 1;
+ $opt_skip_ndbcluster_slave= 1;
+ return;
}
- mtr_report("Has ndbcluster support");
- return 1;
+ $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;
}
-# FIXME why is there a different start below?!
-sub ndbcluster_install () {
+sub ndbcluster_start_install ($) {
+ my $cluster= shift;
- if ( ! $opt_with_ndbcluster or $glob_use_running_ndbcluster )
+ if ( $opt_skip_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;
+
+ 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
+ if ( $mysql_version_id < 50100 )
+ {
+ # 4.1 and 5.0 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";
+ 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 (<IN>)
+ {
+ 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'}/;
+ 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";
}
+ close OUT;
+ close IN;
+
+
+ # Start cluster with "--initial"
- ndbcluster_stop();
- $master->[0]->{'ndbcluster'}= 1;
+ ndbcluster_start($cluster, "--initial");
return 0;
}
-sub ndbcluster_start () {
- if ( ! $opt_with_ndbcluster or $glob_use_running_ndbcluster )
+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'}");
+ 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");
+
+ 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;
}
- # 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", "", "") )
+
+ if ( $cluster->{'pid'} )
{
- mtr_error("Error ndbcluster_start");
- return 1;
+ 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 ndbcluster_stop () {
- if ( ! $opt_with_ndbcluster or $glob_use_running_ndbcluster )
+sub rm_ndbcluster_tables ($) {
+ my $dir= shift;
+ foreach my $bin ( glob("$dir/cluster/apply_status*"),
+ glob("$dir/cluster/schema*") )
{
- return;
+ unlink($bin);
}
- 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", "", "");
-
- return;
}
@@ -1323,9 +2304,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 +2315,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 +2329,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 +2363,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 +2390,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 )
@@ -1441,26 +2418,103 @@ sub run_suite () {
#
##############################################################################
+sub initialize_servers () {
+
+ datadir_setup();
+
+ if ( ! $glob_use_running_server )
+ {
+ kill_running_servers();
+
+ if ( ! $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++)
+ {
+ 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 && !$opt_skip_ndbcluster_slave &&
+ 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 )
{
- # failed to install, disable usage but flag that its no ok
- $opt_with_ndbcluster= 0;
- $flag_ndb_status_ok= 0;
+ 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 +2523,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 +2559,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,31 +2591,127 @@ sub install_db ($$) {
}
-##############################################################################
-#
-# Run a single test case
-#
-##############################################################################
+sub im_prepare_env($) {
+ my $instance_manager = shift;
-# When we get here, we have already filtered out test cases that doesn't
-# apply to the current setup, for example if we use a running server, test
-# cases that restart the server are dropped. So this function should mostly
-# be about doing things, not a lot of logic.
+ im_create_passwd_file($instance_manager);
+ im_prepare_data_dir($instance_manager);
+}
-# We don't start and kill the servers for each testcase. But some
-# testcases needs a restart, because they specify options to start
-# mysqld with. After that testcase, we need to restart again, to set
-# back the normal options.
-sub run_testcase ($) {
- my $tinfo= shift;
+sub im_create_passwd_file($) {
+ my $instance_manager = shift;
- my $tname= $tinfo->{'name'};
+ my $pwd_file_path = $instance_manager->{'password_file'};
- mtr_tonewfile($opt_current_test,"$tname\n"); # Always tell where we are
+ 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 <<EOF
+[mysql]
+
+[manager]
+pid-file = $instance_manager->{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 <<EOF
+[mysqld$server_id]
+socket = $instance->{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
+;
+ if ( $mysql_version_id < 50100 )
+ {
+ print OUT "skip-bdb\n";
+ }
+ print OUT "nonguarded\n" if $instance->{'nonguarded'};
+ if ( $mysql_version_id >= 50100 )
+ {
+ 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);
+ }
+ }
+}
- # output current test to ndbcluster log file to enable diagnostics
- mtr_tofile($file_ndb_testrun_log,"CURRENT TEST $tname\n");
+
+sub run_testcase_check_skip_test($)
+{
+ my ($tinfo)= @_;
# ----------------------------------------------------------------------
# If marked to skip, just print out and return.
@@ -1561,213 +2724,154 @@ sub run_testcase ($) {
{
mtr_report_test_name($tinfo);
mtr_report_test_skipped($tinfo);
- return;
+ return 1;
}
- # ----------------------------------------------------------------------
- # 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 ( ! $glob_use_running_server and ! $glob_use_embedded_server )
+ if ($tinfo->{'ndb_test'})
{
- # 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 )
+ foreach my $cluster (@{$clusters})
{
- $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;
- }
+ last if ($opt_skip_ndbcluster_slave and
+ $cluster->{'name'} eq 'Slave');
- if ( $do_restart )
- {
- stop_masters();
- delete $master->[0]->{'running_master_is_special'}; # Forget history
+ # 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;
+ }
}
+ }
- # ----------------------------------------------------------------------
- # Always terminate all slaves, if any. Else we may have useless
- # reconnection attempts and error messages in case the slave and
- # master servers restart.
- # ----------------------------------------------------------------------
+ return 0;
+}
- stop_slaves();
- }
- # ----------------------------------------------------------------------
- # Prepare to start masters. Even if we use embedded, we want to run
- # the preparation.
- # ----------------------------------------------------------------------
+sub do_before_run_mysqltest($)
+{
+ my $tinfo= shift;
+ my $tname= $tinfo->{'name'};
- $ENV{'TZ'}= $tinfo->{'timezone'};
+ # Remove old files produced by mysqltest
+ my $result_dir= "r";
+ if ( $opt_suite ne "main" )
+ {
+ $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_report_test_name($tinfo);
+ 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");
+ }
-# FIXME test cases that depend on each other, prevent this from
-# being at this location.
-# do_before_start_master($tname,$tinfo->{'master_sh'});
+ 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";
+ }
+}
- # ----------------------------------------------------------------------
- # If any mysqld servers running died, we have to know
- # ----------------------------------------------------------------------
+sub do_after_run_mysqltest($)
+{
+ my $tinfo= shift;
+ my $tname= $tinfo->{'name'};
- mtr_record_dead_children();
+ mtr_tofile($path_mysqltest_log,"CURRENT TEST $tname\n");
- # ----------------------------------------------------------------------
- # Start masters
- # ----------------------------------------------------------------------
+ # Save info from this testcase run to mysqltest.log
+ mtr_appendfile_to_file($path_timefile, $path_mysqltest_log)
+ if -f $path_timefile;
- 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.
+ # Remove the file that mysqltest writes info to
+ unlink($path_timefile);
- 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'},[]);
+##############################################################################
+#
+# Run a single test case
+#
+##############################################################################
- # Restore skip_ndbcluster
- $opt_skip_ndbcluster= $save_opt_skip_ndbcluster;
+# When we get here, we have already filtered out test cases that doesn't
+# apply to the current setup, for example if we use a running server, test
+# cases that restart the server are dropped. So this function should mostly
+# be about doing things, not a lot of logic.
- 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;
- }
- }
+# We don't start and kill the servers for each testcase. But some
+# testcases needs a restart, because they specify options to start
+# mysqld with. After that testcase, we need to restart again, to set
+# back the normal options.
- if ( $tinfo->{'master_restart'} )
- {
- # Save this test case information, so next can examine it
- $master->[0]->{'running_master_is_special'}= $tinfo;
- }
- }
+sub run_testcase ($) {
+ my $tinfo= shift;
- # ----------------------------------------------------------------------
- # Start slaves - if needed
- # ----------------------------------------------------------------------
+ my $master_restart= run_testcase_need_master_restart($tinfo);
+ my $slave_restart= run_testcase_need_slave_restart($tinfo);
- if ( $tinfo->{'slave_num'} )
+ if ($master_restart or $slave_restart)
+ {
+ # Can't restart a running server that may be in use
+ if ( $glob_use_running_server )
{
- mtr_tofile($slave->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n");
+ $tinfo->{'skip'}= 1;
+ $tinfo->{'comment'}= "Can't restart a running server";
- do_before_start_slave($tname,$tinfo->{'slave_sh'});
+ mtr_report_test_name($tinfo);
+ mtr_report_test_skipped($tinfo);
+ return;
+ }
- 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;
- }
- }
- }
+ run_testcase_stop_servers($tinfo, $master_restart, $slave_restart);
+ }
+ my $died= mtr_record_dead_children();
+ if ($died or $master_restart or $slave_restart)
+ {
+ if (run_testcase_start_servers($tinfo))
+ {
+ mtr_report_test_name($tinfo);
+ report_failure_and_restart($tinfo);
+ return 1;
}
}
# ----------------------------------------------------------------------
- # If --start-and-exit given, stop here to let user manually run tests
+ # If --start-and-exit or --start-dirty 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 +2879,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 +2901,125 @@ 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 ( $tinfo->{'component_id'} eq 'im' and
+ !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,25 +3029,18 @@ 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
@@ -1867,33 +3057,26 @@ 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);
}
-sub do_before_start_slave ($$) {
- my $tname= shift;
- my $init_script= shift;
- # 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" )
+sub do_before_start_slave ($) {
+ my ($tinfo)= @_;
+
+ 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 )
{
@@ -1901,7 +3084,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 +3094,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 +3105,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
@@ -1931,21 +3115,25 @@ 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);
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 +3142,44 @@ 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'});
+ if ( $mysql_version_id >= 50100 )
+ {
+ mtr_add_arg($args, "%s--ndb-extra-logging", $prefix);
+ }
+ }
}
if ( $type eq 'slave' )
@@ -1986,25 +3189,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);
@@ -2013,10 +3217,11 @@ 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";
mtr_add_arg($args, "%s--slave-load-tmpdir=%s", $prefix,
- $path_slave_load_tmpdir);
+ $slave_load_path);
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 +3238,27 @@ 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'});
+ if ( $mysql_version_id >= 50100 )
+ {
+ mtr_add_arg($args, "%s--ndb-extra-logging", $prefix);
+ }
+ }
} # end slave
if ( $opt_debug )
@@ -2044,28 +3266,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 +3295,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 +3309,22 @@ sub mysqld_arguments ($$$$$) {
mtr_add_arg($args, "%s--user=root", $prefix);
}
- if ( $type eq 'master' )
+ my $found_skip_core= 0;
+ foreach my $arg ( @opt_extra_mysqld_opt, @$extra_opt )
{
-
- if ( ! $opt_old_master )
+ # Allow --skip-core-file to be set in master.opt file
+ if ($arg eq "--skip-core-file")
{
- mtr_add_arg($args, "%s--rpl-recovery-rank=1", $prefix);
- mtr_add_arg($args, "%s--init-rpl-role=master", $prefix);
+ $found_skip_core= 1;
}
-
- # FIXME strange,.....
- # FIXME MYSQL_MYPORT is not set anythere?!
- if ( $opt_local_master )
+ else
{
- mtr_add_arg($args, "%s--host=127.0.0.1", $prefix);
- mtr_add_arg($args, "%s--port=%s", $prefix, $ENV{'MYSQL_MYPORT'});
+ mtr_add_arg($args, "%s%s", $prefix, $arg);
}
}
-
- foreach my $arg ( @opt_extra_mysqld_opt, @$extra_opt )
+ if ( !$found_skip_core )
{
- mtr_add_arg($args, "%s%s", $prefix, $arg);
+ mtr_add_arg($args, "%s%s", $prefix, "--core-file");
}
if ( $opt_bench )
@@ -2123,7 +3334,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 +3341,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 +3348,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 +3371,675 @@ 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)
+ {
+ 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 )
{
- if ( $pid= mtr_spawn($exe, $args, "",
- $master->[$idx]->{'path_myerr'},
- $master->[$idx]->{'path_myerr'},
- "",
- { append_log_file => 1 }) )
+ 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;
-}
+ # Start shutdown of clusters
+ foreach my $cluster (@{$clusters})
+ {
+ if ( $cluster->{'pid'} )
+ {
+ $pid= mtr_ndbmgm_start($cluster, "shutdown");
+ $admin_pids{$pid}= 1;
-sub stop_masters_slaves () {
+ push(@kill_pids,{
+ pid => $cluster->{'pid'},
+ pidfile => $cluster->{'path_pid'}
+ });
- 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";
-}
+ $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;
+ }
+ }
+ }
+ }
-sub stop_masters () {
+ # Wait blocking until all shutdown processes has completed
+ mtr_wait_blocking(\%admin_pids);
- my @args;
+ # Make sure that process has shutdown else try to kill them
+ mtr_check_stop_servers(\@kill_pids);
- for ( my $idx; $idx < 2; $idx++ )
+ foreach my $mysqld (@{$master}, @{$slave})
{
- # FIXME if we hit ^C before fully started, this test will prevent
- # the mysqld process from being killed
- if ( $master->[$idx]->{'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
- }
+ rm_ndbcluster_tables($mysqld->{'path_myddir'});
}
+}
+
+
+sub run_testcase_need_master_restart($)
+{
+ my ($tinfo)= @_;
- if ( ! $master->[0]->{'ndbcluster'} )
+ # We try to find out if we are to restart the master(s)
+ my $do_restart= 0; # Assumes we don't have to
+
+ 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");
+ }
+ 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 master: Test does not need cluster");
+ }
+ elsif ( ! $opt_skip_ndbcluster and
+ $tinfo->{'ndb_test'} == 1 and
+ $clusters->[0]->{'pid'} == 0 )
{
- ndbcluster_stop();
- $master->[0]->{'ndbcluster'}= 1;
+ $do_restart= 1; # Restart with cluster
+ mtr_verbose("Restart master: Test need cluster");
+ }
+ elsif( $tinfo->{'component_id'} eq 'im' )
+ {
+ $do_restart= 1;
+ mtr_verbose("Restart master: Always restart for im tests");
+ }
+ elsif ( $master->[0]->{'running_master_options'} and
+ $master->[0]->{'running_master_options'}->{'timezone'} ne
+ $tinfo->{'timezone'})
+ {
+ $do_restart= 1;
+ mtr_verbose("Restart master: Different timezone");
+ }
+ # 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 master: running with different options '" .
+ join(" ", @{$tinfo->{'master_opt'}}) . "' != '" .
+ join(" ", @{$master->[0]->{'start_opts'}}) . "'" );
+ }
+ elsif( ! $master->[0]->{'pid'} )
+ {
+ $do_restart= 1;
+ mtr_verbose("Restart master: master is not started");
}
- mtr_stop_mysqld_servers(\@args);
+ return $do_restart;
}
-sub stop_slaves () {
- my $force= shift;
+sub run_testcase_need_slave_restart($)
+{
+ my ($tinfo)= @_;
- my @args;
+ # We try to find out if we are to restart the slaves
+ my $do_slave_restart= 0; # Assumes we don't have to
- for ( my $idx; $idx < 3; $idx++ )
+ if ( $glob_use_embedded_server )
+ {
+ mtr_verbose("Never start or restart for embedded server");
+ return $do_slave_restart;
+ }
+ elsif ( $max_slave_num == 0)
{
- if ( $slave->[$idx]->{'pid'} )
+ mtr_verbose("Skip slave restart: No testcase use slaves");
+ }
+ else
+ {
+
+ # 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)
{
- 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
+ mtr_verbose("Restart slave: Slave is started, always restart");
+ $do_slave_restart= 1;
+ }
+ elsif ( $tinfo->{'slave_num'} )
+ {
+ mtr_verbose("Restart slave: Test need slave");
+ $do_slave_restart= 1;
}
}
- mtr_stop_mysqld_servers(\@args);
+ 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_mysqltest ($) {
- my $tinfo= shift;
+sub run_testcase_stop_servers($$$) {
+ my ($tinfo, $do_restart, $do_slave_restart)= @_;
+ my $pid;
+ my %admin_pids; # hash of admin processes that requests shutdown
+ my @kill_pids; # list of processes to shutdown/kill
- my $cmdline_mysqldump= "$exe_mysqldump --no-defaults -uroot " .
- "--port=$master->[0]->{'path_myport'} " .
- "--socket=$master->[0]->{'path_mysock'} --password=";
- if ( $opt_debug )
+ # Remember if we restarted for this test case (count restarts)
+ $tinfo->{'restarted'}= $do_restart;
+
+ if ( $do_restart )
{
- $cmdline_mysqldump .=
- " --debug=d:t:A,$opt_vardir/log/mysqldump.trace";
+ delete $master->[0]->{'running_master_options'}; # Forget history
+
+ # Start shutdown of all started masters
+ foreach my $mysqld (@{$master})
+ {
+ 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
+ }
+ }
}
- my $cmdline_mysqlimport= "$exe_mysqlimport -uroot " .
- "--port=$master->[0]->{'path_myport'} " .
- "--socket=$master->[0]->{'path_mysock'} --password=";
- if ( $opt_debug )
+
+ if ( $do_restart || $do_slave_restart )
{
- $cmdline_mysqlimport .=
- " --debug=d:t:A,$opt_vardir/log/mysqlimport.trace";
+
+ delete $slave->[0]->{'running_slave_options'}; # 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
+ }
+ }
}
- my $cmdline_mysqlshow= "$exe_mysqlshow -uroot " .
- "--port=$master->[0]->{'path_myport'} " .
- "--socket=$master->[0]->{'path_mysock'} --password=";
- if ( $opt_debug )
+ # ----------------------------------------------------------------------
+ # 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})
{
- $cmdline_mysqlshow .=
- " --debug=d:t:A,$opt_vardir/log/mysqlshow.trace";
+ if ( ! $mysqld->{'pid'} )
+ {
+ # Remove ndbcluster tables if server is stopped
+ rm_ndbcluster_tables($mysqld->{'path_myddir'});
+ }
}
+}
- my $cmdline_mysqlbinlog=
- "$exe_mysqlbinlog --no-defaults --local-load=$opt_tmpdir";
- if ( $opt_debug )
+#
+# run_testcase_start_servers
+#
+# Start the servers needed by this test case
+#
+# RETURN
+# 0 OK
+# 1 Start failed
+#
+
+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' )
{
- $cmdline_mysqlbinlog .=
- " --debug=d:t:A,$opt_vardir/log/mysqlbinlog.trace";
+ 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($tinfo);
+
+ 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
+
+ if ( $mysql_version_id >= 50100 )
+ {
+ # 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'}))
+ {
+
+ $tinfo->{'comment'}= "Failed to create 'cluster/apply_status' table";
+ return 1;
+ }
+ }
+ mtr_tofile($master->[1]->{'path_myerr'},"CURRENT_TEST: $tname\n");
+
+ mysqld_start($master->[1],$tinfo->{'master_opt'},[]);
+ }
+
+ # 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' )
+ {
+ # 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.
- my $cmdline_mysql=
- "$exe_mysql --host=localhost --user=root --password= " .
- "--port=$master->[0]->{'path_myport'} " .
- "--socket=$master->[0]->{'path_mysock'}";
+ im_create_defaults_file($instance_manager);
- 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 ( ! mtr_im_start($instance_manager, $tinfo->{im_opts}) )
+ {
+ $tinfo->{'comment'}= "Failed to start Instance Manager. ";
+ return 1;
+ }
+ }
- if ( $glob_use_embedded_server )
+ # ----------------------------------------------------------------------
+ # Start slaves - if needed
+ # ----------------------------------------------------------------------
+ if ( $tinfo->{'slave_num'} )
{
- $cmdline_mysql_client_test.=
- " -A --language=$path_language" .
- " -A --datadir=$slave->[0]->{'path_myddir'}" .
- " -A --character-sets-dir=$path_charsetsdir";
+ mtr_tofile($slave->[0]->{'path_myerr'},"CURRENT_TEST: $tname\n");
+
+ restore_slave_databases($tinfo->{'slave_num'});
+
+ do_before_start_slave($tinfo);
+
+ 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'});
+
+ }
+ }
+
+ # Save this test case information, so next can examine it
+ $slave->[0]->{'running_slave_options'}= $tinfo;
}
- 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'}";
+ # Wait for clusters to start
+ foreach my $cluster (@{$clusters})
+ {
+ next if !$cluster->{'pid'};
+ if (ndbcluster_wait_started($cluster, ""))
+ {
+ # failed to start
+ $tinfo->{'comment'}= "Start of $cluster->{'name'} cluster failed";
+ return 1;
+ }
+ }
- # 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'}";
+ # Wait for mysqld's to start
+ foreach my $mysqld (@{$master},@{$slave})
+ {
- $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;
+ next if !$mysqld->{'pid'};
- $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;
+ if (mysqld_wait_started($mysqld))
+ {
+ # failed to start
+ $tinfo->{'comment'}=
+ "Failed to start $mysqld->{'type'} mysqld $mysqld->{'idx'}";
+ return 1;
+ }
+ }
+ return 0;
+}
- my $exe= $exe_mysqltest;
- my $args;
+#
+# 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!
+#
+# RETURN VALUE
+# 0 OK
+# 1 Check failed
+#
+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, "--socket=%s", $master->[0]->{'path_mysock'});
+ 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 eq "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");
+ }
+ return $res;
+}
+
+
+
+sub run_mysqltest ($) {
+ my ($tinfo)= @_;
+ my $exe= $exe_mysqltest;
+ 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, "--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, ....
@@ -2404,17 +4070,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 +4114,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 +4125,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 +4136,252 @@ 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'})
+ {
+ if (run_check_testcase("after", $mysqld))
+ {
+ # Check failed, mark the test case with that info
+ $tinfo->{'check_testcase_failed'}= 1;
+ }
+ }
+ }
+ }
+
+ return $res;
+
}
-sub valgrind_arguments {
+#
+# 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
- 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";
+ # Add name of the exe before args
+ unshift(@$$args, "$$exe");
- if ( defined $opt_valgrind_all )
+ }
+ else
{
- mtr_add_arg($args, "-v");
- mtr_add_arg($args, "--show-reachable=yes");
+ mtr_error("Unknown argument \"$debugger\" passed to --debugger");
}
- if ( $opt_valgrind_options )
+ # 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;
+
+ if ( $opt_callgrind)
{
- # FIXME split earlier and put into @glob_valgrind_*
- mtr_add_arg($args, '%s', $_) for (split(' ', $opt_valgrind_options));
+ 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";
+ }
+
+ # 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 +4401,63 @@ sub usage ($) {
print STDERR <<HERE;
-mysql-test-run [ OPTIONS ] [ TESTCASE ]
-
-FIXME when is TESTCASE arg used or not?!
+$0 [ OPTIONS ] [ TESTCASE ]
Options to control what engine/variation to run
embedded-server Use the embedded server, i.e. no mysqld daemons
ps-protocol Use the binary protocol between client and server
- bench Run the benchmark suite FIXME
- small-bench FIXME
- no-manager Use the istanse manager (currently disabled)
+ cursor-protocol Use the cursor protocol between client and server
+ (implies --ps-protocol)
+ view-protocol Create a view to execute all non updating queries
+ sp-protocol Create a stored procedure to execute all queries
+ compress Use the compressed protocol between client and server
+ ssl Use ssl protocol between client and server
+ 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
+
+Options to control directories to use
+ benchdir=DIR The directory where the benchmark suite is stored
+ (default: ../../mysql-bench)
+ tmpdir=DIR The directory where temporary files are stored
+ (default: ./var/tmp).
+ 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
force Continue to run the suite after failure
- with-ndbcluster Use cluster, and enable test cases that requres it
+ 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
+ ndb-extra Run extra tests from ndb directory
do-test=PREFIX Run test cases which name are prefixed with PREFIX
start-from=PREFIX Run test cases starting from test prefixed with PREFIX
suite=NAME Run the test suite named NAME. The default is "main"
skip-rpl Skip the replication test cases.
+ skip-im Don't start IM, and skip the IM test cases
skip-test=PREFIX Skip test cases which name are prefixed with PREFIX
+ big-test Pass "--big-test" to mysqltest which will set the
+ environment variable BIG_TEST, which can be checked
+ from test cases.
Options that specify ports
master_port=PORT Specify the port number used by the first master
slave_port=PORT Specify the port number used by the first slave
- ndbcluster_port=PORT Specify the port number used by cluster
- manager-port=PORT Specify the port number used by manager (currently not used)
+ ndbcluster-port=PORT Specify the port number used by cluster
+ ndbcluster-port-slave=PORT Specify the port number used by slave cluster
Options for test case authoring
record TESTNAME (Re)genereate the result file for TESTNAME
+ check-testcases Check testcases for sideeffects
Options that pass on options
@@ -2543,65 +4466,72 @@ Options that pass on options
Options to run test on running server
extern Use running server for tests FIXME DANGEROUS
- ndbconnectstring=STR Use running cluster, and connect using STR
+ ndb-connectstring=STR Use running cluster, and connect using STR
+ ndb-connectstring-slave=STR Use running slave cluster, and connect using STR
user=USER User for connect to server
Options for debugging the product
- gdb FIXME
- manual-gdb FIXME
- client-gdb FIXME
- ddd FIXME
- strace-client FIXME
+ client-ddd Start mysqltest client in ddd
+ client-debugger=NAME Start mysqltest in the selected debugger
+ client-gdb Start mysqltest client in gdb
+ ddd Start mysqld in ddd
+ debug Dump trace output for all servers and client programs
+ debugger=NAME Start mysqld in the selected debugger
+ gdb Start the mysqld(s) in gdb
+ manual-debug Let user manually start mysqld in debugger, before
+ running test(s)
+ manual-gdb Let user manually start mysqld in gdb, before running
+ test(s)
master-binary=PATH Specify the master "mysqld" to use
slave-binary=PATH Specify the slave "mysqld" to use
+ strace-client Create strace output for mysqltest client
Options for coverage, profiling etc
gcov FIXME
gprof FIXME
- valgrind[=EXE] Run the "mysqltest" executable as well as the "mysqld"
- server using valgrind, optionally specifying the
- executable path/name
- valgrind-mysqltest[=EXE] In addition, run the "mysqltest" executable with valgrind
- valgrind-all[=EXE] Adds verbose flag, and --show-reachable to valgrind
- valgrind-options=ARGS Extra options to give valgrind
+ 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-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
+ callgrind Instruct valgrind to use callgrind
Misc options
- verbose Verbose output from this script
- script-debug Debug this script itself
comment=STR Write STR to the output
- compress Use the compressed protocol between client and server
- timer Show test case execution time
- start-and-exit Only initiate and start the "mysqld" servers, use the startup
- settings for the specified test case if any
- start-dirty Only start the "mysqld" servers without initiation
- fast Don't try to cleanup from earlier runs
- reorder Reorder tests to get less server restarts
+ notimer Don't show test case execution time
+ script-debug Debug this script itself
+ verbose More verbose output
+ start-and-exit Only initialize and start the servers, using the
+ startup settings for the specified test case (if any)
+ start-dirty Only start the servers (without initialization) for
+ the specified test case (if any)
+ fast Don't try to clean up from earlier runs
+ reorder Reorder tests to get fewer server restarts
help Get this help text
unified-diff | udiff When presenting differences, use unified diff
- testcase-timeout=MINUTES Max test case run time (default 5)
- suite-timeout=MINUTES Max test suite run time (default 120)
+ testcase-timeout=MINUTES Max test case run time (default $default_testcase_timeout)
+ suite-timeout=MINUTES Max test suite run time (default $default_suite_timeout)
-Options not yet described, or that I want to look into more
+Deprecated options
+ with-openssl Deprecated option for ssl
- big-test
- debug
+
+Options not yet described, or that I want to look into more
local
- local-master
netware
- old-master
sleep=SECONDS
socket=PATH
- tmpdir=DIR
user-test=s
wait-timeout=SECONDS
warnings
log-warnings
- with-openssl
HERE
mtr_exit(1);
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/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/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/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/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
diff --git a/mysql-test/r/mysqltest.result b/mysql-test/r/mysqltest.result
index 091a3c0547d..ed7267fb71d 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,41 @@ 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: 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'
+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 this version of mysqltest
+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 +198,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 +225,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 +247,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 # <whatever> success: $success
+# <whatever> success: 1
+# Execute: echo # <whatever> success: $success ;
+# <whatever> 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 +337,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 +347,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 +384,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 +401,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 +424,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_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/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_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/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 ad847b5f156..e16a605434e 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/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/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..d98375ca746 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/<test case>.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 <error number> and --error <error number>
# 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,157 @@ 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
+--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.sql
+sleep 4
+# A comment
+show status;
+EOF
--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
+--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
#
# 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 +533,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 +553,7 @@ echo ;
# Illegal use of echo
--error 1
---exec echo "echo $;" | $MYSQL_TEST 2>&1
+--exec echo "echo \$;" | $MYSQL_TEST 2>&1
# ----------------------------------------------------------------------------
@@ -457,8 +591,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 +629,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 +652,19 @@ echo $novar1;
--exec echo "let ;" | $MYSQL_TEST 2>&1
--error 1
---exec echo "let $=hi;" | $MYSQL_TEST 2>&1
-
---error 1
---exec echo "let hi=hi;" | $MYSQL_TEST 2>&1
+--exec echo "let \$=hi;" | $MYSQL_TEST 2>&1
--error 1
---exec echo "let $1 hi;" | $MYSQL_TEST 2>&1
+--exec echo "let \$1 hi;" | $MYSQL_TEST 2>&1
--error 1
---exec echo "let $m hi;" | $MYSQL_TEST 2>&1
+--exec echo "let \$m 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
+--exec echo "let \$ hi;" | $MYSQL_TEST 2>&1
--error 1
--exec echo "let =hi;" | $MYSQL_TEST 2>&1
@@ -529,6 +672,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 # <whatever> success: \$success
+--echo # <whatever> success: $success
+--echo # Execute: echo # <whatever> success: \$success ;
+echo # <whatever> 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 $<var_name>=`<query>`;
+# ----------------------------------------------------------------------------
+--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 +730,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 +780,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 +787,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 +882,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 +899,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 +936,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 +1101,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 +1142,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 +1179,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 +1253,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 +1278,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/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
diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test
index 7c2a42404ad..d986d3e5111 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 -
-set @v=0;
execute stmt using @v;
+set @v=0;
--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_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;
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_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;
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/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 6defa8b16a5..f3877b301d6 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/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');
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
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)