Merge bk-internal.mysql.com:/home/bk/mysql-5.0

into  bodhi.local:/opt/local/work/mysql-5.0-14897
This commit is contained in:
kostja@bodhi.local 2006-08-31 12:34:06 +04:00
commit bddfef1e36
64 changed files with 2601 additions and 822 deletions

View file

@ -1 +1,4 @@
44d03f27qNdqJmARzBoP3Is_cN5e0w
44ec850ac2k4y2Omgr92GiWPBAVKGQ
44edb86b1iE5knJ97MbliK_3lCiAXA
44f33f3aj5KW5qweQeekY1LU0E9ZCg

View file

@ -211,7 +211,13 @@ typedef struct st_net {
char last_error[MYSQL_ERRMSG_SIZE], sqlstate[SQLSTATE_LENGTH+1];
unsigned int last_errno;
unsigned char error;
/*
'query_cache_query' should be accessed only via query cache
functions and methods to maintain proper locking.
*/
gptr query_cache_query;
my_bool report_error; /* We should report error (we have unreported error) */
my_bool return_errno;
} NET;

View file

@ -2,10 +2,6 @@
# that ensure that starting conditions (environment) for the IM-test are as
# expected.
# Wait for mysqld1 (guarded instance) to start.
--exec $MYSQL_TEST_DIR/t/wait_for_process.sh $IM_MYSQLD1_PATH_PID 30 started
# Check the running instances.
--connect (mysql1_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
@ -14,6 +10,8 @@
SHOW VARIABLES LIKE 'server_id';
--source include/not_windows.inc
--connection default
# Let IM detect that mysqld1 is online. This delay should be longer than

View file

@ -1,7 +0,0 @@
--connect (dflt_server_con,localhost,root,,mysql,$IM_MYSQLD1_PORT,$IM_MYSQLD1_SOCK)
--connection dflt_server_con
--source include/not_windows.inc
--connection default
--disconnect dflt_server_con

View file

@ -19,13 +19,39 @@ sub mtr_tonewfile($@);
##############################################################################
sub mtr_get_pid_from_file ($) {
my $file= shift;
my $pid_file_path= shift;
my $TOTAL_ATTEMPTS= 30;
my $timeout= 1;
open(FILE,"<",$file) or mtr_error("can't open file \"$file\": $!");
my $pid= <FILE>;
chomp($pid);
close FILE;
return $pid;
# We should read from the file until we get correct pid. As it is
# stated in BUG#21884, pid file can be empty at some moment. So, we should
# read it until we get valid data.
for (my $cur_attempt= 1; $cur_attempt <= $TOTAL_ATTEMPTS; ++$cur_attempt)
{
mtr_debug("Reading pid file '$pid_file_path' " .
"($cur_attempt of $TOTAL_ATTEMPTS)...");
open(FILE, '<', $pid_file_path)
or mtr_error("can't open file \"$pid_file_path\": $!");
my $pid= <FILE>;
chomp($pid) if defined $pid;
close FILE;
return $pid if defined $pid && $pid ne '';
mtr_debug("Pid file '$pid_file_path' is empty. " .
"Sleeping $timeout second(s)...");
sleep(1);
}
mtr_error("Pid file '$pid_file_path' is corrupted. " .
"Can not retrieve PID in " .
($timeout * $TOTAL_ATTEMPTS) . " seconds.");
}
sub mtr_get_opts_from_file ($) {

View file

@ -20,7 +20,29 @@ sub mtr_record_dead_children ();
sub mtr_exit ($);
sub sleep_until_file_created ($$$);
sub mtr_kill_processes ($);
sub mtr_kill_process ($$$$);
sub mtr_ping_mysqld_server ($);
# Private IM-related operations.
sub mtr_im_kill_process ($$$$);
sub mtr_im_load_pids ($);
sub mtr_im_terminate ($);
sub mtr_im_check_alive ($);
sub mtr_im_check_main_alive ($);
sub mtr_im_check_angel_alive ($);
sub mtr_im_check_mysqlds_alive ($);
sub mtr_im_check_mysqld_alive ($$);
sub mtr_im_cleanup ($);
sub mtr_im_rm_file ($);
sub mtr_im_errlog ($);
sub mtr_im_kill ($);
sub mtr_im_wait_for_connection ($$$);
sub mtr_im_wait_for_mysqld($$$);
# Public IM-related operations.
sub mtr_im_start ($$);
sub mtr_im_stop ($);
# static in C
sub spawn_impl ($$$$$$$$);
@ -359,40 +381,51 @@ sub mtr_process_exit_status {
sub mtr_kill_leftovers () {
# First, kill all masters and slaves that would conflict with
# this run. Make sure to remove the PID file, if any.
# FIXME kill IM manager first, else it will restart the servers, how?!
mtr_debug("mtr_kill_leftovers(): started.");
mtr_im_stop($::instance_manager);
# Kill mysqld servers (masters and slaves) that would conflict with this
# run. Make sure to remove the PID file, if any.
# Don't touch IM-managed mysqld instances -- they should be stopped by
# mtr_im_stop().
mtr_debug("Collecting mysqld-instances to shutdown...");
my @args;
for ( my $idx; $idx < 2; $idx++ )
for ( my $idx= 0; $idx < 2; $idx++ )
{
my $pidfile= $::master->[$idx]->{'path_mypid'};
my $sockfile= $::master->[$idx]->{'path_mysock'};
my $port= $::master->[$idx]->{'path_myport'};
push(@args,{
pid => 0, # We don't know the PID
pidfile => $::instance_manager->{'instances'}->[$idx]->{'path_pid'},
sockfile => $::instance_manager->{'instances'}->[$idx]->{'path_sock'},
port => $::instance_manager->{'instances'}->[$idx]->{'port'},
pidfile => $pidfile,
sockfile => $sockfile,
port => $port,
});
mtr_debug(" - Master mysqld " .
"(idx: $idx; pid: '$pidfile'; socket: '$sockfile'; port: $port)");
}
for ( my $idx; $idx < 2; $idx++ )
for ( my $idx= 0; $idx < 3; $idx++ )
{
push(@args,{
pid => 0, # We don't know the PID
pidfile => $::master->[$idx]->{'path_mypid'},
sockfile => $::master->[$idx]->{'path_mysock'},
port => $::master->[$idx]->{'path_myport'},
});
}
my $pidfile= $::slave->[$idx]->{'path_mypid'};
my $sockfile= $::slave->[$idx]->{'path_mysock'};
my $port= $::slave->[$idx]->{'path_myport'};
for ( my $idx; $idx < 3; $idx++ )
{
push(@args,{
pid => 0, # We don't know the PID
pidfile => $::slave->[$idx]->{'path_mypid'},
sockfile => $::slave->[$idx]->{'path_mysock'},
port => $::slave->[$idx]->{'path_myport'},
pidfile => $pidfile,
sockfile => $sockfile,
port => $port,
});
mtr_debug(" - Slave mysqld " .
"(idx: $idx; pid: '$pidfile'; socket: '$sockfile'; port: $port)");
}
mtr_mysqladmin_shutdown(\@args, 20);
@ -413,6 +446,8 @@ sub mtr_kill_leftovers () {
# FIXME $path_run_dir or something
my $rundir= "$::opt_vardir/run";
mtr_debug("Processing PID files in directory '$rundir'...");
if ( -d $rundir )
{
opendir(RUNDIR, $rundir)
@ -426,8 +461,12 @@ sub mtr_kill_leftovers () {
if ( -f $pidfile )
{
mtr_debug("Processing PID file: '$pidfile'...");
my $pid= mtr_get_pid_from_file($pidfile);
mtr_debug("Got pid: $pid from file '$pidfile'");
# Race, could have been removed between I tested with -f
# and the unlink() below, so I better check again with -f
@ -438,14 +477,24 @@ sub mtr_kill_leftovers () {
if ( $::glob_cygwin_perl or kill(0, $pid) )
{
mtr_debug("There is process with pid $pid -- scheduling for kill.");
push(@pids, $pid); # We know (cygwin guess) it exists
}
else
{
mtr_debug("There is no process with pid $pid -- skipping.");
}
}
}
closedir(RUNDIR);
if ( @pids )
{
mtr_debug("Killing the following processes with PID files: " .
join(' ', @pids) . "...");
start_reap_all();
if ( $::glob_cygwin_perl )
{
# We have no (easy) way of knowing the Cygwin controlling
@ -459,6 +508,7 @@ sub mtr_kill_leftovers () {
my $retries= 10; # 10 seconds
do
{
mtr_debug("Sending SIGKILL to pids: " . join(' ', @pids));
kill(9, @pids);
mtr_debug("Sleep 1 second waiting for processes to die");
sleep(1) # Wait one second
@ -469,19 +519,29 @@ sub mtr_kill_leftovers () {
mtr_warning("can't kill process(es) " . join(" ", @pids));
}
}
stop_reap_all();
}
}
else
{
mtr_debug("Directory for PID files ($rundir) does not exist.");
}
# We may have failed everything, bug we now check again if we have
# the listen ports free to use, and if they are free, just go for it.
mtr_debug("Checking known mysqld servers...");
foreach my $srv ( @args )
{
if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) )
if ( mtr_ping_mysqld_server($srv->{'port'}) )
{
mtr_warning("can't kill old mysqld holding port $srv->{'port'}");
}
}
mtr_debug("mtr_kill_leftovers(): finished.");
}
##############################################################################
@ -653,10 +713,15 @@ sub mtr_mysqladmin_shutdown {
my %mysql_admin_pids;
my @to_kill_specs;
mtr_debug("mtr_mysqladmin_shutdown(): starting...");
mtr_debug("Collecting mysqld-instances to shutdown...");
foreach my $srv ( @$spec )
{
if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) )
if ( mtr_ping_mysqld_server($srv->{'port'}) )
{
mtr_debug("Mysqld (port: $srv->{port}) needs to be stopped.");
push(@to_kill_specs, $srv);
}
}
@ -688,6 +753,9 @@ sub mtr_mysqladmin_shutdown {
mtr_add_arg($args, "--shutdown_timeout=$adm_shutdown_tmo");
mtr_add_arg($args, "shutdown");
mtr_debug("Shutting down mysqld " .
"(port: $srv->{port}; socket: '$srv->{sockfile}')...");
my $path_mysqladmin_log= "$::opt_vardir/log/mysqladmin.log";
my $pid= mtr_spawn($::exe_mysqladmin, $args,
"", $path_mysqladmin_log, $path_mysqladmin_log, "",
@ -719,14 +787,18 @@ sub mtr_mysqladmin_shutdown {
my $res= 1; # If we just fall through, we are done
# in the sense that the servers don't
# listen to their ports any longer
mtr_debug("Waiting for mysqld servers to stop...");
TIME:
while ( $timeout-- )
{
foreach my $srv ( @to_kill_specs )
{
$res= 1; # We are optimistic
if ( mtr_ping_mysqld_server($srv->{'port'}, $srv->{'sockfile'}) )
if ( mtr_ping_mysqld_server($srv->{'port'}) )
{
mtr_debug("Mysqld (port: $srv->{port}) is still alive.");
mtr_debug("Sleep 1 second waiting for processes to stop using port");
sleep(1); # One second
$res= 0;
@ -736,7 +808,14 @@ sub mtr_mysqladmin_shutdown {
last; # If we got here, we are done
}
$timeout or mtr_debug("At least one server is still listening to its port");
if ($res)
{
mtr_debug("mtr_mysqladmin_shutdown(): All mysqld instances are down.");
}
else
{
mtr_debug("mtr_mysqladmin_shutdown(): At least one server is alive.");
}
return $res;
}
@ -795,7 +874,7 @@ sub stop_reap_all {
$SIG{CHLD}= 'DEFAULT';
}
sub mtr_ping_mysqld_server () {
sub mtr_ping_mysqld_server ($) {
my $port= shift;
my $remote= "localhost";
@ -810,13 +889,18 @@ sub mtr_ping_mysqld_server () {
{
mtr_error("can't create socket: $!");
}
mtr_debug("Pinging server (port: $port)...");
if ( connect(SOCK, $paddr) )
{
mtr_debug("Server (port: $port) is alive.");
close(SOCK); # FIXME check error?
return 1;
}
else
{
mtr_debug("Server (port: $port) is dead.");
return 0;
}
}
@ -886,34 +970,6 @@ sub mtr_kill_processes ($) {
}
}
sub mtr_kill_process ($$$$) {
my $pid= shift;
my $signal= shift;
my $total_retries= shift;
my $timeout= shift;
for (my $cur_attempt= 1; $cur_attempt <= $total_retries; ++$cur_attempt)
{
mtr_debug("Sending $signal to $pid...");
kill($signal, $pid);
unless (kill (0, $pid))
{
mtr_debug("Process $pid died.");
return;
}
mtr_debug("Sleeping $timeout second(s) waiting for processes to die...");
sleep($timeout);
}
mtr_debug("Process $pid is still alive after $total_retries " .
"of sending signal $signal.");
}
##############################################################################
#
# When we exit, we kill off all children
@ -943,4 +999,676 @@ sub mtr_exit ($) {
exit($code);
}
##############################################################################
#
# Instance Manager management routines.
#
##############################################################################
sub mtr_im_kill_process ($$$$) {
my $pid_lst= shift;
my $signal= shift;
my $total_retries= shift;
my $timeout= shift;
my %pids;
foreach my $pid (@{$pid_lst})
{
$pids{$pid}= 1;
}
for (my $cur_attempt= 1; $cur_attempt <= $total_retries; ++$cur_attempt)
{
foreach my $pid (keys %pids)
{
mtr_debug("Sending $signal to $pid...");
kill($signal, $pid);
unless (kill (0, $pid))
{
mtr_debug("Process $pid died.");
delete $pids{$pid};
}
}
return if scalar keys %pids == 0;
mtr_debug("Sleeping $timeout second(s) waiting for processes to die...");
sleep($timeout);
}
mtr_debug("Process(es) " .
join(' ', keys %pids) .
" is still alive after $total_retries " .
"of sending signal $signal.");
}
###########################################################################
sub mtr_im_load_pids($) {
my $instance_manager= shift;
mtr_debug("Loading PID files...");
# Obtain mysqld-process pids.
my $instances = $instance_manager->{'instances'};
for (my $idx= 0; $idx < 2; ++$idx)
{
mtr_debug("IM-guarded mysqld[$idx] PID file: '" .
$instances->[$idx]->{'path_pid'} . "'.");
my $mysqld_pid;
if (-r $instances->[$idx]->{'path_pid'})
{
$mysqld_pid= mtr_get_pid_from_file($instances->[$idx]->{'path_pid'});
mtr_debug("IM-guarded mysqld[$idx] PID: $mysqld_pid.");
}
else
{
$mysqld_pid= undef;
mtr_debug("IM-guarded mysqld[$idx]: no PID file.");
}
$instances->[$idx]->{'pid'}= $mysqld_pid;
}
# Re-read Instance Manager PIDs from the file, since during tests Instance
# Manager could have been restarted, so its PIDs could have been changed.
# - IM-main
mtr_debug("IM-main PID file: '$instance_manager->{path_pid}'.");
if (-f $instance_manager->{'path_pid'})
{
$instance_manager->{'pid'} =
mtr_get_pid_from_file($instance_manager->{'path_pid'});
mtr_debug("IM-main PID: $instance_manager->{pid}.");
}
else
{
mtr_debug("IM-main: no PID file.");
$instance_manager->{'pid'}= undef;
}
# - IM-angel
mtr_debug("IM-angel PID file: '$instance_manager->{path_angel_pid}'.");
if (-f $instance_manager->{'path_angel_pid'})
{
$instance_manager->{'angel_pid'} =
mtr_get_pid_from_file($instance_manager->{'path_angel_pid'});
mtr_debug("IM-angel PID: $instance_manager->{'angel_pid'}.");
}
else
{
mtr_debug("IM-angel: no PID file.");
$instance_manager->{'angel_pid'} = undef;
}
}
###########################################################################
sub mtr_im_terminate($) {
my $instance_manager= shift;
# Load pids from pid-files. We should do it first of all, because IM deletes
# them on shutdown.
mtr_im_load_pids($instance_manager);
mtr_debug("Shutting Instance Manager down...");
# Ignoring SIGCHLD so that all children could rest in peace.
start_reap_all();
# Send SIGTERM to IM-main.
if (defined $instance_manager->{'pid'})
{
mtr_debug("IM-main pid: $instance_manager->{pid}.");
mtr_debug("Stopping IM-main...");
mtr_im_kill_process([ $instance_manager->{'pid'} ], 'TERM', 10, 1);
}
else
{
mtr_debug("IM-main pid: n/a.");
}
# If IM-angel was alive, wait for it to die.
if (defined $instance_manager->{'angel_pid'})
{
mtr_debug("IM-angel pid: $instance_manager->{'angel_pid'}.");
mtr_debug("Waiting for IM-angel to die...");
my $total_attempts= 10;
for (my $cur_attempt=1; $cur_attempt <= $total_attempts; ++$cur_attempt)
{
unless (kill (0, $instance_manager->{'angel_pid'}))
{
mtr_debug("IM-angel died.");
last;
}
sleep(1);
}
}
else
{
mtr_debug("IM-angel pid: n/a.");
}
stop_reap_all();
# Re-load PIDs.
mtr_im_load_pids($instance_manager);
}
###########################################################################
sub mtr_im_check_alive($) {
my $instance_manager= shift;
mtr_debug("Checking whether IM-components are alive...");
return 1 if mtr_im_check_main_alive($instance_manager);
return 1 if mtr_im_check_angel_alive($instance_manager);
return 1 if mtr_im_check_mysqlds_alive($instance_manager);
return 0;
}
###########################################################################
sub mtr_im_check_main_alive($) {
my $instance_manager= shift;
# Check that the process, that we know to be IM's, is dead.
if (defined $instance_manager->{'pid'})
{
if (kill (0, $instance_manager->{'pid'}))
{
mtr_debug("IM-main (PID: $instance_manager->{pid}) is alive.");
return 1;
}
else
{
mtr_debug("IM-main (PID: $instance_manager->{pid}) is dead.");
}
}
else
{
mtr_debug("No PID file for IM-main.");
}
# Check that IM does not accept client connections.
if (mtr_ping_mysqld_server($instance_manager->{'port'}))
{
mtr_debug("IM-main (port: $instance_manager->{port}) " .
"is accepting connections.");
mtr_im_errlog("IM-main is accepting connections on port " .
"$instance_manager->{port}, but there is no " .
"process information.");
return 1;
}
else
{
mtr_debug("IM-main (port: $instance_manager->{port}) " .
"does not accept connections.");
return 0;
}
}
###########################################################################
sub mtr_im_check_angel_alive($) {
my $instance_manager= shift;
# Check that the process, that we know to be the Angel, is dead.
if (defined $instance_manager->{'angel_pid'})
{
if (kill (0, $instance_manager->{'angel_pid'}))
{
mtr_debug("IM-angel (PID: $instance_manager->{angel_pid}) is alive.");
return 1;
}
else
{
mtr_debug("IM-angel (PID: $instance_manager->{angel_pid}) is dead.");
return 0;
}
}
else
{
mtr_debug("No PID file for IM-angel.");
return 0;
}
}
###########################################################################
sub mtr_im_check_mysqlds_alive($) {
my $instance_manager= shift;
mtr_debug("Checking for IM-guarded mysqld instances...");
my $instances = $instance_manager->{'instances'};
for (my $idx= 0; $idx < 2; ++$idx)
{
mtr_debug("Checking mysqld[$idx]...");
return 1
if mtr_im_check_mysqld_alive($instance_manager, $instances->[$idx]);
}
}
###########################################################################
sub mtr_im_check_mysqld_alive($$) {
my $instance_manager= shift;
my $mysqld_instance= shift;
# Check that the process is dead.
if (defined $instance_manager->{'pid'})
{
if (kill (0, $instance_manager->{'pid'}))
{
mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is alive.");
return 1;
}
else
{
mtr_debug("Mysqld instance (PID: $mysqld_instance->{pid}) is dead.");
}
}
else
{
mtr_debug("No PID file for mysqld instance.");
}
# Check that mysqld does not accept client connections.
if (mtr_ping_mysqld_server($mysqld_instance->{'port'}))
{
mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " .
"is accepting connections.");
mtr_im_errlog("Mysqld is accepting connections on port " .
"$mysqld_instance->{port}, but there is no " .
"process information.");
return 1;
}
else
{
mtr_debug("Mysqld instance (port: $mysqld_instance->{port}) " .
"does not accept connections.");
return 0;
}
}
###########################################################################
sub mtr_im_cleanup($) {
my $instance_manager= shift;
mtr_im_rm_file($instance_manager->{'path_pid'});
mtr_im_rm_file($instance_manager->{'path_sock'});
mtr_im_rm_file($instance_manager->{'path_angel_pid'});
for (my $idx= 0; $idx < 2; ++$idx)
{
mtr_im_rm_file($instance_manager->{'instances'}->[$idx]->{'path_pid'});
mtr_im_rm_file($instance_manager->{'instances'}->[$idx]->{'path_sock'});
}
}
###########################################################################
sub mtr_im_rm_file($)
{
my $file_path= shift;
if (-f $file_path)
{
mtr_debug("Removing '$file_path'...");
mtr_warning("Can not remove '$file_path'.")
unless unlink($file_path);
}
else
{
mtr_debug("File '$file_path' does not exist already.");
}
}
###########################################################################
sub mtr_im_errlog($) {
my $msg= shift;
# Complain in error log so that a warning will be shown.
#
# TODO: unless BUG#20761 is fixed, we will print the warning to stdout, so
# that it can be seen on console and does not produce pushbuild error.
# my $errlog= "$opt_vardir/log/mysql-test-run.pl.err";
#
# open (ERRLOG, ">>$errlog") ||
# mtr_error("Can not open error log ($errlog)");
#
# my $ts= localtime();
# print ERRLOG
# "Warning: [$ts] $msg\n";
#
# close ERRLOG;
my $ts= localtime();
print "Warning: [$ts] $msg\n";
}
###########################################################################
sub mtr_im_kill($) {
my $instance_manager= shift;
# Re-load PIDs. That can be useful because some processes could have been
# restarted.
mtr_im_load_pids($instance_manager);
# Ignoring SIGCHLD so that all children could rest in peace.
start_reap_all();
# Kill IM-angel first of all.
if (defined $instance_manager->{'angel_pid'})
{
mtr_debug("Killing IM-angel (PID: $instance_manager->{angel_pid})...");
mtr_im_kill_process([ $instance_manager->{'angel_pid'} ], 'KILL', 10, 1)
}
else
{
mtr_debug("IM-angel is dead.");
}
# Re-load PIDs again.
mtr_im_load_pids($instance_manager);
# Kill IM-main.
if (defined $instance_manager->{'pid'})
{
mtr_debug("Killing IM-main (PID: $instance_manager->pid})...");
mtr_im_kill_process([ $instance_manager->{'pid'} ], 'KILL', 10, 1);
}
else
{
mtr_debug("IM-main is dead.");
}
# Re-load PIDs again.
mtr_im_load_pids($instance_manager);
# Kill guarded mysqld instances.
my @mysqld_pids;
mtr_debug("Collecting PIDs of mysqld instances to kill...");
for (my $idx= 0; $idx < 2; ++$idx)
{
my $pid= $instance_manager->{'instances'}->[$idx]->{'pid'};
next unless defined $pid;
mtr_debug(" - IM-guarded mysqld[$idx] PID: $pid.");
push (@mysqld_pids, $pid);
}
if (scalar @mysqld_pids > 0)
{
mtr_debug("Killing IM-guarded mysqld instances...");
mtr_im_kill_process(\@mysqld_pids, 'KILL', 10, 1);
}
# That's all.
stop_reap_all();
}
##############################################################################
sub mtr_im_wait_for_connection($$$) {
my $instance_manager= shift;
my $total_attempts= shift;
my $connect_timeout= shift;
mtr_debug("Waiting for IM on port $instance_manager->{port} " .
"to start accepting connections...");
for (my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt)
{
mtr_debug("Trying to connect to IM ($cur_attempt of $total_attempts)...");
if (mtr_ping_mysqld_server($instance_manager->{'port'}))
{
mtr_debug("IM is accepting connections " .
"on port $instance_manager->{port}.");
return 1;
}
mtr_debug("Sleeping $connect_timeout...");
sleep($connect_timeout);
}
mtr_debug("IM does not accept connections " .
"on port $instance_manager->{port} after " .
($total_attempts * $connect_timeout) . " seconds.");
return 0;
}
##############################################################################
sub mtr_im_wait_for_mysqld($$$) {
my $mysqld= shift;
my $total_attempts= shift;
my $connect_timeout= shift;
mtr_debug("Waiting for IM-guarded mysqld on port $mysqld->{port} " .
"to start accepting connections...");
for (my $cur_attempt= 1; $cur_attempt <= $total_attempts; ++$cur_attempt)
{
mtr_debug("Trying to connect to mysqld " .
"($cur_attempt of $total_attempts)...");
if (mtr_ping_mysqld_server($mysqld->{'port'}))
{
mtr_debug("Mysqld is accepting connections " .
"on port $mysqld->{port}.");
return 1;
}
mtr_debug("Sleeping $connect_timeout...");
sleep($connect_timeout);
}
mtr_debug("Mysqld does not accept connections " .
"on port $mysqld->{port} after " .
($total_attempts * $connect_timeout) . " seconds.");
return 0;
}
##############################################################################
sub mtr_im_start($$) {
my $instance_manager = shift;
my $opts = shift;
mtr_debug("Starting Instance Manager...");
my $args;
mtr_init_args(\$args);
mtr_add_arg($args, "--defaults-file=%s",
$instance_manager->{'defaults_file'});
foreach my $opt (@{$opts})
{
mtr_add_arg($args, $opt);
}
$instance_manager->{'pid'} =
mtr_spawn(
$::exe_im, # path to the executable
$args, # cmd-line args
'', # stdin
$instance_manager->{'path_log'}, # stdout
$instance_manager->{'path_err'}, # stderr
'', # pid file path (not used)
{ append_log_file => 1 } # append log files
);
if ( ! $instance_manager->{'pid'} )
{
mtr_report('Could not start Instance Manager');
return;
}
# Instance Manager can be run in daemon mode. In this case, it creates
# several processes and the parent process, created by mtr_spawn(), exits just
# after start. So, we have to obtain Instance Manager PID from the PID file.
if ( ! sleep_until_file_created(
$instance_manager->{'path_pid'},
$instance_manager->{'start_timeout'},
-1)) # real PID is still unknown
{
mtr_report("Instance Manager PID file is missing");
return;
}
$instance_manager->{'pid'} =
mtr_get_pid_from_file($instance_manager->{'path_pid'});
mtr_debug("Instance Manager started. PID: $instance_manager->{pid}.");
# Wait until we can connect to IM.
my $IM_CONNECT_TIMEOUT= 30;
unless (mtr_im_wait_for_connection($instance_manager,
$IM_CONNECT_TIMEOUT, 1))
{
mtr_debug("Can not connect to Instance Manager " .
"in $IM_CONNECT_TIMEOUT seconds after start.");
mtr_debug("Aborting test suite...");
mtr_kill_leftovers();
mtr_error("Can not connect to Instance Manager " .
"in $IM_CONNECT_TIMEOUT seconds after start.");
}
# Wait until we can connect to guarded mysqld-instances
# (in other words -- wait for IM to start guarded instances).
for (my $idx= 0; $idx < 2; ++$idx)
{
my $mysqld= $instance_manager->{'instances'}->[$idx];
next if exists $mysqld->{'nonguarded'};
mtr_debug("Waiting for mysqld[$idx] to start...");
unless (mtr_im_wait_for_mysqld($mysqld, 30, 1))
{
mtr_debug("Can not connect to mysqld[$idx] " .
"in $IM_CONNECT_TIMEOUT seconds after start.");
mtr_debug("Aborting test suite...");
mtr_kill_leftovers();
mtr_error("Can not connect to mysqld[$idx] " .
"in $IM_CONNECT_TIMEOUT seconds after start.");
}
mtr_debug("mysqld[$idx] started.");
}
mtr_debug("Instance Manager started.");
}
##############################################################################
sub mtr_im_stop($) {
my $instance_manager= shift;
mtr_debug("Stopping Instance Manager...");
# Try graceful shutdown.
mtr_im_terminate($instance_manager);
# Check that all processes died.
unless (mtr_im_check_alive($instance_manager))
{
mtr_debug("Instance Manager has been stopped successfully.");
mtr_im_cleanup($instance_manager);
return 1;
}
# Instance Manager don't want to die. We should kill it.
mtr_im_errlog("Instance Manager did not shutdown gracefully.");
mtr_im_kill($instance_manager);
# Check again that all IM-related processes have been killed.
my $im_is_alive= mtr_im_check_alive($instance_manager);
mtr_im_cleanup($instance_manager);
if ($im_is_alive)
{
mtr_error("Can not kill Instance Manager or its children.");
return 0;
}
mtr_debug("Instance Manager has been killed successfully.");
return 1;
}
###########################################################################
1;

View file

@ -336,7 +336,7 @@ sub snapshot_setup ();
sub executable_setup ();
sub environment_setup ();
sub kill_running_server ();
sub kill_and_cleanup ();
sub cleanup_stale_files ();
sub check_ssl_support ();
sub check_running_as_root();
sub check_ndbcluster_support ();
@ -356,8 +356,6 @@ sub mysqld_arguments ($$$$$$);
sub stop_masters_slaves ();
sub stop_masters ();
sub stop_slaves ();
sub im_start ($$);
sub im_stop ($);
sub run_mysqltest ($);
sub usage ($);
@ -499,7 +497,7 @@ sub command_line_setup () {
my $opt_master_myport= 9306;
my $opt_slave_myport= 9308;
$opt_ndbcluster_port= 9350;
my $im_port= 9310;
my $im_port= 9311;
my $im_mysqld1_port= 9312;
my $im_mysqld2_port= 9314;
@ -1303,6 +1301,7 @@ sub kill_running_server () {
mtr_report("Killing Possible Leftover Processes");
mkpath("$opt_vardir/log"); # Needed for mysqladmin log
mtr_kill_leftovers();
$using_ndbcluster_master= $opt_with_ndbcluster;
@ -1311,9 +1310,7 @@ sub kill_running_server () {
}
}
sub kill_and_cleanup () {
kill_running_server ();
sub cleanup_stale_files () {
mtr_report("Removing Stale Files");
@ -1692,13 +1689,11 @@ sub run_suite () {
sub initialize_servers () {
if ( ! $glob_use_running_server )
{
if ( $opt_start_dirty )
kill_running_server();
unless ( $opt_start_dirty )
{
kill_running_server();
}
else
{
kill_and_cleanup();
cleanup_stale_files();
mysql_install_db();
if ( $opt_force )
{
@ -2100,7 +2095,7 @@ sub run_testcase ($) {
im_create_defaults_file($instance_manager);
im_start($instance_manager, $tinfo->{im_opts});
mtr_im_start($instance_manager, $tinfo->{im_opts});
}
# ----------------------------------------------------------------------
@ -2195,10 +2190,9 @@ sub run_testcase ($) {
# Stop Instance Manager if we are processing an IM-test case.
# ----------------------------------------------------------------------
if ( ! $glob_use_running_server and $tinfo->{'component_id'} eq 'im' and
$instance_manager->{'pid'} )
if ( ! $glob_use_running_server and $tinfo->{'component_id'} eq 'im' )
{
im_stop($instance_manager);
mtr_im_stop($instance_manager);
}
}
@ -2726,11 +2720,8 @@ sub stop_masters_slaves () {
print "Ending Tests\n";
if ( $instance_manager->{'pid'} )
{
print "Shutting-down Instance Manager\n";
im_stop($instance_manager);
}
print "Shutting-down Instance Manager\n";
mtr_im_stop($instance_manager);
print "Shutting-down MySQL daemon\n\n";
stop_masters();
@ -2792,230 +2783,6 @@ sub stop_slaves () {
mtr_stop_mysqld_servers(\@args);
}
##############################################################################
#
# Instance Manager management routines.
#
##############################################################################
sub im_start($$) {
my $instance_manager = shift;
my $opts = shift;
my $args;
mtr_init_args(\$args);
mtr_add_arg($args, "--defaults-file=%s",
$instance_manager->{'defaults_file'});
foreach my $opt (@{$opts})
{
mtr_add_arg($args, $opt);
}
$instance_manager->{'pid'} =
mtr_spawn(
$exe_im, # path to the executable
$args, # cmd-line args
'', # stdin
$instance_manager->{'path_log'}, # stdout
$instance_manager->{'path_err'}, # stderr
'', # pid file path (not used)
{ append_log_file => 1 } # append log files
);
if ( ! $instance_manager->{'pid'} )
{
mtr_report('Could not start Instance Manager');
return;
}
# Instance Manager can be run in daemon mode. In this case, it creates
# several processes and the parent process, created by mtr_spawn(), exits just
# after start. So, we have to obtain Instance Manager PID from the PID file.
if ( ! sleep_until_file_created(
$instance_manager->{'path_pid'},
$instance_manager->{'start_timeout'},
-1)) # real PID is still unknown
{
mtr_report("Instance Manager PID file is missing");
return;
}
$instance_manager->{'pid'} =
mtr_get_pid_from_file($instance_manager->{'path_pid'});
}
sub im_stop($) {
my $instance_manager = shift;
# Obtain mysqld-process pids before we start stopping IM (it can delete pid
# files).
my @mysqld_pids = ();
my $instances = $instance_manager->{'instances'};
push(@mysqld_pids, mtr_get_pid_from_file($instances->[0]->{'path_pid'}))
if -r $instances->[0]->{'path_pid'};
push(@mysqld_pids, mtr_get_pid_from_file($instances->[1]->{'path_pid'}))
if -r $instances->[1]->{'path_pid'};
# Re-read pid from the file, since during tests Instance Manager could have
# been restarted, so its pid could have been changed.
$instance_manager->{'pid'} =
mtr_get_pid_from_file($instance_manager->{'path_pid'})
if -f $instance_manager->{'path_pid'};
if (-f $instance_manager->{'path_angel_pid'})
{
$instance_manager->{'angel_pid'} =
mtr_get_pid_from_file($instance_manager->{'path_angel_pid'})
}
else
{
$instance_manager->{'angel_pid'} = undef;
}
# Inspired from mtr_stop_mysqld_servers().
start_reap_all();
# Try graceful shutdown.
mtr_debug("IM-main pid: $instance_manager->{'pid'}");
mtr_debug("Stopping IM-main...");
mtr_kill_process($instance_manager->{'pid'}, 'TERM', 10, 1);
# If necessary, wait for angel process to die.
if (defined $instance_manager->{'angel_pid'})
{
mtr_debug("IM-angel pid: $instance_manager->{'angel_pid'}");
mtr_debug("Waiting for IM-angel to die...");
my $total_attempts= 10;
for (my $cur_attempt=1; $cur_attempt <= $total_attempts; ++$cur_attempt)
{
unless (kill (0, $instance_manager->{'angel_pid'}))
{
mtr_debug("IM-angel died.");
last;
}
sleep(1);
}
}
# Check that all processes died.
my $clean_shutdown= 0;
while (1)
{
# Check that IM-main died.
if (kill (0, $instance_manager->{'pid'}))
{
mtr_debug("IM-main is still alive.");
last;
}
# Check that IM-angel died.
if (defined $instance_manager->{'angel_pid'} &&
kill (0, $instance_manager->{'angel_pid'}))
{
mtr_debug("IM-angel is still alive.");
last;
}
# Check that all guarded mysqld-instances died.
my $guarded_mysqlds_dead= 1;
foreach my $pid (@mysqld_pids)
{
if (kill (0, $pid))
{
mtr_debug("Guarded mysqld ($pid) is still alive.");
$guarded_mysqlds_dead= 0;
last;
}
}
last unless $guarded_mysqlds_dead;
# Ok, all necessary processes are dead.
$clean_shutdown= 1;
last;
}
# Kill leftovers (the order is important).
if ($clean_shutdown)
{
mtr_debug("IM-shutdown was clean -- all processed died.");
}
else
{
mtr_debug("IM failed to shutdown gracefully. We have to clean the mess...");
}
unless ($clean_shutdown)
{
if (defined $instance_manager->{'angel_pid'})
{
mtr_debug("Killing IM-angel...");
mtr_kill_process($instance_manager->{'angel_pid'}, 'KILL', 10, 1)
}
mtr_debug("Killing IM-main...");
mtr_kill_process($instance_manager->{'pid'}, 'KILL', 10, 1);
# Shutdown managed mysqld-processes. Some of them may be nonguarded, so IM
# will not stop them on shutdown. So, we should firstly try to end them
# legally.
mtr_debug("Killing guarded mysqld(s)...");
mtr_kill_processes(\@mysqld_pids);
# Complain in error log so that a warning will be shown.
#
# TODO: unless BUG#20761 is fixed, we will print the warning
# to stdout, so that it can be seen on console and does not
# produce pushbuild error.
# my $errlog= "$opt_vardir/log/mysql-test-run.pl.err";
#
# open (ERRLOG, ">>$errlog") ||
# mtr_error("Can not open error log ($errlog)");
#
# my $ts= localtime();
# print ERRLOG
# "Warning: [$ts] Instance Manager did not shutdown gracefully.\n";
#
# close ERRLOG;
my $ts= localtime();
print "Warning: [$ts] Instance Manager did not shutdown gracefully.\n";
}
# That's all.
stop_reap_all();
$instance_manager->{'pid'} = undef;
$instance_manager->{'angel_pid'} = undef;
}
#
# Run include/check-testcase.test
# Before a testcase, run in record mode, save result file to var

View file

@ -72,3 +72,16 @@ show tables;
Tables_in_test
t1
drop table t1;
drop database if exists mysqltest;
drop table if exists t1;
create table t1 (i int);
lock tables t1 read;
create database mysqltest;
drop table t1;
show open tables;
drop database mysqltest;
select 1;
1
1
unlock tables;
End of 5.0 tests

View file

@ -943,6 +943,31 @@ DROP TABLE mysqltest3.t_nn;
DROP DATABASE mysqltest3;
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'mysqltest_1'@'localhost';
DROP USER 'mysqltest_1'@'localhost';
use test;
create user mysqltest1_thisisreallytoolong;
ERROR HY000: Operation CREATE USER failed for 'mysqltest1_thisisreallytoolong'@'%'
ERROR HY000: String 'mysqltest1_thisisreallytoolong' is too long for user name (should be no longer than 16)
GRANT CREATE ON mysqltest.* TO 1234567890abcdefGHIKL@localhost;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
GRANT CREATE ON mysqltest.* TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
REVOKE CREATE ON mysqltest.* FROM 1234567890abcdefGHIKL@localhost;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
REVOKE CREATE ON mysqltest.* FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
GRANT CREATE ON t1 TO 1234567890abcdefGHIKL@localhost;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
GRANT CREATE ON t1 TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
REVOKE CREATE ON t1 FROM 1234567890abcdefGHIKL@localhost;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
REVOKE CREATE ON t1 FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
GRANT EXECUTE ON PROCEDURE p1 TO 1234567890abcdefGHIKL@localhost;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
GRANT EXECUTE ON PROCEDURE p1 TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
REVOKE EXECUTE ON PROCEDURE p1 FROM 1234567890abcdefGHIKL@localhost;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
REVOKE EXECUTE ON PROCEDURE t1 FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
End of 5.0 tests

View file

@ -1,4 +1,3 @@
Success: the process has been started.
SHOW VARIABLES LIKE 'server_id';
Variable_name Value
server_id 1

View file

@ -1,4 +1,3 @@
Success: the process has been started.
SHOW VARIABLES LIKE 'server_id';
Variable_name Value
server_id 1

View file

@ -1,4 +1,3 @@
Success: the process has been started.
SHOW VARIABLES LIKE 'server_id';
Variable_name Value
server_id 1

View file

@ -1,4 +1,3 @@
Success: the process has been started.
SHOW VARIABLES LIKE 'server_id';
Variable_name Value
server_id 1

View file

@ -1,4 +1,3 @@
Success: the process has been started.
SHOW VARIABLES LIKE 'server_id';
Variable_name Value
server_id 1

View file

@ -1297,3 +1297,18 @@ ERROR 3D000: No database selected
create temporary table t1 (i int);
ERROR 3D000: No database selected
use test;
DROP TABLE IF EXISTS t1, t2, t3;
CREATE TABLE t1 (i BIGINT, j BIGINT);
CREATE TABLE t2 (i BIGINT);
CREATE TABLE t3 (i BIGINT, j BIGINT);
PREPARE stmt FROM "SELECT * FROM t1 JOIN t2 ON (t2.i = t1.i)
LEFT JOIN t3 ON ((t3.i, t3.j) = (t1.i, t1.j))
WHERE t1.i = ?";
SET @a= 1;
EXECUTE stmt USING @a;
i j i i j
EXECUTE stmt USING @a;
i j i i j
DEALLOCATE PREPARE stmt;
DROP TABLE IF EXISTS t1, t2, t3;
End of 5.0 tests.

View file

@ -634,6 +634,45 @@ flush tables;
return 5;
end|
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create function bug8409() returns int begin reset query cache;
return 1; end|
ERROR 0A000: RESET is not allowed in stored function or trigger
create function bug8409() returns int begin reset master;
return 1; end|
ERROR 0A000: RESET is not allowed in stored function or trigger
create function bug8409() returns int begin reset slave;
return 1; end|
ERROR 0A000: RESET is not allowed in stored function or trigger
create function bug8409() returns int begin flush hosts;
return 1; end|
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create function bug8409() returns int begin flush privileges;
return 1; end|
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create function bug8409() returns int begin flush tables with read lock;
return 1; end|
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create function bug8409() returns int begin flush tables;
return 1; end|
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create function bug8409() returns int begin flush logs;
return 1; end|
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create function bug8409() returns int begin flush status;
return 1; end|
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create function bug8409() returns int begin flush slave;
return 1; end|
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create function bug8409() returns int begin flush master;
return 1; end|
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create function bug8409() returns int begin flush des_key_file;
return 1; end|
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create function bug8409() returns int begin flush user_resources;
return 1; end|
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create procedure bug9529_901234567890123456789012345678901234567890123456789012345()
begin
end|

View file

@ -4872,8 +4872,6 @@ declare continue handler for sqlexception begin end;
select no_such_function();
end|
call bug18787()|
no_such_function()
NULL
drop procedure bug18787|
create database bug18344_012345678901|
use bug18344_012345678901|
@ -5222,6 +5220,126 @@ CHARSET(p3) COLLATION(p3)
greek greek_general_ci
use test|
DROP DATABASE mysqltest1|
drop table if exists t3|
drop table if exists t4|
drop procedure if exists bug8153_subselect|
drop procedure if exists bug8153_subselect_a|
drop procedure if exists bug8153_subselect_b|
drop procedure if exists bug8153_proc_a|
drop procedure if exists bug8153_proc_b|
create table t3 (a int)|
create table t4 (a int)|
insert into t3 values (1), (1), (2), (3)|
insert into t4 values (1), (1)|
create procedure bug8153_subselect()
begin
declare continue handler for sqlexception
begin
select 'statement failed';
end;
update t3 set a=a+1 where (select a from t4 where a=1) is null;
select 'statement after update';
end|
call bug8153_subselect()|
statement failed
statement failed
statement after update
statement after update
select * from t3|
a
1
1
2
3
call bug8153_subselect()|
statement failed
statement failed
statement after update
statement after update
select * from t3|
a
1
1
2
3
drop procedure bug8153_subselect|
create procedure bug8153_subselect_a()
begin
declare continue handler for sqlexception
begin
select 'in continue handler';
end;
select 'reachable code a1';
call bug8153_subselect_b();
select 'reachable code a2';
end|
create procedure bug8153_subselect_b()
begin
select 'reachable code b1';
update t3 set a=a+1 where (select a from t4 where a=1) is null;
select 'unreachable code b2';
end|
call bug8153_subselect_a()|
reachable code a1
reachable code a1
reachable code b1
reachable code b1
in continue handler
in continue handler
reachable code a2
reachable code a2
select * from t3|
a
1
1
2
3
call bug8153_subselect_a()|
reachable code a1
reachable code a1
reachable code b1
reachable code b1
in continue handler
in continue handler
reachable code a2
reachable code a2
select * from t3|
a
1
1
2
3
drop procedure bug8153_subselect_a|
drop procedure bug8153_subselect_b|
create procedure bug8153_proc_a()
begin
declare continue handler for sqlexception
begin
select 'in continue handler';
end;
select 'reachable code a1';
call bug8153_proc_b();
select 'reachable code a2';
end|
create procedure bug8153_proc_b()
begin
select 'reachable code b1';
select no_such_function();
select 'unreachable code b2';
end|
call bug8153_proc_a()|
reachable code a1
reachable code a1
reachable code b1
reachable code b1
in continue handler
in continue handler
reachable code a2
reachable code a2
drop procedure bug8153_proc_a|
drop procedure bug8153_proc_b|
drop table t3|
drop table t4|
drop procedure if exists bug19862|
CREATE TABLE t11 (a INT)|
CREATE TABLE t12 (a INT)|
@ -5256,4 +5374,24 @@ a
1
use test|
drop table t3|
DROP PROCEDURE IF EXISTS bug16899_p1|
DROP FUNCTION IF EXISTS bug16899_f1|
CREATE DEFINER=1234567890abcdefGHIKL@localhost PROCEDURE bug16899_p1()
BEGIN
SET @a = 1;
END|
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
FUNCTION bug16899_f1() RETURNS INT
BEGIN
RETURN 1;
END|
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
drop procedure if exists bug21416|
create procedure bug21416() show create procedure bug21416|
call bug21416()|
Procedure sql_mode Create Procedure
bug21416 CREATE DEFINER=`root`@`localhost` PROCEDURE `bug21416`()
show create procedure bug21416
drop procedure bug21416|
drop table t1,t2;

View file

@ -626,12 +626,51 @@ Trigger Event Table Statement Timing Created sql_mode Definer
t1_bi INSERT t1 set new.a = '2004-01-00' BEFORE # root@localhost
drop table t1;
create table t1 (id int);
create trigger t1_ai after insert on t1 for each row reset query cache;
ERROR 0A000: RESET is not allowed in stored function or trigger
create trigger t1_ai after insert on t1 for each row reset master;
ERROR 0A000: RESET is not allowed in stored function or trigger
create trigger t1_ai after insert on t1 for each row reset slave;
ERROR 0A000: RESET is not allowed in stored function or trigger
create trigger t1_ai after insert on t1 for each row flush hosts;
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create trigger t1_ai after insert on t1 for each row flush tables with read lock;
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create trigger t1_ai after insert on t1 for each row flush logs;
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create trigger t1_ai after insert on t1 for each row flush status;
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create trigger t1_ai after insert on t1 for each row flush slave;
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create trigger t1_ai after insert on t1 for each row flush master;
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create trigger t1_ai after insert on t1 for each row flush des_key_file;
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create trigger t1_ai after insert on t1 for each row flush user_resources;
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create trigger t1_ai after insert on t1 for each row flush tables;
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create trigger t1_ai after insert on t1 for each row flush privileges;
ERROR 0A000: FLUSH is not allowed in stored function or trigger
create procedure p1() flush tables;
drop procedure if exists p1;
create trigger t1_ai after insert on t1 for each row call p1();
create procedure p1() flush tables;
insert into t1 values (0);
ERROR 0A000: FLUSH is not allowed in stored function or trigger
drop procedure p1;
create procedure p1() reset query cache;
insert into t1 values (0);
ERROR 0A000: RESET is not allowed in stored function or trigger
drop procedure p1;
create procedure p1() reset master;
insert into t1 values (0);
ERROR 0A000: RESET is not allowed in stored function or trigger
drop procedure p1;
create procedure p1() reset slave;
insert into t1 values (0);
ERROR 0A000: RESET is not allowed in stored function or trigger
drop procedure p1;
create procedure p1() flush hosts;
insert into t1 values (0);
ERROR 0A000: FLUSH is not allowed in stored function or trigger
drop procedure p1;
@ -639,6 +678,38 @@ create procedure p1() flush privileges;
insert into t1 values (0);
ERROR 0A000: FLUSH is not allowed in stored function or trigger
drop procedure p1;
create procedure p1() flush tables with read lock;
insert into t1 values (0);
ERROR 0A000: FLUSH is not allowed in stored function or trigger
drop procedure p1;
create procedure p1() flush tables;
insert into t1 values (0);
ERROR 0A000: FLUSH is not allowed in stored function or trigger
drop procedure p1;
create procedure p1() flush logs;
insert into t1 values (0);
ERROR 0A000: FLUSH is not allowed in stored function or trigger
drop procedure p1;
create procedure p1() flush status;
insert into t1 values (0);
ERROR 0A000: FLUSH is not allowed in stored function or trigger
drop procedure p1;
create procedure p1() flush slave;
insert into t1 values (0);
ERROR 0A000: FLUSH is not allowed in stored function or trigger
drop procedure p1;
create procedure p1() flush master;
insert into t1 values (0);
ERROR 0A000: FLUSH is not allowed in stored function or trigger
drop procedure p1;
create procedure p1() flush des_key_file;
insert into t1 values (0);
ERROR 0A000: FLUSH is not allowed in stored function or trigger
drop procedure p1;
create procedure p1() flush user_resources;
insert into t1 values (0);
ERROR 0A000: FLUSH is not allowed in stored function or trigger
drop procedure p1;
drop table t1;
create table t1 (id int, data int, username varchar(16));
insert into t1 (id, data) values (1, 0);
@ -1089,4 +1160,17 @@ begin
set @a:= 1;
end|
ERROR HY000: Triggers can not be created on system tables
use test|
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
CREATE TABLE t1(c INT);
CREATE TABLE t2(c INT);
CREATE DEFINER=1234567890abcdefGHIKL@localhost
TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a = 1;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW SET @a = 2;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
DROP TABLE t1;
DROP TABLE t2;
End of 5.0 tests

View file

@ -422,3 +422,34 @@ DROP TABLE IF EXISTS t1;
CREATE TABLE t1(f1 CHAR(100) DEFAULT 'test');
INSERT INTO t1 VALUES(SUBSTR(f1, 1, 3));
DROP TABLE IF EXISTS t1;
drop table if exists t1, t2, t3;
create table t3 (
id int(11),
en varchar(255) character set utf8,
cz varchar(255) character set utf8
);
truncate table t3;
insert into t3 (id, en, cz) values
(1,'en string 1','cz string 1'),
(2,'en string 2','cz string 2'),
(3,'en string 3','cz string 3');
create table t1 (
id int(11),
name_id int(11)
);
insert into t1 (id, name_id) values (1,1), (2,3), (3,3);
create table t2 (id int(11));
insert into t2 (id) values (1), (2), (3);
select t1.*, t2.id, t3.en, t3.cz from t1 left join t2 on t1.id=t2.id
left join t3 on t1.id=t3.id order by t3.id;
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
def test t1 t1 id id 3 11 1 Y 32768 0 63
def test t1 t1 name_id name_id 3 11 1 Y 32768 0 63
def test t2 t2 id id 3 11 1 Y 32768 0 63
def test t3 t3 en en 253 255 11 Y 0 0 8
def test t3 t3 cz cz 253 255 11 Y 0 0 8
id name_id id en cz
1 1 1 en string 1 cz string 1
2 3 2 en string 2 cz string 2
3 3 3 en string 3 cz string 3
drop table t1, t2, t3;

View file

@ -2879,3 +2879,41 @@ View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` where (`t1`.`f1` between now() and (now() + interval 1 minute))
drop view v1;
drop table t1;
DROP TABLE IF EXISTS t1;
DROP VIEW IF EXISTS v1;
DROP VIEW IF EXISTS v2;
CREATE TABLE t1(a INT, b INT);
CREATE DEFINER=1234567890abcdefGHIKL@localhost
VIEW v1 AS SELECT a FROM t1;
ERROR HY000: String '1234567890abcdefGHIKL' is too long for user name (should be no longer than 16)
CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
VIEW v2 AS SELECT b FROM t1;
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
DROP TABLE t1;
DROP FUNCTION IF EXISTS f1;
DROP FUNCTION IF EXISTS f2;
DROP VIEW IF EXISTS v1, v2;
DROP TABLE IF EXISTS t1;
CREATE TABLE t1 (i INT);
CREATE VIEW v1 AS SELECT * FROM t1;
CREATE FUNCTION f1() RETURNS INT
BEGIN
INSERT INTO v1 VALUES (0);
RETURN 0;
END |
SELECT f1();
f1()
0
CREATE ALGORITHM=TEMPTABLE VIEW v2 AS SELECT * FROM t1;
CREATE FUNCTION f2() RETURNS INT
BEGIN
INSERT INTO v2 VALUES (0);
RETURN 0;
END |
SELECT f2();
ERROR HY000: The target table v2 of the INSERT is not updatable
DROP FUNCTION f1;
DROP FUNCTION f2;
DROP VIEW v1, v2;
DROP TABLE t1;
End of 5.0 tests.

Binary file not shown.

View file

@ -81,3 +81,44 @@ show tables;
drop table t1;
# End of 4.1 tests
#
# Test for bug#21216 "Simultaneous DROP TABLE and SHOW OPEN TABLES causes
# server to crash". Crash (caused by failed assertion in 5.0 or by null
# pointer dereference in 5.1) happened when one ran SHOW OPEN TABLES
# while concurrently doing DROP TABLE (or RENAME TABLE, CREATE TABLE LIKE
# or any other command that takes name-lock) in other connection.
#
# Also includes test for similar bug#12212 "Crash that happens during
# removing of database name from cache" reappeared in 5.1 as bug#19403
# In its case crash happened when one concurrently executed DROP DATABASE
# and one of name-locking command.
#
--disable_warnings
drop database if exists mysqltest;
drop table if exists t1;
--enable_warnings
create table t1 (i int);
lock tables t1 read;
create database mysqltest;
connect (addconroot1, localhost, root,,);
--send drop table t1
connect (addconroot2, localhost, root,,);
# Server should not crash in any of the following statements
--disable_result_log
show open tables;
--enable_result_log
--send drop database mysqltest
connection default;
select 1;
unlock tables;
connection addconroot1;
--reap
connection addconroot2;
--reap
disconnect addconroot1;
disconnect addconroot2;
connection default;
--echo End of 5.0 tests

View file

@ -682,8 +682,6 @@ drop table t2;
drop table t1;
#
# Bug#20214: Incorrect error when user calls SHOW CREATE VIEW on non
# privileged view
@ -807,12 +805,62 @@ DROP DATABASE mysqltest3;
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'mysqltest_1'@'localhost';
DROP USER 'mysqltest_1'@'localhost';
# restore the original database
use test;
#
# Bug #10668: CREATE USER does not enforce username length limit
#
--error ER_CANNOT_USER
--error ER_WRONG_STRING_LENGTH
create user mysqltest1_thisisreallytoolong;
#
# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause.
#
# These checks are intended to ensure that appropriate errors are risen when
# illegal user name or hostname is specified in user-clause of GRANT/REVOKE
# statements.
#
# Working with database-level privileges.
--error ER_WRONG_STRING_LENGTH
GRANT CREATE ON mysqltest.* TO 1234567890abcdefGHIKL@localhost;
--error ER_WRONG_STRING_LENGTH
GRANT CREATE ON mysqltest.* TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
--error ER_WRONG_STRING_LENGTH
REVOKE CREATE ON mysqltest.* FROM 1234567890abcdefGHIKL@localhost;
--error ER_WRONG_STRING_LENGTH
REVOKE CREATE ON mysqltest.* FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
# Working with table-level privileges.
--error ER_WRONG_STRING_LENGTH
GRANT CREATE ON t1 TO 1234567890abcdefGHIKL@localhost;
--error ER_WRONG_STRING_LENGTH
GRANT CREATE ON t1 TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
--error ER_WRONG_STRING_LENGTH
REVOKE CREATE ON t1 FROM 1234567890abcdefGHIKL@localhost;
--error ER_WRONG_STRING_LENGTH
REVOKE CREATE ON t1 FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
# Working with routine-level privileges.
--error ER_WRONG_STRING_LENGTH
GRANT EXECUTE ON PROCEDURE p1 TO 1234567890abcdefGHIKL@localhost;
--error ER_WRONG_STRING_LENGTH
GRANT EXECUTE ON PROCEDURE p1 TO some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
--error ER_WRONG_STRING_LENGTH
REVOKE EXECUTE ON PROCEDURE p1 FROM 1234567890abcdefGHIKL@localhost;
--error ER_WRONG_STRING_LENGTH
REVOKE EXECUTE ON PROCEDURE t1 FROM some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY;
--echo End of 5.0 tests

View file

@ -6,7 +6,6 @@
#
###########################################################################
--source include/im_check_os.inc
--source include/im_check_env.inc
###########################################################################

View file

@ -6,7 +6,6 @@
#
###########################################################################
--source include/im_check_os.inc
--source include/im_check_env.inc
###########################################################################

View file

@ -38,7 +38,6 @@
###########################################################################
--source include/im_check_os.inc
--source include/im_check_env.inc
###########################################################################

View file

@ -45,7 +45,6 @@
###########################################################################
--source include/im_check_os.inc
--source include/im_check_env.inc
###########################################################################

View file

@ -6,7 +6,6 @@
#
###########################################################################
--source include/im_check_os.inc
--source include/im_check_env.inc
###########################################################################

View file

@ -1329,4 +1329,33 @@ create temporary table t1 (i int);
# Restore the old environemnt
#
use test;
# End of 5.0 tests
#
# BUG#21166: Prepared statement causes signal 11 on second execution
#
# Changes in an item tree done by optimizer weren't properly
# registered and went unnoticed, which resulted in preliminary freeing
# of used memory.
#
--disable_warnings
DROP TABLE IF EXISTS t1, t2, t3;
--enable_warnings
CREATE TABLE t1 (i BIGINT, j BIGINT);
CREATE TABLE t2 (i BIGINT);
CREATE TABLE t3 (i BIGINT, j BIGINT);
PREPARE stmt FROM "SELECT * FROM t1 JOIN t2 ON (t2.i = t1.i)
LEFT JOIN t3 ON ((t3.i, t3.j) = (t1.i, t1.j))
WHERE t1.i = ?";
SET @a= 1;
EXECUTE stmt USING @a;
EXECUTE stmt USING @a;
DEALLOCATE PREPARE stmt;
DROP TABLE IF EXISTS t1, t2, t3;
--echo End of 5.0 tests.

View file

@ -899,6 +899,45 @@ begin
flush tables;
return 5;
end|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409() returns int begin reset query cache;
return 1; end|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409() returns int begin reset master;
return 1; end|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409() returns int begin reset slave;
return 1; end|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409() returns int begin flush hosts;
return 1; end|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409() returns int begin flush privileges;
return 1; end|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409() returns int begin flush tables with read lock;
return 1; end|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409() returns int begin flush tables;
return 1; end|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409() returns int begin flush logs;
return 1; end|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409() returns int begin flush status;
return 1; end|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409() returns int begin flush slave;
return 1; end|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409() returns int begin flush master;
return 1; end|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409() returns int begin flush des_key_file;
return 1; end|
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create function bug8409() returns int begin flush user_resources;
return 1; end|
#

View file

@ -6146,6 +6146,104 @@ CALL bug16676_p2('a', @v2, @v3)|
use test|
DROP DATABASE mysqltest1|
#
# BUG#8153: Stored procedure with subquery and continue handler, wrong result
#
--disable_warnings
drop table if exists t3|
drop table if exists t4|
drop procedure if exists bug8153_subselect|
drop procedure if exists bug8153_subselect_a|
drop procedure if exists bug8153_subselect_b|
drop procedure if exists bug8153_proc_a|
drop procedure if exists bug8153_proc_b|
--enable_warnings
create table t3 (a int)|
create table t4 (a int)|
insert into t3 values (1), (1), (2), (3)|
insert into t4 values (1), (1)|
## Testing the use case reported in Bug#8153
create procedure bug8153_subselect()
begin
declare continue handler for sqlexception
begin
select 'statement failed';
end;
update t3 set a=a+1 where (select a from t4 where a=1) is null;
select 'statement after update';
end|
call bug8153_subselect()|
select * from t3|
call bug8153_subselect()|
select * from t3|
drop procedure bug8153_subselect|
## Testing a subselect with a non local handler
create procedure bug8153_subselect_a()
begin
declare continue handler for sqlexception
begin
select 'in continue handler';
end;
select 'reachable code a1';
call bug8153_subselect_b();
select 'reachable code a2';
end|
create procedure bug8153_subselect_b()
begin
select 'reachable code b1';
update t3 set a=a+1 where (select a from t4 where a=1) is null;
select 'unreachable code b2';
end|
call bug8153_subselect_a()|
select * from t3|
call bug8153_subselect_a()|
select * from t3|
drop procedure bug8153_subselect_a|
drop procedure bug8153_subselect_b|
## Testing extra use cases, found while investigating
## This is related to BUG#18787, with a non local handler
create procedure bug8153_proc_a()
begin
declare continue handler for sqlexception
begin
select 'in continue handler';
end;
select 'reachable code a1';
call bug8153_proc_b();
select 'reachable code a2';
end|
create procedure bug8153_proc_b()
begin
select 'reachable code b1';
select no_such_function();
select 'unreachable code b2';
end|
call bug8153_proc_a()|
drop procedure bug8153_proc_a|
drop procedure bug8153_proc_b|
drop table t3|
drop table t4|
#
# BUG#19862: Sort with filesort by function evaluates function twice
#
@ -6188,6 +6286,42 @@ select * from (select 1 as a) as t1 natural join (select * from test.t3) as t2|
use test|
drop table t3|
#
# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause.
#
# Prepare.
--disable_warnings
DROP PROCEDURE IF EXISTS bug16899_p1|
DROP FUNCTION IF EXISTS bug16899_f1|
--enable_warnings
--error ER_WRONG_STRING_LENGTH
CREATE DEFINER=1234567890abcdefGHIKL@localhost PROCEDURE bug16899_p1()
BEGIN
SET @a = 1;
END|
--error ER_WRONG_STRING_LENGTH
CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
FUNCTION bug16899_f1() RETURNS INT
BEGIN
RETURN 1;
END|
#
# BUG#21416: SP: Recursion level higher than zero needed for non-recursive call
#
--disable_warnings
drop procedure if exists bug21416|
--enable_warnings
create procedure bug21416() show create procedure bug21416|
call bug21416()|
drop procedure bug21416|
#
# BUG#NNNN: New bug synopsis
#

View file

@ -651,17 +651,105 @@ drop table t1;
# of functions and triggers.
create table t1 (id int);
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger t1_ai after insert on t1 for each row reset query cache;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger t1_ai after insert on t1 for each row reset master;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger t1_ai after insert on t1 for each row reset slave;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger t1_ai after insert on t1 for each row flush hosts;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger t1_ai after insert on t1 for each row flush tables with read lock;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger t1_ai after insert on t1 for each row flush logs;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger t1_ai after insert on t1 for each row flush status;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger t1_ai after insert on t1 for each row flush slave;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger t1_ai after insert on t1 for each row flush master;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger t1_ai after insert on t1 for each row flush des_key_file;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger t1_ai after insert on t1 for each row flush user_resources;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger t1_ai after insert on t1 for each row flush tables;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
create trigger t1_ai after insert on t1 for each row flush privileges;
create procedure p1() flush tables;
--disable_warnings
drop procedure if exists p1;
--enable_warnings
create trigger t1_ai after insert on t1 for each row call p1();
create procedure p1() flush tables;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
create procedure p1() reset query cache;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
create procedure p1() reset master;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
create procedure p1() reset slave;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
create procedure p1() flush hosts;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
create procedure p1() flush privileges;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
create procedure p1() flush tables with read lock;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
create procedure p1() flush tables;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
create procedure p1() flush logs;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
create procedure p1() flush status;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
create procedure p1() flush slave;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
create procedure p1() flush master;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
create procedure p1() flush des_key_file;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
create procedure p1() flush user_resources;
--error ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG
insert into t1 values (0);
drop procedure p1;
drop table t1;
@ -1301,6 +1389,36 @@ create trigger wont_work after update on event for each row
begin
set @a:= 1;
end|
use test|
delimiter ;|
#
# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause.
#
# Prepare.
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP TABLE IF EXISTS t2;
--enable_warnings
CREATE TABLE t1(c INT);
CREATE TABLE t2(c INT);
--error ER_WRONG_STRING_LENGTH
CREATE DEFINER=1234567890abcdefGHIKL@localhost
TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a = 1;
--error ER_WRONG_STRING_LENGTH
CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW SET @a = 2;
# Cleanup.
DROP TABLE t1;
DROP TABLE t2;
--echo End of 5.0 tests

View file

@ -146,3 +146,44 @@ DROP TABLE IF EXISTS t1;
CREATE TABLE t1(f1 CHAR(100) DEFAULT 'test');
INSERT INTO t1 VALUES(SUBSTR(f1, 1, 3));
DROP TABLE IF EXISTS t1;
#
# Bug#14897 "ResultSet.getString("table.column") sometimes doesn't find the
# column"
# Test that after upgrading an old 4.1 VARCHAR column to 5.0 VARCHAR we preserve
# the original column metadata.
#
--disable_warnings
drop table if exists t1, t2, t3;
--enable_warnings
create table t3 (
id int(11),
en varchar(255) character set utf8,
cz varchar(255) character set utf8
);
system cp $MYSQL_TEST_DIR/std_data/14897.frm $MYSQLTEST_VARDIR/master-data/test/t3.frm;
truncate table t3;
insert into t3 (id, en, cz) values
(1,'en string 1','cz string 1'),
(2,'en string 2','cz string 2'),
(3,'en string 3','cz string 3');
create table t1 (
id int(11),
name_id int(11)
);
insert into t1 (id, name_id) values (1,1), (2,3), (3,3);
create table t2 (id int(11));
insert into t2 (id) values (1), (2), (3);
# max_length is different for varchar fields in ps-protocol and we can't
# replace a single metadata column, disable PS protocol
--disable_ps_protocol
--enable_metadata
select t1.*, t2.id, t3.en, t3.cz from t1 left join t2 on t1.id=t2.id
left join t3 on t1.id=t3.id order by t3.id;
--disable_metadata
--enable_ps_protocol
drop table t1, t2, t3;

View file

@ -2760,3 +2760,78 @@ create view v1 as select * from t1 where f1 between now() and now() + interval 1
show create view v1;
drop view v1;
drop table t1;
#
# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause.
#
# Prepare.
--disable_warnings
DROP TABLE IF EXISTS t1;
DROP VIEW IF EXISTS v1;
DROP VIEW IF EXISTS v2;
--enable_warnings
CREATE TABLE t1(a INT, b INT);
--error ER_WRONG_STRING_LENGTH
CREATE DEFINER=1234567890abcdefGHIKL@localhost
VIEW v1 AS SELECT a FROM t1;
--error ER_WRONG_STRING_LENGTH
CREATE DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
VIEW v2 AS SELECT b FROM t1;
# Cleanup.
DROP TABLE t1;
#
# BUG#17591: Updatable view not possible with trigger or stored
# function
#
# During prelocking phase we didn't update lock type of view tables,
# hence READ lock was always requested.
#
--disable_warnings
DROP FUNCTION IF EXISTS f1;
DROP FUNCTION IF EXISTS f2;
DROP VIEW IF EXISTS v1, v2;
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE t1 (i INT);
CREATE VIEW v1 AS SELECT * FROM t1;
delimiter |;
CREATE FUNCTION f1() RETURNS INT
BEGIN
INSERT INTO v1 VALUES (0);
RETURN 0;
END |
delimiter ;|
SELECT f1();
CREATE ALGORITHM=TEMPTABLE VIEW v2 AS SELECT * FROM t1;
delimiter |;
CREATE FUNCTION f2() RETURNS INT
BEGIN
INSERT INTO v2 VALUES (0);
RETURN 0;
END |
delimiter ;|
--error ER_NON_UPDATABLE_TABLE
SELECT f2();
DROP FUNCTION f1;
DROP FUNCTION f2;
DROP VIEW v1, v2;
DROP TABLE t1;
--echo End of 5.0 tests.

View file

@ -117,8 +117,9 @@ DEFS = -DMYSQL_SERVER \
BUILT_SOURCES = sql_yacc.cc sql_yacc.h lex_hash.h
EXTRA_DIST = $(BUILT_SOURCES)
DISTCLEANFILES = lex_hash.h
AM_YFLAGS = -d
DISTCLEANFILES = lex_hash.h sql_yacc.output
AM_YFLAGS = -d --debug --verbose
mysql_tzinfo_to_sql.cc:
rm -f mysql_tzinfo_to_sql.cc

View file

@ -6154,15 +6154,26 @@ Field *Field_string::new_field(MEM_ROOT *root, struct st_table *new_table,
Field *new_field;
if (type() != MYSQL_TYPE_VAR_STRING || keep_type)
return Field::new_field(root, new_table, keep_type);
new_field= Field::new_field(root, new_table, keep_type);
else
{
/*
Old VARCHAR field which should be modified to a VARCHAR on copy
This is done to ensure that ALTER TABLE will convert old VARCHAR fields
to now VARCHAR fields.
*/
return new Field_varstring(field_length, maybe_null(),
field_name, new_table, charset());
/*
Old VARCHAR field which should be modified to a VARCHAR on copy
This is done to ensure that ALTER TABLE will convert old VARCHAR fields
to now VARCHAR fields.
*/
new_field= new Field_varstring(field_length, maybe_null(),
field_name, new_table, charset());
/*
Normally orig_table is different from table only if field was created
via ::new_field. Here we alter the type of field, so ::new_field is
not applicable. But we still need to preserve the original field
metadata for the client-server protocol.
*/
new_field->orig_table= orig_table;
}
return new_field;
}
/****************************************************************************

View file

@ -422,6 +422,49 @@ void Item::rename(char *new_name)
}
/*
Traverse item tree possibly transforming it (replacing items).
SYNOPSIS
Item::transform()
transformer functor that performs transformation of a subtree
arg opaque argument passed to the functor
DESCRIPTION
This function is designed to ease transformation of Item trees.
Re-execution note: every such transformation is registered for
rollback by THD::change_item_tree() and is rolled back at the end
of execution by THD::rollback_item_tree_changes().
Therefore:
- this function can not be used at prepared statement prepare
(in particular, in fix_fields!), as only permanent
transformation of Item trees are allowed at prepare.
- the transformer function shall allocate new Items in execution
memory root (thd->mem_root) and not anywhere else: allocated
items will be gone in the end of execution.
If you don't need to transform an item tree, but only traverse
it, please use Item::walk() instead.
RETURN VALUE
Returns pointer to the new subtree root. THD::change_item_tree()
should be called for it if transformation took place, i.e. if a
pointer to newly allocated item is returned.
*/
Item* Item::transform(Item_transformer transformer, byte *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
return (this->*transformer)(arg);
}
Item_ident::Item_ident(Name_resolution_context *context_arg,
const char *db_name_arg,const char *table_name_arg,
const char *field_name_arg)
@ -3802,11 +3845,11 @@ Item *Item_field::equal_fields_propagator(byte *arg)
See comments in Arg_comparator::set_compare_func() for details
*/
Item *Item_field::set_no_const_sub(byte *arg)
bool Item_field::set_no_const_sub(byte *arg)
{
if (field->charset() != &my_charset_bin)
no_const_subst=1;
return this;
return FALSE;
}
@ -5308,6 +5351,31 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
}
/*
This method like the walk method traverses the item tree, but at the
same time it can replace some nodes in the tree
*/
Item *Item_default_value::transform(Item_transformer transformer, byte *args)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
Item *new_item= arg->transform(transformer, args);
if (!new_item)
return 0;
/*
THD::change_item_tree() should be called only if the tree was
really transformed, i.e. when a new item has been created.
Otherwise we'll be allocating a lot of unnecessary memory for
change records at each execution.
*/
if (arg != new_item)
current_thd->change_item_tree(&arg, new_item);
return (this->*transformer)(args);
}
bool Item_insert_value::eq(const Item *item, bool binary_cmp) const
{
return item->type() == INSERT_VALUE_ITEM &&

View file

@ -734,10 +734,7 @@ public:
return (this->*processor)(arg);
}
virtual Item* transform(Item_transformer transformer, byte *arg)
{
return (this->*transformer)(arg);
}
virtual Item* transform(Item_transformer transformer, byte *arg);
virtual void traverse_cond(Cond_traverser traverser,
void *arg, traverse_order order)
@ -755,7 +752,7 @@ public:
virtual bool is_expensive_processor(byte *arg) { return 0; }
virtual Item *equal_fields_propagator(byte * arg) { return this; }
virtual Item *set_no_const_sub(byte *arg) { return this; }
virtual bool set_no_const_sub(byte *arg) { return FALSE; }
virtual Item *replace_equal_field(byte * arg) { return this; }
/*
@ -1255,7 +1252,7 @@ public:
}
Item_equal *find_item_equal(COND_EQUAL *cond_equal);
Item *equal_fields_propagator(byte *arg);
Item *set_no_const_sub(byte *arg);
bool set_no_const_sub(byte *arg);
Item *replace_equal_field(byte *arg);
inline uint32 max_disp_length() { return field->max_length(); }
Item_field *filed_for_view_update() { return this; }
@ -2116,18 +2113,7 @@ public:
(this->*processor)(args);
}
/*
This method like the walk method traverses the item tree, but
at the same time it can replace some nodes in the tree
*/
Item *transform(Item_transformer transformer, byte *args)
{
Item *new_item= arg->transform(transformer, args);
if (!new_item)
return 0;
arg= new_item;
return (this->*transformer)(args);
}
Item *transform(Item_transformer transformer, byte *args);
};
/*

View file

@ -511,8 +511,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
which would be transformed to:
WHERE col= 'j'
*/
(*a)->transform(&Item::set_no_const_sub, (byte*) 0);
(*b)->transform(&Item::set_no_const_sub, (byte*) 0);
(*a)->walk(&Item::set_no_const_sub, (byte*) 0);
(*b)->walk(&Item::set_no_const_sub, (byte*) 0);
}
break;
}
@ -2765,6 +2765,8 @@ bool Item_cond::walk(Item_processor processor, byte *arg)
Item *Item_cond::transform(Item_transformer transformer, byte *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
List_iterator<Item> li(list);
Item *item;
while ((item= li++))
@ -2772,8 +2774,15 @@ Item *Item_cond::transform(Item_transformer transformer, byte *arg)
Item *new_item= item->transform(transformer, arg);
if (!new_item)
return 0;
/*
THD::change_item_tree() should be called only if the tree was
really transformed, i.e. when a new item has been created.
Otherwise we'll be allocating a lot of unnecessary memory for
change records at each execution.
*/
if (new_item != item)
li.replace(new_item);
current_thd->change_item_tree(li.ref(), new_item);
}
return Item_func::transform(transformer, arg);
}
@ -4018,6 +4027,8 @@ bool Item_equal::walk(Item_processor processor, byte *arg)
Item *Item_equal::transform(Item_transformer transformer, byte *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
List_iterator<Item_field> it(fields);
Item *item;
while ((item= it++))
@ -4025,8 +4036,15 @@ Item *Item_equal::transform(Item_transformer transformer, byte *arg)
Item *new_item= item->transform(transformer, arg);
if (!new_item)
return 0;
/*
THD::change_item_tree() should be called only if the tree was
really transformed, i.e. when a new item has been created.
Otherwise we'll be allocating a lot of unnecessary memory for
change records at each execution.
*/
if (new_item != item)
it.replace((Item_field *) new_item);
current_thd->change_item_tree((Item **) it.ref(), new_item);
}
return Item_func::transform(transformer, arg);
}

View file

@ -258,6 +258,8 @@ void Item_func::traverse_cond(Cond_traverser traverser,
Item *Item_func::transform(Item_transformer transformer, byte *argument)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
if (arg_count)
{
Item **arg,**arg_end;
@ -266,6 +268,13 @@ Item *Item_func::transform(Item_transformer transformer, byte *argument)
Item *new_item= (*arg)->transform(transformer, argument);
if (!new_item)
return 0;
/*
THD::change_item_tree() should be called only if the tree was
really transformed, i.e. when a new item has been created.
Otherwise we'll be allocating a lot of unnecessary memory for
change records at each execution.
*/
if (*arg != new_item)
current_thd->change_item_tree(arg, new_item);
}

View file

@ -154,12 +154,22 @@ bool Item_row::walk(Item_processor processor, byte *arg)
Item *Item_row::transform(Item_transformer transformer, byte *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
for (uint i= 0; i < arg_count; i++)
{
Item *new_item= items[i]->transform(transformer, arg);
if (!new_item)
return 0;
items[i]= new_item;
/*
THD::change_item_tree() should be called only if the tree was
really transformed, i.e. when a new item has been created.
Otherwise we'll be allocating a lot of unnecessary memory for
change records at each execution.
*/
if (items[i] != new_item)
current_thd->change_item_tree(&items[i], new_item);
}
return (this->*transformer)(arg);
}

View file

@ -2051,6 +2051,26 @@ String *Item_func_make_set::val_str(String *str)
}
Item *Item_func_make_set::transform(Item_transformer transformer, byte *arg)
{
DBUG_ASSERT(!current_thd->is_stmt_prepare());
Item *new_item= item->transform(transformer, arg);
if (!new_item)
return 0;
/*
THD::change_item_tree() should be called only if the tree was
really transformed, i.e. when a new item has been created.
Otherwise we'll be allocating a lot of unnecessary memory for
change records at each execution.
*/
if (item != new_item)
current_thd->change_item_tree(&item, new_item);
return Item_str_func::transform(transformer, arg);
}
void Item_func_make_set::print(String *str)
{
str->append(STRING_WITH_LEN("make_set("));

View file

@ -475,14 +475,7 @@ public:
return item->walk(processor, arg) ||
Item_str_func::walk(processor, arg);
}
Item *transform(Item_transformer transformer, byte *arg)
{
Item *new_item= item->transform(transformer, arg);
if (!new_item)
return 0;
item= new_item;
return Item_str_func::transform(transformer, arg);
}
Item *transform(Item_transformer transformer, byte *arg);
void print(String *str);
};

View file

@ -854,6 +854,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
TABLE *table;
char key[MAX_DBKEY_LENGTH];
char *db= table_list->db;
int table_in_key_offset;
uint key_length;
HASH_SEARCH_STATE state;
DBUG_ENTER("lock_table_name");
@ -861,8 +862,9 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
safe_mutex_assert_owner(&LOCK_open);
key_length=(uint) (strmov(strmov(key,db)+1,table_list->table_name)
-key)+ 1;
table_in_key_offset= strmov(key, db) - key + 1;
key_length= (uint)(strmov(key + table_in_key_offset, table_list->table_name)
- key) + 1;
/* Only insert the table if we haven't insert it already */
@ -883,6 +885,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
table->s= &table->share_not_to_be_used;
memcpy((table->s->table_cache_key= (char*) (table+1)), key, key_length);
table->s->db= table->s->table_cache_key;
table->s->table_name= table->s->table_cache_key + table_in_key_offset;
table->s->key_length=key_length;
table->in_use=thd;
table->locked_by_name=1;

View file

@ -566,6 +566,7 @@ void get_default_definer(THD *thd, LEX_USER *definer);
LEX_USER *create_default_definer(THD *thd);
LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name);
LEX_USER *get_current_user(THD *thd, LEX_USER *user);
bool check_string_length(LEX_STRING *str, const char *err_msg, uint max_length);
enum enum_mysql_completiontype {
ROLLBACK_RELEASE=-2, ROLLBACK=1, ROLLBACK_AND_CHAIN=7,
@ -1511,6 +1512,9 @@ void free_list(I_List <i_string> *list);
/* sql_yacc.cc */
extern int MYSQLparse(void *thd);
#ifndef DBUG_OFF
extern void turn_parser_debug_on();
#endif
/* frm_crypt.cc */
#ifdef HAVE_CRYPTED_FRM

View file

@ -2392,10 +2392,8 @@ static int my_message_sql(uint error, const char *str, myf MyFlags)
if ((thd= current_thd))
{
if (thd->spcont &&
thd->spcont->find_handler(error, MYSQL_ERROR::WARN_LEVEL_ERROR))
thd->spcont->handle_error(error, MYSQL_ERROR::WARN_LEVEL_ERROR, thd))
{
if (! thd->spcont->found_handler_here())
thd->net.report_error= 1; /* Make "select" abort correctly */
DBUG_RETURN(0);
}

View file

@ -96,8 +96,11 @@ extern uint test_flags;
extern ulong bytes_sent, bytes_received, net_big_packet_count;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
#ifndef MYSQL_INSTANCE_MANAGER
extern void query_cache_insert(NET *net, const char *packet, ulong length);
#ifdef HAVE_QUERY_CACHE
#define USE_QUERY_CACHE
extern void query_cache_init_query(NET *net);
extern void query_cache_insert(NET *net, const char *packet, ulong length);
#endif // HAVE_QUERY_CACHE
#define update_statistics(A) A
#endif /* MYSQL_INSTANCE_MANGER */
#endif /* defined(MYSQL_SERVER) && !defined(MYSQL_INSTANCE_MANAGER) */
@ -133,7 +136,11 @@ my_bool my_net_init(NET *net, Vio* vio)
net->compress=0; net->reading_or_writing=0;
net->where_b = net->remain_in_buf=0;
net->last_errno=0;
net->query_cache_query=0;
#ifdef USE_QUERY_CACHE
query_cache_init_query(net);
#else
net->query_cache_query= 0;
#endif
net->report_error= 0;
if (vio != 0) /* If real connection */
@ -552,10 +559,8 @@ net_real_write(NET *net,const char *packet,ulong len)
my_bool net_blocking = vio_is_blocking(net->vio);
DBUG_ENTER("net_real_write");
#if defined(MYSQL_SERVER) && defined(HAVE_QUERY_CACHE) \
&& !defined(MYSQL_INSTANCE_MANAGER)
if (net->query_cache_query != 0)
query_cache_insert(net, packet, len);
#if defined(MYSQL_SERVER) && defined(USE_QUERY_CACHE)
query_cache_insert(net, packet, len);
#endif
if (net->error == 2)

View file

@ -53,8 +53,18 @@ bool Protocol_prep::net_store_data(const char *from, uint length)
}
/* Send a error string to client */
/*
Send a error string to client
Design note:
net_printf_error and net_send_error are low-level functions
that shall be used only when a new connection is being
established or at server startup.
For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
critical that every error that can be intercepted is issued in one
place only, my_message_sql.
*/
void net_send_error(THD *thd, uint sql_errno, const char *err)
{
NET *net= &thd->net;
@ -64,19 +74,15 @@ void net_send_error(THD *thd, uint sql_errno, const char *err)
err ? err : net->last_error[0] ?
net->last_error : "NULL"));
DBUG_ASSERT(!thd->spcont);
if (net && net->no_send_error)
{
thd->clear_error();
DBUG_PRINT("info", ("sending error messages prohibited"));
DBUG_VOID_RETURN;
}
if (thd->spcont && thd->spcont->find_handler(sql_errno,
MYSQL_ERROR::WARN_LEVEL_ERROR))
{
if (! thd->spcont->found_handler_here())
thd->net.report_error= 1; /* Make "select" abort correctly */
DBUG_VOID_RETURN;
}
thd->query_error= 1; // needed to catch query errors during replication
if (!err)
{
@ -117,6 +123,15 @@ void net_send_error(THD *thd, uint sql_errno, const char *err)
Write error package and flush to client
It's a little too low level, but I don't want to use another buffer for
this
Design note:
net_printf_error and net_send_error are low-level functions
that shall be used only when a new connection is being
established or at server startup.
For SIGNAL/RESIGNAL and GET DIAGNOSTICS functionality it's
critical that every error that can be intercepted is issued in one
place only, my_message_sql.
*/
void
@ -136,6 +151,8 @@ net_printf_error(THD *thd, uint errcode, ...)
DBUG_ENTER("net_printf_error");
DBUG_PRINT("enter",("message: %u",errcode));
DBUG_ASSERT(!thd->spcont);
if (net && net->no_send_error)
{
thd->clear_error();
@ -143,13 +160,6 @@ net_printf_error(THD *thd, uint errcode, ...)
DBUG_VOID_RETURN;
}
if (thd->spcont && thd->spcont->find_handler(errcode,
MYSQL_ERROR::WARN_LEVEL_ERROR))
{
if (! thd->spcont->found_handler_here())
thd->net.report_error= 1; /* Make "select" abort correctly */
DBUG_VOID_RETURN;
}
thd->query_error= 1; // needed to catch query errors during replication
#ifndef EMBEDDED_LIBRARY
query_cache_abort(net); // Safety

View file

@ -5623,3 +5623,9 @@ ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA
eng "Triggers can not be created on system tables"
ER_REMOVED_SPACES
eng "Leading spaces are removed from name '%s'"
ER_USERNAME
eng "user name"
ER_HOSTNAME
eng "host name"
ER_WRONG_STRING_LENGTH
eng "String '%-.70s' is too long for %s (should be no longer than %d)"

View file

@ -1006,6 +1006,12 @@ sp_find_routine(THD *thd, int type, sp_name *name, sp_cache **cp,
}
DBUG_RETURN(sp->m_first_free_instance);
}
/*
Actually depth could be +1 than the actual value in case a SP calls
SHOW CREATE PROCEDURE. Hence, the linked list could hold up to one more
instance.
*/
level= sp->m_last_cached_sp->m_recursion_level + 1;
if (level > depth)
{
@ -1175,19 +1181,22 @@ sp_update_procedure(THD *thd, sp_name *name, st_sp_chistics *chistics)
int
sp_show_create_procedure(THD *thd, sp_name *name)
{
int ret= SP_KEY_NOT_FOUND;
sp_head *sp;
DBUG_ENTER("sp_show_create_procedure");
DBUG_PRINT("enter", ("name: %.*s", name->m_name.length, name->m_name.str));
/*
Increase the recursion limit for this statement. SHOW CREATE PROCEDURE
does not do actual recursion.
*/
thd->variables.max_sp_recursion_depth++;
if ((sp= sp_find_routine(thd, TYPE_ENUM_PROCEDURE, name,
&thd->sp_proc_cache, FALSE)))
{
int ret= sp->show_create_procedure(thd);
ret= sp->show_create_procedure(thd);
DBUG_RETURN(ret);
}
DBUG_RETURN(SP_KEY_NOT_FOUND);
thd->variables.max_sp_recursion_depth--;
DBUG_RETURN(ret);
}

View file

@ -230,6 +230,12 @@ sp_get_flags_for_command(LEX *lex)
else
flags= sp_head::HAS_COMMIT_OR_ROLLBACK;
break;
case SQLCOM_FLUSH:
flags= sp_head::HAS_SQLCOM_FLUSH;
break;
case SQLCOM_RESET:
flags= sp_head::HAS_SQLCOM_RESET;
break;
case SQLCOM_CREATE_INDEX:
case SQLCOM_CREATE_DB:
case SQLCOM_CREATE_VIEW:

View file

@ -115,7 +115,9 @@ public:
IS_INVOKED= 32, // Is set if this sp_head is being used
HAS_SET_AUTOCOMMIT_STMT= 64,// Is set if a procedure with 'set autocommit'
/* Is set if a procedure with COMMIT (implicit or explicit) | ROLLBACK */
HAS_COMMIT_OR_ROLLBACK= 128
HAS_COMMIT_OR_ROLLBACK= 128,
HAS_SQLCOM_RESET= 2048,
HAS_SQLCOM_FLUSH= 4096
};
/* TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */
@ -335,14 +337,16 @@ public:
my_error(ER_SP_NO_RETSET, MYF(0), where);
else if (m_flags & HAS_SET_AUTOCOMMIT_STMT)
my_error(ER_SP_CANT_SET_AUTOCOMMIT, MYF(0));
else if (m_type != TYPE_ENUM_PROCEDURE &&
(m_flags & sp_head::HAS_COMMIT_OR_ROLLBACK))
{
else if (m_flags & HAS_COMMIT_OR_ROLLBACK)
my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0));
return TRUE;
}
else if (m_flags & HAS_SQLCOM_RESET)
my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "RESET");
else if (m_flags & HAS_SQLCOM_FLUSH)
my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH");
return test(m_flags &
(CONTAINS_DYNAMIC_SQL|MULTI_RESULTS|HAS_SET_AUTOCOMMIT_STMT));
(CONTAINS_DYNAMIC_SQL|MULTI_RESULTS|HAS_SET_AUTOCOMMIT_STMT|
HAS_COMMIT_OR_ROLLBACK|HAS_SQLCOM_RESET|HAS_SQLCOM_FLUSH));
}
#ifndef DBUG_OFF

View file

@ -260,6 +260,65 @@ sp_rcontext::find_handler(uint sql_errno,
return TRUE;
}
/*
Handle the error for a given errno.
The severity of the error is adjusted depending of the current sql_mode.
If an handler is present for the error (see find_handler()),
this function will return true.
If a handler is found and if the severity of the error indicate
that the current instruction executed should abort,
the flag thd->net.report_error is also set.
This will cause the execution of the current instruction in a
sp_instr* to fail, and give control to the handler code itself
in the sp_head::execute() loop.
SYNOPSIS
sql_errno The error code
level Warning level
thd The current thread
- thd->net.report_error is an optional output.
RETURN
TRUE if a handler was found.
FALSE if no handler was found.
*/
bool
sp_rcontext::handle_error(uint sql_errno,
MYSQL_ERROR::enum_warning_level level,
THD *thd)
{
bool handled= FALSE;
MYSQL_ERROR::enum_warning_level elevated_level= level;
/* Depending on the sql_mode of execution,
warnings may be considered errors */
if ((level == MYSQL_ERROR::WARN_LEVEL_WARN) &&
thd->really_abort_on_warning())
{
elevated_level= MYSQL_ERROR::WARN_LEVEL_ERROR;
}
if (find_handler(sql_errno, elevated_level))
{
if (elevated_level == MYSQL_ERROR::WARN_LEVEL_ERROR)
{
/*
Forces to abort the current instruction execution.
NOTE: This code is altering the original meaning of
the net.report_error flag (send an error to the client).
In the context of stored procedures with error handlers,
the flag is reused to cause error propagation,
until the error handler is reached.
No messages will be sent to the client in that context.
*/
thd->net.report_error= 1;
}
handled= TRUE;
}
return handled;
}
void
sp_rcontext::push_cursor(sp_lex_keeper *lex_keeper, sp_instr_cpush *i)

View file

@ -128,6 +128,12 @@ class sp_rcontext : public Sql_alloc
bool
find_handler(uint sql_errno,MYSQL_ERROR::enum_warning_level level);
// If there is an error handler for this error, handle it and return TRUE.
bool
handle_error(uint sql_errno,
MYSQL_ERROR::enum_warning_level level,
THD *thd);
// Returns handler type and sets *ip to location if one was found
inline int
found_handler(uint *ip, uint *fp)

View file

@ -2903,14 +2903,6 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
result= TRUE;
continue;
}
if (Str->host.length > HOSTNAME_LENGTH ||
Str->user.length > USERNAME_LENGTH)
{
my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
MYF(0));
result= TRUE;
continue;
}
/* Create user if needed */
error=replace_user_table(thd, tables[0].table, *Str,
0, revoke_grant, create_new_users,
@ -3115,15 +3107,6 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
result= TRUE;
continue;
}
if (Str->host.length > HOSTNAME_LENGTH ||
Str->user.length > USERNAME_LENGTH)
{
if (!no_error)
my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
MYF(0));
result= TRUE;
continue;
}
/* Create user if needed */
error=replace_user_table(thd, tables[0].table, *Str,
0, revoke_grant, create_new_users,
@ -3249,14 +3232,6 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
result= TRUE;
continue;
}
if (Str->host.length > HOSTNAME_LENGTH ||
Str->user.length > USERNAME_LENGTH)
{
my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
MYF(0));
result= -1;
continue;
}
if (replace_user_table(thd, tables[0].table, *Str,
(!db ? rights : 0), revoke_grant, create_new_users,
test(thd->variables.sql_mode &
@ -4162,14 +4137,6 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
DBUG_RETURN(TRUE);
}
if (lex_user->host.length > HOSTNAME_LENGTH ||
lex_user->user.length > USERNAME_LENGTH)
{
my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
MYF(0));
DBUG_RETURN(TRUE);
}
rw_rdlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
@ -5265,14 +5232,6 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
continue;
}
if (user_name->host.length > HOSTNAME_LENGTH ||
user_name->user.length > USERNAME_LENGTH)
{
append_user(&wrong_users, user_name);
result= TRUE;
continue;
}
/*
Search all in-memory structures and grant tables
for a mention of the new user name.

View file

@ -564,22 +564,63 @@ byte *query_cache_query_get_key(const byte *record, uint *length,
Functions to store things into the query cache
*****************************************************************************/
/*
Note on double-check locking (DCL) usage.
Below, in query_cache_insert(), query_cache_abort() and
query_cache_end_of_result() we use what is called double-check
locking (DCL) for NET::query_cache_query. I.e. we test it first
without a lock, and, if positive, test again under the lock.
This means that if we see 'NET::query_cache_query == 0' without a
lock we will skip the operation. But this is safe here: when we
started to cache a query, we called Query_cache::store_query(), and
NET::query_cache_query was set to non-zero in this thread (and the
thread always sees results of its memory operations, mutex or not).
If later we see 'NET::query_cache_query == 0' without locking a
mutex, that may only mean that some other thread have reset it by
invalidating the query. Skipping the operation in this case is the
right thing to do, as NET::query_cache_query won't get non-zero for
this query again.
See also comments in Query_cache::store_query() and
Query_cache::send_result_to_client().
NOTE, however, that double-check locking is not applicable in
'invalidate' functions, as we may erroneously skip invalidation,
because the thread doing invalidation may never see non-zero
NET::query_cache_query.
*/
void query_cache_init_query(NET *net)
{
/*
It is safe to initialize 'NET::query_cache_query' without a lock
here, because before it will be accessed from different threads it
will be set in this thread under a lock, and access from the same
thread is always safe.
*/
net->query_cache_query= 0;
}
/*
Insert the packet into the query cache.
This should only be called if net->query_cache_query != 0
*/
void query_cache_insert(NET *net, const char *packet, ulong length)
{
DBUG_ENTER("query_cache_insert");
/* See the comment on double-check locking usage above. */
if (net->query_cache_query == 0)
DBUG_VOID_RETURN;
STRUCT_LOCK(&query_cache.structure_guard_mutex);
/*
It is very unlikely that following condition is TRUE (it is possible
only if other thread is resizing cache), so we check it only after guard
mutex lock
*/
if (unlikely(query_cache.query_cache_size == 0))
if (unlikely(query_cache.query_cache_size == 0 ||
query_cache.flush_in_progress))
{
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
DBUG_VOID_RETURN;
@ -616,10 +657,10 @@ void query_cache_insert(NET *net, const char *packet, ulong length)
header->result(result);
header->last_pkt_nr= net->pkt_nr;
BLOCK_UNLOCK_WR(query_block);
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
}
else
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
DBUG_VOID_RETURN;
}
@ -628,33 +669,33 @@ void query_cache_abort(NET *net)
{
DBUG_ENTER("query_cache_abort");
if (net->query_cache_query != 0) // Quick check on unlocked structure
{
STRUCT_LOCK(&query_cache.structure_guard_mutex);
/*
It is very unlikely that following condition is TRUE (it is possible
only if other thread is resizing cache), so we check it only after guard
mutex lock
*/
if (unlikely(query_cache.query_cache_size == 0))
{
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
DBUG_VOID_RETURN;
}
/* See the comment on double-check locking usage above. */
if (net->query_cache_query == 0)
DBUG_VOID_RETURN;
Query_cache_block *query_block = ((Query_cache_block*)
net->query_cache_query);
if (query_block) // Test if changed by other thread
{
DUMP(&query_cache);
BLOCK_LOCK_WR(query_block);
// The following call will remove the lock on query_block
query_cache.free_query(query_block);
}
net->query_cache_query=0;
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
STRUCT_LOCK(&query_cache.structure_guard_mutex);
if (unlikely(query_cache.query_cache_size == 0 ||
query_cache.flush_in_progress))
{
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
DBUG_VOID_RETURN;
}
Query_cache_block *query_block= ((Query_cache_block*)
net->query_cache_query);
if (query_block) // Test if changed by other thread
{
DUMP(&query_cache);
BLOCK_LOCK_WR(query_block);
// The following call will remove the lock on query_block
query_cache.free_query(query_block);
net->query_cache_query= 0;
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
}
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
DBUG_VOID_RETURN;
}
@ -663,60 +704,65 @@ void query_cache_end_of_result(THD *thd)
{
DBUG_ENTER("query_cache_end_of_result");
if (thd->net.query_cache_query != 0) // Quick check on unlocked structure
{
#ifdef EMBEDDED_LIBRARY
query_cache_insert(&thd->net, (char*)thd,
emb_count_querycache_size(thd));
#endif
STRUCT_LOCK(&query_cache.structure_guard_mutex);
/*
It is very unlikely that following condition is TRUE (it is possible
only if other thread is resizing cache), so we check it only after guard
mutex lock
*/
if (unlikely(query_cache.query_cache_size == 0))
{
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
DBUG_VOID_RETURN;
}
/* See the comment on double-check locking usage above. */
if (thd->net.query_cache_query == 0)
DBUG_VOID_RETURN;
Query_cache_block *query_block = ((Query_cache_block*)
thd->net.query_cache_query);
if (query_block)
{
DUMP(&query_cache);
BLOCK_LOCK_WR(query_block);
Query_cache_query *header = query_block->query();
Query_cache_block *last_result_block = header->result()->prev;
ulong allign_size = ALIGN_SIZE(last_result_block->used);
ulong len = max(query_cache.min_allocation_unit, allign_size);
if (last_result_block->length >= query_cache.min_allocation_unit + len)
query_cache.split_block(last_result_block,len);
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
#ifdef EMBEDDED_LIBRARY
query_cache_insert(&thd->net, (char*)thd,
emb_count_querycache_size(thd));
#endif
STRUCT_LOCK(&query_cache.structure_guard_mutex);
if (unlikely(query_cache.query_cache_size == 0 ||
query_cache.flush_in_progress))
{
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
DBUG_VOID_RETURN;
}
Query_cache_block *query_block= ((Query_cache_block*)
thd->net.query_cache_query);
if (query_block)
{
DUMP(&query_cache);
BLOCK_LOCK_WR(query_block);
Query_cache_query *header= query_block->query();
Query_cache_block *last_result_block= header->result()->prev;
ulong allign_size= ALIGN_SIZE(last_result_block->used);
ulong len= max(query_cache.min_allocation_unit, allign_size);
if (last_result_block->length >= query_cache.min_allocation_unit + len)
query_cache.split_block(last_result_block,len);
#ifndef DBUG_OFF
if (header->result() == 0)
{
DBUG_PRINT("error", ("end of data whith no result. query '%s'",
header->query()));
query_cache.wreck(__LINE__, "");
DBUG_VOID_RETURN;
}
#endif
header->found_rows(current_thd->limit_found_rows);
header->result()->type = Query_cache_block::RESULT;
header->writer(0);
BLOCK_UNLOCK_WR(query_block);
}
else
if (header->result() == 0)
{
// Cache was flushed or resized and query was deleted => do nothing
DBUG_PRINT("error", ("end of data whith no result. query '%s'",
header->query()));
query_cache.wreck(__LINE__, "");
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
DBUG_VOID_RETURN;
}
thd->net.query_cache_query=0;
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(0););
#endif
header->found_rows(current_thd->limit_found_rows);
header->result()->type= Query_cache_block::RESULT;
header->writer(0);
thd->net.query_cache_query= 0;
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
BLOCK_UNLOCK_WR(query_block);
}
else
{
// Cache was flushed or resized and query was deleted => do nothing
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
}
DBUG_VOID_RETURN;
}
@ -762,8 +808,7 @@ ulong Query_cache::resize(ulong query_cache_size_arg)
query_cache_size_arg));
DBUG_ASSERT(initialized);
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0)
free_cache();
free_cache();
query_cache_size= query_cache_size_arg;
::query_cache_size= init_cache();
STRUCT_UNLOCK(&structure_guard_mutex);
@ -784,7 +829,15 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
TABLE_COUNTER_TYPE local_tables;
ulong tot_length;
DBUG_ENTER("Query_cache::store_query");
if (query_cache_size == 0 || thd->locked_tables)
/*
Testing 'query_cache_size' without a lock here is safe: the thing
we may loose is that the query won't be cached, but we save on
mutex locking in the case when query cache is disabled or the
query is uncachable.
See also a note on double-check locking usage above.
*/
if (thd->locked_tables || query_cache_size == 0)
DBUG_VOID_RETURN;
uint8 tables_type= 0;
@ -836,9 +889,9 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
acquiring the query cache mutex.
*/
ha_release_temporary_latches(thd);
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size == 0)
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size == 0 || flush_in_progress)
{
STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_VOID_RETURN;
@ -912,11 +965,12 @@ sql mode: 0x%lx, sort len: %lu, conncat len: %lu",
double_linked_list_simple_include(query_block, &queries_blocks);
inserts++;
queries_in_cache++;
STRUCT_UNLOCK(&structure_guard_mutex);
net->query_cache_query= (gptr) query_block;
header->writer(net);
header->tables_type(tables_type);
STRUCT_UNLOCK(&structure_guard_mutex);
// init_n_lock make query block locked
BLOCK_UNLOCK_WR(query_block);
}
@ -970,12 +1024,16 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
Query_cache_query_flags flags;
DBUG_ENTER("Query_cache::send_result_to_client");
if (query_cache_size == 0 || thd->locked_tables ||
thd->variables.query_cache_type == 0)
goto err;
/*
Testing 'query_cache_size' without a lock here is safe: the thing
we may loose is that the query won't be served from cache, but we
save on mutex locking in the case when query cache is disabled.
/* Check that we haven't forgot to reset the query cache variables */
DBUG_ASSERT(thd->net.query_cache_query == 0);
See also a note on double-check locking usage above.
*/
if (thd->locked_tables || thd->variables.query_cache_type == 0 ||
query_cache_size == 0)
goto err;
if (!thd->lex->safe_to_cache_query)
{
@ -1011,11 +1069,15 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
}
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size == 0)
if (query_cache_size == 0 || flush_in_progress)
{
DBUG_PRINT("qcache", ("query cache disabled"));
goto err_unlock;
}
/* Check that we haven't forgot to reset the query cache variables */
DBUG_ASSERT(thd->net.query_cache_query == 0);
Query_cache_block *query_block;
tot_length= query_length + thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE;
@ -1241,45 +1303,43 @@ void Query_cache::invalidate(THD *thd, TABLE_LIST *tables_used,
my_bool using_transactions)
{
DBUG_ENTER("Query_cache::invalidate (table list)");
if (query_cache_size > 0)
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0 && !flush_in_progress)
{
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0)
{
DUMP(this);
DUMP(this);
using_transactions = using_transactions &&
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
for (; tables_used; tables_used= tables_used->next_local)
{
DBUG_ASSERT(!using_transactions || tables_used->table!=0);
if (tables_used->derived)
continue;
if (using_transactions &&
(tables_used->table->file->table_cache_type() ==
HA_CACHE_TBL_TRANSACT))
/*
Tables_used->table can't be 0 in transaction.
Only 'drop' invalidate not opened table, but 'drop'
force transaction finish.
*/
thd->add_changed_table(tables_used->table);
else
invalidate_table(tables_used);
}
using_transactions= using_transactions &&
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
for (; tables_used; tables_used= tables_used->next_local)
{
DBUG_ASSERT(!using_transactions || tables_used->table!=0);
if (tables_used->derived)
continue;
if (using_transactions &&
(tables_used->table->file->table_cache_type() ==
HA_CACHE_TBL_TRANSACT))
/*
Tables_used->table can't be 0 in transaction.
Only 'drop' invalidate not opened table, but 'drop'
force transaction finish.
*/
thd->add_changed_table(tables_used->table);
else
invalidate_table(tables_used);
}
STRUCT_UNLOCK(&structure_guard_mutex);
}
STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_VOID_RETURN;
}
void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used)
{
DBUG_ENTER("Query_cache::invalidate (changed table list)");
if (query_cache_size > 0 && tables_used)
if (tables_used)
{
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0)
if (query_cache_size > 0 && !flush_in_progress)
{
DUMP(this);
for (; tables_used; tables_used= tables_used->next)
@ -1309,10 +1369,10 @@ void Query_cache::invalidate(CHANGED_TABLE_LIST *tables_used)
void Query_cache::invalidate_locked_for_write(TABLE_LIST *tables_used)
{
DBUG_ENTER("Query_cache::invalidate_locked_for_write");
if (query_cache_size > 0 && tables_used)
if (tables_used)
{
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0)
if (query_cache_size > 0 && !flush_in_progress)
{
DUMP(this);
for (; tables_used; tables_used= tables_used->next_local)
@ -1336,21 +1396,19 @@ void Query_cache::invalidate(THD *thd, TABLE *table,
{
DBUG_ENTER("Query_cache::invalidate (table)");
if (query_cache_size > 0)
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0 && !flush_in_progress)
{
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0)
{
using_transactions = using_transactions &&
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
if (using_transactions &&
(table->file->table_cache_type() == HA_CACHE_TBL_TRANSACT))
thd->add_changed_table(table);
else
invalidate_table(table);
}
STRUCT_UNLOCK(&structure_guard_mutex);
using_transactions= using_transactions &&
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
if (using_transactions &&
(table->file->table_cache_type() == HA_CACHE_TBL_TRANSACT))
thd->add_changed_table(table);
else
invalidate_table(table);
}
STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_VOID_RETURN;
}
@ -1359,20 +1417,18 @@ void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length,
{
DBUG_ENTER("Query_cache::invalidate (key)");
if (query_cache_size > 0)
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0 && !flush_in_progress)
{
using_transactions = using_transactions &&
using_transactions= using_transactions &&
(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN));
if (using_transactions) // used for innodb => has_transactions() is TRUE
thd->add_changed_table(key, key_length);
else
{
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0)
invalidate_table((byte*)key, key_length);
STRUCT_UNLOCK(&structure_guard_mutex);
}
invalidate_table((byte*)key, key_length);
}
STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_VOID_RETURN;
}
@ -1383,38 +1439,36 @@ void Query_cache::invalidate(THD *thd, const char *key, uint32 key_length,
void Query_cache::invalidate(char *db)
{
DBUG_ENTER("Query_cache::invalidate (db)");
if (query_cache_size > 0)
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0 && !flush_in_progress)
{
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0)
{
DUMP(this);
DUMP(this);
restart_search:
if (tables_blocks)
if (tables_blocks)
{
Query_cache_block *curr= tables_blocks;
Query_cache_block *next;
do
{
Query_cache_block *curr= tables_blocks;
Query_cache_block *next;
do
{
next= curr->next;
if (strcmp(db, (char*)(curr->table()->db())) == 0)
invalidate_table(curr);
/*
invalidate_table can freed block on which point 'next' (if
table of this block used only in queries which was deleted
by invalidate_table). As far as we do not allocate new blocks
and mark all headers of freed blocks as 'FREE' (even if they are
merged with other blocks) we can just test type of block
to be sure that block is not deleted
*/
if (next->type == Query_cache_block::FREE)
goto restart_search;
curr= next;
} while (curr != tables_blocks);
}
next= curr->next;
if (strcmp(db, (char*)(curr->table()->db())) == 0)
invalidate_table(curr);
/*
invalidate_table can freed block on which point 'next' (if
table of this block used only in queries which was deleted
by invalidate_table). As far as we do not allocate new blocks
and mark all headers of freed blocks as 'FREE' (even if they are
merged with other blocks) we can just test type of block
to be sure that block is not deleted
*/
if (next->type == Query_cache_block::FREE)
goto restart_search;
curr= next;
} while (curr != tables_blocks);
}
STRUCT_UNLOCK(&structure_guard_mutex);
}
STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_VOID_RETURN;
}
@ -1422,23 +1476,22 @@ void Query_cache::invalidate(char *db)
void Query_cache::invalidate_by_MyISAM_filename(const char *filename)
{
DBUG_ENTER("Query_cache::invalidate_by_MyISAM_filename");
if (query_cache_size > 0)
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0 && !flush_in_progress)
{
/* Calculate the key outside the lock to make the lock shorter */
char key[MAX_DBKEY_LENGTH];
uint32 db_length;
uint key_length= filename_2_table_key(key, filename, &db_length);
STRUCT_LOCK(&structure_guard_mutex);
if (query_cache_size > 0) // Safety if cache removed
{
Query_cache_block *table_block;
if ((table_block = (Query_cache_block*) hash_search(&tables,
(byte*) key,
key_length)))
invalidate_table(table_block);
}
STRUCT_UNLOCK(&structure_guard_mutex);
Query_cache_block *table_block;
if ((table_block = (Query_cache_block*) hash_search(&tables,
(byte*) key,
key_length)))
invalidate_table(table_block);
}
STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_VOID_RETURN;
}
@ -1483,7 +1536,12 @@ void Query_cache::destroy()
}
else
{
/* Underlying code expects the lock. */
STRUCT_LOCK(&structure_guard_mutex);
free_cache();
STRUCT_UNLOCK(&structure_guard_mutex);
pthread_cond_destroy(&COND_flush_finished);
pthread_mutex_destroy(&structure_guard_mutex);
initialized = 0;
}
@ -1499,6 +1557,8 @@ void Query_cache::init()
{
DBUG_ENTER("Query_cache::init");
pthread_mutex_init(&structure_guard_mutex,MY_MUTEX_INIT_FAST);
pthread_cond_init(&COND_flush_finished, NULL);
flush_in_progress= FALSE;
initialized = 1;
DBUG_VOID_RETURN;
}
@ -1694,6 +1754,17 @@ void Query_cache::make_disabled()
}
/*
free_cache() - free all resources allocated by the cache.
SYNOPSIS
free_cache()
DESCRIPTION
This function frees all resources allocated by the cache. You
have to call init_cache() before using the cache again.
*/
void Query_cache::free_cache()
{
DBUG_ENTER("Query_cache::free_cache");
@ -1728,17 +1799,51 @@ void Query_cache::free_cache()
Free block data
*****************************************************************************/
/*
The following assumes we have a lock on the cache
flush_cache() - flush the cache.
SYNOPSIS
flush_cache()
DESCRIPTION
This function will flush cache contents. It assumes we have
'structure_guard_mutex' locked. The function sets the
flush_in_progress flag and releases the lock, so other threads may
proceed skipping the cache as if it is disabled. Concurrent
flushes are performed in turn.
*/
void Query_cache::flush_cache()
{
/*
If there is flush in progress, wait for it to finish, and then do
our flush. This is necessary because something could be added to
the cache before we acquire the lock again, and some code (like
Query_cache::free_cache()) depends on the fact that after the
flush the cache is empty.
*/
while (flush_in_progress)
pthread_cond_wait(&COND_flush_finished, &structure_guard_mutex);
/*
Setting 'flush_in_progress' will prevent other threads from using
the cache while we are in the middle of the flush, and we release
the lock so that other threads won't block.
*/
flush_in_progress= TRUE;
STRUCT_UNLOCK(&structure_guard_mutex);
my_hash_reset(&queries);
while (queries_blocks != 0)
{
BLOCK_LOCK_WR(queries_blocks);
free_query(queries_blocks);
free_query_internal(queries_blocks);
}
STRUCT_LOCK(&structure_guard_mutex);
flush_in_progress= FALSE;
pthread_cond_signal(&COND_flush_finished);
}
/*
@ -1784,36 +1889,48 @@ my_bool Query_cache::free_old_query()
DBUG_RETURN(1); // Nothing to remove
}
/*
Free query from query cache.
query_block must be locked for writing.
This function will remove (and destroy) the lock for the query.
free_query_internal() - free query from query cache.
SYNOPSIS
free_query_internal()
query_block Query_cache_block representing the query
DESCRIPTION
This function will remove the query from a cache, and place its
memory blocks to the list of free blocks. 'query_block' must be
locked for writing, this function will release (and destroy) this
lock.
NOTE
'query_block' should be removed from 'queries' hash _before_
calling this method, as the lock will be destroyed here.
*/
void Query_cache::free_query(Query_cache_block *query_block)
void Query_cache::free_query_internal(Query_cache_block *query_block)
{
DBUG_ENTER("Query_cache::free_query");
DBUG_ENTER("Query_cache::free_query_internal");
DBUG_PRINT("qcache", ("free query 0x%lx %lu bytes result",
(ulong) query_block,
query_block->query()->length() ));
queries_in_cache--;
hash_delete(&queries,(byte *) query_block);
Query_cache_query *query = query_block->query();
Query_cache_query *query= query_block->query();
if (query->writer() != 0)
{
/* Tell MySQL that this query should not be cached anymore */
query->writer()->query_cache_query = 0;
query->writer()->query_cache_query= 0;
query->writer(0);
}
double_linked_list_exclude(query_block, &queries_blocks);
Query_cache_block_table *table=query_block->table(0);
Query_cache_block_table *table= query_block->table(0);
for (TABLE_COUNTER_TYPE i=0; i < query_block->n_tables; i++)
for (TABLE_COUNTER_TYPE i= 0; i < query_block->n_tables; i++)
unlink_table(table++);
Query_cache_block *result_block = query->result();
Query_cache_block *result_block= query->result();
/*
The following is true when query destruction was called and no results
@ -1827,11 +1944,11 @@ void Query_cache::free_query(Query_cache_block *query_block)
refused++;
inserts--;
}
Query_cache_block *block = result_block;
Query_cache_block *block= result_block;
do
{
Query_cache_block *current = block;
block = block->next;
Query_cache_block *current= block;
block= block->next;
free_memory_block(current);
} while (block != result_block);
}
@ -1848,6 +1965,32 @@ void Query_cache::free_query(Query_cache_block *query_block)
DBUG_VOID_RETURN;
}
/*
free_query() - free query from query cache.
SYNOPSIS
free_query()
query_block Query_cache_block representing the query
DESCRIPTION
This function will remove 'query_block' from 'queries' hash, and
then call free_query_internal(), which see.
*/
void Query_cache::free_query(Query_cache_block *query_block)
{
DBUG_ENTER("Query_cache::free_query");
DBUG_PRINT("qcache", ("free query 0x%lx %lu bytes result",
(ulong) query_block,
query_block->query()->length() ));
hash_delete(&queries,(byte *) query_block);
free_query_internal(query_block);
DBUG_VOID_RETURN;
}
/*****************************************************************************
Query data creation
*****************************************************************************/
@ -2431,12 +2574,8 @@ Query_cache::allocate_block(ulong len, my_bool not_less, ulong min,
if (!under_guard)
{
STRUCT_LOCK(&structure_guard_mutex);
/*
It is very unlikely that following condition is TRUE (it is possible
only if other thread is resizing cache), so we check it only after
guard mutex lock
*/
if (unlikely(query_cache.query_cache_size == 0))
if (unlikely(query_cache.query_cache_size == 0 || flush_in_progress))
{
STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_RETURN(0);
@ -2892,11 +3031,9 @@ static TABLE_COUNTER_TYPE process_and_count_tables(TABLE_LIST *tables_used,
(query without tables are not cached)
*/
TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len,
char *query,
LEX *lex,
TABLE_LIST *tables_used,
uint8 *tables_type)
TABLE_COUNTER_TYPE
Query_cache::is_cacheable(THD *thd, uint32 query_len, char *query, LEX *lex,
TABLE_LIST *tables_used, uint8 *tables_type)
{
TABLE_COUNTER_TYPE table_count;
DBUG_ENTER("Query_cache::is_cacheable");
@ -2979,13 +3116,10 @@ my_bool Query_cache::ask_handler_allowance(THD *thd,
void Query_cache::pack_cache()
{
DBUG_ENTER("Query_cache::pack_cache");
STRUCT_LOCK(&structure_guard_mutex);
/*
It is very unlikely that following condition is TRUE (it is possible
only if other thread is resizing cache), so we check it only after
guard mutex lock
*/
if (unlikely(query_cache_size == 0))
if (unlikely(query_cache_size == 0 || flush_in_progress))
{
STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_VOID_RETURN;
@ -3300,7 +3434,7 @@ my_bool Query_cache::join_results(ulong join_limit)
DBUG_ENTER("Query_cache::join_results");
STRUCT_LOCK(&structure_guard_mutex);
if (queries_blocks != 0)
if (queries_blocks != 0 && !flush_in_progress)
{
DBUG_ASSERT(query_cache_size > 0);
Query_cache_block *block = queries_blocks;
@ -3587,31 +3721,23 @@ void Query_cache::tables_dump()
}
my_bool Query_cache::check_integrity(bool not_locked)
my_bool Query_cache::check_integrity(bool locked)
{
my_bool result = 0;
uint i;
DBUG_ENTER("check_integrity");
if (query_cache_size == 0)
if (!locked)
STRUCT_LOCK(&structure_guard_mutex);
if (unlikely(query_cache_size == 0 || flush_in_progress))
{
if (!locked)
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
DBUG_PRINT("qcache", ("Query Cache not initialized"));
DBUG_RETURN(0);
}
if (!not_locked)
{
STRUCT_LOCK(&structure_guard_mutex);
/*
It is very unlikely that following condition is TRUE (it is possible
only if other thread is resizing cache), so we check it only after
guard mutex lock
*/
if (unlikely(query_cache_size == 0))
{
STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
DBUG_RETURN(0);
}
}
if (hash_check(&queries))
{
@ -3856,7 +3982,7 @@ my_bool Query_cache::check_integrity(bool not_locked)
}
}
DBUG_ASSERT(result == 0);
if (!not_locked)
if (!locked)
STRUCT_UNLOCK(&structure_guard_mutex);
DBUG_RETURN(result);
}

View file

@ -195,7 +195,6 @@ extern "C"
byte *query_cache_table_get_key(const byte *record, uint *length,
my_bool not_used);
}
void query_cache_insert(NET *thd, const char *packet, ulong length);
extern "C" void query_cache_invalidate_by_MyISAM_filename(const char* filename);
@ -241,6 +240,12 @@ public:
ulong free_memory, queries_in_cache, hits, inserts, refused,
free_memory_blocks, total_blocks, lowmem_prunes;
private:
pthread_cond_t COND_flush_finished;
bool flush_in_progress;
void free_query_internal(Query_cache_block *point);
protected:
/*
The following mutex is locked when searching or changing global
@ -249,6 +254,12 @@ protected:
LOCK SEQUENCE (to prevent deadlocks):
1. structure_guard_mutex
2. query block (for operation inside query (query block/results))
Thread doing cache flush releases the mutex once it sets
flush_in_progress flag, so other threads may bypass the cache as
if it is disabled, not waiting for reset to finish. The exception
is other threads that were going to do cache flush---they'll wait
till the end of a flush operation.
*/
pthread_mutex_t structure_guard_mutex;
byte *cache; // cache memory
@ -358,6 +369,7 @@ protected:
If query is cacheable return number tables in query
(query without tables not cached)
*/
static
TABLE_COUNTER_TYPE is_cacheable(THD *thd, uint32 query_len, char *query,
LEX *lex, TABLE_LIST *tables_used,
uint8 *tables_type);
@ -410,6 +422,7 @@ protected:
void destroy();
friend void query_cache_init_query(NET *net);
friend void query_cache_insert(NET *net, const char *packet, ulong length);
friend void query_cache_end_of_result(THD *thd);
friend void query_cache_abort(NET *net);
@ -435,6 +448,8 @@ protected:
extern Query_cache query_cache;
extern TYPELIB query_cache_type_typelib;
void query_cache_init_query(NET *net);
void query_cache_insert(NET *net, const char *packet, ulong length);
void query_cache_end_of_result(THD *thd);
void query_cache_abort(NET *net);

View file

@ -224,7 +224,7 @@ THD::THD()
#endif
client_capabilities= 0; // minimalistic client
net.last_error[0]=0; // If error on boot
net.query_cache_query=0; // If error on boot
query_cache_init_query(&net); // If error on boot
ull=0;
system_thread= cleanup_done= abort_on_warning= no_warnings_for_error= 0;
peer_port= 0; // For SHOW PROCESSLIST

View file

@ -139,14 +139,8 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level,
}
if (thd->spcont &&
thd->spcont->find_handler(code,
((int) level >=
(int) MYSQL_ERROR::WARN_LEVEL_WARN &&
thd->really_abort_on_warning()) ?
MYSQL_ERROR::WARN_LEVEL_ERROR : level))
thd->spcont->handle_error(code, level, thd))
{
if (! thd->spcont->found_handler_here())
thd->net.report_error= 1; /* Make "select" abort correctly */
DBUG_RETURN(NULL);
}
query_cache_abort(&thd->net);

View file

@ -5787,7 +5787,6 @@ void mysql_init_multi_delete(LEX *lex)
lex->query_tables_last= &lex->query_tables;
}
/*
When you modify mysql_parse(), you may need to mofify
mysql_test_parse_for_slave() in this same file.
@ -5796,6 +5795,9 @@ void mysql_init_multi_delete(LEX *lex)
void mysql_parse(THD *thd, char *inBuf, uint length)
{
DBUG_ENTER("mysql_parse");
DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
mysql_init_query(thd, (uchar*) inBuf, length);
if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
{
@ -6690,11 +6692,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
select_errors=0; /* Write if more errors */
bool tmp_write_to_binlog= 1;
if (thd && thd->in_sub_stmt)
{
my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH");
return 1;
}
DBUG_ASSERT(!thd || !thd->in_sub_stmt);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (options & REFRESH_GRANT)
@ -7542,16 +7540,34 @@ LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
LEX_USER *get_current_user(THD *thd, LEX_USER *user)
{
LEX_USER *curr_user;
if (!user->user.str) // current_user
{
if (!(curr_user= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
{
my_error(ER_OUTOFMEMORY, MYF(0), sizeof(LEX_USER));
return 0;
}
get_default_definer(thd, curr_user);
return curr_user;
}
return create_default_definer(thd);
return user;
}
/*
Check that length of a string does not exceed some limit.
SYNOPSIS
check_string_length()
str string to be checked
err_msg error message to be displayed if the string is too long
max_length max length
RETURN
FALSE the passed string is not longer than max_length
TRUE the passed string is longer than max_length
*/
bool check_string_length(LEX_STRING *str, const char *err_msg,
uint max_length)
{
if (str->length <= max_length)
return FALSE;
my_error(ER_WRONG_STRING_LENGTH, MYF(0), str->str, err_msg, max_length);
return TRUE;
}

View file

@ -158,11 +158,13 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
{
TABLE *table;
bool result= TRUE;
LEX_STRING definer_user;
LEX_STRING definer_host;
String stmt_query;
DBUG_ENTER("mysql_create_or_drop_trigger");
/* Charset of the buffer for statement must be system one. */
stmt_query.set_charset(system_charset_info);
/*
QQ: This function could be merged in mysql_alter_table() function
But do we want this ?
@ -264,8 +266,8 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
}
result= (create ?
table->triggers->create_trigger(thd, tables, &definer_user, &definer_host):
table->triggers->drop_trigger(thd, tables));
table->triggers->create_trigger(thd, tables, &stmt_query):
table->triggers->drop_trigger(thd, tables, &stmt_query));
end:
VOID(pthread_mutex_unlock(&LOCK_open));
@ -277,32 +279,9 @@ end:
{
thd->clear_error();
String log_query(thd->query, thd->query_length, system_charset_info);
if (create)
{
log_query.set((char *) 0, 0, system_charset_info); /* reset log_query */
log_query.append(STRING_WITH_LEN("CREATE "));
if (definer_user.str && definer_host.str)
{
/*
Append definer-clause if the trigger is SUID (a usual trigger in
new MySQL versions).
*/
append_definer(thd, &log_query, &definer_user, &definer_host);
}
log_query.append(thd->lex->stmt_definition_begin,
(char *)thd->lex->sphead->m_body_begin -
thd->lex->stmt_definition_begin +
thd->lex->sphead->m_body.length);
}
/* Such a statement can always go directly to binlog, no trans cache. */
Query_log_event qinfo(thd, log_query.ptr(), log_query.length(), 0, FALSE);
Query_log_event qinfo(thd, stmt_query.ptr(), stmt_query.length(), 0,
FALSE);
mysql_bin_log.write(&qinfo);
}
@ -322,22 +301,8 @@ end:
LEX)
tables - table list containing one open table for which the
trigger is created.
definer_user - [out] after a call it points to 0-terminated string or
contains the NULL-string:
- 0-terminated is returned if the trigger is SUID. The
string contains user name part of the actual trigger
definer.
- NULL-string is returned if the trigger is non-SUID.
Anyway, the caller is responsible to provide memory for
storing LEX_STRING object.
definer_host - [out] after a call it points to 0-terminated string or
contains the NULL-string:
- 0-terminated string is returned if the trigger is
SUID. The string contains host name part of the
actual trigger definer.
- NULL-string is returned if the trigger is non-SUID.
Anyway, the caller is responsible to provide memory for
storing LEX_STRING object.
stmt_query - [OUT] after successful return, this string contains
well-formed statement for creation this trigger.
NOTE
- Assumes that trigger name is fully qualified.
@ -352,8 +317,7 @@ end:
True - error
*/
bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
LEX_STRING *definer_user,
LEX_STRING *definer_host)
String *stmt_query)
{
LEX *lex= thd->lex;
TABLE *table= tables->table;
@ -361,6 +325,8 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
trigname_path[FN_REFLEN];
LEX_STRING dir, file, trigname_file;
LEX_STRING *trg_def, *name;
LEX_STRING definer_user;
LEX_STRING definer_host;
ulonglong *trg_sql_mode;
char trg_definer_holder[USER_HOST_BUFF_SIZE];
LEX_STRING *trg_definer;
@ -508,8 +474,6 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
definers_list.push_back(trg_definer, &table->mem_root))
goto err_with_cleanup;
trg_def->str= thd->query;
trg_def->length= thd->query_length;
*trg_sql_mode= thd->variables.sql_mode;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@ -529,27 +493,54 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
{
/* SUID trigger. */
*definer_user= lex->definer->user;
*definer_host= lex->definer->host;
definer_user= lex->definer->user;
definer_host= lex->definer->host;
trg_definer->str= trg_definer_holder;
trg_definer->length= strxmov(trg_definer->str, definer_user->str, "@",
definer_host->str, NullS) - trg_definer->str;
trg_definer->length= strxmov(trg_definer->str, definer_user.str, "@",
definer_host.str, NullS) - trg_definer->str;
}
else
{
/* non-SUID trigger. */
definer_user->str= 0;
definer_user->length= 0;
definer_user.str= 0;
definer_user.length= 0;
definer_host->str= 0;
definer_host->length= 0;
definer_host.str= 0;
definer_host.length= 0;
trg_definer->str= (char*) "";
trg_definer->length= 0;
}
/*
Create well-formed trigger definition query. Original query is not
appropriated, because definer-clause can be not truncated.
*/
stmt_query->append(STRING_WITH_LEN("CREATE "));
if (trg_definer)
{
/*
Append definer-clause if the trigger is SUID (a usual trigger in
new MySQL versions).
*/
append_definer(thd, stmt_query, &definer_user, &definer_host);
}
stmt_query->append(thd->lex->stmt_definition_begin,
(char *) thd->lex->sphead->m_body_begin -
thd->lex->stmt_definition_begin +
thd->lex->sphead->m_body.length);
trg_def->str= stmt_query->c_ptr();
trg_def->length= stmt_query->length();
/* Create trigger definition file. */
if (!sql_create_definition_file(&dir, &file, &triggers_file_type,
(gptr)this, triggers_file_parameters, 0))
return 0;
@ -647,15 +638,19 @@ static bool save_trigger_file(Table_triggers_list *triggers, const char *db,
SYNOPSIS
drop_trigger()
thd - current thread context (including trigger definition in LEX)
tables - table list containing one open table for which trigger is
dropped.
thd - current thread context
(including trigger definition in LEX)
tables - table list containing one open table for which trigger
is dropped.
stmt_query - [OUT] after successful return, this string contains
well-formed statement for creation this trigger.
RETURN VALUE
False - success
True - error
*/
bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables,
String *stmt_query)
{
LEX *lex= thd->lex;
LEX_STRING *name;
@ -665,6 +660,8 @@ bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
List_iterator<LEX_STRING> it_definer(definers_list);
char path[FN_REFLEN];
stmt_query->append(thd->query, thd->query_length);
while ((name= it_name++))
{
it_def++;

View file

@ -92,10 +92,8 @@ public:
}
~Table_triggers_list();
bool create_trigger(THD *thd, TABLE_LIST *table,
LEX_STRING *definer_user,
LEX_STRING *definer_host);
bool drop_trigger(THD *thd, TABLE_LIST *table);
bool create_trigger(THD *thd, TABLE_LIST *table, String *stmt_query);
bool drop_trigger(THD *thd, TABLE_LIST *table, String *stmt_query);
bool process_triggers(THD *thd, trg_event_type event,
trg_action_time_type time_type,
bool old_row_is_record1);

View file

@ -1060,6 +1060,31 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
table->next_global= view_tables;
}
bool view_is_mergeable= (table->algorithm != VIEW_ALGORITHM_TMPTABLE &&
lex->can_be_merged());
TABLE_LIST *view_main_select_tables;
if (view_is_mergeable)
{
/*
Currently 'view_main_select_tables' differs from 'view_tables'
only then view has CONVERT_TZ() function in its select list.
This may change in future, for example if we enable merging of
views with subqueries in select list.
*/
view_main_select_tables=
(TABLE_LIST*)lex->select_lex.table_list.first;
/*
Let us set proper lock type for tables of the view's main
select since we may want to perform update or insert on
view. This won't work for view containing union. But this is
ok since we don't allow insert and update on such views
anyway.
*/
for (tbl= view_main_select_tables; tbl; tbl= tbl->next_local)
tbl->lock_type= table->lock_type;
}
/*
If we are opening this view as part of implicit LOCK TABLES, then
this view serves as simple placeholder and we should not continue
@ -1114,43 +1139,26 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
- VIEW SELECT allow merging
- VIEW used in subquery or command support MERGE algorithm
*/
if (table->algorithm != VIEW_ALGORITHM_TMPTABLE &&
lex->can_be_merged() &&
if (view_is_mergeable &&
(table->select_lex->master_unit() != &old_lex->unit ||
old_lex->can_use_merged()) &&
!old_lex->can_not_use_merged())
{
List_iterator_fast<TABLE_LIST> ti(view_select->top_join_list);
/*
Currently 'view_main_select_tables' differs from 'view_tables'
only then view has CONVERT_TZ() function in its select list.
This may change in future, for example if we enable merging
of views with subqueries in select list.
*/
TABLE_LIST *view_main_select_tables=
(TABLE_LIST*)lex->select_lex.table_list.first;
/* lex should contain at least one table */
DBUG_ASSERT(view_main_select_tables != 0);
List_iterator_fast<TABLE_LIST> ti(view_select->top_join_list);
table->effective_algorithm= VIEW_ALGORITHM_MERGE;
DBUG_PRINT("info", ("algorithm: MERGE"));
table->updatable= (table->updatable_view != 0);
table->effective_with_check=
old_lex->get_effective_with_check(table);
table->merge_underlying_list= view_main_select_tables;
/*
Let us set proper lock type for tables of the view's main select
since we may want to perform update or insert on view. This won't
work for view containing union. But this is ok since we don't
allow insert and update on such views anyway.
Also we fill correct wanted privileges.
*/
for (tbl= table->merge_underlying_list; tbl; tbl= tbl->next_local)
{
tbl->lock_type= table->lock_type;
/* Fill correct wanted privileges. */
for (tbl= view_main_select_tables; tbl; tbl= tbl->next_local)
tbl->grant.want_privilege= top_view->grant.orig_want_privilege;
}
/* prepare view context */
lex->select_lex.context.resolve_in_table_list_only(view_main_select_tables);

View file

@ -68,6 +68,34 @@ inline Item *is_truth_value(Item *A, bool v1, bool v2)
new Item_int((char *) (v1 ? "FALSE" : "TRUE"),!v1, 1));
}
#ifndef DBUG_OFF
#define YYDEBUG 1
#else
#define YYDEBUG 0
#endif
#ifndef DBUG_OFF
void turn_parser_debug_on()
{
/*
MYSQLdebug is in sql/sql_yacc.cc, in bison generated code.
Turning this option on is **VERY** verbose, and should be
used when investigating a syntax error problem only.
The syntax to run with bison traces is as follows :
- Starting a server manually :
mysqld --debug="d,parser_debug" ...
- Running a test :
mysql-test-run.pl --mysqld="--debug=d,parser_debug" ...
The result will be in the process stderr (var/log/master.err)
*/
extern int yydebug;
yydebug= 1;
}
#endif
%}
%union {
int num;
@ -6759,17 +6787,8 @@ flush:
FLUSH_SYM opt_no_write_to_binlog
{
LEX *lex=Lex;
if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE)
{
/*
Note that both FLUSH TABLES and FLUSH PRIVILEGES will break
execution in prelocked mode. So it is better to disable
FLUSH in stored functions and triggers completely.
*/
my_error(ER_STMT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0), "FLUSH");
YYABORT;
}
lex->sql_command= SQLCOM_FLUSH; lex->type=0;
lex->sql_command= SQLCOM_FLUSH;
lex->type= 0;
lex->no_write_to_binlog= $2;
}
flush_options
@ -7487,6 +7506,9 @@ user:
$$->user = $1;
$$->host.str= (char *) "%";
$$->host.length= 1;
if (check_string_length(&$$->user, ER(ER_USERNAME), USERNAME_LENGTH))
YYABORT;
}
| ident_or_text '@' ident_or_text
{
@ -7494,6 +7516,11 @@ user:
if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
YYABORT;
$$->user = $1; $$->host=$3;
if (check_string_length(&$$->user, ER(ER_USERNAME), USERNAME_LENGTH) ||
check_string_length(&$$->host, ER(ER_HOSTNAME),
HOSTNAME_LENGTH))
YYABORT;
}
| CURRENT_USER optional_braces
{
@ -8971,15 +8998,9 @@ definer:
*/
YYTHD->lex->definer= 0;
}
| DEFINER_SYM EQ CURRENT_USER optional_braces
| DEFINER_SYM EQ user
{
if (! (YYTHD->lex->definer= create_default_definer(YYTHD)))
YYABORT;
}
| DEFINER_SYM EQ ident_or_text '@' ident_or_text
{
if (!(YYTHD->lex->definer= create_definer(YYTHD, &$3, &$5)))
YYABORT;
YYTHD->lex->definer= get_current_user(YYTHD, $3);
}
;