From 40dbf0ea0e678370f4c34700e9868b3560cf8301 Mon Sep 17 00:00:00 2001 From: Bernard Spil Date: Sat, 23 May 2020 22:38:20 +0200 Subject: [PATCH 01/10] Fix duplicate word both both -> both Closes #1560 --- support-files/rpm/my.cnf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support-files/rpm/my.cnf b/support-files/rpm/my.cnf index 8c6a7139de5..5cda317d29e 100644 --- a/support-files/rpm/my.cnf +++ b/support-files/rpm/my.cnf @@ -1,5 +1,5 @@ # -# This group is read both both by the client and the server +# This group is read both by the client and the server # use it for options that affect everything # [client-server] From 8ec0e9111a49fe451109e5a558aeb603eca82259 Mon Sep 17 00:00:00 2001 From: sjaakola Date: Mon, 1 Jun 2020 12:34:33 +0300 Subject: [PATCH 02/10] MDEV-22763 backporting MDEV-20225 fix into 10.1 Backported the support for aborting and replaying stored procedure and fix for trigger key assigments from 10.4 version. Backported also two mtr tests: wsrep_sp_bf_abort and MDEV-20225 --- mysql-test/suite/galera/r/MDEV-20225.result | 16 + .../suite/galera/r/galera_sp_bf_abort.result | 294 +++++++++++++++ mysql-test/suite/galera/t/MDEV-20225.test | 49 +++ .../suite/galera/t/galera_sp_bf_abort.inc | 36 ++ .../suite/galera/t/galera_sp_bf_abort.test | 347 ++++++++++++++++++ sql/sp_head.cc | 89 +++++ sql/sql_trigger.cc | 16 +- sql/wsrep_hton.cc | 22 +- sql/wsrep_mysqld.cc | 9 +- sql/wsrep_thd.cc | 111 +++++- sql/wsrep_thd.h | 1 + 11 files changed, 978 insertions(+), 12 deletions(-) create mode 100644 mysql-test/suite/galera/r/MDEV-20225.result create mode 100644 mysql-test/suite/galera/r/galera_sp_bf_abort.result create mode 100644 mysql-test/suite/galera/t/MDEV-20225.test create mode 100644 mysql-test/suite/galera/t/galera_sp_bf_abort.inc create mode 100644 mysql-test/suite/galera/t/galera_sp_bf_abort.test diff --git a/mysql-test/suite/galera/r/MDEV-20225.result b/mysql-test/suite/galera/r/MDEV-20225.result new file mode 100644 index 00000000000..582353f10a6 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-20225.result @@ -0,0 +1,16 @@ +CREATE TABLE t1 (f1 INT NOT NULL PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; +CREATE TABLE t2 (f1 INT NOT NULL PRIMARY KEY AUTO_INCREMENT, f2 INT) ENGINE=InnoDB; +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES (NULL, NEW.f1); +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_slave_threads = 2; +SET GLOBAL debug_dbug = 'd,sync.mdev_20225'; +DROP TRIGGER tr1; +INSERT INTO t1 VALUES (NULL); +SET GLOBAL debug_dbug = 'RESET'; +SET DEBUG_SYNC = 'now SIGNAL signal.mdev_20225_continue'; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL wsrep_slave_threads = 1; +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/suite/galera/r/galera_sp_bf_abort.result b/mysql-test/suite/galera/r/galera_sp_bf_abort.result new file mode 100644 index 00000000000..205d73dd763 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_sp_bf_abort.result @@ -0,0 +1,294 @@ +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)); +SET SESSION wsrep_sync_wait = 0; +CREATE PROCEDURE proc_update_insert() +BEGIN +UPDATE t1 SET f2 = 'b'; +INSERT INTO t1 VALUES (4, 'd'); +END| +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +INSERT INTO t1 VALUES (2, 'c'); +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync'; +CALL proc_update_insert; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync'; +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +f1 f2 +1 b +2 c +3 b +4 d +wsrep_local_replays +1 +DELETE FROM t1; +CREATE PROCEDURE proc_update_insert_with_exit_handler() +BEGIN +DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END; +UPDATE t1 SET f2 = 'b'; +INSERT INTO t1 VALUES (4, 'd'); +END| +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +INSERT INTO t1 VALUES (2, 'c'); +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync'; +CALL proc_update_insert_with_exit_handler; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync'; +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +f1 f2 +1 b +2 c +3 b +4 d +wsrep_local_replays +1 +DELETE FROM t1; +CREATE PROCEDURE proc_update_insert_with_continue_handler() +BEGIN +DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END; +UPDATE t1 SET f2 = 'b'; +INSERT INTO t1 VALUES (4, 'd'); +END| +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +INSERT INTO t1 VALUES (2, 'c'); +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync'; +CALL proc_update_insert_with_continue_handler; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync'; +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +f1 f2 +1 b +2 c +3 b +4 d +wsrep_local_replays +1 +DELETE FROM t1; +CREATE PROCEDURE proc_update_insert_transaction() +BEGIN +START TRANSACTION; +UPDATE t1 SET f2 = 'b'; +INSERT INTO t1 VALUES (4, 'd'); +COMMIT; +END| +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +INSERT INTO t1 VALUES (2, 'c'); +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync'; +CALL proc_update_insert_transaction; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync'; +Warnings: +Error 1317 Query execution was interrupted +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +f1 f2 +1 b +2 c +3 b +4 d +wsrep_local_replays +1 +DELETE FROM t1; +CREATE PROCEDURE proc_update_insert_transaction_with_continue_handler() +BEGIN +DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END; +START TRANSACTION; +UPDATE t1 SET f2 = 'b'; +INSERT INTO t1 VALUES (4, 'd'); +COMMIT; +END| +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +INSERT INTO t1 VALUES (2, 'c'); +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync'; +CALL proc_update_insert_transaction_with_continue_handler; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync'; +Warnings: +Error 1317 Query execution was interrupted +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +f1 f2 +1 b +2 c +3 b +4 d +wsrep_local_replays +1 +DELETE FROM t1; +CREATE PROCEDURE proc_update_insert_transaction_with_exit_handler() +BEGIN +DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END; +START TRANSACTION; +UPDATE t1 SET f2 = 'b'; +INSERT INTO t1 VALUES (4, 'd'); +COMMIT; +END| +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +INSERT INTO t1 VALUES (2, 'c'); +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync'; +CALL proc_update_insert_transaction_with_exit_handler; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync'; +Warnings: +Error 1317 Query execution was interrupted +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +f1 f2 +1 b +2 c +3 b +4 d +wsrep_local_replays +1 +DELETE FROM t1; +CREATE PROCEDURE proc_insert_insert_conflict() +BEGIN +INSERT INTO t1 VALUES (2, 'd'); +INSERT INTO t1 VALUES (4, 'd'); +END| +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +INSERT INTO t1 VALUES (2, 'c'); +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync'; +CALL proc_insert_insert_conflict; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync'; +Got one of the listed errors +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +f1 f2 +1 a +2 c +3 a +wsrep_local_replays +1 +DELETE FROM t1; +CREATE PROCEDURE proc_insert_insert_conflict_with_exit_handler() +BEGIN +DECLARE EXIT HANDLER FOR SQLEXCEPTION SELECT "Conflict exit handler"; +INSERT INTO t1 VALUES (2, 'd'); +INSERT INTO t1 VALUES (4, 'd'); +END| +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +INSERT INTO t1 VALUES (2, 'c'); +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync'; +CALL proc_insert_insert_conflict_with_exit_handler; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync'; +Conflict exit handler +Conflict exit handler +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +f1 f2 +1 a +2 c +3 a +wsrep_local_replays +1 +DELETE FROM t1; +CREATE PROCEDURE proc_insert_insert_conflict_with_continue_handler() +BEGIN +DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SELECT "Conflict continue handler"; +INSERT INTO t1 VALUES (2, 'd'); +INSERT INTO t1 VALUES (4, 'd'); +END| +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_provider_options = 'dbug=d,apply_monitor_slave_enter_sync'; +INSERT INTO t1 VALUES (2, 'c'); +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'dbug=d,after_replicate_sync'; +CALL proc_insert_insert_conflict_with_continue_handler; +SET SESSION wsrep_on = 0; +SET SESSION wsrep_on = 1; +SET GLOBAL wsrep_provider_options = 'dbug='; +SET GLOBAL wsrep_provider_options = 'signal=apply_monitor_slave_enter_sync'; +SET GLOBAL wsrep_provider_options = 'signal=after_replicate_sync'; +Conflict continue handler +Conflict continue handler +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +f1 f2 +1 a +2 c +3 a +4 d +wsrep_local_replays +1 +DELETE FROM t1; +DROP PROCEDURE proc_update_insert; +DROP PROCEDURE proc_update_insert_with_continue_handler; +DROP PROCEDURE proc_update_insert_with_exit_handler; +DROP PROCEDURE proc_update_insert_transaction; +DROP PROCEDURE proc_update_insert_transaction_with_continue_handler; +DROP PROCEDURE proc_update_insert_transaction_with_exit_handler; +DROP PROCEDURE proc_insert_insert_conflict; +DROP PROCEDURE proc_insert_insert_conflict_with_exit_handler; +DROP PROCEDURE proc_insert_insert_conflict_with_continue_handler; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/MDEV-20225.test b/mysql-test/suite/galera/t/MDEV-20225.test new file mode 100644 index 00000000000..5fbd0965217 --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-20225.test @@ -0,0 +1,49 @@ +# +# MDEV-20225 - Verify that DROP TRIGGER gets keys assigned corresponding +# to all affected tables. +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc + +CREATE TABLE t1 (f1 INT NOT NULL PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; +CREATE TABLE t2 (f1 INT NOT NULL PRIMARY KEY AUTO_INCREMENT, f2 INT) ENGINE=InnoDB; + +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES (NULL, NEW.f1); + +--connection node_2 +SET SESSION wsrep_sync_wait = 0; +SET GLOBAL wsrep_slave_threads = 2; +SET GLOBAL debug_dbug = 'd,sync.mdev_20225'; + +--let $galera_connection_name = node_1a +--let $galera_server_number = 1 +--source include/galera_connect.inc +DROP TRIGGER tr1; + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST WHERE STATE = 'debug sync point: now' +--source include/wait_condition.inc + + +--connection node_1 +INSERT INTO t1 VALUES (NULL); +# We must rely on sleep here. If the bug is fixed, the second applier +# is not allowed to go past apply monitor which would trigger the bug, +# so there is no sync point or condition to wait. +--sleep 1 + +--connection node_2 +SET GLOBAL debug_dbug = 'RESET'; +SET DEBUG_SYNC = 'now SIGNAL signal.mdev_20225_continue'; +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL wsrep_slave_threads = 1; + +--let $wait_condition = SELECT COUNT(*) = 1 FROM test.t1; +--source include/wait_condition.inc + +# Trigger should now be dropped on node_2. +SHOW TRIGGERS; + +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/suite/galera/t/galera_sp_bf_abort.inc b/mysql-test/suite/galera/t/galera_sp_bf_abort.inc new file mode 100644 index 00000000000..7ca8ecf20a9 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sp_bf_abort.inc @@ -0,0 +1,36 @@ +# +# Issue an INSERT for gap between 1 and 3 to node_2 and wait until it hits +# apply monitor sync point on node_1 +# + +--connection node_1a +--let $galera_sync_point = apply_monitor_slave_enter_sync +--source include/galera_set_sync_point.inc + +--connection node_2 +--eval $galera_sp_bf_abort_conflict + +--connection node_1a +--source include/galera_wait_sync_point.inc +--source include/galera_clear_sync_point.inc + +# Send a procedure to node_1 which should take a gap lock between +# rows 1 and 3. It does not conflict with INSERT from node_2 in +# certification. Park the UPDATE after replicate and let INSERT to +# continue applying, generating a BF abort. + +--let $galera_sync_point = after_replicate_sync +--source include/galera_set_sync_point.inc + +--connection node_1 +--send_eval CALL $galera_sp_bf_abort_proc + +--connection node_1a +--let $galera_sync_point = after_replicate_sync apply_monitor_slave_enter_sync +--source include/galera_wait_sync_point.inc +--source include/galera_clear_sync_point.inc + +--let $galera_sync_point = apply_monitor_slave_enter_sync +--source include/galera_signal_sync_point.inc +--let $galera_sync_point = after_replicate_sync +--source include/galera_signal_sync_point.inc diff --git a/mysql-test/suite/galera/t/galera_sp_bf_abort.test b/mysql-test/suite/galera/t/galera_sp_bf_abort.test new file mode 100644 index 00000000000..484e2ca478d --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sp_bf_abort.test @@ -0,0 +1,347 @@ +# +# Test cases for stored procedure BF aborts. +# + +--source include/galera_cluster.inc +--source include/have_innodb.inc + +--connection node_1 + +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)); + +# Control connection for Galera sync point management +--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1 +--connection node_1a +SET SESSION wsrep_sync_wait = 0; + +--connection node_1 +# +# Case 1a: Procedure does and UPDATE which will suffer BF abort +# but there is no actual conflict and non-conflicting INSERT. +# The expected outcome is that both UPDATE and INSERT will succedd +# and no errors are reported to the client, wsrep_local_replays is +# incremented by one. +# +DELIMITER |; +CREATE PROCEDURE proc_update_insert() +BEGIN + UPDATE t1 SET f2 = 'b'; + INSERT INTO t1 VALUES (4, 'd'); +END| +DELIMITER ;| + +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +SET SESSION wsrep_sync_wait = 0; +--let $wsrep_local_replays_orig = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--let $galera_sp_bf_abort_proc = proc_update_insert +--let $galera_sp_bf_abort_conflict = INSERT INTO t1 VALUES (2, 'c') +--source galera_sp_bf_abort.inc +--connection node_1 +--reap +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +--let $wsrep_local_replays_curr = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--disable_query_log +--eval SELECT $wsrep_local_replays_curr - $wsrep_local_replays_orig = 1 AS wsrep_local_replays; +--enable_query_log + +DELETE FROM t1; + +--connection node_1 +# +# Case 1b: Procedure does and UPDATE which will suffer BF abort +# but there is no actual conflict and non-conflicting INSERT. +# An EXIT HANDLER is declared for the procedure. +# The expected outcome is that both UPDATE and INSERT will succedd +# and no errors are reported to the client, wsrep_local_replays is +# incremented by one. +# +DELIMITER |; +CREATE PROCEDURE proc_update_insert_with_exit_handler() +BEGIN + DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END; + UPDATE t1 SET f2 = 'b'; + INSERT INTO t1 VALUES (4, 'd'); +END| +DELIMITER ;| + +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +SET SESSION wsrep_sync_wait = 0; +--let $wsrep_local_replays_orig = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--let $galera_sp_bf_abort_proc = proc_update_insert_with_exit_handler +--let $galera_sp_bf_abort_conflict = INSERT INTO t1 VALUES (2, 'c') +--source galera_sp_bf_abort.inc +--connection node_1 +--reap +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +--let $wsrep_local_replays_curr = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--disable_query_log +--eval SELECT $wsrep_local_replays_curr - $wsrep_local_replays_orig = 1 AS wsrep_local_replays; +--enable_query_log + +DELETE FROM t1; + +--connection node_1 +# +# Case 1c: Procedure does and UPDATE which will suffer BF abort +# but there is no actual conflict and non-conflicting INSERT. +# A CONTINUE HANDLER is declared for the procedure. +# The expected outcome is that both UPDATE and INSERT will succedd +# and no errors are reported to the client, wsrep_local_replays is +# incremented by one. +# +DELIMITER |; +CREATE PROCEDURE proc_update_insert_with_continue_handler() +BEGIN + + DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END; + UPDATE t1 SET f2 = 'b'; + INSERT INTO t1 VALUES (4, 'd'); +END| +DELIMITER ;| + +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +SET SESSION wsrep_sync_wait = 0; +--let $wsrep_local_replays_orig = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--let $galera_sp_bf_abort_proc = proc_update_insert_with_continue_handler +--let $galera_sp_bf_abort_conflict = INSERT INTO t1 VALUES (2, 'c') +--source galera_sp_bf_abort.inc +--connection node_1 +--reap +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +--let $wsrep_local_replays_curr = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--disable_query_log +--eval SELECT $wsrep_local_replays_curr - $wsrep_local_replays_orig = 1 AS wsrep_local_replays; +--enable_query_log + +DELETE FROM t1; + +--connection node_1 +# +# Case 2a: UPDATE and INSERT are run inside a transaction and the transaction +# will be BF aborted on COMMIT. The expected outcome is that the transaction +# succeeds and no errors are reported to the client, wsrep_local_replays +# is incremented by one. +# + +DELIMITER |; +CREATE PROCEDURE proc_update_insert_transaction() +BEGIN + START TRANSACTION; + UPDATE t1 SET f2 = 'b'; + INSERT INTO t1 VALUES (4, 'd'); + COMMIT; +END| +DELIMITER ;| + +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +--let $wsrep_local_replays_orig = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--let $galera_sp_bf_abort_proc = proc_update_insert_transaction +--let $galera_sp_bf_abort_conflict = INSERT INTO t1 VALUES (2, 'c') +SET SESSION wsrep_sync_wait = 0; +--source galera_sp_bf_abort.inc +--connection node_1 +--reap +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +--let $wsrep_local_replays_curr = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--disable_query_log +--eval SELECT $wsrep_local_replays_curr - $wsrep_local_replays_orig = 1 AS wsrep_local_replays; +--enable_query_log + +DELETE FROM t1; + +--connection node_1 +# +# Case 2b: UPDATE and INSERT are run inside a transaction and the transaction +# will be BF aborted on COMMIT. A CONTINUE HANDLER is declared for the +# procedure. The expected outcome is that the transaction +# succeeds and no errors are reported to the client, wsrep_local_replays +# is incremented by one. +# + +DELIMITER |; +CREATE PROCEDURE proc_update_insert_transaction_with_continue_handler() +BEGIN + DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END; + START TRANSACTION; + UPDATE t1 SET f2 = 'b'; + INSERT INTO t1 VALUES (4, 'd'); + COMMIT; +END| +DELIMITER ;| + +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +--let $wsrep_local_replays_orig = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--let $galera_sp_bf_abort_proc = proc_update_insert_transaction_with_continue_handler +--let $galera_sp_bf_abort_conflict = INSERT INTO t1 VALUES (2, 'c') +SET SESSION wsrep_sync_wait = 0; +--source galera_sp_bf_abort.inc +--connection node_1 +--reap +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +--let $wsrep_local_replays_curr = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--disable_query_log +--eval SELECT $wsrep_local_replays_curr - $wsrep_local_replays_orig = 1 AS wsrep_local_replays; +--enable_query_log + +DELETE FROM t1; + +--connection node_1 +# +# Case 2c: UPDATE and INSERT are run inside a transaction and the transaction +# will be BF aborted on COMMIT. An EXIT HANDLE is declared for the procedure. +# The expected outcome is that the transaction succeeds and no errors are +# reported to the client, wsrep_local_replays is incremented by one. +# + +DELIMITER |; +CREATE PROCEDURE proc_update_insert_transaction_with_exit_handler() +BEGIN + DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END; + START TRANSACTION; + UPDATE t1 SET f2 = 'b'; + INSERT INTO t1 VALUES (4, 'd'); + COMMIT; +END| +DELIMITER ;| + +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +--let $wsrep_local_replays_orig = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--let $galera_sp_bf_abort_proc = proc_update_insert_transaction_with_exit_handler +--let $galera_sp_bf_abort_conflict = INSERT INTO t1 VALUES (2, 'c') +SET SESSION wsrep_sync_wait = 0; +--source galera_sp_bf_abort.inc +--connection node_1 +--reap +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +--let $wsrep_local_replays_curr = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--disable_query_log +--eval SELECT $wsrep_local_replays_curr - $wsrep_local_replays_orig = 1 AS wsrep_local_replays; +--enable_query_log + +DELETE FROM t1; + +--connection node_1 + +# +# Case 3a: Two INSERTs are run inside stored procedure, this time +# the first INSERT will have a BF abort and real conflict. The expected outcome +# is that the INSERT fails and an error is reported to the client. +# wsrep_local_replays is not incremented. +# +# Notice that the resulting error code may be both +# ER_DUP_ENTRY (procedure will exit with cert failure conflict state and +# will be) or ER_LOCK_DEADLOCK depending on timing. +# +DELIMITER |; +CREATE PROCEDURE proc_insert_insert_conflict() +BEGIN + INSERT INTO t1 VALUES (2, 'd'); + INSERT INTO t1 VALUES (4, 'd'); +END| +DELIMITER ;| + +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +--let $wsrep_local_replays_orig = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--let $galera_sp_bf_abort_proc = proc_insert_insert_conflict +--let $galera_sp_bf_abort_conflict = INSERT INTO t1 VALUES (2, 'c') +SET SESSION wsrep_sync_wait = 0; +--source galera_sp_bf_abort.inc +--connection node_1 +--error ER_DUP_ENTRY,ER_LOCK_DEADLOCK, ER_ERROR_DURING_COMMIT +--reap +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +--let $wsrep_local_replays_curr = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--disable_query_log +--eval SELECT $wsrep_local_replays_curr - $wsrep_local_replays_orig = 0 AS wsrep_local_replays; +--enable_query_log + +DELETE FROM t1; + +--connection node_1 + +# +# Case 3b: Two INSERTs are run inside stored procedure, this time +# the first INSERT will have a BF abort and real conflict. +# An EXIT HANDLER is declared for the procedure. The expected outcome +# is that the INSERT fails and an error is reported to the client. +# wsrep_local_replays is not incremented. +# +DELIMITER |; +CREATE PROCEDURE proc_insert_insert_conflict_with_exit_handler() +BEGIN + DECLARE EXIT HANDLER FOR SQLEXCEPTION SELECT "Conflict exit handler"; + INSERT INTO t1 VALUES (2, 'd'); + INSERT INTO t1 VALUES (4, 'd'); +END| +DELIMITER ;| + +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +--let $wsrep_local_replays_orig = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--let $galera_sp_bf_abort_proc = proc_insert_insert_conflict_with_exit_handler +--let $galera_sp_bf_abort_conflict = INSERT INTO t1 VALUES (2, 'c') +SET SESSION wsrep_sync_wait = 0; +--source galera_sp_bf_abort.inc +--connection node_1 +--reap +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +--let $wsrep_local_replays_curr = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--disable_query_log +--eval SELECT $wsrep_local_replays_curr - $wsrep_local_replays_orig = 0 AS wsrep_local_replays; +--enable_query_log + +DELETE FROM t1; + +--connection node_1 + +# +# Case 3c: Two INSERTs are run inside stored procedure, this time +# the first INSERT will have a BF abort and real conflict. +# A CONTINUE HANDLER is declared for the procedure. The expected outcome +# is that the the first INSERT fails but the second is executed without +# errors. wsrep_local_replays is not incremented. +# +DELIMITER |; +CREATE PROCEDURE proc_insert_insert_conflict_with_continue_handler() +BEGIN + DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SELECT "Conflict continue handler"; + INSERT INTO t1 VALUES (2, 'd'); + INSERT INTO t1 VALUES (4, 'd'); +END| +DELIMITER ;| + +INSERT INTO t1 VALUES (1, 'a'), (3, 'a'); +--let $wsrep_local_replays_orig = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--let $galera_sp_bf_abort_proc = proc_insert_insert_conflict_with_continue_handler +--let $galera_sp_bf_abort_conflict = INSERT INTO t1 VALUES (2, 'c') +SET SESSION wsrep_sync_wait = 0; +--source galera_sp_bf_abort.inc +--connection node_1 +--reap +SET SESSION wsrep_sync_wait = default; +SELECT * FROM t1; +--let $wsrep_local_replays_curr = `SELECT VARIABLE_VALUE FROM information_schema.global_status WHERE VARIABLE_NAME = 'wsrep_local_replays'` +--disable_query_log +--eval SELECT $wsrep_local_replays_curr - $wsrep_local_replays_orig = 0 AS wsrep_local_replays; +--enable_query_log + +DELETE FROM t1; + + +DROP PROCEDURE proc_update_insert; +DROP PROCEDURE proc_update_insert_with_continue_handler; +DROP PROCEDURE proc_update_insert_with_exit_handler; +DROP PROCEDURE proc_update_insert_transaction; +DROP PROCEDURE proc_update_insert_transaction_with_continue_handler; +DROP PROCEDURE proc_update_insert_transaction_with_exit_handler; +DROP PROCEDURE proc_insert_insert_conflict; +DROP PROCEDURE proc_insert_insert_conflict_with_exit_handler; +DROP PROCEDURE proc_insert_insert_conflict_with_continue_handler; +DROP TABLE t1; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index f940040b480..0428c0198a1 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -44,6 +44,9 @@ #include "transaction.h" // trans_commit_stmt #include "sql_audit.h" #include "debug_sync.h" +#ifdef WITH_WSREP +#include "wsrep_thd.h" +#endif /* WITH_WSREP */ /* Sufficient max length of printed destinations and frame offsets (all uints). @@ -1307,7 +1310,93 @@ sp_head::execute(THD *thd, bool merge_da_on_success) thd->m_digest= NULL; err_status= i->execute(thd, &ip); +#ifdef WITH_WSREP + if (m_type == TYPE_ENUM_PROCEDURE) + { + mysql_mutex_lock(&thd->LOCK_thd_data); + if (thd->wsrep_conflict_state == MUST_REPLAY) + { + wsrep_replay_sp_transaction(thd); + err_status= thd->get_stmt_da()->is_set(); + thd->wsrep_conflict_state= NO_CONFLICT; + } + else if (thd->wsrep_conflict_state == ABORTED || + thd->wsrep_conflict_state == CERT_FAILURE) + { + /* + If the statement execution was BF aborted or was aborted + due to certification failure, clean up transaction here + and reset conflict state to NO_CONFLICT and thd->killed + to THD::NOT_KILLED. Error handling is done based on err_status + below. Error must have been raised by wsrep hton code before + entering here. + */ + DBUG_ASSERT(err_status); + DBUG_ASSERT(thd->get_stmt_da()->is_error()); + thd->wsrep_conflict_state= NO_CONFLICT; + thd->killed= NOT_KILLED; + } + mysql_mutex_unlock(&thd->LOCK_thd_data); + } +#endif /* WITH_WSREP */ +#ifdef WITH_WSREP_NO + if (WSREP(thd)) + { + if (((thd->wsrep_trx().state() == wsrep::transaction::s_executing) && + (thd->is_fatal_error || thd->killed))) + { + WSREP_DEBUG("SP abort err status %d in sub %d trx state %d", + err_status, thd->in_sub_stmt, thd->wsrep_trx().state()); + err_status= 1; + thd->is_fatal_error= 1; + /* + SP was killed, and it is not due to a wsrep conflict. + We skip after_command hook at this point because + otherwise it clears the error, and cleans up the + whole transaction. For now we just return and finish + our handling once we are back to mysql_parse. + */ + WSREP_DEBUG("Skipping after_command hook for killed SP"); + } + else + { + const bool must_replay= wsrep_must_replay(thd); + if (must_replay) + { + WSREP_DEBUG("MUST_REPLAY set after SP, err_status %d trx state: %d", + err_status, thd->wsrep_trx().state()); + } + (void) wsrep_after_statement(thd); + /* + Reset the return code to zero if the transaction was + replayed succesfully. + */ + if (must_replay && !wsrep_current_error(thd)) + { + err_status= 0; + thd->get_stmt_da()->reset_diagnostics_area(); + } + /* + Final wsrep error status for statement is known only after + wsrep_after_statement() call. If the error is set, override + error in thd diagnostics area and reset wsrep client_state error + so that the error does not get propagated via client-server protocol. + */ + if (wsrep_current_error(thd)) + { + wsrep_override_error(thd, wsrep_current_error(thd), + wsrep_current_error_status(thd)); + thd->wsrep_cs().reset_error(); + /* Reset also thd->killed if it has been set during BF abort. */ + if (thd->killed == KILL_QUERY) + thd->killed= NOT_KILLED; + /* if failed transaction was not replayed, must return with error from here */ + if (!must_replay) err_status = 1; + } + } + } +#endif /* WITH_WSREP */ thd->m_digest= parent_digest; if (i->free_list) diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index c4d348ce400..2972ceecd8a 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -34,7 +34,9 @@ #include "sql_handler.h" // mysql_ha_rm_tables #include "sp_cache.h" // sp_invalidate_cache #include - +#ifdef WITH_WSREP +#include "debug_sync.h" +#endif /* WITH_WSREP */ /*************************************************************************/ template @@ -506,7 +508,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) #ifdef WITH_WSREP if (thd->wsrep_exec_mode == LOCAL_STATE) - WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, NULL); + WSREP_TO_ISOLATION_BEGIN(WSREP_MYSQL_DB, NULL, tables); #endif /* We should have only one table in table list. */ @@ -568,6 +570,16 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create) goto end; } +#ifdef WITH_WSREP + DBUG_EXECUTE_IF("sync.mdev_20225", + { + const char act[]= + "now " + "wait_for signal.mdev_20225_continue"; + DBUG_ASSERT(!debug_sync_set_action(thd, + STRING_WITH_LEN(act))); + };); +#endif /* WITH_WSREP */ result= (create ? table->triggers->create_trigger(thd, tables, &stmt_query): table->triggers->drop_trigger(thd, tables, &stmt_query)); diff --git a/sql/wsrep_hton.cc b/sql/wsrep_hton.cc index d8f82b13108..030c4244a30 100644 --- a/sql/wsrep_hton.cc +++ b/sql/wsrep_hton.cc @@ -37,6 +37,8 @@ extern "C" int thd_binlog_format(const MYSQL_THD thd); void wsrep_cleanup_transaction(THD *thd) { if (!WSREP(thd)) return; + DBUG_ASSERT(thd->wsrep_conflict_state != MUST_REPLAY && + thd->wsrep_conflict_state != REPLAYING); if (wsrep_emulate_bin_log) thd_binlog_trx_reset(thd); thd->wsrep_ws_handle.trx_id= WSREP_UNDEFINED_TRX_ID; @@ -136,7 +138,11 @@ void wsrep_post_commit(THD* thd, bool all) /* non-InnoDB statements may have populated events in stmt cache => cleanup */ - WSREP_DEBUG("cleanup transaction for LOCAL_STATE"); + if (thd->wsrep_conflict_state != MUST_REPLAY) + { + WSREP_DEBUG("cleanup transaction for LOCAL_STATE: %s", + WSREP_QUERY(thd)); + } /* Run post-rollback hook to clean up in the case if some keys were populated for the transaction in provider @@ -145,13 +151,18 @@ void wsrep_post_commit(THD* thd, bool all) rolls back to savepoint after first operation. */ if (all && thd->wsrep_conflict_state != MUST_REPLAY && - wsrep && wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle)) + thd->wsrep_conflict_state != REPLAYING && + wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle)) { WSREP_WARN("post_rollback fail: %llu %d", (long long)thd->thread_id, thd->get_stmt_da()->status()); } - wsrep_cleanup_transaction(thd); - break; + if (thd->wsrep_conflict_state != MUST_REPLAY && + thd->wsrep_conflict_state != REPLAYING) + { + wsrep_cleanup_transaction(thd); + } + break; } default: break; } @@ -575,7 +586,8 @@ wsrep_run_wsrep_commit(THD *thd, bool all) DBUG_ASSERT(thd->wsrep_trx_meta.gtid.seqno != WSREP_SEQNO_UNDEFINED); /* fall through */ case WSREP_TRX_FAIL: - WSREP_DEBUG("commit failed for reason: %d", rcode); + WSREP_DEBUG("commit failed for reason: %d conf %d", + rcode, thd->wsrep_conflict_state); DBUG_PRINT("wsrep", ("replicating commit fail")); thd->wsrep_query_state= QUERY_EXEC; diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index f38bf85cd1a..38f8ca413db 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1570,7 +1570,6 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, case SQLCOM_CREATE_TRIGGER: - DBUG_ASSERT(!table_list); DBUG_ASSERT(first_table); if (find_temporary_table(thd, first_table)) @@ -1579,6 +1578,14 @@ static bool wsrep_can_run_in_toi(THD *thd, const char *db, const char *table, } return true; + case SQLCOM_DROP_TRIGGER: + DBUG_ASSERT(table_list); + if (find_temporary_table(thd, table_list)) + { + return false; + } + return true; + default: if (table && !find_temporary_table(thd, db, table)) { diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index fad9e3f70c8..d37af157783 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -90,10 +90,10 @@ void wsrep_client_rollback(THD *thd) #define NUMBER_OF_FIELDS_TO_IDENTIFY_COORDINATOR 1 #define NUMBER_OF_FIELDS_TO_IDENTIFY_WORKER 2 -static rpl_group_info* wsrep_relay_group_init(const char* log_fname) +static rpl_group_info* wsrep_relay_group_init(THD *thd, const char* log_fname) { Relay_log_info* rli= new Relay_log_info(false); - + WSREP_DEBUG("wsrep_relay_group_init %s", log_fname); rli->no_storage= true; if (!rli->relay_log.description_event_for_exec) { @@ -123,7 +123,7 @@ static rpl_group_info* wsrep_relay_group_init(const char* log_fname) rli->mi = new Master_info(&connection_name, false); struct rpl_group_info *rgi= new rpl_group_info(rli); - rgi->thd= rli->sql_driver_thd= current_thd; + rgi->thd= rli->sql_driver_thd= thd; if ((rgi->deferred_events_collecting= rli->mi->rpl_filter->is_on())) { @@ -148,7 +148,7 @@ static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow) else thd->variables.option_bits&= ~(OPTION_BIN_LOG); - if (!thd->wsrep_rgi) thd->wsrep_rgi= wsrep_relay_group_init("wsrep_relay"); + if (!thd->wsrep_rgi) thd->wsrep_rgi= wsrep_relay_group_init(thd, "wsrep_relay"); /* thd->system_thread_info.rpl_sql_info isn't initialized. */ thd->system_thread_info.rpl_sql_info= @@ -189,6 +189,109 @@ static void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow* shadow) thd->set_row_count_func(shadow->row_count_func); } +void wsrep_replay_sp_transaction(THD* thd) +{ + DBUG_ENTER("wsrep_replay_sp_transaction"); + mysql_mutex_assert_owner(&thd->LOCK_thd_data); + DBUG_ASSERT(thd->wsrep_conflict_state == MUST_REPLAY); + DBUG_ASSERT(wsrep_thd_trx_seqno(thd) > 0); + + WSREP_DEBUG("replaying SP transaction %llu", thd->thread_id); + close_thread_tables(thd); + if (thd->locked_tables_mode && thd->lock) + { + WSREP_DEBUG("releasing table lock for replaying (%u)", + thd->thread_id); + thd->locked_tables_list.unlock_locked_tables(thd); + thd->variables.option_bits&= ~(OPTION_TABLE_LOCK); + } + thd->mdl_context.release_transactional_locks(); + + mysql_mutex_unlock(&thd->LOCK_thd_data); + THD *replay_thd= new THD(true); + replay_thd->thread_stack= thd->thread_stack; + + struct wsrep_thd_shadow shadow; + wsrep_prepare_bf_thd(replay_thd, &shadow); + WSREP_DEBUG("replaying set for %p rgi %p", replay_thd, replay_thd->wsrep_rgi); replay_thd->wsrep_trx_meta= thd->wsrep_trx_meta; + replay_thd->wsrep_ws_handle= thd->wsrep_ws_handle; + replay_thd->wsrep_ws_handle.trx_id= WSREP_UNDEFINED_TRX_ID; + replay_thd->wsrep_conflict_state= REPLAYING; + + replay_thd->variables.option_bits|= OPTION_BEGIN; + replay_thd->server_status|= SERVER_STATUS_IN_TRANS; + + thd->reset_globals(); + replay_thd->store_globals(); + wsrep_status_t rcode= wsrep->replay_trx(wsrep, + &replay_thd->wsrep_ws_handle, + (void*) replay_thd); + + wsrep_return_from_bf_mode(replay_thd, &shadow); + replay_thd->reset_globals(); + delete replay_thd; + + mysql_mutex_lock(&thd->LOCK_thd_data); + + thd->store_globals(); + + switch (rcode) + { + case WSREP_OK: + { + thd->wsrep_conflict_state= NO_CONFLICT; + thd->killed= NOT_KILLED; + wsrep_status_t rcode= wsrep->post_commit(wsrep, &thd->wsrep_ws_handle); + if (rcode != WSREP_OK) + { + WSREP_WARN("Post commit failed for SP replay: thd: %u error: %d", + thd->thread_id, rcode); + } + /* As replaying the transaction was successful, an error must not + be returned to client, so we need to reset the error state of + the diagnostics area */ + thd->get_stmt_da()->reset_diagnostics_area(); + break; + } + case WSREP_TRX_FAIL: + { + thd->wsrep_conflict_state= ABORTED; + wsrep_status_t rcode= wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle); + if (rcode != WSREP_OK) + { + WSREP_WARN("Post rollback failed for SP replay: thd: %u error: %d", + thd->thread_id, rcode); + } + if (thd->get_stmt_da()->is_set()) + { + thd->get_stmt_da()->reset_diagnostics_area(); + } + my_error(ER_LOCK_DEADLOCK, MYF(0)); + break; + } + default: + WSREP_ERROR("trx_replay failed for: %d, schema: %s, query: %s", + rcode, + (thd->db ? thd->db : "(null)"), + WSREP_QUERY(thd)); + /* we're now in inconsistent state, must abort */ + mysql_mutex_unlock(&thd->LOCK_thd_data); + unireg_abort(1); + break; + } + + wsrep_cleanup_transaction(thd); + + mysql_mutex_lock(&LOCK_wsrep_replaying); + wsrep_replaying--; + WSREP_DEBUG("replaying decreased: %d, thd: %u", + wsrep_replaying, thd->thread_id); + mysql_cond_broadcast(&COND_wsrep_replaying); + mysql_mutex_unlock(&LOCK_wsrep_replaying); + + DBUG_VOID_RETURN; +} + void wsrep_replay_transaction(THD *thd) { DBUG_ENTER("wsrep_replay_transaction"); diff --git a/sql/wsrep_thd.h b/sql/wsrep_thd.h index 6ce14a4eb0e..8e82a0fbe21 100644 --- a/sql/wsrep_thd.h +++ b/sql/wsrep_thd.h @@ -25,6 +25,7 @@ int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff, enum enum_var_type scope); void wsrep_client_rollback(THD *thd); +void wsrep_replay_sp_transaction(THD* thd); void wsrep_replay_transaction(THD *thd); void wsrep_create_appliers(long threads); void wsrep_create_rollbacker(); From 3f019d1771d4e6e21f941b72a83e0663f15b376f Mon Sep 17 00:00:00 2001 From: Julius Goryavsky Date: Wed, 3 Jun 2020 14:14:08 +0200 Subject: [PATCH 03/10] Added missing include files to check for debug_sync --- mysql-test/suite/galera/t/MDEV-20225.test | 3 +++ mysql-test/suite/galera/t/galera_sp_bf_abort.test | 3 +++ 2 files changed, 6 insertions(+) diff --git a/mysql-test/suite/galera/t/MDEV-20225.test b/mysql-test/suite/galera/t/MDEV-20225.test index 5fbd0965217..38efb0d6647 100644 --- a/mysql-test/suite/galera/t/MDEV-20225.test +++ b/mysql-test/suite/galera/t/MDEV-20225.test @@ -5,6 +5,9 @@ --source include/galera_cluster.inc --source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source suite/galera/include/galera_have_debug_sync.inc CREATE TABLE t1 (f1 INT NOT NULL PRIMARY KEY AUTO_INCREMENT) ENGINE=InnoDB; CREATE TABLE t2 (f1 INT NOT NULL PRIMARY KEY AUTO_INCREMENT, f2 INT) ENGINE=InnoDB; diff --git a/mysql-test/suite/galera/t/galera_sp_bf_abort.test b/mysql-test/suite/galera/t/galera_sp_bf_abort.test index 484e2ca478d..b5f28c23b05 100644 --- a/mysql-test/suite/galera/t/galera_sp_bf_abort.test +++ b/mysql-test/suite/galera/t/galera_sp_bf_abort.test @@ -4,6 +4,9 @@ --source include/galera_cluster.inc --source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source suite/galera/include/galera_have_debug_sync.inc --connection node_1 From f30ff10c8d02d8385bafa290b8c73367d49aece2 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Fri, 29 May 2020 00:32:08 +0530 Subject: [PATCH 04/10] MDEV-22715: SIGSEGV in radixsort_for_str_ptr and in native_compare/my_qsort2 (optimized builds) For DECIMAL[(M[,D])] datatype max_sort_length was not being honoured which was leading to buffer overflow while making the sort key. The fix to this problem would be to create sort keys for decimals with atmost max_sort_key bytes Important: The minimum value of max_sort_length has been raised to 8 (previously was 4), so fixed size datatypes like DOUBLE and BIGINIT are not truncated for lower values of max_sort_length. --- mysql-test/include/ctype_utf8mb4.inc | 2 +- mysql-test/r/ctype_utf16.result | 2 +- mysql-test/r/ctype_utf16le.result | 2 +- mysql-test/r/ctype_utf32.result | 2 +- mysql-test/r/ctype_utf8.result | 4 +- mysql-test/r/ctype_utf8mb4.result | 4 +- mysql-test/r/ctype_utf8mb4_heap.result | 4 +- mysql-test/r/ctype_utf8mb4_innodb.result | 4 +- mysql-test/r/ctype_utf8mb4_myisam.result | 4 +- mysql-test/r/order_by.result | 65 +++++++++++++++++++ .../sys_vars/r/max_sort_length_basic.result | 36 +++++----- .../sys_vars/r/sysvars_server_embedded.result | 2 +- .../r/sysvars_server_notembedded.result | 2 +- .../sys_vars/t/max_sort_length_basic.test | 8 +-- mysql-test/t/ctype_utf16.test | 2 +- mysql-test/t/ctype_utf16le.test | 2 +- mysql-test/t/ctype_utf32.test | 2 +- mysql-test/t/ctype_utf8.test | 2 +- mysql-test/t/ctype_utf8mb4.test | 2 +- mysql-test/t/order_by.test | 17 +++++ sql/field.cc | 5 +- sql/field.h | 7 ++ sql/sys_vars.cc | 2 +- 23 files changed, 135 insertions(+), 47 deletions(-) diff --git a/mysql-test/include/ctype_utf8mb4.inc b/mysql-test/include/ctype_utf8mb4.inc index 71993a946b3..aa06cd97e4c 100644 --- a/mysql-test/include/ctype_utf8mb4.inc +++ b/mysql-test/include/ctype_utf8mb4.inc @@ -1576,7 +1576,7 @@ drop table t1; --echo # --echo # Check strnxfrm() with odd length --echo # -set max_sort_length=5; +set max_sort_length=9; select @@max_sort_length; eval create table t1 (a varchar(128) character set utf8mb4 collate utf8mb4_general_ci) engine $engine; insert into t1 values ('a'),('b'),('c'); diff --git a/mysql-test/r/ctype_utf16.result b/mysql-test/r/ctype_utf16.result index c826a93809d..7c3d18a6cfc 100644 --- a/mysql-test/r/ctype_utf16.result +++ b/mysql-test/r/ctype_utf16.result @@ -1489,7 +1489,7 @@ ab ab AE AE -SET max_sort_length=4; +SET max_sort_length=8; SELECT * FROM t1 ORDER BY s1; s1 ab diff --git a/mysql-test/r/ctype_utf16le.result b/mysql-test/r/ctype_utf16le.result index e1a71e02bb6..d129323bae0 100644 --- a/mysql-test/r/ctype_utf16le.result +++ b/mysql-test/r/ctype_utf16le.result @@ -1762,7 +1762,7 @@ ab ab AE AE -SET max_sort_length=4; +SET max_sort_length=8; SELECT * FROM t1 ORDER BY s1; s1 ab diff --git a/mysql-test/r/ctype_utf32.result b/mysql-test/r/ctype_utf32.result index 4a44147e945..a4f7571d972 100644 --- a/mysql-test/r/ctype_utf32.result +++ b/mysql-test/r/ctype_utf32.result @@ -1503,7 +1503,7 @@ ab ab AE AE -SET max_sort_length=4; +SET max_sort_length=8; SELECT * FROM t1 ORDER BY s1; s1 ab diff --git a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result index 9ff12870d75..8b35305a79b 100644 --- a/mysql-test/r/ctype_utf8.result +++ b/mysql-test/r/ctype_utf8.result @@ -6807,10 +6807,10 @@ DFFFDFFF9CFF9DFF9EFF # # Checking strnxfrm() with odd length # -set max_sort_length=5; +set max_sort_length=9; select @@max_sort_length; @@max_sort_length -5 +9 create table t1 (a varchar(128) character set utf8 collate utf8_general_ci); insert into t1 values ('a'),('b'),('c'); select * from t1 order by a; diff --git a/mysql-test/r/ctype_utf8mb4.result b/mysql-test/r/ctype_utf8mb4.result index fa1cf3b1d19..d7bc36119ec 100644 --- a/mysql-test/r/ctype_utf8mb4.result +++ b/mysql-test/r/ctype_utf8mb4.result @@ -2364,10 +2364,10 @@ drop table t1; # # Check strnxfrm() with odd length # -set max_sort_length=5; +set max_sort_length=9; select @@max_sort_length; @@max_sort_length -5 +9 create table t1 (a varchar(128) character set utf8mb4 collate utf8mb4_general_ci); insert into t1 values ('a'),('b'),('c'); select * from t1 order by a; diff --git a/mysql-test/r/ctype_utf8mb4_heap.result b/mysql-test/r/ctype_utf8mb4_heap.result index ef134641ff8..9933c659ae3 100644 --- a/mysql-test/r/ctype_utf8mb4_heap.result +++ b/mysql-test/r/ctype_utf8mb4_heap.result @@ -2196,10 +2196,10 @@ drop table t1; # # Check strnxfrm() with odd length # -set max_sort_length=5; +set max_sort_length=9; select @@max_sort_length; @@max_sort_length -5 +9 create table t1 (a varchar(128) character set utf8mb4 collate utf8mb4_general_ci) engine heap; insert into t1 values ('a'),('b'),('c'); select * from t1 order by a; diff --git a/mysql-test/r/ctype_utf8mb4_innodb.result b/mysql-test/r/ctype_utf8mb4_innodb.result index 9c58dc87126..ff8fe980247 100644 --- a/mysql-test/r/ctype_utf8mb4_innodb.result +++ b/mysql-test/r/ctype_utf8mb4_innodb.result @@ -2324,10 +2324,10 @@ drop table t1; # # Check strnxfrm() with odd length # -set max_sort_length=5; +set max_sort_length=9; select @@max_sort_length; @@max_sort_length -5 +9 create table t1 (a varchar(128) character set utf8mb4 collate utf8mb4_general_ci) engine InnoDB; insert into t1 values ('a'),('b'),('c'); select * from t1 order by a; diff --git a/mysql-test/r/ctype_utf8mb4_myisam.result b/mysql-test/r/ctype_utf8mb4_myisam.result index 18bec51358d..b2e717a0737 100644 --- a/mysql-test/r/ctype_utf8mb4_myisam.result +++ b/mysql-test/r/ctype_utf8mb4_myisam.result @@ -2324,10 +2324,10 @@ drop table t1; # # Check strnxfrm() with odd length # -set max_sort_length=5; +set max_sort_length=9; select @@max_sort_length; @@max_sort_length -5 +9 create table t1 (a varchar(128) character set utf8mb4 collate utf8mb4_general_ci) engine MyISAM; insert into t1 values ('a'),('b'),('c'); select * from t1 order by a; diff --git a/mysql-test/r/order_by.result b/mysql-test/r/order_by.result index 380687554d7..d35012e0de5 100644 --- a/mysql-test/r/order_by.result +++ b/mysql-test/r/order_by.result @@ -3237,3 +3237,68 @@ o 15 p 16 set @@sort_buffer_size= @save_sort_buffer_size; drop table t1; +# +# MDEV-22715: SIGSEGV in radixsort_for_str_ptr and in native_compare/my_qsort2 (optimized builds) +# +SET @save_sort_buffer_size= @@sort_buffer_size; +SET @save_max_sort_length= @@max_sort_length; +SET max_sort_length=8; +SET sort_buffer_size=1024; +CREATE TABLE t1(a INT, b DECIMAL(65), c BLOB); +INSERT INTO t1 SELECT seq, seq, seq from seq_1_to_25; +INSERT INTO t1 SELECT seq, seq, seq from seq_1_to_25; +SELECT * FROM t1 ORDER BY a,b; +a b c +1 1 1 +1 1 1 +2 2 2 +2 2 2 +3 3 3 +3 3 3 +4 4 4 +4 4 4 +5 5 5 +5 5 5 +6 6 6 +6 6 6 +7 7 7 +7 7 7 +8 8 8 +8 8 8 +9 9 9 +9 9 9 +10 10 10 +10 10 10 +11 11 11 +11 11 11 +12 12 12 +12 12 12 +13 13 13 +13 13 13 +14 14 14 +14 14 14 +15 15 15 +15 15 15 +16 16 16 +16 16 16 +17 17 17 +17 17 17 +18 18 18 +18 18 18 +19 19 19 +19 19 19 +20 20 20 +20 20 20 +21 21 21 +21 21 21 +22 22 22 +22 22 22 +23 23 23 +23 23 23 +24 24 24 +24 24 24 +25 25 25 +25 25 25 +SET @@sort_buffer_size= @save_sort_buffer_size; +SET @@max_sort_length= @save_max_sort_length; +DROP TABLE t1; diff --git a/mysql-test/suite/sys_vars/r/max_sort_length_basic.result b/mysql-test/suite/sys_vars/r/max_sort_length_basic.result index a8876b2c81e..b48b045897c 100644 --- a/mysql-test/suite/sys_vars/r/max_sort_length_basic.result +++ b/mysql-test/suite/sys_vars/r/max_sort_length_basic.result @@ -27,14 +27,14 @@ SELECT @@session.max_sort_length = 1024; @@session.max_sort_length = 1024 1 '#--------------------FN_DYNVARS_084_03-------------------------#' -SET @@global.max_sort_length = 4; +SET @@global.max_sort_length = 8; SELECT @@global.max_sort_length; @@global.max_sort_length -4 -SET @@global.max_sort_length = 5; +8 +SET @@global.max_sort_length = 9; SELECT @@global.max_sort_length; @@global.max_sort_length -5 +9 SET @@global.max_sort_length = 8388608; SELECT @@global.max_sort_length; @@global.max_sort_length @@ -48,14 +48,14 @@ SELECT @@global.max_sort_length; @@global.max_sort_length 65536 '#--------------------FN_DYNVARS_084_04-------------------------#' -SET @@session.max_sort_length = 4; +SET @@session.max_sort_length = 8; SELECT @@session.max_sort_length; @@session.max_sort_length -4 -SET @@session.max_sort_length = 5; +8 +SET @@session.max_sort_length = 9; SELECT @@session.max_sort_length; @@session.max_sort_length -5 +9 SET @@session.max_sort_length = 8388608; SELECT @@session.max_sort_length; @@session.max_sort_length @@ -74,13 +74,13 @@ Warnings: Warning 1292 Truncated incorrect max_sort_length value: '-1024' SELECT @@global.max_sort_length; @@global.max_sort_length -4 +8 SET @@global.max_sort_length = 3; Warnings: Warning 1292 Truncated incorrect max_sort_length value: '3' SELECT @@global.max_sort_length; @@global.max_sort_length -4 +8 SET @@global.max_sort_length = 8388609; Warnings: Warning 1292 Truncated incorrect max_sort_length value: '8388609' @@ -92,17 +92,17 @@ Warnings: Warning 1292 Truncated incorrect max_sort_length value: '0' SELECT @@global.max_sort_length; @@global.max_sort_length -4 +8 SET @@global.max_sort_length = 65530.34; ERROR 42000: Incorrect argument type to variable 'max_sort_length' SELECT @@global.max_sort_length; @@global.max_sort_length -4 +8 SET @@global.max_sort_length = test; ERROR 42000: Incorrect argument type to variable 'max_sort_length' SELECT @@global.max_sort_length; @@global.max_sort_length -4 +8 SET @@session.max_sort_length = 8388610; Warnings: Warning 1292 Truncated incorrect max_sort_length value: '8388610' @@ -114,19 +114,19 @@ Warnings: Warning 1292 Truncated incorrect max_sort_length value: '-1' SELECT @@session.max_sort_length; @@session.max_sort_length -4 +8 SET @@session.max_sort_length = 3; Warnings: Warning 1292 Truncated incorrect max_sort_length value: '3' SELECT @@session.max_sort_length; @@session.max_sort_length -4 +8 SET @@session.max_sort_length = 0; Warnings: Warning 1292 Truncated incorrect max_sort_length value: '0' SELECT @@session.max_sort_length; @@session.max_sort_length -4 +8 SET @@session.max_sort_length = 65530.34; ERROR 42000: Incorrect argument type to variable 'max_sort_length' SET @@session.max_sort_length = 10737418241; @@ -158,13 +158,13 @@ Warnings: Warning 1292 Truncated incorrect max_sort_length value: '1' SELECT @@global.max_sort_length; @@global.max_sort_length -4 +8 SET @@global.max_sort_length = FALSE; Warnings: Warning 1292 Truncated incorrect max_sort_length value: '0' SELECT @@global.max_sort_length; @@global.max_sort_length -4 +8 '#---------------------FN_DYNVARS_084_09----------------------#' SET @@global.max_sort_length = 2048; SELECT @@max_sort_length = @@global.max_sort_length; diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index 9ca6995d7ef..865b5a8ca2f 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -2033,7 +2033,7 @@ DEFAULT_VALUE 1024 VARIABLE_SCOPE SESSION VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_COMMENT The number of bytes to use when sorting BLOB or TEXT values (only the first max_sort_length bytes of each value are used; the rest are ignored) -NUMERIC_MIN_VALUE 4 +NUMERIC_MIN_VALUE 8 NUMERIC_MAX_VALUE 8388608 NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 9288912eb57..21f1f905de8 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -2229,7 +2229,7 @@ DEFAULT_VALUE 1024 VARIABLE_SCOPE SESSION VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_COMMENT The number of bytes to use when sorting BLOB or TEXT values (only the first max_sort_length bytes of each value are used; the rest are ignored) -NUMERIC_MIN_VALUE 4 +NUMERIC_MIN_VALUE 8 NUMERIC_MAX_VALUE 8388608 NUMERIC_BLOCK_SIZE 1 ENUM_VALUE_LIST NULL diff --git a/mysql-test/suite/sys_vars/t/max_sort_length_basic.test b/mysql-test/suite/sys_vars/t/max_sort_length_basic.test index 9c3b88d3c3c..fcd6db017f1 100644 --- a/mysql-test/suite/sys_vars/t/max_sort_length_basic.test +++ b/mysql-test/suite/sys_vars/t/max_sort_length_basic.test @@ -74,9 +74,9 @@ SELECT @@session.max_sort_length = 1024; # Change the value of max_sort_length to a valid value for GLOBAL Scope # ######################################################################### -SET @@global.max_sort_length = 4; +SET @@global.max_sort_length = 8; SELECT @@global.max_sort_length; -SET @@global.max_sort_length = 5; +SET @@global.max_sort_length = 9; SELECT @@global.max_sort_length; SET @@global.max_sort_length = 8388608; SELECT @@global.max_sort_length; @@ -90,10 +90,10 @@ SELECT @@global.max_sort_length; # Change the value of max_sort_length to a valid value for SESSION Scope # ########################################################################## -SET @@session.max_sort_length = 4; +SET @@session.max_sort_length = 8; SELECT @@session.max_sort_length; -SET @@session.max_sort_length = 5; +SET @@session.max_sort_length = 9; SELECT @@session.max_sort_length; SET @@session.max_sort_length = 8388608; diff --git a/mysql-test/t/ctype_utf16.test b/mysql-test/t/ctype_utf16.test index 1febe3d8aea..28c31d639aa 100644 --- a/mysql-test/t/ctype_utf16.test +++ b/mysql-test/t/ctype_utf16.test @@ -721,7 +721,7 @@ CREATE TABLE t1 AS SELECT repeat('a',2) as s1 LIMIT 0; SHOW CREATE TABLE t1; INSERT INTO t1 VALUES ('ab'),('AE'),('ab'),('AE'); SELECT * FROM t1 ORDER BY s1; -SET max_sort_length=4; +SET max_sort_length=8; SELECT * FROM t1 ORDER BY s1; DROP TABLE t1; SET max_sort_length=DEFAULT; diff --git a/mysql-test/t/ctype_utf16le.test b/mysql-test/t/ctype_utf16le.test index 5e29408cbd0..2a8aaeafe59 100644 --- a/mysql-test/t/ctype_utf16le.test +++ b/mysql-test/t/ctype_utf16le.test @@ -683,7 +683,7 @@ CREATE TABLE t1 AS SELECT REPEAT('a',2) as s1 LIMIT 0; SHOW CREATE TABLE t1; INSERT INTO t1 VALUES ('ab'),('AE'),('ab'),('AE'); SELECT * FROM t1 ORDER BY s1; -SET max_sort_length=4; +SET max_sort_length=8; SELECT * FROM t1 ORDER BY s1; DROP TABLE t1; SET max_sort_length=DEFAULT; diff --git a/mysql-test/t/ctype_utf32.test b/mysql-test/t/ctype_utf32.test index bf822291a21..c7835e3c74f 100644 --- a/mysql-test/t/ctype_utf32.test +++ b/mysql-test/t/ctype_utf32.test @@ -778,7 +778,7 @@ CREATE TABLE t1 AS SELECT repeat('a',2) as s1 LIMIT 0; SHOW CREATE TABLE t1; INSERT INTO t1 VALUES ('ab'),('AE'),('ab'),('AE'); SELECT * FROM t1 ORDER BY s1; -SET max_sort_length=4; +SET max_sort_length=8; SELECT * FROM t1 ORDER BY s1; DROP TABLE t1; SET max_sort_length=DEFAULT; diff --git a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test index 51b6d63ee2f..7abcc693926 100644 --- a/mysql-test/t/ctype_utf8.test +++ b/mysql-test/t/ctype_utf8.test @@ -1756,7 +1756,7 @@ set @@collation_connection=utf8_bin; --echo # --echo # Checking strnxfrm() with odd length --echo # -set max_sort_length=5; +set max_sort_length=9; select @@max_sort_length; create table t1 (a varchar(128) character set utf8 collate utf8_general_ci); insert into t1 values ('a'),('b'),('c'); diff --git a/mysql-test/t/ctype_utf8mb4.test b/mysql-test/t/ctype_utf8mb4.test index ffc098ff938..91256d6e096 100644 --- a/mysql-test/t/ctype_utf8mb4.test +++ b/mysql-test/t/ctype_utf8mb4.test @@ -1511,7 +1511,7 @@ drop table t1; --echo # --echo # Check strnxfrm() with odd length --echo # -set max_sort_length=5; +set max_sort_length=9; select @@max_sort_length; create table t1 (a varchar(128) character set utf8mb4 collate utf8mb4_general_ci); insert into t1 values ('a'),('b'),('c'); diff --git a/mysql-test/t/order_by.test b/mysql-test/t/order_by.test index 999c7314139..2fbacb10b68 100644 --- a/mysql-test/t/order_by.test +++ b/mysql-test/t/order_by.test @@ -12,6 +12,8 @@ call mtr.add_suppression("Out of sort memory; increase server sort buffer size") # Test old ORDER BY bug # +--source include/have_sequence.inc + CREATE TABLE t1 ( id int(6) DEFAULT '0' NOT NULL, idservice int(5), @@ -2157,3 +2159,18 @@ select * from t1 order by b; set @@sort_buffer_size= @save_sort_buffer_size; drop table t1; +--echo # +--echo # MDEV-22715: SIGSEGV in radixsort_for_str_ptr and in native_compare/my_qsort2 (optimized builds) +--echo # + +SET @save_sort_buffer_size= @@sort_buffer_size; +SET @save_max_sort_length= @@max_sort_length; +SET max_sort_length=8; +SET sort_buffer_size=1024; +CREATE TABLE t1(a INT, b DECIMAL(65), c BLOB); +INSERT INTO t1 SELECT seq, seq, seq from seq_1_to_25; +INSERT INTO t1 SELECT seq, seq, seq from seq_1_to_25; +SELECT * FROM t1 ORDER BY a,b; +SET @@sort_buffer_size= @save_sort_buffer_size; +SET @@max_sort_length= @save_max_sort_length; +DROP TABLE t1; diff --git a/sql/field.cc b/sql/field.cc index 291e2134dcf..f65c6f88bb9 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -3295,10 +3295,9 @@ int Field_new_decimal::cmp(const uchar *a,const uchar*b) } -void Field_new_decimal::sort_string(uchar *buff, - uint length __attribute__((unused))) +void Field_new_decimal::sort_string(uchar *buff, uint length) { - memcpy(buff, ptr, bin_size); + memcpy(buff, ptr, length); } diff --git a/sql/field.h b/sql/field.h index 60849ea8099..5e8f39d903e 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1099,6 +1099,13 @@ public: void make_sort_key(uchar *buff, uint length); virtual void make_field(Send_field *); + + /* + Some implementations actually may write up to 8 bytes regardless of what + size was requested. This is due to the minimum value of the system variable + max_sort_length. + */ + virtual void sort_string(uchar *buff,uint length)=0; virtual bool optimize_range(uint idx, uint part); virtual void free() {} diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 9f87c846fd0..7dc1d1ab6e8 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2178,7 +2178,7 @@ static Sys_var_ulong Sys_max_sort_length( "the first max_sort_length bytes of each value are used; the rest " "are ignored)", SESSION_VAR(max_sort_length), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(4, 8192*1024L), DEFAULT(1024), BLOCK_SIZE(1)); + VALID_RANGE(8, 8192*1024L), DEFAULT(1024), BLOCK_SIZE(1)); static Sys_var_ulong Sys_max_sp_recursion_depth( "max_sp_recursion_depth", From a8c200c73c96d35b9e58fdcde0987f0ac5cb9b1a Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 5 Jun 2020 10:38:40 -0700 Subject: [PATCH 05/10] MDEV-22042 Server crash in Item_field::print on ANALYZE FORMAT=JSON When processing a query with a recursive CTE a temporary table is used for each recursive reference of the CTE. As any temporary table it uses its own mem-root for table definition structures. Due to specifics of the current implementation of ANALYZE stmt command this mem-root can be freed only at the very of query processing. Such deallocation of mem-root memory happens in close_thread_tables(). The function looks through the list of the tmp tables rec_tables attached to the THD of the query and frees corresponding mem-roots. If the query uses a stored function then such list is created for each query of the function. When a new rec_list has to be created the old one has to be saved and then restored at the proper moment. The bug occurred because only one rec_list for the query containing CTE was created. As a result close_thread_tables() freed tmp mem-roots used for rec_tables prematurely destroying some data needed for the output produced by the ANALYZE command. --- mysql-test/r/cte_recursive.result | 162 ++++++++++++++++++++++++++++++ mysql-test/t/cte_recursive.test | 39 +++++++ sql/sp_head.cc | 4 + 3 files changed, 205 insertions(+) diff --git a/mysql-test/r/cte_recursive.result b/mysql-test/r/cte_recursive.result index 667b8c4289d..0b8bc3fa8ab 100644 --- a/mysql-test/r/cte_recursive.result +++ b/mysql-test/r/cte_recursive.result @@ -3648,3 +3648,165 @@ select * from t1 as t; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t ALL NULL NULL NULL NULL 4 drop table t1,t2; +# +# MDEV-22042: ANALYZE of query using stored function and recursive CTE +# +create table t1 (a1 varchar(20),a2 varchar(20)) engine=myisam; +insert into t1 values (1,1),(2,2),(3,3); +create table t2 ( +a2 varchar(20) primary key, b1 varchar(20), key (b1) +) engine=myisam; +insert into t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7); +insert into t2 values (11,11),(12,12),(13,13),(14,14),(15,15),(16,16),(17,17); +create function f1(id varchar(20)) returns varchar(50) +begin +declare res varchar (50); +select a2 into res from t2 where a2=id and b1=1 limit 1; +return res; +end$$ +select fv +from (select t1.a1, f1(t1.a2) fv from t1) dt +where (dt.a1) in (with recursive cte as (select a2 from t2 where a2='2' + union select tt2.a2 from t2 tt2 join cte on tt2.b1=cte.a2) +select a2 from cte); +fv +NULL +explain select fv +from (select t1.a1, f1(t1.a2) fv from t1) dt +where (dt.a1) in (with recursive cte as (select a2 from t2 where a2='2' + union select tt2.a2 from t2 tt2 join cte on tt2.b1=cte.a2) +select a2 from cte); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY ALL distinct_key NULL NULL NULL 2 +1 PRIMARY t1 ALL NULL NULL NULL NULL 3 Using where; Using join buffer (flat, BNL join) +3 MATERIALIZED ALL NULL NULL NULL NULL 2 +4 DERIVED t2 const PRIMARY PRIMARY 22 const 1 Using index +5 RECURSIVE UNION ALL NULL NULL NULL NULL 2 +5 RECURSIVE UNION tt2 ref b1 b1 23 cte.a2 2 +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +analyze format=json select fv +from (select t1.a1, f1(t1.a2) fv from t1) dt +where (dt.a1) in (with recursive cte as (select a2 from t2 where a2='2' + union select tt2.a2 from t2 tt2 join cte on tt2.b1=cte.a2) +select a2 from cte); +ANALYZE +{ + "query_block": { + "select_id": 1, + "r_loops": 1, + "r_total_time_ms": "REPLACED", + "table": { + "table_name": "", + "access_type": "ALL", + "possible_keys": ["distinct_key"], + "r_loops": 1, + "rows": 2, + "r_rows": 1, + "r_total_time_ms": "REPLACED", + "filtered": 100, + "r_filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 3, + "table": { + "table_name": "", + "access_type": "ALL", + "r_loops": 1, + "rows": 2, + "r_rows": 1, + "r_total_time_ms": "REPLACED", + "filtered": 100, + "r_filtered": 100, + "materialized": { + "query_block": { + "recursive_union": { + "table_name": "", + "access_type": "ALL", + "r_loops": 0, + "r_rows": null, + "query_specifications": [ + { + "query_block": { + "select_id": 4, + "r_loops": 1, + "r_total_time_ms": "REPLACED", + "table": { + "table_name": "t2", + "access_type": "const", + "possible_keys": ["PRIMARY"], + "key": "PRIMARY", + "key_length": "22", + "used_key_parts": ["a2"], + "ref": ["const"], + "r_loops": 0, + "rows": 1, + "r_rows": null, + "filtered": 100, + "r_filtered": null, + "using_index": true + } + } + }, + { + "query_block": { + "select_id": 5, + "r_loops": 1, + "r_total_time_ms": "REPLACED", + "table": { + "table_name": "", + "access_type": "ALL", + "r_loops": 1, + "rows": 2, + "r_rows": 1, + "r_total_time_ms": "REPLACED", + "filtered": 100, + "r_filtered": 100 + }, + "table": { + "table_name": "tt2", + "access_type": "ref", + "possible_keys": ["b1"], + "key": "b1", + "key_length": "23", + "used_key_parts": ["b1"], + "ref": ["cte.a2"], + "r_loops": 1, + "rows": 2, + "r_rows": 1, + "r_total_time_ms": "REPLACED", + "filtered": 100, + "r_filtered": 100 + } + } + } + ] + } + } + } + } + } + } + }, + "block-nl-join": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "r_loops": 1, + "rows": 3, + "r_rows": 3, + "r_total_time_ms": "REPLACED", + "filtered": 100, + "r_filtered": 100 + }, + "buffer_type": "flat", + "buffer_size": "256Kb", + "join_type": "BNL", + "attached_condition": "t1.a1 = cte.a2", + "r_filtered": 33.333 + } + } +} +drop function f1; +drop table t1,t2; +End of 10.2 tests diff --git a/mysql-test/t/cte_recursive.test b/mysql-test/t/cte_recursive.test index 2c20e095130..1c0280f065e 100644 --- a/mysql-test/t/cte_recursive.test +++ b/mysql-test/t/cte_recursive.test @@ -2536,3 +2536,42 @@ with recursive cte as select * from t1 as t; drop table t1,t2; + +--echo # +--echo # MDEV-22042: ANALYZE of query using stored function and recursive CTE +--echo # + +create table t1 (a1 varchar(20),a2 varchar(20)) engine=myisam; +insert into t1 values (1,1),(2,2),(3,3); + +create table t2 ( +a2 varchar(20) primary key, b1 varchar(20), key (b1) +) engine=myisam; +insert into t2 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7); +insert into t2 values (11,11),(12,12),(13,13),(14,14),(15,15),(16,16),(17,17); + +delimiter $$; +create function f1(id varchar(20)) returns varchar(50) +begin + declare res varchar (50); + select a2 into res from t2 where a2=id and b1=1 limit 1; + return res; +end$$ +delimiter ;$$ + +let q= +select fv +from (select t1.a1, f1(t1.a2) fv from t1) dt +where (dt.a1) in (with recursive cte as (select a2 from t2 where a2='2' + union select tt2.a2 from t2 tt2 join cte on tt2.b1=cte.a2) +select a2 from cte); + +eval $q; +eval explain $q; +--source include/analyze-format.inc +eval analyze format=json $q; + +drop function f1; +drop table t1,t2; + +--echo End of 10.2 tests diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 464f2df1506..6a650183fb8 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1126,6 +1126,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) backup_arena; query_id_t old_query_id; TABLE *old_derived_tables; + TABLE *old_rec_tables; LEX *old_lex; Item_change_list old_change_list; String old_packet; @@ -1201,6 +1202,8 @@ sp_head::execute(THD *thd, bool merge_da_on_success) old_query_id= thd->query_id; old_derived_tables= thd->derived_tables; thd->derived_tables= 0; + old_rec_tables= thd->rec_tables; + thd->rec_tables= 0; save_sql_mode= thd->variables.sql_mode; thd->variables.sql_mode= m_sql_mode; save_abort_on_warning= thd->abort_on_warning; @@ -1468,6 +1471,7 @@ sp_head::execute(THD *thd, bool merge_da_on_success) thd->set_query_id(old_query_id); DBUG_ASSERT(!thd->derived_tables); thd->derived_tables= old_derived_tables; + thd->rec_tables= old_rec_tables; thd->variables.sql_mode= save_sql_mode; thd->abort_on_warning= save_abort_on_warning; thd->m_reprepare_observer= save_reprepare_observer; From 7a695d8a82eaaa7db0cf4484b22fc3db3d43ac49 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Fri, 5 Jun 2020 23:33:24 +0300 Subject: [PATCH 06/10] fix compilation with VS2019, preview of 16.7 version Compiler tells something about argument-dependent lookup. I do not understand how that ADL works. But I know that such operators should be free functions, instead of methods: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ro-symmetric Such syntax defines 'friend' free functions. --- include/ilist.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/ilist.h b/include/ilist.h index 5d0a425a9cc..722677f9057 100644 --- a/include/ilist.h +++ b/include/ilist.h @@ -99,8 +99,14 @@ public: reference operator*() { return *static_cast(node_); } pointer operator->() { return static_cast(node_); } - bool operator==(const Iterator &rhs) { return node_ == rhs.node_; } - bool operator!=(const Iterator &rhs) { return !(*this == rhs); } + friend bool operator==(const Iterator &lhs, const Iterator &rhs) + { + return lhs.node_ == rhs.node_; + } + friend bool operator!=(const Iterator &lhs, const Iterator &rhs) + { + return !(lhs == rhs); + } private: ListNode *node_; From 1bd5b75c733840813ea1fe18c5908422a707e677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sat, 6 Jun 2020 09:32:18 +0300 Subject: [PATCH 07/10] MDEV-22818 Server crash on corrupted ROW_FORMAT=COMPRESSED page page_zip_fields_decode(): Do not dereference index=NULL. Instead, return NULL early. The only caller does not care about the values of output parameters in that case. This bug was introduced in MySQL 5.7.6 by mysql/mysql-server@9eae0edb7a8e4004328e61157f5f3b39cebe1b2b and in MariaDB 10.2.2 by commit 2e814d4702d71a04388386a9f591d14a35980bfe. Thanks to my son for pointing this out after investigating the output of a static analysis tool. --- storage/innobase/page/page0zip.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/innobase/page/page0zip.cc b/storage/innobase/page/page0zip.cc index ee82fdbd7cd..b507945f076 100644 --- a/storage/innobase/page/page0zip.cc +++ b/storage/innobase/page/page0zip.cc @@ -1756,8 +1756,9 @@ page_zip_fields_decode( if (!val) { val = ULINT_UNDEFINED; } else if (UNIV_UNLIKELY(val >= n)) { +fail: page_zip_fields_free(index); - index = NULL; + return NULL; } else { index->type = DICT_CLUSTERED; } @@ -1766,8 +1767,7 @@ page_zip_fields_decode( } else { /* Decode the number of nullable fields. */ if (UNIV_UNLIKELY(index->n_nullable > val)) { - page_zip_fields_free(index); - index = NULL; + goto fail; } else { index->n_nullable = unsigned(val); } From 187b9c924ebaff8f02fb4e2139a01fd1512e3dc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sat, 6 Jun 2020 18:07:13 +0300 Subject: [PATCH 08/10] MDEV-22817: Add a test case --- mysql-test/suite/parts/r/longname.result | 34 ++++++++++++++++++++++++ mysql-test/suite/parts/t/longname.test | 24 +++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/mysql-test/suite/parts/r/longname.result b/mysql-test/suite/parts/r/longname.result index 2d2802d8b38..2ca0871bc8d 100644 --- a/mysql-test/suite/parts/r/longname.result +++ b/mysql-test/suite/parts/r/longname.result @@ -25,4 +25,38 @@ SUBPARTITIONS 2 ( PARTITION çççççççççççççççççççççççççççççççççççççççççççççççççççççççççççç VALUES LESS THAN (1000) ENGINE = InnoDB, PARTITION pmax VALUES LESS THAN MAXVALUE ENGINE = InnoDB); ERROR HY000: The path specified for @0n@0n@0n@0n@0n@0n@0n@0n@0n@0n@0n@0n@0n@0n@0n@0n@0n@0n@0n@0n@... is too long +SET @file_per_table=@@GLOBAL.innodb_file_per_table; +SET GLOBAL innodb_file_per_table=0; +CREATE TABLE mysqltest1.t1 (a INT) ENGINE=INNODB +PARTITION BY RANGE (a) SUBPARTITION BY HASH(a) +(PARTITION `$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$` + VALUES LESS THAN (10) +(SUBPARTITION +`--------------------------abcdef0123456789abcdef0123456789abcdef`, +SUBPARTITION +`0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef`) +); +SET GLOBAL innodb_file_per_table=@file_per_table; +SHOW CREATE TABLE mysqltest1.t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 + PARTITION BY RANGE (`a`) +SUBPARTITION BY HASH (`a`) +(PARTITION `$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$` VALUES LESS THAN (10) + (SUBPARTITION `--------------------------abcdef0123456789abcdef0123456789abcdef` ENGINE = InnoDB, + SUBPARTITION `0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef` ENGINE = InnoDB)) +INSERT INTO mysqltest1.t1 VALUES(1); +DROP TABLE mysqltest1.`#mysql50#t1#P#@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024#SP#0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef`; +ERROR 42000: Incorrect table name '#mysql50#t1#P#@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@' +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES +WHERE NAME LIKE 'mysqltest1%'; +NAME +mysqltest1/t1#P#@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024#SP#0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef +mysqltest1/t1#P#@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024#SP#@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002d@002dabcdef0123456789abcdef0123456789abcdef +mysqltest1/test_jfg_table_name_with_64_chars_123456789012345678901234567890#P#pmax#SP#pmaxsp0 +mysqltest1/test_jfg_table_name_with_64_chars_123456789012345678901234567890#P#pmax#SP#pmaxsp1 +mysqltest1/test_jfg_table_name_with_64_chars_123456789012345678901234567890#P#test_jfg_partition_name_with_60_chars_1234567890123456789012#SP#test_jfg_partition_name_with_60_chars_1234567890123456789012sp0 +mysqltest1/test_jfg_table_name_with_64_chars_123456789012345678901234567890#P#test_jfg_partition_name_with_60_chars_1234567890123456789012#SP#test_jfg_partition_name_with_60_chars_1234567890123456789012sp1 drop database mysqltest1; diff --git a/mysql-test/suite/parts/t/longname.test b/mysql-test/suite/parts/t/longname.test index 0f7378ef8e3..b680c3a4ef2 100644 --- a/mysql-test/suite/parts/t/longname.test +++ b/mysql-test/suite/parts/t/longname.test @@ -29,4 +29,28 @@ PARTITION BY RANGE ( id ) PARTITION çççççççççççççççççççççççççççççççççççççççççççççççççççççççççççç VALUES LESS THAN (1000) ENGINE = InnoDB, PARTITION pmax VALUES LESS THAN MAXVALUE ENGINE = InnoDB); +SET @file_per_table=@@GLOBAL.innodb_file_per_table; +SET GLOBAL innodb_file_per_table=0; + +CREATE TABLE mysqltest1.t1 (a INT) ENGINE=INNODB +PARTITION BY RANGE (a) SUBPARTITION BY HASH(a) +(PARTITION `$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$` + VALUES LESS THAN (10) + (SUBPARTITION + `--------------------------abcdef0123456789abcdef0123456789abcdef`, + SUBPARTITION + `0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef`) +); + +SET GLOBAL innodb_file_per_table=@file_per_table; + +SHOW CREATE TABLE mysqltest1.t1; +INSERT INTO mysqltest1.t1 VALUES(1); + +--error ER_WRONG_TABLE_NAME +DROP TABLE mysqltest1.`#mysql50#t1#P#@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024@0024#SP#0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef`; + +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES +WHERE NAME LIKE 'mysqltest1%'; + drop database mysqltest1; From e14ffd85d09a62d098d3db9597fd34bf3d4c4fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sat, 6 Jun 2020 17:36:25 +0300 Subject: [PATCH 09/10] MDEV-22721 fixup for 32-bit GCC lock_check_trx_id_sanity(): Because the argument of UNIV_LIKELY or __builtin_expect() can be less than sizeof(trx_id_t) on 32-bit systems, it cannot reliably perform an implicit comparison to 0. --- storage/innobase/lock/lock0lock.cc | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 858b381e788..1c7407a0c23 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -351,18 +351,18 @@ lock_check_trx_id_sanity( dict_index_t* index, /*!< in: index */ const rec_offs* offsets) /*!< in: rec_get_offsets(rec, index) */ { - ut_ad(rec_offs_validate(rec, index, offsets)); - ut_ad(!rec_is_metadata(rec, index)); + ut_ad(rec_offs_validate(rec, index, offsets)); + ut_ad(!rec_is_metadata(rec, index)); - trx_id_t max_trx_id = trx_sys.get_max_trx_id(); - ut_ad(max_trx_id || srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN); + trx_id_t max_trx_id= trx_sys.get_max_trx_id(); + ut_ad(max_trx_id || srv_force_recovery >= SRV_FORCE_NO_UNDO_LOG_SCAN); - if (UNIV_LIKELY(max_trx_id) && UNIV_UNLIKELY(trx_id >= max_trx_id)) { - lock_report_trx_id_insanity( - trx_id, rec, index, offsets, max_trx_id); - return false; - } - return(true); + if (UNIV_LIKELY(max_trx_id != 0) && UNIV_UNLIKELY(trx_id >= max_trx_id)) + { + lock_report_trx_id_insanity(trx_id, rec, index, offsets, max_trx_id); + return false; + } + return true; } /*********************************************************************//** From be0c46eb9723dd8192e049123483812e6779dd97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Sat, 6 Jun 2020 21:34:21 +0300 Subject: [PATCH 10/10] MDEV-22817: Skip the test in --embedded --- mysql-test/suite/parts/t/longname.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/suite/parts/t/longname.test b/mysql-test/suite/parts/t/longname.test index b680c3a4ef2..0fe45d0d5ff 100644 --- a/mysql-test/suite/parts/t/longname.test +++ b/mysql-test/suite/parts/t/longname.test @@ -1,5 +1,7 @@ source include/have_innodb.inc; source include/have_partition.inc; +# The absolute path names in the embedded server hit the limit earlier. +source include/not_embedded.inc; set names utf8; create database mysqltest1;