mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-03 14:33:32 +03:00 
			
		
		
		
	Merge 10.10 into 10.11
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/CODEOWNERS
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/CODEOWNERS
									
									
									
									
										vendored
									
									
								
							@@ -1,2 +0,0 @@
 | 
				
			|||||||
/debian @ottok
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@@ -42,7 +42,7 @@ variables:
 | 
				
			|||||||
  CMAKE_FLAGS: "-DWITH_SSL=system -DPLUGIN_COLUMNSTORE=NO -DPLUGIN_ROCKSDB=NO -DPLUGIN_S3=NO -DPLUGIN_MROONGA=NO -DPLUGIN_CONNECT=NO -DPLUGIN_MROONGA=NO -DPLUGIN_TOKUDB=NO -DPLUGIN_PERFSCHEMA=NO -DWITH_WSREP=OFF"
 | 
					  CMAKE_FLAGS: "-DWITH_SSL=system -DPLUGIN_COLUMNSTORE=NO -DPLUGIN_ROCKSDB=NO -DPLUGIN_S3=NO -DPLUGIN_MROONGA=NO -DPLUGIN_CONNECT=NO -DPLUGIN_MROONGA=NO -DPLUGIN_TOKUDB=NO -DPLUGIN_PERFSCHEMA=NO -DWITH_WSREP=OFF"
 | 
				
			||||||
  # Major version dictates which branches share the same ccache. E.g. 10.6-abc
 | 
					  # Major version dictates which branches share the same ccache. E.g. 10.6-abc
 | 
				
			||||||
  # and 10.6-xyz will have the same cache.
 | 
					  # and 10.6-xyz will have the same cache.
 | 
				
			||||||
  MARIADB_MAJOR_VERSION: "10.8"
 | 
					  MARIADB_MAJOR_VERSION: "10.9"
 | 
				
			||||||
  # NOTE! Currently ccache is only used on the Centos8 build. As each job has
 | 
					  # NOTE! Currently ccache is only used on the Centos8 build. As each job has
 | 
				
			||||||
  # sufficiently different environments they are unable to benefit from each
 | 
					  # sufficiently different environments they are unable to benefit from each
 | 
				
			||||||
  # other's ccaches. As each build generates about 1 GB of ccache, having
 | 
					  # other's ccaches. As each build generates about 1 GB of ccache, having
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -297,7 +297,7 @@ ELSEIF(RPM MATCHES "sles")
 | 
				
			|||||||
ENDIF()
 | 
					ENDIF()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# MDEV-24629, we need it outside of ELSIFs
 | 
					# MDEV-24629, we need it outside of ELSIFs
 | 
				
			||||||
IF(RPM MATCHES "fedora3[234]")
 | 
					IF(RPM MATCHES "fedora")
 | 
				
			||||||
  ALTERNATIVE_NAME("common" "mariadb-connector-c-config" ${MARIADB_CONNECTOR_C_VERSION}-1)
 | 
					  ALTERNATIVE_NAME("common" "mariadb-connector-c-config" ${MARIADB_CONNECTOR_C_VERSION}-1)
 | 
				
			||||||
ENDIF()
 | 
					ENDIF()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										35
									
								
								debian/additions/innotop/innotop
									
									
									
									
										vendored
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										35
									
								
								debian/additions/innotop/innotop
									
									
									
									
										vendored
									
									
										
										
										Normal file → Executable file
									
								
							@@ -20,6 +20,9 @@
 | 
				
			|||||||
# Street, Fifth Floor, Boston, MA 02110-1335 USA
 | 
					# Street, Fifth Floor, Boston, MA 02110-1335 USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use strict;
 | 
					use strict;
 | 
				
			||||||
 | 
					use warnings;
 | 
				
			||||||
 | 
					use utf8;
 | 
				
			||||||
 | 
					use feature ':5.16';
 | 
				
			||||||
use warnings FATAL => 'all';
 | 
					use warnings FATAL => 'all';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
our $VERSION = '1.11.4';
 | 
					our $VERSION = '1.11.4';
 | 
				
			||||||
@@ -265,7 +268,7 @@ sub get_dbh {
 | 
				
			|||||||
            $dbh->do($sql);
 | 
					            $dbh->do($sql);
 | 
				
			||||||
            MKDEBUG && _d('Enabling charset for STDOUT');
 | 
					            MKDEBUG && _d('Enabling charset for STDOUT');
 | 
				
			||||||
            if ( $charset eq 'utf8' ) {
 | 
					            if ( $charset eq 'utf8' ) {
 | 
				
			||||||
               binmode(STDOUT, ':utf8')
 | 
					               binmode(STDOUT, ':encoding(UTF-8)')
 | 
				
			||||||
                  or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
 | 
					                  or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else {
 | 
					            else {
 | 
				
			||||||
@@ -612,6 +615,9 @@ sub ts_to_string {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
sub parse_innodb_timestamp {
 | 
					sub parse_innodb_timestamp {
 | 
				
			||||||
   my $text = shift;
 | 
					   my $text = shift;
 | 
				
			||||||
 | 
					   if ( ! defined $text ) {
 | 
				
			||||||
 | 
					        return (0, 0, 0, 0, 0, 0);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
   my ( $y, $m, $d, $h, $i, $s )
 | 
					   my ( $y, $m, $d, $h, $i, $s )
 | 
				
			||||||
      = $text =~ m/^(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)$/;
 | 
					      = $text =~ m/^(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)$/;
 | 
				
			||||||
   die("Can't get timestamp from $text\n") unless $y;
 | 
					   die("Can't get timestamp from $text\n") unless $y;
 | 
				
			||||||
@@ -803,7 +809,8 @@ sub parse_fk_transaction_error {
 | 
				
			|||||||
# TODO: write some tests for this
 | 
					# TODO: write some tests for this
 | 
				
			||||||
sub parse_innodb_record_dump {
 | 
					sub parse_innodb_record_dump {
 | 
				
			||||||
   my ( $dump, $complete, $debug ) = @_;
 | 
					   my ( $dump, $complete, $debug ) = @_;
 | 
				
			||||||
   return undef unless $dump;
 | 
					   # Use bare return as recommend in page 199 of PBP
 | 
				
			||||||
 | 
					   return unless $dump;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   my $result = {};
 | 
					   my $result = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6769,6 +6776,9 @@ sub set_precision {
 | 
				
			|||||||
   my ( $num, $precision ) = @_;
 | 
					   my ( $num, $precision ) = @_;
 | 
				
			||||||
   $num = 0 unless defined $num;
 | 
					   $num = 0 unless defined $num;
 | 
				
			||||||
   $precision = $config{num_digits}->{val} if !defined $precision;
 | 
					   $precision = $config{num_digits}->{val} if !defined $precision;
 | 
				
			||||||
 | 
					   if ( $num eq "" ) {
 | 
				
			||||||
 | 
					       $num = int(0);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
   sprintf("%.${precision}f", $num);
 | 
					   sprintf("%.${precision}f", $num);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6777,6 +6787,9 @@ sub set_precision {
 | 
				
			|||||||
sub percent {
 | 
					sub percent {
 | 
				
			||||||
   my ( $num ) = @_;
 | 
					   my ( $num ) = @_;
 | 
				
			||||||
   $num = 0 unless defined $num;
 | 
					   $num = 0 unless defined $num;
 | 
				
			||||||
 | 
					   if ( $num eq "" ) {
 | 
				
			||||||
 | 
					       $num = int(0);
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
   my $digits = $config{num_digits}->{val};
 | 
					   my $digits = $config{num_digits}->{val};
 | 
				
			||||||
   return sprintf("%.${digits}f", $num * 100)
 | 
					   return sprintf("%.${digits}f", $num * 100)
 | 
				
			||||||
      . ($config{show_percent}->{val} ? '%' : '');
 | 
					      . ($config{show_percent}->{val} ? '%' : '');
 | 
				
			||||||
@@ -6841,7 +6854,7 @@ sub make_color_func {
 | 
				
			|||||||
      push @criteria,
 | 
					      push @criteria,
 | 
				
			||||||
         "( defined \$set->{$spec->{col}} && \$set->{$spec->{col}} $spec->{op} $val ) { return '$spec->{color}'; }";
 | 
					         "( defined \$set->{$spec->{col}} && \$set->{$spec->{col}} $spec->{op} $val ) { return '$spec->{color}'; }";
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
   return undef unless @criteria;
 | 
					   return unless @criteria;
 | 
				
			||||||
   my $sub = eval 'sub { my ( $set ) = @_; if ' . join(" elsif ", @criteria) . '}';
 | 
					   my $sub = eval 'sub { my ( $set ) = @_; if ' . join(" elsif ", @criteria) . '}';
 | 
				
			||||||
   die if $EVAL_ERROR;
 | 
					   die if $EVAL_ERROR;
 | 
				
			||||||
   return $sub;
 | 
					   return $sub;
 | 
				
			||||||
@@ -7521,10 +7534,10 @@ sub choose_connections {
 | 
				
			|||||||
sub do_stmt {
 | 
					sub do_stmt {
 | 
				
			||||||
   my ( $cxn, $stmt_name, @args ) = @_;
 | 
					   my ( $cxn, $stmt_name, @args ) = @_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   return undef if $file;
 | 
					   return if $file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   # Test if the cxn should not even be tried
 | 
					   # Test if the cxn should not even be tried
 | 
				
			||||||
   return undef if $dbhs{$cxn}
 | 
					   return if $dbhs{$cxn}
 | 
				
			||||||
      && $dbhs{$cxn}->{failed}
 | 
					      && $dbhs{$cxn}->{failed}
 | 
				
			||||||
      && ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} );
 | 
					      && ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -7596,10 +7609,10 @@ sub handle_cxn_error {
 | 
				
			|||||||
sub do_query {
 | 
					sub do_query {
 | 
				
			||||||
   my ( $cxn, $query ) = @_;
 | 
					   my ( $cxn, $query ) = @_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   return undef if $file;
 | 
					   return if $file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   # Test if the cxn should not even be tried
 | 
					   # Test if the cxn should not even be tried
 | 
				
			||||||
   return undef if $dbhs{$cxn}
 | 
					   return if $dbhs{$cxn}
 | 
				
			||||||
      && $dbhs{$cxn}->{failed}
 | 
					      && $dbhs{$cxn}->{failed}
 | 
				
			||||||
      && ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} );
 | 
					      && ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -7781,7 +7794,7 @@ sub compile_select_stmt {
 | 
				
			|||||||
sub compile_filter {
 | 
					sub compile_filter {
 | 
				
			||||||
   my ( $text ) = @_;
 | 
					   my ( $text ) = @_;
 | 
				
			||||||
   my ( $sub, $err );
 | 
					   my ( $sub, $err );
 | 
				
			||||||
   eval "\$sub = sub { my \$set = shift; $text }";
 | 
					   eval { $sub = sub { my $set = shift; $text } };
 | 
				
			||||||
   if ( $EVAL_ERROR ) {
 | 
					   if ( $EVAL_ERROR ) {
 | 
				
			||||||
      $EVAL_ERROR =~ s/at \(eval.*$//;
 | 
					      $EVAL_ERROR =~ s/at \(eval.*$//;
 | 
				
			||||||
      $sub = sub { return $EVAL_ERROR };
 | 
					      $sub = sub { return $EVAL_ERROR };
 | 
				
			||||||
@@ -8013,7 +8026,7 @@ sub load_config_plugins {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
   # First, find a list of all plugins that exist on disk, and get information about them.
 | 
					   # First, find a list of all plugins that exist on disk, and get information about them.
 | 
				
			||||||
   my $dir = $config{plugin_dir}->{val};
 | 
					   my $dir = $config{plugin_dir}->{val};
 | 
				
			||||||
   foreach my $p_file ( <$dir/*.pm> ) {
 | 
					   foreach my $p_file (glob($dir."/*.pm")) {
 | 
				
			||||||
      my ($package, $desc);
 | 
					      my ($package, $desc);
 | 
				
			||||||
      eval {
 | 
					      eval {
 | 
				
			||||||
         open my $p_in, "<", $p_file or die $OS_ERROR;
 | 
					         open my $p_in, "<", $p_file or die $OS_ERROR;
 | 
				
			||||||
@@ -9192,7 +9205,7 @@ sub switch_var_set {
 | 
				
			|||||||
# edit_stmt_sleep_times {{{3
 | 
					# edit_stmt_sleep_times {{{3
 | 
				
			||||||
sub edit_stmt_sleep_times {
 | 
					sub edit_stmt_sleep_times {
 | 
				
			||||||
   $clear_screen_sub->();
 | 
					   $clear_screen_sub->();
 | 
				
			||||||
   my $stmt = prompt_list('Specify a statement', '', sub { return sort keys %stmt_maker_for });
 | 
					   my $stmt = prompt_list('Specify a statement', '', sub { my @tmparray = sort keys %stmt_maker_for; return @tmparray });
 | 
				
			||||||
   return unless $stmt && exists $stmt_maker_for{$stmt};
 | 
					   return unless $stmt && exists $stmt_maker_for{$stmt};
 | 
				
			||||||
   $clear_screen_sub->();
 | 
					   $clear_screen_sub->();
 | 
				
			||||||
   my $curr_val = $stmt_sleep_time_for{$stmt} || 0;
 | 
					   my $curr_val = $stmt_sleep_time_for{$stmt} || 0;
 | 
				
			||||||
@@ -9843,7 +9856,7 @@ sub get_slave_status {
 | 
				
			|||||||
sub is_func {
 | 
					sub is_func {
 | 
				
			||||||
   my ( $word ) = @_;
 | 
					   my ( $word ) = @_;
 | 
				
			||||||
   return defined(&$word)
 | 
					   return defined(&$word)
 | 
				
			||||||
      || eval "my \$x= sub { $word  }; 1"
 | 
					      || eval { my $x = sub { $word  }; 1 }
 | 
				
			||||||
      || $EVAL_ERROR !~ m/^Bareword/;
 | 
					      || $EVAL_ERROR !~ m/^Bareword/;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								debian/mariadb-server.mariadb.init
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								debian/mariadb-server.mariadb.init
									
									
									
									
										vendored
									
									
								
							@@ -86,7 +86,7 @@ sanity_checks() {
 | 
				
			|||||||
  datadir=`mariadbd_get_param datadir`
 | 
					  datadir=`mariadbd_get_param datadir`
 | 
				
			||||||
  # As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024
 | 
					  # As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024
 | 
				
			||||||
  # 4096 blocks is then lower than 4 MB
 | 
					  # 4096 blocks is then lower than 4 MB
 | 
				
			||||||
  df_available_blocks=`LC_ALL=C BLOCKSIZE= df --output=avail "$datadir" | tail -n 1`
 | 
					  df_available_blocks="$(LC_ALL=C BLOCKSIZE='' df --output=avail "$datadir" | tail -n 1)"
 | 
				
			||||||
  if [ "$df_available_blocks" -lt "4096" ]; then
 | 
					  if [ "$df_available_blocks" -lt "4096" ]; then
 | 
				
			||||||
    log_failure_msg "$0: ERROR: The partition with $datadir is too full!"
 | 
					    log_failure_msg "$0: ERROR: The partition with $datadir is too full!"
 | 
				
			||||||
    echo                "ERROR: The partition with $datadir is too full!" | $ERR_LOGGER
 | 
					    echo                "ERROR: The partition with $datadir is too full!" | $ERR_LOGGER
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								debian/mariadb-server.preinst
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								debian/mariadb-server.preinst
									
									
									
									
										vendored
									
									
								
							@@ -223,15 +223,24 @@ then
 | 
				
			|||||||
  mkdir -Z $mysql_datadir
 | 
					  mkdir -Z $mysql_datadir
 | 
				
			||||||
fi
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Check if MariaDB datadir is available if not fails.
 | 
				
			||||||
 | 
					# There should be symlink or directory available or something will fail.
 | 
				
			||||||
 | 
					if [ -d "$mysql_datadir" ] || [ -L "$mysql_datadir" ]
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
    # As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024
 | 
					    # As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024
 | 
				
			||||||
    # 4096 blocks is then lower than 4 MB
 | 
					    # 4096 blocks is then lower than 4 MB
 | 
				
			||||||
df_available_blocks=`LC_ALL=C BLOCKSIZE= df --output=avail "$datadir" | tail -n 1`
 | 
					    df_available_blocks="$(LC_ALL=C BLOCKSIZE='' df --output=avail "$mysql_datadir" | tail -n 1)"
 | 
				
			||||||
    if [ "$df_available_blocks" -lt "4096" ]
 | 
					    if [ "$df_available_blocks" -lt "4096" ]
 | 
				
			||||||
    then
 | 
					    then
 | 
				
			||||||
      echo "ERROR: There's not enough space in $mysql_datadir/" 1>&2
 | 
					      echo "ERROR: There's not enough space in $mysql_datadir/" 1>&2
 | 
				
			||||||
      db_stop
 | 
					      db_stop
 | 
				
			||||||
      exit 1
 | 
					      exit 1
 | 
				
			||||||
    fi
 | 
					    fi
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					    echo "ERROR: There's no directory or symlink available: $mysql_datadir/" 1>&2
 | 
				
			||||||
 | 
					    db_stop
 | 
				
			||||||
 | 
					    exit 1    
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Since the home directory was created before putting the user into
 | 
					# Since the home directory was created before putting the user into
 | 
				
			||||||
# the mysql group and moreover we cannot guarantee that the
 | 
					# the mysql group and moreover we cannot guarantee that the
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -847,26 +847,48 @@ void mdl_lock_all()
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Convert non-null terminated filename to space name
 | 
					// Convert non-null terminated filename to space name
 | 
				
			||||||
 | 
					// Note that in 10.6 the filename may be an undo file name
 | 
				
			||||||
static std::string filename_to_spacename(const void *filename, size_t len)
 | 
					static std::string filename_to_spacename(const void *filename, size_t len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// null- terminate filename
 | 
					  char f[FN_REFLEN];
 | 
				
			||||||
	char *f = (char *)malloc(len + 1);
 | 
					  char *p= 0, *table, *db;
 | 
				
			||||||
	ut_a(f);
 | 
					  DBUG_ASSERT(len < FN_REFLEN);
 | 
				
			||||||
	memcpy(f, filename, len);
 | 
					
 | 
				
			||||||
	f[len] = 0;
 | 
					  strmake(f, (const char*) filename, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _WIN32
 | 
				
			||||||
  for (size_t i = 0; i < len; i++)
 | 
					  for (size_t i = 0; i < len; i++)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    if (f[i] == '\\')
 | 
					    if (f[i] == '\\')
 | 
				
			||||||
      f[i] = '/';
 | 
					      f[i] = '/';
 | 
				
			||||||
	char *p = strrchr(f, '.');
 | 
					  }
 | 
				
			||||||
	ut_a(p);
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Remove extension, if exists */
 | 
				
			||||||
 | 
					  if (!(p= strrchr(f, '.')))
 | 
				
			||||||
 | 
					    goto err;
 | 
				
			||||||
  *p= 0;
 | 
					  *p= 0;
 | 
				
			||||||
	char *table = strrchr(f, '/');
 | 
					
 | 
				
			||||||
	ut_a(table);
 | 
					  /* Find table name */
 | 
				
			||||||
 | 
					  if (!(table= strrchr(f, '/')))
 | 
				
			||||||
 | 
					    goto err;
 | 
				
			||||||
  *table = 0;
 | 
					  *table = 0;
 | 
				
			||||||
	char *db = strrchr(f, '/');
 | 
					
 | 
				
			||||||
 | 
					  /* Find database name */
 | 
				
			||||||
 | 
					  db= strrchr(f, '/');
 | 
				
			||||||
  *table = '/';
 | 
					  *table = '/';
 | 
				
			||||||
	std::string s(db ? db+1 : f);
 | 
					  if (!db)
 | 
				
			||||||
	free(f);
 | 
					    goto err;
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    std::string s(db+1);
 | 
				
			||||||
 | 
					    return s;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
					  /* Not a database/table. Return original (converted) name */
 | 
				
			||||||
 | 
					  if (p)
 | 
				
			||||||
 | 
					    *p= '.';                                    // Restore removed extension
 | 
				
			||||||
 | 
					  std::string s(f);
 | 
				
			||||||
  return s;
 | 
					  return s;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3146,7 +3168,7 @@ static bool xtrabackup_copy_logfile()
 | 
				
			|||||||
      if (log_sys.buf[recv_sys.offset] <= 1)
 | 
					      if (log_sys.buf[recv_sys.offset] <= 1)
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (recv_sys.parse_mtr(STORE_NO) == recv_sys_t::OK)
 | 
					      if (recv_sys.parse_mtr<false>(false) == recv_sys_t::OK)
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        do
 | 
					        do
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -3156,7 +3178,7 @@ static bool xtrabackup_copy_logfile()
 | 
				
			|||||||
                                                 sequence_offset));
 | 
					                                                 sequence_offset));
 | 
				
			||||||
          *seq= 1;
 | 
					          *seq= 1;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        while ((r= recv_sys.parse_mtr(STORE_NO)) == recv_sys_t::OK);
 | 
					        while ((r= recv_sys.parse_mtr<false>(false)) == recv_sys_t::OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (ds_write(dst_log_file, log_sys.buf + start_offset,
 | 
					        if (ds_write(dst_log_file, log_sys.buf + start_offset,
 | 
				
			||||||
                     recv_sys.offset - start_offset))
 | 
					                     recv_sys.offset - start_offset))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -249,14 +249,15 @@ static inline void lex_string_set3(LEX_CSTRING *lex_str, const char *c_str,
 | 
				
			|||||||
*/
 | 
					*/
 | 
				
			||||||
static inline int safe_strcpy(char *dst, size_t dst_size, const char *src)
 | 
					static inline int safe_strcpy(char *dst, size_t dst_size, const char *src)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  memset(dst, '\0', dst_size);
 | 
					  DBUG_ASSERT(dst_size > 0);
 | 
				
			||||||
  strncpy(dst, src, dst_size - 1);
 | 
					  /* Note, strncpy will zerofill end of dst if src shorter than dst_size */
 | 
				
			||||||
  /*
 | 
					  strncpy(dst, src, dst_size);
 | 
				
			||||||
     If the first condition is true, we are guaranteed to have src length
 | 
					  if (dst[dst_size-1])
 | 
				
			||||||
     >= (dst_size - 1), hence safe to access src[dst_size - 1].
 | 
					  {
 | 
				
			||||||
  */
 | 
					    /* Ensure string is zero terminated */
 | 
				
			||||||
  if (dst[dst_size - 2] != '\0' && src[dst_size - 1] != '\0')
 | 
					    dst[dst_size-1]= 0;
 | 
				
			||||||
    return 1; /* Truncation of src. */
 | 
					    return 1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  return 0;
 | 
					  return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -71,6 +71,7 @@ typedef struct st_myrg_info
 | 
				
			|||||||
  ulong  cache_size;
 | 
					  ulong  cache_size;
 | 
				
			||||||
  uint	 merge_insert_method;
 | 
					  uint	 merge_insert_method;
 | 
				
			||||||
  uint	 tables,options,reclength,keys;
 | 
					  uint	 tables,options,reclength,keys;
 | 
				
			||||||
 | 
					  uint   key_parts;
 | 
				
			||||||
  my_bool cache_in_use;
 | 
					  my_bool cache_in_use;
 | 
				
			||||||
  /* If MERGE children attached to parent. See top comment in ha_myisammrg.cc */
 | 
					  /* If MERGE children attached to parent. See top comment in ha_myisammrg.cc */
 | 
				
			||||||
  my_bool children_attached;
 | 
					  my_bool children_attached;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,6 +57,7 @@ extern struct wsrep_service_st {
 | 
				
			|||||||
  my_bool                     (*wsrep_on_func)(const MYSQL_THD thd);
 | 
					  my_bool                     (*wsrep_on_func)(const MYSQL_THD thd);
 | 
				
			||||||
  bool                        (*wsrep_prepare_key_for_innodb_func)(MYSQL_THD thd, const unsigned char*, size_t, const unsigned char*, size_t, struct wsrep_buf*, size_t*);
 | 
					  bool                        (*wsrep_prepare_key_for_innodb_func)(MYSQL_THD thd, const unsigned char*, size_t, const unsigned char*, size_t, struct wsrep_buf*, size_t*);
 | 
				
			||||||
  void                        (*wsrep_thd_LOCK_func)(const MYSQL_THD thd);
 | 
					  void                        (*wsrep_thd_LOCK_func)(const MYSQL_THD thd);
 | 
				
			||||||
 | 
					  int                         (*wsrep_thd_TRYLOCK_func)(const MYSQL_THD thd);
 | 
				
			||||||
  void                        (*wsrep_thd_UNLOCK_func)(const MYSQL_THD thd);
 | 
					  void                        (*wsrep_thd_UNLOCK_func)(const MYSQL_THD thd);
 | 
				
			||||||
  const char *                (*wsrep_thd_query_func)(const MYSQL_THD thd);
 | 
					  const char *                (*wsrep_thd_query_func)(const MYSQL_THD thd);
 | 
				
			||||||
  int                         (*wsrep_thd_retry_counter_func)(const MYSQL_THD thd);
 | 
					  int                         (*wsrep_thd_retry_counter_func)(const MYSQL_THD thd);
 | 
				
			||||||
@@ -89,7 +90,6 @@ extern struct wsrep_service_st {
 | 
				
			|||||||
  ulong                       (*wsrep_OSU_method_get_func)(const MYSQL_THD thd);
 | 
					  ulong                       (*wsrep_OSU_method_get_func)(const MYSQL_THD thd);
 | 
				
			||||||
  my_bool                     (*wsrep_thd_has_ignored_error_func)(const MYSQL_THD thd);
 | 
					  my_bool                     (*wsrep_thd_has_ignored_error_func)(const MYSQL_THD thd);
 | 
				
			||||||
  void                        (*wsrep_thd_set_ignored_error_func)(MYSQL_THD thd, my_bool val);
 | 
					  void                        (*wsrep_thd_set_ignored_error_func)(MYSQL_THD thd, my_bool val);
 | 
				
			||||||
  bool                        (*wsrep_thd_set_wsrep_aborter_func)(MYSQL_THD bf_thd, MYSQL_THD thd);
 | 
					 | 
				
			||||||
  void                        (*wsrep_report_bf_lock_wait_func)(const MYSQL_THD thd,
 | 
					  void                        (*wsrep_report_bf_lock_wait_func)(const MYSQL_THD thd,
 | 
				
			||||||
                                                                unsigned long long trx_id);
 | 
					                                                                unsigned long long trx_id);
 | 
				
			||||||
  void                        (*wsrep_thd_kill_LOCK_func)(const MYSQL_THD thd);
 | 
					  void                        (*wsrep_thd_kill_LOCK_func)(const MYSQL_THD thd);
 | 
				
			||||||
@@ -111,6 +111,7 @@ extern struct wsrep_service_st {
 | 
				
			|||||||
#define wsrep_on(thd) (thd) && WSREP_ON && wsrep_service->wsrep_on_func(thd)
 | 
					#define wsrep_on(thd) (thd) && WSREP_ON && wsrep_service->wsrep_on_func(thd)
 | 
				
			||||||
#define wsrep_prepare_key_for_innodb(A,B,C,D,E,F,G) wsrep_service->wsrep_prepare_key_for_innodb_func(A,B,C,D,E,F,G)
 | 
					#define wsrep_prepare_key_for_innodb(A,B,C,D,E,F,G) wsrep_service->wsrep_prepare_key_for_innodb_func(A,B,C,D,E,F,G)
 | 
				
			||||||
#define wsrep_thd_LOCK(T) wsrep_service->wsrep_thd_LOCK_func(T)
 | 
					#define wsrep_thd_LOCK(T) wsrep_service->wsrep_thd_LOCK_func(T)
 | 
				
			||||||
 | 
					#define wsrep_thd_TRYLOCK(T) wsrep_service->wsrep_thd_TRYLOCK_func(T)
 | 
				
			||||||
#define wsrep_thd_UNLOCK(T) wsrep_service->wsrep_thd_UNLOCK_func(T)
 | 
					#define wsrep_thd_UNLOCK(T) wsrep_service->wsrep_thd_UNLOCK_func(T)
 | 
				
			||||||
#define wsrep_thd_kill_LOCK(T) wsrep_service->wsrep_thd_kill_LOCK_func(T)
 | 
					#define wsrep_thd_kill_LOCK(T) wsrep_service->wsrep_thd_kill_LOCK_func(T)
 | 
				
			||||||
#define wsrep_thd_kill_UNLOCK(T) wsrep_service->wsrep_thd_kill_UNLOCK_func(T)
 | 
					#define wsrep_thd_kill_UNLOCK(T) wsrep_service->wsrep_thd_kill_UNLOCK_func(T)
 | 
				
			||||||
@@ -141,7 +142,6 @@ extern struct wsrep_service_st {
 | 
				
			|||||||
#define wsrep_OSU_method_get(T) wsrep_service->wsrep_OSU_method_get_func(T)
 | 
					#define wsrep_OSU_method_get(T) wsrep_service->wsrep_OSU_method_get_func(T)
 | 
				
			||||||
#define wsrep_thd_has_ignored_error(T) wsrep_service->wsrep_thd_has_ignored_error_func(T)
 | 
					#define wsrep_thd_has_ignored_error(T) wsrep_service->wsrep_thd_has_ignored_error_func(T)
 | 
				
			||||||
#define wsrep_thd_set_ignored_error(T,V) wsrep_service->wsrep_thd_set_ignored_error_func(T,V)
 | 
					#define wsrep_thd_set_ignored_error(T,V) wsrep_service->wsrep_thd_set_ignored_error_func(T,V)
 | 
				
			||||||
#define wsrep_thd_set_wsrep_aborter(T) wsrep_service->wsrep_thd_set_wsrep_aborter_func(T1, T2)
 | 
					 | 
				
			||||||
#define wsrep_report_bf_lock_wait(T,I) wsrep_service->wsrep_report_bf_lock_wait(T,I)
 | 
					#define wsrep_report_bf_lock_wait(T,I) wsrep_service->wsrep_report_bf_lock_wait(T,I)
 | 
				
			||||||
#define wsrep_thd_set_PA_unsafe(T) wsrep_service->wsrep_thd_set_PA_unsafe_func(T)
 | 
					#define wsrep_thd_set_PA_unsafe(T) wsrep_service->wsrep_thd_set_PA_unsafe_func(T)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
@@ -175,6 +175,8 @@ void wsrep_set_data_home_dir(const char *data_dir);
 | 
				
			|||||||
extern "C" my_bool wsrep_on(const MYSQL_THD thd);
 | 
					extern "C" my_bool wsrep_on(const MYSQL_THD thd);
 | 
				
			||||||
/* Lock thd wsrep lock */
 | 
					/* Lock thd wsrep lock */
 | 
				
			||||||
extern "C" void wsrep_thd_LOCK(const MYSQL_THD thd);
 | 
					extern "C" void wsrep_thd_LOCK(const MYSQL_THD thd);
 | 
				
			||||||
 | 
					/* Try thd wsrep lock. Return non-zero if lock could not be taken. */
 | 
				
			||||||
 | 
					extern "C" int wsrep_thd_TRYLOCK(const MYSQL_THD thd);
 | 
				
			||||||
/* Unlock thd wsrep lock */
 | 
					/* Unlock thd wsrep lock */
 | 
				
			||||||
extern "C" void wsrep_thd_UNLOCK(const MYSQL_THD thd);
 | 
					extern "C" void wsrep_thd_UNLOCK(const MYSQL_THD thd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -197,8 +199,6 @@ extern "C" my_bool wsrep_thd_is_local(const MYSQL_THD thd);
 | 
				
			|||||||
/* Return true if thd is in high priority mode */
 | 
					/* Return true if thd is in high priority mode */
 | 
				
			||||||
/* todo: rename to is_high_priority() */
 | 
					/* todo: rename to is_high_priority() */
 | 
				
			||||||
extern "C" my_bool wsrep_thd_is_applying(const MYSQL_THD thd);
 | 
					extern "C" my_bool wsrep_thd_is_applying(const MYSQL_THD thd);
 | 
				
			||||||
/* set wsrep_aborter for the target THD */
 | 
					 | 
				
			||||||
extern "C" bool wsrep_thd_set_wsrep_aborter(MYSQL_THD bf_thd, MYSQL_THD victim_thd);
 | 
					 | 
				
			||||||
/* Return true if thd is in TOI mode */
 | 
					/* Return true if thd is in TOI mode */
 | 
				
			||||||
extern "C" my_bool wsrep_thd_is_toi(const MYSQL_THD thd);
 | 
					extern "C" my_bool wsrep_thd_is_toi(const MYSQL_THD thd);
 | 
				
			||||||
/* Return true if thd is in replicating TOI mode */
 | 
					/* Return true if thd is in replicating TOI mode */
 | 
				
			||||||
@@ -249,7 +249,6 @@ extern "C" my_bool wsrep_thd_is_applying(const MYSQL_THD thd);
 | 
				
			|||||||
extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd);
 | 
					extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd);
 | 
				
			||||||
extern "C" my_bool wsrep_thd_has_ignored_error(const MYSQL_THD thd);
 | 
					extern "C" my_bool wsrep_thd_has_ignored_error(const MYSQL_THD thd);
 | 
				
			||||||
extern "C" void wsrep_thd_set_ignored_error(MYSQL_THD thd, my_bool val);
 | 
					extern "C" void wsrep_thd_set_ignored_error(MYSQL_THD thd, my_bool val);
 | 
				
			||||||
extern "C" bool wsrep_thd_set_wsrep_aborter(MYSQL_THD bf_thd, MYSQL_THD victim_thd);
 | 
					 | 
				
			||||||
extern "C" void wsrep_report_bf_lock_wait(const THD *thd,
 | 
					extern "C" void wsrep_report_bf_lock_wait(const THD *thd,
 | 
				
			||||||
                                          unsigned long long trx_id);
 | 
					                                          unsigned long long trx_id);
 | 
				
			||||||
/* declare parallel applying unsafety for the THD */
 | 
					/* declare parallel applying unsafety for the THD */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@ use strict;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
use Exporter;
 | 
					use Exporter;
 | 
				
			||||||
use base "Exporter";
 | 
					use base "Exporter";
 | 
				
			||||||
our @EXPORT= qw /rmtree mkpath copytree/;
 | 
					our @EXPORT= qw /rmtree mkpath copytree make_readonly/;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use File::Find;
 | 
					use File::Find;
 | 
				
			||||||
use File::Copy;
 | 
					use File::Copy;
 | 
				
			||||||
@@ -184,6 +184,10 @@ sub copytree {
 | 
				
			|||||||
    # Only copy plain files
 | 
					    # Only copy plain files
 | 
				
			||||||
    next unless -f "$from_dir/$_";
 | 
					    next unless -f "$from_dir/$_";
 | 
				
			||||||
    copy("$from_dir/$_", "$to_dir/$_");
 | 
					    copy("$from_dir/$_", "$to_dir/$_");
 | 
				
			||||||
 | 
					    if (!$use_umask)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      chmod(0666, "$to_dir/$_");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  closedir(DIR);
 | 
					  closedir(DIR);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -193,4 +197,29 @@ sub copytree {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sub make_readonly {
 | 
				
			||||||
 | 
					  my ($dir) = @_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  die "Usage: make_readonly(<dir>])"
 | 
				
			||||||
 | 
					    unless @_ == 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  opendir(DIR, "$dir")
 | 
				
			||||||
 | 
					    or croak("Can't find $dir$!");
 | 
				
			||||||
 | 
					  for(readdir(DIR)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    next if "$_" eq "." or "$_" eq "..";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ( -d "$dir/$_" )
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      make_readonly("$dir/$_");
 | 
				
			||||||
 | 
					      next;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Only copy plain files
 | 
				
			||||||
 | 
					    next unless -f "$dir/$_";
 | 
				
			||||||
 | 
					    chmod 0444, "$dir/$_";
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  closedir(DIR);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
1;
 | 
					1;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -40,7 +40,7 @@ our @EXPORT= qw(create_process);
 | 
				
			|||||||
#   Retry a couple of times if fork returns EAGAIN
 | 
					#   Retry a couple of times if fork returns EAGAIN
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
sub _safe_fork {
 | 
					sub _safe_fork {
 | 
				
			||||||
  my $retries= 5;
 | 
					  my $retries= 100;
 | 
				
			||||||
  my $pid;
 | 
					  my $pid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 FORK:
 | 
					 FORK:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1157,3 +1157,28 @@ explain select * from t1 limit 0 offset 10;
 | 
				
			|||||||
id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
					id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			||||||
1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Zero limit
 | 
					1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Zero limit
 | 
				
			||||||
drop table t1, t2;
 | 
					drop table t1, t2;
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# MDEV-28285 Unexpected result when combining DISTINCT, subselect
 | 
				
			||||||
 | 
					# and LIMIT
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					create table t1 (a int primary key);
 | 
				
			||||||
 | 
					create table t2 (a int primary key, b int not null);
 | 
				
			||||||
 | 
					insert into t1 select seq from seq_1_to_10;
 | 
				
			||||||
 | 
					insert into t2 select seq,seq from seq_1_to_10;
 | 
				
			||||||
 | 
					select distinct a from t1 where t1.a=1 and t1.a in (select a from t2 where t2.b in (1,2));
 | 
				
			||||||
 | 
					a
 | 
				
			||||||
 | 
					1
 | 
				
			||||||
 | 
					explain select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 10,10;
 | 
				
			||||||
 | 
					id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			||||||
 | 
					1	PRIMARY	t1	const	PRIMARY	PRIMARY	4	const	1	Using index; Using temporary
 | 
				
			||||||
 | 
					1	PRIMARY	<subquery2>	eq_ref	distinct_key	distinct_key	8	func	1	
 | 
				
			||||||
 | 
					2	MATERIALIZED	t2	ALL	NULL	NULL	NULL	NULL	10	Using where
 | 
				
			||||||
 | 
					select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 10,10;
 | 
				
			||||||
 | 
					a
 | 
				
			||||||
 | 
					select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 0,1;
 | 
				
			||||||
 | 
					a
 | 
				
			||||||
 | 
					1
 | 
				
			||||||
 | 
					drop table t1,t2;
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# end of 10.5 tests
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -892,3 +892,24 @@ explain select * from t1 limit 0;
 | 
				
			|||||||
explain select * from t1 limit 0 offset 10;
 | 
					explain select * from t1 limit 0 offset 10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
drop table t1, t2;
 | 
					drop table t1, t2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # MDEV-28285 Unexpected result when combining DISTINCT, subselect
 | 
				
			||||||
 | 
					--echo # and LIMIT
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create table t1 (a int primary key);
 | 
				
			||||||
 | 
					create table t2 (a int primary key, b int not null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into t1 select seq from seq_1_to_10;
 | 
				
			||||||
 | 
					insert into t2 select seq,seq from seq_1_to_10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select distinct a from t1 where t1.a=1 and t1.a in (select a from t2 where t2.b in (1,2));
 | 
				
			||||||
 | 
					explain select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 10,10;
 | 
				
			||||||
 | 
					select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 10,10;
 | 
				
			||||||
 | 
					select distinct a from t1 where t1.a=1 and t1.a in (select a+0 from t2 where t2.b in (1,2)) limit 0,1;
 | 
				
			||||||
 | 
					drop table t1,t2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # end of 10.5 tests
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2578,5 +2578,29 @@ SELECT JSON_EXTRACT('{ "my-key": 1 }', '$.my-key');
 | 
				
			|||||||
JSON_EXTRACT('{ "my-key": 1 }', '$.my-key')
 | 
					JSON_EXTRACT('{ "my-key": 1 }', '$.my-key')
 | 
				
			||||||
1
 | 
					1
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					# MDEV-23187: Assorted assertion failures in json_find_path with certain collations
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					SET @save_collation_connection= @@collation_connection;
 | 
				
			||||||
 | 
					SET @json='{ "A": [ [{"k":"v"},[1]],true],"B": {"C": 1} }';
 | 
				
			||||||
 | 
					SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
 | 
				
			||||||
 | 
					JSON_VALUE(@json,'$.A[last-1][last-1].key1')
 | 
				
			||||||
 | 
					NULL
 | 
				
			||||||
 | 
					SET @json='{ "A": [ [{"k":"v"},[1]],true],"B": {"C": 1} }';
 | 
				
			||||||
 | 
					SET collation_connection='ucs2_bin';
 | 
				
			||||||
 | 
					SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
 | 
				
			||||||
 | 
					JSON_VALUE(@json,'$.A[last-1][last-1].key1')
 | 
				
			||||||
 | 
					NULL
 | 
				
			||||||
 | 
					SET @json='{ "A": [ [{"k":"v"},[15]],true],"B": {"C": 1} }';
 | 
				
			||||||
 | 
					SET sql_mode=0,character_set_connection=utf32;
 | 
				
			||||||
 | 
					SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
 | 
				
			||||||
 | 
					JSON_VALUE(@json,'$.A[last-1][last-1].key1')
 | 
				
			||||||
 | 
					NULL
 | 
				
			||||||
 | 
					SET @json='{ "A": [ [{"k":"v"},[15]],true],"B": {"C": 1} }';
 | 
				
			||||||
 | 
					SET sql_mode=0,character_set_connection=utf32;
 | 
				
			||||||
 | 
					SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
 | 
				
			||||||
 | 
					JSON_VALUE(@json,'$.A[last-1][last-1].key1')
 | 
				
			||||||
 | 
					NULL
 | 
				
			||||||
 | 
					SET @@collation_connection= @save_collation_connection;
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
# End of 10.9 Test
 | 
					# End of 10.9 Test
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1772,6 +1772,32 @@ DROP TABLE t1;
 | 
				
			|||||||
SELECT JSON_EXTRACT('{ "my-key": 1 }', '$."my-key"');
 | 
					SELECT JSON_EXTRACT('{ "my-key": 1 }', '$."my-key"');
 | 
				
			||||||
SELECT JSON_EXTRACT('{ "my-key": 1 }', '$.my-key');
 | 
					SELECT JSON_EXTRACT('{ "my-key": 1 }', '$.my-key');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # MDEV-23187: Assorted assertion failures in json_find_path with certain collations
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET @save_collation_connection= @@collation_connection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET @json='{ "A": [ [{"k":"v"},[1]],true],"B": {"C": 1} }';
 | 
				
			||||||
 | 
					SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET @json='{ "A": [ [{"k":"v"},[1]],true],"B": {"C": 1} }';
 | 
				
			||||||
 | 
					SET collation_connection='ucs2_bin';
 | 
				
			||||||
 | 
					SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET @json='{ "A": [ [{"k":"v"},[15]],true],"B": {"C": 1} }';
 | 
				
			||||||
 | 
					SET sql_mode=0,character_set_connection=utf32;
 | 
				
			||||||
 | 
					SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET @json='{ "A": [ [{"k":"v"},[15]],true],"B": {"C": 1} }';
 | 
				
			||||||
 | 
					SET sql_mode=0,character_set_connection=utf32;
 | 
				
			||||||
 | 
					SELECT JSON_VALUE(@json,'$.A[last-1][last-1].key1');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET @@collation_connection= @save_collation_connection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--echo #
 | 
					--echo #
 | 
				
			||||||
--echo # End of 10.9 Test
 | 
					--echo # End of 10.9 Test
 | 
				
			||||||
--echo #
 | 
					--echo #
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4095,6 +4095,116 @@ MIN(pk)	a
 | 
				
			|||||||
5	10
 | 
					5	10
 | 
				
			||||||
DROP TABLE t1;
 | 
					DROP TABLE t1;
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					# MDEV-6768 Wrong result with agregate with join with no resultset
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					create table t1
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					PARENT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
 | 
				
			||||||
 | 
					PARENT_FIELD VARCHAR(10),
 | 
				
			||||||
 | 
					PRIMARY KEY (PARENT_ID)
 | 
				
			||||||
 | 
					) engine=innodb;
 | 
				
			||||||
 | 
					create table t2
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
					CHILD_ID INT NOT NULL AUTO_INCREMENT,
 | 
				
			||||||
 | 
					PARENT_ID INT NOT NULL,
 | 
				
			||||||
 | 
					CHILD_FIELD varchar(10),
 | 
				
			||||||
 | 
					PRIMARY KEY (CHILD_ID)
 | 
				
			||||||
 | 
					)engine=innodb;
 | 
				
			||||||
 | 
					INSERT INTO t1 (PARENT_FIELD)
 | 
				
			||||||
 | 
					SELECT 'AAAA';
 | 
				
			||||||
 | 
					INSERT INTO t2 (PARENT_ID, CHILD_FIELD)
 | 
				
			||||||
 | 
					SELECT 1, 'BBBB';
 | 
				
			||||||
 | 
					explain select
 | 
				
			||||||
 | 
					t1.PARENT_ID,
 | 
				
			||||||
 | 
					min(CHILD_FIELD)
 | 
				
			||||||
 | 
					from t1 straight_join t2
 | 
				
			||||||
 | 
					where t1.PARENT_ID = 1
 | 
				
			||||||
 | 
					and t1.PARENT_ID = t2.PARENT_ID
 | 
				
			||||||
 | 
					and t2.CHILD_FIELD = "ZZZZ";
 | 
				
			||||||
 | 
					id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			||||||
 | 
					1	SIMPLE	t1	const	PRIMARY	PRIMARY	4	const	1	Using index
 | 
				
			||||||
 | 
					1	SIMPLE	t2	ALL	NULL	NULL	NULL	NULL	1	Using where
 | 
				
			||||||
 | 
					select
 | 
				
			||||||
 | 
					t1.PARENT_ID,
 | 
				
			||||||
 | 
					min(CHILD_FIELD)
 | 
				
			||||||
 | 
					from t1 straight_join t2
 | 
				
			||||||
 | 
					where t1.PARENT_ID = 1
 | 
				
			||||||
 | 
					and t1.PARENT_ID = t2.PARENT_ID
 | 
				
			||||||
 | 
					and t2.CHILD_FIELD = "ZZZZ";
 | 
				
			||||||
 | 
					PARENT_ID	min(CHILD_FIELD)
 | 
				
			||||||
 | 
					NULL	NULL
 | 
				
			||||||
 | 
					select
 | 
				
			||||||
 | 
					1,
 | 
				
			||||||
 | 
					min(CHILD_FIELD)
 | 
				
			||||||
 | 
					from t1 straight_join t2
 | 
				
			||||||
 | 
					where t1.PARENT_ID = 1
 | 
				
			||||||
 | 
					and t1.PARENT_ID = t2.PARENT_ID
 | 
				
			||||||
 | 
					and t2.CHILD_FIELD = "ZZZZ";
 | 
				
			||||||
 | 
					1	min(CHILD_FIELD)
 | 
				
			||||||
 | 
					1	NULL
 | 
				
			||||||
 | 
					select
 | 
				
			||||||
 | 
					IFNULL(t1.PARENT_ID,1),
 | 
				
			||||||
 | 
					min(CHILD_FIELD)
 | 
				
			||||||
 | 
					from t1 straight_join t2
 | 
				
			||||||
 | 
					where t1.PARENT_ID = 1
 | 
				
			||||||
 | 
					and t1.PARENT_ID = t2.PARENT_ID
 | 
				
			||||||
 | 
					and t2.CHILD_FIELD = "ZZZZ";
 | 
				
			||||||
 | 
					IFNULL(t1.PARENT_ID,1)	min(CHILD_FIELD)
 | 
				
			||||||
 | 
					1	NULL
 | 
				
			||||||
 | 
					# Check that things works with MyISAM (which has different explain)
 | 
				
			||||||
 | 
					alter table t1 engine=myisam;
 | 
				
			||||||
 | 
					alter table t2 engine=myisam;
 | 
				
			||||||
 | 
					explain select
 | 
				
			||||||
 | 
					t1.PARENT_ID,
 | 
				
			||||||
 | 
					min(CHILD_FIELD)
 | 
				
			||||||
 | 
					from t1 straight_join t2
 | 
				
			||||||
 | 
					where t1.PARENT_ID = 1
 | 
				
			||||||
 | 
					and t1.PARENT_ID = t2.PARENT_ID
 | 
				
			||||||
 | 
					and t2.CHILD_FIELD = "ZZZZ";
 | 
				
			||||||
 | 
					id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			||||||
 | 
					1	SIMPLE	NULL	NULL	NULL	NULL	NULL	NULL	NULL	Impossible WHERE noticed after reading const tables
 | 
				
			||||||
 | 
					select
 | 
				
			||||||
 | 
					t1.PARENT_ID,
 | 
				
			||||||
 | 
					min(CHILD_FIELD)
 | 
				
			||||||
 | 
					from t1 straight_join t2
 | 
				
			||||||
 | 
					where t1.PARENT_ID = 1
 | 
				
			||||||
 | 
					and t1.PARENT_ID = t2.PARENT_ID
 | 
				
			||||||
 | 
					and t2.CHILD_FIELD = "ZZZZ";
 | 
				
			||||||
 | 
					PARENT_ID	min(CHILD_FIELD)
 | 
				
			||||||
 | 
					NULL	NULL
 | 
				
			||||||
 | 
					drop table t1,t2;
 | 
				
			||||||
 | 
					# Check that things works if sub queries are re-executed
 | 
				
			||||||
 | 
					create table t1 (a int primary key, b int);
 | 
				
			||||||
 | 
					create table t2 (a int primary key, b int);
 | 
				
			||||||
 | 
					create table t3 (a int primary key, b int);
 | 
				
			||||||
 | 
					insert into t1 values (1,1),(2,2),(3,3);
 | 
				
			||||||
 | 
					insert into t2 values (1,1),(2,2),(3,3);
 | 
				
			||||||
 | 
					insert into t3 values (1,1),(3,3);
 | 
				
			||||||
 | 
					explain
 | 
				
			||||||
 | 
					select *,
 | 
				
			||||||
 | 
					(select
 | 
				
			||||||
 | 
					CONCAT('t2:',       IFNULL(t2.a,      't2a-null'), ';',
 | 
				
			||||||
 | 
					'min_t3_b:', IFNULL(min(t3.b), 't3b-null'))
 | 
				
			||||||
 | 
					from t2,t3
 | 
				
			||||||
 | 
					where t2.a=1 and t1.b = t3.a) as s1
 | 
				
			||||||
 | 
					from t1;
 | 
				
			||||||
 | 
					id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			||||||
 | 
					1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	3	
 | 
				
			||||||
 | 
					2	DEPENDENT SUBQUERY	t2	const	PRIMARY	PRIMARY	4	const	1	Using index
 | 
				
			||||||
 | 
					2	DEPENDENT SUBQUERY	t3	eq_ref	PRIMARY	PRIMARY	4	test.t1.b	1	
 | 
				
			||||||
 | 
					select *,
 | 
				
			||||||
 | 
					(select
 | 
				
			||||||
 | 
					CONCAT('t2:',       IFNULL(t2.a,      't2a-null'), ';',
 | 
				
			||||||
 | 
					'min_t3_b:', IFNULL(min(t3.b), 't3b-null'))
 | 
				
			||||||
 | 
					from t2,t3
 | 
				
			||||||
 | 
					where t2.a=1 and t1.b = t3.a) as s1
 | 
				
			||||||
 | 
					from t1;
 | 
				
			||||||
 | 
					a	b	s1
 | 
				
			||||||
 | 
					1	1	t2:1;min_t3_b:1
 | 
				
			||||||
 | 
					2	2	t2:t2a-null;min_t3_b:t3b-null
 | 
				
			||||||
 | 
					3	3	t2:1;min_t3_b:3
 | 
				
			||||||
 | 
					drop table t1,t2,t3;
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
# End of 10.5 tests
 | 
					# End of 10.5 tests
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1749,6 +1749,116 @@ SELECT MIN(pk), a FROM t1 WHERE pk <> 1 GROUP BY a;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
DROP TABLE t1;
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # MDEV-6768 Wrong result with agregate with join with no resultset
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create table t1
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
						PARENT_ID int(10) unsigned NOT NULL AUTO_INCREMENT,
 | 
				
			||||||
 | 
						PARENT_FIELD VARCHAR(10),
 | 
				
			||||||
 | 
						PRIMARY KEY (PARENT_ID)
 | 
				
			||||||
 | 
					) engine=innodb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create table t2
 | 
				
			||||||
 | 
					(
 | 
				
			||||||
 | 
						CHILD_ID INT NOT NULL AUTO_INCREMENT,
 | 
				
			||||||
 | 
						PARENT_ID INT NOT NULL,
 | 
				
			||||||
 | 
						CHILD_FIELD varchar(10),
 | 
				
			||||||
 | 
						PRIMARY KEY (CHILD_ID)
 | 
				
			||||||
 | 
					)engine=innodb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INSERT INTO t1 (PARENT_FIELD)
 | 
				
			||||||
 | 
					SELECT 'AAAA';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INSERT INTO t2 (PARENT_ID, CHILD_FIELD)
 | 
				
			||||||
 | 
					SELECT 1, 'BBBB';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					explain select
 | 
				
			||||||
 | 
					 t1.PARENT_ID,
 | 
				
			||||||
 | 
					 min(CHILD_FIELD)
 | 
				
			||||||
 | 
					 from t1 straight_join t2
 | 
				
			||||||
 | 
					 where t1.PARENT_ID = 1
 | 
				
			||||||
 | 
					 and t1.PARENT_ID = t2.PARENT_ID
 | 
				
			||||||
 | 
					 and t2.CHILD_FIELD = "ZZZZ";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select
 | 
				
			||||||
 | 
					 t1.PARENT_ID,
 | 
				
			||||||
 | 
					 min(CHILD_FIELD)
 | 
				
			||||||
 | 
					 from t1 straight_join t2
 | 
				
			||||||
 | 
					 where t1.PARENT_ID = 1
 | 
				
			||||||
 | 
					 and t1.PARENT_ID = t2.PARENT_ID
 | 
				
			||||||
 | 
					 and t2.CHILD_FIELD = "ZZZZ";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select
 | 
				
			||||||
 | 
					 1,
 | 
				
			||||||
 | 
					 min(CHILD_FIELD)
 | 
				
			||||||
 | 
					 from t1 straight_join t2
 | 
				
			||||||
 | 
					 where t1.PARENT_ID = 1
 | 
				
			||||||
 | 
					 and t1.PARENT_ID = t2.PARENT_ID
 | 
				
			||||||
 | 
					 and t2.CHILD_FIELD = "ZZZZ";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select
 | 
				
			||||||
 | 
					 IFNULL(t1.PARENT_ID,1),
 | 
				
			||||||
 | 
					 min(CHILD_FIELD)
 | 
				
			||||||
 | 
					 from t1 straight_join t2
 | 
				
			||||||
 | 
					 where t1.PARENT_ID = 1
 | 
				
			||||||
 | 
					 and t1.PARENT_ID = t2.PARENT_ID
 | 
				
			||||||
 | 
					 and t2.CHILD_FIELD = "ZZZZ";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo # Check that things works with MyISAM (which has different explain)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					alter table t1 engine=myisam;
 | 
				
			||||||
 | 
					alter table t2 engine=myisam;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					explain select
 | 
				
			||||||
 | 
					 t1.PARENT_ID,
 | 
				
			||||||
 | 
					 min(CHILD_FIELD)
 | 
				
			||||||
 | 
					 from t1 straight_join t2
 | 
				
			||||||
 | 
					 where t1.PARENT_ID = 1
 | 
				
			||||||
 | 
					 and t1.PARENT_ID = t2.PARENT_ID
 | 
				
			||||||
 | 
					 and t2.CHILD_FIELD = "ZZZZ";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select
 | 
				
			||||||
 | 
					 t1.PARENT_ID,
 | 
				
			||||||
 | 
					 min(CHILD_FIELD)
 | 
				
			||||||
 | 
					 from t1 straight_join t2
 | 
				
			||||||
 | 
					 where t1.PARENT_ID = 1
 | 
				
			||||||
 | 
					 and t1.PARENT_ID = t2.PARENT_ID
 | 
				
			||||||
 | 
					 and t2.CHILD_FIELD = "ZZZZ";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					drop table t1,t2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo # Check that things works if sub queries are re-executed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					create table t1 (a int primary key, b int);
 | 
				
			||||||
 | 
					create table t2 (a int primary key, b int);
 | 
				
			||||||
 | 
					create table t3 (a int primary key, b int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					insert into t1 values (1,1),(2,2),(3,3);
 | 
				
			||||||
 | 
					insert into t2 values (1,1),(2,2),(3,3);
 | 
				
			||||||
 | 
					insert into t3 values (1,1),(3,3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					explain
 | 
				
			||||||
 | 
					select *,
 | 
				
			||||||
 | 
					   (select
 | 
				
			||||||
 | 
					        CONCAT('t2:',       IFNULL(t2.a,      't2a-null'), ';',
 | 
				
			||||||
 | 
					               'min_t3_b:', IFNULL(min(t3.b), 't3b-null'))
 | 
				
			||||||
 | 
					    from t2,t3
 | 
				
			||||||
 | 
					    where t2.a=1 and t1.b = t3.a) as s1
 | 
				
			||||||
 | 
					from t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					select *,
 | 
				
			||||||
 | 
					   (select
 | 
				
			||||||
 | 
					        CONCAT('t2:',       IFNULL(t2.a,      't2a-null'), ';',
 | 
				
			||||||
 | 
					               'min_t3_b:', IFNULL(min(t3.b), 't3b-null'))
 | 
				
			||||||
 | 
					    from t2,t3
 | 
				
			||||||
 | 
					    where t2.a=1 and t1.b = t3.a) as s1
 | 
				
			||||||
 | 
					from t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					drop table t1,t2,t3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--echo #
 | 
					--echo #
 | 
				
			||||||
--echo # End of 10.5 tests
 | 
					--echo # End of 10.5 tests
 | 
				
			||||||
--echo #
 | 
					--echo #
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3902,6 +3902,18 @@ DROP TABLE t1;
 | 
				
			|||||||
DROP TABLE m1;
 | 
					DROP TABLE m1;
 | 
				
			||||||
set global default_storage_engine=@save_default_storage_engine;
 | 
					set global default_storage_engine=@save_default_storage_engine;
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 | 
					# MDEV-31083 ASAN use-after-poison in myrg_attach_children
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					CREATE TABLE t1 (f TEXT, FULLTEXT (f)) ENGINE=MyISAM;
 | 
				
			||||||
 | 
					INSERT INTO t1 VALUES ('foo'),('bar');
 | 
				
			||||||
 | 
					CREATE TABLE mrg (f TEXT) ENGINE=MERGE, UNION(t1);
 | 
				
			||||||
 | 
					SELECT * FROM mrg;
 | 
				
			||||||
 | 
					f
 | 
				
			||||||
 | 
					foo
 | 
				
			||||||
 | 
					bar
 | 
				
			||||||
 | 
					DROP TABLE mrg, t1;
 | 
				
			||||||
 | 
					End of 10.5 tests
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
# End of 10.0 tests
 | 
					# End of 10.0 tests
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2859,6 +2859,18 @@ set global default_storage_engine=@save_default_storage_engine;
 | 
				
			|||||||
# gone so execution of other tests won't be affected by their presence.
 | 
					# gone so execution of other tests won't be affected by their presence.
 | 
				
			||||||
--source include/wait_until_count_sessions.inc
 | 
					--source include/wait_until_count_sessions.inc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # MDEV-31083 ASAN use-after-poison in myrg_attach_children
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CREATE TABLE t1 (f TEXT, FULLTEXT (f)) ENGINE=MyISAM;
 | 
				
			||||||
 | 
					INSERT INTO t1 VALUES ('foo'),('bar');
 | 
				
			||||||
 | 
					CREATE TABLE mrg (f TEXT) ENGINE=MERGE, UNION(t1);
 | 
				
			||||||
 | 
					SELECT * FROM mrg;
 | 
				
			||||||
 | 
					DROP TABLE mrg, t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo End of 10.5 tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--echo #
 | 
					--echo #
 | 
				
			||||||
--echo # End of 10.0 tests
 | 
					--echo # End of 10.0 tests
 | 
				
			||||||
--echo #
 | 
					--echo #
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1824,7 +1824,6 @@ test.t1	analyze	status	Table is already up to date
 | 
				
			|||||||
test.t2	analyze	status	Engine-independent statistics collected
 | 
					test.t2	analyze	status	Engine-independent statistics collected
 | 
				
			||||||
test.t2	analyze	status	Table is already up to date
 | 
					test.t2	analyze	status	Table is already up to date
 | 
				
			||||||
set optimizer_switch='exists_to_in=off';
 | 
					set optimizer_switch='exists_to_in=off';
 | 
				
			||||||
set optimizer_use_condition_selectivity=2;
 | 
					 | 
				
			||||||
SELECT * FROM t1
 | 
					SELECT * FROM t1
 | 
				
			||||||
WHERE
 | 
					WHERE
 | 
				
			||||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
					EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
				
			||||||
@@ -1849,18 +1848,39 @@ id	a
 | 
				
			|||||||
17	17
 | 
					17	17
 | 
				
			||||||
18	18
 | 
					18	18
 | 
				
			||||||
19	19
 | 
					19	19
 | 
				
			||||||
explain SELECT * FROM t1
 | 
					set statement optimizer_use_condition_selectivity=2 for explain SELECT * FROM t1
 | 
				
			||||||
WHERE
 | 
					WHERE
 | 
				
			||||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
					EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
				
			||||||
WHERE A.a=t1.a AND t2.b < 20);
 | 
					WHERE A.a=t1.a AND t2.b < 20);
 | 
				
			||||||
id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
					id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			||||||
1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	100	Using where
 | 
					1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	100	Using where
 | 
				
			||||||
2	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	
 | 
					3	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	
 | 
				
			||||||
2	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (10%)	Using where; Using rowid filter
 | 
					3	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (10%)	Using where; Using rowid filter
 | 
				
			||||||
EXPLAIN  SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65;
 | 
					set statement optimizer_use_condition_selectivity=4 for explain SELECT * FROM t1
 | 
				
			||||||
 | 
					WHERE
 | 
				
			||||||
 | 
					EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
				
			||||||
 | 
					WHERE A.a=t1.a AND t2.b < 20);
 | 
				
			||||||
id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
					id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			||||||
1	SIMPLE	A	const	PRIMARY,a	PRIMARY	4	const	1	
 | 
					1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	100	Using where
 | 
				
			||||||
1	SIMPLE	B	ref	a	a	5	const	1	
 | 
					3	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	
 | 
				
			||||||
 | 
					3	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (10%)	Using where; Using rowid filter
 | 
				
			||||||
 | 
					set @query="EXPLAIN  SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65";
 | 
				
			||||||
 | 
					set statement optimizer_use_condition_selectivity=2 for explain SELECT * FROM t1
 | 
				
			||||||
 | 
					WHERE
 | 
				
			||||||
 | 
					EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
				
			||||||
 | 
					WHERE A.a=t1.a AND t2.b < 20);
 | 
				
			||||||
 | 
					id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			||||||
 | 
					1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	100	Using where
 | 
				
			||||||
 | 
					3	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	
 | 
				
			||||||
 | 
					3	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (10%)	Using where; Using rowid filter
 | 
				
			||||||
 | 
					set statement optimizer_use_condition_selectivity=4 for explain SELECT * FROM t1
 | 
				
			||||||
 | 
					WHERE
 | 
				
			||||||
 | 
					EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
				
			||||||
 | 
					WHERE A.a=t1.a AND t2.b < 20);
 | 
				
			||||||
 | 
					id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			||||||
 | 
					1	PRIMARY	t1	ALL	NULL	NULL	NULL	NULL	100	Using where
 | 
				
			||||||
 | 
					3	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	
 | 
				
			||||||
 | 
					3	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (10%)	Using where; Using rowid filter
 | 
				
			||||||
explain SELECT * FROM t1
 | 
					explain SELECT * FROM t1
 | 
				
			||||||
WHERE
 | 
					WHERE
 | 
				
			||||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
					EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
				
			||||||
@@ -1870,7 +1890,6 @@ id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			|||||||
2	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	
 | 
					2	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	
 | 
				
			||||||
2	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (10%)	Using where; Using rowid filter
 | 
					2	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (10%)	Using where; Using rowid filter
 | 
				
			||||||
set optimizer_switch= @save_optimizer_switch;
 | 
					set optimizer_switch= @save_optimizer_switch;
 | 
				
			||||||
set optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
 | 
					 | 
				
			||||||
drop table t1,t2;
 | 
					drop table t1,t2;
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# MDEV-21495: Conditional jump or move depends on uninitialised value in sel_arg_range_seq_next
 | 
					# MDEV-21495: Conditional jump or move depends on uninitialised value in sel_arg_range_seq_next
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1236,13 +1236,10 @@ set optimizer_use_condition_selectivity= @@optimizer_use_condition_selectivity;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
drop table t1,t2,t3;
 | 
					drop table t1,t2,t3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
--echo #
 | 
					--echo #
 | 
				
			||||||
--echo # MDEV-20519: Query plan regression with optimizer_use_condition_selectivity=4
 | 
					--echo # MDEV-20519: Query plan regression with optimizer_use_condition_selectivity=4
 | 
				
			||||||
--echo #
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
create table t1 (id int, a int, PRIMARY KEY(id), key(a));
 | 
					create table t1 (id int, a int, PRIMARY KEY(id), key(a));
 | 
				
			||||||
insert into t1 select seq,seq from seq_1_to_100;
 | 
					insert into t1 select seq,seq from seq_1_to_100;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1252,7 +1249,6 @@ insert into t2 select seq,seq,seq from seq_1_to_100;
 | 
				
			|||||||
analyze table t1,t2 persistent for all;
 | 
					analyze table t1,t2 persistent for all;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set optimizer_switch='exists_to_in=off';
 | 
					set optimizer_switch='exists_to_in=off';
 | 
				
			||||||
set optimizer_use_condition_selectivity=2;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
let $query= SELECT * FROM t1
 | 
					let $query= SELECT * FROM t1
 | 
				
			||||||
            WHERE
 | 
					            WHERE
 | 
				
			||||||
@@ -1260,14 +1256,16 @@ let $query= SELECT * FROM t1
 | 
				
			|||||||
                      WHERE A.a=t1.a AND t2.b < 20);
 | 
					                      WHERE A.a=t1.a AND t2.b < 20);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
eval $query;
 | 
					eval $query;
 | 
				
			||||||
eval explain $query;
 | 
					eval set statement optimizer_use_condition_selectivity=2 for explain $query;
 | 
				
			||||||
 | 
					eval set statement optimizer_use_condition_selectivity=4 for explain $query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXPLAIN  SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65;
 | 
					set @query="EXPLAIN  SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65";
 | 
				
			||||||
 | 
					eval set statement optimizer_use_condition_selectivity=2 for explain $query;
 | 
				
			||||||
 | 
					eval set statement optimizer_use_condition_selectivity=4 for explain $query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
eval explain $query;
 | 
					eval explain $query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
set optimizer_switch= @save_optimizer_switch;
 | 
					set optimizer_switch= @save_optimizer_switch;
 | 
				
			||||||
set optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
 | 
					 | 
				
			||||||
drop table t1,t2;
 | 
					drop table t1,t2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--echo #
 | 
					--echo #
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1836,7 +1836,6 @@ test.t1	analyze	status	OK
 | 
				
			|||||||
test.t2	analyze	status	Engine-independent statistics collected
 | 
					test.t2	analyze	status	Engine-independent statistics collected
 | 
				
			||||||
test.t2	analyze	status	OK
 | 
					test.t2	analyze	status	OK
 | 
				
			||||||
set optimizer_switch='exists_to_in=off';
 | 
					set optimizer_switch='exists_to_in=off';
 | 
				
			||||||
set optimizer_use_condition_selectivity=2;
 | 
					 | 
				
			||||||
SELECT * FROM t1
 | 
					SELECT * FROM t1
 | 
				
			||||||
WHERE
 | 
					WHERE
 | 
				
			||||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
					EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
				
			||||||
@@ -1861,18 +1860,39 @@ id	a
 | 
				
			|||||||
17	17
 | 
					17	17
 | 
				
			||||||
18	18
 | 
					18	18
 | 
				
			||||||
19	19
 | 
					19	19
 | 
				
			||||||
explain SELECT * FROM t1
 | 
					set statement optimizer_use_condition_selectivity=2 for explain SELECT * FROM t1
 | 
				
			||||||
WHERE
 | 
					WHERE
 | 
				
			||||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
					EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
				
			||||||
WHERE A.a=t1.a AND t2.b < 20);
 | 
					WHERE A.a=t1.a AND t2.b < 20);
 | 
				
			||||||
id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
					id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			||||||
1	PRIMARY	t1	index	NULL	a	5	NULL	100	Using where; Using index
 | 
					1	PRIMARY	t1	index	NULL	a	5	NULL	100	Using where; Using index
 | 
				
			||||||
2	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	Using index
 | 
					3	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	Using index
 | 
				
			||||||
2	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (19%)	Using where; Using rowid filter
 | 
					3	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (19%)	Using where; Using rowid filter
 | 
				
			||||||
EXPLAIN  SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65;
 | 
					set statement optimizer_use_condition_selectivity=4 for explain SELECT * FROM t1
 | 
				
			||||||
 | 
					WHERE
 | 
				
			||||||
 | 
					EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
				
			||||||
 | 
					WHERE A.a=t1.a AND t2.b < 20);
 | 
				
			||||||
id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
					id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			||||||
1	SIMPLE	A	const	PRIMARY,a	PRIMARY	4	const	1	
 | 
					1	PRIMARY	t1	index	NULL	a	5	NULL	100	Using where; Using index
 | 
				
			||||||
1	SIMPLE	B	ref	a	a	5	const	1	Using index
 | 
					3	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	Using index
 | 
				
			||||||
 | 
					3	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (19%)	Using where; Using rowid filter
 | 
				
			||||||
 | 
					set @query="EXPLAIN  SELECT * FROM t1 A, t1 B WHERE A.a = B.a and A.id = 65";
 | 
				
			||||||
 | 
					set statement optimizer_use_condition_selectivity=2 for explain SELECT * FROM t1
 | 
				
			||||||
 | 
					WHERE
 | 
				
			||||||
 | 
					EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
				
			||||||
 | 
					WHERE A.a=t1.a AND t2.b < 20);
 | 
				
			||||||
 | 
					id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			||||||
 | 
					1	PRIMARY	t1	index	NULL	a	5	NULL	100	Using where; Using index
 | 
				
			||||||
 | 
					3	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	Using index
 | 
				
			||||||
 | 
					3	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (19%)	Using where; Using rowid filter
 | 
				
			||||||
 | 
					set statement optimizer_use_condition_selectivity=4 for explain SELECT * FROM t1
 | 
				
			||||||
 | 
					WHERE
 | 
				
			||||||
 | 
					EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
				
			||||||
 | 
					WHERE A.a=t1.a AND t2.b < 20);
 | 
				
			||||||
 | 
					id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			||||||
 | 
					1	PRIMARY	t1	index	NULL	a	5	NULL	100	Using where; Using index
 | 
				
			||||||
 | 
					3	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	Using index
 | 
				
			||||||
 | 
					3	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (19%)	Using where; Using rowid filter
 | 
				
			||||||
explain SELECT * FROM t1
 | 
					explain SELECT * FROM t1
 | 
				
			||||||
WHERE
 | 
					WHERE
 | 
				
			||||||
EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
					EXISTS (SELECT * FROM t1 A INNER JOIN t2 ON t2.a = A.id
 | 
				
			||||||
@@ -1882,7 +1902,6 @@ id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 | 
				
			|||||||
2	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	Using index
 | 
					2	DEPENDENT SUBQUERY	A	ref	PRIMARY,a	a	5	test.t1.a	1	Using index
 | 
				
			||||||
2	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (19%)	Using where; Using rowid filter
 | 
					2	DEPENDENT SUBQUERY	t2	ref|filter	a,b	a|b	5|5	test.A.id	1 (19%)	Using where; Using rowid filter
 | 
				
			||||||
set optimizer_switch= @save_optimizer_switch;
 | 
					set optimizer_switch= @save_optimizer_switch;
 | 
				
			||||||
set optimizer_use_condition_selectivity= @save_optimizer_use_condition_selectivity;
 | 
					 | 
				
			||||||
drop table t1,t2;
 | 
					drop table t1,t2;
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# MDEV-21495: Conditional jump or move depends on uninitialised value in sel_arg_range_seq_next
 | 
					# MDEV-21495: Conditional jump or move depends on uninitialised value in sel_arg_range_seq_next
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1230,6 +1230,8 @@ SELECT * FROM t1 HAVING MIN(t1.c1) >= ALL(SELECT 'a' UNION SELECT 'r');
 | 
				
			|||||||
c1
 | 
					c1
 | 
				
			||||||
Warnings:
 | 
					Warnings:
 | 
				
			||||||
Warning	1292	Truncated incorrect datetime value: 'r'
 | 
					Warning	1292	Truncated incorrect datetime value: 'r'
 | 
				
			||||||
 | 
					SELECT * FROM t1 HAVING MIN(t1.c1) > 0;
 | 
				
			||||||
 | 
					c1
 | 
				
			||||||
DROP TABLE t1;
 | 
					DROP TABLE t1;
 | 
				
			||||||
CREATE TABLE t1 (c1 timestamp);
 | 
					CREATE TABLE t1 (c1 timestamp);
 | 
				
			||||||
INSERT INTO t1 VALUES ('2010-01-01 00:00:00');
 | 
					INSERT INTO t1 VALUES ('2010-01-01 00:00:00');
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -810,6 +810,7 @@ DROP TABLE t1;
 | 
				
			|||||||
CREATE TABLE t1 (c1 timestamp);
 | 
					CREATE TABLE t1 (c1 timestamp);
 | 
				
			||||||
SELECT MIN(t1.c1) AS k1 FROM t1 HAVING (k1 >= ALL(SELECT 'a' UNION SELECT 'r'));
 | 
					SELECT MIN(t1.c1) AS k1 FROM t1 HAVING (k1 >= ALL(SELECT 'a' UNION SELECT 'r'));
 | 
				
			||||||
SELECT * FROM t1 HAVING MIN(t1.c1) >= ALL(SELECT 'a' UNION SELECT 'r');
 | 
					SELECT * FROM t1 HAVING MIN(t1.c1) >= ALL(SELECT 'a' UNION SELECT 'r');
 | 
				
			||||||
 | 
					SELECT * FROM t1 HAVING MIN(t1.c1) > 0;
 | 
				
			||||||
DROP TABLE t1;
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CREATE TABLE t1 (c1 timestamp);
 | 
					CREATE TABLE t1 (c1 timestamp);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -408,8 +408,11 @@ sub main {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  mark_time_used('collect');
 | 
					  mark_time_used('collect');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mysql_install_db(default_mysqld(), "$opt_vardir/install.db") unless using_extern();
 | 
					  if (!using_extern())
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    mysql_install_db(default_mysqld(), "$opt_vardir/install.db");
 | 
				
			||||||
 | 
					    make_readonly("$opt_vardir/install.db");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  if ($opt_dry_run)
 | 
					  if ($opt_dry_run)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    for (@$tests) {
 | 
					    for (@$tests) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,3 +27,5 @@ galera_bf_kill_debug : timeout after 900 seconds
 | 
				
			|||||||
galera_ssl_upgrade : [Warning] Failed to load slave replication state from table mysql.gtid_slave_pos: 130: Incorrect file format 'gtid_slave_pos'
 | 
					galera_ssl_upgrade : [Warning] Failed to load slave replication state from table mysql.gtid_slave_pos: 130: Incorrect file format 'gtid_slave_pos'
 | 
				
			||||||
galera_parallel_simple : timeout related to wsrep_sync_wait
 | 
					galera_parallel_simple : timeout related to wsrep_sync_wait
 | 
				
			||||||
galera_insert_bulk : MDEV-30536 no expected deadlock in galera_insert_bulk test
 | 
					galera_insert_bulk : MDEV-30536 no expected deadlock in galera_insert_bulk test
 | 
				
			||||||
 | 
					MDEV-27713 : test is using get_lock(), which is now rejected in cluster
 | 
				
			||||||
 | 
					galera_bf_abort_group_commit : MDEV-30855 PR to remove the test exists
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								mysql-test/suite/galera/r/MDEV-29293.result
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								mysql-test/suite/galera/r/MDEV-29293.result
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					connection node_2;
 | 
				
			||||||
 | 
					connection node_1;
 | 
				
			||||||
 | 
					connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
 | 
				
			||||||
 | 
					connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1;
 | 
				
			||||||
 | 
					set wsrep_sync_wait = 0;
 | 
				
			||||||
 | 
					CREATE TABLE t1(a int not null primary key auto_increment, b int) engine=InnoDB;
 | 
				
			||||||
 | 
					INSERT INTO t1 VALUES (1,2);
 | 
				
			||||||
 | 
					connection node_1a;
 | 
				
			||||||
 | 
					BEGIN;
 | 
				
			||||||
 | 
					UPDATE t1 SET b=3 WHERE a=1;
 | 
				
			||||||
 | 
					connection node_1;
 | 
				
			||||||
 | 
					set debug_sync='wsrep_kill_before_awake_no_mutex SIGNAL before_kill WAIT_FOR continue';
 | 
				
			||||||
 | 
					connection node_1b;
 | 
				
			||||||
 | 
					set debug_sync= 'now WAIT_FOR before_kill';
 | 
				
			||||||
 | 
					connection node_2;
 | 
				
			||||||
 | 
					UPDATE t1 SET b=7 WHERE a=1;
 | 
				
			||||||
 | 
					connection node_1b;
 | 
				
			||||||
 | 
					set debug_sync= 'now SIGNAL continue';
 | 
				
			||||||
 | 
					connection node_1;
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					SET DEBUG_SYNC= 'RESET';
 | 
				
			||||||
@@ -82,6 +82,7 @@ connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1;
 | 
				
			|||||||
LOCK TABLE t2 WRITE;
 | 
					LOCK TABLE t2 WRITE;
 | 
				
			||||||
connection node_1;
 | 
					connection node_1;
 | 
				
			||||||
CREATE TABLE t1 AS SELECT * FROM t2;;
 | 
					CREATE TABLE t1 AS SELECT * FROM t2;;
 | 
				
			||||||
 | 
					connection node_1a;
 | 
				
			||||||
connection node_2;
 | 
					connection node_2;
 | 
				
			||||||
SELECT COUNT(*) = 5 FROM t2;
 | 
					SELECT COUNT(*) = 5 FROM t2;
 | 
				
			||||||
COUNT(*) = 5
 | 
					COUNT(*) = 5
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -134,6 +134,3 @@ connection node_1;
 | 
				
			|||||||
call mtr.add_suppression("Error in Log_event::read_log_event():.*");
 | 
					call mtr.add_suppression("Error in Log_event::read_log_event():.*");
 | 
				
			||||||
CALL mtr.add_suppression("conflict state 7 after post commit");
 | 
					CALL mtr.add_suppression("conflict state 7 after post commit");
 | 
				
			||||||
CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
 | 
					CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
 | 
				
			||||||
connection node_2;
 | 
					 | 
				
			||||||
call mtr.add_suppression("Error in Log_event::read_log_event():.*");
 | 
					 | 
				
			||||||
CALL mtr.add_suppression("Skipped GCache ring buffer recovery");
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										27
									
								
								mysql-test/suite/galera/r/galera_kill_group_commit.result
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								mysql-test/suite/galera/r/galera_kill_group_commit.result
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					connection node_2;
 | 
				
			||||||
 | 
					connection node_1;
 | 
				
			||||||
 | 
					connect node_1_kill, 127.0.0.1, root, , test, $NODE_MYPORT_1;
 | 
				
			||||||
 | 
					connect node_1_ctrl, 127.0.0.1, root, , test, $NODE_MYPORT_1;
 | 
				
			||||||
 | 
					SET SESSION wsrep_sync_wait = 0;
 | 
				
			||||||
 | 
					connect node_1_follower, 127.0.0.1, root, , test, $NODE_MYPORT_1;
 | 
				
			||||||
 | 
					SET SESSION wsrep_sync_wait = 0;
 | 
				
			||||||
 | 
					connection node_1;
 | 
				
			||||||
 | 
					CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
 | 
				
			||||||
 | 
					SET SESSION DEBUG_SYNC = "commit_before_enqueue SIGNAL leader_before_enqueue_reached WAIT_FOR leader_before_enqueue_continue";
 | 
				
			||||||
 | 
					INSERT INTO t1 VALUES (1);
 | 
				
			||||||
 | 
					connection node_1_ctrl;
 | 
				
			||||||
 | 
					SET DEBUG_SYNC = "now WAIT_FOR leader_before_enqueue_reached";
 | 
				
			||||||
 | 
					connection node_1_follower;
 | 
				
			||||||
 | 
					INSERT INTO t1 VALUES (2);;
 | 
				
			||||||
 | 
					connection node_1_ctrl;
 | 
				
			||||||
 | 
					connection node_1_kill;
 | 
				
			||||||
 | 
					# Execute KILL QUERY for group commit follower
 | 
				
			||||||
 | 
					SET DEBUG_SYNC = "now SIGNAL leader_before_enqueue_continue";
 | 
				
			||||||
 | 
					connection node_1_follower;
 | 
				
			||||||
 | 
					connection node_1;
 | 
				
			||||||
 | 
					SELECT * FROM t1;
 | 
				
			||||||
 | 
					f1
 | 
				
			||||||
 | 
					1
 | 
				
			||||||
 | 
					2
 | 
				
			||||||
 | 
					SET DEBUG_SYNC = "RESET";
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
@@ -36,7 +36,10 @@ SET DEBUG_SYNC = 'now SIGNAL wsrep_retry_autocommit_continue';
 | 
				
			|||||||
connection node_1;
 | 
					connection node_1;
 | 
				
			||||||
SELECT COUNT(*) FROM t1;
 | 
					SELECT COUNT(*) FROM t1;
 | 
				
			||||||
COUNT(*)
 | 
					COUNT(*)
 | 
				
			||||||
1
 | 
					connection node_1;
 | 
				
			||||||
 | 
					SELECT COUNT(*) FROM t1;
 | 
				
			||||||
 | 
					COUNT(*)
 | 
				
			||||||
 | 
					0
 | 
				
			||||||
SET DEBUG_SYNC = 'RESET';
 | 
					SET DEBUG_SYNC = 'RESET';
 | 
				
			||||||
SET GLOBAL debug_dbug = NULL;
 | 
					SET GLOBAL debug_dbug = NULL;
 | 
				
			||||||
DROP TABLE t1;
 | 
					DROP TABLE t1;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										41
									
								
								mysql-test/suite/galera/t/MDEV-29293.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								mysql-test/suite/galera/t/MDEV-29293.test
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					--source include/galera_cluster.inc
 | 
				
			||||||
 | 
					--source include/have_innodb.inc
 | 
				
			||||||
 | 
					--source include/have_debug_sync.inc
 | 
				
			||||||
 | 
					--source include/galera_have_debug_sync.inc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
 | 
				
			||||||
 | 
					--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1
 | 
				
			||||||
 | 
					set wsrep_sync_wait = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CREATE TABLE t1(a int not null primary key auto_increment, b int) engine=InnoDB;
 | 
				
			||||||
 | 
					INSERT INTO t1 VALUES (1,2); 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connection node_1a
 | 
				
			||||||
 | 
					--let $victim_id = `SELECT CONNECTION_ID()`
 | 
				
			||||||
 | 
					BEGIN;
 | 
				
			||||||
 | 
					UPDATE t1 SET b=3 WHERE a=1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connection node_1
 | 
				
			||||||
 | 
					set debug_sync='wsrep_kill_before_awake_no_mutex SIGNAL before_kill WAIT_FOR continue';
 | 
				
			||||||
 | 
					--disable_query_log
 | 
				
			||||||
 | 
					--disable_result_log
 | 
				
			||||||
 | 
					--send_eval KILL CONNECTION $victim_id 
 | 
				
			||||||
 | 
					--enable_result_log
 | 
				
			||||||
 | 
					--enable_query_log
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connection node_1b
 | 
				
			||||||
 | 
					set debug_sync= 'now WAIT_FOR before_kill';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connection node_2
 | 
				
			||||||
 | 
					UPDATE t1 SET b=7 WHERE a=1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connection node_1b 
 | 
				
			||||||
 | 
					--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE User = 'system user' AND  State LIKE 'Update_rows_log_event%'; 
 | 
				
			||||||
 | 
					--source include/wait_condition.inc
 | 
				
			||||||
 | 
					set debug_sync= 'now SIGNAL continue'; 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connection node_1
 | 
				
			||||||
 | 
					--reap 
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					SET DEBUG_SYNC= 'RESET';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -113,6 +113,10 @@ LOCK TABLE t2 WRITE;
 | 
				
			|||||||
--connection node_1
 | 
					--connection node_1
 | 
				
			||||||
--send CREATE TABLE t1 AS SELECT * FROM t2;
 | 
					--send CREATE TABLE t1 AS SELECT * FROM t2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connection node_1a
 | 
				
			||||||
 | 
					--let $wait_condition = SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE STATE LIKE 'Waiting for table metadata lock%'
 | 
				
			||||||
 | 
					--source include/wait_condition.inc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--connection node_2
 | 
					--connection node_2
 | 
				
			||||||
SELECT COUNT(*) = 5 FROM t2;
 | 
					SELECT COUNT(*) = 5 FROM t2;
 | 
				
			||||||
CREATE TABLE t1 AS SELECT * FROM t2;
 | 
					CREATE TABLE t1 AS SELECT * FROM t2;
 | 
				
			||||||
@@ -121,7 +125,7 @@ CREATE TABLE t1 AS SELECT * FROM t2;
 | 
				
			|||||||
UNLOCK TABLES;
 | 
					UNLOCK TABLES;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--connection node_1
 | 
					--connection node_1
 | 
				
			||||||
--error ER_TABLE_EXISTS_ERROR,ER_LOCK_DEADLOCK
 | 
					--error ER_TABLE_EXISTS_ERROR,ER_QUERY_INTERRUPTED
 | 
				
			||||||
--reap
 | 
					--reap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DROP TABLE t1, t2;
 | 
					DROP TABLE t1, t2;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										5
									
								
								mysql-test/suite/galera/t/galera_kill_group_commit.cnf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								mysql-test/suite/galera/t/galera_kill_group_commit.cnf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					!include ../galera_2nodes.cnf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[mysqld]
 | 
				
			||||||
 | 
					log-bin
 | 
				
			||||||
 | 
					log-slave-updates
 | 
				
			||||||
							
								
								
									
										69
									
								
								mysql-test/suite/galera/t/galera_kill_group_commit.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								mysql-test/suite/galera/t/galera_kill_group_commit.test
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					#
 | 
				
			||||||
 | 
					# Verify that transaction which has reached group commit queue
 | 
				
			||||||
 | 
					# cannot be killed. If the kill succeeds, assertion for
 | 
				
			||||||
 | 
					# wsrep transaction state will fail.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# If the bug is present, i.e. wsrep transaction gets killed during
 | 
				
			||||||
 | 
					# group commit wait, this test is enough to reproduce the crash
 | 
				
			||||||
 | 
					# most of the time.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--source include/have_innodb.inc
 | 
				
			||||||
 | 
					--source include/have_debug_sync.inc
 | 
				
			||||||
 | 
					--source include/galera_cluster.inc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Connection for KILL commands
 | 
				
			||||||
 | 
					--connect node_1_kill, 127.0.0.1, root, , test, $NODE_MYPORT_1
 | 
				
			||||||
 | 
					# Connection for sync point control
 | 
				
			||||||
 | 
					--connect node_1_ctrl, 127.0.0.1, root, , test, $NODE_MYPORT_1
 | 
				
			||||||
 | 
					SET SESSION wsrep_sync_wait = 0;
 | 
				
			||||||
 | 
					# Connection for group commit follower
 | 
				
			||||||
 | 
					--connect node_1_follower, 127.0.0.1, root, , test, $NODE_MYPORT_1
 | 
				
			||||||
 | 
					# Need to disable sync wait to reach commit queue when leader
 | 
				
			||||||
 | 
					# is blocked.
 | 
				
			||||||
 | 
					SET SESSION wsrep_sync_wait = 0;
 | 
				
			||||||
 | 
					--let $follower_id = `SELECT CONNECTION_ID()`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connection node_1
 | 
				
			||||||
 | 
					CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET SESSION DEBUG_SYNC = "commit_before_enqueue SIGNAL leader_before_enqueue_reached WAIT_FOR leader_before_enqueue_continue";
 | 
				
			||||||
 | 
					--send INSERT INTO t1 VALUES (1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connection node_1_ctrl
 | 
				
			||||||
 | 
					SET DEBUG_SYNC = "now WAIT_FOR leader_before_enqueue_reached";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connection node_1_follower
 | 
				
			||||||
 | 
					# SET SESSION DEBUG_SYNC = "group_commit_waiting_for_prior SIGNAL follower_waiting_for_prior_reached WAIT_FOR follower_waiting_for_prior_continue";
 | 
				
			||||||
 | 
					--send INSERT INTO t1 VALUES (2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connection node_1_ctrl
 | 
				
			||||||
 | 
					# TODO: Is it possible to use sync points to enforce group commit to happen?
 | 
				
			||||||
 | 
					# The leader will hold commit monitor in commit_before_enqueue sync point,
 | 
				
			||||||
 | 
					# which prevents the follower to reach the group commit wait state.
 | 
				
			||||||
 | 
					# We now sleep and expect the follower to reach group commit, but this
 | 
				
			||||||
 | 
					# may cause false negatives.
 | 
				
			||||||
 | 
					--sleep 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connection node_1_kill
 | 
				
			||||||
 | 
					--echo # Execute KILL QUERY for group commit follower
 | 
				
			||||||
 | 
					--disable_query_log
 | 
				
			||||||
 | 
					--disable_result_log
 | 
				
			||||||
 | 
					# Because it is currently impossible to verify that the
 | 
				
			||||||
 | 
					# follower has reached group commit queue, the KILL may
 | 
				
			||||||
 | 
					# sometimes return success.
 | 
				
			||||||
 | 
					--error 0,ER_KILL_DENIED_ERROR
 | 
				
			||||||
 | 
					--eval KILL QUERY $follower_id
 | 
				
			||||||
 | 
					--enable_result_log
 | 
				
			||||||
 | 
					--enable_query_log
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET DEBUG_SYNC = "now SIGNAL leader_before_enqueue_continue";
 | 
				
			||||||
 | 
					--connection node_1_follower
 | 
				
			||||||
 | 
					--reap
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--connection node_1
 | 
				
			||||||
 | 
					--reap
 | 
				
			||||||
 | 
					SELECT * FROM t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET DEBUG_SYNC = "RESET";
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
@@ -64,6 +64,7 @@ SELECT COUNT(*) FROM t1;
 | 
				
			|||||||
SET DEBUG_SYNC = 'now SIGNAL wsrep_retry_autocommit_continue';
 | 
					SET DEBUG_SYNC = 'now SIGNAL wsrep_retry_autocommit_continue';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--connection node_1
 | 
					--connection node_1
 | 
				
			||||||
 | 
					--error 0,ER_LOCK_DEADLOCK
 | 
				
			||||||
--reap
 | 
					--reap
 | 
				
			||||||
SELECT COUNT(*) FROM t1;
 | 
					SELECT COUNT(*) FROM t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,9 @@
 | 
				
			|||||||
set global innodb_monitor_disable = All;
 | 
					 | 
				
			||||||
select name, if(enabled,'enabled','disabled') status
 | 
					select name, if(enabled,'enabled','disabled') status
 | 
				
			||||||
from information_schema.innodb_metrics;
 | 
					from information_schema.innodb_metrics;
 | 
				
			||||||
name	status
 | 
					name	status
 | 
				
			||||||
metadata_table_handles_opened	disabled
 | 
					metadata_table_handles_opened	disabled
 | 
				
			||||||
lock_deadlocks	disabled
 | 
					lock_deadlocks	enabled
 | 
				
			||||||
lock_timeouts	disabled
 | 
					lock_timeouts	enabled
 | 
				
			||||||
lock_rec_lock_waits	disabled
 | 
					lock_rec_lock_waits	disabled
 | 
				
			||||||
lock_table_lock_waits	disabled
 | 
					lock_table_lock_waits	disabled
 | 
				
			||||||
lock_rec_lock_requests	disabled
 | 
					lock_rec_lock_requests	disabled
 | 
				
			||||||
@@ -14,30 +13,30 @@ lock_rec_locks	disabled
 | 
				
			|||||||
lock_table_lock_created	disabled
 | 
					lock_table_lock_created	disabled
 | 
				
			||||||
lock_table_lock_removed	disabled
 | 
					lock_table_lock_removed	disabled
 | 
				
			||||||
lock_table_locks	disabled
 | 
					lock_table_locks	disabled
 | 
				
			||||||
lock_row_lock_current_waits	disabled
 | 
					lock_row_lock_current_waits	enabled
 | 
				
			||||||
lock_row_lock_time	disabled
 | 
					lock_row_lock_time	enabled
 | 
				
			||||||
lock_row_lock_time_max	disabled
 | 
					lock_row_lock_time_max	enabled
 | 
				
			||||||
lock_row_lock_waits	disabled
 | 
					lock_row_lock_waits	enabled
 | 
				
			||||||
lock_row_lock_time_avg	disabled
 | 
					lock_row_lock_time_avg	enabled
 | 
				
			||||||
buffer_pool_size	disabled
 | 
					buffer_pool_size	enabled
 | 
				
			||||||
buffer_pool_reads	disabled
 | 
					buffer_pool_reads	enabled
 | 
				
			||||||
buffer_pool_read_requests	disabled
 | 
					buffer_pool_read_requests	enabled
 | 
				
			||||||
buffer_pool_write_requests	disabled
 | 
					buffer_pool_write_requests	enabled
 | 
				
			||||||
buffer_pool_wait_free	disabled
 | 
					buffer_pool_wait_free	enabled
 | 
				
			||||||
buffer_pool_read_ahead	disabled
 | 
					buffer_pool_read_ahead	enabled
 | 
				
			||||||
buffer_pool_read_ahead_evicted	disabled
 | 
					buffer_pool_read_ahead_evicted	enabled
 | 
				
			||||||
buffer_pool_pages_total	disabled
 | 
					buffer_pool_pages_total	enabled
 | 
				
			||||||
buffer_pool_pages_misc	disabled
 | 
					buffer_pool_pages_misc	enabled
 | 
				
			||||||
buffer_pool_pages_data	disabled
 | 
					buffer_pool_pages_data	enabled
 | 
				
			||||||
buffer_pool_bytes_data	disabled
 | 
					buffer_pool_bytes_data	enabled
 | 
				
			||||||
buffer_pool_pages_dirty	disabled
 | 
					buffer_pool_pages_dirty	enabled
 | 
				
			||||||
buffer_pool_bytes_dirty	disabled
 | 
					buffer_pool_bytes_dirty	enabled
 | 
				
			||||||
buffer_pool_pages_free	disabled
 | 
					buffer_pool_pages_free	enabled
 | 
				
			||||||
buffer_pages_created	disabled
 | 
					buffer_pages_created	enabled
 | 
				
			||||||
buffer_pages_written	disabled
 | 
					buffer_pages_written	enabled
 | 
				
			||||||
buffer_pages_read	disabled
 | 
					buffer_pages_read	enabled
 | 
				
			||||||
buffer_data_reads	disabled
 | 
					buffer_data_reads	enabled
 | 
				
			||||||
buffer_data_written	disabled
 | 
					buffer_data_written	enabled
 | 
				
			||||||
buffer_flush_batch_scanned	disabled
 | 
					buffer_flush_batch_scanned	disabled
 | 
				
			||||||
buffer_flush_batch_num_scan	disabled
 | 
					buffer_flush_batch_num_scan	disabled
 | 
				
			||||||
buffer_flush_batch_scanned_per_call	disabled
 | 
					buffer_flush_batch_scanned_per_call	disabled
 | 
				
			||||||
@@ -70,8 +69,8 @@ buffer_flush_background_pages	disabled
 | 
				
			|||||||
buffer_LRU_batch_scanned	disabled
 | 
					buffer_LRU_batch_scanned	disabled
 | 
				
			||||||
buffer_LRU_batch_num_scan	disabled
 | 
					buffer_LRU_batch_num_scan	disabled
 | 
				
			||||||
buffer_LRU_batch_scanned_per_call	disabled
 | 
					buffer_LRU_batch_scanned_per_call	disabled
 | 
				
			||||||
buffer_LRU_batch_flush_total_pages	disabled
 | 
					buffer_LRU_batch_flush_total_pages	enabled
 | 
				
			||||||
buffer_LRU_batch_evict_total_pages	disabled
 | 
					buffer_LRU_batch_evict_total_pages	enabled
 | 
				
			||||||
buffer_LRU_single_flush_failure_count	disabled
 | 
					buffer_LRU_single_flush_failure_count	disabled
 | 
				
			||||||
buffer_LRU_get_free_search	disabled
 | 
					buffer_LRU_get_free_search	disabled
 | 
				
			||||||
buffer_LRU_search_scanned	disabled
 | 
					buffer_LRU_search_scanned	disabled
 | 
				
			||||||
@@ -112,21 +111,21 @@ buffer_page_written_blob	disabled
 | 
				
			|||||||
buffer_page_written_zblob	disabled
 | 
					buffer_page_written_zblob	disabled
 | 
				
			||||||
buffer_page_written_zblob2	disabled
 | 
					buffer_page_written_zblob2	disabled
 | 
				
			||||||
buffer_page_written_other	disabled
 | 
					buffer_page_written_other	disabled
 | 
				
			||||||
os_data_reads	disabled
 | 
					os_data_reads	enabled
 | 
				
			||||||
os_data_writes	disabled
 | 
					os_data_writes	enabled
 | 
				
			||||||
os_data_fsyncs	disabled
 | 
					os_data_fsyncs	enabled
 | 
				
			||||||
os_pending_reads	disabled
 | 
					os_pending_reads	enabled
 | 
				
			||||||
os_pending_writes	disabled
 | 
					os_pending_writes	enabled
 | 
				
			||||||
os_log_bytes_written	disabled
 | 
					os_log_bytes_written	enabled
 | 
				
			||||||
trx_rw_commits	disabled
 | 
					trx_rw_commits	disabled
 | 
				
			||||||
trx_ro_commits	disabled
 | 
					trx_ro_commits	disabled
 | 
				
			||||||
trx_nl_ro_commits	disabled
 | 
					trx_nl_ro_commits	disabled
 | 
				
			||||||
trx_commits_insert_update	disabled
 | 
					trx_commits_insert_update	disabled
 | 
				
			||||||
trx_rollbacks	disabled
 | 
					trx_rollbacks	disabled
 | 
				
			||||||
trx_rollbacks_savepoint	disabled
 | 
					trx_rollbacks_savepoint	disabled
 | 
				
			||||||
trx_rseg_history_len	disabled
 | 
					trx_rseg_history_len	enabled
 | 
				
			||||||
trx_undo_slots_used	disabled
 | 
					trx_undo_slots_used	disabled
 | 
				
			||||||
trx_undo_slots_cached	disabled
 | 
					trx_undo_slots_cached	enabled
 | 
				
			||||||
trx_rseg_current_size	disabled
 | 
					trx_rseg_current_size	disabled
 | 
				
			||||||
purge_del_mark_records	disabled
 | 
					purge_del_mark_records	disabled
 | 
				
			||||||
purge_upd_exist_or_extern_records	disabled
 | 
					purge_upd_exist_or_extern_records	disabled
 | 
				
			||||||
@@ -142,9 +141,9 @@ log_lsn_current	disabled
 | 
				
			|||||||
log_lsn_checkpoint_age	disabled
 | 
					log_lsn_checkpoint_age	disabled
 | 
				
			||||||
log_lsn_buf_pool_oldest	disabled
 | 
					log_lsn_buf_pool_oldest	disabled
 | 
				
			||||||
log_max_modified_age_async	disabled
 | 
					log_max_modified_age_async	disabled
 | 
				
			||||||
log_waits	disabled
 | 
					log_waits	enabled
 | 
				
			||||||
log_write_requests	disabled
 | 
					log_write_requests	enabled
 | 
				
			||||||
log_writes	disabled
 | 
					log_writes	enabled
 | 
				
			||||||
compress_pages_compressed	disabled
 | 
					compress_pages_compressed	disabled
 | 
				
			||||||
compress_pages_decompressed	disabled
 | 
					compress_pages_decompressed	disabled
 | 
				
			||||||
compression_pad_increments	disabled
 | 
					compression_pad_increments	disabled
 | 
				
			||||||
@@ -162,34 +161,34 @@ index_page_merge_successful	disabled
 | 
				
			|||||||
index_page_reorg_attempts	disabled
 | 
					index_page_reorg_attempts	disabled
 | 
				
			||||||
index_page_reorg_successful	disabled
 | 
					index_page_reorg_successful	disabled
 | 
				
			||||||
index_page_discards	disabled
 | 
					index_page_discards	disabled
 | 
				
			||||||
adaptive_hash_searches	disabled
 | 
					adaptive_hash_searches	enabled
 | 
				
			||||||
adaptive_hash_searches_btree	disabled
 | 
					adaptive_hash_searches_btree	enabled
 | 
				
			||||||
adaptive_hash_pages_added	disabled
 | 
					adaptive_hash_pages_added	disabled
 | 
				
			||||||
adaptive_hash_pages_removed	disabled
 | 
					adaptive_hash_pages_removed	disabled
 | 
				
			||||||
adaptive_hash_rows_added	disabled
 | 
					adaptive_hash_rows_added	disabled
 | 
				
			||||||
adaptive_hash_rows_removed	disabled
 | 
					adaptive_hash_rows_removed	disabled
 | 
				
			||||||
adaptive_hash_rows_deleted_no_hash_entry	disabled
 | 
					adaptive_hash_rows_deleted_no_hash_entry	disabled
 | 
				
			||||||
adaptive_hash_rows_updated	disabled
 | 
					adaptive_hash_rows_updated	disabled
 | 
				
			||||||
file_num_open_files	disabled
 | 
					file_num_open_files	enabled
 | 
				
			||||||
ibuf_merges_insert	disabled
 | 
					ibuf_merges_insert	enabled
 | 
				
			||||||
ibuf_merges_delete_mark	disabled
 | 
					ibuf_merges_delete_mark	enabled
 | 
				
			||||||
ibuf_merges_delete	disabled
 | 
					ibuf_merges_delete	enabled
 | 
				
			||||||
ibuf_merges_discard_insert	disabled
 | 
					ibuf_merges_discard_insert	enabled
 | 
				
			||||||
ibuf_merges_discard_delete_mark	disabled
 | 
					ibuf_merges_discard_delete_mark	enabled
 | 
				
			||||||
ibuf_merges_discard_delete	disabled
 | 
					ibuf_merges_discard_delete	enabled
 | 
				
			||||||
ibuf_merges	disabled
 | 
					ibuf_merges	enabled
 | 
				
			||||||
ibuf_size	disabled
 | 
					ibuf_size	enabled
 | 
				
			||||||
innodb_master_thread_sleeps	disabled
 | 
					innodb_master_thread_sleeps	disabled
 | 
				
			||||||
innodb_activity_count	disabled
 | 
					innodb_activity_count	enabled
 | 
				
			||||||
innodb_master_active_loops	disabled
 | 
					innodb_master_active_loops	disabled
 | 
				
			||||||
innodb_master_idle_loops	disabled
 | 
					innodb_master_idle_loops	disabled
 | 
				
			||||||
innodb_log_flush_usec	disabled
 | 
					innodb_log_flush_usec	disabled
 | 
				
			||||||
innodb_dict_lru_usec	disabled
 | 
					innodb_dict_lru_usec	disabled
 | 
				
			||||||
innodb_dict_lru_count_active	disabled
 | 
					innodb_dict_lru_count_active	disabled
 | 
				
			||||||
innodb_dict_lru_count_idle	disabled
 | 
					innodb_dict_lru_count_idle	disabled
 | 
				
			||||||
innodb_dblwr_writes	disabled
 | 
					innodb_dblwr_writes	enabled
 | 
				
			||||||
innodb_dblwr_pages_written	disabled
 | 
					innodb_dblwr_pages_written	enabled
 | 
				
			||||||
innodb_page_size	disabled
 | 
					innodb_page_size	enabled
 | 
				
			||||||
ddl_background_drop_indexes	disabled
 | 
					ddl_background_drop_indexes	disabled
 | 
				
			||||||
ddl_online_create_index	disabled
 | 
					ddl_online_create_index	disabled
 | 
				
			||||||
ddl_pending_alter_table	disabled
 | 
					ddl_pending_alter_table	disabled
 | 
				
			||||||
@@ -199,6 +198,9 @@ icp_attempts	disabled
 | 
				
			|||||||
icp_no_match	disabled
 | 
					icp_no_match	disabled
 | 
				
			||||||
icp_out_of_range	disabled
 | 
					icp_out_of_range	disabled
 | 
				
			||||||
icp_match	disabled
 | 
					icp_match	disabled
 | 
				
			||||||
 | 
					set global innodb_monitor_disable = All;
 | 
				
			||||||
 | 
					select name from information_schema.innodb_metrics where enabled;
 | 
				
			||||||
 | 
					name
 | 
				
			||||||
set global innodb_monitor_enable = all;
 | 
					set global innodb_monitor_enable = all;
 | 
				
			||||||
select name from information_schema.innodb_metrics where not enabled;
 | 
					select name from information_schema.innodb_metrics where not enabled;
 | 
				
			||||||
name
 | 
					name
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,4 +26,60 @@ UPDATE mysql.innodb_table_stats SET last_update=NULL WHERE table_name='t1';
 | 
				
			|||||||
XA END 'test';
 | 
					XA END 'test';
 | 
				
			||||||
XA ROLLBACK 'test';
 | 
					XA ROLLBACK 'test';
 | 
				
			||||||
DROP TABLE t1;
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Testing a non-default format: Field_timestamp0 - UINT4 based
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					SET @@global.mysql56_temporal_format=0;
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW COLUMNS FROM mysql.innodb_table_stats LIKE 'last_update';
 | 
				
			||||||
 | 
					Field	Type	Null	Key	Default	Extra
 | 
				
			||||||
 | 
					last_update	timestamp /* mariadb-5.3 */	NO		current_timestamp()	on update current_timestamp()
 | 
				
			||||||
 | 
					SHOW COLUMNS FROM mysql.innodb_index_stats LIKE 'last_update';
 | 
				
			||||||
 | 
					Field	Type	Null	Key	Default	Extra
 | 
				
			||||||
 | 
					last_update	timestamp /* mariadb-5.3 */	NO		current_timestamp()	on update current_timestamp()
 | 
				
			||||||
 | 
					CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1;
 | 
				
			||||||
 | 
					SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_table_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1';
 | 
				
			||||||
 | 
					TIMESTAMPDIFF(DAY,last_update,now())<=1
 | 
				
			||||||
 | 
					1
 | 
				
			||||||
 | 
					SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_index_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1' AND stat_name='size';
 | 
				
			||||||
 | 
					TIMESTAMPDIFF(DAY,last_update,now())<=1
 | 
				
			||||||
 | 
					1
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Now as the table t1 is dropped, expect no statistics
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					SELECT * FROM mysql.innodb_table_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1';
 | 
				
			||||||
 | 
					database_name	table_name	last_update	n_rows	clustered_index_size	sum_of_other_index_sizes
 | 
				
			||||||
 | 
					SELECT * FROM mysql.innodb_index_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1' AND stat_name='size';
 | 
				
			||||||
 | 
					database_name	table_name	index_name	last_update	stat_name	stat_value	sample_size	stat_description
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Testing with the default format: Field_timestampf - BINARY(4) based with the UNSIGNED_FLAG
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					SET @@global.mysql56_temporal_format=1;
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW COLUMNS FROM mysql.innodb_table_stats LIKE 'last_update';
 | 
				
			||||||
 | 
					Field	Type	Null	Key	Default	Extra
 | 
				
			||||||
 | 
					last_update	timestamp	NO		current_timestamp()	on update current_timestamp()
 | 
				
			||||||
 | 
					SHOW COLUMNS FROM mysql.innodb_index_stats LIKE 'last_update';
 | 
				
			||||||
 | 
					Field	Type	Null	Key	Default	Extra
 | 
				
			||||||
 | 
					last_update	timestamp	NO		current_timestamp()	on update current_timestamp()
 | 
				
			||||||
 | 
					CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1;
 | 
				
			||||||
 | 
					SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_table_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1';
 | 
				
			||||||
 | 
					TIMESTAMPDIFF(DAY,last_update,now())<=1
 | 
				
			||||||
 | 
					1
 | 
				
			||||||
 | 
					SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_index_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1' AND stat_name='size';
 | 
				
			||||||
 | 
					TIMESTAMPDIFF(DAY,last_update,now())<=1
 | 
				
			||||||
 | 
					1
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
# End of 10.6 tests
 | 
					# End of 10.6 tests
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,12 +5,14 @@
 | 
				
			|||||||
# sys_vars.innodb_monitor_enable_basic
 | 
					# sys_vars.innodb_monitor_enable_basic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--source include/have_innodb.inc
 | 
					--source include/have_innodb.inc
 | 
				
			||||||
set global innodb_monitor_disable = All;
 | 
					 | 
				
			||||||
# Test turn on/off the monitor counter  with "all" option
 | 
					# Test turn on/off the monitor counter  with "all" option
 | 
				
			||||||
# By default, they will be off.
 | 
					# By default, they will be off.
 | 
				
			||||||
select name, if(enabled,'enabled','disabled') status
 | 
					select name, if(enabled,'enabled','disabled') status
 | 
				
			||||||
from information_schema.innodb_metrics;
 | 
					from information_schema.innodb_metrics;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set global innodb_monitor_disable = All;
 | 
				
			||||||
 | 
					select name from information_schema.innodb_metrics where enabled;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Turn on all monitor counters
 | 
					# Turn on all monitor counters
 | 
				
			||||||
set global innodb_monitor_enable = all;
 | 
					set global innodb_monitor_enable = all;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,4 +28,57 @@ XA END 'test';
 | 
				
			|||||||
XA ROLLBACK 'test';
 | 
					XA ROLLBACK 'test';
 | 
				
			||||||
DROP TABLE t1;
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The following tests demonstrate that these columns:
 | 
				
			||||||
 | 
					# - innodb_table_stats.last_update
 | 
				
			||||||
 | 
					# - innodb_index_stats.last_update
 | 
				
			||||||
 | 
					# have sane values close to NOW(), rather than any garbage,
 | 
				
			||||||
 | 
					# with all TIMESTAMP formats.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # Testing a non-default format: Field_timestamp0 - UINT4 based
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET @@global.mysql56_temporal_format=0;
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW COLUMNS FROM mysql.innodb_table_stats LIKE 'last_update';
 | 
				
			||||||
 | 
					SHOW COLUMNS FROM mysql.innodb_index_stats LIKE 'last_update';
 | 
				
			||||||
 | 
					CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_table_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1';
 | 
				
			||||||
 | 
					SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_index_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1' AND stat_name='size';
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # Now as the table t1 is dropped, expect no statistics
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SELECT * FROM mysql.innodb_table_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1';
 | 
				
			||||||
 | 
					SELECT * FROM mysql.innodb_index_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1' AND stat_name='size';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # Testing with the default format: Field_timestampf - BINARY(4) based with the UNSIGNED_FLAG
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET @@global.mysql56_temporal_format=1;
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW COLUMNS FROM mysql.innodb_table_stats LIKE 'last_update';
 | 
				
			||||||
 | 
					SHOW COLUMNS FROM mysql.innodb_index_stats LIKE 'last_update';
 | 
				
			||||||
 | 
					CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1;
 | 
				
			||||||
 | 
					SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_table_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1';
 | 
				
			||||||
 | 
					SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_index_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1' AND stat_name='size';
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--echo # End of 10.6 tests
 | 
					--echo # End of 10.6 tests
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								mysql-test/suite/parts/r/partition_purge.result
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								mysql-test/suite/parts/r/partition_purge.result
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					CREATE TABLE t1(f1 INT, f2 INT, INDEX(f1))ENGINE=InnoDB
 | 
				
			||||||
 | 
					PARTITION BY LIST(f1) (
 | 
				
			||||||
 | 
					PARTITION p1 VALUES in (1, 2, 3),
 | 
				
			||||||
 | 
					PARTITION p2 VALUES in (4, 5, 6));
 | 
				
			||||||
 | 
					INSERT INTO t1 VALUES(1, 1), (1, 1), (6, 1);
 | 
				
			||||||
 | 
					connect con1,localhost,root,,,;
 | 
				
			||||||
 | 
					START TRANSACTION WITH CONSISTENT SNAPSHOT;
 | 
				
			||||||
 | 
					connect con2,localhost,root,,,;
 | 
				
			||||||
 | 
					SET DEBUG_SYNC="innodb_rollback_inplace_alter_table SIGNAL default_resume WAIT_FOR alter_resume";
 | 
				
			||||||
 | 
					ALTER TABLE t1 ADD UNIQUE INDEX(f1);
 | 
				
			||||||
 | 
					connection default;
 | 
				
			||||||
 | 
					set DEBUG_SYNC="now WAIT_FOR default_resume";
 | 
				
			||||||
 | 
					SET DEBUG_SYNC="innodb_row_update_for_mysql_begin SIGNAL alter_resume WAIT_FOR alter_finish";
 | 
				
			||||||
 | 
					DELETE FROM t1;
 | 
				
			||||||
 | 
					connection con2;
 | 
				
			||||||
 | 
					ERROR 23000: Duplicate entry '1' for key 'f1_2'
 | 
				
			||||||
 | 
					SET DEBUG_SYNC="now SIGNAL alter_finish";
 | 
				
			||||||
 | 
					connection default;
 | 
				
			||||||
 | 
					connection con1;
 | 
				
			||||||
 | 
					commit;
 | 
				
			||||||
 | 
					connection default;
 | 
				
			||||||
 | 
					disconnect con1;
 | 
				
			||||||
 | 
					disconnect con2;
 | 
				
			||||||
 | 
					InnoDB		0 transactions not purged
 | 
				
			||||||
 | 
					drop table t1;
 | 
				
			||||||
 | 
					SET DEBUG_SYNC=reset;
 | 
				
			||||||
							
								
								
									
										1
									
								
								mysql-test/suite/parts/t/partition_purge.opt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								mysql-test/suite/parts/t/partition_purge.opt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					--innodb_purge_threads=1
 | 
				
			||||||
							
								
								
									
										37
									
								
								mysql-test/suite/parts/t/partition_purge.test
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								mysql-test/suite/parts/t/partition_purge.test
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
				
			|||||||
 | 
					--source include/have_innodb.inc
 | 
				
			||||||
 | 
					--source include/have_partition.inc
 | 
				
			||||||
 | 
					--source include/have_debug.inc
 | 
				
			||||||
 | 
					--source include/have_debug_sync.inc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CREATE TABLE t1(f1 INT, f2 INT, INDEX(f1))ENGINE=InnoDB
 | 
				
			||||||
 | 
					                PARTITION BY LIST(f1) (
 | 
				
			||||||
 | 
					                        PARTITION p1 VALUES in (1, 2, 3),
 | 
				
			||||||
 | 
					                        PARTITION p2 VALUES in (4, 5, 6));
 | 
				
			||||||
 | 
					INSERT INTO t1 VALUES(1, 1), (1, 1), (6, 1);
 | 
				
			||||||
 | 
					connect(con1,localhost,root,,,);
 | 
				
			||||||
 | 
					START TRANSACTION WITH CONSISTENT SNAPSHOT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					connect(con2,localhost,root,,,);
 | 
				
			||||||
 | 
					SET DEBUG_SYNC="innodb_rollback_inplace_alter_table SIGNAL default_resume WAIT_FOR alter_resume";
 | 
				
			||||||
 | 
					send ALTER TABLE t1 ADD UNIQUE INDEX(f1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					connection default;
 | 
				
			||||||
 | 
					set DEBUG_SYNC="now WAIT_FOR default_resume";
 | 
				
			||||||
 | 
					SET DEBUG_SYNC="innodb_row_update_for_mysql_begin SIGNAL alter_resume WAIT_FOR alter_finish";
 | 
				
			||||||
 | 
					send DELETE FROM t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					connection con2;
 | 
				
			||||||
 | 
					--error ER_DUP_ENTRY
 | 
				
			||||||
 | 
					reap;
 | 
				
			||||||
 | 
					SET DEBUG_SYNC="now SIGNAL alter_finish";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					connection default;
 | 
				
			||||||
 | 
					reap;
 | 
				
			||||||
 | 
					connection con1;
 | 
				
			||||||
 | 
					commit;
 | 
				
			||||||
 | 
					connection default;
 | 
				
			||||||
 | 
					disconnect con1;
 | 
				
			||||||
 | 
					disconnect con2;
 | 
				
			||||||
 | 
					--source ../../innodb/include/wait_all_purged.inc
 | 
				
			||||||
 | 
					drop table t1;
 | 
				
			||||||
 | 
					SET DEBUG_SYNC=reset;
 | 
				
			||||||
							
								
								
									
										17
									
								
								plugin/type_mysql_timestamp/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								plugin/type_mysql_timestamp/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					# Copyright (c) 2019, MariaDB corporation
 | 
				
			||||||
 | 
					# 
 | 
				
			||||||
 | 
					# This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation; version 2 of the License.
 | 
				
			||||||
 | 
					# 
 | 
				
			||||||
 | 
					# This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU General Public License for more details.
 | 
				
			||||||
 | 
					# 
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					# along with this program; if not, write to the Free Software
 | 
				
			||||||
 | 
					# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  USA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MYSQL_ADD_PLUGIN(type_mysql_timestamp plugin.cc RECOMPILE_FOR_EMBEDDED
 | 
				
			||||||
 | 
					                 MODULE_ONLY COMPONENT Test)
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					--plugin-load-add=$TYPE_MYSQL_TIMESTAMP_SO
 | 
				
			||||||
@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					package My::Suite::Type_test;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@ISA = qw(My::Suite);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					return "No TYPE_TEST plugin" unless $ENV{TYPE_MYSQL_TIMESTAMP_SO};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sub is_default { 1 }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bless { };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					#
 | 
				
			||||||
 | 
					# MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					SELECT
 | 
				
			||||||
 | 
					PLUGIN_NAME,
 | 
				
			||||||
 | 
					PLUGIN_VERSION,
 | 
				
			||||||
 | 
					PLUGIN_STATUS,
 | 
				
			||||||
 | 
					PLUGIN_TYPE,
 | 
				
			||||||
 | 
					PLUGIN_AUTHOR,
 | 
				
			||||||
 | 
					PLUGIN_DESCRIPTION,
 | 
				
			||||||
 | 
					PLUGIN_LICENSE,
 | 
				
			||||||
 | 
					PLUGIN_MATURITY,
 | 
				
			||||||
 | 
					PLUGIN_AUTH_VERSION
 | 
				
			||||||
 | 
					FROM INFORMATION_SCHEMA.PLUGINS
 | 
				
			||||||
 | 
					WHERE PLUGIN_TYPE='DATA TYPE'
 | 
				
			||||||
 | 
					    AND PLUGIN_NAME LIKE 'type_mysql_timestamp';
 | 
				
			||||||
 | 
					PLUGIN_NAME	type_mysql_timestamp
 | 
				
			||||||
 | 
					PLUGIN_VERSION	1.0
 | 
				
			||||||
 | 
					PLUGIN_STATUS	ACTIVE
 | 
				
			||||||
 | 
					PLUGIN_TYPE	DATA TYPE
 | 
				
			||||||
 | 
					PLUGIN_AUTHOR	MariaDB Corporation
 | 
				
			||||||
 | 
					PLUGIN_DESCRIPTION	Data type TYPE_MYSQL_TIMESTAMP
 | 
				
			||||||
 | 
					PLUGIN_LICENSE	GPL
 | 
				
			||||||
 | 
					PLUGIN_MATURITY	Experimental
 | 
				
			||||||
 | 
					PLUGIN_AUTH_VERSION	1.0
 | 
				
			||||||
 | 
					CREATE TABLE t1 (a TYPE_MYSQL_TIMESTAMP);
 | 
				
			||||||
 | 
					SHOW CREATE TABLE t1;
 | 
				
			||||||
 | 
					Table	Create Table
 | 
				
			||||||
 | 
					t1	CREATE TABLE `t1` (
 | 
				
			||||||
 | 
					  `a` type_mysql_timestamp NULL DEFAULT NULL
 | 
				
			||||||
 | 
					) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					CREATE TABLE t1 (a TIMESTAMP);
 | 
				
			||||||
 | 
					SHOW CREATE TABLE t1;
 | 
				
			||||||
 | 
					Table	Create Table
 | 
				
			||||||
 | 
					t1	CREATE TABLE `t1` (
 | 
				
			||||||
 | 
					  `a` timestamp NULL DEFAULT NULL
 | 
				
			||||||
 | 
					) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
 | 
				
			||||||
 | 
					ALTER TABLE t1 MODIFY a TYPE_MYSQL_TIMESTAMP;
 | 
				
			||||||
 | 
					SHOW CREATE TABLE t1;
 | 
				
			||||||
 | 
					Table	Create Table
 | 
				
			||||||
 | 
					t1	CREATE TABLE `t1` (
 | 
				
			||||||
 | 
					  `a` type_mysql_timestamp NULL DEFAULT NULL
 | 
				
			||||||
 | 
					) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					--source include/have_innodb.inc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--vertical_results
 | 
				
			||||||
 | 
					SELECT
 | 
				
			||||||
 | 
					  PLUGIN_NAME,
 | 
				
			||||||
 | 
					  PLUGIN_VERSION,
 | 
				
			||||||
 | 
					  PLUGIN_STATUS,
 | 
				
			||||||
 | 
					  PLUGIN_TYPE,
 | 
				
			||||||
 | 
					  PLUGIN_AUTHOR,
 | 
				
			||||||
 | 
					  PLUGIN_DESCRIPTION,
 | 
				
			||||||
 | 
					  PLUGIN_LICENSE,
 | 
				
			||||||
 | 
					  PLUGIN_MATURITY,
 | 
				
			||||||
 | 
					  PLUGIN_AUTH_VERSION
 | 
				
			||||||
 | 
					FROM INFORMATION_SCHEMA.PLUGINS
 | 
				
			||||||
 | 
					  WHERE PLUGIN_TYPE='DATA TYPE'
 | 
				
			||||||
 | 
					    AND PLUGIN_NAME LIKE 'type_mysql_timestamp';
 | 
				
			||||||
 | 
					--horizontal_results
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CREATE TABLE t1 (a TYPE_MYSQL_TIMESTAMP);
 | 
				
			||||||
 | 
					SHOW CREATE TABLE t1;
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CREATE TABLE t1 (a TIMESTAMP);
 | 
				
			||||||
 | 
					SHOW CREATE TABLE t1;
 | 
				
			||||||
 | 
					ALTER TABLE t1 MODIFY a TYPE_MYSQL_TIMESTAMP;
 | 
				
			||||||
 | 
					SHOW CREATE TABLE t1;
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
@@ -0,0 +1,108 @@
 | 
				
			|||||||
 | 
					#
 | 
				
			||||||
 | 
					# MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					SET @@global.innodb_stats_persistent=0;
 | 
				
			||||||
 | 
					SHOW CREATE TABLE mysql.innodb_table_stats;
 | 
				
			||||||
 | 
					Table	Create Table
 | 
				
			||||||
 | 
					innodb_table_stats	CREATE TABLE `innodb_table_stats` (
 | 
				
			||||||
 | 
					  `database_name` varchar(64) NOT NULL,
 | 
				
			||||||
 | 
					  `table_name` varchar(199) NOT NULL,
 | 
				
			||||||
 | 
					  `last_update` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
 | 
				
			||||||
 | 
					  `n_rows` bigint(20) unsigned NOT NULL,
 | 
				
			||||||
 | 
					  `clustered_index_size` bigint(20) unsigned NOT NULL,
 | 
				
			||||||
 | 
					  `sum_of_other_index_sizes` bigint(20) unsigned NOT NULL,
 | 
				
			||||||
 | 
					  PRIMARY KEY (`database_name`,`table_name`)
 | 
				
			||||||
 | 
					) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_table_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW CREATE TABLE mysql.innodb_table_stats;
 | 
				
			||||||
 | 
					Table	Create Table
 | 
				
			||||||
 | 
					innodb_table_stats	CREATE TABLE `innodb_table_stats` (
 | 
				
			||||||
 | 
					  `database_name` varchar(64) NOT NULL,
 | 
				
			||||||
 | 
					  `table_name` varchar(199) NOT NULL,
 | 
				
			||||||
 | 
					  `last_update` type_mysql_timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
 | 
				
			||||||
 | 
					  `n_rows` bigint(20) unsigned NOT NULL,
 | 
				
			||||||
 | 
					  `clustered_index_size` bigint(20) unsigned NOT NULL,
 | 
				
			||||||
 | 
					  `sum_of_other_index_sizes` bigint(20) unsigned NOT NULL,
 | 
				
			||||||
 | 
					  PRIMARY KEY (`database_name`,`table_name`)
 | 
				
			||||||
 | 
					) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_index_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW CREATE TABLE mysql.innodb_index_stats;
 | 
				
			||||||
 | 
					Table	Create Table
 | 
				
			||||||
 | 
					innodb_index_stats	CREATE TABLE `innodb_index_stats` (
 | 
				
			||||||
 | 
					  `database_name` varchar(64) NOT NULL,
 | 
				
			||||||
 | 
					  `table_name` varchar(199) NOT NULL,
 | 
				
			||||||
 | 
					  `index_name` varchar(64) NOT NULL,
 | 
				
			||||||
 | 
					  `last_update` type_mysql_timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
 | 
				
			||||||
 | 
					  `stat_name` varchar(64) NOT NULL,
 | 
				
			||||||
 | 
					  `stat_value` bigint(20) unsigned NOT NULL,
 | 
				
			||||||
 | 
					  `sample_size` bigint(20) unsigned DEFAULT NULL,
 | 
				
			||||||
 | 
					  `stat_description` varchar(1024) NOT NULL,
 | 
				
			||||||
 | 
					  PRIMARY KEY (`database_name`,`table_name`,`index_name`,`stat_name`)
 | 
				
			||||||
 | 
					) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
 | 
				
			||||||
 | 
					SET @@global.innodb_stats_persistent=1;
 | 
				
			||||||
 | 
					CREATE TABLE t1 (a INT, KEY(a)) ENGINE=InnoDB;
 | 
				
			||||||
 | 
					INSERT INTO t1 VALUES (10);
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					SET @@global.innodb_stats_persistent=0;
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW CREATE TABLE mysql.innodb_table_stats;
 | 
				
			||||||
 | 
					Table	Create Table
 | 
				
			||||||
 | 
					innodb_table_stats	CREATE TABLE `innodb_table_stats` (
 | 
				
			||||||
 | 
					  `database_name` varchar(64) NOT NULL,
 | 
				
			||||||
 | 
					  `table_name` varchar(199) NOT NULL,
 | 
				
			||||||
 | 
					  `last_update` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
 | 
				
			||||||
 | 
					  `n_rows` bigint(20) unsigned NOT NULL,
 | 
				
			||||||
 | 
					  `clustered_index_size` bigint(20) unsigned NOT NULL,
 | 
				
			||||||
 | 
					  `sum_of_other_index_sizes` bigint(20) unsigned NOT NULL,
 | 
				
			||||||
 | 
					  PRIMARY KEY (`database_name`,`table_name`)
 | 
				
			||||||
 | 
					) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW CREATE TABLE mysql.innodb_index_stats;
 | 
				
			||||||
 | 
					Table	Create Table
 | 
				
			||||||
 | 
					innodb_index_stats	CREATE TABLE `innodb_index_stats` (
 | 
				
			||||||
 | 
					  `database_name` varchar(64) NOT NULL,
 | 
				
			||||||
 | 
					  `table_name` varchar(199) NOT NULL,
 | 
				
			||||||
 | 
					  `index_name` varchar(64) NOT NULL,
 | 
				
			||||||
 | 
					  `last_update` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
 | 
				
			||||||
 | 
					  `stat_name` varchar(64) NOT NULL,
 | 
				
			||||||
 | 
					  `stat_value` bigint(20) unsigned NOT NULL,
 | 
				
			||||||
 | 
					  `sample_size` bigint(20) unsigned DEFAULT NULL,
 | 
				
			||||||
 | 
					  `stat_description` varchar(1024) NOT NULL,
 | 
				
			||||||
 | 
					  PRIMARY KEY (`database_name`,`table_name`,`index_name`,`stat_name`)
 | 
				
			||||||
 | 
					) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin STATS_PERSISTENT=0
 | 
				
			||||||
 | 
					SET @@global.innodb_stats_persistent=1;
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Testing MySQL-5.6-alike Field_timestampf: BINARY(4) based, without UNSIGNED_FLAG
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_table_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_index_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW COLUMNS FROM mysql.innodb_table_stats LIKE 'last_update';
 | 
				
			||||||
 | 
					Field	Type	Null	Key	Default	Extra
 | 
				
			||||||
 | 
					last_update	type_mysql_timestamp	NO		current_timestamp()	on update current_timestamp()
 | 
				
			||||||
 | 
					SHOW COLUMNS FROM mysql.innodb_index_stats LIKE 'last_update';
 | 
				
			||||||
 | 
					Field	Type	Null	Key	Default	Extra
 | 
				
			||||||
 | 
					last_update	type_mysql_timestamp	NO		current_timestamp()	on update current_timestamp()
 | 
				
			||||||
 | 
					CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1;
 | 
				
			||||||
 | 
					SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_table_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1';
 | 
				
			||||||
 | 
					TIMESTAMPDIFF(DAY,last_update,now())<=1
 | 
				
			||||||
 | 
					1
 | 
				
			||||||
 | 
					SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_index_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1' AND stat_name='size';
 | 
				
			||||||
 | 
					TIMESTAMPDIFF(DAY,last_update,now())<=1
 | 
				
			||||||
 | 
					1
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Now as the table t1 is dropped, expect no statistics
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					SELECT * FROM mysql.innodb_table_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1';
 | 
				
			||||||
 | 
					database_name	table_name	last_update	n_rows	clustered_index_size	sum_of_other_index_sizes
 | 
				
			||||||
 | 
					SELECT * FROM mysql.innodb_index_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1' AND stat_name='size';
 | 
				
			||||||
 | 
					database_name	table_name	index_name	last_update	stat_name	stat_value	sample_size	stat_description
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Restore the structure of the tables
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					--source include/have_innodb.inc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # MDEV-30483 After upgrade to 10.6 from Mysql 5.7 seeing "InnoDB: Column last_update in table mysql.innodb_table_stats is BINARY(4) NOT NULL but should be INT UNSIGNED NOT NULL"
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET @@global.innodb_stats_persistent=0;
 | 
				
			||||||
 | 
					SHOW CREATE TABLE mysql.innodb_table_stats;
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_table_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW CREATE TABLE mysql.innodb_table_stats;
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_index_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW CREATE TABLE mysql.innodb_index_stats;
 | 
				
			||||||
 | 
					SET @@global.innodb_stats_persistent=1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CREATE TABLE t1 (a INT, KEY(a)) ENGINE=InnoDB;
 | 
				
			||||||
 | 
					INSERT INTO t1 VALUES (10);
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET @@global.innodb_stats_persistent=0;
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW CREATE TABLE mysql.innodb_table_stats;
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW CREATE TABLE mysql.innodb_index_stats;
 | 
				
			||||||
 | 
					SET @@global.innodb_stats_persistent=1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The following test demonstrate that these columns:
 | 
				
			||||||
 | 
					# - innodb_table_stats.last_update
 | 
				
			||||||
 | 
					# - innodb_index_stats.last_update
 | 
				
			||||||
 | 
					# have sane values close to NOW(), rather than any garbage,
 | 
				
			||||||
 | 
					# with MySQL-alike Field_timestampf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # Testing MySQL-5.6-alike Field_timestampf: BINARY(4) based, without UNSIGNED_FLAG
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_table_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_index_stats MODIFY last_update TYPE_MYSQL_TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					SHOW COLUMNS FROM mysql.innodb_table_stats LIKE 'last_update';
 | 
				
			||||||
 | 
					SHOW COLUMNS FROM mysql.innodb_index_stats LIKE 'last_update';
 | 
				
			||||||
 | 
					CREATE TABLE t1 (a INT PRIMARY KEY) ENGINE=InnoDB STATS_PERSISTENT=1;
 | 
				
			||||||
 | 
					SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_table_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1';
 | 
				
			||||||
 | 
					SELECT TIMESTAMPDIFF(DAY,last_update,now())<=1 FROM mysql.innodb_index_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1' AND stat_name='size';
 | 
				
			||||||
 | 
					DROP TABLE t1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # Now as the table t1 is dropped, expect no statistics
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SELECT * FROM mysql.innodb_table_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1';
 | 
				
			||||||
 | 
					SELECT * FROM mysql.innodb_index_stats
 | 
				
			||||||
 | 
					WHERE database_name='test' AND table_name='t1' AND stat_name='size';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					--echo # Restore the structure of the tables
 | 
				
			||||||
 | 
					--echo #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_table_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
 | 
					ALTER TABLE mysql.innodb_index_stats MODIFY last_update TIMESTAMP NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp();
 | 
				
			||||||
							
								
								
									
										177
									
								
								plugin/type_mysql_timestamp/plugin.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								plugin/type_mysql_timestamp/plugin.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,177 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					   Copyright (c) 2023, MariaDB Corporation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					   it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					   the Free Software Foundation; version 2 of the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					   GNU General Public License for more details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					   along with this program; if not, write to the Free Software
 | 
				
			||||||
 | 
					   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <my_global.h>
 | 
				
			||||||
 | 
					#include <sql_class.h>
 | 
				
			||||||
 | 
					#include <mysql/plugin_data_type.h>
 | 
				
			||||||
 | 
					#include "sql_type.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Type_collection_local: public Type_collection
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					protected:
 | 
				
			||||||
 | 
					  const Type_handler *aggregate_common(const Type_handler *h1,
 | 
				
			||||||
 | 
					                                       const Type_handler *h2) const;
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  const Type_handler *handler_by_name(const LEX_CSTRING &name) const override
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Type_handler *aggregate_for_result(const Type_handler *h1,
 | 
				
			||||||
 | 
					                                           const Type_handler *h2)
 | 
				
			||||||
 | 
					                                           const override
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    return aggregate_common(h1, h2);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Type_handler *aggregate_for_comparison(const Type_handler *h1,
 | 
				
			||||||
 | 
					                                               const Type_handler *h2)
 | 
				
			||||||
 | 
					                                               const override
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    return aggregate_common(h1, h2);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Type_handler *aggregate_for_min_max(const Type_handler *h1,
 | 
				
			||||||
 | 
					                                            const Type_handler *h2)
 | 
				
			||||||
 | 
					                                            const override
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    return aggregate_common(h1, h2);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const Type_handler *aggregate_for_num_op(const Type_handler *h1,
 | 
				
			||||||
 | 
					                                           const Type_handler *h2)
 | 
				
			||||||
 | 
					                                           const override
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    return aggregate_common(h1, h2);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static Type_collection_local type_collection_local;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  A more MySQL compatible Field:
 | 
				
			||||||
 | 
					  it does not set the UNSIGNED_FLAG.
 | 
				
			||||||
 | 
					  This is how MySQL's Field_timestampf works.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					class Field_mysql_timestampf :public Field_timestampf
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  Field_mysql_timestampf(const LEX_CSTRING &name,
 | 
				
			||||||
 | 
					                         const Record_addr &addr,
 | 
				
			||||||
 | 
					                         enum utype unireg_check_arg,
 | 
				
			||||||
 | 
					                         TABLE_SHARE *share, decimal_digits_t dec_arg)
 | 
				
			||||||
 | 
					   :Field_timestampf(addr.ptr(), addr.null_ptr(), addr.null_bit(),
 | 
				
			||||||
 | 
					                     unireg_check_arg, &name, share, dec_arg)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    flags&= ~UNSIGNED_FLAG; // MySQL compatibility
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  void sql_type(String &str) const override
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    sql_type_opt_dec_comment(str,
 | 
				
			||||||
 | 
					                             Field_mysql_timestampf::type_handler()->name(),
 | 
				
			||||||
 | 
					                             dec, type_version_mysql56());
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  const Type_handler *type_handler() const override;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Type_handler_mysql_timestamp2: public Type_handler_timestamp2
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  const Type_collection *type_collection() const override
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    return &type_collection_local;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *root,
 | 
				
			||||||
 | 
					                                   const LEX_CSTRING *name,
 | 
				
			||||||
 | 
					                                   const Record_addr &rec, const Bit_addr &bit,
 | 
				
			||||||
 | 
					                                   const Column_definition_attributes *attr,
 | 
				
			||||||
 | 
					                                   uint32 flags) const override
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    return new (root)
 | 
				
			||||||
 | 
					      Field_mysql_timestampf(*name, rec, attr->unireg_check, share,
 | 
				
			||||||
 | 
					                             attr->temporal_dec(MAX_DATETIME_WIDTH));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  void Column_definition_implicit_upgrade(Column_definition *c) const override
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					      Suppress the automatic upgrade depending on opt_mysql56_temporal_format,
 | 
				
			||||||
 | 
					      derived from Type_handler_timestamp_common.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static Type_handler_mysql_timestamp2 type_handler_mysql_timestamp2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Type_handler *Field_mysql_timestampf::type_handler() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return &type_handler_mysql_timestamp2;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const Type_handler *
 | 
				
			||||||
 | 
					Type_collection_local::aggregate_common(const Type_handler *h1,
 | 
				
			||||||
 | 
					                                        const Type_handler *h2) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  if (h1 == h2)
 | 
				
			||||||
 | 
					    return h1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static const Type_aggregator::Pair agg[]=
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      &type_handler_timestamp2,
 | 
				
			||||||
 | 
					      &type_handler_mysql_timestamp2,
 | 
				
			||||||
 | 
					      &type_handler_mysql_timestamp2
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {NULL,NULL,NULL}
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return Type_aggregator::find_handler_in_array(agg, h1, h2, true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct st_mariadb_data_type plugin_descriptor_type_mysql_timestamp=
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  MariaDB_DATA_TYPE_INTERFACE_VERSION,
 | 
				
			||||||
 | 
					  &type_handler_mysql_timestamp2
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					maria_declare_plugin(type_mysql_timestamp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  MariaDB_DATA_TYPE_PLUGIN,     // the plugin type (see include/mysql/plugin.h)
 | 
				
			||||||
 | 
					  &plugin_descriptor_type_mysql_timestamp, // pointer to type-specific plugin descriptor
 | 
				
			||||||
 | 
					  "type_mysql_timestamp",       // plugin name
 | 
				
			||||||
 | 
					  "MariaDB Corporation",        // plugin author
 | 
				
			||||||
 | 
					  "Data type TYPE_MYSQL_TIMESTAMP", // the plugin description
 | 
				
			||||||
 | 
					  PLUGIN_LICENSE_GPL,           // the plugin license (see include/mysql/plugin.h)
 | 
				
			||||||
 | 
					  0,                            // Pointer to plugin initialization function
 | 
				
			||||||
 | 
					  0,                            // Pointer to plugin deinitialization function
 | 
				
			||||||
 | 
					  0x0100,                       // Numeric version 0xAABB means AA.BB version
 | 
				
			||||||
 | 
					  NULL,                         // Status variables
 | 
				
			||||||
 | 
					  NULL,                         // System variables
 | 
				
			||||||
 | 
					  "1.0",                        // String version representation
 | 
				
			||||||
 | 
					  MariaDB_PLUGIN_MATURITY_EXPERIMENTAL // Maturity(see include/mysql/plugin.h)*/
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					maria_declare_plugin_end;
 | 
				
			||||||
@@ -3354,7 +3354,7 @@ public:
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
  TIMESTAMP(0..6) - MySQL56 version
 | 
					  TIMESTAMP(0..6) - MySQL56 version
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
class Field_timestampf final :public Field_timestamp_with_dec {
 | 
					class Field_timestampf :public Field_timestamp_with_dec {
 | 
				
			||||||
  void store_TIMEVAL(const timeval &tv) override;
 | 
					  void store_TIMEVAL(const timeval &tv) override;
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  Field_timestampf(uchar *ptr_arg,
 | 
					  Field_timestampf(uchar *ptr_arg,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7972,6 +7972,9 @@ Compare_keys handler::compare_key_parts(const Field &old_field,
 | 
				
			|||||||
  concurrent accesses. And it's an overkill to take LOCK_plugin and
 | 
					  concurrent accesses. And it's an overkill to take LOCK_plugin and
 | 
				
			||||||
  iterate the whole installed_htons[] array every time.
 | 
					  iterate the whole installed_htons[] array every time.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @note Object victim_thd is not guaranteed to exist after this
 | 
				
			||||||
 | 
					        function returns.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @param bf_thd       brute force THD asking for the abort
 | 
					  @param bf_thd       brute force THD asking for the abort
 | 
				
			||||||
  @param victim_thd   victim THD to be aborted
 | 
					  @param victim_thd   victim THD to be aborted
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -7985,6 +7988,8 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal)
 | 
				
			|||||||
  if (!WSREP(bf_thd) &&
 | 
					  if (!WSREP(bf_thd) &&
 | 
				
			||||||
      !(bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU &&
 | 
					      !(bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU &&
 | 
				
			||||||
        wsrep_thd_is_toi(bf_thd))) {
 | 
					        wsrep_thd_is_toi(bf_thd))) {
 | 
				
			||||||
 | 
					    mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					    mysql_mutex_unlock(&victim_thd->LOCK_thd_kill);
 | 
				
			||||||
    DBUG_RETURN(0);
 | 
					    DBUG_RETURN(0);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -7996,6 +8001,8 @@ int ha_abort_transaction(THD *bf_thd, THD *victim_thd, my_bool signal)
 | 
				
			|||||||
  else
 | 
					  else
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    WSREP_WARN("Cannot abort InnoDB transaction");
 | 
					    WSREP_WARN("Cannot abort InnoDB transaction");
 | 
				
			||||||
 | 
					    mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					    mysql_mutex_unlock(&victim_thd->LOCK_thd_kill);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  DBUG_RETURN(0);
 | 
					  DBUG_RETURN(0);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,6 +45,7 @@
 | 
				
			|||||||
#include "sql_sequence.h"
 | 
					#include "sql_sequence.h"
 | 
				
			||||||
#include "mem_root_array.h"
 | 
					#include "mem_root_array.h"
 | 
				
			||||||
#include <utility>     // pair
 | 
					#include <utility>     // pair
 | 
				
			||||||
 | 
					#include <my_attribute.h> /* __attribute__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Alter_info;
 | 
					class Alter_info;
 | 
				
			||||||
class Virtual_column_info;
 | 
					class Virtual_column_info;
 | 
				
			||||||
@@ -1460,8 +1461,8 @@ struct handlerton
 | 
				
			|||||||
                            const char *query, uint query_length,
 | 
					                            const char *query, uint query_length,
 | 
				
			||||||
                            const char *db, const char *table_name);
 | 
					                            const char *db, const char *table_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   void (*abort_transaction)(handlerton *hton, THD *bf_thd,
 | 
					   void (*abort_transaction)(handlerton *hton, THD *bf_thd, THD *victim_thd,
 | 
				
			||||||
			    THD *victim_thd, my_bool signal);
 | 
					                             my_bool signal) __attribute__((nonnull));
 | 
				
			||||||
   int (*set_checkpoint)(handlerton *hton, const XID *xid);
 | 
					   int (*set_checkpoint)(handlerton *hton, const XID *xid);
 | 
				
			||||||
   int (*get_checkpoint)(handlerton *hton, XID* xid);
 | 
					   int (*get_checkpoint)(handlerton *hton, XID* xid);
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -373,7 +373,7 @@ public:
 | 
				
			|||||||
  {
 | 
					  {
 | 
				
			||||||
    for (uint i= 0; i < arg_count; i++)
 | 
					    for (uint i= 0; i < arg_count; i++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      args[i]->no_rows_in_result();
 | 
					      args[i]->restore_to_before_no_rows_in_result();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  void convert_const_compared_to_int_field(THD *thd);
 | 
					  void convert_const_compared_to_int_field(THD *thd);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1747,6 +1747,11 @@ static void close_connections(void)
 | 
				
			|||||||
      (void) unlink(mysqld_unix_port);
 | 
					      (void) unlink(mysqld_unix_port);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  /*
 | 
				
			||||||
 | 
					    The following is needed to the threads stuck in
 | 
				
			||||||
 | 
					    setup_connection_thread_globals()
 | 
				
			||||||
 | 
					    to continue.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
  listen_sockets.free_memory();
 | 
					  listen_sockets.free_memory();
 | 
				
			||||||
  mysql_mutex_unlock(&LOCK_start_thread);
 | 
					  mysql_mutex_unlock(&LOCK_start_thread);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2032,6 +2037,7 @@ static void clean_up(bool print_message)
 | 
				
			|||||||
  end_ssl();
 | 
					  end_ssl();
 | 
				
			||||||
#ifndef EMBEDDED_LIBRARY
 | 
					#ifndef EMBEDDED_LIBRARY
 | 
				
			||||||
  vio_end();
 | 
					  vio_end();
 | 
				
			||||||
 | 
					  listen_sockets.free_memory();
 | 
				
			||||||
#endif /*!EMBEDDED_LIBRARY*/
 | 
					#endif /*!EMBEDDED_LIBRARY*/
 | 
				
			||||||
#if defined(ENABLED_DEBUG_SYNC)
 | 
					#if defined(ENABLED_DEBUG_SYNC)
 | 
				
			||||||
  /* End the debug sync facility. See debug_sync.cc. */
 | 
					  /* End the debug sync facility. See debug_sync.cc. */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,6 +32,11 @@ extern "C" void wsrep_thd_LOCK(const THD *thd)
 | 
				
			|||||||
  mysql_mutex_lock(&thd->LOCK_thd_data);
 | 
					  mysql_mutex_lock(&thd->LOCK_thd_data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" int wsrep_thd_TRYLOCK(const THD *thd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return mysql_mutex_trylock(&thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern "C" void wsrep_thd_UNLOCK(const THD *thd)
 | 
					extern "C" void wsrep_thd_UNLOCK(const THD *thd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  mysql_mutex_unlock(&thd->LOCK_thd_data);
 | 
					  mysql_mutex_unlock(&thd->LOCK_thd_data);
 | 
				
			||||||
@@ -196,6 +201,7 @@ extern "C" void wsrep_handle_SR_rollback(THD *bf_thd,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /* Note: do not store/reset globals before wsrep_bf_abort() call
 | 
					  /* Note: do not store/reset globals before wsrep_bf_abort() call
 | 
				
			||||||
     to avoid losing BF thd context. */
 | 
					     to avoid losing BF thd context. */
 | 
				
			||||||
 | 
					  mysql_mutex_lock(&victim_thd->LOCK_thd_data);
 | 
				
			||||||
  if (!(bf_thd && bf_thd != victim_thd))
 | 
					  if (!(bf_thd && bf_thd != victim_thd))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    DEBUG_SYNC(victim_thd, "wsrep_before_SR_rollback");
 | 
					    DEBUG_SYNC(victim_thd, "wsrep_before_SR_rollback");
 | 
				
			||||||
@@ -208,6 +214,7 @@ extern "C" void wsrep_handle_SR_rollback(THD *bf_thd,
 | 
				
			|||||||
  {
 | 
					  {
 | 
				
			||||||
    wsrep_thd_self_abort(victim_thd);
 | 
					    wsrep_thd_self_abort(victim_thd);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
 | 
				
			||||||
  if (bf_thd)
 | 
					  if (bf_thd)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    wsrep_store_threadvars(bf_thd);
 | 
					    wsrep_store_threadvars(bf_thd);
 | 
				
			||||||
@@ -218,7 +225,7 @@ extern "C" my_bool wsrep_thd_bf_abort(THD *bf_thd, THD *victim_thd,
 | 
				
			|||||||
                                      my_bool signal)
 | 
					                                      my_bool signal)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  mysql_mutex_assert_owner(&victim_thd->LOCK_thd_kill);
 | 
					  mysql_mutex_assert_owner(&victim_thd->LOCK_thd_kill);
 | 
				
			||||||
  mysql_mutex_assert_not_owner(&victim_thd->LOCK_thd_data);
 | 
					  mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
 | 
				
			||||||
  my_bool ret= wsrep_bf_abort(bf_thd, victim_thd);
 | 
					  my_bool ret= wsrep_bf_abort(bf_thd, victim_thd);
 | 
				
			||||||
  /*
 | 
					  /*
 | 
				
			||||||
    Send awake signal if victim was BF aborted or does not
 | 
					    Send awake signal if victim was BF aborted or does not
 | 
				
			||||||
@@ -227,19 +234,8 @@ extern "C" my_bool wsrep_thd_bf_abort(THD *bf_thd, THD *victim_thd,
 | 
				
			|||||||
   */
 | 
					   */
 | 
				
			||||||
  if ((ret || !wsrep_on(victim_thd)) && signal)
 | 
					  if ((ret || !wsrep_on(victim_thd)) && signal)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    mysql_mutex_lock(&victim_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (victim_thd->wsrep_aborter && victim_thd->wsrep_aborter != bf_thd->thread_id)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      WSREP_DEBUG("victim is killed already by %llu, skipping awake",
 | 
					 | 
				
			||||||
                  victim_thd->wsrep_aborter);
 | 
					 | 
				
			||||||
      mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    victim_thd->wsrep_aborter= bf_thd->thread_id;
 | 
					    victim_thd->wsrep_aborter= bf_thd->thread_id;
 | 
				
			||||||
    victim_thd->awake_no_mutex(KILL_QUERY_HARD);
 | 
					    victim_thd->awake_no_mutex(KILL_QUERY_HARD);
 | 
				
			||||||
    mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    WSREP_DEBUG("wsrep_thd_bf_abort skipped awake, signal %d", signal);
 | 
					    WSREP_DEBUG("wsrep_thd_bf_abort skipped awake, signal %d", signal);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -368,25 +364,6 @@ extern "C" ulong wsrep_OSU_method_get(const MYSQL_THD thd)
 | 
				
			|||||||
    return(global_system_variables.wsrep_OSU_method);
 | 
					    return(global_system_variables.wsrep_OSU_method);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern "C" bool wsrep_thd_set_wsrep_aborter(THD *bf_thd, THD *victim_thd)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
  if (!bf_thd)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    victim_thd->wsrep_aborter= 0;
 | 
					 | 
				
			||||||
    WSREP_DEBUG("wsrep_thd_set_wsrep_aborter resetting wsrep_aborter");
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (victim_thd->wsrep_aborter && victim_thd->wsrep_aborter != bf_thd->thread_id)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  victim_thd->wsrep_aborter= bf_thd->thread_id;
 | 
					 | 
				
			||||||
  WSREP_DEBUG("wsrep_thd_set_wsrep_aborter setting wsrep_aborter %u",
 | 
					 | 
				
			||||||
              victim_thd->wsrep_aborter);
 | 
					 | 
				
			||||||
  return false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
extern "C" void wsrep_report_bf_lock_wait(const THD *thd,
 | 
					extern "C" void wsrep_report_bf_lock_wait(const THD *thd,
 | 
				
			||||||
                                          unsigned long long trx_id)
 | 
					                                          unsigned long long trx_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1293,6 +1293,11 @@ void THD::init()
 | 
				
			|||||||
  wsrep_affected_rows     = 0;
 | 
					  wsrep_affected_rows     = 0;
 | 
				
			||||||
  m_wsrep_next_trx_id     = WSREP_UNDEFINED_TRX_ID;
 | 
					  m_wsrep_next_trx_id     = WSREP_UNDEFINED_TRX_ID;
 | 
				
			||||||
  wsrep_aborter           = 0;
 | 
					  wsrep_aborter           = 0;
 | 
				
			||||||
 | 
					  wsrep_abort_by_kill     = NOT_KILLED;
 | 
				
			||||||
 | 
					  wsrep_abort_by_kill_err = 0;
 | 
				
			||||||
 | 
					#ifndef DBUG_OFF
 | 
				
			||||||
 | 
					  wsrep_killed_state      = 0;
 | 
				
			||||||
 | 
					#endif /* DBUG_OFF */
 | 
				
			||||||
  wsrep_desynced_backup_stage= false;
 | 
					  wsrep_desynced_backup_stage= false;
 | 
				
			||||||
#endif /* WITH_WSREP */
 | 
					#endif /* WITH_WSREP */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1641,6 +1646,13 @@ void THD::reset_for_reuse()
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef WITH_WSREP
 | 
					#ifdef WITH_WSREP
 | 
				
			||||||
  wsrep_free_status(this);
 | 
					  wsrep_free_status(this);
 | 
				
			||||||
 | 
					  wsrep_cs().reset_error();
 | 
				
			||||||
 | 
					  wsrep_aborter= 0;
 | 
				
			||||||
 | 
					  wsrep_abort_by_kill= NOT_KILLED;
 | 
				
			||||||
 | 
					  wsrep_abort_by_kill_err= 0;
 | 
				
			||||||
 | 
					#ifndef DBUG_OFF
 | 
				
			||||||
 | 
					  wsrep_killed_state= 0;
 | 
				
			||||||
 | 
					#endif /* DBUG_OFF */
 | 
				
			||||||
#endif /* WITH_WSREP */
 | 
					#endif /* WITH_WSREP */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1897,7 +1909,9 @@ void THD::awake_no_mutex(killed_state state_to_set)
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Interrupt target waiting inside a storage engine. */
 | 
					  /* Interrupt target waiting inside a storage engine. */
 | 
				
			||||||
  if (state_to_set != NOT_KILLED  && !wsrep_is_bf_aborted(this))
 | 
					  if (state_to_set != NOT_KILLED &&
 | 
				
			||||||
 | 
					      IF_WSREP(!wsrep_is_bf_aborted(this) && wsrep_abort_by_kill == NOT_KILLED,
 | 
				
			||||||
 | 
					               true))
 | 
				
			||||||
    ha_kill_query(this, thd_kill_level(this));
 | 
					    ha_kill_query(this, thd_kill_level(this));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  abort_current_cond_wait(false);
 | 
					  abort_current_cond_wait(false);
 | 
				
			||||||
@@ -2125,6 +2139,17 @@ void THD::reset_killed()
 | 
				
			|||||||
    mysql_mutex_unlock(&LOCK_thd_kill);
 | 
					    mysql_mutex_unlock(&LOCK_thd_kill);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#ifdef WITH_WSREP
 | 
					#ifdef WITH_WSREP
 | 
				
			||||||
 | 
					  if (WSREP_NNULL(this))
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    if (wsrep_abort_by_kill != NOT_KILLED)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      mysql_mutex_assert_not_owner(&LOCK_thd_kill);
 | 
				
			||||||
 | 
					      mysql_mutex_lock(&LOCK_thd_kill);
 | 
				
			||||||
 | 
					      wsrep_abort_by_kill= NOT_KILLED;
 | 
				
			||||||
 | 
					      wsrep_abort_by_kill_err= 0;
 | 
				
			||||||
 | 
					      mysql_mutex_unlock(&LOCK_thd_kill);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  mysql_mutex_assert_not_owner(&LOCK_thd_data);
 | 
					  mysql_mutex_assert_not_owner(&LOCK_thd_data);
 | 
				
			||||||
  mysql_mutex_lock(&LOCK_thd_data);
 | 
					  mysql_mutex_lock(&LOCK_thd_data);
 | 
				
			||||||
  wsrep_aborter= 0;
 | 
					  wsrep_aborter= 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5382,7 +5382,14 @@ public:
 | 
				
			|||||||
  bool                      wsrep_ignore_table;
 | 
					  bool                      wsrep_ignore_table;
 | 
				
			||||||
  /* thread who has started kill for this THD protected by LOCK_thd_data*/
 | 
					  /* thread who has started kill for this THD protected by LOCK_thd_data*/
 | 
				
			||||||
  my_thread_id              wsrep_aborter;
 | 
					  my_thread_id              wsrep_aborter;
 | 
				
			||||||
 | 
					  /* Kill signal used, if thread was killed by manual KILL. Protected by
 | 
				
			||||||
 | 
					     LOCK_thd_kill. */
 | 
				
			||||||
 | 
					  std::atomic<killed_state> wsrep_abort_by_kill;
 | 
				
			||||||
 | 
					  /* */
 | 
				
			||||||
 | 
					  struct err_info*          wsrep_abort_by_kill_err;
 | 
				
			||||||
 | 
					#ifndef DBUG_OFF
 | 
				
			||||||
 | 
					  int                       wsrep_killed_state;
 | 
				
			||||||
 | 
					#endif /* DBUG_OFF */
 | 
				
			||||||
  /* true if BF abort is observed in do_command() right after reading
 | 
					  /* true if BF abort is observed in do_command() right after reading
 | 
				
			||||||
  client's packet, and if the client has sent PS execute command. */
 | 
					  client's packet, and if the client has sent PS execute command. */
 | 
				
			||||||
  bool                      wsrep_delayed_BF_abort;
 | 
					  bool                      wsrep_delayed_BF_abort;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -61,6 +61,15 @@ class Select_limit_counters
 | 
				
			|||||||
     with_ties= false;
 | 
					     with_ties= false;
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   /* Send the first row, still honoring offset_limit_cnt */
 | 
				
			||||||
 | 
					   void send_first_row()
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					     /* Guard against overflow */
 | 
				
			||||||
 | 
					     if ((select_limit_cnt= offset_limit_cnt +1 ) == 0)
 | 
				
			||||||
 | 
					       select_limit_cnt= offset_limit_cnt;
 | 
				
			||||||
 | 
					     // with_ties= false;   Remove // on merge to 10.6
 | 
				
			||||||
 | 
					   }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   bool is_unlimited() const
 | 
					   bool is_unlimited() const
 | 
				
			||||||
   { return select_limit_cnt == HA_POS_ERROR; }
 | 
					   { return select_limit_cnt == HA_POS_ERROR; }
 | 
				
			||||||
   /*
 | 
					   /*
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9229,23 +9229,20 @@ kill_one_thread(THD *thd, my_thread_id id, killed_state kill_signal, killed_type
 | 
				
			|||||||
        thd->security_ctx->user_matches(tmp->security_ctx))
 | 
					        thd->security_ctx->user_matches(tmp->security_ctx))
 | 
				
			||||||
#endif /* WITH_WSREP */
 | 
					#endif /* WITH_WSREP */
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
#ifdef WITH_WSREP
 | 
					 | 
				
			||||||
      DEBUG_SYNC(thd, "before_awake_no_mutex");
 | 
					 | 
				
			||||||
      if (tmp->wsrep_aborter && tmp->wsrep_aborter != thd->thread_id)
 | 
					 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        /* victim is in hit list already, bail out */
 | 
					#ifdef WITH_WSREP
 | 
				
			||||||
	WSREP_DEBUG("victim %lld has wsrep aborter: %lu, skipping awake()",
 | 
					        if (WSREP(tmp))
 | 
				
			||||||
		    id, tmp->wsrep_aborter);
 | 
					        {
 | 
				
			||||||
        error= 0;
 | 
					          error = wsrep_kill_thd(thd, tmp, kill_signal);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
#endif /* WITH_WSREP */
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
        WSREP_DEBUG("kill_one_thread victim: %lld wsrep_aborter %lu"
 | 
					#endif /* WITH_WSREP */
 | 
				
			||||||
                    " by signal %d",
 | 
					 | 
				
			||||||
                    id, tmp->wsrep_aborter, kill_signal);
 | 
					 | 
				
			||||||
        tmp->awake_no_mutex(kill_signal);
 | 
					        tmp->awake_no_mutex(kill_signal);
 | 
				
			||||||
        error= 0;
 | 
					        error= 0;
 | 
				
			||||||
 | 
					#ifdef WITH_WSREP
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					#endif /* WITH_WSREP */
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
@@ -9368,18 +9365,6 @@ static
 | 
				
			|||||||
void sql_kill(THD *thd, my_thread_id id, killed_state state, killed_type type)
 | 
					void sql_kill(THD *thd, my_thread_id id, killed_state state, killed_type type)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  uint error;
 | 
					  uint error;
 | 
				
			||||||
#ifdef WITH_WSREP
 | 
					 | 
				
			||||||
  if (WSREP(thd))
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    WSREP_DEBUG("sql_kill called");
 | 
					 | 
				
			||||||
    if (thd->wsrep_applier)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      WSREP_DEBUG("KILL in applying, bailing out here");
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif /* WITH_WSREP */
 | 
					 | 
				
			||||||
  if (likely(!(error= kill_one_thread(thd, id, state, type))))
 | 
					  if (likely(!(error= kill_one_thread(thd, id, state, type))))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    if (!thd->killed)
 | 
					    if (!thd->killed)
 | 
				
			||||||
@@ -9389,11 +9374,6 @@ void sql_kill(THD *thd, my_thread_id id, killed_state state, killed_type type)
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
    my_error(error, MYF(0), id);
 | 
					    my_error(error, MYF(0), id);
 | 
				
			||||||
#ifdef WITH_WSREP
 | 
					 | 
				
			||||||
  return;
 | 
					 | 
				
			||||||
 wsrep_error_label:
 | 
					 | 
				
			||||||
  my_error(ER_KILL_DENIED_ERROR, MYF(0), (long long) thd->thread_id);
 | 
					 | 
				
			||||||
#endif /* WITH_WSREP */
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -9402,18 +9382,6 @@ sql_kill_user(THD *thd, LEX_USER *user, killed_state state)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  uint error;
 | 
					  uint error;
 | 
				
			||||||
  ha_rows rows;
 | 
					  ha_rows rows;
 | 
				
			||||||
#ifdef WITH_WSREP
 | 
					 | 
				
			||||||
  if (WSREP(thd))
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    WSREP_DEBUG("sql_kill_user called");
 | 
					 | 
				
			||||||
    if (thd->wsrep_applier)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      WSREP_DEBUG("KILL in applying, bailing out here");
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL)
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif /* WITH_WSREP */
 | 
					 | 
				
			||||||
  switch (error= kill_threads_for_user(thd, user, state, &rows))
 | 
					  switch (error= kill_threads_for_user(thd, user, state, &rows))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
  case 0:
 | 
					  case 0:
 | 
				
			||||||
@@ -9429,11 +9397,6 @@ sql_kill_user(THD *thd, LEX_USER *user, killed_state state)
 | 
				
			|||||||
  default:
 | 
					  default:
 | 
				
			||||||
    my_error(error, MYF(0));
 | 
					    my_error(error, MYF(0));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
#ifdef WITH_WSREP
 | 
					 | 
				
			||||||
  return;
 | 
					 | 
				
			||||||
 wsrep_error_label:
 | 
					 | 
				
			||||||
  my_error(ER_KILL_DENIED_ERROR, MYF(0), (long long) thd->thread_id);
 | 
					 | 
				
			||||||
#endif /* WITH_WSREP */
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -151,6 +151,7 @@ static struct wsrep_service_st wsrep_handler = {
 | 
				
			|||||||
  wsrep_on,
 | 
					  wsrep_on,
 | 
				
			||||||
  wsrep_prepare_key_for_innodb,
 | 
					  wsrep_prepare_key_for_innodb,
 | 
				
			||||||
  wsrep_thd_LOCK,
 | 
					  wsrep_thd_LOCK,
 | 
				
			||||||
 | 
					  wsrep_thd_TRYLOCK,
 | 
				
			||||||
  wsrep_thd_UNLOCK,
 | 
					  wsrep_thd_UNLOCK,
 | 
				
			||||||
  wsrep_thd_query,
 | 
					  wsrep_thd_query,
 | 
				
			||||||
  wsrep_thd_retry_counter,
 | 
					  wsrep_thd_retry_counter,
 | 
				
			||||||
@@ -179,7 +180,6 @@ static struct wsrep_service_st wsrep_handler = {
 | 
				
			|||||||
  wsrep_OSU_method_get,
 | 
					  wsrep_OSU_method_get,
 | 
				
			||||||
  wsrep_thd_has_ignored_error,
 | 
					  wsrep_thd_has_ignored_error,
 | 
				
			||||||
  wsrep_thd_set_ignored_error,
 | 
					  wsrep_thd_set_ignored_error,
 | 
				
			||||||
  wsrep_thd_set_wsrep_aborter,
 | 
					 | 
				
			||||||
  wsrep_report_bf_lock_wait,
 | 
					  wsrep_report_bf_lock_wait,
 | 
				
			||||||
  wsrep_thd_kill_LOCK,
 | 
					  wsrep_thd_kill_LOCK,
 | 
				
			||||||
  wsrep_thd_kill_UNLOCK,
 | 
					  wsrep_thd_kill_UNLOCK,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -150,10 +150,10 @@ static void update_depend_map_for_order(JOIN *join, ORDER *order);
 | 
				
			|||||||
static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond,
 | 
					static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond,
 | 
				
			||||||
			   bool change_list, bool *simple_order);
 | 
								   bool change_list, bool *simple_order);
 | 
				
			||||||
static int return_zero_rows(JOIN *join, select_result *res, 
 | 
					static int return_zero_rows(JOIN *join, select_result *res, 
 | 
				
			||||||
                            List<TABLE_LIST> &tables,
 | 
					                            List<TABLE_LIST> *tables,
 | 
				
			||||||
                            List<Item> &fields, bool send_row,
 | 
					                            List<Item> *fields, bool send_row,
 | 
				
			||||||
                            ulonglong select_options, const char *info,
 | 
					                            ulonglong select_options, const char *info,
 | 
				
			||||||
                            Item *having, List<Item> &all_fields);
 | 
					                            Item *having, List<Item> *all_fields);
 | 
				
			||||||
static COND *build_equal_items(JOIN *join, COND *cond,
 | 
					static COND *build_equal_items(JOIN *join, COND *cond,
 | 
				
			||||||
                               COND_EQUAL *inherited,
 | 
					                               COND_EQUAL *inherited,
 | 
				
			||||||
                               List<TABLE_LIST> *join_list,
 | 
					                               List<TABLE_LIST> *join_list,
 | 
				
			||||||
@@ -1301,11 +1301,40 @@ int SELECT_LEX::vers_setup_conds(THD *thd, TABLE_LIST *tables)
 | 
				
			|||||||
  DBUG_RETURN(0);
 | 
					  DBUG_RETURN(0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*****************************************************************************
 | 
					/*****************************************************************************
 | 
				
			||||||
  Check fields, find best join, do the select and output fields.
 | 
					  Check fields, find best join, do the select and output fields.
 | 
				
			||||||
  mysql_select assumes that all tables are already opened
 | 
					  mysql_select assumes that all tables are already opened
 | 
				
			||||||
*****************************************************************************/
 | 
					*****************************************************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  Check if we have a field reference. If yes, we have to use
 | 
				
			||||||
 | 
					  mixed_implicit_grouping.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool check_list_for_field(List<Item> *items)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  List_iterator_fast <Item> select_it(*items);
 | 
				
			||||||
 | 
					  Item *select_el;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  while ((select_el= select_it++))
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    if (select_el->with_field())
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool check_list_for_field(ORDER *order)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  for (; order; order= order->next)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    if (order->item[0]->with_field())
 | 
				
			||||||
 | 
					      return true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
  Prepare of whole select (including sub queries in future).
 | 
					  Prepare of whole select (including sub queries in future).
 | 
				
			||||||
@@ -1387,52 +1416,43 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num,
 | 
				
			|||||||
    DBUG_RETURN(-1);
 | 
					    DBUG_RETURN(-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*
 | 
					  /*
 | 
				
			||||||
    TRUE if the SELECT list mixes elements with and without grouping,
 | 
					    mixed_implicit_grouping will be set to TRUE if the SELECT list
 | 
				
			||||||
    and there is no GROUP BY clause. Mixing non-aggregated fields with
 | 
					    mixes elements with and without grouping, and there is no GROUP BY
 | 
				
			||||||
    aggregate functions in the SELECT list is a MySQL extenstion that
 | 
					    clause.
 | 
				
			||||||
    is allowed only if the ONLY_FULL_GROUP_BY sql mode is not set.
 | 
					    Mixing non-aggregated fields with aggregate functions in the
 | 
				
			||||||
 | 
					    SELECT list or HAVING is a MySQL extension that is allowed only if
 | 
				
			||||||
 | 
					    the ONLY_FULL_GROUP_BY sql mode is not set.
 | 
				
			||||||
  */
 | 
					  */
 | 
				
			||||||
  mixed_implicit_grouping= false;
 | 
					  mixed_implicit_grouping= false;
 | 
				
			||||||
  if ((~thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) &&
 | 
					  if ((~thd->variables.sql_mode & MODE_ONLY_FULL_GROUP_BY) &&
 | 
				
			||||||
      select_lex->with_sum_func && !group_list)
 | 
					      select_lex->with_sum_func && !group_list)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    List_iterator_fast <Item> select_it(fields_list);
 | 
					    if (check_list_for_field(&fields_list)  ||
 | 
				
			||||||
    Item *select_el; /* Element of the SELECT clause, can be an expression. */
 | 
					        check_list_for_field(order))
 | 
				
			||||||
    bool found_field_elem= false;
 | 
					 | 
				
			||||||
    bool found_sum_func_elem= false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while ((select_el= select_it++))
 | 
					 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      if (select_el->with_sum_func())
 | 
					 | 
				
			||||||
        found_sum_func_elem= true;
 | 
					 | 
				
			||||||
      if (select_el->with_field())
 | 
					 | 
				
			||||||
        found_field_elem= true;
 | 
					 | 
				
			||||||
      if (found_sum_func_elem && found_field_elem)
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        mixed_implicit_grouping= true;
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  table_count= select_lex->leaf_tables.elements;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  TABLE_LIST *tbl;
 | 
					 | 
				
			||||||
      List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
 | 
					      List_iterator_fast<TABLE_LIST> li(select_lex->leaf_tables);
 | 
				
			||||||
  while ((tbl= li++))
 | 
					
 | 
				
			||||||
 | 
					      mixed_implicit_grouping= true;            // mark for future
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      while (TABLE_LIST *tbl= li++)
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        /*
 | 
					        /*
 | 
				
			||||||
      If the query uses implicit grouping where the select list contains both
 | 
					          If the query uses implicit grouping where the select list
 | 
				
			||||||
      aggregate functions and non-aggregate fields, any non-aggregated field
 | 
					          contains both aggregate functions and non-aggregate fields,
 | 
				
			||||||
      may produce a NULL value. Set all fields of each table as nullable before
 | 
					          any non-aggregated field may produce a NULL value. Set all
 | 
				
			||||||
      semantic analysis to take into account this change of nullability.
 | 
					          fields of each table as nullable before semantic analysis to
 | 
				
			||||||
 | 
					          take into account this change of nullability.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      Note: this loop doesn't touch tables inside merged semi-joins, because
 | 
					          Note: this loop doesn't touch tables inside merged
 | 
				
			||||||
      subquery-to-semijoin conversion has not been done yet. This is intended.
 | 
					          semi-joins, because subquery-to-semijoin conversion has not
 | 
				
			||||||
 | 
					          been done yet. This is intended.
 | 
				
			||||||
        */
 | 
					        */
 | 
				
			||||||
    if (mixed_implicit_grouping && tbl->table)
 | 
					        if (tbl->table)
 | 
				
			||||||
          tbl->table->maybe_null= 1;
 | 
					          tbl->table->maybe_null= 1;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  table_count= select_lex->leaf_tables.elements;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  uint real_og_num= og_num;
 | 
					  uint real_og_num= og_num;
 | 
				
			||||||
  if (skip_order_by && 
 | 
					  if (skip_order_by && 
 | 
				
			||||||
@@ -1453,7 +1473,7 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, uint og_num,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    List_iterator_fast<TABLE_LIST> it(select_lex->leaf_tables);
 | 
					    List_iterator_fast<TABLE_LIST> it(select_lex->leaf_tables);
 | 
				
			||||||
    while ((tbl= it++))
 | 
					    while (TABLE_LIST *tbl= it++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      if (tbl->table_function &&
 | 
					      if (tbl->table_function &&
 | 
				
			||||||
          tbl->table_function->setup(thd, tbl, select_lex_arg))
 | 
					          tbl->table_function->setup(thd, tbl, select_lex_arg))
 | 
				
			||||||
@@ -4074,7 +4094,7 @@ bool JOIN::make_aggr_tables_info()
 | 
				
			|||||||
  set_items_ref_array(items0);
 | 
					  set_items_ref_array(items0);
 | 
				
			||||||
  if (join_tab)
 | 
					  if (join_tab)
 | 
				
			||||||
    join_tab[exec_join_tab_cnt() + aggr_tables - 1].next_select=
 | 
					    join_tab[exec_join_tab_cnt() + aggr_tables - 1].next_select=
 | 
				
			||||||
      setup_end_select_func(this, NULL);
 | 
					      setup_end_select_func(this);
 | 
				
			||||||
  group= has_group_by;
 | 
					  group= has_group_by;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  DBUG_RETURN(false);
 | 
					  DBUG_RETURN(false);
 | 
				
			||||||
@@ -4469,13 +4489,7 @@ JOIN::reinit()
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* Reset of sum functions */
 | 
					  clear_sum_funcs();
 | 
				
			||||||
  if (sum_funcs)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    Item_sum *func, **func_ptr= sum_funcs;
 | 
					 | 
				
			||||||
    while ((func= *(func_ptr++)))
 | 
					 | 
				
			||||||
      func->clear();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (no_rows_in_result_called)
 | 
					  if (no_rows_in_result_called)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
@@ -4758,12 +4772,12 @@ void JOIN::exec_inner()
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      (void) return_zero_rows(this, result, select_lex->leaf_tables,
 | 
					      (void) return_zero_rows(this, result, &select_lex->leaf_tables,
 | 
				
			||||||
                              *columns_list,
 | 
					                              columns_list,
 | 
				
			||||||
			      send_row_on_empty_set(),
 | 
								      send_row_on_empty_set(),
 | 
				
			||||||
			      select_options,
 | 
								      select_options,
 | 
				
			||||||
			      zero_result_cause,
 | 
								      zero_result_cause,
 | 
				
			||||||
			      having ? having : tmp_having, all_fields);
 | 
								      having ? having : tmp_having, &all_fields);
 | 
				
			||||||
      DBUG_VOID_RETURN;
 | 
					      DBUG_VOID_RETURN;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -15641,10 +15655,36 @@ ORDER *simple_remove_const(ORDER *order, COND *where)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  Set all fields in the table to have a null value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @param tables            Table list
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void make_tables_null_complemented(List<TABLE_LIST> *tables)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  List_iterator<TABLE_LIST> ti(*tables);
 | 
				
			||||||
 | 
					  TABLE_LIST *table;
 | 
				
			||||||
 | 
					  while ((table= ti++))
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					      Don't touch semi-join materialization tables, as the a join_free()
 | 
				
			||||||
 | 
					      call may have freed them (and HAVING clause can't have references to
 | 
				
			||||||
 | 
					      them anyway).
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    if (!table->is_jtbm())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      TABLE *tbl= table->table;
 | 
				
			||||||
 | 
					      mark_as_null_row(tbl);		// Set fields to NULL
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
 | 
					return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> *tables,
 | 
				
			||||||
		 List<Item> &fields, bool send_row, ulonglong select_options,
 | 
							 List<Item> *fields, bool send_row, ulonglong select_options,
 | 
				
			||||||
		 const char *info, Item *having, List<Item> &all_fields)
 | 
							 const char *info, Item *having, List<Item> *all_fields)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  DBUG_ENTER("return_zero_rows");
 | 
					  DBUG_ENTER("return_zero_rows");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -15660,24 +15700,15 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
 | 
				
			|||||||
      Set all tables to have NULL row. This is needed as we will be evaluating
 | 
					      Set all tables to have NULL row. This is needed as we will be evaluating
 | 
				
			||||||
      HAVING condition.
 | 
					      HAVING condition.
 | 
				
			||||||
    */
 | 
					    */
 | 
				
			||||||
    List_iterator<TABLE_LIST> ti(tables);
 | 
					    make_tables_null_complemented(tables);
 | 
				
			||||||
    TABLE_LIST *table;
 | 
					
 | 
				
			||||||
    while ((table= ti++))
 | 
					    List_iterator_fast<Item> it(*all_fields);
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      /*
 | 
					 | 
				
			||||||
        Don't touch semi-join materialization tables, as the above join_free()
 | 
					 | 
				
			||||||
        call has freed them (and HAVING clause can't have references to them 
 | 
					 | 
				
			||||||
        anyway).
 | 
					 | 
				
			||||||
      */
 | 
					 | 
				
			||||||
      if (!table->is_jtbm())
 | 
					 | 
				
			||||||
        mark_as_null_row(table->table);		// All fields are NULL
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    List_iterator_fast<Item> it(all_fields);
 | 
					 | 
				
			||||||
    Item *item;
 | 
					    Item *item;
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
      Inform all items (especially aggregating) to calculate HAVING correctly,
 | 
					      Inform all items (especially aggregating) to calculate HAVING correctly,
 | 
				
			||||||
      also we will need it for sending results.
 | 
					      also we will need it for sending results.
 | 
				
			||||||
    */
 | 
					    */
 | 
				
			||||||
 | 
					    join->no_rows_in_result_called= 1;
 | 
				
			||||||
    while ((item= it++))
 | 
					    while ((item= it++))
 | 
				
			||||||
      item->no_rows_in_result();
 | 
					      item->no_rows_in_result();
 | 
				
			||||||
    if (having && having->val_int() == 0)
 | 
					    if (having && having->val_int() == 0)
 | 
				
			||||||
@@ -15691,12 +15722,12 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
 | 
				
			|||||||
    join->thd->limit_found_rows= 0;
 | 
					    join->thd->limit_found_rows= 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!(result->send_result_set_metadata(fields,
 | 
					  if (!(result->send_result_set_metadata(*fields,
 | 
				
			||||||
                              Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)))
 | 
					                              Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    bool send_error= FALSE;
 | 
					    bool send_error= FALSE;
 | 
				
			||||||
    if (send_row)
 | 
					    if (send_row)
 | 
				
			||||||
      send_error= result->send_data_with_check(fields, join->unit, 0) > 0;
 | 
					      send_error= result->send_data_with_check(*fields, join->unit, 0) > 0;
 | 
				
			||||||
    if (likely(!send_error))
 | 
					    if (likely(!send_error))
 | 
				
			||||||
      result->send_eof();				// Should be safe
 | 
					      result->send_eof();				// Should be safe
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -15712,31 +15743,25 @@ return_zero_rows(JOIN *join, select_result *result, List<TABLE_LIST> &tables,
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
  used only in JOIN::clear (always) and in do_select()
 | 
					  Reset table rows to contain a null-complement row (all fields are null)
 | 
				
			||||||
  (if there where no matching rows)
 | 
					
 | 
				
			||||||
 | 
					  Used only in JOIN::clear() and in do_select() if there where no matching rows.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @param join            JOIN
 | 
					  @param join            JOIN
 | 
				
			||||||
  @param cleared_tables  If not null, clear also const tables and mark all
 | 
					  @param cleared_tables  Used to mark all cleared tables in the map. Needed for
 | 
				
			||||||
                         cleared tables in the map. cleared_tables is only
 | 
					                         unclear_tables() to know which tables to restore to
 | 
				
			||||||
                         set when called from do_select() when there is a
 | 
					                         their original state.
 | 
				
			||||||
                         group function and there where no matching rows.
 | 
					 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void clear_tables(JOIN *join, table_map *cleared_tables)
 | 
					static void clear_tables(JOIN *join, table_map *cleared_tables)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  /* 
 | 
					  DBUG_ASSERT(cleared_tables);
 | 
				
			||||||
    must clear only the non-const tables as const tables are not re-calculated.
 | 
					 | 
				
			||||||
  */
 | 
					 | 
				
			||||||
  for (uint i= 0 ; i < join->table_count ; i++)
 | 
					  for (uint i= 0 ; i < join->table_count ; i++)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    TABLE *table= join->table[i];
 | 
					    TABLE *table= join->table[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (table->null_row)
 | 
					    if (table->null_row)
 | 
				
			||||||
      continue;                                 // Nothing more to do
 | 
					      continue;                                 // Nothing more to do
 | 
				
			||||||
    if (!(table->map & join->const_table_map) || cleared_tables)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      if (cleared_tables)
 | 
					 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
    (*cleared_tables)|= (((table_map) 1) << i);
 | 
					    (*cleared_tables)|= (((table_map) 1) << i);
 | 
				
			||||||
    if (table->s->null_bytes)
 | 
					    if (table->s->null_bytes)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -15746,15 +15771,14 @@ static void clear_tables(JOIN *join, table_map *cleared_tables)
 | 
				
			|||||||
      */
 | 
					      */
 | 
				
			||||||
      memcpy(table->record[1], table->null_flags, table->s->null_bytes);
 | 
					      memcpy(table->record[1], table->null_flags, table->s->null_bytes);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    mark_as_null_row(table);                  // All fields are NULL
 | 
					    mark_as_null_row(table);                  // All fields are NULL
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
   Reverse null marking for tables and restore null bits.
 | 
					   Reverse null marking for tables and restore null bits.
 | 
				
			||||||
 | 
					   This return the tables to the state of before clear_tables().
 | 
				
			||||||
 | 
					
 | 
				
			||||||
   We have to do this because the tables may be re-used in a sub query
 | 
					   We have to do this because the tables may be re-used in a sub query
 | 
				
			||||||
   and the subquery will assume that the const tables contains the original
 | 
					   and the subquery will assume that the const tables contains the original
 | 
				
			||||||
@@ -21493,9 +21517,9 @@ void set_postjoin_aggr_write_func(JOIN_TAB *tab)
 | 
				
			|||||||
    end_select function to use. This function can't fail.
 | 
					    end_select function to use. This function can't fail.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Next_select_func setup_end_select_func(JOIN *join, JOIN_TAB *tab)
 | 
					Next_select_func setup_end_select_func(JOIN *join)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  TMP_TABLE_PARAM *tmp_tbl= tab ? tab->tmp_table_param : &join->tmp_table_param;
 | 
					  TMP_TABLE_PARAM *tmp_tbl= &join->tmp_table_param;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* 
 | 
					  /* 
 | 
				
			||||||
     Choose method for presenting result to user. Use end_send_group
 | 
					     Choose method for presenting result to user. Use end_send_group
 | 
				
			||||||
@@ -21565,7 +21589,7 @@ do_select(JOIN *join, Procedure *procedure)
 | 
				
			|||||||
  join->duplicate_rows= join->send_records=0;
 | 
					  join->duplicate_rows= join->send_records=0;
 | 
				
			||||||
  if (join->only_const_tables() && !join->need_tmp)
 | 
					  if (join->only_const_tables() && !join->need_tmp)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    Next_select_func end_select= setup_end_select_func(join, NULL);
 | 
					    Next_select_func end_select= setup_end_select_func(join);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
      HAVING will be checked after processing aggregate functions,
 | 
					      HAVING will be checked after processing aggregate functions,
 | 
				
			||||||
@@ -22040,6 +22064,7 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Restore state if mark_as_null_row() have been called */
 | 
				
			||||||
  if (join_tab->last_inner)
 | 
					  if (join_tab->last_inner)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    JOIN_TAB *last_inner_tab= join_tab->last_inner;
 | 
					    JOIN_TAB *last_inner_tab= join_tab->last_inner;
 | 
				
			||||||
@@ -23452,11 +23477,18 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  int idx= -1;
 | 
					  int idx= -1;
 | 
				
			||||||
  enum_nested_loop_state ok_code= NESTED_LOOP_OK;
 | 
					  enum_nested_loop_state ok_code= NESTED_LOOP_OK;
 | 
				
			||||||
 | 
					  /*
 | 
				
			||||||
 | 
					    join_tab can be 0 in the case all tables are const tables and we did not
 | 
				
			||||||
 | 
					    need a temporary table to store the result.
 | 
				
			||||||
 | 
					    In this case we use the original given fields, which is stored in
 | 
				
			||||||
 | 
					    join->fields.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
  List<Item> *fields= join_tab ? (join_tab-1)->fields : join->fields;
 | 
					  List<Item> *fields= join_tab ? (join_tab-1)->fields : join->fields;
 | 
				
			||||||
  DBUG_ENTER("end_send_group");
 | 
					  DBUG_ENTER("end_send_group");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!join->items3.is_null() && !join->set_group_rpa)
 | 
					  if (!join->items3.is_null() && !join->set_group_rpa)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					    /* Move ref_pointer_array to points to items3 */
 | 
				
			||||||
    join->set_group_rpa= true;
 | 
					    join->set_group_rpa= true;
 | 
				
			||||||
    join->set_items_ref_array(join->items3);
 | 
					    join->set_items_ref_array(join->items3);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -23464,10 +23496,12 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
 | 
				
			|||||||
  if (!join->first_record || end_of_records ||
 | 
					  if (!join->first_record || end_of_records ||
 | 
				
			||||||
      (idx=test_if_group_changed(join->group_fields)) >= 0)
 | 
					      (idx=test_if_group_changed(join->group_fields)) >= 0)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!join->group_sent &&
 | 
					    if (!join->group_sent &&
 | 
				
			||||||
        (join->first_record ||
 | 
					        (join->first_record ||
 | 
				
			||||||
         (end_of_records && !join->group && !join->group_optimized_away)))
 | 
					         (end_of_records && !join->group && !join->group_optimized_away)))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					      table_map cleared_tables= (table_map) 0;
 | 
				
			||||||
      if (join->procedure)
 | 
					      if (join->procedure)
 | 
				
			||||||
	join->procedure->end_group();
 | 
						join->procedure->end_group();
 | 
				
			||||||
      /* Test if there was a group change. */
 | 
					      /* Test if there was a group change. */
 | 
				
			||||||
@@ -23492,11 +23526,13 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
 | 
				
			|||||||
          /* Reset all sum functions on group change. */
 | 
					          /* Reset all sum functions on group change. */
 | 
				
			||||||
	  if (!join->first_record)
 | 
						  if (!join->first_record)
 | 
				
			||||||
	  {
 | 
						  {
 | 
				
			||||||
            List_iterator_fast<Item> it(*join->fields);
 | 
					 | 
				
			||||||
            Item *item;
 | 
					 | 
				
			||||||
            /* No matching rows for group function */
 | 
					            /* No matching rows for group function */
 | 
				
			||||||
            join->clear();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            List_iterator_fast<Item> it(*fields);
 | 
				
			||||||
 | 
					            Item *item;
 | 
				
			||||||
 | 
					            join->no_rows_in_result_called= 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            join->clear(&cleared_tables);
 | 
				
			||||||
            while ((item= it++))
 | 
					            while ((item= it++))
 | 
				
			||||||
              item->no_rows_in_result();
 | 
					              item->no_rows_in_result();
 | 
				
			||||||
	  }
 | 
						  }
 | 
				
			||||||
@@ -23524,6 +23560,13 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab, bool end_of_records)
 | 
				
			|||||||
	    if (join->rollup_send_data((uint) (idx+1)))
 | 
						    if (join->rollup_send_data((uint) (idx+1)))
 | 
				
			||||||
	      error= 1;
 | 
						      error= 1;
 | 
				
			||||||
	  }
 | 
						  }
 | 
				
			||||||
 | 
					          if (join->no_rows_in_result_called)
 | 
				
			||||||
 | 
					          {
 | 
				
			||||||
 | 
					            /* Restore null tables to original state */
 | 
				
			||||||
 | 
					            join->no_rows_in_result_called= 0;
 | 
				
			||||||
 | 
					            if (cleared_tables)
 | 
				
			||||||
 | 
					              unclear_tables(join, &cleared_tables);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
	if (unlikely(error > 0))
 | 
						if (unlikely(error > 0))
 | 
				
			||||||
          DBUG_RETURN(NESTED_LOOP_ERROR);        /* purecov: inspected */
 | 
					          DBUG_RETURN(NESTED_LOOP_ERROR);        /* purecov: inspected */
 | 
				
			||||||
@@ -23841,6 +23884,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
 | 
				
			|||||||
  {
 | 
					  {
 | 
				
			||||||
    if (join->first_record || (end_of_records && !join->group))
 | 
					    if (join->first_record || (end_of_records && !join->group))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					      table_map cleared_tables= (table_map) 0;
 | 
				
			||||||
      if (join->procedure)
 | 
					      if (join->procedure)
 | 
				
			||||||
	join->procedure->end_group();
 | 
						join->procedure->end_group();
 | 
				
			||||||
      int send_group_parts= join->send_group_parts;
 | 
					      int send_group_parts= join->send_group_parts;
 | 
				
			||||||
@@ -23849,7 +23893,7 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
 | 
				
			|||||||
        if (!join->first_record)
 | 
					        if (!join->first_record)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          /* No matching rows for group function */
 | 
					          /* No matching rows for group function */
 | 
				
			||||||
          join->clear();
 | 
					          join->clear(&cleared_tables);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        copy_sum_funcs(join->sum_funcs,
 | 
					        copy_sum_funcs(join->sum_funcs,
 | 
				
			||||||
                       join->sum_funcs_end[send_group_parts]);
 | 
					                       join->sum_funcs_end[send_group_parts]);
 | 
				
			||||||
@@ -23872,6 +23916,8 @@ end_write_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
 | 
				
			|||||||
	    DBUG_RETURN(NESTED_LOOP_ERROR);
 | 
						    DBUG_RETURN(NESTED_LOOP_ERROR);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					        if (cleared_tables)
 | 
				
			||||||
 | 
					          unclear_tables(join, &cleared_tables);
 | 
				
			||||||
	if (end_of_records)
 | 
						if (end_of_records)
 | 
				
			||||||
	  goto end;
 | 
						  goto end;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -25603,7 +25649,7 @@ JOIN_TAB::remove_duplicates()
 | 
				
			|||||||
      !(join->select_options & OPTION_FOUND_ROWS))
 | 
					      !(join->select_options & OPTION_FOUND_ROWS))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    // only const items with no OPTION_FOUND_ROWS
 | 
					    // only const items with no OPTION_FOUND_ROWS
 | 
				
			||||||
    join->unit->lim.set_single_row();		// Only send first row
 | 
					    join->unit->lim.send_first_row();		// Only send first row
 | 
				
			||||||
    my_free(sortorder);
 | 
					    my_free(sortorder);
 | 
				
			||||||
    DBUG_RETURN(false);
 | 
					    DBUG_RETURN(false);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -28007,11 +28053,8 @@ int JOIN::rollup_write_data(uint idx, TMP_TABLE_PARAM *tmp_table_param_arg,
 | 
				
			|||||||
  (end_send_group/end_write_group)
 | 
					  (end_send_group/end_write_group)
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void JOIN::clear()
 | 
					void inline JOIN::clear_sum_funcs()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  clear_tables(this, 0);
 | 
					 | 
				
			||||||
  copy_fields(&tmp_table_param);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (sum_funcs)
 | 
					  if (sum_funcs)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    Item_sum *func, **func_ptr= sum_funcs;
 | 
					    Item_sum *func, **func_ptr= sum_funcs;
 | 
				
			||||||
@@ -28021,6 +28064,22 @@ void JOIN::clear()
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  Prepare for returning 'empty row' when there is no matching row.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - Mark all tables with mark_as_null_row()
 | 
				
			||||||
 | 
					  - Make a copy of of all simple SELECT items
 | 
				
			||||||
 | 
					  - Reset all sum functions to NULL or 0.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void JOIN::clear(table_map *cleared_tables)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  clear_tables(this, cleared_tables);
 | 
				
			||||||
 | 
					  copy_fields(&tmp_table_param);
 | 
				
			||||||
 | 
					  clear_sum_funcs();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
  Print an EXPLAIN line with all NULLs and given message in the 'Extra' column
 | 
					  Print an EXPLAIN line with all NULLs and given message in the 'Extra' column
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -227,7 +227,7 @@ enum sj_strategy_enum
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
typedef enum_nested_loop_state
 | 
					typedef enum_nested_loop_state
 | 
				
			||||||
(*Next_select_func)(JOIN *, struct st_join_table *, bool);
 | 
					(*Next_select_func)(JOIN *, struct st_join_table *, bool);
 | 
				
			||||||
Next_select_func setup_end_select_func(JOIN *join, JOIN_TAB *tab);
 | 
					Next_select_func setup_end_select_func(JOIN *join);
 | 
				
			||||||
int rr_sequential(READ_RECORD *info);
 | 
					int rr_sequential(READ_RECORD *info);
 | 
				
			||||||
int read_record_func_for_rr_and_unpack(READ_RECORD *info);
 | 
					int read_record_func_for_rr_and_unpack(READ_RECORD *info);
 | 
				
			||||||
Item *remove_pushed_top_conjuncts(THD *thd, Item *cond);
 | 
					Item *remove_pushed_top_conjuncts(THD *thd, Item *cond);
 | 
				
			||||||
@@ -1722,7 +1722,8 @@ public:
 | 
				
			|||||||
  void join_free();
 | 
					  void join_free();
 | 
				
			||||||
  /** Cleanup this JOIN, possibly for reuse */
 | 
					  /** Cleanup this JOIN, possibly for reuse */
 | 
				
			||||||
  void cleanup(bool full);
 | 
					  void cleanup(bool full);
 | 
				
			||||||
  void clear();
 | 
					  void clear(table_map *cleared_tables);
 | 
				
			||||||
 | 
					  void inline clear_sum_funcs();
 | 
				
			||||||
  bool send_row_on_empty_set()
 | 
					  bool send_row_on_empty_set()
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    return (do_send_rows && implicit_grouping && !group_optimized_away &&
 | 
					    return (do_send_rows && implicit_grouping && !group_optimized_away &&
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7574,8 +7574,9 @@ extern Named_type_handler<Type_handler_time>        type_handler_time;
 | 
				
			|||||||
extern Named_type_handler<Type_handler_time2>       type_handler_time2;
 | 
					extern Named_type_handler<Type_handler_time2>       type_handler_time2;
 | 
				
			||||||
extern Named_type_handler<Type_handler_datetime>    type_handler_datetime;
 | 
					extern Named_type_handler<Type_handler_datetime>    type_handler_datetime;
 | 
				
			||||||
extern Named_type_handler<Type_handler_datetime2>   type_handler_datetime2;
 | 
					extern Named_type_handler<Type_handler_datetime2>   type_handler_datetime2;
 | 
				
			||||||
extern Named_type_handler<Type_handler_timestamp>   type_handler_timestamp;
 | 
					
 | 
				
			||||||
extern Named_type_handler<Type_handler_timestamp2>  type_handler_timestamp2;
 | 
					extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_timestamp>   type_handler_timestamp;
 | 
				
			||||||
 | 
					extern MYSQL_PLUGIN_IMPORT Named_type_handler<Type_handler_timestamp2>  type_handler_timestamp2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern Type_handler_interval_DDhhmmssff type_handler_interval_DDhhmmssff;
 | 
					extern Type_handler_interval_DDhhmmssff type_handler_interval_DDhhmmssff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3376,10 +3376,16 @@ inline void mark_as_null_row(TABLE *table)
 | 
				
			|||||||
    bfill(table->null_flags,table->s->null_bytes,255);
 | 
					    bfill(table->null_flags,table->s->null_bytes,255);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  Restore table to state before mark_as_null_row() call.
 | 
				
			||||||
 | 
					  This assumes that the caller has restored table->null_flags,
 | 
				
			||||||
 | 
					  as is done in unclear_tables().
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline void unmark_as_null_row(TABLE *table)
 | 
					inline void unmark_as_null_row(TABLE *table)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  table->null_row= 0;
 | 
					  table->null_row= 0;
 | 
				
			||||||
  table->status= STATUS_NO_RECORD;
 | 
					  table->status&= ~STATUS_NULL_ROW;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool is_simple_order(ORDER *order);
 | 
					bool is_simple_order(ORDER *order);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,6 +56,11 @@ my_bool wsrep_on(const THD *)
 | 
				
			|||||||
void wsrep_thd_LOCK(const THD *)
 | 
					void wsrep_thd_LOCK(const THD *)
 | 
				
			||||||
{ }
 | 
					{ }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int wsrep_thd_TRYLOCK(const THD *)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wsrep_thd_UNLOCK(const THD *)
 | 
					void wsrep_thd_UNLOCK(const THD *)
 | 
				
			||||||
{ }
 | 
					{ }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -154,8 +159,6 @@ void wsrep_thd_set_ignored_error(THD*, my_bool)
 | 
				
			|||||||
{ }
 | 
					{ }
 | 
				
			||||||
ulong wsrep_OSU_method_get(const THD*)
 | 
					ulong wsrep_OSU_method_get(const THD*)
 | 
				
			||||||
{ return 0;}
 | 
					{ return 0;}
 | 
				
			||||||
bool wsrep_thd_set_wsrep_aborter(THD*, THD*)
 | 
					 | 
				
			||||||
{ return 0;}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void wsrep_report_bf_lock_wait(const THD*,
 | 
					void wsrep_report_bf_lock_wait(const THD*,
 | 
				
			||||||
                               unsigned long long)
 | 
					                               unsigned long long)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -510,6 +510,7 @@ int Wsrep_high_priority_service::log_dummy_write_set(const wsrep::ws_handle& ws_
 | 
				
			|||||||
      m_thd->wait_for_prior_commit();
 | 
					      m_thd->wait_for_prior_commit();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    WSREP_DEBUG("checkpointing dummy write set %lld", ws_meta.seqno().get());
 | 
				
			||||||
    wsrep_set_SE_checkpoint(ws_meta.gtid(), wsrep_gtid_server.gtid());
 | 
					    wsrep_set_SE_checkpoint(ws_meta.gtid(), wsrep_gtid_server.gtid());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!WSREP_EMULATE_BINLOG(m_thd))
 | 
					    if (!WSREP_EMULATE_BINLOG(m_thd))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -52,6 +52,7 @@
 | 
				
			|||||||
#include "log_event.h"
 | 
					#include "log_event.h"
 | 
				
			||||||
#include "sql_connect.h"
 | 
					#include "sql_connect.h"
 | 
				
			||||||
#include "thread_cache.h"
 | 
					#include "thread_cache.h"
 | 
				
			||||||
 | 
					#include "debug_sync.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <sstream>
 | 
					#include <sstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3107,6 +3108,20 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
 | 
				
			|||||||
                  request_thd, granted_thd);
 | 
					                  request_thd, granted_thd);
 | 
				
			||||||
    ticket->wsrep_report(wsrep_debug);
 | 
					    ticket->wsrep_report(wsrep_debug);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    DEBUG_SYNC(request_thd, "before_wsrep_thd_abort");
 | 
				
			||||||
 | 
					    DBUG_EXECUTE_IF("sync.before_wsrep_thd_abort", {
 | 
				
			||||||
 | 
					      const char act[]= "now "
 | 
				
			||||||
 | 
					                        "SIGNAL sync.before_wsrep_thd_abort_reached "
 | 
				
			||||||
 | 
					                        "WAIT_FOR signal.before_wsrep_thd_abort";
 | 
				
			||||||
 | 
					      DBUG_ASSERT(!debug_sync_set_action(request_thd, STRING_WITH_LEN(act)));
 | 
				
			||||||
 | 
					    };);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Here we will call wsrep_abort_transaction so we should hold
 | 
				
			||||||
 | 
					    THD::LOCK_thd_data to protect victim from concurrent usage
 | 
				
			||||||
 | 
					    and THD::LOCK_thd_kill to protect from disconnect or delete.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    mysql_mutex_lock(&granted_thd->LOCK_thd_kill);
 | 
				
			||||||
    mysql_mutex_lock(&granted_thd->LOCK_thd_data);
 | 
					    mysql_mutex_lock(&granted_thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (wsrep_thd_is_toi(granted_thd) ||
 | 
					    if (wsrep_thd_is_toi(granted_thd) ||
 | 
				
			||||||
@@ -3118,13 +3133,11 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
 | 
				
			|||||||
                    wsrep_thd_query(request_thd));
 | 
					                    wsrep_thd_query(request_thd));
 | 
				
			||||||
        THD_STAGE_INFO(request_thd, stage_waiting_isolation);
 | 
					        THD_STAGE_INFO(request_thd, stage_waiting_isolation);
 | 
				
			||||||
        ticket->wsrep_report(wsrep_debug);
 | 
					        ticket->wsrep_report(wsrep_debug);
 | 
				
			||||||
        mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      else if (wsrep_thd_is_SR(granted_thd) && !wsrep_thd_is_SR(request_thd))
 | 
					      else if (wsrep_thd_is_SR(granted_thd) && !wsrep_thd_is_SR(request_thd))
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        WSREP_MDL_LOG(INFO, "MDL conflict, DDL vs SR",
 | 
					        WSREP_MDL_LOG(INFO, "MDL conflict, DDL vs SR",
 | 
				
			||||||
                      schema, schema_len, request_thd, granted_thd);
 | 
					                      schema, schema_len, request_thd, granted_thd);
 | 
				
			||||||
        mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
        WSREP_DEBUG("wsrep_handle_mdl_conflict DDL vs SR for %s",
 | 
					        WSREP_DEBUG("wsrep_handle_mdl_conflict DDL vs SR for %s",
 | 
				
			||||||
                    wsrep_thd_query(request_thd));
 | 
					                    wsrep_thd_query(request_thd));
 | 
				
			||||||
        THD_STAGE_INFO(request_thd, stage_waiting_isolation);
 | 
					        THD_STAGE_INFO(request_thd, stage_waiting_isolation);
 | 
				
			||||||
@@ -3136,6 +3149,7 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
 | 
				
			|||||||
                      request_thd, granted_thd);
 | 
					                      request_thd, granted_thd);
 | 
				
			||||||
        ticket->wsrep_report(true);
 | 
					        ticket->wsrep_report(true);
 | 
				
			||||||
        mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
 | 
					        mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					        mysql_mutex_unlock(&granted_thd->LOCK_thd_kill);
 | 
				
			||||||
        unireg_abort(1);
 | 
					        unireg_abort(1);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -3146,7 +3160,6 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
 | 
				
			|||||||
                  wsrep_thd_query(request_thd));
 | 
					                  wsrep_thd_query(request_thd));
 | 
				
			||||||
      THD_STAGE_INFO(request_thd, stage_waiting_ddl);
 | 
					      THD_STAGE_INFO(request_thd, stage_waiting_ddl);
 | 
				
			||||||
      ticket->wsrep_report(wsrep_debug);
 | 
					      ticket->wsrep_report(wsrep_debug);
 | 
				
			||||||
      mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
      if (granted_thd->current_backup_stage != BACKUP_FINISHED &&
 | 
					      if (granted_thd->current_backup_stage != BACKUP_FINISHED &&
 | 
				
			||||||
	  wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP))
 | 
						  wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP))
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
@@ -3160,7 +3173,6 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
 | 
				
			|||||||
                  wsrep_thd_query(request_thd));
 | 
					                  wsrep_thd_query(request_thd));
 | 
				
			||||||
      THD_STAGE_INFO(request_thd, stage_waiting_isolation);
 | 
					      THD_STAGE_INFO(request_thd, stage_waiting_isolation);
 | 
				
			||||||
      ticket->wsrep_report(wsrep_debug);
 | 
					      ticket->wsrep_report(wsrep_debug);
 | 
				
			||||||
      mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
      wsrep_abort_thd(request_thd, granted_thd, 1);
 | 
					      wsrep_abort_thd(request_thd, granted_thd, 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
@@ -3174,7 +3186,6 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      if (granted_thd->wsrep_trx().active())
 | 
					      if (granted_thd->wsrep_trx().active())
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
        wsrep_abort_thd(request_thd, granted_thd, 1);
 | 
					        wsrep_abort_thd(request_thd, granted_thd, 1);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      else
 | 
					      else
 | 
				
			||||||
@@ -3183,10 +3194,9 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
 | 
				
			|||||||
          Granted_thd is likely executing with wsrep_on=0. If the requesting
 | 
					          Granted_thd is likely executing with wsrep_on=0. If the requesting
 | 
				
			||||||
          thd is BF, BF abort and wait.
 | 
					          thd is BF, BF abort and wait.
 | 
				
			||||||
        */
 | 
					        */
 | 
				
			||||||
        mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (wsrep_thd_is_BF(request_thd, FALSE))
 | 
					        if (wsrep_thd_is_BF(request_thd, FALSE))
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					          granted_thd->awake_no_mutex(KILL_QUERY_HARD);
 | 
				
			||||||
          ha_abort_transaction(request_thd, granted_thd, TRUE);
 | 
					          ha_abort_transaction(request_thd, granted_thd, TRUE);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
@@ -3195,10 +3205,14 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
 | 
				
			|||||||
                        schema, schema_len,
 | 
					                        schema, schema_len,
 | 
				
			||||||
                        request_thd, granted_thd);
 | 
					                        request_thd, granted_thd);
 | 
				
			||||||
	  ticket->wsrep_report(true);
 | 
						  ticket->wsrep_report(true);
 | 
				
			||||||
 | 
					          mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					          mysql_mutex_unlock(&granted_thd->LOCK_thd_kill);
 | 
				
			||||||
	  unireg_abort(1);
 | 
						  unireg_abort(1);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    mysql_mutex_unlock(&granted_thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					    mysql_mutex_unlock(&granted_thd->LOCK_thd_kill);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
@@ -3210,13 +3224,17 @@ void wsrep_handle_mdl_conflict(MDL_context *requestor_ctx,
 | 
				
			|||||||
static bool abort_replicated(THD *thd)
 | 
					static bool abort_replicated(THD *thd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  bool ret_code= false;
 | 
					  bool ret_code= false;
 | 
				
			||||||
 | 
					  mysql_mutex_lock(&thd->LOCK_thd_kill);
 | 
				
			||||||
 | 
					  mysql_mutex_lock(&thd->LOCK_thd_data);
 | 
				
			||||||
  if (thd->wsrep_trx().state() == wsrep::transaction::s_committing)
 | 
					  if (thd->wsrep_trx().state() == wsrep::transaction::s_committing)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    WSREP_DEBUG("aborting replicated trx: %llu", (ulonglong)(thd->real_id));
 | 
					    WSREP_DEBUG("aborting replicated trx: %llu", (ulonglong)(thd->real_id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    (void)wsrep_abort_thd(thd, thd, TRUE);
 | 
					    wsrep_abort_thd(thd, thd, TRUE);
 | 
				
			||||||
    ret_code= true;
 | 
					    ret_code= true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  mysql_mutex_unlock(&thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					  mysql_mutex_unlock(&thd->LOCK_thd_kill);
 | 
				
			||||||
  return ret_code;
 | 
					  return ret_code;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -148,9 +148,13 @@ void Wsrep_server_service::release_high_priority_service(wsrep::high_priority_se
 | 
				
			|||||||
  wsrep_delete_threadvars();
 | 
					  wsrep_delete_threadvars();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Wsrep_server_service::background_rollback(wsrep::client_state& client_state)
 | 
					void Wsrep_server_service::background_rollback(
 | 
				
			||||||
 | 
					    wsrep::unique_lock<wsrep::mutex> &lock WSREP_UNUSED,
 | 
				
			||||||
 | 
					    wsrep::client_state &client_state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  DBUG_ASSERT(lock.owns_lock());
 | 
				
			||||||
  Wsrep_client_state &cs= static_cast<Wsrep_client_state &>(client_state);
 | 
					  Wsrep_client_state &cs= static_cast<Wsrep_client_state &>(client_state);
 | 
				
			||||||
 | 
					  mysql_mutex_assert_owner(&cs.thd()->LOCK_thd_data);
 | 
				
			||||||
  wsrep_fire_rollbacker(cs.thd());
 | 
					  wsrep_fire_rollbacker(cs.thd());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,7 +46,8 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  void release_high_priority_service(wsrep::high_priority_service*);
 | 
					  void release_high_priority_service(wsrep::high_priority_service*);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void background_rollback(wsrep::client_state&);
 | 
					  void background_rollback(wsrep::unique_lock<wsrep::mutex> &,
 | 
				
			||||||
 | 
					                           wsrep::client_state &);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void bootstrap();
 | 
					  void bootstrap();
 | 
				
			||||||
  void log_message(enum wsrep::log::level, const char*);
 | 
					  void log_message(enum wsrep::log::level, const char*);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										202
									
								
								sql/wsrep_thd.cc
									
									
									
									
									
								
							
							
						
						
									
										202
									
								
								sql/wsrep_thd.cc
									
									
									
									
									
								
							@@ -307,48 +307,9 @@ void wsrep_fire_rollbacker(THD *thd)
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool wsrep_bf_abort_low(THD *bf_thd, THD *victim_thd)
 | 
				
			||||||
int wsrep_abort_thd(THD *bf_thd,
 | 
					 | 
				
			||||||
                    THD *victim_thd,
 | 
					 | 
				
			||||||
                    my_bool signal)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  DBUG_ENTER("wsrep_abort_thd");
 | 
					  mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					 | 
				
			||||||
  mysql_mutex_lock(&victim_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /* Note that when you use RSU node is desynced from cluster, thus WSREP(thd)
 | 
					 | 
				
			||||||
  might not be true.
 | 
					 | 
				
			||||||
  */
 | 
					 | 
				
			||||||
  if ((WSREP_NNULL(bf_thd) ||
 | 
					 | 
				
			||||||
       ((WSREP_ON || bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU) &&
 | 
					 | 
				
			||||||
	 wsrep_thd_is_toi(bf_thd))) &&
 | 
					 | 
				
			||||||
       !wsrep_thd_is_aborting(victim_thd))
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
      WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu",
 | 
					 | 
				
			||||||
                  (long long)bf_thd->real_id, (long long)victim_thd->real_id);
 | 
					 | 
				
			||||||
      mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
      ha_abort_transaction(bf_thd, victim_thd, signal);
 | 
					 | 
				
			||||||
      DBUG_RETURN(1);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  else
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    WSREP_DEBUG("wsrep_abort_thd not effective: bf %llu victim %llu "
 | 
					 | 
				
			||||||
                "wsrep %d wsrep_on %d RSU %d TOI %d aborting %d",
 | 
					 | 
				
			||||||
                (long long)bf_thd->real_id, (long long)victim_thd->real_id,
 | 
					 | 
				
			||||||
                WSREP_NNULL(bf_thd), WSREP_ON,
 | 
					 | 
				
			||||||
                bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU,
 | 
					 | 
				
			||||||
                wsrep_thd_is_toi(bf_thd),
 | 
					 | 
				
			||||||
                wsrep_thd_is_aborting(victim_thd));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
  DBUG_RETURN(1);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  WSREP_LOG_THD(bf_thd, "BF aborter before");
 | 
					 | 
				
			||||||
  WSREP_LOG_THD(victim_thd, "victim before");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef ENABLED_DEBUG_SYNC
 | 
					#ifdef ENABLED_DEBUG_SYNC
 | 
				
			||||||
  DBUG_EXECUTE_IF("sync.wsrep_bf_abort",
 | 
					  DBUG_EXECUTE_IF("sync.wsrep_bf_abort",
 | 
				
			||||||
@@ -362,6 +323,85 @@ bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd)
 | 
				
			|||||||
                  };);
 | 
					                  };);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  wsrep::seqno bf_seqno(bf_thd->wsrep_trx().ws_meta().seqno());
 | 
				
			||||||
 | 
					  bool ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    /* Adopt the lock, it is being held by the caller. */
 | 
				
			||||||
 | 
					    Wsrep_mutex wsm{&victim_thd->LOCK_thd_data};
 | 
				
			||||||
 | 
					    wsrep::unique_lock<wsrep::mutex> lock{wsm, std::adopt_lock};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (wsrep_thd_is_toi(bf_thd))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      ret= victim_thd->wsrep_cs().total_order_bf_abort(lock, bf_seqno);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      DBUG_ASSERT(WSREP(victim_thd) ? victim_thd->wsrep_trx().active() : 1);
 | 
				
			||||||
 | 
					      ret= victim_thd->wsrep_cs().bf_abort(lock, bf_seqno);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (ret)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      /* BF abort should be allowed only once by wsrep-lib.*/
 | 
				
			||||||
 | 
					      DBUG_ASSERT(victim_thd->wsrep_aborter == 0);
 | 
				
			||||||
 | 
					      victim_thd->wsrep_aborter= bf_thd->thread_id;
 | 
				
			||||||
 | 
					      wsrep_bf_aborts_counter++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    lock.release(); /* No unlock at the end of the scope. */
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Sanity check for wsrep-lib calls to return with LOCK_thd_data held. */
 | 
				
			||||||
 | 
					  mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wsrep_abort_thd(THD *bf_thd,
 | 
				
			||||||
 | 
					                    THD *victim_thd,
 | 
				
			||||||
 | 
					                    my_bool signal)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  DBUG_ENTER("wsrep_abort_thd");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mysql_mutex_assert_owner(&victim_thd->LOCK_thd_kill);
 | 
				
			||||||
 | 
					  mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Note that when you use RSU node is desynced from cluster, thus WSREP(thd)
 | 
				
			||||||
 | 
					  might not be true.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					  if ((WSREP(bf_thd)
 | 
				
			||||||
 | 
					       || ((WSREP_ON || bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU)
 | 
				
			||||||
 | 
					           &&  wsrep_thd_is_toi(bf_thd))
 | 
				
			||||||
 | 
					       || bf_thd->lex->sql_command == SQLCOM_KILL)
 | 
				
			||||||
 | 
					      && !wsrep_thd_is_aborting(victim_thd) &&
 | 
				
			||||||
 | 
					      wsrep_bf_abort_low(bf_thd, victim_thd) &&
 | 
				
			||||||
 | 
					      !victim_thd->wsrep_cs().is_rollbacker_active())
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    WSREP_DEBUG("wsrep_abort_thd, by: %llu, victim: %llu",
 | 
				
			||||||
 | 
					                (long long)bf_thd->real_id, (long long)victim_thd->real_id);
 | 
				
			||||||
 | 
					    victim_thd->awake_no_mutex(KILL_QUERY_HARD);
 | 
				
			||||||
 | 
					    ha_abort_transaction(bf_thd, victim_thd, signal);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    WSREP_DEBUG("wsrep_abort_thd not effective: bf %llu victim %llu "
 | 
				
			||||||
 | 
					                "wsrep %d wsrep_on %d RSU %d TOI %d aborting %d",
 | 
				
			||||||
 | 
					                (long long)bf_thd->real_id, (long long)victim_thd->real_id,
 | 
				
			||||||
 | 
					                WSREP_NNULL(bf_thd), WSREP_ON,
 | 
				
			||||||
 | 
					                bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU,
 | 
				
			||||||
 | 
					                wsrep_thd_is_toi(bf_thd),
 | 
				
			||||||
 | 
					                wsrep_thd_is_aborting(victim_thd));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  DBUG_VOID_RETURN;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  WSREP_LOG_THD(bf_thd, "BF aborter before");
 | 
				
			||||||
 | 
					  WSREP_LOG_THD(victim_thd, "victim before");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (WSREP(victim_thd) && !victim_thd->wsrep_trx().active())
 | 
					  if (WSREP(victim_thd) && !victim_thd->wsrep_trx().active())
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    WSREP_DEBUG("wsrep_bf_abort, BF abort for non active transaction."
 | 
					    WSREP_DEBUG("wsrep_bf_abort, BF abort for non active transaction."
 | 
				
			||||||
@@ -384,30 +424,84 @@ bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd)
 | 
				
			|||||||
        wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP))
 | 
					        wsrep_check_mode(WSREP_MODE_BF_MARIABACKUP))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      WSREP_DEBUG("killing connection for non wsrep session");
 | 
					      WSREP_DEBUG("killing connection for non wsrep session");
 | 
				
			||||||
      mysql_mutex_lock(&victim_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
      victim_thd->awake_no_mutex(KILL_CONNECTION);
 | 
					      victim_thd->awake_no_mutex(KILL_CONNECTION);
 | 
				
			||||||
      mysql_mutex_unlock(&victim_thd->LOCK_thd_data);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool ret;
 | 
					  return wsrep_bf_abort_low(bf_thd, victim_thd);
 | 
				
			||||||
  wsrep::seqno bf_seqno(bf_thd->wsrep_trx().ws_meta().seqno());
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (wsrep_thd_is_toi(bf_thd))
 | 
					uint wsrep_kill_thd(THD *thd, THD *victim_thd, killed_state kill_signal)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ret= victim_thd->wsrep_cs().total_order_bf_abort(bf_seqno);
 | 
					  DBUG_ENTER("wsrep_kill_thd");
 | 
				
			||||||
  }
 | 
					  DBUG_ASSERT(WSREP(victim_thd));
 | 
				
			||||||
  else
 | 
					  mysql_mutex_assert_owner(&victim_thd->LOCK_thd_kill);
 | 
				
			||||||
 | 
					  mysql_mutex_assert_owner(&victim_thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					  using trans= wsrep::transaction;
 | 
				
			||||||
 | 
					  auto trx_state= victim_thd->wsrep_trx().state();
 | 
				
			||||||
 | 
					#ifndef DBUG_OFF
 | 
				
			||||||
 | 
					  victim_thd->wsrep_killed_state= trx_state;
 | 
				
			||||||
 | 
					#endif /* DBUG_OFF */
 | 
				
			||||||
 | 
					  /*
 | 
				
			||||||
 | 
					    Already killed or in commit codepath. Mark the victim as killed,
 | 
				
			||||||
 | 
					    the killed status will be restored in wsrep_after_commit() and
 | 
				
			||||||
 | 
					    will be processed after the commit is over. In case of multiple
 | 
				
			||||||
 | 
					    KILLs happened on commit codepath, the last one will be effective.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					  if (victim_thd->wsrep_abort_by_kill ||
 | 
				
			||||||
 | 
					      trx_state == trans::s_preparing ||
 | 
				
			||||||
 | 
					      trx_state == trans::s_committing ||
 | 
				
			||||||
 | 
					      trx_state == trans::s_ordered_commit)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    DBUG_ASSERT(WSREP(victim_thd) ? victim_thd->wsrep_trx().active() : 1);
 | 
					    victim_thd->wsrep_abort_by_kill= kill_signal;
 | 
				
			||||||
    ret= victim_thd->wsrep_cs().bf_abort(bf_seqno);
 | 
					    DBUG_RETURN(0);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (ret)
 | 
					  /*
 | 
				
			||||||
 | 
					    Mark killed victim_thd with kill_signal so that awake_no_mutex does
 | 
				
			||||||
 | 
					    not dive into storage engine. We use ha_abort_transaction()
 | 
				
			||||||
 | 
					    to do the storage engine part for wsrep THDs.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					  DEBUG_SYNC(thd, "wsrep_kill_before_awake_no_mutex");
 | 
				
			||||||
 | 
					  victim_thd->wsrep_abort_by_kill= kill_signal;
 | 
				
			||||||
 | 
					  victim_thd->awake_no_mutex(kill_signal);
 | 
				
			||||||
 | 
					  /* ha_abort_transaction() releases tmp->LOCK_thd_kill, so tmp
 | 
				
			||||||
 | 
					     is not safe to access anymore. */
 | 
				
			||||||
 | 
					  ha_abort_transaction(thd, victim_thd, 1);
 | 
				
			||||||
 | 
					  DBUG_RETURN(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wsrep_backup_kill_for_commit(THD *thd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    wsrep_bf_aborts_counter++;
 | 
					  DBUG_ASSERT(WSREP(thd));
 | 
				
			||||||
 | 
					  mysql_mutex_assert_owner(&thd->LOCK_thd_kill);
 | 
				
			||||||
 | 
					  DBUG_ASSERT(thd->killed != NOT_KILLED);
 | 
				
			||||||
 | 
					  mysql_mutex_lock(&thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					  /* If the transaction will roll back, keep the killed state.
 | 
				
			||||||
 | 
					     For must replay, the replay will happen in different THD context
 | 
				
			||||||
 | 
					     which is high priority and cannot be killed. The owning thread will
 | 
				
			||||||
 | 
					     pick the killed state in after statement processing. */
 | 
				
			||||||
 | 
					  if (thd->wsrep_trx().state() != wsrep::transaction::s_cert_failed &&
 | 
				
			||||||
 | 
					      thd->wsrep_trx().state() != wsrep::transaction::s_must_abort &&
 | 
				
			||||||
 | 
					      thd->wsrep_trx().state() != wsrep::transaction::s_aborting &&
 | 
				
			||||||
 | 
					      thd->wsrep_trx().state() != wsrep::transaction::s_must_replay)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    thd->wsrep_abort_by_kill= thd->killed;
 | 
				
			||||||
 | 
					    thd->wsrep_abort_by_kill_err= thd->killed_err;
 | 
				
			||||||
 | 
					    thd->killed= NOT_KILLED;
 | 
				
			||||||
 | 
					    thd->killed_err= 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return ret;
 | 
					  mysql_mutex_unlock(&thd->LOCK_thd_data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void wsrep_restore_kill_after_commit(THD *thd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  DBUG_ASSERT(WSREP(thd));
 | 
				
			||||||
 | 
					  mysql_mutex_assert_owner(&thd->LOCK_thd_kill);
 | 
				
			||||||
 | 
					  thd->killed= thd->wsrep_abort_by_kill;
 | 
				
			||||||
 | 
					  thd->killed_err= thd->wsrep_abort_by_kill_err;
 | 
				
			||||||
 | 
					  thd->wsrep_abort_by_kill= NOT_KILLED;
 | 
				
			||||||
 | 
					  thd->wsrep_abort_by_kill_err= 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int wsrep_create_threadvars()
 | 
					int wsrep_create_threadvars()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -88,10 +88,39 @@ bool wsrep_create_appliers(long threads, bool mutex_protected=false);
 | 
				
			|||||||
void wsrep_create_rollbacker();
 | 
					void wsrep_create_rollbacker();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd);
 | 
					bool wsrep_bf_abort(THD* bf_thd, THD* victim_thd);
 | 
				
			||||||
int  wsrep_abort_thd(THD *bf_thd,
 | 
					/*
 | 
				
			||||||
 | 
					  Abort transaction for victim_thd. This function is called from
 | 
				
			||||||
 | 
					  MDL BF abort codepath.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					void wsrep_abort_thd(THD *bf_thd,
 | 
				
			||||||
                     THD *victim_thd,
 | 
					                     THD *victim_thd,
 | 
				
			||||||
                     my_bool signal) __attribute__((nonnull(1,2)));
 | 
					                     my_bool signal) __attribute__((nonnull(1,2)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  Kill wsrep connection with kill_signal. Object thd is not
 | 
				
			||||||
 | 
					  guaranteed to exist anymore when this function returns.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Asserts that the caller holds victim_thd->LOCK_thd_kill,
 | 
				
			||||||
 | 
					  victim_thd->LOCK_thd_data.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @param thd THD object for connection that executes the KILL.
 | 
				
			||||||
 | 
					  @param victim_thd THD object for connection to be killed.
 | 
				
			||||||
 | 
					  @param kill_signal Kill signal.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @return Zero if the kill was successful, otherwise non-zero error code.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					uint wsrep_kill_thd(THD *thd, THD *victim_thd, killed_state kill_signal);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  Backup kill status for commit.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wsrep_backup_kill_for_commit(THD *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  Restore KILL status after commit.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void wsrep_restore_kill_after_commit(THD *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
  Helper methods to deal with thread local storage.
 | 
					  Helper methods to deal with thread local storage.
 | 
				
			||||||
  The purpose of these methods is to hide the details of thread
 | 
					  The purpose of these methods is to hide the details of thread
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -256,6 +256,11 @@ static inline int wsrep_before_prepare(THD* thd, bool all)
 | 
				
			|||||||
                   thd->wsrep_trx().ws_meta().gtid(),
 | 
					                   thd->wsrep_trx().ws_meta().gtid(),
 | 
				
			||||||
                   wsrep_gtid_server.gtid());
 | 
					                   wsrep_gtid_server.gtid());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mysql_mutex_lock(&thd->LOCK_thd_kill);
 | 
				
			||||||
 | 
					  if (thd->killed) wsrep_backup_kill_for_commit(thd);
 | 
				
			||||||
 | 
					  mysql_mutex_unlock(&thd->LOCK_thd_kill);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  DBUG_RETURN(ret);
 | 
					  DBUG_RETURN(ret);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -325,6 +330,11 @@ static inline int wsrep_before_commit(THD* thd, bool all)
 | 
				
			|||||||
                   wsrep_gtid_server.gtid());
 | 
					                   wsrep_gtid_server.gtid());
 | 
				
			||||||
    wsrep_register_for_group_commit(thd);
 | 
					    wsrep_register_for_group_commit(thd);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  mysql_mutex_lock(&thd->LOCK_thd_kill);
 | 
				
			||||||
 | 
					  if (thd->killed) wsrep_backup_kill_for_commit(thd);
 | 
				
			||||||
 | 
					  mysql_mutex_unlock(&thd->LOCK_thd_kill);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  DBUG_RETURN(ret);
 | 
					  DBUG_RETURN(ret);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -343,7 +353,8 @@ static inline int wsrep_before_commit(THD* thd, bool all)
 | 
				
			|||||||
static inline int wsrep_ordered_commit(THD* thd, bool all)
 | 
					static inline int wsrep_ordered_commit(THD* thd, bool all)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  DBUG_ENTER("wsrep_ordered_commit");
 | 
					  DBUG_ENTER("wsrep_ordered_commit");
 | 
				
			||||||
  WSREP_DEBUG("wsrep_ordered_commit: %d", wsrep_is_real(thd, all));
 | 
					  WSREP_DEBUG("wsrep_ordered_commit: %d %lld", wsrep_is_real(thd, all),
 | 
				
			||||||
 | 
					              (long long) wsrep_thd_trx_seqno(thd));
 | 
				
			||||||
  DBUG_ASSERT(wsrep_run_commit_hook(thd, all));
 | 
					  DBUG_ASSERT(wsrep_run_commit_hook(thd, all));
 | 
				
			||||||
  DBUG_RETURN(thd->wsrep_cs().ordered_commit());
 | 
					  DBUG_RETURN(thd->wsrep_cs().ordered_commit());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -451,10 +462,18 @@ int wsrep_after_statement(THD* thd)
 | 
				
			|||||||
              wsrep::to_c_string(thd->wsrep_cs().state()),
 | 
					              wsrep::to_c_string(thd->wsrep_cs().state()),
 | 
				
			||||||
              wsrep::to_c_string(thd->wsrep_cs().mode()),
 | 
					              wsrep::to_c_string(thd->wsrep_cs().mode()),
 | 
				
			||||||
              wsrep::to_c_string(thd->wsrep_cs().transaction().state()));
 | 
					              wsrep::to_c_string(thd->wsrep_cs().transaction().state()));
 | 
				
			||||||
  DBUG_RETURN((thd->wsrep_cs().state() != wsrep::client_state::s_none &&
 | 
					  int ret= ((thd->wsrep_cs().state() != wsrep::client_state::s_none &&
 | 
				
			||||||
               thd->wsrep_cs().mode() == Wsrep_client_state::m_local) &&
 | 
					               thd->wsrep_cs().mode() == Wsrep_client_state::m_local) &&
 | 
				
			||||||
              !thd->internal_transaction() ?
 | 
					              !thd->internal_transaction() ?
 | 
				
			||||||
              thd->wsrep_cs().after_statement() : 0);
 | 
					              thd->wsrep_cs().after_statement() : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (wsrep_is_active(thd))
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    mysql_mutex_lock(&thd->LOCK_thd_kill);
 | 
				
			||||||
 | 
					    wsrep_restore_kill_after_commit(thd);
 | 
				
			||||||
 | 
					    mysql_mutex_unlock(&thd->LOCK_thd_kill);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  DBUG_RETURN(ret);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void wsrep_after_apply(THD* thd)
 | 
					static inline void wsrep_after_apply(THD* thd)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2140,6 +2140,8 @@ void buf_page_free(fil_space_t *space, uint32_t page, mtr_t *mtr)
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  block->page.lock.x_lock();
 | 
					  block->page.lock.x_lock();
 | 
				
			||||||
 | 
					  if (block->page.is_ibuf_exist())
 | 
				
			||||||
 | 
					    ibuf_merge_or_delete_for_page(nullptr, page_id, block->page.zip_size());
 | 
				
			||||||
#ifdef BTR_CUR_HASH_ADAPT
 | 
					#ifdef BTR_CUR_HASH_ADAPT
 | 
				
			||||||
  if (block->index)
 | 
					  if (block->index)
 | 
				
			||||||
    btr_search_drop_page_hash_index(block, false);
 | 
					    btr_search_drop_page_hash_index(block, false);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -372,7 +372,7 @@ void buf_dblwr_t::recover()
 | 
				
			|||||||
    const uint32_t space_id= page_get_space_id(page);
 | 
					    const uint32_t space_id= page_get_space_id(page);
 | 
				
			||||||
    const page_id_t page_id(space_id, page_no);
 | 
					    const page_id_t page_id(space_id, page_no);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (recv_sys.lsn < lsn)
 | 
					    if (recv_sys.scanned_lsn < lsn)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      ib::info() << "Ignoring a doublewrite copy of page " << page_id
 | 
					      ib::info() << "Ignoring a doublewrite copy of page " << page_id
 | 
				
			||||||
                 << " with future log sequence number " << lsn;
 | 
					                 << " with future log sequence number " << lsn;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -966,12 +966,20 @@ uint32_t fil_space_t::flush_freed(bool writable)
 | 
				
			|||||||
  mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex);
 | 
					  mysql_mutex_assert_not_owner(&buf_pool.flush_list_mutex);
 | 
				
			||||||
  mysql_mutex_assert_not_owner(&buf_pool.mutex);
 | 
					  mysql_mutex_assert_not_owner(&buf_pool.mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (;;)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
    freed_range_mutex.lock();
 | 
					    freed_range_mutex.lock();
 | 
				
			||||||
  if (freed_ranges.empty() || log_sys.get_flushed_lsn() < get_last_freed_lsn())
 | 
					    if (freed_ranges.empty())
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      freed_range_mutex.unlock();
 | 
					      freed_range_mutex.unlock();
 | 
				
			||||||
      return 0;
 | 
					      return 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    const lsn_t flush_lsn= last_freed_lsn;
 | 
				
			||||||
 | 
					    if (log_sys.get_flushed_lsn() >= flush_lsn)
 | 
				
			||||||
 | 
					      break;
 | 
				
			||||||
 | 
					    freed_range_mutex.unlock();
 | 
				
			||||||
 | 
					    log_write_up_to(flush_lsn, true);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const unsigned physical{physical_size()};
 | 
					  const unsigned physical{physical_size()};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2430,6 +2438,7 @@ static void buf_flush_page_cleaner()
 | 
				
			|||||||
    else if (buf_pool.ran_out())
 | 
					    else if (buf_pool.ran_out())
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      buf_pool.page_cleaner_set_idle(false);
 | 
					      buf_pool.page_cleaner_set_idle(false);
 | 
				
			||||||
 | 
					      buf_pool.get_oldest_modification(0);
 | 
				
			||||||
      mysql_mutex_unlock(&buf_pool.flush_list_mutex);
 | 
					      mysql_mutex_unlock(&buf_pool.flush_list_mutex);
 | 
				
			||||||
      n= srv_max_io_capacity;
 | 
					      n= srv_max_io_capacity;
 | 
				
			||||||
      mysql_mutex_lock(&buf_pool.mutex);
 | 
					      mysql_mutex_lock(&buf_pool.mutex);
 | 
				
			||||||
@@ -2583,6 +2592,7 @@ ATTRIBUTE_COLD void buf_flush_page_cleaner_init()
 | 
				
			|||||||
/** Flush the buffer pool on shutdown. */
 | 
					/** Flush the buffer pool on shutdown. */
 | 
				
			||||||
ATTRIBUTE_COLD void buf_flush_buffer_pool()
 | 
					ATTRIBUTE_COLD void buf_flush_buffer_pool()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  ut_ad(!os_aio_pending_reads());
 | 
				
			||||||
  ut_ad(!buf_page_cleaner_is_active);
 | 
					  ut_ad(!buf_page_cleaner_is_active);
 | 
				
			||||||
  ut_ad(!buf_flush_sync_lsn);
 | 
					  ut_ad(!buf_flush_sync_lsn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1086,7 +1086,11 @@ static bool buf_LRU_block_remove_hashed(buf_page_t *bpage, const page_id_t id,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			ut_a(!zip || !bpage->oldest_modification());
 | 
								ut_a(!zip || !bpage->oldest_modification());
 | 
				
			||||||
			ut_ad(bpage->zip_size());
 | 
								ut_ad(bpage->zip_size());
 | 
				
			||||||
 | 
								/* Skip consistency checks if the page was freed.
 | 
				
			||||||
 | 
								In recovery, we could get a sole FREE_PAGE record
 | 
				
			||||||
 | 
								and nothing else, for a ROW_FORMAT=COMPRESSED page.
 | 
				
			||||||
 | 
								Its contents would be garbage. */
 | 
				
			||||||
 | 
								if (!bpage->is_freed())
 | 
				
			||||||
			switch (fil_page_get_type(page)) {
 | 
								switch (fil_page_get_type(page)) {
 | 
				
			||||||
			case FIL_PAGE_TYPE_ALLOCATED:
 | 
								case FIL_PAGE_TYPE_ALLOCATED:
 | 
				
			||||||
			case FIL_PAGE_INODE:
 | 
								case FIL_PAGE_INODE:
 | 
				
			||||||
@@ -1217,6 +1221,7 @@ void buf_pool_t::corrupted_evict(buf_page_t *bpage, uint32_t state)
 | 
				
			|||||||
  buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(id.fold());
 | 
					  buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(id.fold());
 | 
				
			||||||
  page_hash_latch &hash_lock= buf_pool.page_hash.lock_get(chain);
 | 
					  page_hash_latch &hash_lock= buf_pool.page_hash.lock_get(chain);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  recv_sys.free_corrupted_page(id);
 | 
				
			||||||
  mysql_mutex_lock(&mutex);
 | 
					  mysql_mutex_lock(&mutex);
 | 
				
			||||||
  hash_lock.lock();
 | 
					  hash_lock.lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1241,8 +1246,6 @@ void buf_pool_t::corrupted_evict(buf_page_t *bpage, uint32_t state)
 | 
				
			|||||||
    buf_LRU_block_free_hashed_page(reinterpret_cast<buf_block_t*>(bpage));
 | 
					    buf_LRU_block_free_hashed_page(reinterpret_cast<buf_block_t*>(bpage));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  mysql_mutex_unlock(&mutex);
 | 
					  mysql_mutex_unlock(&mutex);
 | 
				
			||||||
 | 
					 | 
				
			||||||
  recv_sys.free_corrupted_page(id);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Update buf_pool.LRU_old_ratio.
 | 
					/** Update buf_pool.LRU_old_ratio.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -265,9 +265,6 @@ buf_read_page_low(
 | 
				
			|||||||
	buf_page_t*	bpage;
 | 
						buf_page_t*	bpage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (buf_dblwr.is_inside(page_id)) {
 | 
						if (buf_dblwr.is_inside(page_id)) {
 | 
				
			||||||
		ib::error() << "Trying to read doublewrite buffer page "
 | 
					 | 
				
			||||||
			<< page_id;
 | 
					 | 
				
			||||||
		ut_ad(0);
 | 
					 | 
				
			||||||
		space->release();
 | 
							space->release();
 | 
				
			||||||
		return DB_PAGE_CORRUPTED;
 | 
							return DB_PAGE_CORRUPTED;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -525,7 +522,7 @@ buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /* We will check that almost all pages in the area have been accessed
 | 
					  /* We will check that almost all pages in the area have been accessed
 | 
				
			||||||
  in the desired order. */
 | 
					  in the desired order. */
 | 
				
			||||||
  const bool descending= page_id == low;
 | 
					  const bool descending= page_id != low;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!descending && page_id != high_1)
 | 
					  if (!descending && page_id != high_1)
 | 
				
			||||||
    /* This is not a border page of the area */
 | 
					    /* This is not a border page of the area */
 | 
				
			||||||
@@ -555,7 +552,7 @@ fail:
 | 
				
			|||||||
                               uint32_t{buf_pool.read_ahead_area});
 | 
					                               uint32_t{buf_pool.read_ahead_area});
 | 
				
			||||||
  page_id_t new_low= low, new_high_1= high_1;
 | 
					  page_id_t new_low= low, new_high_1= high_1;
 | 
				
			||||||
  unsigned prev_accessed= 0;
 | 
					  unsigned prev_accessed= 0;
 | 
				
			||||||
  for (page_id_t i= low; i != high_1; ++i)
 | 
					  for (page_id_t i= low; i <= high_1; ++i)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(i.fold());
 | 
					    buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(i.fold());
 | 
				
			||||||
    transactional_shared_lock_guard<page_hash_latch> g
 | 
					    transactional_shared_lock_guard<page_hash_latch> g
 | 
				
			||||||
@@ -583,12 +580,21 @@ failed:
 | 
				
			|||||||
      if (prev == FIL_NULL || next == FIL_NULL)
 | 
					      if (prev == FIL_NULL || next == FIL_NULL)
 | 
				
			||||||
        goto fail;
 | 
					        goto fail;
 | 
				
			||||||
      page_id_t id= page_id;
 | 
					      page_id_t id= page_id;
 | 
				
			||||||
      if (descending && next - 1 == page_id.page_no())
 | 
					      if (descending)
 | 
				
			||||||
        id.set_page_no(prev);
 | 
					      {
 | 
				
			||||||
      else if (!descending && prev + 1 == page_id.page_no())
 | 
					        if (id == high_1)
 | 
				
			||||||
        id.set_page_no(next);
 | 
					          ++id;
 | 
				
			||||||
 | 
					        else if (next - 1 != page_id.page_no())
 | 
				
			||||||
 | 
					          goto fail;
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
        goto fail; /* Successor or predecessor not in the right order */
 | 
					          id.set_page_no(prev);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        if (prev + 1 != page_id.page_no())
 | 
				
			||||||
 | 
					          goto fail;
 | 
				
			||||||
 | 
					        id.set_page_no(next);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      new_low= id - (id.page_no() % buf_read_ahead_area);
 | 
					      new_low= id - (id.page_no() % buf_read_ahead_area);
 | 
				
			||||||
      new_high_1= new_low + (buf_read_ahead_area - 1);
 | 
					      new_high_1= new_low + (buf_read_ahead_area - 1);
 | 
				
			||||||
@@ -620,7 +626,7 @@ failed:
 | 
				
			|||||||
  /* If we got this far, read-ahead can be sensible: do it */
 | 
					  /* If we got this far, read-ahead can be sensible: do it */
 | 
				
			||||||
  count= 0;
 | 
					  count= 0;
 | 
				
			||||||
  for (ulint ibuf_mode= ibuf ? BUF_READ_IBUF_PAGES_ONLY : BUF_READ_ANY_PAGE;
 | 
					  for (ulint ibuf_mode= ibuf ? BUF_READ_IBUF_PAGES_ONLY : BUF_READ_ANY_PAGE;
 | 
				
			||||||
       new_low != new_high_1; ++new_low)
 | 
					       new_low <= new_high_1; ++new_low)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    if (ibuf_bitmap_page(new_low, zip_size))
 | 
					    if (ibuf_bitmap_page(new_low, zip_size))
 | 
				
			||||||
      continue;
 | 
					      continue;
 | 
				
			||||||
@@ -649,60 +655,35 @@ failed:
 | 
				
			|||||||
  return count;
 | 
					  return count;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @return whether a page has been freed */
 | 
					/** Schedule a page for recovery.
 | 
				
			||||||
inline bool fil_space_t::is_freed(uint32_t page)
 | 
					@param space    tablespace
 | 
				
			||||||
 | 
					@param page_id  page identifier
 | 
				
			||||||
 | 
					@param recs     log records
 | 
				
			||||||
 | 
					@param init     page initialization, or nullptr if the page needs to be read */
 | 
				
			||||||
 | 
					void buf_read_recover(fil_space_t *space, const page_id_t page_id,
 | 
				
			||||||
 | 
					                      page_recv_t &recs, recv_init *init)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  std::lock_guard<std::mutex> freed_lock(freed_range_mutex);
 | 
					  ut_ad(space->id == page_id.space());
 | 
				
			||||||
  return freed_ranges.contains(page);
 | 
					  space->reacquire();
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Issues read requests for pages which recovery wants to read in.
 | 
					 | 
				
			||||||
@param space_id	tablespace identifier
 | 
					 | 
				
			||||||
@param page_nos	page numbers to read, in ascending order */
 | 
					 | 
				
			||||||
void buf_read_recv_pages(uint32_t space_id, st_::span<uint32_t> page_nos)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	fil_space_t* space = fil_space_t::get(space_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!space) {
 | 
					 | 
				
			||||||
		/* The tablespace is missing or unreadable: do nothing */
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const ulint zip_size= space->zip_size();
 | 
					  const ulint zip_size= space->zip_size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (ulint i = 0; i < page_nos.size(); i++) {
 | 
					  if (init)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
		/* Ignore if the page already present in freed ranges. */
 | 
					    if (buf_page_t *bpage= buf_page_init_for_read(BUF_READ_ANY_PAGE, page_id,
 | 
				
			||||||
		if (space->is_freed(page_nos[i])) {
 | 
					                                                  zip_size, true))
 | 
				
			||||||
			continue;
 | 
					    {
 | 
				
			||||||
 | 
					      ut_ad(bpage->in_file());
 | 
				
			||||||
 | 
					      os_fake_read(IORequest{bpage, (buf_tmp_buffer_t*) &recs,
 | 
				
			||||||
 | 
					                             UT_LIST_GET_FIRST(space->chain),
 | 
				
			||||||
 | 
					                             IORequest::READ_ASYNC}, ptrdiff_t(init));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
		const page_id_t	cur_page_id(space_id, page_nos[i]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		ulint limit = 0;
 | 
					 | 
				
			||||||
		for (ulint j = 0; j < buf_pool.n_chunks; j++) {
 | 
					 | 
				
			||||||
			limit += buf_pool.chunks[j].size / 2;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  else if (dberr_t err= buf_read_page_low(space, false, BUF_READ_ANY_PAGE,
 | 
				
			||||||
		if (os_aio_pending_reads() >= limit) {
 | 
					                                          page_id, zip_size, true))
 | 
				
			||||||
			os_aio_wait_until_no_pending_reads(false);
 | 
					  {
 | 
				
			||||||
		}
 | 
					    if (err != DB_SUCCESS_LOCKED_REC)
 | 
				
			||||||
 | 
					 | 
				
			||||||
		space->reacquire();
 | 
					 | 
				
			||||||
		switch (buf_read_page_low(space, false, BUF_READ_ANY_PAGE,
 | 
					 | 
				
			||||||
					  cur_page_id, zip_size, true)) {
 | 
					 | 
				
			||||||
		case DB_SUCCESS: case DB_SUCCESS_LOCKED_REC:
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
      sql_print_error("InnoDB: Recovery failed to read page "
 | 
					      sql_print_error("InnoDB: Recovery failed to read page "
 | 
				
			||||||
                      UINT32PF " from %s",
 | 
					                      UINT32PF " from %s",
 | 
				
			||||||
					cur_page_id.page_no(),
 | 
					                      page_id.page_no(), space->chain.start->name);
 | 
				
			||||||
					space->chain.start->name);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        DBUG_PRINT("ib_buf", ("recovery read (%zu pages) for %s",
 | 
					 | 
				
			||||||
			      page_nos.size(), space->chain.start->name));
 | 
					 | 
				
			||||||
	space->release();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -204,7 +204,17 @@ static const dict_table_schema_t table_stats_schema =
 | 
				
			|||||||
  {
 | 
					  {
 | 
				
			||||||
    {"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
 | 
					    {"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
 | 
				
			||||||
    {"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597},
 | 
					    {"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597},
 | 
				
			||||||
    {"last_update", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 4},
 | 
					    /*
 | 
				
			||||||
 | 
					      Don't check the DATA_UNSIGNED flag in last_update.
 | 
				
			||||||
 | 
					      It presents if the server is running in a pure MariaDB installation,
 | 
				
			||||||
 | 
					      because MariaDB's Field_timestampf::flags has UNSIGNED_FLAG.
 | 
				
			||||||
 | 
					      But DATA_UNSIGNED misses when the server starts on a MySQL-5.7 directory
 | 
				
			||||||
 | 
					      (during a migration), because MySQL's Field_timestampf::flags does not
 | 
				
			||||||
 | 
					      have UNSIGNED_FLAG.
 | 
				
			||||||
 | 
					      This is fine not to check DATA_UNSIGNED, because Field_timestampf
 | 
				
			||||||
 | 
					      in both MariaDB and MySQL support only non-negative time_t values.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    {"last_update", DATA_INT, DATA_NOT_NULL, 4},
 | 
				
			||||||
    {"n_rows", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
 | 
					    {"n_rows", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
 | 
				
			||||||
    {"clustered_index_size", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
 | 
					    {"clustered_index_size", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
 | 
				
			||||||
    {"sum_of_other_index_sizes", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
 | 
					    {"sum_of_other_index_sizes", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
 | 
				
			||||||
@@ -218,7 +228,11 @@ static const dict_table_schema_t index_stats_schema =
 | 
				
			|||||||
    {"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
 | 
					    {"database_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
 | 
				
			||||||
    {"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597},
 | 
					    {"table_name", DATA_VARMYSQL, DATA_NOT_NULL, 597},
 | 
				
			||||||
    {"index_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
 | 
					    {"index_name", DATA_VARMYSQL, DATA_NOT_NULL, 192},
 | 
				
			||||||
    {"last_update", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 4},
 | 
					    /*
 | 
				
			||||||
 | 
					      Don't check the DATA_UNSIGNED flag in last_update.
 | 
				
			||||||
 | 
					      See comments about last_update in table_stats_schema above.
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    {"last_update", DATA_INT, DATA_NOT_NULL, 4},
 | 
				
			||||||
    {"stat_name", DATA_VARMYSQL, DATA_NOT_NULL, 64*3},
 | 
					    {"stat_name", DATA_VARMYSQL, DATA_NOT_NULL, 64*3},
 | 
				
			||||||
    {"stat_value", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
 | 
					    {"stat_value", DATA_INT, DATA_NOT_NULL | DATA_UNSIGNED, 8},
 | 
				
			||||||
    {"sample_size", DATA_INT, DATA_UNSIGNED, 8},
 | 
					    {"sample_size", DATA_INT, DATA_UNSIGNED, 8},
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -447,7 +447,9 @@ static bool fil_node_open_file(fil_node_t *node)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return fil_node_open_file_low(node);
 | 
					  /* The node can be opened beween releasing and acquiring fil_system.mutex
 | 
				
			||||||
 | 
					  in the above code */
 | 
				
			||||||
 | 
					  return node->is_open() || fil_node_open_file_low(node);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Close the file handle. */
 | 
					/** Close the file handle. */
 | 
				
			||||||
@@ -1953,8 +1955,8 @@ err_exit:
 | 
				
			|||||||
						     FIL_TYPE_TABLESPACE,
 | 
											     FIL_TYPE_TABLESPACE,
 | 
				
			||||||
						     crypt_data, mode, true)) {
 | 
											     crypt_data, mode, true)) {
 | 
				
			||||||
		fil_node_t* node = space->add(path, file, size, false, true);
 | 
							fil_node_t* node = space->add(path, file, size, false, true);
 | 
				
			||||||
		mysql_mutex_unlock(&fil_system.mutex);
 | 
					 | 
				
			||||||
		IF_WIN(node->find_metadata(), node->find_metadata(file, true));
 | 
							IF_WIN(node->find_metadata(), node->find_metadata(file, true));
 | 
				
			||||||
 | 
							mysql_mutex_unlock(&fil_system.mutex);
 | 
				
			||||||
		mtr.start();
 | 
							mtr.start();
 | 
				
			||||||
		mtr.set_named_space(space);
 | 
							mtr.set_named_space(space);
 | 
				
			||||||
		ut_a(fsp_header_init(space, size, &mtr) == DB_SUCCESS);
 | 
							ut_a(fsp_header_init(space, size, &mtr) == DB_SUCCESS);
 | 
				
			||||||
@@ -2775,38 +2777,41 @@ func_exit:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <tpool.h>
 | 
					#include <tpool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Callback for AIO completion */
 | 
					void IORequest::write_complete() const
 | 
				
			||||||
void fil_aio_callback(const IORequest &request)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  ut_ad(fil_validate_skip());
 | 
					  ut_ad(fil_validate_skip());
 | 
				
			||||||
  ut_ad(request.node);
 | 
					  ut_ad(node);
 | 
				
			||||||
 | 
					  ut_ad(is_write());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!request.bpage)
 | 
					  if (!bpage)
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    ut_ad(!srv_read_only_mode);
 | 
					    ut_ad(!srv_read_only_mode);
 | 
				
			||||||
    if (request.type == IORequest::DBLWR_BATCH)
 | 
					    if (type == IORequest::DBLWR_BATCH)
 | 
				
			||||||
      buf_dblwr.flush_buffered_writes_completed(request);
 | 
					      buf_dblwr.flush_buffered_writes_completed(*this);
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      ut_ad(request.type == IORequest::WRITE_ASYNC);
 | 
					      ut_ad(type == IORequest::WRITE_ASYNC);
 | 
				
			||||||
write_completed:
 | 
					 | 
				
			||||||
    request.node->complete_write();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  else if (request.is_write())
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    buf_page_write_complete(request);
 | 
					 | 
				
			||||||
    goto write_completed;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else
 | 
					  else
 | 
				
			||||||
 | 
					    buf_page_write_complete(*this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  node->complete_write();
 | 
				
			||||||
 | 
					  node->space->release();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void IORequest::read_complete() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ut_ad(request.is_read());
 | 
					  ut_ad(fil_validate_skip());
 | 
				
			||||||
 | 
					  ut_ad(node);
 | 
				
			||||||
 | 
					  ut_ad(is_read());
 | 
				
			||||||
 | 
					  ut_ad(bpage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* IMPORTANT: since i/o handling for reads will read also the insert
 | 
					  /* IMPORTANT: since i/o handling for reads will read also the insert
 | 
				
			||||||
  buffer in fil_system.sys_space, we have to be very careful not to
 | 
					  buffer in fil_system.sys_space, we have to be very careful not to
 | 
				
			||||||
    introduce deadlocks. We never close fil_system.sys_space data
 | 
					  introduce deadlocks. We never close fil_system.sys_space data files
 | 
				
			||||||
    files and never issue asynchronous reads of change buffer pages. */
 | 
					  and never issue asynchronous reads of change buffer pages. */
 | 
				
			||||||
    const page_id_t id(request.bpage->id());
 | 
					  const page_id_t id(bpage->id());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (dberr_t err= request.bpage->read_complete(*request.node))
 | 
					  if (dberr_t err= bpage->read_complete(*node))
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    if (recv_recovery_is_on() && !srv_force_recovery)
 | 
					    if (recv_recovery_is_on() && !srv_force_recovery)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -2817,11 +2822,10 @@ write_completed:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (err != DB_FAIL)
 | 
					    if (err != DB_FAIL)
 | 
				
			||||||
      ib::error() << "Failed to read page " << id.page_no()
 | 
					      ib::error() << "Failed to read page " << id.page_no()
 | 
				
			||||||
                    << " from file '" << request.node->name << "': " << err;
 | 
					                  << " from file '" << node->name << "': " << err;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  request.node->space->release();
 | 
					  node->space->release();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Flush to disk the writes in file spaces of the given type
 | 
					/** Flush to disk the writes in file spaces of the given type
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1284,24 +1284,21 @@ static dberr_t fsp_free_page(fil_space_t *space, page_no_t offset, mtr_t *mtr)
 | 
				
			|||||||
			      + header->page.frame, frag_n_used - 1);
 | 
								      + header->page.frame, frag_n_used - 1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mtr->free(*space, static_cast<uint32_t>(offset));
 | 
				
			||||||
 | 
						xdes_set_free<true>(*xdes, descr, offset % FSP_EXTENT_SIZE, mtr);
 | 
				
			||||||
 | 
						ut_ad(err == DB_SUCCESS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!xdes_get_n_used(descr)) {
 | 
						if (!xdes_get_n_used(descr)) {
 | 
				
			||||||
		/* The extent has become free: move it to another list */
 | 
							/* The extent has become free: move it to another list */
 | 
				
			||||||
		err = flst_remove(header, FSP_HEADER_OFFSET + FSP_FREE_FRAG,
 | 
							err = flst_remove(header, FSP_HEADER_OFFSET + FSP_FREE_FRAG,
 | 
				
			||||||
				  xdes, xoffset, mtr);
 | 
									  xdes, xoffset, mtr);
 | 
				
			||||||
		if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
 | 
							if (err == DB_SUCCESS) {
 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
			err = fsp_free_extent(space, offset, mtr);
 | 
								err = fsp_free_extent(space, offset, mtr);
 | 
				
			||||||
		if (UNIV_UNLIKELY(err != DB_SUCCESS)) {
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mtr->free(*space, static_cast<uint32_t>(offset));
 | 
					 | 
				
			||||||
	xdes_set_free<true>(*xdes, descr, offset % FSP_EXTENT_SIZE, mtr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return DB_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @return Number of segment inodes which fit on a single page */
 | 
					/** @return Number of segment inodes which fit on a single page */
 | 
				
			||||||
inline ulint FSP_SEG_INODES_PER_PAGE(ulint physical_size)
 | 
					inline ulint FSP_SEG_INODES_PER_PAGE(ulint physical_size)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -945,7 +945,8 @@ static SHOW_VAR innodb_status_variables[]= {
 | 
				
			|||||||
  {"buffer_pool_read_ahead", &buf_pool.stat.n_ra_pages_read, SHOW_SIZE_T},
 | 
					  {"buffer_pool_read_ahead", &buf_pool.stat.n_ra_pages_read, SHOW_SIZE_T},
 | 
				
			||||||
  {"buffer_pool_read_ahead_evicted",
 | 
					  {"buffer_pool_read_ahead_evicted",
 | 
				
			||||||
   &buf_pool.stat.n_ra_pages_evicted, SHOW_SIZE_T},
 | 
					   &buf_pool.stat.n_ra_pages_evicted, SHOW_SIZE_T},
 | 
				
			||||||
  {"buffer_pool_read_requests", &buf_pool.stat.n_page_gets, SHOW_SIZE_T},
 | 
					  {"buffer_pool_read_requests",
 | 
				
			||||||
 | 
					   &export_vars.innodb_buffer_pool_read_requests, SHOW_SIZE_T},
 | 
				
			||||||
  {"buffer_pool_reads", &buf_pool.stat.n_pages_read, SHOW_SIZE_T},
 | 
					  {"buffer_pool_reads", &buf_pool.stat.n_pages_read, SHOW_SIZE_T},
 | 
				
			||||||
  {"buffer_pool_wait_free", &buf_pool.stat.LRU_waits, SHOW_SIZE_T},
 | 
					  {"buffer_pool_wait_free", &buf_pool.stat.LRU_waits, SHOW_SIZE_T},
 | 
				
			||||||
  {"buffer_pool_write_requests", &buf_pool.flush_list_requests, SHOW_SIZE_T},
 | 
					  {"buffer_pool_write_requests", &buf_pool.flush_list_requests, SHOW_SIZE_T},
 | 
				
			||||||
@@ -1917,7 +1918,8 @@ static void innodb_disable_internal_writes(bool disable)
 | 
				
			|||||||
    sst_enable_innodb_writes();
 | 
					    sst_enable_innodb_writes();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void wsrep_abort_transaction(handlerton*, THD *, THD *, my_bool);
 | 
					static void wsrep_abort_transaction(handlerton *, THD *, THD *, my_bool)
 | 
				
			||||||
 | 
					    __attribute__((nonnull));
 | 
				
			||||||
static int innobase_wsrep_set_checkpoint(handlerton *hton, const XID *xid);
 | 
					static int innobase_wsrep_set_checkpoint(handlerton *hton, const XID *xid);
 | 
				
			||||||
static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
 | 
					static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
 | 
				
			||||||
#endif /* WITH_WSREP */
 | 
					#endif /* WITH_WSREP */
 | 
				
			||||||
@@ -18622,36 +18624,45 @@ void lock_wait_wsrep_kill(trx_t *bf_trx, ulong thd_id, trx_id_t trx_id)
 | 
				
			|||||||
                      wsrep_thd_client_mode_str(vthd),
 | 
					                      wsrep_thd_client_mode_str(vthd),
 | 
				
			||||||
                      wsrep_thd_transaction_state_str(vthd),
 | 
					                      wsrep_thd_transaction_state_str(vthd),
 | 
				
			||||||
                      wsrep_thd_query(vthd));
 | 
					                      wsrep_thd_query(vthd));
 | 
				
			||||||
          /* Mark transaction as a victim for Galera abort */
 | 
					 | 
				
			||||||
          vtrx->lock.set_wsrep_victim();
 | 
					 | 
				
			||||||
          if (!wsrep_thd_set_wsrep_aborter(bf_thd, vthd))
 | 
					 | 
				
			||||||
          aborting= true;
 | 
					          aborting= true;
 | 
				
			||||||
          else
 | 
					 | 
				
			||||||
            WSREP_DEBUG("kill transaction skipped due to wsrep_aborter set");
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      mysql_mutex_unlock(&lock_sys.wait_mutex);
 | 
					      mysql_mutex_unlock(&lock_sys.wait_mutex);
 | 
				
			||||||
      vtrx->mutex_unlock();
 | 
					      vtrx->mutex_unlock();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    wsrep_thd_UNLOCK(vthd);
 | 
					
 | 
				
			||||||
    if (aborting)
 | 
					    DEBUG_SYNC(bf_thd, "before_wsrep_thd_abort");
 | 
				
			||||||
 | 
					    if (aborting && wsrep_thd_bf_abort(bf_thd, vthd, true))
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					      /* Need to grab mutexes again to ensure that the trx is still in
 | 
				
			||||||
 | 
					         right state. */
 | 
				
			||||||
 | 
					      lock_sys.wr_lock(SRW_LOCK_CALL);
 | 
				
			||||||
 | 
					      mysql_mutex_lock(&lock_sys.wait_mutex);
 | 
				
			||||||
 | 
					      vtrx->mutex_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      /* if victim is waiting for some other lock, we have to cancel
 | 
					      /* if victim is waiting for some other lock, we have to cancel
 | 
				
			||||||
         that waiting
 | 
					         that waiting
 | 
				
			||||||
      */
 | 
					      */
 | 
				
			||||||
      lock_sys.cancel_lock_wait_for_trx(vtrx);
 | 
					      if (vtrx->id == trx_id)
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
      DEBUG_SYNC(bf_thd, "before_wsrep_thd_abort");
 | 
					        switch (vtrx->state) {
 | 
				
			||||||
      if (!wsrep_thd_bf_abort(bf_thd, vthd, true))
 | 
					        default:
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case TRX_STATE_ACTIVE:
 | 
				
			||||||
 | 
					        case TRX_STATE_PREPARED:
 | 
				
			||||||
 | 
					          lock_sys.cancel_lock_wait_for_wsrep_bf_abort(vtrx);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      lock_sys.wr_unlock();
 | 
				
			||||||
 | 
					      mysql_mutex_unlock(&lock_sys.wait_mutex);
 | 
				
			||||||
 | 
					      vtrx->mutex_unlock();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        wsrep_thd_LOCK(vthd);
 | 
					 | 
				
			||||||
        wsrep_thd_set_wsrep_aborter(NULL, vthd);
 | 
					 | 
				
			||||||
        wsrep_thd_UNLOCK(vthd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      WSREP_DEBUG("wsrep_thd_bf_abort has failed, victim %lu will survive",
 | 
					      WSREP_DEBUG("wsrep_thd_bf_abort has failed, victim %lu will survive",
 | 
				
			||||||
                  thd_get_thread_id(vthd));
 | 
					                  thd_get_thread_id(vthd));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    }
 | 
					    wsrep_thd_UNLOCK(vthd);
 | 
				
			||||||
    wsrep_thd_kill_UNLOCK(vthd);
 | 
					    wsrep_thd_kill_UNLOCK(vthd);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -18659,67 +18670,49 @@ void lock_wait_wsrep_kill(trx_t *bf_trx, ulong thd_id, trx_id_t trx_id)
 | 
				
			|||||||
/** This function forces the victim transaction to abort. Aborting the
 | 
					/** This function forces the victim transaction to abort. Aborting the
 | 
				
			||||||
  transaction does NOT end it, it still has to be rolled back.
 | 
					  transaction does NOT end it, it still has to be rolled back.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The caller must lock LOCK_thd_kill and LOCK_thd_data.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @param bf_thd       brute force THD asking for the abort
 | 
					  @param bf_thd       brute force THD asking for the abort
 | 
				
			||||||
  @param victim_thd   victim THD to be aborted
 | 
					  @param victim_thd   victim THD to be aborted
 | 
				
			||||||
 | 
					 | 
				
			||||||
  @return 0 victim was aborted
 | 
					 | 
				
			||||||
  @return -1 victim thread was aborted (no transaction)
 | 
					 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
static
 | 
					static void wsrep_abort_transaction(handlerton *, THD *bf_thd, THD *victim_thd,
 | 
				
			||||||
void
 | 
					 | 
				
			||||||
wsrep_abort_transaction(
 | 
					 | 
				
			||||||
	handlerton*,
 | 
					 | 
				
			||||||
	THD *bf_thd,
 | 
					 | 
				
			||||||
	THD *victim_thd,
 | 
					 | 
				
			||||||
                                    my_bool signal)
 | 
					                                    my_bool signal)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  DBUG_ENTER("wsrep_abort_transaction");
 | 
					  DBUG_ENTER("wsrep_abort_transaction");
 | 
				
			||||||
  ut_ad(bf_thd);
 | 
					  ut_ad(bf_thd);
 | 
				
			||||||
  ut_ad(victim_thd);
 | 
					  ut_ad(victim_thd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wsrep_thd_kill_LOCK(victim_thd);
 | 
					 | 
				
			||||||
	wsrep_thd_LOCK(victim_thd);
 | 
					 | 
				
			||||||
  trx_t *victim_trx= thd_to_trx(victim_thd);
 | 
					  trx_t *victim_trx= thd_to_trx(victim_thd);
 | 
				
			||||||
	wsrep_thd_UNLOCK(victim_thd);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %s",
 | 
					  WSREP_DEBUG("abort transaction: BF: %s victim: %s victim conf: %s",
 | 
				
			||||||
			wsrep_thd_query(bf_thd),
 | 
					              wsrep_thd_query(bf_thd), wsrep_thd_query(victim_thd),
 | 
				
			||||||
			wsrep_thd_query(victim_thd),
 | 
					 | 
				
			||||||
              wsrep_thd_transaction_state_str(victim_thd));
 | 
					              wsrep_thd_transaction_state_str(victim_thd));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (victim_trx) {
 | 
					  if (!victim_trx)
 | 
				
			||||||
		victim_trx->lock.set_wsrep_victim();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		wsrep_thd_LOCK(victim_thd);
 | 
					 | 
				
			||||||
		bool aborting= !wsrep_thd_set_wsrep_aborter(bf_thd, victim_thd);
 | 
					 | 
				
			||||||
		wsrep_thd_UNLOCK(victim_thd);
 | 
					 | 
				
			||||||
		if (aborting) {
 | 
					 | 
				
			||||||
			DEBUG_SYNC(bf_thd, "before_wsrep_thd_abort");
 | 
					 | 
				
			||||||
			DBUG_EXECUTE_IF("sync.before_wsrep_thd_abort",
 | 
					 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
					   const char act[]=
 | 
					    WSREP_DEBUG("abort transaction: victim did not exist");
 | 
				
			||||||
					     "now "
 | 
					    DBUG_VOID_RETURN;
 | 
				
			||||||
					     "SIGNAL sync.before_wsrep_thd_abort_reached "
 | 
					 | 
				
			||||||
					     "WAIT_FOR signal.before_wsrep_thd_abort";
 | 
					 | 
				
			||||||
					   DBUG_ASSERT(!debug_sync_set_action(bf_thd,
 | 
					 | 
				
			||||||
									      STRING_WITH_LEN(act)));
 | 
					 | 
				
			||||||
					 };);
 | 
					 | 
				
			||||||
			wsrep_thd_bf_abort(bf_thd, victim_thd, signal);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		DBUG_EXECUTE_IF("sync.before_wsrep_thd_abort",
 | 
					 | 
				
			||||||
				 {
 | 
					 | 
				
			||||||
				   const char act[]=
 | 
					 | 
				
			||||||
				     "now "
 | 
					 | 
				
			||||||
				     "SIGNAL sync.before_wsrep_thd_abort_reached "
 | 
					 | 
				
			||||||
				     "WAIT_FOR signal.before_wsrep_thd_abort";
 | 
					 | 
				
			||||||
				   DBUG_ASSERT(!debug_sync_set_action(bf_thd,
 | 
					 | 
				
			||||||
								      STRING_WITH_LEN(act)));
 | 
					 | 
				
			||||||
				 };);
 | 
					 | 
				
			||||||
		wsrep_thd_bf_abort(bf_thd, victim_thd, signal);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wsrep_thd_kill_UNLOCK(victim_thd);
 | 
					  lock_sys.wr_lock(SRW_LOCK_CALL);
 | 
				
			||||||
 | 
					  mysql_mutex_lock(&lock_sys.wait_mutex);
 | 
				
			||||||
 | 
					  victim_trx->mutex_lock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  switch (victim_trx->state) {
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    break;
 | 
				
			||||||
 | 
					  case TRX_STATE_ACTIVE:
 | 
				
			||||||
 | 
					  case TRX_STATE_PREPARED:
 | 
				
			||||||
 | 
					    /* Cancel lock wait if the victim is waiting for a lock in InnoDB.
 | 
				
			||||||
 | 
					       The transaction which is blocked somewhere else (e.g. waiting
 | 
				
			||||||
 | 
					       for next command or MDL) has been interrupted by THD::awake_no_mutex()
 | 
				
			||||||
 | 
					       on server level before calling this function. */
 | 
				
			||||||
 | 
					    lock_sys.cancel_lock_wait_for_wsrep_bf_abort(victim_trx);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  lock_sys.wr_unlock();
 | 
				
			||||||
 | 
					  mysql_mutex_unlock(&lock_sys.wait_mutex);
 | 
				
			||||||
 | 
					  victim_trx->mutex_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  DBUG_VOID_RETURN;
 | 
					  DBUG_VOID_RETURN;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2365,6 +2365,7 @@ tablespace_deleted:
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const ulint zip_size = s->zip_size(), size = s->size;
 | 
							const ulint zip_size = s->zip_size(), size = s->size;
 | 
				
			||||||
 | 
							s->x_lock();
 | 
				
			||||||
		s->release();
 | 
							s->release();
 | 
				
			||||||
		mtr_t mtr;
 | 
							mtr_t mtr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -2382,13 +2383,17 @@ tablespace_deleted:
 | 
				
			|||||||
				|| !page_is_leaf(block->page.frame);
 | 
									|| !page_is_leaf(block->page.frame);
 | 
				
			||||||
			mtr.commit();
 | 
								mtr.commit();
 | 
				
			||||||
			if (err == DB_TABLESPACE_DELETED) {
 | 
								if (err == DB_TABLESPACE_DELETED) {
 | 
				
			||||||
 | 
									s->x_unlock();
 | 
				
			||||||
				goto tablespace_deleted;
 | 
									goto tablespace_deleted;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if (!remove) {
 | 
								if (!remove) {
 | 
				
			||||||
 | 
									s->x_unlock();
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							s->x_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (srv_shutdown_state == SRV_SHUTDOWN_NONE
 | 
							if (srv_shutdown_state == SRV_SHUTDOWN_NONE
 | 
				
			||||||
		    || srv_fast_shutdown) {
 | 
							    || srv_fast_shutdown) {
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
@@ -2417,7 +2422,7 @@ tablespace_deleted:
 | 
				
			|||||||
		/* Prevent an infinite loop, by removing entries from
 | 
							/* Prevent an infinite loop, by removing entries from
 | 
				
			||||||
		the change buffer in the case the bitmap bits were
 | 
							the change buffer in the case the bitmap bits were
 | 
				
			||||||
		wrongly clear even though buffered changes exist. */
 | 
							wrongly clear even though buffered changes exist. */
 | 
				
			||||||
		ibuf_delete_recs(page_id_t(space_ids[i], page_nos[i]));
 | 
							ibuf_delete_recs(page_id_t(space_id, page_nos[i]));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -4195,25 +4200,26 @@ dberr_t ibuf_merge_or_delete_for_page(buf_block_t *block,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		ibuf_mtr_commit(&mtr);
 | 
							ibuf_mtr_commit(&mtr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (bitmap_bits
 | 
							if (!bitmap_bits) {
 | 
				
			||||||
		    && DB_SUCCESS
 | 
							done:
 | 
				
			||||||
 | 
								/* No changes are buffered for this page. */
 | 
				
			||||||
 | 
								space->release();
 | 
				
			||||||
 | 
								return DB_SUCCESS;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!block
 | 
				
			||||||
 | 
							    || DB_SUCCESS
 | 
				
			||||||
		    == fseg_page_is_allocated(space, page_id.page_no())) {
 | 
							    == fseg_page_is_allocated(space, page_id.page_no())) {
 | 
				
			||||||
			ibuf_mtr_start(&mtr);
 | 
								ibuf_mtr_start(&mtr);
 | 
				
			||||||
			mtr.set_named_space(space);
 | 
								mtr.set_named_space(space);
 | 
				
			||||||
			ibuf_reset_bitmap(block, page_id, zip_size, &mtr);
 | 
								ibuf_reset_bitmap(block, page_id, zip_size, &mtr);
 | 
				
			||||||
			ibuf_mtr_commit(&mtr);
 | 
								ibuf_mtr_commit(&mtr);
 | 
				
			||||||
			bitmap_bits = 0;
 | 
					 | 
				
			||||||
			if (!block
 | 
								if (!block
 | 
				
			||||||
			    || btr_page_get_index_id(block->page.frame)
 | 
								    || btr_page_get_index_id(block->page.frame)
 | 
				
			||||||
			    != DICT_IBUF_ID_MIN + IBUF_SPACE_ID) {
 | 
								    != DICT_IBUF_ID_MIN + IBUF_SPACE_ID) {
 | 
				
			||||||
				ibuf_delete_recs(page_id);
 | 
									ibuf_delete_recs(page_id);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
								goto done;
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!bitmap_bits) {
 | 
					 | 
				
			||||||
			/* No changes are buffered for this page. */
 | 
					 | 
				
			||||||
			space->release();
 | 
					 | 
				
			||||||
			return DB_SUCCESS;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,8 +75,7 @@ struct buf_pool_info_t
 | 
				
			|||||||
	ulint	flush_list_len;		/*!< Length of buf_pool.flush_list */
 | 
						ulint	flush_list_len;		/*!< Length of buf_pool.flush_list */
 | 
				
			||||||
	ulint	n_pend_unzip;		/*!< buf_pool.n_pend_unzip, pages
 | 
						ulint	n_pend_unzip;		/*!< buf_pool.n_pend_unzip, pages
 | 
				
			||||||
					pending decompress */
 | 
										pending decompress */
 | 
				
			||||||
	ulint	n_pend_reads;		/*!< buf_pool.n_pend_reads, pages
 | 
						ulint	n_pend_reads;		/*!< os_aio_pending_reads() */
 | 
				
			||||||
					pending read */
 | 
					 | 
				
			||||||
	ulint	n_pending_flush_lru;	/*!< Pages pending flush in LRU */
 | 
						ulint	n_pending_flush_lru;	/*!< Pages pending flush in LRU */
 | 
				
			||||||
	ulint	n_pending_flush_list;	/*!< Pages pending flush in FLUSH
 | 
						ulint	n_pending_flush_list;	/*!< Pages pending flush in FLUSH
 | 
				
			||||||
					LIST */
 | 
										LIST */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -102,10 +102,13 @@ which could result in a deadlock if the OS does not support asynchronous io.
 | 
				
			|||||||
ulint
 | 
					ulint
 | 
				
			||||||
buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf);
 | 
					buf_read_ahead_linear(const page_id_t page_id, ulint zip_size, bool ibuf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Issue read requests for pages that need to be recovered.
 | 
					/** Schedule a page for recovery.
 | 
				
			||||||
@param space_id	tablespace identifier
 | 
					@param space    tablespace
 | 
				
			||||||
@param page_nos	page numbers to read, in ascending order */
 | 
					@param page_id  page identifier
 | 
				
			||||||
void buf_read_recv_pages(uint32_t space_id, st_::span<uint32_t> page_nos);
 | 
					@param recs     log records
 | 
				
			||||||
 | 
					@param init     page initialization, or nullptr if the page needs to be read */
 | 
				
			||||||
 | 
					void buf_read_recover(fil_space_t *space, const page_id_t page_id,
 | 
				
			||||||
 | 
					                      page_recv_t &recs, recv_init *init);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @name Modes used in read-ahead @{ */
 | 
					/** @name Modes used in read-ahead @{ */
 | 
				
			||||||
/** read only pages belonging to the insert buffer tree */
 | 
					/** read only pages belonging to the insert buffer tree */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -638,8 +638,6 @@ public:
 | 
				
			|||||||
  /** Close all tablespace files at shutdown */
 | 
					  /** Close all tablespace files at shutdown */
 | 
				
			||||||
  static void close_all();
 | 
					  static void close_all();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** @return last_freed_lsn */
 | 
					 | 
				
			||||||
  lsn_t get_last_freed_lsn() { return last_freed_lsn; }
 | 
					 | 
				
			||||||
  /** Update last_freed_lsn */
 | 
					  /** Update last_freed_lsn */
 | 
				
			||||||
  void update_last_freed_lsn(lsn_t lsn) { last_freed_lsn= lsn; }
 | 
					  void update_last_freed_lsn(lsn_t lsn) { last_freed_lsn= lsn; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -955,6 +955,10 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  /** Cancel possible lock waiting for a transaction */
 | 
					  /** Cancel possible lock waiting for a transaction */
 | 
				
			||||||
  static void cancel_lock_wait_for_trx(trx_t *trx);
 | 
					  static void cancel_lock_wait_for_trx(trx_t *trx);
 | 
				
			||||||
 | 
					#ifdef WITH_WSREP
 | 
				
			||||||
 | 
					  /** Cancel lock waiting for a wsrep BF abort. */
 | 
				
			||||||
 | 
					  static void cancel_lock_wait_for_wsrep_bf_abort(trx_t *trx);
 | 
				
			||||||
 | 
					#endif /* WITH_WSREP */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** The lock system */
 | 
					/** The lock system */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,9 +38,9 @@ Created 9/20/1997 Heikki Tuuri
 | 
				
			|||||||
#define recv_recovery_is_on() UNIV_UNLIKELY(recv_sys.recovery_on)
 | 
					#define recv_recovery_is_on() UNIV_UNLIKELY(recv_sys.recovery_on)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ATTRIBUTE_COLD MY_ATTRIBUTE((nonnull, warn_unused_result))
 | 
					ATTRIBUTE_COLD MY_ATTRIBUTE((nonnull, warn_unused_result))
 | 
				
			||||||
/** Apply any buffered redo log to a page that was just read from a data file.
 | 
					/** Apply any buffered redo log to a page.
 | 
				
			||||||
@param[in,out]	space	tablespace
 | 
					@param space     tablespace
 | 
				
			||||||
@param[in,out]	bpage	buffer pool page
 | 
					@param bpage     buffer pool page
 | 
				
			||||||
@return whether the page was recovered correctly */
 | 
					@return whether the page was recovered correctly */
 | 
				
			||||||
bool recv_recover_page(fil_space_t* space, buf_page_t* bpage);
 | 
					bool recv_recover_page(fil_space_t* space, buf_page_t* bpage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -49,17 +49,6 @@ of first system tablespace page
 | 
				
			|||||||
@return error code or DB_SUCCESS */
 | 
					@return error code or DB_SUCCESS */
 | 
				
			||||||
dberr_t recv_recovery_from_checkpoint_start();
 | 
					dberr_t recv_recovery_from_checkpoint_start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Whether to store redo log records in recv_sys.pages */
 | 
					 | 
				
			||||||
enum store_t {
 | 
					 | 
				
			||||||
	/** Do not store redo log records. */
 | 
					 | 
				
			||||||
	STORE_NO,
 | 
					 | 
				
			||||||
	/** Store redo log records. */
 | 
					 | 
				
			||||||
	STORE_YES,
 | 
					 | 
				
			||||||
	/** Store redo log records if the tablespace exists. */
 | 
					 | 
				
			||||||
	STORE_IF_EXISTS
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Report an operation to create, delete, or rename a file during backup.
 | 
					/** Report an operation to create, delete, or rename a file during backup.
 | 
				
			||||||
@param[in]	space_id	tablespace identifier
 | 
					@param[in]	space_id	tablespace identifier
 | 
				
			||||||
@param[in]	type		file operation redo log type
 | 
					@param[in]	type		file operation redo log type
 | 
				
			||||||
@@ -125,21 +114,15 @@ struct recv_dblwr_t
 | 
				
			|||||||
  list pages;
 | 
					  list pages;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** the recovery state and buffered records for a page */
 | 
					/** recv_sys.pages entry; protected by recv_sys.mutex */
 | 
				
			||||||
struct page_recv_t
 | 
					struct page_recv_t
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  /** Recovery state; protected by recv_sys.mutex */
 | 
					  /** Recovery status: 0=not in progress, 1=log is being applied,
 | 
				
			||||||
  enum
 | 
					  -1=log has been applied and the entry may be erased.
 | 
				
			||||||
  {
 | 
					  Transitions from 1 to -1 are NOT protected by recv_sys.mutex. */
 | 
				
			||||||
    /** not yet processed */
 | 
					  Atomic_relaxed<int8_t> being_processed{0};
 | 
				
			||||||
    RECV_NOT_PROCESSED,
 | 
					  /** Whether reading the page will be skipped */
 | 
				
			||||||
    /** not processed; the page will be reinitialized */
 | 
					  bool skip_read= false;
 | 
				
			||||||
    RECV_WILL_NOT_READ,
 | 
					 | 
				
			||||||
    /** page is being read */
 | 
					 | 
				
			||||||
    RECV_BEING_READ,
 | 
					 | 
				
			||||||
    /** log records are being applied on the page */
 | 
					 | 
				
			||||||
    RECV_BEING_PROCESSED
 | 
					 | 
				
			||||||
  } state= RECV_NOT_PROCESSED;
 | 
					 | 
				
			||||||
  /** Latest written byte offset when applying the log records.
 | 
					  /** Latest written byte offset when applying the log records.
 | 
				
			||||||
  @see mtr_t::m_last_offset */
 | 
					  @see mtr_t::m_last_offset */
 | 
				
			||||||
  uint16_t last_offset= 1;
 | 
					  uint16_t last_offset= 1;
 | 
				
			||||||
@@ -162,6 +145,9 @@ struct page_recv_t
 | 
				
			|||||||
        head= recs;
 | 
					        head= recs;
 | 
				
			||||||
      tail= recs;
 | 
					      tail= recs;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    /** Remove the last records for the page
 | 
				
			||||||
 | 
					    @param start_lsn   start of the removed log */
 | 
				
			||||||
 | 
					    ATTRIBUTE_COLD void rewind(lsn_t start_lsn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** @return the last log snippet */
 | 
					    /** @return the last log snippet */
 | 
				
			||||||
    const log_rec_t* last() const { return tail; }
 | 
					    const log_rec_t* last() const { return tail; }
 | 
				
			||||||
@@ -180,8 +166,8 @@ struct page_recv_t
 | 
				
			|||||||
    iterator begin() { return head; }
 | 
					    iterator begin() { return head; }
 | 
				
			||||||
    iterator end() { return NULL; }
 | 
					    iterator end() { return NULL; }
 | 
				
			||||||
    bool empty() const { ut_ad(!head == !tail); return !head; }
 | 
					    bool empty() const { ut_ad(!head == !tail); return !head; }
 | 
				
			||||||
    /** Clear and free the records; @see recv_sys_t::alloc() */
 | 
					    /** Clear and free the records; @see recv_sys_t::add() */
 | 
				
			||||||
    inline void clear();
 | 
					    void clear();
 | 
				
			||||||
  } log;
 | 
					  } log;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Trim old log records for a page.
 | 
					  /** Trim old log records for a page.
 | 
				
			||||||
@@ -190,21 +176,27 @@ struct page_recv_t
 | 
				
			|||||||
  inline bool trim(lsn_t start_lsn);
 | 
					  inline bool trim(lsn_t start_lsn);
 | 
				
			||||||
  /** Ignore any earlier redo log records for this page. */
 | 
					  /** Ignore any earlier redo log records for this page. */
 | 
				
			||||||
  inline void will_not_read();
 | 
					  inline void will_not_read();
 | 
				
			||||||
  /** @return whether the log records for the page are being processed */
 | 
					};
 | 
				
			||||||
  bool is_being_processed() const { return state == RECV_BEING_PROCESSED; }
 | 
					
 | 
				
			||||||
 | 
					/** A page initialization operation that was parsed from the redo log */
 | 
				
			||||||
 | 
					struct recv_init
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  /** log sequence number of the page initialization */
 | 
				
			||||||
 | 
					  lsn_t lsn;
 | 
				
			||||||
 | 
					  /** Whether btr_page_create() avoided a read of the page.
 | 
				
			||||||
 | 
					  At the end of the last recovery batch, mark_ibuf_exist()
 | 
				
			||||||
 | 
					  will mark pages for which this flag is set. */
 | 
				
			||||||
 | 
					  bool created;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Recovery system data structure */
 | 
					/** Recovery system data structure */
 | 
				
			||||||
struct recv_sys_t
 | 
					struct recv_sys_t
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  /** mutex protecting apply_log_recs and page_recv_t::state */
 | 
					  using init= recv_init;
 | 
				
			||||||
  mysql_mutex_t mutex;
 | 
					
 | 
				
			||||||
 | 
					  /** mutex protecting this as well as some of page_recv_t */
 | 
				
			||||||
 | 
					  alignas(CPU_LEVEL1_DCACHE_LINESIZE) mysql_mutex_t mutex;
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  /** condition variable for
 | 
					 | 
				
			||||||
  !apply_batch_on || pages.empty() || found_corrupt_log || found_corrupt_fs */
 | 
					 | 
				
			||||||
  pthread_cond_t cond;
 | 
					 | 
				
			||||||
  /** whether recv_apply_hashed_log_recs() is running */
 | 
					 | 
				
			||||||
  bool apply_batch_on;
 | 
					 | 
				
			||||||
  /** set when finding a corrupt log block or record, or there is a
 | 
					  /** set when finding a corrupt log block or record, or there is a
 | 
				
			||||||
  log parsing buffer overflow */
 | 
					  log parsing buffer overflow */
 | 
				
			||||||
  bool found_corrupt_log;
 | 
					  bool found_corrupt_log;
 | 
				
			||||||
@@ -226,6 +218,8 @@ public:
 | 
				
			|||||||
  size_t offset;
 | 
					  size_t offset;
 | 
				
			||||||
  /** log sequence number of the first non-parsed record */
 | 
					  /** log sequence number of the first non-parsed record */
 | 
				
			||||||
  lsn_t lsn;
 | 
					  lsn_t lsn;
 | 
				
			||||||
 | 
					  /** log sequence number of the last parsed mini-transaction */
 | 
				
			||||||
 | 
					  lsn_t scanned_lsn;
 | 
				
			||||||
  /** log sequence number at the end of the FILE_CHECKPOINT record, or 0 */
 | 
					  /** log sequence number at the end of the FILE_CHECKPOINT record, or 0 */
 | 
				
			||||||
  lsn_t file_checkpoint;
 | 
					  lsn_t file_checkpoint;
 | 
				
			||||||
  /** the time when progress was last reported */
 | 
					  /** the time when progress was last reported */
 | 
				
			||||||
@@ -238,6 +232,9 @@ public:
 | 
				
			|||||||
  map pages;
 | 
					  map pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
					  /** iterator to pages, used by parse() */
 | 
				
			||||||
 | 
					  map::iterator pages_it;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Process a record that indicates that a tablespace size is being shrunk.
 | 
					  /** Process a record that indicates that a tablespace size is being shrunk.
 | 
				
			||||||
  @param page_id first page that is not in the file
 | 
					  @param page_id first page that is not in the file
 | 
				
			||||||
  @param lsn     log sequence number of the shrink operation */
 | 
					  @param lsn     log sequence number of the shrink operation */
 | 
				
			||||||
@@ -257,30 +254,42 @@ public:
 | 
				
			|||||||
  /** The contents of the doublewrite buffer */
 | 
					  /** The contents of the doublewrite buffer */
 | 
				
			||||||
  recv_dblwr_t dblwr;
 | 
					  recv_dblwr_t dblwr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Last added LSN to pages, before switching to STORE_NO */
 | 
					 | 
				
			||||||
  lsn_t last_stored_lsn= 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  inline void read(os_offset_t offset, span<byte> buf);
 | 
					  inline void read(os_offset_t offset, span<byte> buf);
 | 
				
			||||||
  inline size_t files_size();
 | 
					  inline size_t files_size();
 | 
				
			||||||
  void close_files() { files.clear(); files.shrink_to_fit(); }
 | 
					  void close_files() { files.clear(); files.shrink_to_fit(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Advance pages_it if it matches the iterator */
 | 
				
			||||||
 | 
					  void pages_it_invalidate(const map::iterator &p)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    mysql_mutex_assert_owner(&mutex);
 | 
				
			||||||
 | 
					    if (pages_it == p)
 | 
				
			||||||
 | 
					      pages_it++;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  /** Invalidate pages_it if it points to the given tablespace */
 | 
				
			||||||
 | 
					  void pages_it_invalidate(uint32_t space_id)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    mysql_mutex_assert_owner(&mutex);
 | 
				
			||||||
 | 
					    if (pages_it != pages.end() && pages_it->first.space() == space_id)
 | 
				
			||||||
 | 
					      pages_it= pages.end();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  /** Attempt to initialize a page based on redo log records.
 | 
					  /** Attempt to initialize a page based on redo log records.
 | 
				
			||||||
  @param page_id  page identifier
 | 
					  @param p        iterator
 | 
				
			||||||
  @param p        iterator pointing to page_id
 | 
					 | 
				
			||||||
  @param mtr      mini-transaction
 | 
					  @param mtr      mini-transaction
 | 
				
			||||||
  @param b        pre-allocated buffer pool block
 | 
					  @param b        pre-allocated buffer pool block
 | 
				
			||||||
 | 
					  @param init     page initialization
 | 
				
			||||||
  @return the recovered block
 | 
					  @return the recovered block
 | 
				
			||||||
  @retval nullptr if the page cannot be initialized based on log records
 | 
					  @retval nullptr if the page cannot be initialized based on log records
 | 
				
			||||||
  @retval -1      if the page cannot be recovered due to corruption */
 | 
					  @retval -1      if the page cannot be recovered due to corruption */
 | 
				
			||||||
  inline buf_block_t *recover_low(const page_id_t page_id, map::iterator &p,
 | 
					  inline buf_block_t *recover_low(const map::iterator &p, mtr_t &mtr,
 | 
				
			||||||
                                  mtr_t &mtr, buf_block_t *b);
 | 
					                                  buf_block_t *b, init &init);
 | 
				
			||||||
  /** Attempt to initialize a page based on redo log records.
 | 
					  /** Attempt to initialize a page based on redo log records.
 | 
				
			||||||
  @param page_id  page identifier
 | 
					  @param page_id  page identifier
 | 
				
			||||||
  @return the recovered block
 | 
					  @return the recovered block
 | 
				
			||||||
  @retval nullptr if the page cannot be initialized based on log records
 | 
					  @retval nullptr if the page cannot be initialized based on log records
 | 
				
			||||||
  @retval -1      if the page cannot be recovered due to corruption */
 | 
					  @retval -1      if the page cannot be recovered due to corruption */
 | 
				
			||||||
  buf_block_t *recover_low(const page_id_t page_id);
 | 
					  ATTRIBUTE_COLD buf_block_t *recover_low(const page_id_t page_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** All found log files (multiple ones are possible if we are upgrading
 | 
					  /** All found log files (multiple ones are possible if we are upgrading
 | 
				
			||||||
  from before MariaDB Server 10.5.1) */
 | 
					  from before MariaDB Server 10.5.1) */
 | 
				
			||||||
@@ -289,10 +298,27 @@ private:
 | 
				
			|||||||
  /** Base node of the redo block list.
 | 
					  /** Base node of the redo block list.
 | 
				
			||||||
  List elements are linked via buf_block_t::unzip_LRU. */
 | 
					  List elements are linked via buf_block_t::unzip_LRU. */
 | 
				
			||||||
  UT_LIST_BASE_NODE_T(buf_block_t) blocks;
 | 
					  UT_LIST_BASE_NODE_T(buf_block_t) blocks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Allocate a block from the buffer pool for recv_sys.pages */
 | 
				
			||||||
 | 
					  ATTRIBUTE_COLD buf_block_t *add_block();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Wait for buffer pool to become available.
 | 
				
			||||||
 | 
					  @param pages number of buffer pool pages needed */
 | 
				
			||||||
 | 
					  ATTRIBUTE_COLD void wait_for_pool(size_t pages);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Free log for processed pages. */
 | 
				
			||||||
 | 
					  void garbage_collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Apply a recovery batch.
 | 
				
			||||||
 | 
					  @param space_id       current tablespace identifier
 | 
				
			||||||
 | 
					  @param space          current tablespace
 | 
				
			||||||
 | 
					  @param free_block     spare buffer block
 | 
				
			||||||
 | 
					  @param last_batch     whether it is possible to write more redo log
 | 
				
			||||||
 | 
					  @return whether the caller must provide a new free_block */
 | 
				
			||||||
 | 
					  bool apply_batch(uint32_t space_id, fil_space_t *&space,
 | 
				
			||||||
 | 
					                   buf_block_t *&free_block, bool last_batch);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  /** Check whether the number of read redo log blocks exceeds the maximum.
 | 
					 | 
				
			||||||
  @return whether the memory is exhausted */
 | 
					 | 
				
			||||||
  inline bool is_memory_exhausted();
 | 
					 | 
				
			||||||
  /** Apply buffered log to persistent data pages.
 | 
					  /** Apply buffered log to persistent data pages.
 | 
				
			||||||
  @param last_batch     whether it is possible to write more redo log */
 | 
					  @param last_batch     whether it is possible to write more redo log */
 | 
				
			||||||
  void apply(bool last_batch);
 | 
					  void apply(bool last_batch);
 | 
				
			||||||
@@ -310,7 +336,7 @@ public:
 | 
				
			|||||||
  /** Clean up after create() */
 | 
					  /** Clean up after create() */
 | 
				
			||||||
  void close();
 | 
					  void close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool is_initialised() const { return last_stored_lsn != 0; }
 | 
					  bool is_initialised() const { return scanned_lsn != 0; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Find the latest checkpoint.
 | 
					  /** Find the latest checkpoint.
 | 
				
			||||||
  @return error code or DB_SUCCESS */
 | 
					  @return error code or DB_SUCCESS */
 | 
				
			||||||
@@ -321,60 +347,76 @@ public:
 | 
				
			|||||||
  @param start_lsn start LSN of the mini-transaction
 | 
					  @param start_lsn start LSN of the mini-transaction
 | 
				
			||||||
  @param lsn      @see mtr_t::commit_lsn()
 | 
					  @param lsn      @see mtr_t::commit_lsn()
 | 
				
			||||||
  @param l        redo log snippet
 | 
					  @param l        redo log snippet
 | 
				
			||||||
  @param len      length of l, in bytes */
 | 
					  @param len      length of l, in bytes
 | 
				
			||||||
  inline void add(map::iterator it, lsn_t start_lsn, lsn_t lsn,
 | 
					  @return whether we ran out of memory */
 | 
				
			||||||
 | 
					  bool add(map::iterator it, lsn_t start_lsn, lsn_t lsn,
 | 
				
			||||||
           const byte *l, size_t len);
 | 
					           const byte *l, size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  enum parse_mtr_result { OK, PREMATURE_EOF, GOT_EOF };
 | 
					  /** Parsing result */
 | 
				
			||||||
 | 
					  enum parse_mtr_result {
 | 
				
			||||||
 | 
					    /** a record was successfully parsed */
 | 
				
			||||||
 | 
					    OK,
 | 
				
			||||||
 | 
					    /** the log ended prematurely (need to read more) */
 | 
				
			||||||
 | 
					    PREMATURE_EOF,
 | 
				
			||||||
 | 
					    /** the end of the log was reached */
 | 
				
			||||||
 | 
					    GOT_EOF,
 | 
				
			||||||
 | 
					    /** parse<true>(l, false) ran out of memory */
 | 
				
			||||||
 | 
					    GOT_OOM
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
  /** Parse and register one log_t::FORMAT_10_8 mini-transaction.
 | 
					  /** Parse and register one log_t::FORMAT_10_8 mini-transaction.
 | 
				
			||||||
  @param store   whether to store the records
 | 
					  @tparam store     whether to store the records
 | 
				
			||||||
  @param l       log data source */
 | 
					  @param  l         log data source
 | 
				
			||||||
 | 
					  @param  if_exists if store: whether to check if the tablespace exists */
 | 
				
			||||||
 | 
					  template<typename source,bool store>
 | 
				
			||||||
 | 
					  inline parse_mtr_result parse(source &l, bool if_exists) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Rewind a mini-transaction when parse() runs out of memory.
 | 
				
			||||||
 | 
					  @param  l         log data source
 | 
				
			||||||
 | 
					  @param  begin     start of the mini-transaction */
 | 
				
			||||||
  template<typename source>
 | 
					  template<typename source>
 | 
				
			||||||
  inline parse_mtr_result parse(store_t store, source& l) noexcept;
 | 
					  ATTRIBUTE_COLD void rewind(source &l, source &begin) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Report progress in terms of LSN or pages remaining */
 | 
				
			||||||
 | 
					  ATTRIBUTE_COLD void report_progress() const;
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  /** Parse and register one log_t::FORMAT_10_8 mini-transaction,
 | 
					  /** Parse and register one log_t::FORMAT_10_8 mini-transaction,
 | 
				
			||||||
  handling log_sys.is_pmem() buffer wrap-around.
 | 
					  handling log_sys.is_pmem() buffer wrap-around.
 | 
				
			||||||
  @param store           whether to store the records */
 | 
					  @tparam store     whether to store the records
 | 
				
			||||||
  static parse_mtr_result parse_mtr(store_t store) noexcept;
 | 
					  @param  if_exists if store: whether to check if the tablespace exists */
 | 
				
			||||||
 | 
					  template<bool store>
 | 
				
			||||||
 | 
					  static parse_mtr_result parse_mtr(bool if_exists) noexcept;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Parse and register one log_t::FORMAT_10_8 mini-transaction,
 | 
					  /** Parse and register one log_t::FORMAT_10_8 mini-transaction,
 | 
				
			||||||
  handling log_sys.is_pmem() buffer wrap-around.
 | 
					  handling log_sys.is_pmem() buffer wrap-around.
 | 
				
			||||||
  @param store   whether to store the records */
 | 
					  @tparam store     whether to store the records
 | 
				
			||||||
  static parse_mtr_result parse_pmem(store_t store) noexcept
 | 
					  @param  if_exists if store: whether to check if the tablespace exists */
 | 
				
			||||||
 | 
					  template<bool store>
 | 
				
			||||||
 | 
					  static parse_mtr_result parse_pmem(bool if_exists) noexcept
 | 
				
			||||||
#ifdef HAVE_PMEM
 | 
					#ifdef HAVE_PMEM
 | 
				
			||||||
    ;
 | 
					    ;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
  { return parse_mtr(store); }
 | 
					  { return parse_mtr<store>(if_exists); }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Erase log records for a page. */
 | 
				
			||||||
 | 
					  void erase(map::iterator p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Clear a fully processed set of stored redo log records. */
 | 
					  /** Clear a fully processed set of stored redo log records. */
 | 
				
			||||||
  inline void clear();
 | 
					  void clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Determine whether redo log recovery progress should be reported.
 | 
					  /** Determine whether redo log recovery progress should be reported.
 | 
				
			||||||
  @param time  the current time
 | 
					  @param time  the current time
 | 
				
			||||||
  @return whether progress should be reported
 | 
					  @return whether progress should be reported
 | 
				
			||||||
  (the last report was at least 15 seconds ago) */
 | 
					  (the last report was at least 15 seconds ago) */
 | 
				
			||||||
  bool report(time_t time)
 | 
					  bool report(time_t time);
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    if (time - progress_time < 15)
 | 
					 | 
				
			||||||
      return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    progress_time= time;
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** The alloc() memory alignment, in bytes */
 | 
					  /** The alloc() memory alignment, in bytes */
 | 
				
			||||||
  static constexpr size_t ALIGNMENT= sizeof(size_t);
 | 
					  static constexpr size_t ALIGNMENT= sizeof(size_t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Allocate memory for log_rec_t
 | 
					 | 
				
			||||||
  @param len  allocation size, in bytes
 | 
					 | 
				
			||||||
  @return pointer to len bytes of memory (never NULL) */
 | 
					 | 
				
			||||||
  inline void *alloc(size_t len);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /** Free a redo log snippet.
 | 
					  /** Free a redo log snippet.
 | 
				
			||||||
  @param data buffer returned by alloc() */
 | 
					  @param data buffer allocated in add() */
 | 
				
			||||||
  inline void free(const void *data);
 | 
					  inline void free(const void *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Remove records for a corrupted page.
 | 
					  /** Remove records for a corrupted page.
 | 
				
			||||||
@@ -386,8 +428,6 @@ public:
 | 
				
			|||||||
  ATTRIBUTE_COLD void set_corrupt_fs();
 | 
					  ATTRIBUTE_COLD void set_corrupt_fs();
 | 
				
			||||||
  /** Flag log file corruption during recovery. */
 | 
					  /** Flag log file corruption during recovery. */
 | 
				
			||||||
  ATTRIBUTE_COLD void set_corrupt_log();
 | 
					  ATTRIBUTE_COLD void set_corrupt_log();
 | 
				
			||||||
  /** Possibly finish a recovery batch. */
 | 
					 | 
				
			||||||
  inline void maybe_finish_batch();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** @return whether data file corruption was found */
 | 
					  /** @return whether data file corruption was found */
 | 
				
			||||||
  bool is_corrupt_fs() const { return UNIV_UNLIKELY(found_corrupt_fs); }
 | 
					  bool is_corrupt_fs() const { return UNIV_UNLIKELY(found_corrupt_fs); }
 | 
				
			||||||
@@ -405,12 +445,13 @@ public:
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** Try to recover a tablespace that was not readable earlier
 | 
					  /** Try to recover a tablespace that was not readable earlier
 | 
				
			||||||
  @param p          iterator, initially pointing to page_id_t{space_id,0};
 | 
					  @param p          iterator
 | 
				
			||||||
                    the records will be freed and the iterator advanced
 | 
					 | 
				
			||||||
  @param name       tablespace file name
 | 
					  @param name       tablespace file name
 | 
				
			||||||
  @param free_block spare buffer block
 | 
					  @param free_block spare buffer block
 | 
				
			||||||
  @return whether recovery failed */
 | 
					  @return recovered tablespace
 | 
				
			||||||
  bool recover_deferred(map::iterator &p, const std::string &name,
 | 
					  @retval nullptr if recovery failed */
 | 
				
			||||||
 | 
					  fil_space_t *recover_deferred(const map::iterator &p,
 | 
				
			||||||
 | 
					                                const std::string &name,
 | 
				
			||||||
                                buf_block_t *&free_block);
 | 
					                                buf_block_t *&free_block);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -212,6 +212,10 @@ public:
 | 
				
			|||||||
  bool is_LRU() const { return (type & (WRITE_LRU ^ WRITE_ASYNC)) != 0; }
 | 
					  bool is_LRU() const { return (type & (WRITE_LRU ^ WRITE_ASYNC)) != 0; }
 | 
				
			||||||
  bool is_async() const { return (type & (READ_SYNC ^ READ_ASYNC)) != 0; }
 | 
					  bool is_async() const { return (type & (READ_SYNC ^ READ_ASYNC)) != 0; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void write_complete() const;
 | 
				
			||||||
 | 
					  void read_complete() const;
 | 
				
			||||||
 | 
					  void fake_read_complete(os_offset_t offset) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** If requested, free storage space associated with a section of the file.
 | 
					  /** If requested, free storage space associated with a section of the file.
 | 
				
			||||||
  @param off   byte offset from the start (SEEK_SET)
 | 
					  @param off   byte offset from the start (SEEK_SET)
 | 
				
			||||||
  @param len   size of the hole in bytes
 | 
					  @param len   size of the hole in bytes
 | 
				
			||||||
@@ -1040,6 +1044,11 @@ int os_aio_init();
 | 
				
			|||||||
Frees the asynchronous io system. */
 | 
					Frees the asynchronous io system. */
 | 
				
			||||||
void os_aio_free();
 | 
					void os_aio_free();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Submit a fake read request during crash recovery.
 | 
				
			||||||
 | 
					@param type   fake read request
 | 
				
			||||||
 | 
					@param offset additional context */
 | 
				
			||||||
 | 
					void os_fake_read(const IORequest &type, os_offset_t offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Request a read or write.
 | 
					/** Request a read or write.
 | 
				
			||||||
@param type		I/O request
 | 
					@param type		I/O request
 | 
				
			||||||
@param buf		buffer
 | 
					@param buf		buffer
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -617,6 +617,8 @@ struct export_var_t{
 | 
				
			|||||||
#ifdef UNIV_DEBUG
 | 
					#ifdef UNIV_DEBUG
 | 
				
			||||||
	ulint innodb_buffer_pool_pages_latched;	/*!< Latched pages */
 | 
						ulint innodb_buffer_pool_pages_latched;	/*!< Latched pages */
 | 
				
			||||||
#endif /* UNIV_DEBUG */
 | 
					#endif /* UNIV_DEBUG */
 | 
				
			||||||
 | 
						/** buf_pool.stat.n_page_gets (a sharded counter) */
 | 
				
			||||||
 | 
						ulint innodb_buffer_pool_read_requests;
 | 
				
			||||||
	ulint innodb_checkpoint_age;
 | 
						ulint innodb_checkpoint_age;
 | 
				
			||||||
	ulint innodb_checkpoint_max_age;
 | 
						ulint innodb_checkpoint_max_age;
 | 
				
			||||||
	ulint innodb_data_pending_reads;	/*!< Pending reads */
 | 
						ulint innodb_data_pending_reads;	/*!< Pending reads */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1055,7 +1055,7 @@ public:
 | 
				
			|||||||
  void close();
 | 
					  void close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /** @return total number of active (non-prepared) transactions */
 | 
					  /** @return total number of active (non-prepared) transactions */
 | 
				
			||||||
  ulint any_active_transactions();
 | 
					  size_t any_active_transactions(size_t *prepared= nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -216,14 +216,6 @@ buf_block_t*
 | 
				
			|||||||
trx_undo_assign_low(trx_t *trx, trx_rseg_t *rseg, trx_undo_t **undo,
 | 
					trx_undo_assign_low(trx_t *trx, trx_rseg_t *rseg, trx_undo_t **undo,
 | 
				
			||||||
                    mtr_t *mtr, dberr_t *err)
 | 
					                    mtr_t *mtr, dberr_t *err)
 | 
				
			||||||
	MY_ATTRIBUTE((nonnull, warn_unused_result));
 | 
						MY_ATTRIBUTE((nonnull, warn_unused_result));
 | 
				
			||||||
/******************************************************************//**
 | 
					 | 
				
			||||||
Sets the state of the undo log segment at a transaction finish.
 | 
					 | 
				
			||||||
@return undo log segment header page, x-latched */
 | 
					 | 
				
			||||||
buf_block_t*
 | 
					 | 
				
			||||||
trx_undo_set_state_at_finish(
 | 
					 | 
				
			||||||
/*=========================*/
 | 
					 | 
				
			||||||
	trx_undo_t*	undo,	/*!< in: undo log memory copy */
 | 
					 | 
				
			||||||
	mtr_t*		mtr);	/*!< in: mtr */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Set the state of the undo log segment at a XA PREPARE or XA ROLLBACK.
 | 
					/** Set the state of the undo log segment at a XA PREPARE or XA ROLLBACK.
 | 
				
			||||||
@param[in,out]	trx		transaction
 | 
					@param[in,out]	trx		transaction
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5732,12 +5732,13 @@ static void lock_release_autoinc_locks(trx_t *trx)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Cancel a waiting lock request and release possibly waiting transactions */
 | 
					/** Cancel a waiting lock request and release possibly waiting transactions */
 | 
				
			||||||
template <bool from_deadlock= false>
 | 
					template <bool from_deadlock= false, bool inner_trx_lock= true>
 | 
				
			||||||
void lock_cancel_waiting_and_release(lock_t *lock)
 | 
					void lock_cancel_waiting_and_release(lock_t *lock)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  lock_sys.assert_locked(*lock);
 | 
					  lock_sys.assert_locked(*lock);
 | 
				
			||||||
  mysql_mutex_assert_owner(&lock_sys.wait_mutex);
 | 
					  mysql_mutex_assert_owner(&lock_sys.wait_mutex);
 | 
				
			||||||
  trx_t *trx= lock->trx;
 | 
					  trx_t *trx= lock->trx;
 | 
				
			||||||
 | 
					  if (inner_trx_lock)
 | 
				
			||||||
    trx->mutex_lock();
 | 
					    trx->mutex_lock();
 | 
				
			||||||
  ut_d(const auto trx_state= trx->state);
 | 
					  ut_d(const auto trx_state= trx->state);
 | 
				
			||||||
  ut_ad(trx_state == TRX_STATE_COMMITTED_IN_MEMORY ||
 | 
					  ut_ad(trx_state == TRX_STATE_COMMITTED_IN_MEMORY ||
 | 
				
			||||||
@@ -5762,6 +5763,7 @@ void lock_cancel_waiting_and_release(lock_t *lock)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  lock_wait_end<from_deadlock>(trx);
 | 
					  lock_wait_end<from_deadlock>(trx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (inner_trx_lock)
 | 
				
			||||||
    trx->mutex_unlock();
 | 
					    trx->mutex_unlock();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -5779,6 +5781,19 @@ void lock_sys_t::cancel_lock_wait_for_trx(trx_t *trx)
 | 
				
			|||||||
  mysql_mutex_unlock(&lock_sys.wait_mutex);
 | 
					  mysql_mutex_unlock(&lock_sys.wait_mutex);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef WITH_WSREP
 | 
				
			||||||
 | 
					void lock_sys_t::cancel_lock_wait_for_wsrep_bf_abort(trx_t *trx)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  lock_sys.assert_locked();
 | 
				
			||||||
 | 
					  mysql_mutex_assert_owner(&lock_sys.wait_mutex);
 | 
				
			||||||
 | 
					  ut_ad(trx->mutex_is_owner());
 | 
				
			||||||
 | 
					  ut_ad(trx->state == TRX_STATE_ACTIVE || trx->state == TRX_STATE_PREPARED);
 | 
				
			||||||
 | 
					  trx->lock.set_wsrep_victim();
 | 
				
			||||||
 | 
					  if (lock_t *lock= trx->lock.wait_lock)
 | 
				
			||||||
 | 
					    lock_cancel_waiting_and_release<false, false>(lock);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* WITH_WSREP */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Cancel a waiting lock request.
 | 
					/** Cancel a waiting lock request.
 | 
				
			||||||
@tparam check_victim  whether to check for DB_DEADLOCK
 | 
					@tparam check_victim  whether to check for DB_DEADLOCK
 | 
				
			||||||
@param trx            active transaction
 | 
					@param trx            active transaction
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -3427,15 +3427,12 @@ os_file_get_status(
 | 
				
			|||||||
	return(ret);
 | 
						return(ret);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void io_callback_errorcheck(const tpool::aiocb *cb)
 | 
				
			||||||
extern void fil_aio_callback(const IORequest &request);
 | 
					{
 | 
				
			||||||
 | 
					  if (cb->m_err != DB_SUCCESS)
 | 
				
			||||||
static void io_callback(tpool::aiocb *cb)
 | 
					 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    const IORequest &request= *static_cast<const IORequest*>
 | 
					    const IORequest &request= *static_cast<const IORequest*>
 | 
				
			||||||
      (static_cast<const void*>(cb->m_userdata));
 | 
					      (static_cast<const void*>(cb->m_userdata));
 | 
				
			||||||
  if (cb->m_err != DB_SUCCESS)
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    ib::fatal() << "IO Error: " << cb->m_err << " during " <<
 | 
					    ib::fatal() << "IO Error: " << cb->m_err << " during " <<
 | 
				
			||||||
      (request.is_async() ? "async " : "sync ") <<
 | 
					      (request.is_async() ? "async " : "sync ") <<
 | 
				
			||||||
      (request.is_LRU() ? "lru " : "") <<
 | 
					      (request.is_LRU() ? "lru " : "") <<
 | 
				
			||||||
@@ -3443,19 +3440,36 @@ static void io_callback(tpool::aiocb *cb)
 | 
				
			|||||||
      " of " << cb->m_len << " bytes, for file " << cb->m_fh << ", returned " <<
 | 
					      " of " << cb->m_len << " bytes, for file " << cb->m_fh << ", returned " <<
 | 
				
			||||||
      cb->m_ret_len;
 | 
					      cb->m_ret_len;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  /* Return cb back to cache*/
 | 
					}
 | 
				
			||||||
  if (cb->m_opcode == tpool::aio_opcode::AIO_PREAD)
 | 
					
 | 
				
			||||||
 | 
					static void fake_io_callback(void *c)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  tpool::aiocb *cb= static_cast<tpool::aiocb*>(c);
 | 
				
			||||||
  ut_ad(read_slots->contains(cb));
 | 
					  ut_ad(read_slots->contains(cb));
 | 
				
			||||||
    fil_aio_callback(request);
 | 
					  static_cast<const IORequest*>(static_cast<const void*>(cb->m_userdata))->
 | 
				
			||||||
 | 
					    fake_read_complete(cb->m_offset);
 | 
				
			||||||
  read_slots->release(cb);
 | 
					  read_slots->release(cb);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
  else
 | 
					
 | 
				
			||||||
 | 
					static void read_io_callback(void *c)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    ut_ad(write_slots->contains(cb));
 | 
					  tpool::aiocb *cb= static_cast<tpool::aiocb*>(c);
 | 
				
			||||||
    fil_aio_callback(request);
 | 
					  ut_ad(cb->m_opcode == tpool::aio_opcode::AIO_PREAD);
 | 
				
			||||||
    write_slots->release(cb);
 | 
					  io_callback_errorcheck(cb);
 | 
				
			||||||
 | 
					  ut_ad(read_slots->contains(cb));
 | 
				
			||||||
 | 
					  static_cast<const IORequest*>
 | 
				
			||||||
 | 
					    (static_cast<const void*>(cb->m_userdata))->read_complete();
 | 
				
			||||||
 | 
					  read_slots->release(cb);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void write_io_callback(void *c)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  tpool::aiocb *cb= static_cast<tpool::aiocb*>(c);
 | 
				
			||||||
 | 
					  ut_ad(cb->m_opcode == tpool::aio_opcode::AIO_PWRITE);
 | 
				
			||||||
 | 
					  ut_ad(write_slots->contains(cb));
 | 
				
			||||||
 | 
					  static_cast<const IORequest*>
 | 
				
			||||||
 | 
					    (static_cast<const void*>(cb->m_userdata))->write_complete();
 | 
				
			||||||
 | 
					  write_slots->release(cb);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef LINUX_NATIVE_AIO
 | 
					#ifdef LINUX_NATIVE_AIO
 | 
				
			||||||
@@ -3758,6 +3772,28 @@ void os_aio_wait_until_no_pending_reads(bool declare)
 | 
				
			|||||||
    tpool::tpool_wait_end();
 | 
					    tpool::tpool_wait_end();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Submit a fake read request during crash recovery.
 | 
				
			||||||
 | 
					@param type  fake read request
 | 
				
			||||||
 | 
					@param offset additional context */
 | 
				
			||||||
 | 
					void os_fake_read(const IORequest &type, os_offset_t offset)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  tpool::aiocb *cb= read_slots->acquire();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  cb->m_group= read_slots->get_task_group();
 | 
				
			||||||
 | 
					  cb->m_fh= type.node->handle.m_file;
 | 
				
			||||||
 | 
					  cb->m_buffer= nullptr;
 | 
				
			||||||
 | 
					  cb->m_len= 0;
 | 
				
			||||||
 | 
					  cb->m_offset= offset;
 | 
				
			||||||
 | 
					  cb->m_opcode= tpool::aio_opcode::AIO_PREAD;
 | 
				
			||||||
 | 
					  new (cb->m_userdata) IORequest{type};
 | 
				
			||||||
 | 
					  cb->m_internal_task.m_func= fake_io_callback;
 | 
				
			||||||
 | 
					  cb->m_internal_task.m_arg= cb;
 | 
				
			||||||
 | 
					  cb->m_internal_task.m_group= cb->m_group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  srv_thread_pool->submit_task(&cb->m_internal_task);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Request a read or write.
 | 
					/** Request a read or write.
 | 
				
			||||||
@param type		I/O request
 | 
					@param type		I/O request
 | 
				
			||||||
@param buf		buffer
 | 
					@param buf		buffer
 | 
				
			||||||
@@ -3803,23 +3839,32 @@ func_exit:
 | 
				
			|||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						io_slots* slots;
 | 
				
			||||||
 | 
						tpool::callback_func callback;
 | 
				
			||||||
 | 
						tpool::aio_opcode opcode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (type.is_read()) {
 | 
						if (type.is_read()) {
 | 
				
			||||||
		++os_n_file_reads;
 | 
							++os_n_file_reads;
 | 
				
			||||||
 | 
							slots = read_slots;
 | 
				
			||||||
 | 
							callback = read_io_callback;
 | 
				
			||||||
 | 
							opcode = tpool::aio_opcode::AIO_PREAD;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		++os_n_file_writes;
 | 
							++os_n_file_writes;
 | 
				
			||||||
 | 
							slots = write_slots;
 | 
				
			||||||
 | 
							callback = write_io_callback;
 | 
				
			||||||
 | 
							opcode = tpool::aio_opcode::AIO_PWRITE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	compile_time_assert(sizeof(IORequest) <= tpool::MAX_AIO_USERDATA_LEN);
 | 
						compile_time_assert(sizeof(IORequest) <= tpool::MAX_AIO_USERDATA_LEN);
 | 
				
			||||||
	io_slots* slots= type.is_read() ? read_slots : write_slots;
 | 
					 | 
				
			||||||
	tpool::aiocb* cb = slots->acquire();
 | 
						tpool::aiocb* cb = slots->acquire();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cb->m_buffer = buf;
 | 
						cb->m_buffer = buf;
 | 
				
			||||||
	cb->m_callback = (tpool::callback_func)io_callback;
 | 
						cb->m_callback = callback;
 | 
				
			||||||
	cb->m_group = slots->get_task_group();
 | 
						cb->m_group = slots->get_task_group();
 | 
				
			||||||
	cb->m_fh = type.node->handle.m_file;
 | 
						cb->m_fh = type.node->handle.m_file;
 | 
				
			||||||
	cb->m_len = (int)n;
 | 
						cb->m_len = (int)n;
 | 
				
			||||||
	cb->m_offset = offset;
 | 
						cb->m_offset = offset;
 | 
				
			||||||
	cb->m_opcode = type.is_read() ? tpool::aio_opcode::AIO_PREAD : tpool::aio_opcode::AIO_PWRITE;
 | 
						cb->m_opcode = opcode;
 | 
				
			||||||
	new (cb->m_userdata) IORequest{type};
 | 
						new (cb->m_userdata) IORequest{type};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (srv_thread_pool->submit_io(cb)) {
 | 
						if (srv_thread_pool->submit_io(cb)) {
 | 
				
			||||||
@@ -3827,6 +3872,7 @@ func_exit:
 | 
				
			|||||||
		os_file_handle_error(type.node->name, type.is_read()
 | 
							os_file_handle_error(type.node->name, type.is_read()
 | 
				
			||||||
				     ? "aio read" : "aio write");
 | 
									     ? "aio read" : "aio write");
 | 
				
			||||||
		err = DB_IO_ERROR;
 | 
							err = DB_IO_ERROR;
 | 
				
			||||||
 | 
							type.node->space->release();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	goto func_exit;
 | 
						goto func_exit;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -214,14 +214,14 @@ row_ins_sec_index_entry_by_modify(
 | 
				
			|||||||
		made to the clustered index, and completed the
 | 
							made to the clustered index, and completed the
 | 
				
			||||||
		secondary index creation before we got here. In this
 | 
							secondary index creation before we got here. In this
 | 
				
			||||||
		case, the change would already be there. The CREATE
 | 
							case, the change would already be there. The CREATE
 | 
				
			||||||
		INDEX should be waiting for a MySQL meta-data lock
 | 
							INDEX should be in wait_while_table_is_used() at least
 | 
				
			||||||
		upgrade at least until this INSERT or UPDATE
 | 
							until this INSERT or UPDATE returns. After that point,
 | 
				
			||||||
		returns. After that point, set_committed(true)
 | 
							set_committed(true) would be invoked in
 | 
				
			||||||
		would be invoked in commit_inplace_alter_table(). */
 | 
							commit_inplace_alter_table(). */
 | 
				
			||||||
		ut_a(update->n_fields == 0);
 | 
							ut_a(update->n_fields == 0);
 | 
				
			||||||
		ut_a(!cursor->index()->is_committed());
 | 
					 | 
				
			||||||
		ut_ad(!dict_index_is_online_ddl(cursor->index()));
 | 
							ut_ad(!dict_index_is_online_ddl(cursor->index()));
 | 
				
			||||||
		return(DB_SUCCESS);
 | 
							return cursor->index()->is_committed()
 | 
				
			||||||
 | 
								? DB_CORRUPTION : DB_SUCCESS;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mode == BTR_MODIFY_LEAF) {
 | 
						if (mode == BTR_MODIFY_LEAF) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -615,6 +615,8 @@ row_purge_del_mark(
 | 
				
			|||||||
      const auto type= node->index->type;
 | 
					      const auto type= node->index->type;
 | 
				
			||||||
      if (type & (DICT_FTS | DICT_CORRUPT))
 | 
					      if (type & (DICT_FTS | DICT_CORRUPT))
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
 | 
					      if (node->index->online_status > ONLINE_INDEX_CREATION)
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
      if (UNIV_UNLIKELY(DICT_VIRTUAL & type) && !node->index->is_committed() &&
 | 
					      if (UNIV_UNLIKELY(DICT_VIRTUAL & type) && !node->index->is_committed() &&
 | 
				
			||||||
          node->index->has_new_v_col())
 | 
					          node->index->has_new_v_col())
 | 
				
			||||||
        continue;
 | 
					        continue;
 | 
				
			||||||
@@ -767,6 +769,11 @@ row_purge_upd_exist_or_extern_func(
 | 
				
			|||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (node->index->online_status
 | 
				
			||||||
 | 
							    > ONLINE_INDEX_CREATION) {
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (row_upd_changes_ord_field_binary(node->index, node->update,
 | 
							if (row_upd_changes_ord_field_binary(node->index, node->update,
 | 
				
			||||||
						     thr, NULL, NULL)) {
 | 
											     thr, NULL, NULL)) {
 | 
				
			||||||
			/* Build the older version of the index entry */
 | 
								/* Build the older version of the index entry */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -674,7 +674,7 @@ static monitor_info_t	innodb_counter_info[] =
 | 
				
			|||||||
	{"trx_rseg_history_len", "transaction",
 | 
						{"trx_rseg_history_len", "transaction",
 | 
				
			||||||
	 "Length of the TRX_RSEG_HISTORY list",
 | 
						 "Length of the TRX_RSEG_HISTORY list",
 | 
				
			||||||
	 static_cast<monitor_type_t>(
 | 
						 static_cast<monitor_type_t>(
 | 
				
			||||||
	 MONITOR_EXISTING | MONITOR_DISPLAY_CURRENT),
 | 
						 MONITOR_EXISTING | MONITOR_DISPLAY_CURRENT | MONITOR_DEFAULT_ON),
 | 
				
			||||||
	 MONITOR_DEFAULT_START, MONITOR_RSEG_HISTORY_LEN},
 | 
						 MONITOR_DEFAULT_START, MONITOR_RSEG_HISTORY_LEN},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	{"trx_undo_slots_used", "transaction", "Number of undo slots used",
 | 
						{"trx_undo_slots_used", "transaction", "Number of undo slots used",
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user