Commit d6f8da6e authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

merge

parents 6efcf9e3 7ba05466
......@@ -67,6 +67,7 @@
#define MAX_COLUMNS 256
#define MAX_EMBEDDED_SERVER_ARGS 64
#define MAX_DELIMITER_LENGTH 16
#define DEFAULT_MAX_CONN 128
/* Flags controlling send and reap */
#define QUERY_SEND_FLAG 1
......@@ -79,8 +80,8 @@ static int setenv(const char *name, const char *value, int overwrite);
enum {
OPT_SKIP_SAFEMALLOC=OPT_MAX_CLIENT_OPTION,
OPT_PS_PROTOCOL, OPT_SP_PROTOCOL, OPT_CURSOR_PROTOCOL, OPT_VIEW_PROTOCOL,
OPT_MAX_CONNECT_RETRIES, OPT_MARK_PROGRESS, OPT_LOG_DIR, OPT_TAIL_LINES,
OPT_RESULT_FORMAT_VERSION
OPT_MAX_CONNECT_RETRIES, OPT_MAX_CONNECTIONS, OPT_MARK_PROGRESS,
OPT_LOG_DIR, OPT_TAIL_LINES, OPT_RESULT_FORMAT_VERSION,
};
static int record= 0, opt_sleep= -1;
......@@ -92,6 +93,7 @@ const char *opt_include= 0, *opt_charsets_dir;
static int opt_port= 0;
static int opt_max_connect_retries;
static int opt_result_format_version;
static int opt_max_connections= DEFAULT_MAX_CONN;
static my_bool opt_compress= 0, silent= 0, verbose= 0;
static my_bool debug_info_flag= 0, debug_check_flag= 0;
static my_bool tty_password= 0;
......@@ -101,7 +103,7 @@ 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,
static my_bool display_result_vertically= FALSE, display_result_lower= FALSE,
display_metadata= FALSE, display_result_sorted= FALSE;
static my_bool disable_query_log= 0, disable_result_log= 0;
static my_bool disable_warnings= 0;
......@@ -138,6 +140,7 @@ struct st_block
int line; /* Start line of block */
my_bool ok; /* Should block be executed */
enum block_cmd cmd; /* Command owning the block */
char delim[MAX_DELIMITER_LENGTH]; /* Delimiter before block */
};
static struct st_block block_stack[32];
......@@ -233,6 +236,8 @@ struct st_connection
char *name;
size_t name_len;
MYSQL_STMT* stmt;
/* Set after send to disallow other queries before reap */
my_bool pending;
#ifdef EMBEDDED_LIBRARY
const char *cur_query;
......@@ -242,7 +247,8 @@ struct st_connection
int query_done;
#endif /*EMBEDDED_LIBRARY*/
};
struct st_connection connections[128];
struct st_connection *connections= NULL;
struct st_connection* cur_con= NULL, *next_con, *connections_end;
/*
......@@ -276,6 +282,7 @@ enum enum_commands {
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_SORTED_RESULT,
Q_LOWERCASE,
Q_START_TIMER, Q_END_TIMER,
Q_CHARACTER_SET, Q_DISABLE_PS_PROTOCOL, Q_ENABLE_PS_PROTOCOL,
Q_DISABLE_RECONNECT, Q_ENABLE_RECONNECT,
......@@ -288,7 +295,7 @@ enum enum_commands {
Q_LIST_FILES, Q_LIST_FILES_WRITE_FILE, Q_LIST_FILES_APPEND_FILE,
Q_SEND_SHUTDOWN, Q_SHUTDOWN_SERVER,
Q_RESULT_FORMAT_VERSION,
Q_MOVE_FILE, Q_SEND_EVAL,
Q_MOVE_FILE, Q_REMOVE_FILES_WILDCARD, Q_SEND_EVAL,
Q_UNKNOWN, /* Unknown command. */
Q_COMMENT, /* Comments, ignored. */
Q_COMMENT_WITH_COMMAND,
......@@ -348,6 +355,7 @@ const char *command_names[]=
"query_vertical",
"query_horizontal",
"sorted_result",
"lowercase_result",
"start_timer",
"end_timer",
"character_set",
......@@ -384,6 +392,7 @@ const char *command_names[]=
"shutdown_server",
"result_format",
"move_file",
"remove_files_wildcard",
"send_eval",
0
......@@ -488,6 +497,8 @@ void free_replace();
void do_get_replace_regex(struct st_command *command);
void free_replace_regex();
/* Used by sleep */
void check_eol_junk_line(const char *eol);
void free_all_replace(){
free_replace();
......@@ -1034,7 +1045,7 @@ void check_command_args(struct st_command *command,
}
/* Check for too many arguments passed */
ptr= command->last_argument;
while(ptr <= command->end)
while(ptr <= command->end && *ptr != '#')
{
if (*ptr && *ptr != ' ')
die("Extra argument '%s' passed to '%.*s'",
......@@ -1092,6 +1103,7 @@ void close_connections()
mysql_close(next_con->util_mysql);
my_free(next_con->name, MYF(MY_ALLOW_ZERO_PTR));
}
my_free(connections, MYF(MY_WME));
DBUG_VOID_RETURN;
}
......@@ -1118,7 +1130,7 @@ void close_files()
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));
fclose(cur_file->file);
}
my_free((uchar*) cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR));
cur_file->file_name= 0;
......@@ -1132,6 +1144,7 @@ void free_used_memory()
uint i;
DBUG_ENTER("free_used_memory");
if (connections)
close_connections();
close_files();
my_hash_free(&var_hash);
......@@ -2493,7 +2506,7 @@ int open_file(const char *name)
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))))
if (!(cur_file->file = fopen(buff, "rb")))
{
cur_file--;
die("Could not open '%s' for reading, errno: %d", buff, errno);
......@@ -2705,6 +2718,10 @@ void do_exec(struct st_command *command)
#endif
#endif
/* exec command is interpreted externally and will not take newlines */
while(replace(&ds_cmd, "\n", 1, " ", 1) == 0)
;
DBUG_PRINT("info", ("Executing '%s' as '%s'",
command->first_argument, ds_cmd.str));
......@@ -2928,6 +2945,81 @@ void do_remove_file(struct st_command *command)
}
/*
SYNOPSIS
do_remove_files_wildcard
command called command
DESCRIPTION
remove_files_wildcard <directory> [<file_name_pattern>]
Remove the files in <directory> optionally matching <file_name_pattern>
*/
void do_remove_files_wildcard(struct st_command *command)
{
int error= 0;
uint i;
MY_DIR *dir_info;
FILEINFO *file;
char dir_separator[2];
static DYNAMIC_STRING ds_directory;
static DYNAMIC_STRING ds_wild;
static DYNAMIC_STRING ds_file_to_remove;
char dirname[FN_REFLEN];
const struct command_arg rm_args[] = {
{ "directory", ARG_STRING, TRUE, &ds_directory,
"Directory containing files to delete" },
{ "filename", ARG_STRING, FALSE, &ds_wild, "File pattern to delete" }
};
DBUG_ENTER("do_remove_files_wildcard");
check_command_args(command, command->first_argument,
rm_args, sizeof(rm_args)/sizeof(struct command_arg),
' ');
fn_format(dirname, ds_directory.str, "", "", MY_UNPACK_FILENAME);
DBUG_PRINT("info", ("listing directory: %s", dirname));
/* Note that my_dir sorts the list if not given any flags */
if (!(dir_info= my_dir(dirname, MYF(MY_DONT_SORT | MY_WANT_STAT))))
{
error= 1;
goto end;
}
init_dynamic_string(&ds_file_to_remove, dirname, 1024, 1024);
dir_separator[0]= FN_LIBCHAR;
dir_separator[1]= 0;
dynstr_append(&ds_file_to_remove, dir_separator);
for (i= 0; i < (uint) dir_info->number_off_files; i++)
{
file= dir_info->dir_entry + i;
/* Remove only regular files, i.e. no directories etc. */
/* if (!MY_S_ISREG(file->mystat->st_mode)) */
/* MY_S_ISREG does not work here on Windows, just skip directories */
if (MY_S_ISDIR(file->mystat->st_mode))
continue;
if (ds_wild.length &&
wild_compare(file->name, ds_wild.str, 0))
continue;
ds_file_to_remove.length= ds_directory.length + 1;
ds_file_to_remove.str[ds_directory.length + 1]= 0;
dynstr_append(&ds_file_to_remove, file->name);
DBUG_PRINT("info", ("removing file: %s", ds_file_to_remove.str));
error= my_delete(ds_file_to_remove.str, MYF(0)) != 0;
if (error)
break;
}
my_dirend(dir_info);
end:
handle_command_error(command, error);
dynstr_free(&ds_directory);
dynstr_free(&ds_wild);
dynstr_free(&ds_file_to_remove);
DBUG_VOID_RETURN;
}
/*
SYNOPSIS
do_copy_file
......@@ -3688,13 +3780,22 @@ void do_perl(struct st_command *command)
sizeof(perl_args)/sizeof(struct command_arg),
' ');
ds_script= command->content;
/* If it hasn't been done already by a loop iteration, fill it in */
if (! ds_script.str)
{
/* 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);
command->content= ds_script;
}
/* This function could be called even if "false", so check before doing */
if (cur_block->ok)
{
DBUG_PRINT("info", ("Executing perl: %s", ds_script.str));
/* Create temporary file name */
......@@ -3730,7 +3831,7 @@ void do_perl(struct st_command *command)
my_delete(temp_file_path, MYF(0));
handle_command_error(command, WEXITSTATUS(error));
dynstr_free(&ds_script);
}
dynstr_free(&ds_delimiter);
DBUG_VOID_RETURN;
}
......@@ -4138,10 +4239,19 @@ void do_let(struct st_command *command)
int do_sleep(struct st_command *command, my_bool real_sleep)
{
int error= 0;
char *p= command->first_argument;
char *sleep_start, *sleep_end= command->end;
char *sleep_start, *sleep_end;
double sleep_val;
char *p;
static DYNAMIC_STRING ds_sleep;
const struct command_arg sleep_args[] = {
{ "sleep_delay", ARG_STRING, TRUE, &ds_sleep, "Number of seconds to sleep." }
};
check_command_args(command, command->first_argument, sleep_args,
sizeof(sleep_args)/sizeof(struct command_arg),
' ');
p= ds_sleep.str;
sleep_end= ds_sleep.str + ds_sleep.length;
while (my_isspace(charset_info, *p))
p++;
if (!*p)
......@@ -4150,11 +4260,13 @@ int do_sleep(struct st_command *command, my_bool real_sleep)
/* 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\"", command->first_word_len,
command->query,command->first_argument);
command->query, sleep_start);
sleep_val= my_strtod(sleep_start, &sleep_end, &error);
check_eol_junk_line(sleep_end);
if (error)
die("Invalid argument to %.*s \"%s\"", command->first_word_len,
command->query, command->first_argument);
dynstr_free(&ds_sleep);
/* Fixed sleep time selected by --sleep option */
if (opt_sleep >= 0 && !real_sleep)
......@@ -4163,7 +4275,6 @@ int do_sleep(struct st_command *command, my_bool real_sleep)
DBUG_PRINT("info", ("sleep_val: %f", sleep_val));
if (sleep_val)
my_sleep((ulong) (sleep_val * 1000000L));
command->last_argument= sleep_end;
return 0;
}
......@@ -4701,6 +4812,7 @@ void do_close_connection(struct st_command *command)
if (con->util_mysql)
mysql_close(con->util_mysql);
con->util_mysql= 0;
con->pending= FALSE;
my_free(con->name, MYF(0));
......@@ -5035,7 +5147,7 @@ void do_connect(struct st_command *command)
{
if (!(con_slot= find_connection_by_name("-closed_connection-")))
die("Connection limit exhausted, you can have max %d connections",
(int) (sizeof(connections)/sizeof(struct st_connection)));
opt_max_connections);
}
#ifdef EMBEDDED_LIBRARY
......@@ -5154,6 +5266,12 @@ int do_done(struct st_command *command)
}
else
{
if (*cur_block->delim)
{
/* Restore "old" delimiter after false if block */
strcpy (delimiter, cur_block->delim);
delimiter_length= strlen(delimiter);
}
/* Pop block from stack, goto next line */
cur_block--;
parser.current_line++;
......@@ -5212,6 +5330,7 @@ void do_block(enum block_cmd cmd, struct st_command* command)
cur_block++;
cur_block->cmd= cmd;
cur_block->ok= FALSE;
cur_block->delim[0]= '\0';
DBUG_VOID_RETURN;
}
......@@ -5248,6 +5367,15 @@ void do_block(enum block_cmd cmd, struct st_command* command)
if (not_expr)
cur_block->ok = !cur_block->ok;
if (cur_block->ok)
{
cur_block->delim[0]= '\0';
} else
{
/* Remember "old" delimiter if entering a false if block */
strcpy (cur_block->delim, delimiter);
}
DBUG_PRINT("info", ("OK: %d", cur_block->ok));
var_free(&v);
......@@ -5350,7 +5478,7 @@ int read_line(char *buf, int size)
found_eof:
if (cur_file->file != stdin)
{
my_fclose(cur_file->file, MYF(0));
fclose(cur_file->file);
cur_file->file= 0;
}
my_free((uchar*) cur_file->file_name, MYF(MY_ALLOW_ZERO_PTR));
......@@ -5790,6 +5918,10 @@ static struct my_option my_long_options[] =
"Max number of connection attempts when connecting to server",
(uchar**) &opt_max_connect_retries, (uchar**) &opt_max_connect_retries, 0,
GET_INT, REQUIRED_ARG, 500, 1, 10000, 0, 0, 0},
{"max-connections", OPT_MAX_CONNECTIONS,
"Max number of open connections to server",
(uchar**) &opt_max_connections, (uchar**) &opt_max_connections, 0,
GET_INT, REQUIRED_ARG, 128, 8, 5120, 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 or 0 for default to, in "
......@@ -5960,7 +6092,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
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))))
fopen(buff, "rb")))
die("Could not open '%s' for reading, errno: %d", buff, errno);
cur_file->file_name= my_strdup(buff, MYF(MY_FAE));
cur_file->lineno= 1;
......@@ -6579,7 +6711,10 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
wait_query_thread_end(cn);
#endif /*EMBEDDED_LIBRARY*/
if (!(flags & QUERY_REAP_FLAG))
{
cn->pending= TRUE;
DBUG_VOID_RETURN;
}
do
{
......@@ -6664,6 +6799,7 @@ void run_query_normal(struct st_connection *cn, struct st_command *command,
end:
cn->pending= FALSE;
/*
We save the return code (mysql_errno(mysql)) from the last call sent
to the server into the mysqltest builtin variable $mysql_errno. This
......@@ -7140,6 +7276,9 @@ void run_query(struct st_connection *cn, struct st_command *command, int flags)
init_dynamic_string(&ds_warnings, NULL, 0, 256);
if (cn->pending && (flags & QUERY_SEND_FLAG))
die ("Cannot run query on connection between send and reap");
/*
Evaluate query if this is an eval command
*/
......@@ -7662,12 +7801,6 @@ int main(int argc, char **argv)
/* Init expected errors */
memset(&saved_expected_errors, 0, sizeof(saved_expected_errors));
/* Init connections */
memset(connections, 0, sizeof(connections));
connections_end= connections +
(sizeof(connections)/sizeof(struct st_connection)) - 1;
next_con= connections + 1;
#ifdef EMBEDDED_LIBRARY
/* set appropriate stack for the 'query' threads */
(void) pthread_attr_init(&cn_thd_attrib);
......@@ -7694,7 +7827,14 @@ int main(int argc, char **argv)
1024, 0, 0, get_var_key, var_free, MYF(0)))
die("Variable hash initialization failed");
var_set_string("$MYSQL_SERVER_VERSION", MYSQL_SERVER_VERSION);
var_set_string("MYSQL_SERVER_VERSION", MYSQL_SERVER_VERSION);
var_set_string("MYSQL_SYSTEM_TYPE", SYSTEM_TYPE);
var_set_string("MYSQL_MACHINE_TYPE", MACHINE_TYPE);
if (sizeof(void *) == 8) {
var_set_string("MYSQL_SYSTEM_ARCHITECTURE", "64");
} else {
var_set_string("MYSQL_SYSTEM_ARCHITECTURE", "32");
}
memset(&master_pos, 0, sizeof(master_pos));
......@@ -7722,6 +7862,13 @@ int main(int argc, char **argv)
verbose_msg("Tracing progress in '%s'.", progress_file.file_name());
}
/* Init connections, allocate 1 extra as buffer + 1 for default */
connections= (struct st_connection*)
my_malloc((opt_max_connections+2) * sizeof(struct st_connection),
MYF(MY_WME | MY_ZEROFILL));
connections_end= connections + opt_max_connections +1;
next_con= connections + 1;
var_set_int("$PS_PROTOCOL", ps_protocol);
var_set_int("$SP_PROTOCOL", sp_protocol);
var_set_int("$VIEW_PROTOCOL", view_protocol);
......@@ -7825,7 +7972,8 @@ int main(int argc, char **argv)
command->type= Q_COMMENT;
}
my_bool ok_to_do= cur_block->ok;
/* delimiter needs to be executed so we can continue to parse */
my_bool ok_to_do= cur_block->ok || command->type == Q_DELIMITER;
/*
Some commands need to be "done" the first time if they may get
re-iterated over in a true context. This can only happen if there's
......@@ -7883,6 +8031,7 @@ int main(int argc, char **argv)
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_REMOVE_FILES_WILDCARD: do_remove_files_wildcard(command); break;
case Q_MKDIR: do_mkdir(command); break;
case Q_RMDIR: do_rmdir(command); break;
case Q_LIST_FILES: do_list_files(command); break;
......@@ -7920,6 +8069,13 @@ int main(int argc, char **argv)
*/
display_result_sorted= TRUE;
break;
case Q_LOWERCASE:
/*
Turn on lowercasing of result, will be reset after next
command
*/
display_result_lower= TRUE;
break;
case Q_LET: do_let(command); break;
case Q_EVAL_RESULT:
die("'eval_result' command is deprecated");
......@@ -8164,8 +8320,9 @@ int main(int argc, char **argv)
*/
free_all_replace();
/* Also reset "sorted_result" */
/* Also reset "sorted_result" and "lowercase"*/
display_result_sorted= FALSE;
display_result_lower= FALSE;
}
last_command_executed= command_executed;
......@@ -9505,7 +9662,7 @@ int insert_pointer_name(reg1 POINTER_ARRAY *pa,char * name)
if (pa->length+length >= pa->max_length)
{
if (!(new_pos= (uchar*) my_realloc((uchar*) pa->str,
(uint) (pa->max_length+PS_MALLOC),
(uint) (pa->length+length+PS_MALLOC),
MYF(MY_WME))))
DBUG_RETURN(1);
if (new_pos != pa->str)
......@@ -9516,7 +9673,7 @@ int insert_pointer_name(reg1 POINTER_ARRAY *pa,char * name)
char*);
pa->str=new_pos;
}
pa->max_length+=PS_MALLOC;
pa->max_length= pa->length+length+PS_MALLOC;
}
if (pa->typelib.count >= pa->max_count-1)
{
......@@ -9569,6 +9726,18 @@ void replace_dynstr_append_mem(DYNAMIC_STRING *ds,
fix_win_paths(val, len);
#endif
if (display_result_lower)
{
/* Convert to lower case, and do this first */
char lower[512];
char *c= lower;
for (const char *v= val; *v; v++)
*c++= my_tolower(charset_info, *v);
*c= '\0';
/* Copy from this buffer instead */
val= lower;
}
if (glob_replace_regex)
{
/* Regex replace */
......
......@@ -774,6 +774,7 @@ connection default;
handler t1 read a next;
handler t1 close;
connection con1;
--reap # Since last in this connection was a send
drop table t1;
disconnect con1;
--source include/wait_until_disconnected.inc
......
......@@ -194,6 +194,27 @@ INSERT INTO global_suppressions VALUES
("Slave I/O: Get master COLLATION_SERVER failed with error:.*"),
("Slave I/O: Get master TIME_ZONE failed with error:.*"),
/* Messages from valgrind */
("==[0-9]*== Memcheck,"),
("==[0-9]*== Copyright"),
("==[0-9]*== Using"),
("==[0-9]*== For more details"),
/* This comes with innodb plugin tests */
("==[0-9]*== Warning: set address range perms: large range"),
/* valgrind warnings: invalid file descriptor -1 in syscall
write()/read(). Bug #50414 */
("==[0-9]*== Warning: invalid file descriptor -1 in syscall write()"),
("==[0-9]*== Warning: invalid file descriptor -1 in syscall read()"),
/*
Transient network failures that cause warnings on reconnect.
BUG#47743 and BUG#47983.
*/
("Slave I/O: Get master SERVER_ID failed with error:.*"),
("Slave I/O: Get master clock failed with error:.*"),
("Slave I/O: Get master COLLATION_SERVER failed with error:.*"),
("Slave I/O: Get master TIME_ZONE failed with error:.*"),
/*
BUG#42147 - Concurrent DML and LOCK TABLE ... READ for InnoDB
table cause warnings in errlog
......
......@@ -81,7 +81,6 @@ sub is_child {
}
# Find the safe process binary or script
my @safe_process_cmd;
my $safe_kill;
my $bindir;
......@@ -96,7 +95,11 @@ else
$bindir = ".";
}
if (IS_WIN32PERL or IS_CYGWIN){
# Find the safe process binary or script
sub find_bin {
if (IS_WIN32PERL or IS_CYGWIN)
{
# Use my_safe_process.exe
my $exe= my_find_bin($bindir, ["lib/My/SafeProcess", "My/SafeProcess"],
"my_safe_process");
......@@ -104,13 +107,14 @@ if (IS_WIN32PERL or IS_CYGWIN){
# Use my_safe_kill.exe
$safe_kill= my_find_bin($bindir, "lib/My/SafeProcess", "my_safe_kill");
}
else
{
}
else
{
# Use my_safe_process
my $exe= my_find_bin($bindir, ["lib/My/SafeProcess", "My/SafeProcess"],
"my_safe_process");
push(@safe_process_cmd, $exe);
}
}
......@@ -195,63 +199,6 @@ sub run {
return $proc->exit_status();
}
#
# Start a process that returns after "duration" seconds
# or when it's parent process does not exist anymore
#
sub timer {
my $class= shift;
my $duration= shift or croak "duration required";
my $parent_pid= $$;
my $pid= My::SafeProcess::Base::_safe_fork();
if ($pid){
# Parent
my $proc= bless
({
SAFE_PID => $pid,
SAFE_NAME => "timer",
PARENT => $$,
}, $class);
# Put the new process in list of running
$running{$pid}= $proc;
return $proc;
}
# Child, install signal handlers and sleep for "duration"
$SIG{INT}= 'IGNORE';
$SIG{TERM}= sub {
#print STDERR "timer $$: woken up, exiting!\n";
exit(0);
};
$0= "safe_timer($duration)";
if (IS_WIN32PERL){
# Just a thread in same process
sleep($duration);
print STDERR "timer $$: expired after $duration seconds\n";
exit(0);
}
my $count_down= $duration;
while($count_down--){
# Check that parent is still alive
if (kill(0, $parent_pid) == 0){
#print STDERR "timer $$: parent gone, exiting!\n";
exit(0);
}
sleep(1);
}
print STDERR "timer $$: expired after $duration seconds\n";
exit(0);
}
#
# Shutdown process nicely, and wait for shutdown_timeout seconds
# If processes hasn't shutdown, kill them hard and wait for return
......@@ -350,12 +297,12 @@ sub start_kill {
$ret= system($safe_kill, $winpid) >> 8;
if ($ret == 3){
print "Couldn't open the winpid: $winpid ",
print "Couldn't open the winpid: $winpid ".
"for pid: $pid, try one more time\n";
sleep(1);
$winpid= _winpid($pid);
$ret= system($safe_kill, $winpid) >> 8;
print "Couldn't open the winpid: $winpid ",
print "Couldn't open the winpid: $winpid ".
"for pid: $pid, continue and see what happens...\n";
}
}
......@@ -549,6 +496,40 @@ sub wait_any {
}
#
# Wait for any process to exit, or a timeout
#
# Returns a reference to the SafeProcess that
# exited or a pseudo-process with $proc->{timeout} == 1
#
sub wait_any_timeout {
my $class= shift;
my $timeout= shift;
my $proc;
my $millis=10;
do {
::mtr_milli_sleep($millis);
# Slowly increse interval up to max. 1 second
$millis++ if $millis < 1000;
# Return a "fake" process for timeout
if (::has_expired($timeout)) {
$proc= bless
({
SAFE_PID => 0,
SAFE_NAME => "timer",
timeout => 1,
}, $class);
} else {
$proc= check_any();
}
} while (! $proc);
return $proc;
}
#
# Wait for all processes to exit
#
......@@ -606,7 +587,7 @@ sub self2str {
sub _verbose {
return unless $_verbose;
print STDERR " ## ", @_, "\n";
print STDERR " ## ". @_. "\n";
}
......
......@@ -187,13 +187,19 @@ int main(int argc, const char** argv )
die("No real args -> nothing to do");
/* Copy the remaining args to child_arg */
for (int j= i+1; j < argc; j++) {
if (strchr (argv[j], ' ')) {
/* Protect with "" if this arg contains a space */
arg= argv[j];
if (strchr (arg, ' ') &&
arg[0] != '\"' &&
arg[strlen(arg)] != '\"')
{
/* Quote arg that contains spaces and are not quoted already */
to+= _snprintf(to, child_args + sizeof(child_args) - to,
"\"%s\" ", argv[j]);
} else {
"\"%s\" ", arg);
}
else
{
to+= _snprintf(to, child_args + sizeof(child_args) - to,
"%s ", argv[j]);
"%s ", arg);
}
}
break;
......
......@@ -40,7 +40,6 @@ our $default_storage_engine;
our $opt_with_ndbcluster_only;
our $defaults_file;
our $defaults_extra_file;
our $reorder= 1;
our $quick_collect;
sub collect_option {
......@@ -99,7 +98,8 @@ sub init_pattern {
#
##############################################################################
sub collect_test_cases ($$) {
sub collect_test_cases ($$$) {
my $opt_reorder= shift; # True if we're reordering tests
my $suites= shift; # Semicolon separated list of test suites
my $opt_cases= shift;
my $cases= []; # Array of hash(one hash for each testcase)
......@@ -118,11 +118,17 @@ sub collect_test_cases ($$) {
!(IS_WINDOWS && $::opt_embedded_server) &&
$lib_innodb_plugin);
# If not reordering, we also shouldn't group by suites, unless
# no test cases were named.
# This also effects some logic in the loop following this.
if ($opt_reorder or !@$opt_cases)
{
foreach my $suite (split(",", $suites))
{
push(@$cases, collect_one_suite($suite, $opt_cases));
last if $some_test_found;
}
}
if ( @$opt_cases )
{
......@@ -135,6 +141,7 @@ sub collect_test_cases ($$) {
my ($sname, $tname, $extension)= split_testname($test_name_spec);
foreach my $test ( @$cases )
{
last unless $opt_reorder;
# test->{name} is always in suite.name format
if ( $test->{name} =~ /.*\.$tname/ )
{
......@@ -144,12 +151,13 @@ sub collect_test_cases ($$) {
}
if ( not $found )
{
$sname= "main" if !$opt_reorder and !$sname;
mtr_error("Could not find '$tname' in '$suites' suite(s)") unless $sname;
# If suite was part of name, find it there
my ($this_case) = collect_one_suite($sname, [ $tname ]);
if ($this_case)
# If suite was part of name, find it there, may come with combinations
my @this_case = collect_one_suite($sname, [ $tname ]);
if (@this_case)
{
push (@$cases, $this_case);
push (@$cases, @this_case);
}
else
{
......@@ -159,7 +167,7 @@ sub collect_test_cases ($$) {
}
}
if ( $reorder && !$quick_collect)
if ( $opt_reorder && !$quick_collect)
{
# Reorder the test cases in an order that will make them faster to run
my %sort_criteria;
......
......@@ -20,43 +20,20 @@
use strict;
# These are not to be prefixed with "mtr_"
sub gprof_collect ($@) {
my ($exe_mysqld, @gprof_dirs)= @_;
sub gprof_prepare ();
sub gprof_collect ();
print ("Collecting gprof reports.....\n");
##############################################################################
#
#
#
##############################################################################
sub gprof_prepare () {
rmtree($::opt_gprof_dir);
mkdir($::opt_gprof_dir);
}
# FIXME what about master1 and slave1?!
sub gprof_collect () {
if ( -f "$::master->[0]->{'path_myddir'}/gmon.out" )
foreach my $datadir (@gprof_dirs)
{
# FIXME check result code?!
mtr_run("gprof",
[$::exe_master_mysqld,
"$::master->[0]->{'path_myddir'}/gmon.out"],
$::opt_gprof_master, "", "", "");
print "Master execution profile has been saved in $::opt_gprof_master\n";
}
if ( -f "$::slave->[0]->{'path_myddir'}/gmon.out" )
my $gprof_msg= "$datadir/gprof.msg";
my $gprof_err= "$datadir/gprof.err";
if ( -f "$datadir/gmon.out" )
{
# FIXME check result code?!
mtr_run("gprof",
[$::exe_slave_mysqld,
"$::slave->[0]->{'path_myddir'}/gmon.out"],
$::opt_gprof_slave, "", "", "");
print "Slave execution profile has been saved in $::opt_gprof_slave\n";
system("gprof $exe_mysqld $datadir/gmon.out 2>$gprof_err >$gprof_msg");
print ("GPROF output in $gprof_msg, errors in $gprof_err\n");
}
}
}
......
......@@ -30,7 +30,9 @@ sub mtr_script_exists(@);
sub mtr_file_exists(@);
sub mtr_exe_exists(@);
sub mtr_exe_maybe_exists(@);
sub mtr_milli_sleep($);
sub start_timer($);
sub has_expired($);
##############################################################################
#
......@@ -167,11 +169,18 @@ sub mtr_exe_exists (@) {
}
sub mtr_milli_sleep {
sub mtr_milli_sleep ($) {
die "usage: mtr_milli_sleep(milliseconds)" unless @_ == 1;
my ($millis)= @_;
select(undef, undef, undef, ($millis/1000));
}
# Simple functions to start and check timers (have to be actively polled)
# Timer can be "killed" by setting it to 0
sub start_timer ($) { return time + $_[0]; }
sub has_expired ($) { return $_[0] && time gt $_[0]; }
1;
......@@ -69,7 +69,7 @@ sub _mtr_report_test_name ($) {
$tname.= " '$tinfo->{combination}'"
if defined $tinfo->{combination};
print _name(), _timestamp();
print _name(). _timestamp();
printf "%-40s ", $tname;
my $worker = $tinfo->{worker};
printf "w$worker " if $worker;
......@@ -222,8 +222,8 @@ sub mtr_report_test ($) {
}
sub mtr_report_stats ($;$) {
my ($tests, $dont_error)= @_;
sub mtr_report_stats ($$;$) {
my ($prefix, $tests, $dont_error)= @_;
# ----------------------------------------------------------------------
# Find out how we where doing
......@@ -328,6 +328,9 @@ sub mtr_report_stats ($;$) {
}
}
# Print summary line prefix
print "$prefix: ";
# Print a list of testcases that failed
if ( $tot_failed != 0 )
{
......@@ -387,13 +390,13 @@ sub mtr_report_stats ($;$) {
##############################################################################
sub mtr_print_line () {
print '-' x 60, "\n";
print '-' x 60 . "\n";
}
sub mtr_print_thick_line {
my $char= shift || '=';
print $char x 78, "\n";
print $char x 78 . "\n";
}
......@@ -451,7 +454,7 @@ sub _timestamp {
# Always print message to screen
sub mtr_print (@) {
print _name(), join(" ", @_), "\n";
print _name(). join(" ", @_). "\n";
}
......@@ -459,22 +462,22 @@ sub mtr_print (@) {
sub mtr_report (@) {
if (defined $verbose)
{
print _name(), join(" ", @_), "\n";
print _name(). join(" ", @_). "\n";
}
}
# Print warning to screen
sub mtr_warning (@) {
print STDERR _name(), _timestamp(),
"mysql-test-run: WARNING: ", join(" ", @_), "\n";
print STDERR _name(). _timestamp().
"mysql-test-run: WARNING: ". join(" ", @_). "\n";
}
# Print error to screen and then exit
sub mtr_error (@) {
print STDERR _name(), _timestamp(),
"mysql-test-run: *** ERROR: ", join(" ", @_), "\n";
print STDERR _name(). _timestamp().
"mysql-test-run: *** ERROR: ". join(" ", @_). "\n";
if (IS_WINDOWS)
{
POSIX::_exit(1);
......@@ -489,8 +492,8 @@ sub mtr_error (@) {
sub mtr_debug (@) {
if ( $verbose > 2 )
{
print STDERR _name(),
_timestamp(), "####: ", join(" ", @_), "\n";
print STDERR _name().
_timestamp(). "####: ". join(" ", @_). "\n";
}
}
......@@ -498,8 +501,8 @@ sub mtr_debug (@) {
sub mtr_verbose (@) {
if ( $verbose )
{
print STDERR _name(), _timestamp(),
"> ",join(" ", @_),"\n";
print STDERR _name(). _timestamp().
"> ".join(" ", @_)."\n";
}
}
......@@ -509,8 +512,8 @@ sub mtr_verbose_restart (@) {
my $proc= $server->{proc};
if ( $verbose_restart )
{
print STDERR _name(),_timestamp(),
"> Restart $proc - ",join(" ", @args),"\n";
print STDERR _name()._timestamp().
"> Restart $proc - ".join(" ", @args)."\n";
}
}
......
......@@ -150,7 +150,7 @@ sub run_stress_test ()
mtr_add_arg($args, "--verbose");
mtr_add_arg($args, "--cleanup");
mtr_add_arg($args, "--log-error-details");
mtr_add_arg($args, "--abort-on-error");
mtr_add_arg($args, "--abort-on-error=1");
if ( $::opt_stress_init_file )
{
......
......@@ -150,7 +150,7 @@ sub run_stress_test ()
mtr_add_arg($args, "--verbose");
mtr_add_arg($args, "--cleanup");
mtr_add_arg($args, "--log-error-details");
mtr_add_arg($args, "--abort-on-error");
mtr_add_arg($args, "--abort-on-error=1");
if ( $::opt_stress_init_file )
{
......
......@@ -905,6 +905,11 @@ sub command_line_setup () {
mtr_report("Using default engine '$used_default_engine'")
if defined $used_default_engine;
if ($glob_win32 and defined $opt_mem) {
mtr_report("--mem not supported on Windows, ignored");
$opt_mem= undef;
}
# --------------------------------------------------------------------------
# Check if we should speed up tests by trying to run on tmpfs
# --------------------------------------------------------------------------
......
......@@ -102,6 +102,7 @@ use IO::Select;
require "lib/mtr_process.pl";
require "lib/mtr_io.pl";
require "lib/mtr_gcov.pl";
require "lib/mtr_gprof.pl";
require "lib/mtr_misc.pl";
$SIG{INT}= sub { mtr_error("Got ^C signal"); };
......@@ -187,6 +188,9 @@ our $opt_gcov_exe= "gcov";
our $opt_gcov_err= "mysql-test-gcov.msg";
our $opt_gcov_msg= "mysql-test-gcov.err";
our $opt_gprof;
our %gprof_dirs;
our $glob_debugger= 0;
our $opt_gdb;
our $opt_client_gdb;
......@@ -205,7 +209,9 @@ our $opt_experimental;
our $experimental_test_cases;
my $baseport;
# $opt_build_thread may later be set from $opt_port_base
my $opt_build_thread= $ENV{'MTR_BUILD_THREAD'} || "auto";
my $opt_port_base= $ENV{'MTR_PORT_BASE'} || "auto";
my $build_thread= 0;
my $opt_record;
......@@ -215,6 +221,7 @@ my $opt_skip_core;
our $opt_check_testcases= 1;
my $opt_mark_progress;
my $opt_max_connections;
my $opt_sleep;
......@@ -234,6 +241,7 @@ my $opt_wait_all;
my $opt_repeat= 1;
my $opt_retry= 3;
my $opt_retry_failure= env_or_val(MTR_RETRY_FAILURE => 2);
my $opt_reorder= 1;
my $opt_strace_client;
......@@ -246,6 +254,7 @@ my @default_valgrind_args= ("--show-reachable=yes");
my @valgrind_args;
my $opt_valgrind_path;
my $opt_callgrind;
my %mysqld_logs;
my $opt_debug_sync_timeout= 300; # Default timeout for WAIT_FOR actions.
our $opt_warnings= 1;
......@@ -285,6 +294,9 @@ sub main {
command_line_setup();
# --help will not reach here, so now it's safe to assume we have binaries
My::SafeProcess::find_bin();
if ( $opt_gcov ) {
gcov_prepare($basedir);
}
......@@ -314,7 +326,7 @@ sub main {
}
mtr_report("Collecting tests...");
my $tests= collect_test_cases($opt_suites, \@opt_cases);
my $tests= collect_test_cases($opt_reorder, $opt_suites, \@opt_cases);
if ( $opt_report_features ) {
# Put "report features" as the first test to run
......@@ -431,7 +443,7 @@ sub main {
$opt_gcov_msg, $opt_gcov_err);
}
mtr_report_stats($completed);
mtr_report_stats("Completed", $completed);
exit(0);
}
......@@ -455,7 +467,7 @@ sub run_test_server ($$$) {
my $result;
my $exe_mysqld= find_mysqld($basedir) || ""; # Used as hint to CoreDump
my $suite_timeout_proc= My::SafeProcess->timer(suite_timeout());
my $suite_timeout= start_timer(suite_timeout());
my $s= IO::Select->new();
$s->add($server);
......@@ -476,7 +488,6 @@ sub run_test_server ($$$) {
mtr_verbose("Child closed socket");
$s->remove($sock);
if (--$childs == 0){
$suite_timeout_proc->kill();
return $completed;
}
next;
......@@ -545,15 +556,13 @@ sub run_test_server ($$$) {
if ( !$opt_force ) {
# Test has failed, force is off
$suite_timeout_proc->kill();
push(@$completed, $result);
return $completed;
}
elsif ($opt_max_test_fail > 0 and
$num_failed_test >= $opt_max_test_fail) {
$suite_timeout_proc->kill();
push(@$completed, $result);
mtr_report_stats($completed, 1);
mtr_report_stats("Too many failed", $completed, 1);
mtr_report("Too many tests($num_failed_test) failed!",
"Terminating...");
return undef;
......@@ -640,9 +649,9 @@ sub run_test_server ($$$) {
next;
}
# Prefer same configuration
if (defined $result and
$result->{template_path} eq $t->{template_path})
# Prefer same configuration, or just use next if --noreorder
if (!$opt_reorder or (defined $result and
$result->{template_path} eq $t->{template_path}))
{
#mtr_report("Test uses same config => good match");
# Test uses same config => good match
......@@ -683,9 +692,9 @@ sub run_test_server ($$$) {
# ----------------------------------------------------
# Check if test suite timer expired
# ----------------------------------------------------
if ( ! $suite_timeout_proc->wait_one(0) )
if ( has_expired($suite_timeout) )
{
mtr_report_stats($completed, 1);
mtr_report_stats("Timeout", $completed, 1);
mtr_report("Test suite timeout! Terminating...");
return undef;
}
......@@ -761,6 +770,12 @@ sub run_worker ($) {
elsif ($line eq 'BYE'){
mtr_report("Server said BYE");
stop_all_servers($opt_shutdown_timeout);
if ($opt_valgrind_mysqld) {
valgrind_exit_reports();
}
if ( $opt_gprof ) {
gprof_collect (find_mysqld($basedir), keys %gprof_dirs);
}
exit(0);
}
else {
......@@ -841,9 +856,11 @@ sub command_line_setup {
'combination=s' => \@opt_combinations,
'skip-combinations' => \&collect_option,
'experimental=s' => \$opt_experimental,
'skip-im' => \&ignore_option,
# Specify ports
'build-thread|mtr-build-thread=i' => \$opt_build_thread,
'port-base|mtr-port-base=i' => \$opt_port_base,
# Test case authoring
'record' => \$opt_record,
......@@ -874,6 +891,7 @@ sub command_line_setup {
# Coverage, profiling etc
'gcov' => \$opt_gcov,
'gprof' => \$opt_gprof,
'valgrind|valgrind-all' => \$opt_valgrind,
'valgrind-mysqltest' => \$opt_valgrind_mysqltest,
'valgrind-mysqld' => \$opt_valgrind_mysqld,
......@@ -904,7 +922,7 @@ sub command_line_setup {
'report-features' => \$opt_report_features,
'comment=s' => \$opt_comment,
'fast' => \$opt_fast,
'reorder!' => \&collect_option,
'reorder!' => \$opt_reorder,
'enable-disabled' => \&collect_option,
'verbose+' => \$opt_verbose,
'verbose-restart' => \&report_option,
......@@ -924,6 +942,7 @@ sub command_line_setup {
'warnings!' => \$opt_warnings,
'timestamp' => \&report_option,
'timediff' => \&report_option,
'max-connections=i' => \$opt_max_connections,
'help|h' => \$opt_usage,
'list-options' => \$opt_list_options,
......@@ -948,6 +967,11 @@ sub command_line_setup {
# Find the absolute path to the test directory
$glob_mysql_test_dir= cwd();
if ($glob_mysql_test_dir =~ / /)
{
die("Working directory \"$glob_mysql_test_dir\" contains space\n".
"Bailing out, cannot function properly with space in path");
}
if (IS_CYGWIN)
{
# Use mixed path format i.e c:/path/to/
......@@ -1104,6 +1128,21 @@ sub command_line_setup {
}
}
if (IS_WINDOWS and defined $opt_mem) {
mtr_report("--mem not supported on Windows, ignored");
$opt_mem= undef;
}
if ($opt_port_base ne "auto")
{
if (my $rem= $opt_port_base % 10)
{
mtr_warning ("Port base $opt_port_base rounded down to multiple of 10");
$opt_port_base-= $rem;
}
$opt_build_thread= $opt_port_base / 10 - 1000;
}
# --------------------------------------------------------------------------
# Check if we should speed up tests by trying to run on tmpfs
# --------------------------------------------------------------------------
......@@ -1276,7 +1315,7 @@ sub command_line_setup {
# --------------------------------------------------------------------------
# Gcov flag
# --------------------------------------------------------------------------
if ( $opt_gcov and ! $source_dist )
if ( ($opt_gcov or $opt_gprof) and ! $source_dist )
{
mtr_error("Coverage test needs the source - please use source dist");
}
......@@ -1375,8 +1414,7 @@ sub command_line_setup {
push(@valgrind_args, @default_valgrind_args)
unless @valgrind_args;
# Make valgrind run in quiet mode so it only print errors
push(@valgrind_args, "--quiet" );
# Don't add --quiet; you will loose the summary reports.
mtr_report("Running valgrind with options \"",
join(" ", @valgrind_args), "\"");
......@@ -1481,6 +1519,12 @@ sub collect_mysqld_features {
mtr_add_arg($args, "--verbose");
mtr_add_arg($args, "--help");
# Need --user=root if running as *nix root user
if (!IS_WINDOWS and $> == 0)
{
mtr_add_arg($args, "--user=root");
}
my $exe_mysqld= find_mysqld($basedir);
my $cmd= join(" ", $exe_mysqld, @$args);
my $list= `$cmd`;
......@@ -1824,11 +1868,11 @@ sub environment_setup {
{
push(@ld_library_paths, "$basedir/libmysql/.libs/",
"$basedir/libmysql_r/.libs/",
"$basedir/zlib.libs/");
"$basedir/zlib/.libs/");
}
else
{
push(@ld_library_paths, "$basedir/lib");
push(@ld_library_paths, "$basedir/lib", "$basedir/lib/mysql");
}
}
......@@ -2601,6 +2645,7 @@ sub create_config_file_for_extern {
# binlog reads from [client] and [mysqlbinlog]
[mysqlbinlog]
character-sets-dir= $path_charsetsdir
local-load= $opt_tmpdir
# mysql_fix_privilege_tables.sh don't read from [client]
[mysql_fix_privilege_tables]
......@@ -3030,11 +3075,11 @@ sub check_testcase($$)
# Return immediately if no check proceess was started
return 0 unless ( keys %started );
my $timeout_proc= My::SafeProcess->timer(check_timeout());
my $timeout= start_timer(check_timeout());
while (1){
my $result;
my $proc= My::SafeProcess->wait_any();
my $proc= My::SafeProcess->wait_any_timeout($timeout);
mtr_report("Got $proc");
if ( delete $started{$proc->pid()} ) {
......@@ -3058,9 +3103,6 @@ sub check_testcase($$)
if ( keys(%started) == 0){
# All checks completed
$timeout_proc->kill();
return 0;
}
# Wait for next process to exit
......@@ -3101,10 +3143,9 @@ test case was executed:\n";
}
}
elsif ( $proc eq $timeout_proc ) {
$tinfo->{comment}.= "Timeout $timeout_proc for ".
"'check-testcase' expired after ".check_timeout().
" seconds";
elsif ( $proc->{timeout} ) {
$tinfo->{comment}.= "Timeout for 'check-testcase' expired after "
.check_timeout()." seconds";
$result= 4;
}
else {
......@@ -3119,8 +3160,6 @@ test case was executed:\n";
# Kill any check processes still running
map($_->kill(), values(%started));
$timeout_proc->kill();
return $result;
}
......@@ -3192,11 +3231,11 @@ sub run_on_all($$)
# Return immediately if no check proceess was started
return 0 unless ( keys %started );
my $timeout_proc= My::SafeProcess->timer(check_timeout());
my $timeout= start_timer(check_timeout());
while (1){
my $result;
my $proc= My::SafeProcess->wait_any();
my $proc= My::SafeProcess->wait_any_timeout($timeout);
mtr_report("Got $proc");
if ( delete $started{$proc->pid()} ) {
......@@ -3215,17 +3254,15 @@ sub run_on_all($$)
if ( keys(%started) == 0){
# All completed
$timeout_proc->kill();
return 0;
}
# Wait for next process to exit
next;
}
elsif ( $proc eq $timeout_proc ) {
$tinfo->{comment}.= "Timeout $timeout_proc for '$run' ".
"expired after ". check_timeout().
" seconds";
elsif ($proc->{timeout}) {
$tinfo->{comment}.= "Timeout for '$run' expired after "
.check_timeout()." seconds";
}
else {
# Unknown process returned, most likley a crash, abort everything
......@@ -3237,8 +3274,6 @@ sub run_on_all($$)
# Kill any check processes still running
map($_->kill(), values(%started));
$timeout_proc->kill();
return 1;
}
mtr_error("INTERNAL_ERROR: run_on_all");
......@@ -3345,9 +3380,11 @@ sub run_testcase ($) {
mtr_verbose("Running test:", $tinfo->{name});
# Allow only alpanumerics pluss _ - + . in combination names
# Allow only alpanumerics pluss _ - + . in combination names,
# or anything beginning with -- (the latter comes from --combination)
my $combination= $tinfo->{combination};
if ($combination && $combination !~ /^\w[-\w\.\+]+$/)
if ($combination && $combination !~ /^\w[-\w\.\+]+$/
&& $combination !~ /^--/)
{
mtr_error("Combination '$combination' contains illegal characters");
}
......@@ -3468,7 +3505,7 @@ sub run_testcase ($) {
}
}
my $test_timeout_proc= My::SafeProcess->timer(testcase_timeout());
my $test_timeout= start_timer(testcase_timeout());
do_before_run_mysqltest($tinfo);
......@@ -3476,9 +3513,6 @@ sub run_testcase ($) {
# Failed to record state of server or server crashed
report_failure_and_restart($tinfo);
# Stop the test case timer
$test_timeout_proc->kill();
return 1;
}
......@@ -3496,20 +3530,20 @@ sub run_testcase ($) {
if ($proc)
{
mtr_verbose ("Found exited process $proc");
# If that was the timeout, cancel waiting
if ( $proc eq $test_timeout_proc )
{
$keep_waiting_proc = 0;
}
}
else
{
$proc = $keep_waiting_proc;
# Also check if timer has expired, if so cancel waiting
if ( has_expired($test_timeout) )
{
$keep_waiting_proc = 0;
}
}
else
}
if (! $keep_waiting_proc)
{
$proc= My::SafeProcess->wait_any();
$proc= My::SafeProcess->wait_any_timeout($test_timeout);
}
# Will be restored if we need to keep waiting
......@@ -3526,9 +3560,6 @@ sub run_testcase ($) {
# ----------------------------------------------------
if ($proc eq $test)
{
# Stop the test case timer
$test_timeout_proc->kill();
my $res= $test->exit_status();
if ($res == 0 and $opt_warnings and check_warnings($tinfo) )
......@@ -3585,6 +3616,14 @@ sub run_testcase ($) {
run_on_all($tinfo, "analyze-$analyze");
}
# Wait a bit and see if a server died, if so report that instead
mtr_milli_sleep(100);
my $srvproc= My::SafeProcess::check_any();
if ($srvproc && grep($srvproc eq $_, started(all_servers()))) {
$proc= $srvproc;
goto SRVDIED;
}
# Test case failure reported by mysqltest
report_failure_and_restart($tinfo);
}
......@@ -3592,7 +3631,7 @@ sub run_testcase ($) {
{
# mysqltest failed, probably crashed
$tinfo->{comment}=
"mysqltest failed with unexpected return code $res";
"mysqltest failed with unexpected return code $res\n";
report_failure_and_restart($tinfo);
}
......@@ -3610,6 +3649,7 @@ sub run_testcase ($) {
# ----------------------------------------------------
# Check if it was an expected crash
# ----------------------------------------------------
SRVDIED:
my $check_crash = check_expected_crash_and_restart($proc);
if ($check_crash)
{
......@@ -3622,7 +3662,7 @@ sub run_testcase ($) {
# ----------------------------------------------------
# Stop the test case timer
# ----------------------------------------------------
$test_timeout_proc->kill();
$test_timeout= 0;
# ----------------------------------------------------
# Check if it was a server that died
......@@ -3661,7 +3701,7 @@ sub run_testcase ($) {
# ----------------------------------------------------
# Check if testcase timer expired
# ----------------------------------------------------
if ( $proc eq $test_timeout_proc )
if ( $proc->{timeout} )
{
my $log_file_name= $opt_vardir."/log/".$tinfo->{shortname}.".log";
$tinfo->{comment}=
......@@ -3783,16 +3823,24 @@ sub extract_warning_lines ($$) {
(
qr/^Warning:|mysqld: Warning|\[Warning\]/,
qr/^Error:|\[ERROR\]/,
qr/^==\d*==/, # valgrind errors
qr/^==\d+==\s+\S/, # valgrind errors
qr/InnoDB: Warning|InnoDB: Error/,
qr/^safe_mutex:|allocated at line/,
qr/missing DBUG_RETURN/,
qr/Attempting backtrace/,
qr/Assertion .* failed/,
);
my $skip_valgrind= 0;
foreach my $line ( @lines )
{
if ($opt_valgrind_mysqld) {
# Skip valgrind summary from tests where server has been restarted
# Should this contain memory leaks, the final report will find it
$skip_valgrind= 1 if $line =~ /^==\d+== ERROR SUMMARY:/;
$skip_valgrind= 0 unless $line =~ /^==\d+==/;
next if $skip_valgrind;
}
foreach my $pat ( @patterns )
{
if ( $line =~ /$pat/ )
......@@ -3832,7 +3880,6 @@ sub start_check_warnings ($$) {
mtr_add_arg($args, "--loose-skip-safemalloc");
mtr_add_arg($args, "--test-file=%s", "include/check-warnings.test");
mtr_add_arg($args, "--verbose");
if ( $opt_embedded_server )
{
......@@ -3895,11 +3942,11 @@ sub check_warnings ($) {
# Return immediately if no check proceess was started
return 0 unless ( keys %started );
my $timeout_proc= My::SafeProcess->timer(check_timeout());
my $timeout= start_timer(check_timeout());
while (1){
my $result= 0;
my $proc= My::SafeProcess->wait_any();
my $proc= My::SafeProcess->wait_any_timeout($timeout);
mtr_report("Got $proc");
if ( delete $started{$proc->pid()} ) {
......@@ -3928,9 +3975,6 @@ sub check_warnings ($) {
if ( keys(%started) == 0){
# All checks completed
$timeout_proc->kill();
return $result;
}
# Wait for next process to exit
......@@ -3947,10 +3991,9 @@ sub check_warnings ($) {
$result= 2;
}
}
elsif ( $proc eq $timeout_proc ) {
$tinfo->{comment}.= "Timeout $timeout_proc for ".
"'check warnings' expired after ".check_timeout().
" seconds";
elsif ( $proc->{timeout} ) {
$tinfo->{comment}.= "Timeout for 'check warnings' expired after "
.check_timeout()." seconds";
$result= 4;
}
else {
......@@ -3964,8 +4007,6 @@ sub check_warnings ($) {
# Kill any check processes still running
map($_->kill(), values(%started));
$timeout_proc->kill();
return $result;
}
......@@ -3983,7 +4024,7 @@ sub check_expected_crash_and_restart {
foreach my $mysqld ( mysqlds() )
{
next unless ( $mysqld->{proc} eq $proc );
next unless ( $mysqld->{proc} and $mysqld->{proc} eq $proc );
# Check if crash expected by looking at the .expect file
# in var/tmp
......@@ -4181,6 +4222,20 @@ sub report_failure_and_restart ($) {
# about what failed has been saved to file. Save the report
# in tinfo
$tinfo->{logfile}= mtr_fromfile($logfile);
# If no newlines in the test log:
# (it will contain the CURRENT_TEST written by mtr, so is not empty)
if ($tinfo->{logfile} !~ /\n/)
{
# Show how far it got before suddenly failing
$tinfo->{comment}.= "mysqltest failed but provided no output\n";
my $log_file_name= $opt_vardir."/log/".$tinfo->{shortname}.".log";
if (-e $log_file_name) {
$tinfo->{comment}.=
"The result from queries just before the failure was:".
"\n< snip >\n".
mtr_lastlinesfromfile($log_file_name, 20)."\n";
}
}
}
else
{
......@@ -4395,6 +4450,10 @@ sub mysqld_start ($$) {
# see the exact location where valgrind complains
$output= "$opt_vardir/log/".$mysqld->name().".trace";
}
# Remember this log file for valgrind error report search
$mysqld_logs{$output}= 1 if $opt_valgrind;
# Remember data dir for gmon.out files if using gprof
$gprof_dirs{$mysqld->value('datadir')}= 1 if $opt_gprof;
if ( defined $exe )
{
......@@ -4944,6 +5003,10 @@ sub start_mysqltest ($) {
mtr_add_arg($args, "--ssl");
}
if ( $opt_max_connections ) {
mtr_add_arg($args, "--max-connections=%d", $opt_max_connections);
}
if ( $opt_embedded_server )
{
......@@ -5172,7 +5235,7 @@ sub debugger_arguments {
{
# vc[express] /debugexe exe arg1 .. argn
# Add /debugexe and name of the exe before args
# Add name of the exe and /debugexe before args
unshift(@$$args, "$$exe");
unshift(@$$args, "/debugexe");
......@@ -5247,6 +5310,66 @@ sub valgrind_arguments {
}
}
#
# Search server logs for valgrind reports printed at mysqld termination
#
sub valgrind_exit_reports() {
foreach my $log_file (keys %mysqld_logs)
{
my @culprits= ();
my $valgrind_rep= "";
my $found_report= 0;
my $err_in_report= 0;
my $LOGF = IO::File->new($log_file)
or mtr_error("Could not open file '$log_file' for reading: $!");
while ( my $line = <$LOGF> )
{
if ($line =~ /^CURRENT_TEST: (.+)$/)
{
my $testname= $1;
# If we have a report, report it if needed and start new list of tests
if ($found_report)
{
if ($err_in_report)
{
mtr_print ("Valgrind report from $log_file after tests:\n",
@culprits);
mtr_print_line();
print ("$valgrind_rep\n");
$err_in_report= 0;
}
# Make ready to collect new report
@culprits= ();
$found_report= 0;
$valgrind_rep= "";
}
push (@culprits, $testname);
next;
}
# This line marks the start of a valgrind report
$found_report= 1 if $line =~ /ERROR SUMMARY:/;
if ($found_report) {
$line=~ s/^==\d+== //;
$valgrind_rep .= $line;
$err_in_report= 1 if $line =~ /ERROR SUMMARY: [1-9]/;
$err_in_report= 1 if $line =~ /definitely lost: [1-9]/;
$err_in_report= 1 if $line =~ /possibly lost: [1-9]/;
}
}
$LOGF= undef;
if ($err_in_report) {
mtr_print ("Valgrind report from $log_file after tests:\n", @culprits);
mtr_print_line();
print ("$valgrind_rep\n");
}
}
}
#
# Usage
......@@ -5326,6 +5449,11 @@ Options to control what test suites or cases to run
Options that specify ports
mtr-port-base=# Base for port numbers, ports from this number to
port-base=# number+9 are reserved. Should be divisible by 10;
if not it will be rounded down. May be set with
environment variable MTR_PORT_BASE. If this value is
set and is not "auto", it overrides build-thread.
mtr-build-thread=# Specify unique number to calculate port number(s) from.
build-thread=# Can be set in environment variable MTR_BUILD_THREAD.
Set MTR_BUILD_THREAD="auto" to automatically aquire
......@@ -5437,6 +5565,7 @@ Misc options
timestamp Print timestamp before each test report line
timediff With --timestamp, also print time passed since
*previous* test started
max-connections=N Max number of open connection to server in mysqltest
HERE
exit(1);
......
......@@ -147,9 +147,10 @@ hello
hello
;;;;;;;;
# MySQL: -- The
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: Extra argument '6' passed to 'sleep'
mysqltest: At line 1: Extra argument '6' passed to 'sleep'
mysqltest: At line 1: Extra argument 'A comment
show status' passed to 'sleep'
mysqltest: At line 1: End of line junk detected: "sleep 7
# Another comment
"
......@@ -216,6 +217,12 @@ source database
echo message echo message
mysqltest: At line 1: Missing argument in exec
1
1
2
2
X
3
MySQL
"MySQL"
MySQL: The
......@@ -348,8 +355,10 @@ here is the sourced script
here is the sourced script
"hello"
"hello"
mysqltest: At line 1: Missing argument to sleep
mysqltest: At line 1: Missing argument to real_sleep
mysqltest: At line 2: Invalid argument to sleep "xyz"
mysqltest: At line 2: Invalid argument to real_sleep "xyz"
mysqltest: At line 1: Missing required argument 'sleep_delay' to command 'sleep'
mysqltest: At line 1: Missing required argument 'sleep_delay' to command 'real_sleep'
mysqltest: At line 1: Invalid argument to sleep "abc"
mysqltest: At line 1: Invalid argument to real_sleep "abc"
1
......@@ -377,6 +386,10 @@ test
test2
test3
test4
outer
true-inner
true-inner again
true-outer
Counter is greater than 0, (counter=10)
Counter is not 0, (counter=0)
1
......@@ -417,6 +430,9 @@ mysqltest: At line 1: Wrong number of arguments to replace_column in 'replace_co
mysqltest: At line 1: Wrong column number to replace_column in 'replace_column a b'
mysqltest: At line 1: Wrong column number to replace_column in 'replace_column a 1'
mysqltest: At line 1: Wrong column number to replace_column in 'replace_column 1 b c '
select "LONG_STRING" as x;
x
LONG_STRING
mysqltest: At line 1: Invalid integer argument "10!"
mysqltest: At line 1: Invalid integer argument "a"
mysqltest: At line 1: Missing required argument 'connection name' to command 'connect'
......@@ -523,7 +539,28 @@ a D
1 1
1 4
drop table t1;
create table t1 ( f1 char(10));
insert into t1 values ("Abcd");
select * from t1;
f1
Abcd
select * from t2;;
ERROR 42S02: Table 'test.t2' doesn't exist
select * from t1;
f1
Abcd
select * from t1;;
Result coming up
f1
Abcd
select * from t1;;
f1
Abcd
mysqltest: At line 2: Cannot run query on connection between send and reap
select * from t1;;
drop table t1;
mysqltest: At line 1: Missing required argument 'filename' to command 'remove_file'
mysqltest: At line 1: Missing required argument 'directory' to command 'remove_files_wildcard'
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
Content for test_file1
......@@ -553,6 +590,8 @@ hello
mysqltest: At line 1: Max delimiter length(16) exceeded
hello
hello
val is 5
val is 5
mysqltest: At line 1: test of die
Some output
create table t1( a int, b char(255), c timestamp);
......@@ -680,6 +719,29 @@ INSERT INTO t1 SELECT f1 - 256 FROM t1;
INSERT INTO t1 SELECT f1 - 512 FROM t1;
SELECT * FROM t1;
DROP TABLE t1;
select "500g blåbærsyltetøy" as "will be lower cased";
will be lower cased
500g blåbærsyltetøy
SELECT "UPPER" AS "WILL NOT BE lower cased";
WILL NOT BE lower cased
UPPER
UP
SELECT 0 as "UP AGAIN";
UP AGAIN
0
select "abcdef" as "uvwxyz";
uvwxyz
abcdef
select "xyz" as name union select "abc" as name order by name desc;
name
abc
xyz
select 1 as "some new text";
some new text
1
select 0 as "will not lower case ÄËÐ";
will not lower case ÄËÐ
0
CREATE TABLE t1(
a int, b varchar(255), c datetime
);
......@@ -726,6 +788,8 @@ mysqltest: At line 1: change user failed: Access denied for user 'root'@'localho
file1.txt
file1.txt
file2.txt
file11.txt
dir-list.txt
SELECT 'c:\\a.txt' AS col;
col
z
......
......@@ -78,6 +78,7 @@ COMMIT;
--echo 'CONNECTION con2'
CONNECTION con2;
reap;
UNLOCK tables;
DROP TABLE t1;
......
......@@ -128,6 +128,7 @@ connection con0;
SET SESSION low_priority_updates = OFF;
--echo ** Connection con1 **
connection con1;
reap;
SET SESSION low_priority_updates = OFF;
--echo ** Connection default**
connection default;
......
......@@ -605,6 +605,15 @@ echo ;
--error 1
--exec echo "--exec " | $MYSQL_TEST 2>&1
# Multi-line exec
exec $MYSQL
test -e "select 1";
exec $MYSQL test -e "select
2";
let $query = select 3
as X;
exec $MYSQL test -e "$query";
# ----------------------------------------------------------------------------
# Test let command
# ----------------------------------------------------------------------------
......@@ -911,6 +920,28 @@ sleep 0.5;
sleep 1;
real_sleep 1;
# Parameter from variable, legal and illegal
let $sleep_var= 0.1;
sleep $sleep_var;
let $sleep_var= 1;
--real_sleep $sleep_var
--write_file $MYSQL_TMP_DIR/sleep.inc
let $sleep_var= xyz;
--sleep $sleep_var
EOF
--error 1
--exec $MYSQL_TEST < $MYSQL_TMP_DIR/sleep.inc 2>&1
--remove_file $MYSQL_TMP_DIR/sleep.inc
--write_file $MYSQL_TMP_DIR/sleep.inc
let $sleep_var= xyz;
real_sleep $sleep_var;
EOF
--error 1
--exec $MYSQL_TEST < $MYSQL_TMP_DIR/sleep.inc 2>&1
--remove_file $MYSQL_TMP_DIR/sleep.inc
# Missing parameter
--error 1
--exec echo "sleep ;" | $MYSQL_TEST 2>&1
......@@ -1006,6 +1037,37 @@ echo test3stop
--delimiter ;
echo test4;
# ----------------------------------------------------------------------------
# Test that delimiter within if() works in in various combinations
# ----------------------------------------------------------------------------
if (0)
{
delimiter ||;
echo false-inner||
if (0)
{
delimiter *||
echo false-innerer*
delimiter ||*
}
echo false-inner again||
}
echo outer;
if (1)
{
delimiter /;
echo true-inner/
if (0)
{
delimiter %/
echo true-innerer%
}
echo true-inner again/
}
echo true-outer/
delimiter ;/
# ----------------------------------------------------------------------------
# Test if
......@@ -1285,6 +1347,17 @@ select "a" as col1, "c" as col2;
--error 1
--exec echo "--replace_column 1 b c " | $MYSQL_TEST 2>&1
let $long_rep= 1234567890123456789012345678901234567890;
let $long_rep= $long_rep,$long_rep;
let $long_rep= $long_rep,$long_rep;
let $long_rep= $long_rep,$long_rep;
let $long_rep= $long_rep,$long_rep;
let $long_rep= $long_rep,$long_rep;
# This tests from strings > 1024 (here 1311)
--replace_result $long_rep LONG_STRING
eval select "$long_rep" as x;
# ----------------------------------------------------------------------------
# Test sync_with_master
......@@ -1605,6 +1678,57 @@ insert into t1 values (2,4);
select * from t1;
drop table t1;
# ----------------------------------------------------------------------------
# Tests of send
# ----------------------------------------------------------------------------
create table t1 ( f1 char(10));
insert into t1 values ("Abcd");
# 1. Basic test
send select * from t1;
reap;
# 2. Test with error
--send select * from t2;
--error ER_NO_SUCH_TABLE
--reap
# 3. test send of next stmt
--send
select * from t1;
--reap
# 4. Non-query stmt betwen send and reap allowed
--send select * from t1;
--sleep 0.05
--echo Result coming up
--reap
# 5. Test of send_eval
--let $my_stmt= select * from t1;
--send_eval $my_stmt
--reap
# 6. Test that mysqltest does not allow query stmt between send and reap
# Untestable directly as it causes mysqltest to fail
--write_file $MYSQLTEST_VARDIR/tmp/mysqltest.in
--send select * from t1;
select 1;
--reap
EOF
--error 1
--exec $MYSQL_TEST < $MYSQLTEST_VARDIR/tmp/mysqltest.in 2>&1
remove_file $MYSQLTEST_VARDIR/tmp/mysqltest.in;
drop table t1;
# ----------------------------------------------------------------------------
# test for remove_file
# ----------------------------------------------------------------------------
......@@ -1615,6 +1739,19 @@ drop table t1;
--error 1
remove_file non_existing_file;
# ----------------------------------------------------------------------------
# test for remove_files_wildcard
# ----------------------------------------------------------------------------
--error 1
--exec echo "remove_files_wildcard ;" | $MYSQL_TEST 2>&1
--error 1
remove_files_wildcard non_existing_dir;
--error 1
remove_files_wildcard non_existing_dir non_existing_file;
# ----------------------------------------------------------------------------
# test for write_file
# ----------------------------------------------------------------------------
......@@ -1905,6 +2042,20 @@ perl;
print "hello\n";
EOF
# Test perl within while, also with if being false first iteration
let $outer= 3;
let $ifval= 0;
while ($outer) {
if ($ifval) {
perl UNTIL;
my $val= 5;
print "val is $val\n";
UNTIL
}
inc $ifval;
dec $outer;
}
# ----------------------------------------------------------------------------
# test for die
# ----------------------------------------------------------------------------
......@@ -2045,6 +2196,44 @@ INSERT INTO t1 SELECT f1 - 512 FROM t1;
SELECT * FROM t1;
--enable_result_log
DROP TABLE t1;
# ----------------------------------------------------------------------------
# test for lowercase_result
# ----------------------------------------------------------------------------
# 1. Basic test
--lowercase_result
SELECT "500g BLBRSYLTETY" AS "WILL BE lower cased";
# 2. test that it does not apply to next statement
SELECT "UPPER" AS "WILL NOT BE lower cased";
# 3. test that it does not affect non-SQL or the following statement
--lowercase_result
--echo UP
SELECT 0 as "UP AGAIN";
# 4. test that it works with eval and variables
let $lower_stmt=SELECT "ABCdef" AS "uvwXYZ";
--lowercase_result
eval $lower_stmt;
# 5. test that it works in combination with sort
sorted_result;
lowercase_result;
SELECT "Xyz" AS Name UNION SELECT "Abc" as Name ORDER BY Name DESC;
# 6. Test combination with replace, and that lower casing is done first
--lowercase_result
--replace_result old new
SELECT 1 as "SOME OLD TEXT";
# 7. Test missing lower casing of "unknown" characters
--character_set utf8
--lowercase_result
SELECT 0 as "WILL NOT lower case ";
--character_set latin1
# ----------------------------------------------------------------------------
# Some coverage tests
# ----------------------------------------------------------------------------
......@@ -2230,9 +2419,14 @@ rmdir $MYSQLTEST_VARDIR/tmp/testdir;
cat_file $MYSQLTEST_VARDIR/tmp/testdir/file3.txt;
remove_file $MYSQLTEST_VARDIR/tmp/testdir/file1.txt;
remove_file $MYSQLTEST_VARDIR/tmp/testdir/file2.txt;
remove_file $MYSQLTEST_VARDIR/tmp/testdir/file3.txt;
list_files_write_file $MYSQLTEST_VARDIR/tmp/testdir/file11.txt $MYSQLTEST_VARDIR/tmp/testdir file?.txt;
remove_files_wildcard $MYSQLTEST_VARDIR/tmp/testdir file?.txt;
list_files_write_file $MYSQLTEST_VARDIR/tmp/testdir/dir-list.txt $MYSQLTEST_VARDIR/tmp/testdir file*.txt;
cat_file $MYSQLTEST_VARDIR/tmp/testdir/dir-list.txt;
remove_files_wildcard $MYSQLTEST_VARDIR/tmp/testdir file*.txt;
list_files $MYSQLTEST_VARDIR/tmp/testdir;
remove_files_wildcard $MYSQLTEST_VARDIR/tmp/testdir;
list_files $MYSQLTEST_VARDIR/tmp/testdir;
rmdir $MYSQLTEST_VARDIR/tmp/testdir;
#
......
......@@ -187,6 +187,7 @@ SELECT * FROM t1;
--echo # Switch to connection con2
connection con2;
reap;
SELECT * FROM t1;
connection default;
......
......@@ -416,8 +416,7 @@ else
echo "Try 'mysqld --help' if you have problems with paths. Using --log"
echo "gives you a log in $ldata that may be helpful."
echo
echo "The latest information about MySQL is available on the web at"
echo "http://www.mysql.com/. Please consult the MySQL manual section"
echo "Please consult the MySQL manual section"
echo "'Problems running mysql_install_db', and the manual section that"
echo "describes problems on your OS. Another information source are the"
echo "MySQL email archives available at http://lists.mysql.com/."
......@@ -476,9 +475,6 @@ then
echo
echo "Please report any problems with the $scriptdir/mysqlbug script!"
echo
echo "The latest information about MySQL is available at http://www.mysql.com/"
echo "Support MySQL by buying support/licenses from http://shop.mysql.com/"
echo
fi
exit 0
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment