summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/include/commit.inc2
-rw-r--r--mysql-test/lib/My/Debugger.pm2
-rw-r--r--mysql-test/main/commit_1innodb.result2
-rw-r--r--mysql-test/suite/binlog/r/binlog_admin_cmd_kill.result40
-rw-r--r--mysql-test/suite/binlog/t/binlog_admin_cmd_kill.test95
-rw-r--r--mysql-test/suite/galera_3nodes/disabled.def1
-rw-r--r--mysql-test/suite/rpl/r/rpl_mark_optimize_tbl_ddl.result79
-rw-r--r--mysql-test/suite/rpl/t/rpl_mark_optimize_tbl_ddl.test142
-rw-r--r--mysql-test/suite/rpl/t/rpl_slave_shutdown_mdev20821.test8
-rw-r--r--sql/handler.h12
-rw-r--r--sql/log_event.cc4
-rw-r--r--sql/rpl_rli.cc4
-rw-r--r--sql/sql_admin.cc77
-rw-r--r--sql/sql_class.h3
-rw-r--r--storage/innobase/handler/ha_innodb.cc8
15 files changed, 426 insertions, 53 deletions
diff --git a/mysql-test/include/commit.inc b/mysql-test/include/commit.inc
index a28d3e5f3d1..1844a5320f7 100644
--- a/mysql-test/include/commit.inc
+++ b/mysql-test/include/commit.inc
@@ -770,7 +770,7 @@ call p_verify_status_increment(2, 0, 2, 0);
commit;
call p_verify_status_increment(0, 0, 0, 0);
check table t1, t2, t3;
-call p_verify_status_increment(6, 0, 6, 0);
+call p_verify_status_increment(4, 0, 4, 0);
commit;
call p_verify_status_increment(0, 0, 0, 0);
drop view v1;
diff --git a/mysql-test/lib/My/Debugger.pm b/mysql-test/lib/My/Debugger.pm
index 5e04c070e7f..cc151b233d5 100644
--- a/mysql-test/lib/My/Debugger.pm
+++ b/mysql-test/lib/My/Debugger.pm
@@ -139,7 +139,7 @@ sub do_args($$$$$) {
my $v = $debuggers{$k};
# on windows mtr args are quoted (for system), otherwise not (for exec)
- sub quote($) { $_[0] =~ / / ? "\"$_[0]\"" : $_[0] }
+ sub quote($) { $_[0] =~ /[; ]/ ? "\"$_[0]\"" : $_[0] }
sub unquote($) { $_[0] =~ s/^"(.*)"$/$1/; $_[0] }
sub quote_from_mtr($) { IS_WINDOWS() ? $_[0] : quote($_[0]) }
sub unquote_for_mtr($) { IS_WINDOWS() ? $_[0] : unquote($_[0]) }
diff --git a/mysql-test/main/commit_1innodb.result b/mysql-test/main/commit_1innodb.result
index 7d21540b548..a7b544dc282 100644
--- a/mysql-test/main/commit_1innodb.result
+++ b/mysql-test/main/commit_1innodb.result
@@ -874,7 +874,7 @@ Table Op Msg_type Msg_text
test.t1 check status OK
test.t2 check status OK
test.t3 check status OK
-call p_verify_status_increment(6, 0, 6, 0);
+call p_verify_status_increment(4, 0, 4, 0);
SUCCESS
commit;
diff --git a/mysql-test/suite/binlog/r/binlog_admin_cmd_kill.result b/mysql-test/suite/binlog/r/binlog_admin_cmd_kill.result
new file mode 100644
index 00000000000..a2eb7ee5c0a
--- /dev/null
+++ b/mysql-test/suite/binlog/r/binlog_admin_cmd_kill.result
@@ -0,0 +1,40 @@
+#
+# Kill OPTIMIZE command prior to table modification
+#
+RESET MASTER;
+CREATE TABLE t1 (f INT) ENGINE=INNODB;
+CREATE TABLE t2 (f INT) ENGINE=INNODB;
+connect con1,127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection con1;
+SET debug_sync='admin_command_kill_before_modify SIGNAL ready_to_be_killed WAIT_FOR master_cont';
+OPTIMIZE TABLE t1,t2;
+connection default;
+SET debug_sync='now WAIT_FOR ready_to_be_killed';
+KILL THD_ID;
+SET debug_sync = 'reset';
+disconnect con1;
+include/show_binlog_events.inc
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Gtid # # GTID #-#-#
+master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (f INT) ENGINE=INNODB
+master-bin.000001 # Gtid # # GTID #-#-#
+master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (f INT) ENGINE=INNODB
+DROP TABLE t1,t2;
+FLUSH LOGS;
+#
+# Kill OPTIMIZE command after table modification
+#
+CREATE TABLE t1 (f INT) ENGINE=INNODB;
+CREATE TABLE t2 (f INT) ENGINE=INNODB;
+connect con1,127.0.0.1,root,,test,$MASTER_MYPORT,;
+connection con1;
+SET debug_sync='admin_command_kill_after_modify SIGNAL ready_to_be_killed WAIT_FOR master_cont';
+OPTIMIZE TABLE t1,t2;
+connection default;
+SET debug_sync='now WAIT_FOR ready_to_be_killed';
+KILL THD_ID;
+SET debug_sync = 'reset';
+disconnect con1;
+DROP TABLE t1,t2;
+FLUSH LOGS;
+FOUND 1 /OPTIMIZE TABLE t1,t2/ in mysqlbinlog.out
diff --git a/mysql-test/suite/binlog/t/binlog_admin_cmd_kill.test b/mysql-test/suite/binlog/t/binlog_admin_cmd_kill.test
new file mode 100644
index 00000000000..9b248097ae2
--- /dev/null
+++ b/mysql-test/suite/binlog/t/binlog_admin_cmd_kill.test
@@ -0,0 +1,95 @@
+# ==== Purpose ====
+#
+# Test verifies that when an admin command execution is interrupted by KILL
+# command it should stop its execution. The admin command in binary log should
+# contain only the list of tables which have successfully executed admin
+# command prior to kill.
+#
+# ==== Implementation ====
+#
+# Steps:
+# 0 - Create two table t1,t2.
+# 1 - Execute OPTIMIZE TABLE t1,t2 command.
+# 2 - Using debug sync mechanism kill OPTIMIZE TABLE command at a stage
+# where it has not optimized any table.
+# 3 - Check that OPTIMIZE TABLE command is not written to binary log.
+# 4 - Using debug sync mechanism hold the execution of OPTIMIZE TABLE after
+# t1 table optimization. Now kill the OPTIMIZE TABLE command.
+# 5 - Observe the binlog output, the OPTIMIZE TABLE command should display `t1,t2`.
+# 6 - Please note that, we binlog the entire query even if at least one
+# table is modified as admin commands are safe to replicate and they will
+# not make the slave to diverge.
+#
+# ==== References ====
+#
+# MDEV-22530: Aborting OPTIMIZE TABLE still logs in binary log and replicates to the Slave server.
+#
+--source include/have_log_bin.inc
+--source include/have_debug.inc
+--source include/have_debug_sync.inc
+--source include/have_innodb.inc
+
+--echo #
+--echo # Kill OPTIMIZE command prior to table modification
+--echo #
+RESET MASTER;
+
+CREATE TABLE t1 (f INT) ENGINE=INNODB;
+CREATE TABLE t2 (f INT) ENGINE=INNODB;
+
+--connect(con1,127.0.0.1,root,,test,$MASTER_MYPORT,)
+--connection con1
+SET debug_sync='admin_command_kill_before_modify SIGNAL ready_to_be_killed WAIT_FOR master_cont';
+--send OPTIMIZE TABLE t1,t2
+
+--connection default
+SET debug_sync='now WAIT_FOR ready_to_be_killed';
+--let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%OPTIMIZE TABLE %'`
+
+# Now kill.
+--replace_result $thd_id THD_ID
+eval KILL $thd_id;
+
+SET debug_sync = 'reset';
+--disconnect con1
+
+--source include/show_binlog_events.inc
+DROP TABLE t1,t2;
+
+FLUSH LOGS;
+
+--echo #
+--echo # Kill OPTIMIZE command after table modification
+--echo #
+
+CREATE TABLE t1 (f INT) ENGINE=INNODB;
+CREATE TABLE t2 (f INT) ENGINE=INNODB;
+
+--connect(con1,127.0.0.1,root,,test,$MASTER_MYPORT,)
+--connection con1
+SET debug_sync='admin_command_kill_after_modify SIGNAL ready_to_be_killed WAIT_FOR master_cont';
+--send OPTIMIZE TABLE t1,t2
+
+--connection default
+SET debug_sync='now WAIT_FOR ready_to_be_killed';
+--let $thd_id= `SELECT ID FROM INFORMATION_SCHEMA.PROCESSLIST WHERE INFO LIKE '%OPTIMIZE TABLE %'`
+
+# Now kill.
+--replace_result $thd_id THD_ID
+eval KILL $thd_id;
+
+SET debug_sync = 'reset';
+--disconnect con1
+
+DROP TABLE t1,t2;
+let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
+FLUSH LOGS;
+
+--let $MYSQLD_DATADIR= `select @@datadir`
+--exec $MYSQL_BINLOG $MYSQLD_DATADIR/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
+
+--let SEARCH_PATTERN= OPTIMIZE TABLE t1,t2
+--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
+--source include/search_pattern_in_file.inc
+
+--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
diff --git a/mysql-test/suite/galera_3nodes/disabled.def b/mysql-test/suite/galera_3nodes/disabled.def
index 7c4d16f98f5..9100db4d441 100644
--- a/mysql-test/suite/galera_3nodes/disabled.def
+++ b/mysql-test/suite/galera_3nodes/disabled.def
@@ -15,7 +15,6 @@ galera_gtid_2_cluster : MDEV-23775 Galera test failure on galera_3nodes.galera_g
galera_ist_gcache_rollover : MDEV-23578 WSREP: exception caused by message: {v=0,t=1,ut=255,o=4,s=0,sr=0,as=1,f=6,src=50524cfe,srcvid=view_id(REG,50524cfe,4),insvid=view_id(UNKNOWN,00000000,0),ru=00000000,r=[-1,-1],fs=75,nl=(}
galera_load_data_ist : MDEV-24639 galera_3nodes.galera_load_data_ist MTR failed with SIGABRT: query 'reap' failed: 2013: Lost connection to MySQL server during query
galera_load_data_ist : MDEV-24639 galera_3nodes.galera_load_data_ist MTR failed with SIGABRT: query 'reap' failed: 2013: Lost connection to MySQL server during query
-galera_pc_bootstrap : MDEV-24650 galera_pc_bootstrap MTR failed: Could not execute 'check-testcase' before testcase
galera_safe_to_bootstrap : MDEV-24097 galera_3nodes.galera_safe_to_bootstrap MTR sporadaically fails: Failed to start mysqld or mysql_shutdown failed
galera_slave_options_do : MDEV-8798
galera_slave_options_ignore : MDEV-8798
diff --git a/mysql-test/suite/rpl/r/rpl_mark_optimize_tbl_ddl.result b/mysql-test/suite/rpl/r/rpl_mark_optimize_tbl_ddl.result
new file mode 100644
index 00000000000..9aa31a73e49
--- /dev/null
+++ b/mysql-test/suite/rpl/r/rpl_mark_optimize_tbl_ddl.result
@@ -0,0 +1,79 @@
+include/rpl_init.inc [topology=1->2]
+connection server_1;
+FLUSH TABLES;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+connection server_2;
+SET @save_slave_parallel_threads= @@GLOBAL.slave_parallel_threads;
+SET @save_slave_parallel_mode= @@GLOBAL.slave_parallel_mode;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=2;
+SET GLOBAL slave_parallel_mode=optimistic;
+include/start_slave.inc
+connection server_1;
+CREATE TABLE t1(a INT) ENGINE=INNODB;
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+test.t1 optimize status OK
+INSERT INTO t1 VALUES(1);
+INSERT INTO t1 SELECT 1+a FROM t1;
+INSERT INTO t1 SELECT 2+a FROM t1;
+connection server_2;
+#
+# Verify that following admin commands are marked as ddl
+# 'OPTIMIZE TABLE', 'REPAIR TABLE' and 'ANALYZE TABLE'
+#
+connection server_1;
+OPTIMIZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 optimize note Table does not support optimize, doing recreate + analyze instead
+test.t1 optimize status OK
+REPAIR TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 repair note The storage engine for the table doesn't support repair
+ANALYZE TABLE t1;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+FLUSH LOGS;
+FOUND 1 /GTID 0-1-8 ddl/ in mysqlbinlog.out
+FOUND 1 /GTID 0-1-9 ddl/ in mysqlbinlog.out
+FOUND 1 /GTID 0-1-10 ddl/ in mysqlbinlog.out
+#
+# Clean up
+#
+DROP TABLE t1;
+connection server_2;
+FLUSH LOGS;
+#
+# Check that ALTER TABLE commands with ANALYZE, OPTIMIZE and REPAIR on
+# partitions will be marked as DDL in binary log.
+#
+connection server_1;
+CREATE TABLE t1(id INT) PARTITION BY RANGE (id) (PARTITION p0 VALUES LESS THAN (100),
+PARTITION pmax VALUES LESS THAN (MAXVALUE));
+INSERT INTO t1 VALUES (1), (10), (100), (1000);
+ALTER TABLE t1 ANALYZE PARTITION p0;
+Table Op Msg_type Msg_text
+test.t1 analyze status Engine-independent statistics collected
+test.t1 analyze status OK
+ALTER TABLE t1 OPTIMIZE PARTITION p0;
+Table Op Msg_type Msg_text
+test.t1 optimize status OK
+ALTER TABLE t1 REPAIR PARTITION p0;
+Table Op Msg_type Msg_text
+test.t1 repair status OK
+FLUSH LOGS;
+FOUND 1 /GTID 0-1-14 ddl/ in mysqlbinlog.out
+FOUND 1 /GTID 0-1-15 ddl/ in mysqlbinlog.out
+FOUND 1 /GTID 0-1-16 ddl/ in mysqlbinlog.out
+#
+# Clean up
+#
+DROP TABLE t1;
+connection server_2;
+include/stop_slave.inc
+SET GLOBAL slave_parallel_threads= @save_slave_parallel_threads;
+SET GLOBAL slave_parallel_mode= @save_slave_parallel_mode;
+include/start_slave.inc
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_mark_optimize_tbl_ddl.test b/mysql-test/suite/rpl/t/rpl_mark_optimize_tbl_ddl.test
new file mode 100644
index 00000000000..6d66e3fd088
--- /dev/null
+++ b/mysql-test/suite/rpl/t/rpl_mark_optimize_tbl_ddl.test
@@ -0,0 +1,142 @@
+# ==== Purpose ====
+#
+# Test verifies that there is no deadlock or assertion in
+# slave_parallel_mode=optimistic configuration while applying admin command
+# like 'OPTIMIZE TABLE', 'REPAIR TABLE' and 'ANALYZE TABLE'.
+#
+# ==== Implementation ====
+#
+# Steps:
+# 0 - Create a table, execute OPTIMIZE TABLE command on the table followed
+# by some DMLS.
+# 1 - No assert should happen on slave server.
+# 2 - Assert that 'OPTIMIZE TABLE', 'REPAIR TABLE' and 'ANALYZE TABLE' are
+# marked as 'DDL' in the binary log.
+#
+# ==== References ====
+#
+# MDEV-17515: GTID Replication in optimistic mode deadlock
+#
+--source include/have_partition.inc
+--source include/have_innodb.inc
+--let $rpl_topology=1->2
+--source include/rpl_init.inc
+
+--connection server_1
+FLUSH TABLES;
+ALTER TABLE mysql.gtid_slave_pos ENGINE=InnoDB;
+
+--connection server_2
+SET @save_slave_parallel_threads= @@GLOBAL.slave_parallel_threads;
+SET @save_slave_parallel_mode= @@GLOBAL.slave_parallel_mode;
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads=2;
+SET GLOBAL slave_parallel_mode=optimistic;
+--source include/start_slave.inc
+
+--connection server_1
+CREATE TABLE t1(a INT) ENGINE=INNODB;
+OPTIMIZE TABLE t1;
+INSERT INTO t1 VALUES(1);
+INSERT INTO t1 SELECT 1+a FROM t1;
+INSERT INTO t1 SELECT 2+a FROM t1;
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+
+--echo #
+--echo # Verify that following admin commands are marked as ddl
+--echo # 'OPTIMIZE TABLE', 'REPAIR TABLE' and 'ANALYZE TABLE'
+--echo #
+--connection server_1
+
+OPTIMIZE TABLE t1;
+--let optimize_gtid= `SELECT @@GLOBAL.gtid_binlog_pos`
+
+REPAIR TABLE t1;
+--let repair_gtid= `SELECT @@GLOBAL.gtid_binlog_pos`
+
+ANALYZE TABLE t1;
+--let analyze_gtid= `SELECT @@GLOBAL.gtid_binlog_pos`
+
+let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
+FLUSH LOGS;
+
+--let $MYSQLD_DATADIR= `select @@datadir`
+--exec $MYSQL_BINLOG $MYSQLD_DATADIR/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
+
+--let SEARCH_PATTERN= GTID $optimize_gtid ddl
+--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
+--source include/search_pattern_in_file.inc
+
+--let SEARCH_PATTERN= GTID $repair_gtid ddl
+--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
+--source include/search_pattern_in_file.inc
+
+--let SEARCH_PATTERN= GTID $analyze_gtid ddl
+--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
+--source include/search_pattern_in_file.inc
+
+--echo #
+--echo # Clean up
+--echo #
+DROP TABLE t1;
+--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+FLUSH LOGS;
+
+--echo #
+--echo # Check that ALTER TABLE commands with ANALYZE, OPTIMIZE and REPAIR on
+--echo # partitions will be marked as DDL in binary log.
+--echo #
+--connection server_1
+CREATE TABLE t1(id INT) PARTITION BY RANGE (id) (PARTITION p0 VALUES LESS THAN (100),
+ PARTITION pmax VALUES LESS THAN (MAXVALUE));
+INSERT INTO t1 VALUES (1), (10), (100), (1000);
+
+ALTER TABLE t1 ANALYZE PARTITION p0;
+--let analyze_gtid= `SELECT @@GLOBAL.gtid_binlog_pos`
+
+ALTER TABLE t1 OPTIMIZE PARTITION p0;
+--let optimize_gtid= `SELECT @@GLOBAL.gtid_binlog_pos`
+
+ALTER TABLE t1 REPAIR PARTITION p0;
+--let repair_gtid= `SELECT @@GLOBAL.gtid_binlog_pos`
+
+let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1);
+FLUSH LOGS;
+
+--exec $MYSQL_BINLOG $MYSQLD_DATADIR/$binlog_file > $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
+
+--let SEARCH_PATTERN= GTID $analyze_gtid ddl
+--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
+--source include/search_pattern_in_file.inc
+
+--let SEARCH_PATTERN= GTID $optimize_gtid ddl
+--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
+--source include/search_pattern_in_file.inc
+
+--let SEARCH_PATTERN= GTID $repair_gtid ddl
+--let SEARCH_FILE= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
+--source include/search_pattern_in_file.inc
+
+--echo #
+--echo # Clean up
+--echo #
+DROP TABLE t1;
+--remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog.out
+--save_master_pos
+
+--connection server_2
+--sync_with_master
+
+--source include/stop_slave.inc
+SET GLOBAL slave_parallel_threads= @save_slave_parallel_threads;
+SET GLOBAL slave_parallel_mode= @save_slave_parallel_mode;
+--source include/start_slave.inc
+
+--source include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/rpl_slave_shutdown_mdev20821.test b/mysql-test/suite/rpl/t/rpl_slave_shutdown_mdev20821.test
index 563533bb104..6f73de984d3 100644
--- a/mysql-test/suite/rpl/t/rpl_slave_shutdown_mdev20821.test
+++ b/mysql-test/suite/rpl/t/rpl_slave_shutdown_mdev20821.test
@@ -4,6 +4,10 @@
# hang when the parallel workers were idle.
# The bug reported scenario is extented to cover the multi-sources case as well as
# checking is done for both the idle and busy workers cases.
+#
+# MDEV-25336 Parallel replication causes failed assert while restarting
+# Since this test case involves slave restart this will help in testing
+# Mdev-25336 too.
--source include/have_innodb.inc
--source include/have_binlog_format_mixed.inc
@@ -26,7 +30,7 @@ select @@global.slave_parallel_workers as two;
# At this point worker threads have no assignement.
# Shutdown must not hang.
-
+# In 10.2/10.3 there should not be any assert failure `prev != 0 && next != 0'
--connection server_3
--write_file $MYSQLTEST_VARDIR/tmp/mysqld.3.expect
wait
@@ -75,6 +79,7 @@ insert into t1 values (1);
--connection server_3
--sync_with_master 0,''
+# In 10.2/10.3 there should not be any assert failure `prev != 0 && next != 0'
# At this point worker threads have no assignement.
# Shutdown must not hang.
@@ -117,6 +122,7 @@ insert into t1 values (2);
insert into t2 values (2);
+# In 10.2/10.3 there should not be any assert failure `prev != 0 && next != 0'
# At this point there's a good chance the worker threads are busy.
# SHUTDOWN must proceed without any delay as above.
--connection server_3
diff --git a/sql/handler.h b/sql/handler.h
index 891187db171..8b56a16bd6c 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1787,9 +1787,19 @@ struct THD_TRANS
CREATED_TEMP_TABLE= 2,
DROPPED_TEMP_TABLE= 4,
DID_WAIT= 8,
- DID_DDL= 0x10
+ DID_DDL= 0x10,
+ EXECUTED_TABLE_ADMIN_CMD= 0x20
};
+ void mark_executed_table_admin_cmd()
+ {
+ DBUG_PRINT("debug", ("mark_executed_table_admin_cmd"));
+ m_unsafe_rollback_flags|= EXECUTED_TABLE_ADMIN_CMD;
+ }
+ bool trans_executed_admin_cmd()
+ {
+ return (m_unsafe_rollback_flags & EXECUTED_TABLE_ADMIN_CMD) != 0;
+ }
void mark_created_temp_table()
{
DBUG_PRINT("debug", ("mark_created_temp_table"));
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 349e35488e2..0dcb1a8d9a2 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -7990,8 +7990,10 @@ Gtid_log_event::Gtid_log_event(THD *thd_arg, uint64 seq_no_arg,
flags2|= FL_WAITED;
if (thd_arg->transaction.stmt.trans_did_ddl() ||
thd_arg->transaction.stmt.has_created_dropped_temp_table() ||
+ thd_arg->transaction.stmt.trans_executed_admin_cmd() ||
thd_arg->transaction.all.trans_did_ddl() ||
- thd_arg->transaction.all.has_created_dropped_temp_table())
+ thd_arg->transaction.all.has_created_dropped_temp_table() ||
+ thd_arg->transaction.all.trans_executed_admin_cmd())
flags2|= FL_DDL;
else if (is_transactional && !is_tmp_table)
flags2|= FL_TRANSACTIONAL;
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index c8f77acf523..c0ade40b461 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -207,8 +207,8 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
*/
sql_print_warning("Neither --relay-log nor --relay-log-index were used;"
" so replication "
- "may break when this MySQL server acts as a "
- "slave and has his hostname changed!! Please "
+ "may break when this MariaDB server acts as a "
+ "replica and has its hostname changed. Please "
"use '--log-basename=#' or '--relay-log=%s' to avoid "
"this problem.", ln);
name_warning_sent= 1;
diff --git a/sql/sql_admin.cc b/sql/sql_admin.cc
index a96eb58809b..273955b7541 100644
--- a/sql/sql_admin.cc
+++ b/sql/sql_admin.cc
@@ -1,5 +1,5 @@
/* Copyright (c) 2010, 2015, Oracle and/or its affiliates.
- Copyright (c) 2011, 2020, MariaDB
+ Copyright (c) 2011, 2021, MariaDB
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
@@ -497,7 +497,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
int (handler::*operator_func)(THD *,
HA_CHECK_OPT *),
int (view_operator_func)(THD *, TABLE_LIST*,
- HA_CHECK_OPT *))
+ HA_CHECK_OPT *),
+ bool is_cmd_replicated)
{
TABLE_LIST *table;
List<Item> field_list;
@@ -508,6 +509,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
int compl_result_code;
bool need_repair_or_alter= 0;
wait_for_commit* suspended_wfc;
+ bool is_table_modified= false;
+
DBUG_ENTER("mysql_admin_table");
DBUG_PRINT("enter", ("extra_open_options: %u", extra_open_options));
@@ -567,6 +570,10 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
bool open_for_modify= org_open_for_modify;
DBUG_PRINT("admin", ("table: '%s'.'%s'", db, table->table_name.str));
+ DEBUG_SYNC(thd, "admin_command_kill_before_modify");
+
+ if (thd->is_killed())
+ break;
strxmov(table_name, db, ".", table->table_name.str, NullS);
thd->open_options|= extra_open_options;
table->lock_type= lock_type;
@@ -1219,6 +1226,13 @@ send_result_message:
break;
}
}
+ /*
+ Admin commands acquire table locks and these locks are not detected by
+ parallel replication deadlock detection-and-handling mechanism. Hence
+ they must be marked as DDL so that they are not scheduled in parallel
+ with conflicting DMLs resulting in deadlock.
+ */
+ thd->transaction.stmt.mark_executed_table_admin_cmd();
if (table->table && !table->view)
{
if (table->table->s->tmp_table)
@@ -1254,10 +1268,9 @@ send_result_message:
}
else
{
- if (trans_commit_stmt(thd) ||
- (stmt_causes_implicit_commit(thd, CF_IMPLICIT_COMMIT_END) &&
- trans_commit_implicit(thd)))
+ if (trans_commit_stmt(thd))
goto err;
+ is_table_modified= true;
}
close_thread_tables(thd);
thd->release_transactional_locks();
@@ -1280,6 +1293,16 @@ send_result_message:
if (protocol->write())
goto err;
+ DEBUG_SYNC(thd, "admin_command_kill_after_modify");
+ }
+ if (is_table_modified && is_cmd_replicated &&
+ (!opt_readonly || thd->slave_thread) && !thd->lex->no_write_to_binlog)
+ {
+ thd->get_stmt_da()->set_overwrite_status(true);
+ auto res= write_bin_log(thd, true, thd->query(), thd->query_length());
+ thd->get_stmt_da()->set_overwrite_status(false);
+ if (res)
+ goto err;
}
my_eof(thd);
@@ -1342,7 +1365,7 @@ bool mysql_assign_to_keycache(THD* thd, TABLE_LIST* tables,
check_opt.key_cache= key_cache;
DBUG_RETURN(mysql_admin_table(thd, tables, &check_opt,
"assign_to_keycache", TL_READ_NO_INSERT, 0, 0,
- 0, 0, &handler::assign_to_keycache, 0));
+ 0, 0, &handler::assign_to_keycache, 0, false));
}
@@ -1369,7 +1392,7 @@ bool mysql_preload_keys(THD* thd, TABLE_LIST* tables)
*/
DBUG_RETURN(mysql_admin_table(thd, tables, 0,
"preload_keys", TL_READ_NO_INSERT, 0, 0, 0, 0,
- &handler::preload_keys, 0));
+ &handler::preload_keys, 0, false));
}
@@ -1390,17 +1413,8 @@ bool Sql_cmd_analyze_table::execute(THD *thd)
WSREP_TO_ISOLATION_BEGIN_WRTCHK(NULL, NULL, first_table);
res= mysql_admin_table(thd, first_table, &m_lex->check_opt,
"analyze", lock_type, 1, 0, 0, 0,
- &handler::ha_analyze, 0);
- /* ! we write after unlocking the table */
- if (!res && !m_lex->no_write_to_binlog && (!opt_readonly || thd->slave_thread))
- {
- /*
- Presumably, ANALYZE and binlog writing doesn't require synchronization
- */
- thd->get_stmt_da()->set_overwrite_status(true);
- res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
- thd->get_stmt_da()->set_overwrite_status(false);
- }
+ &handler::ha_analyze, 0, true);
+
m_lex->first_select_lex()->table_list.first= first_table;
m_lex->query_tables= first_table;
@@ -1426,7 +1440,7 @@ bool Sql_cmd_check_table::execute(THD *thd)
res= mysql_admin_table(thd, first_table, &m_lex->check_opt, "check",
lock_type, 0, 0, HA_OPEN_FOR_REPAIR, 0,
- &handler::ha_check, &view_check);
+ &handler::ha_check, &view_check, false);
m_lex->first_select_lex()->table_list.first= first_table;
m_lex->query_tables= first_table;
@@ -1451,17 +1465,8 @@ bool Sql_cmd_optimize_table::execute(THD *thd)
mysql_recreate_table(thd, first_table, true) :
mysql_admin_table(thd, first_table, &m_lex->check_opt,
"optimize", TL_WRITE, 1, 0, 0, 0,
- &handler::ha_optimize, 0);
- /* ! we write after unlocking the table */
- if (!res && !m_lex->no_write_to_binlog && (!opt_readonly || thd->slave_thread))
- {
- /*
- Presumably, OPTIMIZE and binlog writing doesn't require synchronization
- */
- thd->get_stmt_da()->set_overwrite_status(true);
- res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
- thd->get_stmt_da()->set_overwrite_status(false);
- }
+ &handler::ha_optimize, 0, true);
+
m_lex->first_select_lex()->table_list.first= first_table;
m_lex->query_tables= first_table;
@@ -1484,18 +1489,8 @@ bool Sql_cmd_repair_table::execute(THD *thd)
TL_WRITE, 1,
MY_TEST(m_lex->check_opt.sql_flags & TT_USEFRM),
HA_OPEN_FOR_REPAIR, &prepare_for_repair,
- &handler::ha_repair, &view_repair);
+ &handler::ha_repair, &view_repair, true);
- /* ! we write after unlocking the table */
- if (!res && !m_lex->no_write_to_binlog && (!opt_readonly || thd->slave_thread))
- {
- /*
- Presumably, REPAIR and binlog writing doesn't require synchronization
- */
- thd->get_stmt_da()->set_overwrite_status(true);
- res= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
- thd->get_stmt_da()->set_overwrite_status(false);
- }
m_lex->first_select_lex()->table_list.first= first_table;
m_lex->query_tables= first_table;
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 8edc6225d73..f754524332d 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -4992,7 +4992,8 @@ public:
transaction.all.m_unsafe_rollback_flags|=
(transaction.stmt.m_unsafe_rollback_flags &
(THD_TRANS::DID_WAIT | THD_TRANS::CREATED_TEMP_TABLE |
- THD_TRANS::DROPPED_TEMP_TABLE | THD_TRANS::DID_DDL));
+ THD_TRANS::DROPPED_TEMP_TABLE | THD_TRANS::DID_DDL |
+ THD_TRANS::EXECUTED_TABLE_ADMIN_CMD));
}
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 52b388b8d2a..6107f2bb1f4 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -9307,8 +9307,12 @@ ha_innobase::index_read(
/* For R-Tree index, we will always place the page lock to
pages being searched */
- if (dict_index_is_spatial(index)) {
- ++m_prebuilt->trx->will_lock;
+ if (index->is_spatial() && !m_prebuilt->trx->will_lock) {
+ if (trx_is_started(m_prebuilt->trx)) {
+ DBUG_RETURN(HA_ERR_READ_ONLY_TRANSACTION);
+ } else {
+ m_prebuilt->trx->will_lock = true;
+ }
}
/* Note that if the index for which the search template is built is not