Commit 88a1c9c9 authored by Tatiana A. Nurnberg's avatar Tatiana A. Nurnberg

auto-merge

parents 2ba60c19 ca7a17dc
...@@ -47,6 +47,10 @@ SET(WITH_MYISAMMRG_STORAGE_ENGINE TRUE) ...@@ -47,6 +47,10 @@ SET(WITH_MYISAMMRG_STORAGE_ENGINE TRUE)
ADD_DEFINITIONS(-DWITH_MYISAMMRG_STORAGE_ENGINE) ADD_DEFINITIONS(-DWITH_MYISAMMRG_STORAGE_ENGINE)
SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_myisammrg_plugin") SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_myisammrg_plugin")
IF(WITH_COMMUNITY_FEATURES)
ADD_DEFINITIONS(-DENABLED_PROFILING -DCOMMUNITY_SERVER)
ENDIF(WITH_COMMUNITY_FEATURES)
IF(WITH_ARCHIVE_STORAGE_ENGINE) IF(WITH_ARCHIVE_STORAGE_ENGINE)
ADD_DEFINITIONS(-DWITH_ARCHIVE_STORAGE_ENGINE) ADD_DEFINITIONS(-DWITH_ARCHIVE_STORAGE_ENGINE)
SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_archive_plugin") SET (mysql_plugin_defs "${mysql_plugin_defs},builtin_archive_plugin")
......
...@@ -1979,7 +1979,7 @@ static COMMANDS *find_command(char *name,char cmd_char) ...@@ -1979,7 +1979,7 @@ static COMMANDS *find_command(char *name,char cmd_char)
*/ */
if (strstr(name, "\\g") || (strstr(name, delimiter) && if (strstr(name, "\\g") || (strstr(name, delimiter) &&
!(strlen(name) >= 9 && !(strlen(name) >= 9 &&
!my_strnncoll(charset_info, !my_strnncoll(&my_charset_latin1,
(uchar*) name, 9, (uchar*) name, 9,
(const uchar*) "delimiter", (const uchar*) "delimiter",
9)))) 9))))
...@@ -2000,7 +2000,7 @@ static COMMANDS *find_command(char *name,char cmd_char) ...@@ -2000,7 +2000,7 @@ static COMMANDS *find_command(char *name,char cmd_char)
{ {
if (commands[i].func && if (commands[i].func &&
((name && ((name &&
!my_strnncoll(charset_info,(uchar*)name,len, !my_strnncoll(&my_charset_latin1, (uchar*)name, len,
(uchar*)commands[i].name,len) && (uchar*)commands[i].name,len) &&
!commands[i].name[len] && !commands[i].name[len] &&
(!end || (end && commands[i].takes_params))) || (!end || (end && commands[i].takes_params))) ||
......
...@@ -39,6 +39,7 @@ static uint my_end_arg= 0; ...@@ -39,6 +39,7 @@ static uint my_end_arg= 0;
static char *opt_user= (char*)"root"; static char *opt_user= (char*)"root";
static DYNAMIC_STRING ds_args; static DYNAMIC_STRING ds_args;
static DYNAMIC_STRING conn_args;
static char *opt_password= 0; static char *opt_password= 0;
static my_bool tty_password= 0; static my_bool tty_password= 0;
...@@ -135,6 +136,7 @@ static void free_used_memory(void) ...@@ -135,6 +136,7 @@ static void free_used_memory(void)
free_defaults(defaults_argv); free_defaults(defaults_argv);
dynstr_free(&ds_args); dynstr_free(&ds_args);
dynstr_free(&conn_args);
} }
...@@ -204,7 +206,7 @@ static void add_one_option(DYNAMIC_STRING* ds, ...@@ -204,7 +206,7 @@ static void add_one_option(DYNAMIC_STRING* ds,
} }
} }
dynstr_append_os_quoted(ds, "--", opt->name, eq, arg, NullS); dynstr_append_os_quoted(ds, "--", opt->name, eq, arg, NullS);
dynstr_append(&ds_args, " "); dynstr_append(ds, " ");
} }
...@@ -256,6 +258,15 @@ get_one_option(int optid, const struct my_option *opt, ...@@ -256,6 +258,15 @@ get_one_option(int optid, const struct my_option *opt,
case 'f': /* --force */ case 'f': /* --force */
add_option= FALSE; add_option= FALSE;
break; break;
case 'h': /* --host */
case 'W': /* --pipe */
case 'P': /* --port */
case 'S': /* --socket */
case OPT_MYSQL_PROTOCOL: /* --protocol */
case OPT_SHARED_MEMORY_BASE_NAME: /* --shared-memory-base-name */
add_one_option(&conn_args, opt, argument);
break;
} }
if (add_option) if (add_option)
...@@ -603,6 +614,20 @@ static void create_mysql_upgrade_info_file(void) ...@@ -603,6 +614,20 @@ static void create_mysql_upgrade_info_file(void)
} }
/*
Print connection-related arguments.
*/
static void print_conn_args(const char *tool_name)
{
if (conn_args.str[0])
verbose("Running '%s' with connection arguments: %s", tool_name,
conn_args.str);
else
verbose("Running '%s with default connection arguments", tool_name);
}
/* /*
Check and upgrade(if neccessary) all tables Check and upgrade(if neccessary) all tables
in the server using "mysqlcheck --check-upgrade .." in the server using "mysqlcheck --check-upgrade .."
...@@ -610,7 +635,7 @@ static void create_mysql_upgrade_info_file(void) ...@@ -610,7 +635,7 @@ static void create_mysql_upgrade_info_file(void)
static int run_mysqlcheck_upgrade(void) static int run_mysqlcheck_upgrade(void)
{ {
verbose("Running 'mysqlcheck'..."); print_conn_args("mysqlcheck");
return run_tool(mysqlcheck_path, return run_tool(mysqlcheck_path,
NULL, /* Send output from mysqlcheck directly to screen */ NULL, /* Send output from mysqlcheck directly to screen */
"--no-defaults", "--no-defaults",
...@@ -624,7 +649,7 @@ static int run_mysqlcheck_upgrade(void) ...@@ -624,7 +649,7 @@ static int run_mysqlcheck_upgrade(void)
static int run_mysqlcheck_fixnames(void) static int run_mysqlcheck_fixnames(void)
{ {
verbose("Running 'mysqlcheck'..."); print_conn_args("mysqlcheck");
return run_tool(mysqlcheck_path, return run_tool(mysqlcheck_path,
NULL, /* Send output from mysqlcheck directly to screen */ NULL, /* Send output from mysqlcheck directly to screen */
"--no-defaults", "--no-defaults",
...@@ -753,7 +778,8 @@ int main(int argc, char **argv) ...@@ -753,7 +778,8 @@ int main(int argc, char **argv)
strncpy(self_name, argv[0], FN_REFLEN); strncpy(self_name, argv[0], FN_REFLEN);
} }
if (init_dynamic_string(&ds_args, "", 512, 256)) if (init_dynamic_string(&ds_args, "", 512, 256) ||
init_dynamic_string(&conn_args, "", 512, 256))
die("Out of memory"); die("Out of memory");
load_defaults("my", load_default_groups, &argc, &argv); load_defaults("my", load_default_groups, &argc, &argv);
......
...@@ -404,7 +404,8 @@ typedef struct st_mi_check_param ...@@ -404,7 +404,8 @@ typedef struct st_mi_check_param
my_off_t keydata,totaldata,key_blocks,start_check_pos; my_off_t keydata,totaldata,key_blocks,start_check_pos;
ha_rows total_records,total_deleted; ha_rows total_records,total_deleted;
ha_checksum record_checksum,glob_crc; ha_checksum record_checksum,glob_crc;
ulong use_buffers,read_buffer_length,write_buffer_length, ulonglong use_buffers;
ulong read_buffer_length,write_buffer_length,
sort_buffer_length,sort_key_blocks; sort_buffer_length,sort_key_blocks;
uint out_flag,warning_printed,error_printed,verbose; uint out_flag,warning_printed,error_printed,verbose;
uint opt_sort_key,total_files,max_level; uint opt_sort_key,total_files,max_level;
......
...@@ -57,3 +57,13 @@ BEGIN ...@@ -57,3 +57,13 @@ BEGIN
mysql.user; mysql.user;
END|| END||
--
-- Procedure used by test case used to force all
-- servers to restart after testcase and thus skipping
-- check test case after test
--
CREATE DEFINER=root@localhost PROCEDURE force_restart()
BEGIN
SELECT 1 INTO OUTFILE 'force_restart';
END||
...@@ -22,6 +22,33 @@ use My::Platform; ...@@ -22,6 +22,33 @@ use My::Platform;
use File::Temp qw/ tempfile tempdir /; use File::Temp qw/ tempfile tempdir /;
my $hint_mysqld; # Last resort guess for executable path
# If path in core file is 79 chars we assume it's been truncated
# Looks like we can still find the full path using 'strings'
# If that doesn't work, use the hint (mysqld path) as last resort.
sub _verify_binpath {
my ($binary, $core_name)= @_;
my $binpath;
if (length $binary != 79) {
$binpath= $binary;
print "Core generated by '$binpath'\n";
} else {
# Last occurrence of path ending in /mysql*, cut from first /
if (`strings '$core_name' | grep "/mysql[^/. ]*\$" | tail -1` =~ /(\/.*)/) {
$binpath= $1;
print "Guessing that core was generated by '$binpath'\n";
} else {
return unless $hint_mysqld;
$binpath= $hint_mysqld;
print "Wild guess that core was generated by '$binpath'\n";
}
}
return $binpath;
}
sub _gdb { sub _gdb {
my ($core_name)= @_; my ($core_name)= @_;
...@@ -33,7 +60,8 @@ sub _gdb { ...@@ -33,7 +60,8 @@ sub _gdb {
`gdb -c '$core_name' --batch 2>&1` =~ `gdb -c '$core_name' --batch 2>&1` =~
/Core was generated by `([^\s\'\`]+)/; /Core was generated by `([^\s\'\`]+)/;
my $binary= $1 or return; my $binary= $1 or return;
print "Core generated by '$binary'\n";
$binary= _verify_binpath ($binary, $core_name) or return;
# Create tempfile containing gdb commands # Create tempfile containing gdb commands
my ($tmp, $tmp_name) = tempfile(); my ($tmp, $tmp_name) = tempfile();
...@@ -73,7 +101,8 @@ sub _dbx { ...@@ -73,7 +101,8 @@ sub _dbx {
`echo | dbx - '$core_name' 2>&1` =~ `echo | dbx - '$core_name' 2>&1` =~
/Corefile specified executable: "([^"]+)"/; /Corefile specified executable: "([^"]+)"/;
my $binary= $1 or return; my $binary= $1 or return;
print "Core generated by '$binary'\n";
$binary= _verify_binpath ($binary, $core_name) or return;
# Find all threads # Find all threads
my @thr_ids = `echo threads | dbx '$binary' '$core_name' 2>&1` =~ /t@\d+/g; my @thr_ids = `echo threads | dbx '$binary' '$core_name' 2>&1` =~ /t@\d+/g;
...@@ -203,7 +232,7 @@ sub _cdb { ...@@ -203,7 +232,7 @@ sub _cdb {
my $cdb_cmd = "!sym prompts off; !analyze -v; .ecxr; !for_each_frame dv /t;!uniqstack -p;q"; my $cdb_cmd = "!sym prompts off; !analyze -v; .ecxr; !for_each_frame dv /t;!uniqstack -p;q";
my $cdb_output= my $cdb_output=
`cdb -z $core_name -i "$image_path" -y "$symbol_path" -t 0 -lines -c "$cdb_cmd" 2>&1`; `cdb -c "$cdb_cmd" -z $core_name -i "$image_path" -y "$symbol_path" -t 0 -lines 2>&1`;
return if $? >> 8; return if $? >> 8;
return unless $cdb_output; return unless $cdb_output;
...@@ -225,7 +254,8 @@ EOF ...@@ -225,7 +254,8 @@ EOF
sub show { sub show {
my ($class, $core_name)= @_; my ($class, $core_name, $exe_mysqld)= @_;
$hint_mysqld= $exe_mysqld;
# On Windows, rely on cdb to be there... # On Windows, rely on cdb to be there...
if (IS_WINDOWS) if (IS_WINDOWS)
......
...@@ -164,6 +164,9 @@ sub copytree { ...@@ -164,6 +164,9 @@ sub copytree {
copytree("$from_dir/$_", "$to_dir/$_"); copytree("$from_dir/$_", "$to_dir/$_");
next; next;
} }
# Only copy plain files
next unless -f "$from_dir/$_";
copy("$from_dir/$_", "$to_dir/$_"); copy("$from_dir/$_", "$to_dir/$_");
} }
closedir(DIR); closedir(DIR);
......
...@@ -536,7 +536,37 @@ sub wait_any { ...@@ -536,7 +536,37 @@ sub wait_any {
return $proc; return $proc;
} }
#
# Wait for all processes to exit
#
sub wait_all {
while(keys %running)
{
wait_any();
}
}
# #
# Check if any process has exited, but don't wait.
#
# Returns a reference to the SafeProcess that
# exited or undefined
#
sub check_any {
for my $proc (values %running){
if ( $proc->is_child($$) ) {
if (not $proc->wait_one(0)) {
_verbose ("Found exited $proc");
return $proc;
}
}
}
return undef;
}
# Overload string operator # Overload string operator
# and fallback to default functions if no # and fallback to default functions if no
# overloaded function is found # overloaded function is found
......
...@@ -83,6 +83,13 @@ sub exit_status { ...@@ -83,6 +83,13 @@ sub exit_status {
}; };
} }
# threads.pm may not exist everywhere, so use only on Windows.
use if $^O eq "MSWin32", "threads";
use if $^O eq "MSWin32", "threads::shared";
my $win32_spawn_lock :shared;
# #
# Create a new process # Create a new process
...@@ -104,6 +111,8 @@ sub create_process { ...@@ -104,6 +111,8 @@ sub create_process {
if ($^O eq "MSWin32"){ if ($^O eq "MSWin32"){
lock($win32_spawn_lock);
#printf STDERR "stdin %d, stdout %d, stderr %d\n", #printf STDERR "stdin %d, stdout %d, stderr %d\n",
# fileno STDIN, fileno STDOUT, fileno STDERR; # fileno STDIN, fileno STDOUT, fileno STDERR;
......
...@@ -259,22 +259,37 @@ int main(int argc, const char** argv ) ...@@ -259,22 +259,37 @@ int main(int argc, const char** argv )
the JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, making sure it will be the JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, making sure it will be
terminated when the last handle to it is closed(which is owned by terminated when the last handle to it is closed(which is owned by
this process). this process).
If breakaway from job fails on some reason, fallback is to create a
new process group. Process groups also allow to kill process and its
descedants, subject to some restrictions (processes have to run within
the same console,and must not ignore CTRL_BREAK)
*/ */
if (CreateProcess(NULL, (LPSTR)child_args, DWORD create_flags[]= {CREATE_BREAKAWAY_FROM_JOB, CREATE_NEW_PROCESS_GROUP, 0};
BOOL process_created= FALSE;
BOOL jobobject_assigned= FALSE;
for (int i=0; i < sizeof(create_flags)/sizeof(create_flags[0]); i++)
{
process_created= CreateProcess(NULL, (LPSTR)child_args,
NULL, NULL,
NULL, NULL,
TRUE, /* inherit handles */ TRUE, /* inherit handles */
CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB, CREATE_SUSPENDED | create_flags[i],
NULL, NULL,
NULL, NULL,
&si, &si,
&process_info) == 0) &process_info);
die("CreateProcess failed"); if (process_created)
{
jobobject_assigned= AssignProcessToJobObject(job_handle, process_info.hProcess);
break;
}
}
if (AssignProcessToJobObject(job_handle, process_info.hProcess) == 0) if (!process_created)
{ {
TerminateProcess(process_info.hProcess, 200); die("CreateProcess failed");
die("AssignProcessToJobObject failed");
} }
ResumeThread(process_info.hThread); ResumeThread(process_info.hThread);
CloseHandle(process_info.hThread); CloseHandle(process_info.hThread);
...@@ -312,6 +327,13 @@ int main(int argc, const char** argv ) ...@@ -312,6 +327,13 @@ int main(int argc, const char** argv )
message("TerminateJobObject failed"); message("TerminateJobObject failed");
CloseHandle(job_handle); CloseHandle(job_handle);
message("Job terminated and closed"); message("Job terminated and closed");
if (!jobobject_assigned)
{
GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, process_info.dwProcessId);
TerminateProcess(process_info.hProcess, 202);
}
if (wait_res != WAIT_OBJECT_0 + CHILD) if (wait_res != WAIT_OBJECT_0 + CHILD)
{ {
/* The child has not yet returned, wait for it */ /* The child has not yet returned, wait for it */
......
...@@ -33,7 +33,7 @@ our $print_testcases; ...@@ -33,7 +33,7 @@ our $print_testcases;
our $skip_rpl; our $skip_rpl;
our $do_test; our $do_test;
our $skip_test; our $skip_test;
our $opt_skip_combination; our $skip_combinations;
our $binlog_format; our $binlog_format;
our $enable_disabled; our $enable_disabled;
our $default_storage_engine; our $default_storage_engine;
...@@ -119,11 +119,22 @@ sub collect_test_cases ($$) { ...@@ -119,11 +119,22 @@ sub collect_test_cases ($$) {
if ( $test->{name} =~ /.*\.$tname/ ) if ( $test->{name} =~ /.*\.$tname/ )
{ {
$found= 1; $found= 1;
last;
} }
} }
if ( not $found ) if ( not $found )
{ {
mtr_error("Could not find '$tname' in '$suites' suite(s)"); 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)
{
push (@$cases, $this_case);
}
else
{
mtr_error("Could not find '$tname' in '$sname' suite");
}
} }
} }
} }
...@@ -375,7 +386,7 @@ sub collect_one_suite($) ...@@ -375,7 +386,7 @@ sub collect_one_suite($)
# Read combinations for this suite and build testcases x combinations # Read combinations for this suite and build testcases x combinations
# if any combinations exists # if any combinations exists
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
if ( ! $opt_skip_combination ) if ( ! $skip_combinations )
{ {
my @combinations; my @combinations;
my $combination_file= "$suitedir/combinations"; my $combination_file= "$suitedir/combinations";
......
...@@ -21,7 +21,25 @@ ...@@ -21,7 +21,25 @@
use strict; use strict;
use Socket; use Socket;
use Errno; use Errno;
use My::Platform;
use if IS_WINDOWS, "Net::Ping";
# Ancient perl might not have port_number method for Net::Ping.
# Check it and use fallback to connect() if it is not present.
BEGIN
{
my $use_netping= 0;
if (IS_WINDOWS)
{
my $ping = Net::Ping->new();
if ($ping->can("port_number"))
{
$use_netping= 1;
}
}
eval 'sub USE_NETPING { $use_netping }';
}
sub sleep_until_file_created ($$$); sub sleep_until_file_created ($$$);
sub mtr_ping_port ($); sub mtr_ping_port ($);
...@@ -30,6 +48,24 @@ sub mtr_ping_port ($) { ...@@ -30,6 +48,24 @@ sub mtr_ping_port ($) {
mtr_verbose("mtr_ping_port: $port"); mtr_verbose("mtr_ping_port: $port");
if (IS_WINDOWS && USE_NETPING)
{
# Under Windows, connect to a port that is not open is slow
# It takes ~1sec. Net::Ping with small timeout is much faster.
my $ping = Net::Ping->new();
$ping->port_number($port);
if ($ping->ping("localhost",0.1))
{
mtr_verbose("USED");
return 1;
}
else
{
mtr_verbose("FREE");
return 0;
}
}
my $remote= "localhost"; my $remote= "localhost";
my $iaddr= inet_aton($remote); my $iaddr= inet_aton($remote);
if ( ! $iaddr ) if ( ! $iaddr )
......
...@@ -30,6 +30,8 @@ our @EXPORT= qw(report_option mtr_print_line mtr_print_thick_line ...@@ -30,6 +30,8 @@ our @EXPORT= qw(report_option mtr_print_line mtr_print_thick_line
mtr_report_test); mtr_report_test);
use mtr_match; use mtr_match;
use My::Platform;
use POSIX qw[ _exit ];
require "mtr_io.pl"; require "mtr_io.pl";
my $tot_real_time= 0; my $tot_real_time= 0;
...@@ -257,6 +259,17 @@ sub mtr_report_stats ($) { ...@@ -257,6 +259,17 @@ sub mtr_report_stats ($) {
$tot_restarts++; $tot_restarts++;
} }
# Add counts for repeated runs, if any.
# Note that the last run has already been counted above.
my $num_repeat = $tinfo->{'repeat'} - 1;
if ( $num_repeat > 0 )
{
$tot_tests += $num_repeat;
my $rep_failed = $tinfo->{'rep_failures'} || 0;
$tot_failed += $rep_failed;
$tot_passed += $num_repeat - $rep_failed;
}
# Look for warnings produced by mysqltest # Look for warnings produced by mysqltest
my $base_file= mtr_match_extension($tinfo->{'result_file'}, my $base_file= mtr_match_extension($tinfo->{'result_file'},
"result"); # Trim extension "result"); # Trim extension
...@@ -336,7 +349,7 @@ sub mtr_report_stats ($) { ...@@ -336,7 +349,7 @@ sub mtr_report_stats ($) {
foreach my $tinfo (@$tests) foreach my $tinfo (@$tests)
{ {
my $tname= $tinfo->{'name'}; my $tname= $tinfo->{'name'};
if ( $tinfo->{failures} and ! $seen{$tname}) if ( ($tinfo->{failures} || $tinfo->{rep_failures}) and ! $seen{$tname})
{ {
print " $tname"; print " $tname";
$seen{$tname}= 1; $seen{$tname}= 1;
...@@ -459,7 +472,14 @@ sub mtr_warning (@) { ...@@ -459,7 +472,14 @@ sub mtr_warning (@) {
sub mtr_error (@) { sub mtr_error (@) {
print STDERR _name(), _timestamp(), print STDERR _name(), _timestamp(),
"mysql-test-run: *** ERROR: ", join(" ", @_), "\n"; "mysql-test-run: *** ERROR: ", join(" ", @_), "\n";
exit(1); if (IS_WINDOWS)
{
POSIX::_exit(1);
}
else
{
exit(1);
}
} }
......
...@@ -28,32 +28,36 @@ sub msg { ...@@ -28,32 +28,36 @@ sub msg {
# print "### unique($$) - ", join(" ", @_), "\n"; # print "### unique($$) - ", join(" ", @_), "\n";
} }
my $file; my $dir;
if(!IS_WINDOWS) if(!IS_WINDOWS)
{ {
$file= "/tmp/mysql-test-ports"; $dir= "/tmp/mysql-unique-ids";
} }
else else
{ {
$file= $ENV{'TEMP'}."/mysql-test-ports"; # Try to use machine-wide directory location for unique IDs,
# $ALLUSERSPROFILE . IF it is not available, fallback to $TEMP
# which is typically a per-user temporary directory
if (exists $ENV{'ALLUSERSPROFILE'} && -w $ENV{'ALLUSERSPROFILE'})
{
$dir= $ENV{'ALLUSERSPROFILE'}."/mysql-unique-ids";
}
else
{
$dir= $ENV{'TEMP'}."/mysql-unique-ids";
}
} }
my %mtr_unique_ids; my $mtr_unique_fh = undef;
END { END
my $allocated_id= $mtr_unique_ids{$$}; {
if (defined $allocated_id) mtr_release_unique_id();
{
mtr_release_unique_id($allocated_id);
}
delete $mtr_unique_ids{$$};
} }
# #
# Get a unique, numerical ID, given a file name (where all # Get a unique, numerical ID in a specified range.
# requested IDs are stored), a minimum and a maximum value.
# #
# If no unique ID within the specified parameters can be # If no unique ID within the specified parameters can be
# obtained, return undef. # obtained, return undef.
...@@ -61,135 +65,63 @@ END { ...@@ -61,135 +65,63 @@ END {
sub mtr_get_unique_id($$) { sub mtr_get_unique_id($$) {
my ($min, $max)= @_;; my ($min, $max)= @_;;
msg("get, '$file', $min-$max"); msg("get $min-$max, $$");
die "Can only get one unique id per process!" if $mtr_unique_ids{$$};
my $ret = undef; die "Can only get one unique id per process!" if defined $mtr_unique_fh;
my $changed = 0;
if(eval("readlink '$file'") || eval("readlink '$file.sem'")) {
die 'lock file is a symbolic link';
}
chmod 0777, "$file.sem";
open SEM, ">", "$file.sem" or die "can't write to $file.sem";
flock SEM, LOCK_EX or die "can't lock $file.sem";
if(! -e $file) {
open FILE, ">", $file or die "can't create $file";
close FILE;
}
msg("HAVE THE LOCK"); # Make sure our ID directory exists
if (! -d $dir)
{
# If there is a file with the reserved
# directory name, just delete the file.
if (-e $dir)
{
unlink($dir);
}
if(eval("readlink '$file'") || eval("readlink '$file.sem'")) { mkdir $dir;
die 'lock file is a symbolic link'; chmod 0777, $dir;
}
chmod 0777, $file; if(! -d $dir)
open FILE, "+<", $file or die "can't open $file"; {
#select undef,undef,undef,0.2; die "can't make directory $dir";
seek FILE, 0, 0;
my %taken = ();
while(<FILE>) {
chomp;
my ($id, $pid) = split / /;
$taken{$id} = $pid;
msg("taken: $id, $pid");
# Check if process with given pid is alive
if(!process_alive($pid)) {
print "Removing slot $id used by missing process $pid\n";
msg("Removing slot $id used by missing process $pid");
delete $taken{$id};
$changed++;
} }
} }
for(my $i=$min; $i<=$max; ++$i) {
if(! exists $taken{$i}) {
$ret = $i; my $fh;
$taken{$i} = $$; for(my $id = $min; $id <= $max; $id++)
$changed++; {
# Remember the id this process got open( $fh, ">$dir/$id");
$mtr_unique_ids{$$}= $i; chmod 0666, "$dir/$id";
msg(" got $i"); # Try to lock the file exclusively. If lock succeeds, we're done.
last; if (flock($fh, LOCK_EX|LOCK_NB))
{
# Store file handle - we would need it to release the ID (==unlock the file)
$mtr_unique_fh = $fh;
return $id;
} }
} else
if($changed) { {
seek FILE, 0, 0; close $fh;
truncate FILE, 0 or die "can't truncate $file";
for my $k (keys %taken) {
print FILE $k . ' ' . $taken{$k} . "\n";
} }
} }
close FILE; return undef;
msg("RELEASING THE LOCK");
flock SEM, LOCK_UN or warn "can't unlock $file.sem";
close SEM;
return $ret;
} }
# #
# Release a unique ID. # Release a unique ID.
# #
sub mtr_release_unique_id($) { sub mtr_release_unique_id()
my ($myid)= @_; {
msg("release $$");
msg("release, $myid"); if (defined $mtr_unique_fh)
if(eval("readlink '$file'") || eval("readlink '$file.sem'")) {
die 'lock file is a symbolic link';
}
open SEM, ">", "$file.sem" or die "can't write to $file.sem";
flock SEM, LOCK_EX or die "can't lock $file.sem";
msg("HAVE THE LOCK");
if(eval("readlink '$file'") || eval("readlink '$file.sem'")) {
die 'lock file is a symbolic link';
}
if(! -e $file) {
open FILE, ">", $file or die "can't create $file";
close FILE;
}
open FILE, "+<", $file or die "can't open $file";
#select undef,undef,undef,0.2;
seek FILE, 0, 0;
my %taken = ();
while(<FILE>) {
chomp;
my ($id, $pid) = split / /;
msg(" taken, $id $pid");
$taken{$id} = $pid;
}
if ($taken{$myid} != $$)
{ {
msg(" The unique id for this process does not match pid"); close $mtr_unique_fh;
$mtr_unique_fh = undef;
} }
msg(" removing $myid");
delete $taken{$myid};
seek FILE, 0, 0;
truncate FILE, 0 or die "can't truncate $file";
for my $k (keys %taken) {
print FILE $k . ' ' . $taken{$k} . "\n";
}
close FILE;
msg("RELEASE THE LOCK");
flock SEM, LOCK_UN or warn "can't unlock $file.sem";
close SEM;
delete $mtr_unique_ids{$$};
} }
......
...@@ -209,6 +209,7 @@ sub check_timeout { return $opt_testcase_timeout * 6; }; ...@@ -209,6 +209,7 @@ sub check_timeout { return $opt_testcase_timeout * 6; };
my $opt_start; my $opt_start;
my $opt_start_dirty; my $opt_start_dirty;
my $opt_wait_all;
my $opt_repeat= 1; my $opt_repeat= 1;
my $opt_retry= 3; my $opt_retry= 3;
my $opt_retry_failure= 2; my $opt_retry_failure= 2;
...@@ -429,6 +430,7 @@ sub run_test_server ($$$) { ...@@ -429,6 +430,7 @@ sub run_test_server ($$$) {
my $completed= []; my $completed= [];
my %running; my %running;
my $result; 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_proc= My::SafeProcess->timer(suite_timeout());
...@@ -500,7 +502,7 @@ sub run_test_server ($$$) { ...@@ -500,7 +502,7 @@ sub run_test_server ($$$) {
mtr_report(" - found '$core_name'", mtr_report(" - found '$core_name'",
"($num_saved_cores/$opt_max_save_core)"); "($num_saved_cores/$opt_max_save_core)");
My::CoreDump->show($core_file); My::CoreDump->show($core_file, $exe_mysqld);
if ($num_saved_cores >= $opt_max_save_core) { if ($num_saved_cores >= $opt_max_save_core) {
mtr_report(" - deleting it, already saved", mtr_report(" - deleting it, already saved",
...@@ -515,6 +517,7 @@ sub run_test_server ($$$) { ...@@ -515,6 +517,7 @@ sub run_test_server ($$$) {
} }
} }
$num_saved_datadir++; $num_saved_datadir++;
$num_failed_test++ unless $result->{retries};
if ( !$opt_force ) { if ( !$opt_force ) {
# Test has failed, force is off # Test has failed, force is off
...@@ -529,7 +532,6 @@ sub run_test_server ($$$) { ...@@ -529,7 +532,6 @@ sub run_test_server ($$$) {
"Terminating..."); "Terminating...");
return undef; return undef;
} }
$num_failed_test++;
} }
# Retry test run after test failure # Retry test run after test failure
...@@ -554,9 +556,11 @@ sub run_test_server ($$$) { ...@@ -554,9 +556,11 @@ sub run_test_server ($$$) {
# Repeat test $opt_repeat number of times # Repeat test $opt_repeat number of times
my $repeat= $result->{repeat} || 1; my $repeat= $result->{repeat} || 1;
if ($repeat < $opt_repeat) # Don't repeat if test was skipped
if ($repeat < $opt_repeat && $result->{'result'} ne 'MTR_RES_SKIPPED')
{ {
$result->{retries}= 0; $result->{retries}= 0;
$result->{rep_failures}++ if $result->{failures};
$result->{failures}= 0; $result->{failures}= 0;
delete($result->{result}); delete($result->{result});
$result->{repeat}= $repeat+1; $result->{repeat}= $repeat+1;
...@@ -876,6 +880,7 @@ sub command_line_setup { ...@@ -876,6 +880,7 @@ sub command_line_setup {
'sleep=i' => \$opt_sleep, 'sleep=i' => \$opt_sleep,
'start-dirty' => \$opt_start_dirty, 'start-dirty' => \$opt_start_dirty,
'start' => \$opt_start, 'start' => \$opt_start,
'wait-all' => \$opt_wait_all,
'print-testcases' => \&collect_option, 'print-testcases' => \&collect_option,
'repeat=i' => \$opt_repeat, 'repeat=i' => \$opt_repeat,
'retry=i' => \$opt_retry, 'retry=i' => \$opt_retry,
...@@ -1233,6 +1238,15 @@ sub command_line_setup { ...@@ -1233,6 +1238,15 @@ sub command_line_setup {
} }
} }
# --------------------------------------------------------------------------
# Check use of wait-all
# --------------------------------------------------------------------------
if ($opt_wait_all && ! ($opt_start_dirty || $opt_start))
{
mtr_error("--wait-all can only be used with --start or --start-dirty");
}
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# Check timeout arguments # Check timeout arguments
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
...@@ -1323,29 +1337,31 @@ sub set_build_thread_ports($) { ...@@ -1323,29 +1337,31 @@ sub set_build_thread_ports($) {
if ( lc($opt_build_thread) eq 'auto' ) { if ( lc($opt_build_thread) eq 'auto' ) {
my $found_free = 0; my $found_free = 0;
$build_thread = 250; # Start attempts from here $build_thread = 300; # Start attempts from here
while (! $found_free) while (! $found_free)
{ {
$build_thread= mtr_get_unique_id($build_thread, 299); $build_thread= mtr_get_unique_id($build_thread, 349);
if ( !defined $build_thread ) { if ( !defined $build_thread ) {
mtr_error("Could not get a unique build thread id"); mtr_error("Could not get a unique build thread id");
} }
$found_free= check_ports_free($build_thread); $found_free= check_ports_free($build_thread);
# If not free, release and try from next number # If not free, release and try from next number
mtr_release_unique_id($build_thread++) unless $found_free; if (! $found_free) {
mtr_release_unique_id();
$build_thread++;
}
} }
} }
else else
{ {
$build_thread = $opt_build_thread + $thread - 1; $build_thread = $opt_build_thread + $thread - 1;
if (! check_ports_free($build_thread)) {
# Some port was not free(which one has already been printed)
mtr_error("Some port(s) was not free")
}
} }
$ENV{MTR_BUILD_THREAD}= $build_thread; $ENV{MTR_BUILD_THREAD}= $build_thread;
if (! check_ports_free($build_thread)) {
# Some port was not free(which one has already been printed)
mtr_error("Some port(s) was not free")
}
# Calculate baseport # Calculate baseport
$baseport= $build_thread * 10 + 10000; $baseport= $build_thread * 10 + 10000;
if ( $baseport < 5001 or $baseport + 9 >= 32767 ) if ( $baseport < 5001 or $baseport + 9 >= 32767 )
...@@ -3134,6 +3150,26 @@ sub find_analyze_request ...@@ -3134,6 +3150,26 @@ sub find_analyze_request
} }
# The test can leave a file in var/tmp/ to signal
# that all servers should be restarted
sub restart_forced_by_test
{
my $restart = 0;
foreach my $mysqld ( mysqlds() )
{
my $datadir = $mysqld->value('datadir');
my $force_restart_file = "$datadir/mtr/force_restart";
if ( -f $force_restart_file )
{
mtr_verbose("Restart of servers forced by test");
$restart = 1;
last;
}
}
return $restart;
}
# Return timezone value of tinfo or default value # Return timezone value of tinfo or default value
sub timezone { sub timezone {
my ($tinfo)= @_; my ($tinfo)= @_;
...@@ -3175,7 +3211,7 @@ sub run_testcase ($) { ...@@ -3175,7 +3211,7 @@ sub run_testcase ($) {
{ {
# Remove old datadirs # Remove old datadirs
clean_datadir(); clean_datadir() unless $opt_start_dirty;
# Restore old ENV # Restore old ENV
while (my ($option, $value)= each( %old_env )) { while (my ($option, $value)= each( %old_env )) {
...@@ -3242,19 +3278,29 @@ sub run_testcase ($) { ...@@ -3242,19 +3278,29 @@ sub run_testcase ($) {
# -------------------------------------------------------------------- # --------------------------------------------------------------------
# If --start or --start-dirty given, stop here to let user manually # If --start or --start-dirty given, stop here to let user manually
# run tests # run tests
# If --wait-all is also given, do the same, but don't die if one
# server exits
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
if ( $opt_start or $opt_start_dirty ) if ( $opt_start or $opt_start_dirty )
{ {
mtr_print("\nStarted", started(all_servers())); mtr_print("\nStarted", started(all_servers()));
mtr_print("Waiting for server(s) to exit..."); mtr_print("Waiting for server(s) to exit...");
my $proc= My::SafeProcess->wait_any(); if ( $opt_wait_all ) {
if ( grep($proc eq $_, started(all_servers())) ) My::SafeProcess->wait_all();
{ mtr_print( "All servers exited" );
mtr_print("Server $proc died"); exit(1);
}
else {
my $proc= My::SafeProcess->wait_any();
if ( grep($proc eq $_, started(all_servers())) )
{
mtr_print("Server $proc died");
exit(1);
}
mtr_print("Unknown process $proc died");
exit(1); exit(1);
} }
mtr_print("Unknown process $proc died");
exit(1);
} }
my $test_timeout_proc= My::SafeProcess->timer(testcase_timeout()); my $test_timeout_proc= My::SafeProcess->timer(testcase_timeout());
...@@ -3272,10 +3318,38 @@ sub run_testcase ($) { ...@@ -3272,10 +3318,38 @@ sub run_testcase ($) {
} }
my $test= start_mysqltest($tinfo); my $test= start_mysqltest($tinfo);
# Set only when we have to keep waiting after expectedly died server
my $keep_waiting_proc = 0;
while (1) while (1)
{ {
my $proc= My::SafeProcess->wait_any(); my $proc;
if ($keep_waiting_proc)
{
# Any other process exited?
$proc = My::SafeProcess->check_any();
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;
}
}
else
{
$proc= My::SafeProcess->wait_any();
}
# Will be restored if we need to keep waiting
$keep_waiting_proc = 0;
unless ( defined $proc ) unless ( defined $proc )
{ {
mtr_error("wait_any failed"); mtr_error("wait_any failed");
...@@ -3302,7 +3376,11 @@ sub run_testcase ($) { ...@@ -3302,7 +3376,11 @@ sub run_testcase ($) {
if ( $res == 0 ) if ( $res == 0 )
{ {
my $check_res; my $check_res;
if ( $opt_check_testcases and if ( restart_forced_by_test() )
{
stop_all_servers();
}
elsif ( $opt_check_testcases and
$check_res= check_testcase($tinfo, "after")) $check_res= check_testcase($tinfo, "after"))
{ {
if ($check_res == 1) { if ($check_res == 1) {
...@@ -3367,8 +3445,12 @@ sub run_testcase ($) { ...@@ -3367,8 +3445,12 @@ sub run_testcase ($) {
# ---------------------------------------------------- # ----------------------------------------------------
# Check if it was an expected crash # Check if it was an expected crash
# ---------------------------------------------------- # ----------------------------------------------------
if ( check_expected_crash_and_restart($proc) ) my $check_crash = check_expected_crash_and_restart($proc);
if ($check_crash)
{ {
# Keep waiting if it returned 2, if 1 don't wait or stop waiting.
$keep_waiting_proc = 0 if $check_crash == 1;
$keep_waiting_proc = $proc if $check_crash == 2;
next; next;
} }
...@@ -3709,16 +3791,16 @@ sub check_expected_crash_and_restart { ...@@ -3709,16 +3791,16 @@ sub check_expected_crash_and_restart {
{ {
mtr_verbose("Crash was expected, file '$expect_file' exists"); mtr_verbose("Crash was expected, file '$expect_file' exists");
while (1){ for (my $waits = 0; $waits < 50; $waits++)
{
# If last line in expect file starts with "wait" # If last line in expect file starts with "wait"
# sleep a little and try again, thus allowing the # sleep a little and try again, thus allowing the
# test script to control when the server should start # test script to control when the server should start
# up again # up again. Keep trying for up to 5s at a time.
my $last_line= mtr_lastlinesfromfile($expect_file, 1); my $last_line= mtr_lastlinesfromfile($expect_file, 1);
if ($last_line =~ /^wait/ ) if ($last_line =~ /^wait/ )
{ {
mtr_verbose("Test says wait before restart"); mtr_verbose("Test says wait before restart") if $waits == 0;
mtr_milli_sleep(100); mtr_milli_sleep(100);
next; next;
} }
...@@ -3728,11 +3810,11 @@ sub check_expected_crash_and_restart { ...@@ -3728,11 +3810,11 @@ sub check_expected_crash_and_restart {
# Start server with same settings as last time # Start server with same settings as last time
mysqld_start($mysqld, $mysqld->{'started_opts'}); mysqld_start($mysqld, $mysqld->{'started_opts'});
last; return 1;
} }
# Loop ran through: we should keep waiting after a re-check
return 2;
} }
return 1;
} }
# Not an expected crash # Not an expected crash
...@@ -4431,14 +4513,17 @@ sub start_servers($) { ...@@ -4431,14 +4513,17 @@ sub start_servers($) {
my $mysqld_basedir= $mysqld->value('basedir'); my $mysqld_basedir= $mysqld->value('basedir');
if ( $basedir eq $mysqld_basedir ) if ( $basedir eq $mysqld_basedir )
{ {
# Copy datadir from installed system db if (! $opt_start_dirty) # If dirty, keep possibly grown system db
for my $path ( "$opt_vardir", "$opt_vardir/..") { {
my $install_db= "$path/install.db"; # Copy datadir from installed system db
copytree($install_db, $datadir) for my $path ( "$opt_vardir", "$opt_vardir/..") {
if -d $install_db; my $install_db= "$path/install.db";
copytree($install_db, $datadir)
if -d $install_db;
}
mtr_error("Failed to copy system db to '$datadir'")
unless -d $datadir;
} }
mtr_error("Failed to copy system db to '$datadir'")
unless -d $datadir;
} }
else else
{ {
...@@ -4978,10 +5063,13 @@ Options to control what engine/variation to run ...@@ -4978,10 +5063,13 @@ Options to control what engine/variation to run
vs-config Visual Studio configuration used to create executables vs-config Visual Studio configuration used to create executables
(default: MTR_VS_CONFIG environment variable) (default: MTR_VS_CONFIG environment variable)
config|defaults-file=<config template> Use fixed config template for all defaults-file=<config template> Use fixed config template for all
tests tests
defaults_extra_file=<config template> Extra config template to add to defaults_extra_file=<config template> Extra config template to add to
all generated configs all generated configs
combination=<opt> Use at least twice to run tests with specified
options to mysqld
skip-combinations Ignore combination file (or options)
Options to control directories to use Options to control directories to use
tmpdir=DIR The directory where temporary files are stored tmpdir=DIR The directory where temporary files are stored
...@@ -5004,7 +5092,6 @@ Options to control what test suites or cases to run ...@@ -5004,7 +5092,6 @@ Options to control what test suites or cases to run
force Continue to run the suite after failure force Continue to run the suite after failure
with-ndbcluster-only Run only tests that include "ndb" in the filename with-ndbcluster-only Run only tests that include "ndb" in the filename
skip-ndb[cluster] Skip all tests that need cluster skip-ndb[cluster] Skip all tests that need cluster
skip-ndb[cluster]-slave Skip all tests that need a slave cluster
do-test=PREFIX or REGEX do-test=PREFIX or REGEX
Run test cases which name are prefixed with PREFIX Run test cases which name are prefixed with PREFIX
or fulfills REGEX or fulfills REGEX
...@@ -5019,6 +5106,9 @@ Options to control what test suites or cases to run ...@@ -5019,6 +5106,9 @@ Options to control what test suites or cases to run
The default is: "$DEFAULT_SUITES" The default is: "$DEFAULT_SUITES"
skip-rpl Skip the replication test cases. skip-rpl Skip the replication test cases.
big-test Also run tests marked as "big" big-test Also run tests marked as "big"
enable-disabled Run also tests marked as disabled
print_testcases Don't run the tests but print details about all the
selected tests, in the order they would be run.
Options that specify ports Options that specify ports
...@@ -5087,7 +5177,7 @@ Options for valgrind ...@@ -5087,7 +5177,7 @@ Options for valgrind
valgrind-options=ARGS Deprecated, use --valgrind-option valgrind-options=ARGS Deprecated, use --valgrind-option
valgrind-option=ARGS Option to give valgrind, replaces default option(s), valgrind-option=ARGS Option to give valgrind, replaces default option(s),
can be specified more then once can be specified more then once
valgrind-path=[EXE] Path to the valgrind executable valgrind-path=<EXE> Path to the valgrind executable
callgrind Instruct valgrind to use callgrind callgrind Instruct valgrind to use callgrind
Misc options Misc options
...@@ -5095,14 +5185,18 @@ Misc options ...@@ -5095,14 +5185,18 @@ Misc options
comment=STR Write STR to the output comment=STR Write STR to the output
notimer Don't show test case execution time notimer Don't show test case execution time
verbose More verbose output(use multiple times for even more) verbose More verbose output(use multiple times for even more)
verbose-restart Write when and why servers are restarted
start Only initialize and start the servers, using the start Only initialize and start the servers, using the
startup settings for the first specified test case startup settings for the first specified test case
Example: Example:
$0 --start alias & $0 --start alias &
start-dirty Only start the servers (without initialization) for start-dirty Only start the servers (without initialization) for
the first specified test case the first specified test case
wait-all If --start or --start-dirty option is used, wait for all
servers to exit before finishing the process
fast Run as fast as possible, dont't wait for servers fast Run as fast as possible, dont't wait for servers
to shutdown etc. to shutdown etc.
parallel=N Run tests in N parallel threads (default=1)
repeat=N Run each test N number of times repeat=N Run each test N number of times
retry=N Retry tests that fail N times, limit number of failures retry=N Retry tests that fail N times, limit number of failures
to $opt_retry_failure to $opt_retry_failure
...@@ -5120,6 +5214,12 @@ Misc options ...@@ -5120,6 +5214,12 @@ Misc options
sleep=SECONDS Passed to mysqltest, will be used as fixed sleep time sleep=SECONDS Passed to mysqltest, will be used as fixed sleep time
gcov Collect coverage information after the test. gcov Collect coverage information after the test.
The result is a gcov file per source and header file. The result is a gcov file per source and header file.
experimental=<file> Refer to list of tests considered experimental;
failures will be marked exp-fail instead of fail.
report-features First run a "test" that reports mysql features
timestamp Print timestamp before each test report line
timediff With --timestamp, also print time passed since
*previous* test started
HERE HERE
exit(1); exit(1);
......
...@@ -4,6 +4,7 @@ SELECT * INTO @Y FROM init_file.startup limit 1,1; ...@@ -4,6 +4,7 @@ SELECT * INTO @Y FROM init_file.startup limit 1,1;
SELECT YEAR(@X)-YEAR(@Y); SELECT YEAR(@X)-YEAR(@Y);
YEAR(@X)-YEAR(@Y) YEAR(@X)-YEAR(@Y)
0 0
DROP DATABASE init_file;
ok ok
end of 4.1 tests end of 4.1 tests
select * from t1; select * from t1;
...@@ -19,3 +20,5 @@ y ...@@ -19,3 +20,5 @@ y
3 3
11 11
13 13
drop table t1, t2;
call mtr.force_restart();
...@@ -198,6 +198,7 @@ COUNT (*) ...@@ -198,6 +198,7 @@ COUNT (*)
1 1
COUNT (*) COUNT (*)
1 1
ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (errno)
End of 5.0 tests End of 5.0 tests
WARNING: --server-arg option not supported in this configuration. WARNING: --server-arg option not supported in this configuration.
Warning (Code 1286): Unknown table engine 'nonexistent' Warning (Code 1286): Unknown table engine 'nonexistent'
......
...@@ -1660,3 +1660,13 @@ declare continue handler for sqlstate '00000' set @x=0; ...@@ -1660,3 +1660,13 @@ declare continue handler for sqlstate '00000' set @x=0;
end$$ end$$
ERROR 42000: Bad SQLSTATE: '00000' ERROR 42000: Bad SQLSTATE: '00000'
LOAD DATA INFILE '../../tmp/proc.txt' INTO TABLE mysql.proc; LOAD DATA INFILE '../../tmp/proc.txt' INTO TABLE mysql.proc;
CREATE TABLE t1 (a INT, b INT);
INSERT INTO t1 VALUES (1,1), (2,2);
SELECT MAX (a) FROM t1 WHERE b = 999999;
ERROR 42000: FUNCTION test.MAX does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual
SELECT AVG (a) FROM t1 WHERE b = 999999;
AVG (a)
NULL
SELECT non_existent (a) FROM t1 WHERE b = 999999;
ERROR 42000: FUNCTION test.non_existent does not exist
DROP TABLE t1;
...@@ -96,10 +96,11 @@ CREATE FUNCTION function_for_routines() RETURNS INT RETURN 0; ...@@ -96,10 +96,11 @@ CREATE FUNCTION function_for_routines() RETURNS INT RETURN 0;
SELECT specific_name,routine_catalog,routine_schema,routine_name,routine_type, SELECT specific_name,routine_catalog,routine_schema,routine_name,routine_type,
routine_body,external_name,external_language,parameter_style,sql_path routine_body,external_name,external_language,parameter_style,sql_path
FROM information_schema.routines FROM information_schema.routines
WHERE routine_catalog IS NOT NULL OR external_name IS NOT NULL WHERE routine_schema = 'test' AND
(routine_catalog IS NOT NULL OR external_name IS NOT NULL
OR external_language IS NOT NULL OR sql_path IS NOT NULL OR external_language IS NOT NULL OR sql_path IS NOT NULL
OR routine_body <> 'SQL' OR parameter_style <> 'SQL' OR routine_body <> 'SQL' OR parameter_style <> 'SQL'
OR specific_name <> routine_name; OR specific_name <> routine_name);
DROP PROCEDURE sp_for_routines; DROP PROCEDURE sp_for_routines;
DROP FUNCTION function_for_routines; DROP FUNCTION function_for_routines;
......
...@@ -111,10 +111,11 @@ CREATE FUNCTION function_for_routines() RETURNS INT RETURN 0; ...@@ -111,10 +111,11 @@ CREATE FUNCTION function_for_routines() RETURNS INT RETURN 0;
SELECT specific_name,routine_catalog,routine_schema,routine_name,routine_type, SELECT specific_name,routine_catalog,routine_schema,routine_name,routine_type,
routine_body,external_name,external_language,parameter_style,sql_path routine_body,external_name,external_language,parameter_style,sql_path
FROM information_schema.routines FROM information_schema.routines
WHERE routine_catalog IS NOT NULL OR external_name IS NOT NULL WHERE routine_schema = 'test' AND
(routine_catalog IS NOT NULL OR external_name IS NOT NULL
OR external_language IS NOT NULL OR sql_path IS NOT NULL OR external_language IS NOT NULL OR sql_path IS NOT NULL
OR routine_body <> 'SQL' OR parameter_style <> 'SQL' OR routine_body <> 'SQL' OR parameter_style <> 'SQL'
OR specific_name <> routine_name; OR specific_name <> routine_name);
specific_name routine_catalog routine_schema routine_name routine_type routine_body external_name external_language parameter_style sql_path specific_name routine_catalog routine_schema routine_name routine_type routine_body external_name external_language parameter_style sql_path
DROP PROCEDURE sp_for_routines; DROP PROCEDURE sp_for_routines;
DROP FUNCTION function_for_routines; DROP FUNCTION function_for_routines;
......
...@@ -14,7 +14,7 @@ SELECT * INTO @X FROM init_file.startup limit 0,1; ...@@ -14,7 +14,7 @@ SELECT * INTO @X FROM init_file.startup limit 0,1;
SELECT * INTO @Y FROM init_file.startup limit 1,1; SELECT * INTO @Y FROM init_file.startup limit 1,1;
SELECT YEAR(@X)-YEAR(@Y); SELECT YEAR(@X)-YEAR(@Y);
# Enable this DROP DATABASE only after resolving bug #42507 # Enable this DROP DATABASE only after resolving bug #42507
# DROP DATABASE init_file; DROP DATABASE init_file;
--echo ok --echo ok
--echo end of 4.1 tests --echo end of 4.1 tests
...@@ -28,4 +28,9 @@ select * from t1; ...@@ -28,4 +28,9 @@ select * from t1;
# 30, 3, 11, 13 # 30, 3, 11, 13
select * from t2; select * from t2;
# Enable this DROP TABLE only after resolving bug #42507 # Enable this DROP TABLE only after resolving bug #42507
#drop table t1, t2; drop table t1, t2;
# MTR will restart server anyway, but by forcing it we avoid being warned
# about the apparent side effect
call mtr.force_restart();
...@@ -349,6 +349,14 @@ remove_file $MYSQLTEST_VARDIR/tmp/bug31060.sql; ...@@ -349,6 +349,14 @@ remove_file $MYSQLTEST_VARDIR/tmp/bug31060.sql;
--exec $MYSQL --ignore-spaces -e "SELECT COUNT (*)" --exec $MYSQL --ignore-spaces -e "SELECT COUNT (*)"
--exec $MYSQL -b -i -e "SELECT COUNT (*)" --exec $MYSQL -b -i -e "SELECT COUNT (*)"
#
# Bug#37268 'binary' character set makes CLI-internal commands case sensitive
#
--replace_regex /\([0-9]*\)/(errno)/
--error 1
--exec $MYSQL --default-character-set=binary test -e "CONNECT test invalid_hostname" 2>&1
--exec $MYSQL --default-character-set=binary test -e "DELIMITER //" 2>&1
--echo End of 5.0 tests --echo End of 5.0 tests
# #
......
...@@ -2435,3 +2435,16 @@ delimiter ;$$ ...@@ -2435,3 +2435,16 @@ delimiter ;$$
# #
LOAD DATA INFILE '../../tmp/proc.txt' INTO TABLE mysql.proc; LOAD DATA INFILE '../../tmp/proc.txt' INTO TABLE mysql.proc;
remove_file $MYSQLTEST_VARDIR/tmp/proc.txt; remove_file $MYSQLTEST_VARDIR/tmp/proc.txt;
#
# Bug #38159: Function parsing problem generates misleading error message
#
CREATE TABLE t1 (a INT, b INT);
INSERT INTO t1 VALUES (1,1), (2,2);
--error ER_FUNC_INEXISTENT_NAME_COLLISION
SELECT MAX (a) FROM t1 WHERE b = 999999;
SELECT AVG (a) FROM t1 WHERE b = 999999;
--error ER_SP_DOES_NOT_EXIST
SELECT non_existent (a) FROM t1 WHERE b = 999999;
DROP TABLE t1;
...@@ -67,7 +67,7 @@ my_which () ...@@ -67,7 +67,7 @@ my_which ()
ret=0 ret=0
for file for file
do do
for dir in "$PATH" for dir in $PATH
do do
if [ -f "$dir/$file" ] if [ -f "$dir/$file" ]
then then
......
...@@ -5802,6 +5802,14 @@ Item_func_sp::func_name() const ...@@ -5802,6 +5802,14 @@ Item_func_sp::func_name() const
} }
int my_missing_function_error(const LEX_STRING &token, const char *func_name)
{
if (token.length && is_lex_native_function (&token))
return my_error(ER_FUNC_INEXISTENT_NAME_COLLISION, MYF(0), func_name);
else
return my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", func_name);
}
/** /**
@brief Initialize the result field by creating a temporary dummy table @brief Initialize the result field by creating a temporary dummy table
...@@ -5834,7 +5842,7 @@ Item_func_sp::init_result_field(THD *thd) ...@@ -5834,7 +5842,7 @@ Item_func_sp::init_result_field(THD *thd)
if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name, if (!(m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
&thd->sp_func_cache, TRUE))) &thd->sp_func_cache, TRUE)))
{ {
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str); my_missing_function_error (m_name->m_name, m_name->m_qname.str);
context->process_error(thd); context->process_error(thd);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
......
...@@ -6177,3 +6177,6 @@ ER_TOO_LONG_TABLE_COMMENT ...@@ -6177,3 +6177,6 @@ ER_TOO_LONG_TABLE_COMMENT
ER_TOO_LONG_FIELD_COMMENT ER_TOO_LONG_FIELD_COMMENT
eng "Comment for field '%-.64s' is too long (max = %lu)" eng "Comment for field '%-.64s' is too long (max = %lu)"
por "Comentrio para o campo '%-.64s' longo demais (max = %lu)" por "Comentrio para o campo '%-.64s' longo demais (max = %lu)"
ER_FUNC_INEXISTENT_NAME_COLLISION 42000
eng "FUNCTION %s does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual"
...@@ -179,6 +179,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) ...@@ -179,6 +179,7 @@ bool mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list)
{ {
if (thd->is_error() && if (thd->is_error() &&
(thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR || (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR ||
thd->main_da.sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION ||
thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST)) thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST))
{ {
thd->clear_error(); thd->clear_error();
......
...@@ -433,6 +433,16 @@ bool is_keyword(const char *name, uint len) ...@@ -433,6 +433,16 @@ bool is_keyword(const char *name, uint len)
return get_hash_symbol(name,len,0)!=0; return get_hash_symbol(name,len,0)!=0;
} }
/**
Check if name is a sql function
@param name checked name
@return is this a native function or not
@retval 0 name is a function
@retval 1 name isn't a function
*/
bool is_lex_native_function(const LEX_STRING *name) bool is_lex_native_function(const LEX_STRING *name)
{ {
DBUG_ASSERT(name != NULL); DBUG_ASSERT(name != NULL);
......
...@@ -1976,4 +1976,6 @@ extern bool is_lex_native_function(const LEX_STRING *name); ...@@ -1976,4 +1976,6 @@ extern bool is_lex_native_function(const LEX_STRING *name);
@} (End of group Semantic_Analysis) @} (End of group Semantic_Analysis)
*/ */
int my_missing_function_error(const LEX_STRING &token, const char *name);
#endif /* MYSQL_SERVER */ #endif /* MYSQL_SERVER */
...@@ -779,7 +779,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head, ...@@ -779,7 +779,7 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
strpos=disk_buff+6; strpos=disk_buff+6;
if (!(rec_per_key= (ulong*) alloc_root(&share->mem_root, if (!(rec_per_key= (ulong*) alloc_root(&share->mem_root,
sizeof(ulong*)*key_parts))) sizeof(ulong)*key_parts)))
goto err; goto err;
for (i=0 ; i < keys ; i++, keyinfo++) for (i=0 ; i < keys ; i++, keyinfo++)
...@@ -3341,6 +3341,7 @@ void TABLE_LIST::hide_view_error(THD *thd) ...@@ -3341,6 +3341,7 @@ void TABLE_LIST::hide_view_error(THD *thd)
if (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR || if (thd->main_da.sql_errno() == ER_BAD_FIELD_ERROR ||
thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST || thd->main_da.sql_errno() == ER_SP_DOES_NOT_EXIST ||
thd->main_da.sql_errno() == ER_FUNC_INEXISTENT_NAME_COLLISION ||
thd->main_da.sql_errno() == ER_PROCACCESS_DENIED_ERROR || thd->main_da.sql_errno() == ER_PROCACCESS_DENIED_ERROR ||
thd->main_da.sql_errno() == ER_COLUMNACCESS_DENIED_ERROR || thd->main_da.sql_errno() == ER_COLUMNACCESS_DENIED_ERROR ||
thd->main_da.sql_errno() == ER_TABLEACCESS_DENIED_ERROR || thd->main_da.sql_errno() == ER_TABLEACCESS_DENIED_ERROR ||
......
...@@ -1085,7 +1085,7 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char ...@@ -1085,7 +1085,7 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char
if (bytesToStore) if (bytesToStore)
memcpy(db2Buf, dataToStore, bytesToStore); memcpy(db2Buf, dataToStore, bytesToStore);
if (bytesToPad) if (bytesToPad)
wmemset((wchar_t*)(db2Buf + bytesToStore), 0x0020, bytesToPad/2); memset16((db2Buf + bytesToStore), 0x0020, bytesToPad/2);
} }
else else
{ {
...@@ -1108,7 +1108,7 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char ...@@ -1108,7 +1108,7 @@ int32 ha_ibmdb2i::convertMySQLtoDB2(Field* field, const DB2Field& db2Field, char
bytesToStore = db2BytesToStore; bytesToStore = db2BytesToStore;
} }
if (db2BytesToStore < maxDb2BytesToStore) // If need to pad if (db2BytesToStore < maxDb2BytesToStore) // If need to pad
wmemset((wchar_t*)(db2Buf + db2BytesToStore), 0x0020, (maxDb2BytesToStore - db2BytesToStore)/2); memset16((db2Buf + db2BytesToStore), 0x0020, (maxDb2BytesToStore - db2BytesToStore)/2);
} }
if (db2FieldType == QMY_VARGRAPHIC) if (db2FieldType == QMY_VARGRAPHIC)
......
...@@ -109,5 +109,21 @@ bool isOrdinaryIdentifier(const char* s) ...@@ -109,5 +109,21 @@ bool isOrdinaryIdentifier(const char* s)
} }
return true; return true;
} }
/**
Fill memory with a 16-bit word.
@param p Pointer to space to fill.
@param v Value to fill
@param l Length of space (in 16-bit words)
*/
void memset16(void* p, uint16 v, size_t l)
{
uint16* p2=(uint16*)p;
while (l--)
{
*(p2++) = v;
}
}
#endif #endif
...@@ -1807,7 +1807,7 @@ int ha_myisam::info(uint flag) ...@@ -1807,7 +1807,7 @@ int ha_myisam::info(uint flag)
if (share->key_parts) if (share->key_parts)
memcpy((char*) table->key_info[0].rec_per_key, memcpy((char*) table->key_info[0].rec_per_key,
(char*) misam_info.rec_per_key, (char*) misam_info.rec_per_key,
sizeof(table->key_info[0].rec_per_key[0])*share->key_parts); sizeof(table->key_info[0].rec_per_key[0])*share->key_parts);
if (share->tmp_table == NO_TMP_TABLE) if (share->tmp_table == NO_TMP_TABLE)
pthread_mutex_unlock(&share->mutex); pthread_mutex_unlock(&share->mutex);
......
...@@ -287,8 +287,8 @@ static struct my_option my_long_options[] = ...@@ -287,8 +287,8 @@ static struct my_option my_long_options[] =
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{ "key_buffer_size", OPT_KEY_BUFFER_SIZE, "", { "key_buffer_size", OPT_KEY_BUFFER_SIZE, "",
(uchar**) &check_param.use_buffers, (uchar**) &check_param.use_buffers, 0, (uchar**) &check_param.use_buffers, (uchar**) &check_param.use_buffers, 0,
GET_ULONG, REQUIRED_ARG, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD, GET_ULL, REQUIRED_ARG, USE_BUFFER_INIT, MALLOC_OVERHEAD,
(long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0}, SIZE_T_MAX, MALLOC_OVERHEAD, IO_SIZE, 0},
{ "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "", { "key_cache_block_size", OPT_KEY_CACHE_BLOCK_SIZE, "",
(uchar**) &opt_key_cache_block_size, (uchar**) &opt_key_cache_block_size,
(uchar**) &opt_key_cache_block_size, 0, (uchar**) &opt_key_cache_block_size, 0,
...@@ -1102,7 +1102,7 @@ static int myisamchk(MI_CHECK *param, char * filename) ...@@ -1102,7 +1102,7 @@ static int myisamchk(MI_CHECK *param, char * filename)
{ {
if (param->testflag & (T_EXTEND | T_MEDIUM)) if (param->testflag & (T_EXTEND | T_MEDIUM))
VOID(init_key_cache(dflt_key_cache,opt_key_cache_block_size, VOID(init_key_cache(dflt_key_cache,opt_key_cache_block_size,
param->use_buffers, 0, 0)); (size_t) param->use_buffers, 0, 0));
VOID(init_io_cache(&param->read_cache,datafile, VOID(init_io_cache(&param->read_cache,datafile,
(uint) param->read_buffer_length, (uint) param->read_buffer_length,
READ_CACHE, READ_CACHE,
...@@ -1525,8 +1525,8 @@ static int mi_sort_records(MI_CHECK *param, ...@@ -1525,8 +1525,8 @@ static int mi_sort_records(MI_CHECK *param,
if (share->state.key_root[sort_key] == HA_OFFSET_ERROR) if (share->state.key_root[sort_key] == HA_OFFSET_ERROR)
DBUG_RETURN(0); /* Nothing to do */ DBUG_RETURN(0); /* Nothing to do */
init_key_cache(dflt_key_cache, opt_key_cache_block_size, param->use_buffers, init_key_cache(dflt_key_cache, opt_key_cache_block_size,
0, 0); (size_t) param->use_buffers, 0, 0);
if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length, if (init_io_cache(&info->rec_cache,-1,(uint) param->write_buffer_length,
WRITE_CACHE,share->pack.header_length,1, WRITE_CACHE,share->pack.header_length,1,
MYF(MY_WME | MY_WAIT_IF_FULL))) MYF(MY_WME | MY_WAIT_IF_FULL)))
......
...@@ -925,11 +925,11 @@ int ha_myisammrg::info(uint flag) ...@@ -925,11 +925,11 @@ int ha_myisammrg::info(uint flag)
with such a number, it'll be an error later anyway. with such a number, it'll be an error later anyway.
*/ */
bzero((char*) table->key_info[0].rec_per_key, bzero((char*) table->key_info[0].rec_per_key,
sizeof(table->key_info[0].rec_per_key) * table->s->key_parts); sizeof(table->key_info[0].rec_per_key[0]) * table->s->key_parts);
#endif #endif
memcpy((char*) table->key_info[0].rec_per_key, memcpy((char*) table->key_info[0].rec_per_key,
(char*) mrg_info.rec_per_key, (char*) mrg_info.rec_per_key,
sizeof(table->key_info[0].rec_per_key) * sizeof(table->key_info[0].rec_per_key[0]) *
min(file->keys, table->s->key_parts)); min(file->keys, table->s->key_parts));
} }
} }
......
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