diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-01-11 17:32:08 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-01-11 17:32:08 +0200 |
commit | 666565c7f00b0f39bbb459a428efd0093ed05fc8 (patch) | |
tree | d9b7dc26979995f0a332c50d2daf043c2a75866e | |
parent | 92abdcca5a5324f0727112ab2417d10c7a8d5094 (diff) | |
parent | 8de233af815f28d096ac4ff136525abc3ddc771d (diff) | |
download | mariadb-git-666565c7f00b0f39bbb459a428efd0093ed05fc8.tar.gz |
Merge 10.5 into 10.6
72 files changed, 1597 insertions, 327 deletions
diff --git a/cmake/install_macros.cmake b/cmake/install_macros.cmake index 83c57bcf89a..97023bbfac1 100644 --- a/cmake/install_macros.cmake +++ b/cmake/install_macros.cmake @@ -180,7 +180,7 @@ IF(WIN32) MARK_AS_ADVANCED(SIGNCODE) IF(SIGNCODE) SET(SIGNTOOL_PARAMETERS - /a /t http://timestamp.verisign.com/scripts/timstamp.dll + /a /t http://timestamp.globalsign.com/scripts/timstamp.dll CACHE STRING "parameters for signtool (list)") FIND_PROGRAM(SIGNTOOL_EXECUTABLE signtool PATHS "$ENV{ProgramFiles}/Microsoft SDKs/Windows/v7.0A/bin" diff --git a/mysql-test/main/cte_recursive.result b/mysql-test/main/cte_recursive.result index decb1b47f13..dedef068129 100644 --- a/mysql-test/main/cte_recursive.result +++ b/mysql-test/main/cte_recursive.result @@ -1301,7 +1301,7 @@ select ancestors.name, ancestors.dob from ancestors; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY <derived4> ALL NULL NULL NULL NULL 24 4 DERIVED folks ALL NULL NULL NULL NULL 12 Using where -6 RECURSIVE UNION <derived3> ALL NULL NULL NULL NULL 12 +6 UNION <derived3> ALL NULL NULL NULL NULL 12 5 RECURSIVE UNION <derived4> ALL NULL NULL NULL NULL 24 NULL UNION RESULT <union4,6,5> ALL NULL NULL NULL NULL NULL 3 DERIVED folks ALL NULL NULL NULL NULL 12 Using where @@ -4019,7 +4019,7 @@ id select_type table type possible_keys key key_len ref rows Extra 3 RECURSIVE UNION t1 ALL NULL NULL NULL NULL 4 Using where 3 RECURSIVE UNION <derived2> ref key0 key0 9 test.t1.c 2 NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL -4 RECURSIVE UNION <derived2> ALL NULL NULL NULL NULL 4 +4 UNION <derived2> ALL NULL NULL NULL NULL 4 with recursive r_cte as ( select * from t1 as s union diff --git a/mysql-test/suite/galera/r/galera#500.result b/mysql-test/suite/galera/r/galera#500.result index d983e844d76..a5ab0b19718 100644 --- a/mysql-test/suite/galera/r/galera#500.result +++ b/mysql-test/suite/galera/r/galera#500.result @@ -1,5 +1,3 @@ -connection node_1; -connection node_2; connection node_2; connection node_1; connection node_1; diff --git a/mysql-test/suite/galera/r/galera_as_slave_replay.result b/mysql-test/suite/galera/r/galera_as_slave_replay.result index 760617be5f7..3c2cea19179 100644 --- a/mysql-test/suite/galera/r/galera_as_slave_replay.result +++ b/mysql-test/suite/galera/r/galera_as_slave_replay.result @@ -1,10 +1,13 @@ connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; connection node_2a; +connection node_2; connection node_1; +connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3; +connection node_3; RESET MASTER; connection node_2a; START SLAVE; -connection node_1; +connection node_3; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)) engine=innodb; INSERT INTO t1 VALUES (1, 'a'); INSERT INTO t1 VALUES (3, 'a'); @@ -18,15 +21,14 @@ f1 f2 UPDATE t1 SET f2 = 'c' WHERE f1 > 1; connection node_2a; SET SESSION wsrep_sync_wait = 0; -connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3; -connection node_3; +connection node_1; SET SESSION wsrep_sync_wait = 0; connection node_2a; -SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_enter_sync'; +SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_master_enter_sync'; SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb"; -connection node_3; -INSERT INTO test.t1 VALUES (2, 'b'); connection node_1; +INSERT INTO test.t1 VALUES (2, 'b'); +connection node_3; COMMIT; connection node_2a; SET SESSION wsrep_on = 0; @@ -35,8 +37,8 @@ SET GLOBAL debug_dbug = ""; SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb"; connection node_2a; SET GLOBAL wsrep_provider_options = 'dbug='; -SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_enter_sync'; -connection node_1; +SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync'; +connection node_3; SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'a'; COUNT(*) = 1 1 @@ -61,7 +63,7 @@ SET DEBUG_SYNC = "RESET"; # # test phase with real abort # -connection node_1; +connection node_3; set binlog_format=ROW; insert into t1 values (4, 'd'); SET AUTOCOMMIT=ON; @@ -70,9 +72,9 @@ UPDATE t1 SET f2 = 'd' WHERE f1 = 3; connection node_2a; SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_enter_sync'; SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb"; -connection node_3; -UPDATE test.t1 SET f2 = 'e' WHERE f1 = 3; connection node_1; +UPDATE test.t1 SET f2 = 'e' WHERE f1 = 3; +connection node_3; COMMIT; connection node_2a; SET GLOBAL debug_dbug = ""; @@ -90,6 +92,6 @@ set session wsrep_sync_wait=0; STOP SLAVE; RESET SLAVE; DROP TABLE t1; -connection node_1; +connection node_3; DROP TABLE t1; RESET MASTER; diff --git a/mysql-test/suite/galera/r/galera_bf_abort_ps.result b/mysql-test/suite/galera/r/galera_bf_abort_ps.result new file mode 100644 index 00000000000..42292cb20a0 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_bf_abort_ps.result @@ -0,0 +1,16 @@ +connection node_2; +connection node_1; +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(6)) ENGINE=InnoDB; +connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; +connection node_2; +START TRANSACTION; +INSERT INTO t1 VALUES (1,'node_2'); +connection node_1; +INSERT INTO t1 VALUES (1,'node_1'); +connection node_2a; +connection node_2; +INSERT INTO t1 VALUES (2, 'node_2'); +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +wsrep_local_aborts_increment +1 +DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_bf_abort_ps_threadpool.result b/mysql-test/suite/galera/r/galera_bf_abort_ps_threadpool.result new file mode 100644 index 00000000000..7482e76778e --- /dev/null +++ b/mysql-test/suite/galera/r/galera_bf_abort_ps_threadpool.result @@ -0,0 +1,22 @@ +connection node_2; +connection node_1; +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(6)) ENGINE=InnoDB; +connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; +connection node_2; +START TRANSACTION; +INSERT INTO t1 VALUES (1,'node_2'); +connection node_2a; +SET GLOBAL debug_dbug = "+d,sync.wsrep_apply_cb"; +connection node_1; +INSERT INTO t1 VALUES (1,'node_1'); +connection node_2a; +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached"; +connection node_2; +SET DEBUG_SYNC = "wsrep_before_before_command SIGNAL signal.wsrep_apply_cb WAIT_FOR bf_abort"; +INSERT INTO t1 VALUES (2, 'node_2'); +ERROR 40001: Deadlock found when trying to get lock; try restarting transaction +wsrep_local_aborts_increment +1 +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL debug_dbug = DEFAULT; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/MDEV-16509.test b/mysql-test/suite/galera/t/MDEV-16509.test index eecc0e5e4e6..c0a8988aecc 100644 --- a/mysql-test/suite/galera/t/MDEV-16509.test +++ b/mysql-test/suite/galera/t/MDEV-16509.test @@ -5,6 +5,7 @@ --source include/galera_cluster.inc --source include/have_debug.inc --source include/have_debug_sync.inc +--source include/galera_have_debug_sync.inc CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB; diff --git a/mysql-test/suite/galera/t/galera_as_slave_replay.test b/mysql-test/suite/galera/t/galera_as_slave_replay.test index 93f95349e6d..47f70bda721 100644 --- a/mysql-test/suite/galera/t/galera_as_slave_replay.test +++ b/mysql-test/suite/galera/t/galera_as_slave_replay.test @@ -18,9 +18,10 @@ #--source suite/galera/include/galera_have_debug_sync.inc # -# node 1 is native MariaDB server operating as async replication master +# node 3 is native MariaDB server operating as async replication master # ---connection node_1 +--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3 +--connection node_3 RESET MASTER; --connection node_2a @@ -31,14 +32,14 @@ RESET MASTER; # -# nodes 2 and 3 form a galera cluster, node 2 operates as slave for native MariaDB naster in node 1 +# nodes 1 and 2 form a galera cluster, node 2 operates as slave for native MariaDB naster in node 3 # --disable_query_log ---eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_1; +--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_USER='root', MASTER_PORT=$NODE_MYPORT_3; --enable_query_log START SLAVE; ---connection node_1 +--connection node_3 CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)) engine=innodb; INSERT INTO t1 VALUES (1, 'a'); INSERT INTO t1 VALUES (3, 'a'); @@ -63,15 +64,14 @@ SET SESSION wsrep_sync_wait = 0; --source include/wait_condition.inc # wait for create table and inserts to be replicated in cluster ---connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3 ---connection node_3 +--connection node_1 SET SESSION wsrep_sync_wait = 0; --let $wait_condition = SELECT COUNT(*) = 2 FROM test.t1; --source include/wait_condition.inc --connection node_2a # Block the future commit of async replication ---let $galera_sync_point = commit_monitor_enter_sync +--let $galera_sync_point = commit_monitor_master_enter_sync --source include/galera_set_sync_point.inc # block also the applier before applying begins @@ -81,13 +81,13 @@ SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb"; # now inject a conflicting insert from node 3, it will replicate with # earlier seqno (than async transaction) and pause before applying in node 2 # ---connection node_3 +--connection node_1 INSERT INTO test.t1 VALUES (2, 'b'); # # send the update from master, this will succeed here, beceuase of async replication. # async replication will apply this in node 2 and pause before commit phase, ---connection node_1 +--connection node_3 --error 0 COMMIT; @@ -108,7 +108,7 @@ SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb"; --source include/galera_clear_sync_point.inc --source include/galera_signal_sync_point.inc ---connection node_1 +--connection node_3 SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'a'; SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c'; @@ -139,7 +139,7 @@ SET DEBUG_SYNC = "RESET"; --echo # test phase with real abort --echo # ---connection node_1 +--connection node_3 set binlog_format=ROW; @@ -163,11 +163,11 @@ UPDATE t1 SET f2 = 'd' WHERE f1 = 3; SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb"; # Inject a conflicting update from node 3 ---connection node_3 +--connection node_1 UPDATE test.t1 SET f2 = 'e' WHERE f1 = 3; # send the update from master ---connection node_1 +--connection node_3 --error 0 COMMIT; @@ -195,6 +195,6 @@ RESET SLAVE; DROP TABLE t1; ---connection node_1 +--connection node_3 DROP TABLE t1; RESET MASTER; diff --git a/mysql-test/suite/galera/t/galera_bf_abort_ps.cnf b/mysql-test/suite/galera/t/galera_bf_abort_ps.cnf new file mode 100644 index 00000000000..34c1a8cc3cf --- /dev/null +++ b/mysql-test/suite/galera/t/galera_bf_abort_ps.cnf @@ -0,0 +1,3 @@ +!include ../galera_2nodes.cnf +[mysqltest] +ps-protocol
\ No newline at end of file diff --git a/mysql-test/suite/galera/t/galera_bf_abort_ps.test b/mysql-test/suite/galera/t/galera_bf_abort_ps.test new file mode 100644 index 00000000000..d2dfb92651e --- /dev/null +++ b/mysql-test/suite/galera/t/galera_bf_abort_ps.test @@ -0,0 +1,34 @@ +# +# MDEV-24255 +# Test BF abort of a transaction that has ps-protocol enabled +# + +--source include/galera_cluster.inc + +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(6)) ENGINE=InnoDB; +--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 + +--connection node_2 +--let $wsrep_local_bf_aborts_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` + +START TRANSACTION; +INSERT INTO t1 VALUES (1,'node_2'); + +--connection node_1 +INSERT INTO t1 VALUES (1,'node_1'); + +--connection node_2a +--let $wait_condition = SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'node_1' +--source include/wait_condition.inc + +--connection node_2 +--error ER_LOCK_DEADLOCK +INSERT INTO t1 VALUES (2, 'node_2'); + +--let $wsrep_local_bf_aborts_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` + +--disable_query_log +--eval SELECT $wsrep_local_bf_aborts_after - $wsrep_local_bf_aborts_before = 1 AS wsrep_local_aborts_increment; +--enable_query_log + +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_bf_abort_ps_threadpool.cnf b/mysql-test/suite/galera/t/galera_bf_abort_ps_threadpool.cnf new file mode 100644 index 00000000000..83baa995c17 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_bf_abort_ps_threadpool.cnf @@ -0,0 +1,7 @@ +!include ../galera_2nodes.cnf + +[mysqld] +thread-handling=pool-of-threads + +[mysqltest] +ps-protocol diff --git a/mysql-test/suite/galera/t/galera_bf_abort_ps_threadpool.test b/mysql-test/suite/galera/t/galera_bf_abort_ps_threadpool.test new file mode 100644 index 00000000000..56348a6f527 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_bf_abort_ps_threadpool.test @@ -0,0 +1,54 @@ +# +# MDEV-24255 +# Test BF abort of a transaction that has ps-protocol enabled +# This test stresses the case where wsrep_before_command() +# finds the transaction in state s_must_abort. This only +# possible when the server is using the thread pool. +# + +--source include/galera_cluster.inc +--source include/have_debug_sync.inc + +CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(6)) ENGINE=InnoDB; + +--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2 + +--connection node_2 +--let $wsrep_local_bf_aborts_before = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` + +START TRANSACTION; +INSERT INTO t1 VALUES (1,'node_2'); + +--connection node_2a +SET GLOBAL debug_dbug = "+d,sync.wsrep_apply_cb"; + +--connection node_1 +INSERT INTO t1 VALUES (1,'node_1'); + +--connection node_2a +SET DEBUG_SYNC = "now WAIT_FOR sync.wsrep_apply_cb_reached"; + +--connection node_2 +SET DEBUG_SYNC = "wsrep_before_before_command SIGNAL signal.wsrep_apply_cb WAIT_FOR bf_abort"; + +# +# The following INSERT is expected to enter +# wsrep_before_command() and find its transaction +# in state s_must_abort. +# Notice that the test appears more complicated +# than it needs to... however we cannot use +# --send for this INSERT, otherwise mysqltest +# will not use ps-protocol +# +--error ER_LOCK_DEADLOCK +INSERT INTO t1 VALUES (2, 'node_2'); + +--let $wsrep_local_bf_aborts_after = `SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_bf_aborts'` + +--disable_query_log +--eval SELECT $wsrep_local_bf_aborts_after - $wsrep_local_bf_aborts_before = 1 AS wsrep_local_aborts_increment; +--enable_query_log + +SET DEBUG_SYNC = 'RESET'; +SET GLOBAL debug_dbug = DEFAULT; +DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_rsu_error.test b/mysql-test/suite/galera/t/galera_rsu_error.test index cad8154ac76..6de7607b6ec 100644 --- a/mysql-test/suite/galera/t/galera_rsu_error.test +++ b/mysql-test/suite/galera/t/galera_rsu_error.test @@ -9,6 +9,9 @@ CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB; INSERT INTO t1 VALUES (1), (1); --connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t1'; +--source include/wait_condition.inc + SET SESSION wsrep_OSU_method = "RSU"; --error ER_DUP_ENTRY ALTER TABLE t1 ADD PRIMARY KEY (f1); diff --git a/mysql-test/suite/galera/t/galera_toi_ddl_sequential.test b/mysql-test/suite/galera/t/galera_toi_ddl_sequential.test index 51eae7005df..89a1af845c9 100644 --- a/mysql-test/suite/galera/t/galera_toi_ddl_sequential.test +++ b/mysql-test/suite/galera/t/galera_toi_ddl_sequential.test @@ -9,6 +9,9 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); --connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t1'; +--source include/wait_condition.inc + ALTER TABLE t1 ADD COLUMN f2 INTEGER; INSERT INTO t1 VALUES (2, 3); diff --git a/mysql-test/suite/galera/t/galera_toi_lock_shared.test b/mysql-test/suite/galera/t/galera_toi_lock_shared.test index 6857a0e08ca..6b7feec6031 100644 --- a/mysql-test/suite/galera/t/galera_toi_lock_shared.test +++ b/mysql-test/suite/galera/t/galera_toi_lock_shared.test @@ -10,6 +10,9 @@ CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); --connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t1'; +--source include/wait_condition.inc + ALTER TABLE t1 ADD COLUMN f2 INTEGER, LOCK=SHARED; --connection node_1 diff --git a/mysql-test/suite/galera/t/galera_truncate.test b/mysql-test/suite/galera/t/galera_truncate.test index 79f9bad1f1b..3c3ee56a23f 100644 --- a/mysql-test/suite/galera/t/galera_truncate.test +++ b/mysql-test/suite/galera/t/galera_truncate.test @@ -14,6 +14,9 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB; INSERT INTO t1 VALUES (1); --connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t1'; +--source include/wait_condition.inc + TRUNCATE TABLE t1; SELECT COUNT(*) = 0 FROM t1; diff --git a/mysql-test/suite/galera/t/galera_truncate_temporary.test b/mysql-test/suite/galera/t/galera_truncate_temporary.test index 3ad94eb9930..ea20911bd5d 100644 --- a/mysql-test/suite/galera/t/galera_truncate_temporary.test +++ b/mysql-test/suite/galera/t/galera_truncate_temporary.test @@ -67,6 +67,9 @@ CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB; INSERT INTO t1 VALUES (2); --connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t1'; +--source include/wait_condition.inc + TRUNCATE TABLE t1; SELECT COUNT(*) = 0 FROM t1; diff --git a/mysql-test/suite/galera_sr/t/GCF-900.test b/mysql-test/suite/galera_sr/t/GCF-900.test index 3f1b53630b6..b44423c5013 100644 --- a/mysql-test/suite/galera_sr/t/GCF-900.test +++ b/mysql-test/suite/galera_sr/t/GCF-900.test @@ -15,6 +15,9 @@ START TRANSACTION; INSERT INTO t1 VALUES (2, 0); --connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t1'; +--source include/wait_condition.inc + ALTER TABLE t1 DROP COLUMN f2; --connection node_1 diff --git a/mysql-test/suite/gcol/r/innodb_virtual_stats.result b/mysql-test/suite/gcol/r/innodb_virtual_stats.result index c0f595263df..c11b02ff8cb 100644 --- a/mysql-test/suite/gcol/r/innodb_virtual_stats.result +++ b/mysql-test/suite/gcol/r/innodb_virtual_stats.result @@ -121,19 +121,5 @@ SELECT index_name, stat_name, stat_description FROM mysql.innodb_index_stats WHERE database_name = 'test' AND table_name = 't'; index_name stat_name stat_description -GEN_CLUST_INDEX n_diff_pfx01 DB_ROW_ID -GEN_CLUST_INDEX n_leaf_pages Number of leaf pages in the index -GEN_CLUST_INDEX size Number of pages in the index -idxb n_diff_pfx01 b -idxb n_diff_pfx02 b,DB_ROW_ID -idxb n_leaf_pages Number of leaf pages in the index -idxb size Number of pages in the index -vidxe n_diff_pfx01 e -vidxe n_diff_pfx02 e,DB_ROW_ID -vidxe n_leaf_pages Number of leaf pages in the index -vidxe size Number of pages in the index -vidxf n_diff_pfx01 f -vidxf n_diff_pfx02 f,DB_ROW_ID -vidxf n_leaf_pages Number of leaf pages in the index -vidxf size Number of pages in the index +# MDEV-24564 FIXME: Do reload statistics after the above ALTER TABLE! DROP TABLE t; diff --git a/mysql-test/suite/gcol/t/innodb_virtual_stats.test b/mysql-test/suite/gcol/t/innodb_virtual_stats.test index 69c67af8ed1..728f84de72c 100644 --- a/mysql-test/suite/gcol/t/innodb_virtual_stats.test +++ b/mysql-test/suite/gcol/t/innodb_virtual_stats.test @@ -52,5 +52,6 @@ ALTER TABLE t DROP INDEX vidxcd; SELECT index_name, stat_name, stat_description FROM mysql.innodb_index_stats WHERE database_name = 'test' AND table_name = 't'; +-- echo # MDEV-24564 FIXME: Do reload statistics after the above ALTER TABLE! DROP TABLE t; diff --git a/mysql-test/suite/innodb/r/innodb-virtual-columns2.result b/mysql-test/suite/innodb/r/innodb-virtual-columns2.result index 3574ba72849..99a1c610bd3 100644 --- a/mysql-test/suite/innodb/r/innodb-virtual-columns2.result +++ b/mysql-test/suite/innodb/r/innodb-virtual-columns2.result @@ -62,3 +62,28 @@ INSERT INTO t1 (i) VALUES (1),(2); SELECT * FROM t1 WHERE y BETWEEN 2012 AND 2016 FOR UPDATE; y i b vi DROP TABLE t1; +# +# MDEV-23632 ALTER TABLE...ADD KEY creates corrupted index on virtual column +# +CREATE TABLE t1(a INT PRIMARY KEY, b INT, g INT GENERATED ALWAYS AS(b)VIRTUAL) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,1,default); +ALTER TABLE t1 ADD COLUMN c INT; +ALTER TABLE t1 ADD KEY(g); +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +SELECT g FROM t1 FORCE INDEX (g); +g +1 +DROP TABLE t1; +CREATE TABLE t1(a INT, b INT, g INT GENERATED ALWAYS AS(b)VIRTUAL) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,1,default); +ALTER TABLE t1 ADD COLUMN c INT PRIMARY KEY; +ALTER TABLE t1 ADD KEY(g); +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +SELECT g FROM t1 FORCE INDEX (g); +g +1 +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/r/instant_alter_debug.result b/mysql-test/suite/innodb/r/instant_alter_debug.result index 9053cbacec6..110ef5b64e1 100644 --- a/mysql-test/suite/innodb/r/instant_alter_debug.result +++ b/mysql-test/suite/innodb/r/instant_alter_debug.result @@ -327,7 +327,6 @@ FROM information_schema.global_status WHERE variable_name = 'innodb_instant_alter_column'; instants 22 -SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; # # MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col # @@ -371,6 +370,20 @@ SET DEBUG_SYNC='RESET'; disconnect con2; DROP TABLE t1; # +# MDEV-24512 Assertion failed in rec_is_metadata() +# in btr_discard_only_page_on_level() +# +SET @save_limit= @@GLOBAL.innodb_limit_optimistic_insert_debug; +SET GLOBAL innodb_limit_optimistic_insert_debug=2; +CREATE TABLE t1 (c CHAR(1) UNIQUE) ENGINE=InnoDB; +ALTER TABLE t1 ADD c2 INT NOT NULL DEFAULT 0 FIRST; +INSERT INTO t1 (c) VALUES ('x'),('d'),('r'),('f'),('y'),('u'),('m'),('d'); +ERROR 23000: Duplicate entry 'd' for key 'c' +SET GLOBAL innodb_limit_optimistic_insert_debug=@save_limit; +SELECT * FROM t1; +c2 c +DROP TABLE t1; +# # MDEV-22867 Assertion instant.n_core_fields == n_core_fields # in dict_index_t::instant_add_field # @@ -408,3 +421,4 @@ Table Op Msg_type Msg_text test.t1 check status OK DROP TABLE t1; SET DEBUG_SYNC=RESET; +SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; diff --git a/mysql-test/suite/innodb/t/innodb-virtual-columns2.test b/mysql-test/suite/innodb/t/innodb-virtual-columns2.test index 474a6354576..13ecffcc896 100644 --- a/mysql-test/suite/innodb/t/innodb-virtual-columns2.test +++ b/mysql-test/suite/innodb/t/innodb-virtual-columns2.test @@ -52,3 +52,23 @@ SELECT * FROM t1 WHERE y BETWEEN 2012 AND 2016 FOR UPDATE; INSERT INTO t1 (i) VALUES (1),(2); SELECT * FROM t1 WHERE y BETWEEN 2012 AND 2016 FOR UPDATE; DROP TABLE t1; + +--echo # +--echo # MDEV-23632 ALTER TABLE...ADD KEY creates corrupted index on virtual column +--echo # + +CREATE TABLE t1(a INT PRIMARY KEY, b INT, g INT GENERATED ALWAYS AS(b)VIRTUAL) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,1,default); +ALTER TABLE t1 ADD COLUMN c INT; +ALTER TABLE t1 ADD KEY(g); +CHECK TABLE t1; +SELECT g FROM t1 FORCE INDEX (g); +DROP TABLE t1; + +CREATE TABLE t1(a INT, b INT, g INT GENERATED ALWAYS AS(b)VIRTUAL) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1,1,default); +ALTER TABLE t1 ADD COLUMN c INT PRIMARY KEY; # Triggers `new_clustered` +ALTER TABLE t1 ADD KEY(g); +CHECK TABLE t1; +SELECT g FROM t1 FORCE INDEX (g); +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/instant_alter_debug.test b/mysql-test/suite/innodb/t/instant_alter_debug.test index 86273bcddd5..b4ba8794041 100644 --- a/mysql-test/suite/innodb/t/instant_alter_debug.test +++ b/mysql-test/suite/innodb/t/instant_alter_debug.test @@ -361,8 +361,6 @@ SELECT variable_value-@old_instant instants FROM information_schema.global_status WHERE variable_name = 'innodb_instant_alter_column'; -SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; - --echo # --echo # MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col --echo # @@ -416,6 +414,22 @@ SET DEBUG_SYNC='RESET'; DROP TABLE t1; --echo # +--echo # MDEV-24512 Assertion failed in rec_is_metadata() +--echo # in btr_discard_only_page_on_level() +--echo # + +SET @save_limit= @@GLOBAL.innodb_limit_optimistic_insert_debug; +SET GLOBAL innodb_limit_optimistic_insert_debug=2; +CREATE TABLE t1 (c CHAR(1) UNIQUE) ENGINE=InnoDB; + +ALTER TABLE t1 ADD c2 INT NOT NULL DEFAULT 0 FIRST; +--error ER_DUP_ENTRY +INSERT INTO t1 (c) VALUES ('x'),('d'),('r'),('f'),('y'),('u'),('m'),('d'); +SET GLOBAL innodb_limit_optimistic_insert_debug=@save_limit; +SELECT * FROM t1; +DROP TABLE t1; + +--echo # --echo # MDEV-22867 Assertion instant.n_core_fields == n_core_fields --echo # in dict_index_t::instant_add_field --echo # @@ -460,3 +474,5 @@ INSERT INTO t1 VALUES (2),(3),(4); CHECK TABLE t1; DROP TABLE t1; SET DEBUG_SYNC=RESET; + +SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency; diff --git a/mysql-test/suite/plugins/r/server_audit.result b/mysql-test/suite/plugins/r/server_audit.result index 6ded4f687a6..2c06b70c509 100644 --- a/mysql-test/suite/plugins/r/server_audit.result +++ b/mysql-test/suite/plugins/r/server_audit.result @@ -227,6 +227,7 @@ set global server_audit_logging= on; disconnect cn1; drop user user1@localhost; set global server_audit_events=''; +set global server_audit_incl_users='root, plug_dest'; CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest'; CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd'; connect(localhost,plug,plug_dest,test,MYSQL_PORT,MYSQL_SOCK); @@ -277,7 +278,7 @@ server_audit_file_path server_audit_file_rotate_now OFF server_audit_file_rotate_size 1000000 server_audit_file_rotations 9 -server_audit_incl_users root +server_audit_incl_users root, plug_dest server_audit_logging ON server_audit_mode 1 server_audit_output_type file @@ -431,6 +432,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,roles_mapping, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,global_priv, TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_events=\'\'',0 +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_incl_users=\'root, plug_dest\'',0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_priv, @@ -454,6 +456,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,global_priv, TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'GRANT PROXY ON plug_dest TO plug',0 TIME,HOSTNAME,plug,localhost,ID,0,CONNECT,test,,0 TIME,HOSTNAME,plug,localhost,ID,0,PROXY_CONNECT,test,`plug_dest`@`%`,0 +TIME,HOSTNAME,plug,localhost,ID,ID,QUERY,test,'select USER(),CURRENT_USER()',0 TIME,HOSTNAME,plug,localhost,ID,0,DISCONNECT,test,,0 TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, diff --git a/mysql-test/suite/plugins/t/server_audit.test b/mysql-test/suite/plugins/t/server_audit.test index 787541f7ca0..0d65c451d08 100644 --- a/mysql-test/suite/plugins/t/server_audit.test +++ b/mysql-test/suite/plugins/t/server_audit.test @@ -173,6 +173,7 @@ source include/wait_until_count_sessions.inc; drop user user1@localhost; set global server_audit_events=''; +set global server_audit_incl_users='root, plug_dest'; CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest'; CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd'; diff --git a/mysql-test/suite/rpl/r/rpl_row_vcol_crash.result b/mysql-test/suite/rpl/r/rpl_row_vcol_crash.result new file mode 100644 index 00000000000..f76d8935fa8 --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_row_vcol_crash.result @@ -0,0 +1,380 @@ +include/master-slave.inc +[connection master] +# +# Test case 1: KEY on a virtual column with ON DELETE CASCADE +# +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1),(2),(3); +CREATE TABLE t2 (id INT NOT NULL PRIMARY KEY, +t1_id INT NOT NULL, +v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), KEY (t1_id), +CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; +INSERT INTO t2 VALUES (90,1,NULL); +INSERT INTO t2 VALUES (91,2,default); +DELETE FROM t1 WHERE id=1; +connection slave; +# +# Verify data consistency on slave +# +include/diff_tables.inc [master:test.t1, slave:test.t1] +include/diff_tables.inc [master:test.t2, slave:test.t2] +connection master; +DROP TABLE t2,t1; +connection slave; +# +# Test case 2: Verify "ON DELETE CASCADE" for parent->child->child scenario +# Parent table: users +# Child tables: matchmaking_groups, matchmaking_group_users +# Parent table: matchmaking_groups +# Child tables: matchmaking_group_users, matchmaking_group_maps +# +# Deleting a row from parent table should be reflected in +# child tables. +# matchmaking_groups->matchmaking_group_users->matchmaking_group_maps +# users->matchmaking_group_users->matchmaking_group_maps +# +connection master; +CREATE TABLE users (id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, +name VARCHAR(32) NOT NULL DEFAULT '' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE matchmaking_groups ( +id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, +host_user_id INT UNSIGNED NOT NULL UNIQUE, +v_col INT AS (host_user_id+1) VIRTUAL, KEY (v_col), +CONSTRAINT FOREIGN KEY (host_user_id) REFERENCES users (id) +ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE matchmaking_group_users ( +matchmaking_group_id BIGINT UNSIGNED NOT NULL, +user_id INT UNSIGNED NOT NULL, +v_col1 int as (user_id+1) virtual, KEY (v_col1), +PRIMARY KEY (matchmaking_group_id,user_id), +UNIQUE KEY user_id (user_id), +CONSTRAINT FOREIGN KEY (matchmaking_group_id) +REFERENCES matchmaking_groups (id) ON DELETE CASCADE ON UPDATE CASCADE, +CONSTRAINT FOREIGN KEY (user_id) +REFERENCES users (id) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE matchmaking_group_maps ( +matchmaking_group_id BIGINT UNSIGNED NOT NULL, +map_id TINYINT UNSIGNED NOT NULL, +v_col2 INT AS (map_id+1) VIRTUAL, KEY (v_col2), +PRIMARY KEY (matchmaking_group_id,map_id), +CONSTRAINT FOREIGN KEY (matchmaking_group_id) +REFERENCES matchmaking_groups (id) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +connection slave; +connection master; +INSERT INTO users VALUES (NULL,'foo'),(NULL,'bar'); +INSERT INTO matchmaking_groups VALUES (10,1,default),(11,2,default); +INSERT INTO matchmaking_group_users VALUES (10,1,default),(11,2,default); +INSERT INTO matchmaking_group_maps VALUES (10,55,default),(11,66,default); +DELETE FROM matchmaking_groups WHERE id = 10; +connection slave; +# +# No rows should be returned as ON DELETE CASCASE should have removed +# corresponding rows from child tables. There should not any mismatch +# of 'id' field between parent->child. +# +SELECT * FROM matchmaking_group_users WHERE matchmaking_group_id NOT IN (SELECT id FROM matchmaking_groups); +matchmaking_group_id user_id v_col1 +SELECT * FROM matchmaking_group_maps WHERE matchmaking_group_id NOT IN (SELECT id FROM matchmaking_groups); +matchmaking_group_id map_id v_col2 +# +# Rows with id=11 should be present +# +SELECT * FROM matchmaking_group_users; +matchmaking_group_id user_id v_col1 +11 2 3 +SELECT * FROM matchmaking_group_maps; +matchmaking_group_id map_id v_col2 +11 66 67 +connection master; +DELETE FROM users WHERE id = 2; +connection slave; +# +# No rows should be present in both the child tables +# +SELECT * FROM matchmaking_group_users; +matchmaking_group_id user_id v_col1 +SELECT * FROM matchmaking_group_maps; +matchmaking_group_id map_id v_col2 +connection master; +DROP TABLE matchmaking_group_maps, matchmaking_group_users, matchmaking_groups, users; +connection slave; +# +# Test case 3: KEY on a virtual column with ON UPDATE CASCADE +# +connection master; +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, 80); +CREATE TABLE t2 (a INT KEY, b INT, +v_col int as (b+1) virtual, KEY (v_col), +CONSTRAINT b FOREIGN KEY (b) REFERENCES t1(a) ON UPDATE CASCADE +) ENGINE=InnoDB; +INSERT INTO t2 VALUES (51, 1, default); +connection slave; +connection master; +UPDATE t1 SET a = 50 WHERE a = 1; +# +# Master: Verify that ON UPDATE CASCADE works fine +# old_row: (51, 1, 2) ON UPDATE New_row: (51, 50, 51) +# +SELECT * FROM t2 WHERE b=50; +a b v_col +51 50 51 +connection slave; +# +# Slave: Verify that ON UPDATE CASCADE works fine +# old_row: (51, 1, 2) ON UPDATE New_row: (51, 50, 51) +# +SELECT * FROM t2 WHERE b=50; +a b v_col +51 50 51 +connection master; +DROP TABLE t2, t1; +connection slave; +# +# Test case 4: Define triggers on master, their results should be +# replicated as part of row events and they should be +# applied on slave with the default +# slave_run_triggers_for_rbr=NO +# +connection master; +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (count INT NOT NULL) ENGINE=InnoDB; +CREATE TRIGGER trg AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES (1); +INSERT INTO t1 VALUES (2),(3); +connection slave; +SHOW GLOBAL VARIABLES LIKE 'slave_run_triggers_for_rbr'; +Variable_name Value +slave_run_triggers_for_rbr NO +# +# As two rows are inserted in table 't1', two rows should get inserted +# into table 't2' as part of trigger. +# +include/assert.inc [Table t2 should have two rows.] +connection master; +DROP TABLE t1,t2; +connection slave; +# +# Test case 5: Define triggers + Foreign Keys on master, their results +# should be replicated as part of row events and master +# and slave should be in sync. +# +connection master; +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (t1_id INT NOT NULL, +v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), KEY (t1_id), +CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; +CREATE TABLE t3 (count INT NOT NULL) ENGINE=InnoDB; +CREATE TRIGGER trg AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t3 VALUES (1); +INSERT INTO t1 VALUES (2),(3); +INSERT INTO t2 VALUES (2, default), (3, default); +connection slave; +# +# As two rows are inserted in table 't1', two rows should get inserted +# into table 't3' as part of trigger. +# +include/assert.inc [Table t3 should have two rows.] +# +# Verify ON DELETE CASCASE correctness +# +connection master; +DELETE FROM t1 WHERE id=2; +connection slave; +connection master; +include/diff_tables.inc [master:test.t1, slave:test.t1] +include/diff_tables.inc [master:test.t2, slave:test.t2] +include/diff_tables.inc [master:test.t3, slave:test.t3] +DROP TABLE t3,t2,t1; +connection slave; +# +# Test case 6: Triggers are present only on slave and +# 'slave_run_triggers_for_rbr=NO' +# +connection slave; +SET @save_slave_run_triggers_for_rbr= @@GLOBAL.slave_run_triggers_for_rbr; +SET GLOBAL slave_run_triggers_for_rbr= NO;; +SHOW GLOBAL VARIABLES LIKE '%slave_run_triggers_for_rbr%'; +Variable_name Value +slave_run_triggers_for_rbr NO +connection master; +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (t1_id INT NOT NULL, +v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), +KEY (t1_id), CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; +CREATE TABLE t3 (count INT NOT NULL) ENGINE=InnoDB; +connection slave; +CREATE TRIGGER trg AFTER INSERT ON t2 FOR EACH ROW INSERT INTO t3 VALUES (1); +connection master; +INSERT INTO t1 VALUES (2),(3); +INSERT INTO t2 VALUES (2, default), (3, default); +connection slave; +# +# Count must be 0 +# +include/assert.inc [Table t3 should have zero rows.] +connection master; +DELETE FROM t1 WHERE id=2; +connection slave; +SET GLOBAL slave_run_triggers_for_rbr= @save_slave_run_triggers_for_rbr; +# +# Verify t1, t2 are consistent on slave. +# +include/diff_tables.inc [master:test.t1, slave:test.t1] +include/diff_tables.inc [master:test.t2, slave:test.t2] +connection master; +DROP TABLE t3,t2,t1; +connection slave; +# +# Test case 7: Triggers are present only on slave and +# 'slave_run_triggers_for_rbr=YES' +# +connection slave; +SET @save_slave_run_triggers_for_rbr= @@GLOBAL.slave_run_triggers_for_rbr; +SET GLOBAL slave_run_triggers_for_rbr= YES;; +SHOW GLOBAL VARIABLES LIKE '%slave_run_triggers_for_rbr%'; +Variable_name Value +slave_run_triggers_for_rbr YES +connection master; +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (t1_id INT NOT NULL, +v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), +KEY (t1_id), CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; +CREATE TABLE t3 (count INT NOT NULL) ENGINE=InnoDB; +connection slave; +CREATE TRIGGER trg AFTER INSERT ON t2 FOR EACH ROW INSERT INTO t3 VALUES (1); +connection master; +INSERT INTO t1 VALUES (2),(3); +INSERT INTO t2 VALUES (2, default), (3, default); +connection slave; +# +# Count must be 2 +# +include/assert.inc [Table t3 should have two rows.] +connection master; +DELETE FROM t1 WHERE id=2; +connection slave; +SET GLOBAL slave_run_triggers_for_rbr= @save_slave_run_triggers_for_rbr; +# +# Verify t1, t2 are consistent on slave. +# +include/diff_tables.inc [master:test.t1, slave:test.t1] +include/diff_tables.inc [master:test.t2, slave:test.t2] +connection master; +DROP TABLE t3,t2,t1; +connection slave; +# +# Test case 8: Triggers and Foreign Keys are present only on slave and +# 'slave_run_triggers_for_rbr=NO' +# +connection slave; +SET @save_slave_run_triggers_for_rbr= @@GLOBAL.slave_run_triggers_for_rbr; +SET GLOBAL slave_run_triggers_for_rbr= NO;; +SHOW GLOBAL VARIABLES LIKE '%slave_run_triggers_for_rbr%'; +Variable_name Value +slave_run_triggers_for_rbr NO +connection master; +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +SET sql_log_bin=0; +CREATE TABLE t2 (t1_id INT NOT NULL,v_col INT AS (t1_id+1) VIRTUAL) ENGINE=INNODB; +SET sql_log_bin=1; +CREATE TABLE t3 (count INT NOT NULL) ENGINE=InnoDB; +connection slave; +CREATE TABLE t2 (t1_id INT NOT NULL, +v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), KEY (t1_id), +CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; +CREATE TRIGGER trg AFTER INSERT ON t2 FOR EACH ROW INSERT INTO t3 VALUES (1); +connection master; +INSERT INTO t1 VALUES (2),(3); +INSERT INTO t2 VALUES (2, default), (3, default); +connection slave; +# +# Count must be 0 +# +include/assert.inc [Table t3 should have zero rows.] +connection master; +DELETE FROM t1 WHERE id=2; +# t1: Should have one row +SELECT * FROM t1; +id +3 +# t2: Should have two rows +SELECT * FROM t2; +t1_id v_col +2 3 +3 4 +connection slave; +# t1: Should have one row +SELECT * FROM t1; +id +3 +# t2: Should have one row on slave due to ON DELETE CASCASE +SELECT * FROM t2; +t1_id v_col +3 4 +SET GLOBAL slave_run_triggers_for_rbr= @save_slave_run_triggers_for_rbr; +connection master; +DROP TABLE t3,t2,t1; +connection slave; +# +# Test case 9: Triggers are Foreign Keys are present only on slave and +# 'slave_run_triggers_for_rbr=YES' +# +connection slave; +SET @save_slave_run_triggers_for_rbr= @@GLOBAL.slave_run_triggers_for_rbr; +SET GLOBAL slave_run_triggers_for_rbr= YES;; +SHOW GLOBAL VARIABLES LIKE '%slave_run_triggers_for_rbr%'; +Variable_name Value +slave_run_triggers_for_rbr YES +connection master; +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +SET sql_log_bin=0; +CREATE TABLE t2 (t1_id INT NOT NULL,v_col INT AS (t1_id+1) VIRTUAL) ENGINE=INNODB; +SET sql_log_bin=1; +CREATE TABLE t3 (count INT NOT NULL) ENGINE=InnoDB; +connection slave; +CREATE TABLE t2 (t1_id INT NOT NULL, +v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), KEY (t1_id), +CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; +CREATE TRIGGER trg AFTER INSERT ON t2 FOR EACH ROW INSERT INTO t3 VALUES (1); +connection master; +INSERT INTO t1 VALUES (2),(3); +INSERT INTO t2 VALUES (2, default), (3, default); +connection slave; +# +# Count must be 2 +# +include/assert.inc [Table t3 should have two rows.] +connection master; +DELETE FROM t1 WHERE id=2; +# t1: Should have one row +SELECT * FROM t1; +id +3 +# t2: Should have two rows +SELECT * FROM t2; +t1_id v_col +2 3 +3 4 +connection slave; +# t1: Should have one row +SELECT * FROM t1; +id +3 +# t2: Should have one row on slave due to ON DELETE CASCASE +SELECT * FROM t2; +t1_id v_col +3 4 +SET GLOBAL slave_run_triggers_for_rbr= @save_slave_run_triggers_for_rbr; +connection master; +DROP TABLE t3,t2,t1; +connection slave; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_vcol_crash.test b/mysql-test/suite/rpl/t/rpl_row_vcol_crash.test new file mode 100644 index 00000000000..84ee14977f3 --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_vcol_crash.test @@ -0,0 +1,425 @@ +# ==== Purpose ==== +# +# Test verifies that, slave doesn't report any assert on UPDATE or DELETE of +# row which tries to update the virtual columns with associated KEYs. +# +# Test scenarios are listed below. +# 1) KEY on a virtual column with ON DELETE CASCADE +# 2) Verify "ON DELETE CASCADE" for parent->child->child scenario +# 3) KEY on a virtual column with ON UPDATE CASCADE +# 4) Define triggers on master, their results should be replicated +# as part of row events and they should be applied on slave with +# the default slave_run_triggers_for_rbr=NO +# 5) Define triggers + Foreign Keys on master, their results should be +# replicated as part of row events and master and slave should be in sync. +# 6) Triggers are present only on slave and 'slave_run_triggers_for_rbr=NO' +# 7) Triggers are present only on slave and 'slave_run_triggers_for_rbr=YES' +# 8) Triggers and Foreign Keys are present only on slave and +# 'slave_run_triggers_for_rbr=NO' +# 9) Triggers are Foreign Keys are present only on slave and +# 'slave_run_triggers_for_rbr=YES' +# +# ==== References ==== +# +# MDEV-23033: All slaves crash once in ~24 hours and loop restart with signal 11 +# + +--source include/have_binlog_format_row.inc +--source include/have_innodb.inc +--source include/master-slave.inc + + +--echo # +--echo # Test case 1: KEY on a virtual column with ON DELETE CASCADE +--echo # +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1),(2),(3); + +CREATE TABLE t2 (id INT NOT NULL PRIMARY KEY, + t1_id INT NOT NULL, + v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), KEY (t1_id), + CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; + +INSERT INTO t2 VALUES (90,1,NULL); +INSERT INTO t2 VALUES (91,2,default); + +# Following query results in an assert on slave +DELETE FROM t1 WHERE id=1; +--sync_slave_with_master + +--echo # +--echo # Verify data consistency on slave +--echo # +--let $diff_tables= master:test.t1, slave:test.t1 +--source include/diff_tables.inc +--let $diff_tables= master:test.t2, slave:test.t2 +--source include/diff_tables.inc + +--connection master +DROP TABLE t2,t1; +--sync_slave_with_master + +--echo # +--echo # Test case 2: Verify "ON DELETE CASCADE" for parent->child->child scenario +--echo # Parent table: users +--echo # Child tables: matchmaking_groups, matchmaking_group_users +--echo # Parent table: matchmaking_groups +--echo # Child tables: matchmaking_group_users, matchmaking_group_maps +--echo # +--echo # Deleting a row from parent table should be reflected in +--echo # child tables. +--echo # matchmaking_groups->matchmaking_group_users->matchmaking_group_maps +--echo # users->matchmaking_group_users->matchmaking_group_maps +--echo # + +--connection master +CREATE TABLE users (id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(32) NOT NULL DEFAULT '' +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE matchmaking_groups ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + host_user_id INT UNSIGNED NOT NULL UNIQUE, + v_col INT AS (host_user_id+1) VIRTUAL, KEY (v_col), + CONSTRAINT FOREIGN KEY (host_user_id) REFERENCES users (id) + ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE matchmaking_group_users ( + matchmaking_group_id BIGINT UNSIGNED NOT NULL, + user_id INT UNSIGNED NOT NULL, + v_col1 int as (user_id+1) virtual, KEY (v_col1), + PRIMARY KEY (matchmaking_group_id,user_id), + UNIQUE KEY user_id (user_id), + CONSTRAINT FOREIGN KEY (matchmaking_group_id) + REFERENCES matchmaking_groups (id) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT FOREIGN KEY (user_id) + REFERENCES users (id) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE matchmaking_group_maps ( + matchmaking_group_id BIGINT UNSIGNED NOT NULL, + map_id TINYINT UNSIGNED NOT NULL, + v_col2 INT AS (map_id+1) VIRTUAL, KEY (v_col2), + PRIMARY KEY (matchmaking_group_id,map_id), + CONSTRAINT FOREIGN KEY (matchmaking_group_id) + REFERENCES matchmaking_groups (id) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +--sync_slave_with_master + +--connection master +INSERT INTO users VALUES (NULL,'foo'),(NULL,'bar'); +INSERT INTO matchmaking_groups VALUES (10,1,default),(11,2,default); +INSERT INTO matchmaking_group_users VALUES (10,1,default),(11,2,default); +INSERT INTO matchmaking_group_maps VALUES (10,55,default),(11,66,default); + +DELETE FROM matchmaking_groups WHERE id = 10; +--sync_slave_with_master + +--echo # +--echo # No rows should be returned as ON DELETE CASCASE should have removed +--echo # corresponding rows from child tables. There should not any mismatch +--echo # of 'id' field between parent->child. +--echo # +SELECT * FROM matchmaking_group_users WHERE matchmaking_group_id NOT IN (SELECT id FROM matchmaking_groups); +SELECT * FROM matchmaking_group_maps WHERE matchmaking_group_id NOT IN (SELECT id FROM matchmaking_groups); + +--echo # +--echo # Rows with id=11 should be present +--echo # +SELECT * FROM matchmaking_group_users; +SELECT * FROM matchmaking_group_maps; + +--connection master +DELETE FROM users WHERE id = 2; +--sync_slave_with_master + +--echo # +--echo # No rows should be present in both the child tables +--echo # +SELECT * FROM matchmaking_group_users; +SELECT * FROM matchmaking_group_maps; + +--connection master +DROP TABLE matchmaking_group_maps, matchmaking_group_users, matchmaking_groups, users; +--sync_slave_with_master + +--echo # +--echo # Test case 3: KEY on a virtual column with ON UPDATE CASCADE +--echo # + +--connection master +CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b INT NOT NULL) ENGINE=InnoDB; +INSERT INTO t1 VALUES (1, 80); + +CREATE TABLE t2 (a INT KEY, b INT, + v_col int as (b+1) virtual, KEY (v_col), + CONSTRAINT b FOREIGN KEY (b) REFERENCES t1(a) ON UPDATE CASCADE +) ENGINE=InnoDB; +INSERT INTO t2 VALUES (51, 1, default); +--sync_slave_with_master + +--connection master +UPDATE t1 SET a = 50 WHERE a = 1; + +--echo # +--echo # Master: Verify that ON UPDATE CASCADE works fine +--echo # old_row: (51, 1, 2) ON UPDATE New_row: (51, 50, 51) +--echo # +SELECT * FROM t2 WHERE b=50; +--sync_slave_with_master + +--echo # +--echo # Slave: Verify that ON UPDATE CASCADE works fine +--echo # old_row: (51, 1, 2) ON UPDATE New_row: (51, 50, 51) +--echo # +SELECT * FROM t2 WHERE b=50; + +--connection master +DROP TABLE t2, t1; +--sync_slave_with_master + +--echo # +--echo # Test case 4: Define triggers on master, their results should be +--echo # replicated as part of row events and they should be +--echo # applied on slave with the default +--echo # slave_run_triggers_for_rbr=NO +--echo # + +# In row-based replication, the binary log contains row changes. It will have +# both the changes made by the statement itself, and the changes made by the +# triggers that were invoked by the statement. Slave server(s) do not need to +# run triggers for row changes they are applying. Hence verify that this +# property remains the same and data should be available as if trigger was +# executed. Please note by default slave_run_triggers_for_rbr=NO. + +--connection master +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (count INT NOT NULL) ENGINE=InnoDB; +CREATE TRIGGER trg AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t2 VALUES (1); +INSERT INTO t1 VALUES (2),(3); +--sync_slave_with_master + +SHOW GLOBAL VARIABLES LIKE 'slave_run_triggers_for_rbr'; +--echo # +--echo # As two rows are inserted in table 't1', two rows should get inserted +--echo # into table 't2' as part of trigger. +--echo # +--let $assert_cond= COUNT(*) = 2 FROM t2 +--let $assert_text= Table t2 should have two rows. +--source include/assert.inc + +--connection master +DROP TABLE t1,t2; +--sync_slave_with_master + +--echo # +--echo # Test case 5: Define triggers + Foreign Keys on master, their results +--echo # should be replicated as part of row events and master +--echo # and slave should be in sync. +--echo # +--connection master +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (t1_id INT NOT NULL, + v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), KEY (t1_id), + CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; +CREATE TABLE t3 (count INT NOT NULL) ENGINE=InnoDB; +CREATE TRIGGER trg AFTER INSERT ON t1 FOR EACH ROW INSERT INTO t3 VALUES (1); + +INSERT INTO t1 VALUES (2),(3); +INSERT INTO t2 VALUES (2, default), (3, default); +--sync_slave_with_master + +--echo # +--echo # As two rows are inserted in table 't1', two rows should get inserted +--echo # into table 't3' as part of trigger. +--echo # +--let $assert_cond= COUNT(*) = 2 FROM t3 +--let $assert_text= Table t3 should have two rows. +--source include/assert.inc + +--echo # +--echo # Verify ON DELETE CASCASE correctness +--echo # +--connection master +DELETE FROM t1 WHERE id=2; +--sync_slave_with_master + +--connection master +--let $diff_tables= master:test.t1, slave:test.t1 +--source include/diff_tables.inc +--let $diff_tables= master:test.t2, slave:test.t2 +--source include/diff_tables.inc +--let $diff_tables= master:test.t3, slave:test.t3 +--source include/diff_tables.inc + +DROP TABLE t3,t2,t1; +--sync_slave_with_master + +# +# Test case: Triggers only on slave +# +--write_file $MYSQLTEST_VARDIR/tmp/trig_on_slave.inc PROCEDURE + if ($slave_run_triggers_for_rbr == '') { + --die !!!ERROR IN TEST: you must set $slave_run_triggers_for_rbr + } + +--connection slave +SET @save_slave_run_triggers_for_rbr= @@GLOBAL.slave_run_triggers_for_rbr; +--eval SET GLOBAL slave_run_triggers_for_rbr= $slave_run_triggers_for_rbr; +SHOW GLOBAL VARIABLES LIKE '%slave_run_triggers_for_rbr%'; + +--connection master +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +CREATE TABLE t2 (t1_id INT NOT NULL, + v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), + KEY (t1_id), CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; +CREATE TABLE t3 (count INT NOT NULL) ENGINE=InnoDB; +--sync_slave_with_master + +CREATE TRIGGER trg AFTER INSERT ON t2 FOR EACH ROW INSERT INTO t3 VALUES (1); + +--connection master +INSERT INTO t1 VALUES (2),(3); +INSERT INTO t2 VALUES (2, default), (3, default); +--sync_slave_with_master + +if ($slave_run_triggers_for_rbr == 'NO') { +--echo # +--echo # Count must be 0 +--echo # +--let $assert_cond= COUNT(*) = 0 FROM t3 +--let $assert_text= Table t3 should have zero rows. +--source include/assert.inc +} +if ($slave_run_triggers_for_rbr == 'YES') { +--echo # +--echo # Count must be 2 +--echo # +--let $assert_cond= COUNT(*) = 2 FROM t3 +--let $assert_text= Table t3 should have two rows. +--source include/assert.inc +} + +--connection master +DELETE FROM t1 WHERE id=2; +--sync_slave_with_master +SET GLOBAL slave_run_triggers_for_rbr= @save_slave_run_triggers_for_rbr; + +--echo # +--echo # Verify t1, t2 are consistent on slave. +--echo # +--let $diff_tables= master:test.t1, slave:test.t1 +--source include/diff_tables.inc +--let $diff_tables= master:test.t2, slave:test.t2 +--source include/diff_tables.inc + +--connection master +DROP TABLE t3,t2,t1; +--sync_slave_with_master +#END OF +PROCEDURE + +--echo # +--echo # Test case 6: Triggers are present only on slave and +--echo # 'slave_run_triggers_for_rbr=NO' +--echo # +--let $slave_run_triggers_for_rbr=NO +--source $MYSQLTEST_VARDIR/tmp/trig_on_slave.inc + +--echo # +--echo # Test case 7: Triggers are present only on slave and +--echo # 'slave_run_triggers_for_rbr=YES' +--echo # +--let $slave_run_triggers_for_rbr=YES +--source $MYSQLTEST_VARDIR/tmp/trig_on_slave.inc +--remove_file $MYSQLTEST_VARDIR/tmp/trig_on_slave.inc + +# +# Test case: Trigger and Foreign Key are present only on slave +# +--write_file $MYSQLTEST_VARDIR/tmp/trig_fk_on_slave.inc PROCEDURE + if ($slave_run_triggers_for_rbr == '') { + --die !!!ERROR IN TEST: you must set $slave_run_triggers_for_rbr + } + +--connection slave +SET @save_slave_run_triggers_for_rbr= @@GLOBAL.slave_run_triggers_for_rbr; +--eval SET GLOBAL slave_run_triggers_for_rbr= $slave_run_triggers_for_rbr; +SHOW GLOBAL VARIABLES LIKE '%slave_run_triggers_for_rbr%'; + +--connection master +CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +SET sql_log_bin=0; +CREATE TABLE t2 (t1_id INT NOT NULL,v_col INT AS (t1_id+1) VIRTUAL) ENGINE=INNODB; +SET sql_log_bin=1; +CREATE TABLE t3 (count INT NOT NULL) ENGINE=InnoDB; +--sync_slave_with_master + +# Have foreign key and trigger on slave. +CREATE TABLE t2 (t1_id INT NOT NULL, + v_col INT AS (t1_id+1) VIRTUAL, KEY (v_col), KEY (t1_id), + CONSTRAINT a FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE +) ENGINE=InnoDB; +CREATE TRIGGER trg AFTER INSERT ON t2 FOR EACH ROW INSERT INTO t3 VALUES (1); + +--connection master +INSERT INTO t1 VALUES (2),(3); +INSERT INTO t2 VALUES (2, default), (3, default); +--sync_slave_with_master + +if ($slave_run_triggers_for_rbr == 'NO') { +--echo # +--echo # Count must be 0 +--echo # +--let $assert_cond= COUNT(*) = 0 FROM t3 +--let $assert_text= Table t3 should have zero rows. +--source include/assert.inc +} +if ($slave_run_triggers_for_rbr == 'YES') { +--echo # +--echo # Count must be 2 +--echo # +--let $assert_cond= COUNT(*) = 2 FROM t3 +--let $assert_text= Table t3 should have two rows. +--source include/assert.inc +} + +--connection master +DELETE FROM t1 WHERE id=2; +--echo # t1: Should have one row +SELECT * FROM t1; +--echo # t2: Should have two rows +SELECT * FROM t2; +--sync_slave_with_master +--echo # t1: Should have one row +SELECT * FROM t1; +--echo # t2: Should have one row on slave due to ON DELETE CASCASE +SELECT * FROM t2; +SET GLOBAL slave_run_triggers_for_rbr= @save_slave_run_triggers_for_rbr; + +--connection master +DROP TABLE t3,t2,t1; +--sync_slave_with_master +#END OF +PROCEDURE + +--echo # +--echo # Test case 8: Triggers and Foreign Keys are present only on slave and +--echo # 'slave_run_triggers_for_rbr=NO' +--echo # +--let $slave_run_triggers_for_rbr=NO +--source $MYSQLTEST_VARDIR/tmp/trig_fk_on_slave.inc + +--echo # +--echo # Test case 9: Triggers are Foreign Keys are present only on slave and +--echo # 'slave_run_triggers_for_rbr=YES' +--echo # +--let $slave_run_triggers_for_rbr=YES +--source $MYSQLTEST_VARDIR/tmp/trig_fk_on_slave.inc +--remove_file $MYSQLTEST_VARDIR/tmp/trig_fk_on_slave.inc + +--source include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_semisync_ali_issues.test b/mysql-test/suite/rpl/t/rpl_semisync_ali_issues.test index 52cd9e31753..f67c6e2ac0a 100644 --- a/mysql-test/suite/rpl/t/rpl_semisync_ali_issues.test +++ b/mysql-test/suite/rpl/t/rpl_semisync_ali_issues.test @@ -31,8 +31,12 @@ echo [ enable semi-sync on slave ]; stop slave; set global rpl_semi_sync_slave_enabled = 1; start slave; +let $status_var= rpl_semi_sync_slave_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; show status like 'rpl_semi_sync_slave%'; + connection master; CREATE TABLE t1(a INT) ENGINE=InnoDB; sync_slave_with_master; @@ -190,6 +194,12 @@ connection con1; INSERT INTO t1 values (2); sync_slave_with_master; connection con1; +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 1; +source include/wait_for_status_var.inc; +let $status_var= Rpl_semi_sync_master_status; +let $status_var_value= ON; +source include/wait_for_status_var.inc; show status like 'Rpl_semi_sync_master_clients'; show status like 'Rpl_semi_sync_master_status'; @@ -259,7 +269,12 @@ START SLAVE IO_THREAD; --echo ######################################################### connection con1; SET GLOBAL rpl_semi_sync_master_enabled = 0; + +let $status_var= Rpl_semi_sync_master_clients; +let $status_var_value= 1; +source include/wait_for_status_var.inc; show status like 'Rpl_semi_sync_master_clients'; + INSERT INTO t1 VALUES (1); SET GLOBAL rpl_semi_sync_master_enabled = 1; INSERT INTO t1 VALUES (2); diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 99d1c01cc49..98d98ff4034 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -912,6 +912,7 @@ t1 CREATE TABLE `t1` ( PARTITION BY SYSTEM_TIME INTERVAL 7 SECOND STARTS TIMESTAMP'2018-04-11 17:00:04' (PARTITION `ver_p1` HISTORY ENGINE = DEFAULT_ENGINE, PARTITION `ver_pn` CURRENT ENGINE = DEFAULT_ENGINE) +set timestamp= default; # # MDEV-19175 Server crashes in ha_partition::vers_can_native upon INSERT DELAYED into versioned partitioned table # @@ -1079,6 +1080,41 @@ create table t1 (a int) with system versioning partition by system_time (partition p1 history, partition pn current); alter table t1 add partition (partition p2); ERROR HY000: Wrong partitioning type, expected type: `SYSTEM_TIME` +# MDEV-17891 Assertion failures in select_insert::abort_result_set and +# mysql_load upon attempt to replace into a full table +set @@max_heap_table_size= 1024*1024; +create or replace table t1 ( +pk integer auto_increment, +primary key (pk), +f varchar(45000) +) with system versioning engine=memory +partition by system_time interval 1 year (partition p1 history, +partition pn current); +# fill the table until full +insert into t1 () values (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(); +insert into t1 (f) select f from t1; +ERROR HY000: The table 't1' is full +# leave space for exactly one record in current partition +delete from t1 where pk = 1; +# copy all data into history partition +replace into t1 select * from t1; +replace into t1 select * from t1; +ERROR HY000: The table 't1' is full +create or replace table t1 ( +pk integer auto_increment, +primary key (pk), +f varchar(45000) +) with system versioning engine=memory +partition by system_time interval 1 year (partition p1 history, +partition pn current); +insert into t1 () values (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(); +select * into outfile 'load.data' from t1; +load data infile 'load.data' replace into table t1; +load data infile 'load.data' replace into table t1; +ERROR HY000: The table 't1' is full +load data infile 'load.data' replace into table t1; +ERROR HY000: The table 't1' is full +set @@max_heap_table_size= 1048576; drop table t1; # # MDEV-22178 Assertion `info->alias.str' failed in partition_info::check_partition_info instead of ER_VERS_WRONG_PARTS diff --git a/mysql-test/suite/versioning/r/replace.result b/mysql-test/suite/versioning/r/replace.result index bda61f118b0..57a992cce49 100644 --- a/mysql-test/suite/versioning/r/replace.result +++ b/mysql-test/suite/versioning/r/replace.result @@ -48,3 +48,16 @@ INSERT INTO t1 () VALUES (),(),(),(),(),(); UPDATE IGNORE t1 SET f = 1; REPLACE t1 SELECT * FROM t1; DROP TABLE t1; +# MDEV-22540 ER_DUP_ENTRY upon REPLACE or Assertion failed +set timestamp=1589245268.41934; +create table t1 (a int primary key) with system versioning; +insert into t1 values (1),(2); +connect con1,localhost,root,,test; +set timestamp=1589245268.52093; +replace into t1 values (1),(2); +connection default; +replace into t1 values (1),(2); +connection con1; +replace into t1 values (1),(2); +ERROR 23000: Duplicate entry '1' for key 'PRIMARY' +drop table t1; diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index b4c2a058147..f9f12f4c6af 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -769,6 +769,7 @@ partition by system_time interval column_get(column_create(7,7), 7 as int) secon partition ver_pn current); --replace_result $default_engine DEFAULT_ENGINE show create table t1; +set timestamp= default; --echo # --echo # MDEV-19175 Server crashes in ha_partition::vers_can_native upon INSERT DELAYED into versioned partitioned table @@ -936,7 +937,51 @@ create table t1 (a int) with system versioning partition by system_time --error ER_PARTITION_WRONG_TYPE alter table t1 add partition (partition p2); +--echo # MDEV-17891 Assertion failures in select_insert::abort_result_set and +--echo # mysql_load upon attempt to replace into a full table + +--let $max_heap_table_size_orig= `select @@max_heap_table_size;` +set @@max_heap_table_size= 1024*1024; +create or replace table t1 ( + pk integer auto_increment, + primary key (pk), + f varchar(45000) +) with system versioning engine=memory + partition by system_time interval 1 year (partition p1 history, + partition pn current); + +--echo # fill the table until full +insert into t1 () values (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(); +--error ER_RECORD_FILE_FULL +insert into t1 (f) select f from t1; +--echo # leave space for exactly one record in current partition +delete from t1 where pk = 1; +--echo # copy all data into history partition +replace into t1 select * from t1; +--error ER_RECORD_FILE_FULL +replace into t1 select * from t1; + +create or replace table t1 ( + pk integer auto_increment, + primary key (pk), + f varchar(45000) +) with system versioning engine=memory + partition by system_time interval 1 year (partition p1 history, + partition pn current); + +insert into t1 () values (),(),(),(),(),(),(),(),(),(),(),(),(),(),(),(); + +select * into outfile 'load.data' from t1; +load data infile 'load.data' replace into table t1; +--error ER_RECORD_FILE_FULL +load data infile 'load.data' replace into table t1; +--error ER_RECORD_FILE_FULL +load data infile 'load.data' replace into table t1; + # Cleanup +--let $datadir= `select @@datadir` +--remove_file $datadir/test/load.data +eval set @@max_heap_table_size= $max_heap_table_size_orig; drop table t1; --echo # diff --git a/mysql-test/suite/versioning/t/replace.test b/mysql-test/suite/versioning/t/replace.test index 392c0ffcf35..83489f4a4b9 100644 --- a/mysql-test/suite/versioning/t/replace.test +++ b/mysql-test/suite/versioning/t/replace.test @@ -59,4 +59,22 @@ UPDATE IGNORE t1 SET f = 1; REPLACE t1 SELECT * FROM t1; DROP TABLE t1; +--echo # MDEV-22540 ER_DUP_ENTRY upon REPLACE or Assertion failed +set timestamp=1589245268.41934; +create table t1 (a int primary key) with system versioning; +insert into t1 values (1),(2); + +--connect (con1,localhost,root,,test) +set timestamp=1589245268.52093; +replace into t1 values (1),(2); + +--connection default +replace into t1 values (1),(2); + +--connection con1 +--error ER_DUP_ENTRY +replace into t1 values (1),(2); + +drop table t1; + --source suite/versioning/common_finish.inc diff --git a/mysys/CMakeLists.txt b/mysys/CMakeLists.txt index 5b1a2608eeb..1a3e670878f 100644 --- a/mysys/CMakeLists.txt +++ b/mysys/CMakeLists.txt @@ -115,7 +115,7 @@ ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64") COMPILE_FLAGS "-march=armv8-a+crc+crypto") ENDIF() ENDIF() -ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64") +ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64|powerpc64") SET(MYSYS_SOURCES ${MYSYS_SOURCES} crc32/crc32_ppc64.c crc32/crc32c_ppc.c) SET_SOURCE_FILES_PROPERTIES(crc32/crc32_ppc64.c crc32/crc32c_ppc.c PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -maltivec -mvsx -mpower8-vector -mcrypto -mpower8-vector") diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index 83799b4c714..888cc4a6252 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -1581,22 +1581,27 @@ no_password: -static int do_log_user(const char *name, int take_lock) +static int do_log_user(const char *name, int len, + const char *proxy, int proxy_len, int take_lock) { - size_t len; int result; if (!name) return 0; - len= strlen(name); if (take_lock) flogger_mutex_lock(&lock_operations); if (incl_user_coll.n_users) - result= coll_search(&incl_user_coll, name, len) != 0; + { + result= coll_search(&incl_user_coll, name, len) != 0 || + (proxy && coll_search(&incl_user_coll, proxy, proxy_len) != 0); + } else if (excl_user_coll.n_users) - result= coll_search(&excl_user_coll, name, len) == 0; + { + result= coll_search(&excl_user_coll, name, len) == 0 && + (proxy && coll_search(&excl_user_coll, proxy, proxy_len) == 0); + } else result= 1; @@ -2137,7 +2142,9 @@ void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev) } if (event_class == MYSQL_AUDIT_GENERAL_CLASS && FILTER(EVENT_QUERY) && - cn && (cn->log_always || do_log_user(cn->user, 1))) + cn && (cn->log_always || do_log_user(cn->user, cn->user_length, + cn->proxy, cn->proxy_length, + 1))) { const struct mysql_event_general *event = (const struct mysql_event_general *) ev; @@ -2157,7 +2164,8 @@ void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev) { const struct mysql_event_table *event = (const struct mysql_event_table *) ev; - if (do_log_user(event->user, 1)) + if (do_log_user(event->user, (int) SAFE_STRLEN(event->user), + cn->proxy, cn->proxy_length, 1)) { switch (event->event_subclass) { diff --git a/sql/log_event_client.cc b/sql/log_event_client.cc index 0480a8fa59f..9d53611260b 100644 --- a/sql/log_event_client.cc +++ b/sql/log_event_client.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2018, Oracle and/or its affiliates. - Copyright (c) 2009, 2020, MariaDB + Copyright (c) 2009, 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 diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index cd35c6d6d23..b32131f0245 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. - Copyright (c) 2009, 2020, MariaDB + Copyright (c) 2009, 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 @@ -5287,7 +5287,7 @@ int Rows_log_event::do_add_row_data(uchar *row_data, size_t length) There was the same problem with MERGE MYISAM tables and so here we try to go the same way. */ -static void restore_empty_query_table_list(LEX *lex) +inline void restore_empty_query_table_list(LEX *lex) { if (lex->first_not_own_table()) (*lex->first_not_own_table()->prev_global)= NULL; @@ -5302,6 +5302,8 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) TABLE* table; DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)"); int error= 0; + LEX *lex= thd->lex; + uint8 new_trg_event_map= get_trg_event_map(); /* If m_table_id == ~0ULL, then we have a dummy event that does not contain any data. In that case, we just remove all tables in the @@ -5392,27 +5394,30 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(action))); };); - if (slave_run_triggers_for_rbr) - { - LEX *lex= thd->lex; - uint8 new_trg_event_map= get_trg_event_map(); - /* - Trigger's procedures work with global table list. So we have to add - rgi->tables_to_lock content there to get trigger's in the list. + /* + Trigger's procedures work with global table list. So we have to add + rgi->tables_to_lock content there to get trigger's in the list. - Then restore_empty_query_table_list() restore the list as it was - */ - DBUG_ASSERT(lex->query_tables == NULL); - if ((lex->query_tables= rgi->tables_to_lock)) - rgi->tables_to_lock->prev_global= &lex->query_tables; + Then restore_empty_query_table_list() restore the list as it was + */ + DBUG_ASSERT(lex->query_tables == NULL); + if ((lex->query_tables= rgi->tables_to_lock)) + rgi->tables_to_lock->prev_global= &lex->query_tables; - for (TABLE_LIST *tables= rgi->tables_to_lock; tables; - tables= tables->next_global) + for (TABLE_LIST *tables= rgi->tables_to_lock; tables; + tables= tables->next_global) + { + if (slave_run_triggers_for_rbr) { tables->trg_event_map= new_trg_event_map; lex->query_tables_last= &tables->next_global; } + else if (!WSREP_ON) + { + tables->slave_fk_event_map= new_trg_event_map; + lex->query_tables_last= &tables->next_global; + } } if (unlikely(open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0))) { @@ -5771,8 +5776,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) } /* remove trigger's tables */ - if (slave_run_triggers_for_rbr) - restore_empty_query_table_list(thd->lex); + restore_empty_query_table_list(thd->lex); #if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE) if (WSREP(thd) && wsrep_thd_is_applying(thd)) @@ -5791,8 +5795,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi) DBUG_RETURN(error); err: - if (slave_run_triggers_for_rbr) - restore_empty_query_table_list(thd->lex); + restore_empty_query_table_list(thd->lex); rgi->slave_close_thread_tables(thd); DBUG_RETURN(error); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 291cad89d79..87970ee11b4 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4591,7 +4591,72 @@ add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx, DBUG_RETURN(FALSE); } +/** + Extend the table_list to include foreign tables for prelocking. + + @param[in] thd Thread context. + @param[in] prelocking_ctx Prelocking context of the statement. + @param[in] table_list Table list element for table. + @param[in] sp Routine body. + @param[out] need_prelocking Set to TRUE if method detects that prelocking + required, not changed otherwise. + + @retval FALSE Success. + @retval TRUE Failure (OOM). +*/ +inline bool +prepare_fk_prelocking_list(THD *thd, Query_tables_list *prelocking_ctx, + TABLE_LIST *table_list, bool *need_prelocking, + uint8 op) +{ + DBUG_ENTER("prepare_fk_prelocking_list"); + List <FOREIGN_KEY_INFO> fk_list; + List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list); + FOREIGN_KEY_INFO *fk; + Query_arena *arena, backup; + TABLE *table= table_list->table; + + arena= thd->activate_stmt_arena_if_needed(&backup); + + table->file->get_parent_foreign_key_list(thd, &fk_list); + if (unlikely(thd->is_error())) + { + if (arena) + thd->restore_active_arena(arena, &backup); + return TRUE; + } + + *need_prelocking= TRUE; + + while ((fk= fk_list_it++)) + { + // FK_OPTION_RESTRICT and FK_OPTION_NO_ACTION only need read access + thr_lock_type lock_type; + + if ((op & (1 << TRG_EVENT_DELETE) && fk_modifies_child(fk->delete_method)) + || (op & (1 << TRG_EVENT_UPDATE) && fk_modifies_child(fk->update_method))) + lock_type= TL_WRITE_ALLOW_WRITE; + else + lock_type= TL_READ; + if (table_already_fk_prelocked(prelocking_ctx->query_tables, + fk->foreign_db, fk->foreign_table, + lock_type)) + continue; + + TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); + tl->init_one_table_for_prelocking(fk->foreign_db, + fk->foreign_table, + NULL, lock_type, + TABLE_LIST::PRELOCK_FK, + table_list->belong_to_view, op, + &prelocking_ctx->query_tables_last, + table_list->for_insert_data); + } + if (arena) + thd->restore_active_arena(arena, &backup); + DBUG_RETURN(FALSE); +} /** Defines how prelocking algorithm for DML statements should handle table list @@ -4638,53 +4703,20 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx, if (table->file->referenced_by_foreign_key()) { - List <FOREIGN_KEY_INFO> fk_list; - List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list); - FOREIGN_KEY_INFO *fk; - Query_arena *arena, backup; - - arena= thd->activate_stmt_arena_if_needed(&backup); - - table->file->get_parent_foreign_key_list(thd, &fk_list); - if (unlikely(thd->is_error())) - { - if (arena) - thd->restore_active_arena(arena, &backup); - DBUG_RETURN(TRUE); - } - - *need_prelocking= TRUE; - - while ((fk= fk_list_it++)) - { - // FK_OPTION_RESTRICT and FK_OPTION_NO_ACTION only need read access - uint8 op= table_list->trg_event_map; - thr_lock_type lock_type; - - if ((op & (1 << TRG_EVENT_DELETE) && fk_modifies_child(fk->delete_method)) - || (op & (1 << TRG_EVENT_UPDATE) && fk_modifies_child(fk->update_method))) - lock_type= TL_WRITE_ALLOW_WRITE; - else - lock_type= TL_READ; - - if (table_already_fk_prelocked(prelocking_ctx->query_tables, - fk->foreign_db, fk->foreign_table, - lock_type)) - continue; - - TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST)); - tl->init_one_table_for_prelocking(fk->foreign_db, - fk->foreign_table, - NULL, lock_type, - TABLE_LIST::PRELOCK_FK, - table_list->belong_to_view, op, - &prelocking_ctx->query_tables_last, - table_list->for_insert_data); - } - if (arena) - thd->restore_active_arena(arena, &backup); + if (prepare_fk_prelocking_list(thd, prelocking_ctx, table_list, + need_prelocking, + table_list->trg_event_map)) + return TRUE; } } + else if (table_list->slave_fk_event_map && + table->file->referenced_by_foreign_key()) + { + if (prepare_fk_prelocking_list(thd, prelocking_ctx, table_list, + need_prelocking, + table_list->slave_fk_event_map)) + return TRUE; + } /* Open any tables used by DEFAULT (like sequence tables) */ DBUG_PRINT("info", ("table: %p name: %s db: %s flags: %u", diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 1cc9a6a61d3..d8ceefb5238 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2015, Oracle and/or its affiliates. - Copyright (c) 2008, 2020, MariaDB Corporation. + Copyright (c) 2008, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1531,16 +1531,29 @@ void THD::reset_db(const LEX_CSTRING *new_db) /* Do operations that may take a long time */ -void THD::cleanup(void) +void THD::cleanup(bool have_mutex) { DBUG_ENTER("THD::cleanup"); DBUG_ASSERT(cleanup_done == 0); - set_killed(KILL_CONNECTION); + if (have_mutex) + set_killed_no_mutex(KILL_CONNECTION,0,0); + else + set_killed(KILL_CONNECTION); #ifdef WITH_WSREP if (wsrep_cs().state() != wsrep::client_state::s_none) { - wsrep_cs().cleanup(); + if (have_mutex) + { + mysql_mutex_assert_owner(static_cast<mysql_mutex_t*> + (m_wsrep_mutex.native())); + // Below wsrep-lib function will not acquire any mutexes + wsrep::unique_lock<wsrep::mutex> lock(m_wsrep_mutex, std::adopt_lock); + wsrep_cs().cleanup(lock); + lock.release(); + } + else + wsrep_cs().cleanup(); } wsrep_client_thread= false; #endif /* WITH_WSREP */ @@ -1614,16 +1627,38 @@ void THD::cleanup(void) void THD::free_connection() { DBUG_ASSERT(free_connection_done == 0); - my_free((char*) db.str); + /* Make sure threads are not available via server_threads. */ + assert_not_linked(); + + /* + Other threads may have a lock on THD::LOCK_thd_data or + THD::LOCK_thd_kill to ensure that this THD is not deleted + while they access it. The following mutex_lock ensures + that no one else is using this THD and it's now safe to + continue. + + For example consider KILL-statement execution on + sql_parse.cc kill_one_thread() that will use + THD::LOCK_thd_data to protect victim thread during + THD::awake(). + */ + mysql_mutex_lock(&LOCK_thd_data); + mysql_mutex_lock(&LOCK_thd_kill); + +#ifdef WITH_WSREP + delete wsrep_rgi; + wsrep_rgi= nullptr; +#endif /* WITH_WSREP */ + my_free(const_cast<char*>(db.str)); db= null_clex_str; #ifndef EMBEDDED_LIBRARY if (net.vio) vio_delete(net.vio); - net.vio= 0; + net.vio= nullptr; net_end(&net); #endif - if (!cleanup_done) - cleanup(); + if (!cleanup_done) + cleanup(true); // We have locked THD::LOCK_thd_kill ha_close_connection(this); plugin_thdvar_cleanup(this); mysql_audit_free_thd(this); @@ -1635,6 +1670,8 @@ void THD::free_connection() profiling.restart(); // Reset profiling #endif debug_sync_reset_thread(this); + mysql_mutex_unlock(&LOCK_thd_kill); + mysql_mutex_unlock(&LOCK_thd_data); } /* @@ -1690,24 +1727,10 @@ THD::~THD() if (!status_in_global) add_status_to_global(); - /* - Other threads may have a lock on LOCK_thd_kill to ensure that this - THD is not deleted while they access it. The following mutex_lock - ensures that no one else is using this THD and it's now safe to delete - */ - if (WSREP_NNULL(this)) mysql_mutex_lock(&LOCK_thd_data); - mysql_mutex_lock(&LOCK_thd_kill); - mysql_mutex_unlock(&LOCK_thd_kill); - if (WSREP_NNULL(this)) mysql_mutex_unlock(&LOCK_thd_data); - if (!free_connection_done) free_connection(); #ifdef WITH_WSREP - if (wsrep_rgi != NULL) { - delete wsrep_rgi; - wsrep_rgi = NULL; - } mysql_cond_destroy(&COND_wsrep_thd); #endif mdl_context.destroy(); @@ -3154,12 +3177,12 @@ static File create_file(THD *thd, char *path, sql_exchange *exchange, } /* Create the file world readable */ if ((file= mysql_file_create(key_select_to_file, - path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0) + path, 0644, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0) return file; #ifdef HAVE_FCHMOD - (void) fchmod(file, 0666); // Because of umask() + (void) fchmod(file, 0644); // Because of umask() #else - (void) chmod(path, 0666); + (void) chmod(path, 0644); #endif if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME))) { diff --git a/sql/sql_class.h b/sql/sql_class.h index fa29f187683..4532c69e8e1 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3463,7 +3463,7 @@ public: void update_all_stats(); void update_stats(void); void change_user(void); - void cleanup(void); + void cleanup(bool have_mutex=false); void cleanup_after_query(); void free_connection(); void reset_for_reuse(); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index f26ee27df42..be91e23ef58 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2027,6 +2027,8 @@ int write_record(THD *thd, TABLE *table, COPY_INFO *info, select_result *sink) if (likely(!error)) { info->deleted++; + if (!table->file->has_transactions()) + thd->transaction->stmt.modified_non_trans_table= TRUE; if (table->versioned(VERS_TIMESTAMP)) { store_record(table, record[2]); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index dc5449d0ab4..f93db3d00de 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -5467,14 +5467,14 @@ void st_select_lex::set_explain_type(bool on_the_fly) /* pos_in_table_list=NULL for e.g. post-join aggregation JOIN_TABs. */ - if (!tab->table); - else if (const TABLE_LIST *pos= tab->table->pos_in_table_list) + if (!(tab->table && tab->table->pos_in_table_list)) + continue; + TABLE_LIST *tbl= tab->table->pos_in_table_list; + if (tbl->with && tbl->with->is_recursive && + tbl->is_with_table_recursive_reference()) { - if (pos->with && pos->with->is_recursive) - { - uses_cte= true; - break; - } + uses_cte= true; + break; } } if (uses_cte) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index c3998b62c89..d976e75843a 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. - Copyright (c) 2008, 2020, MariaDB + Copyright (c) 2008, 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 @@ -1140,6 +1140,14 @@ static bool wsrep_tables_accessible_when_detached(const TABLE_LIST *tables) } return true; } + +static bool wsrep_command_no_result(char command) +{ + return (command == COM_STMT_PREPARE || + command == COM_STMT_FETCH || + command == COM_STMT_SEND_LONG_DATA || + command == COM_STMT_CLOSE); +} #endif /* WITH_WSREP */ #ifndef EMBEDDED_LIBRARY static enum enum_server_command fetch_command(THD *thd, char *packet) @@ -1278,12 +1286,21 @@ bool do_command(THD *thd) #ifdef WITH_WSREP DEBUG_SYNC(thd, "wsrep_before_before_command"); /* - Aborted by background rollbacker thread. - Handle error here and jump straight to out + If this command does not return a result, then we + instruct wsrep_before_command() to skip result handling. + This causes BF aborted transaction to roll back but keep + the error state until next command which is able to return + a result to the client. */ - if (unlikely(wsrep_service_started) && wsrep_before_command(thd)) + if (unlikely(wsrep_service_started) && + wsrep_before_command(thd, wsrep_command_no_result(command))) { - thd->store_globals(); + /* + Aborted by background rollbacker thread. + Handle error here and jump straight to out. + Notice that thd->store_globals() is called + in wsrep_before_command(). + */ WSREP_LOG_THD(thd, "enter found BF aborted"); DBUG_ASSERT(!thd->mdl_context.has_locks()); DBUG_ASSERT(!thd->get_stmt_da()->is_set()); @@ -2269,20 +2286,12 @@ dispatch_end: */ if (unlikely(wsrep_service_started)) { - /* - BF aborted before sending response back to client - */ if (thd->killed == KILL_QUERY) { WSREP_DEBUG("THD is killed at dispatch_end"); } wsrep_after_command_before_result(thd); - if (wsrep_current_error(thd) && - !(command == COM_STMT_PREPARE || - command == COM_STMT_FETCH || - command == COM_STMT_SEND_LONG_DATA || - command == COM_STMT_CLOSE - )) + if (wsrep_current_error(thd) && !wsrep_command_no_result(command)) { /* todo: Pass wsrep client state current error to override */ wsrep_override_error(thd, wsrep_current_error(thd), diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 285846558d2..864aaec180c 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2002, 2015, Oracle and/or its affiliates. - Copyright (c) 2008, 2020, MariaDB + Copyright (c) 2008, 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 @@ -117,6 +117,8 @@ When one supplies long data for a placeholder: #include <mysql.h> #else #include <mysql_com.h> +/* Constants defining bits in parameter type flags. Flags are read from high byte of short value */ +static const uint PARAMETER_FLAG_UNSIGNED= 128U << 8; #endif #include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL #include "sql_handler.h" @@ -127,9 +129,6 @@ When one supplies long data for a placeholder: #include "wsrep_trans_observer.h" #endif /* WITH_WSREP */ -/* Constants defining bits in parameter type flags. Flags are read from high byte of short value */ -static const uint PARAMETER_FLAG_UNSIGNED = 128U << 8; - /** A result class used to send cursor rows using the binary protocol. */ diff --git a/sql/sql_update.cc b/sql/sql_update.cc index d0956ec8bd1..49d73657689 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -2487,6 +2487,7 @@ int multi_update::send_data(List<Item> ¬_used_values) { TABLE_LIST *cur_table; DBUG_ENTER("multi_update::send_data"); + int error= 0; for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local) { @@ -2533,7 +2534,6 @@ int multi_update::send_data(List<Item> ¬_used_values) found++; if (!can_compare_record || compare_record(table)) { - int error; if ((error= cur_table->view_check_option(thd, ignore)) != VIEW_CHECK_OK) @@ -2616,7 +2616,6 @@ error: } else { - int error; TABLE *tmp_table= tmp_tables[offset]; if (copy_funcs(tmp_table_param[offset].items_to_copy, thd)) DBUG_RETURN(1); diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 44d29c5da0b..12b6ea96182 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -6051,8 +6051,10 @@ static Sys_var_uint Sys_wsrep_gtid_domain_id( "wsrep_gtid_domain_id", "When wsrep_gtid_mode is set, this value is " "used as gtid_domain_id for galera transactions and also copied to the " "joiner nodes during state transfer. It is ignored, otherwise.", - GLOBAL_VAR(wsrep_gtid_server.domain_id), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(0, UINT_MAX32), DEFAULT(0), BLOCK_SIZE(1)); + GLOBAL_VAR(wsrep_gtid_domain_id), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, UINT_MAX32), DEFAULT(0), BLOCK_SIZE(1), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(wsrep_gtid_domain_id_update)); static Sys_var_ulonglong Sys_wsrep_gtid_seq_no( "wsrep_gtid_seq_no", diff --git a/sql/table.h b/sql/table.h index 48a08c24de5..c48eae94df8 100644 --- a/sql/table.h +++ b/sql/table.h @@ -2547,8 +2547,12 @@ struct TABLE_LIST Indicates what triggers we need to pre-load for this TABLE_LIST when opening an associated TABLE. This is filled after the parsed tree is created. + + slave_fk_event_map is filled on the slave side with bitmaps value + representing row-based event operation to help find and prelock + possible FK constrain-related child tables. */ - uint8 trg_event_map; + uint8 trg_event_map, slave_fk_event_map; /* TRUE <=> this table is a const one and was optimized away. */ bool optimized_away; diff --git a/sql/wsrep_client_service.cc b/sql/wsrep_client_service.cc index 24e1e198507..3131e753e60 100644 --- a/sql/wsrep_client_service.cc +++ b/sql/wsrep_client_service.cc @@ -73,7 +73,7 @@ bool Wsrep_client_service::interrupted( Locking order is: 1) LOCK_thd_data 2) LOCK_thd_kill */ - mysql_mutex_assert_owner(static_cast<mysql_mutex_t*>(lock.mutex().native())); + mysql_mutex_assert_owner(static_cast<mysql_mutex_t*>(lock.mutex()->native())); mysql_mutex_lock(&m_thd->LOCK_thd_kill); bool ret= (m_thd->killed != NOT_KILLED); if (ret) diff --git a/sql/wsrep_condition_variable.h b/sql/wsrep_condition_variable.h index 4412154e67b..6ad53a3086c 100644 --- a/sql/wsrep_condition_variable.h +++ b/sql/wsrep_condition_variable.h @@ -44,7 +44,7 @@ public: void wait(wsrep::unique_lock<wsrep::mutex>& lock) { - mysql_mutex_t* mutex= static_cast<mysql_mutex_t*>(lock.mutex().native()); + mysql_mutex_t* mutex= static_cast<mysql_mutex_t*>(lock.mutex()->native()); mysql_cond_wait(&m_cond, mutex); } private: diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 50650280a2a..8118822d595 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1,5 +1,5 @@ /* Copyright 2008-2015 Codership Oy <http://www.codership.com> - Copyright (c) 2020, MariaDB + Copyright (c) 2020, 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 @@ -110,6 +110,7 @@ ulong wsrep_mysql_replication_bundle; bool wsrep_gtid_mode; // Enable WSREP native GTID support Wsrep_gtid_server wsrep_gtid_server; +uint wsrep_gtid_domain_id=0; // Domain id on above structure /* Other configuration variables and their default values. */ my_bool wsrep_incremental_data_collection= 0; // Incremental data collection @@ -319,29 +320,31 @@ wsp::node_status local_status; */ Wsrep_schema *wsrep_schema= 0; -static void wsrep_log_cb(wsrep::log::level level, const char *msg) +static void wsrep_log_cb(wsrep::log::level level, + const char*, const char *msg) { /* Silence all wsrep related logging from lib and provider if wsrep is not enabled. */ - if (WSREP_ON) - { - switch (level) { - case wsrep::log::info: - sql_print_information("WSREP: %s", msg); - break; - case wsrep::log::warning: - sql_print_warning("WSREP: %s", msg); - break; - case wsrep::log::error: - sql_print_error("WSREP: %s", msg); + if (!WSREP_ON) return; + + switch (level) { + case wsrep::log::info: + WSREP_INFO("%s", msg); + break; + case wsrep::log::warning: + WSREP_WARN("%s", msg); + break; + case wsrep::log::error: + WSREP_ERROR("%s", msg); + break; + case wsrep::log::debug: + WSREP_DEBUG("%s", msg); + break; + case wsrep::log::unknown: + WSREP_UNKNOWN("%s", msg); break; - case wsrep::log::debug: - if (wsrep_debug) sql_print_information ("[Debug] WSREP: %s", msg); - default: - break; - } } } @@ -786,6 +789,7 @@ int wsrep_init_server() void wsrep_init_globals() { + wsrep_gtid_server.domain_id= wsrep_gtid_domain_id; wsrep_init_sidno(Wsrep_server_state::instance().connected_gtid().id()); wsrep_init_gtid(); /* Recover last written wsrep gtid */ diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index eb32636d67f..adfd3cec626 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -1,5 +1,5 @@ /* Copyright 2008-2017 Codership Oy <http://www.codership.com> - Copyright (c) 2020, MariaDB + Copyright (c) 2020, 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 @@ -101,6 +101,7 @@ extern ulong wsrep_running_rollbacker_threads; extern bool wsrep_new_cluster; extern bool wsrep_gtid_mode; extern my_bool wsrep_strict_ddl; +extern uint wsrep_gtid_domain_id; enum enum_wsrep_reject_types { WSREP_REJECT_NONE, /* nothing rejected */ @@ -254,10 +255,11 @@ void WSREP_LOG(void (*fun)(const char* fmt, ...), const char* fmt, ...); #define WSREP_INFO(...) sql_print_information( "WSREP: " __VA_ARGS__) #define WSREP_WARN(...) sql_print_warning( "WSREP: " __VA_ARGS__) #define WSREP_ERROR(...) sql_print_error( "WSREP: " __VA_ARGS__) +#define WSREP_UNKNOWN(fmt, ...) WSREP_ERROR("UNKNOWN: " fmt, ##__VA_ARGS__) #define WSREP_LOG_CONFLICT_THD(thd, role) \ - sql_print_information( \ - "WSREP: %s: \n " \ + WSREP_INFO( \ + "%s: \n " \ " THD: %lu, mode: %s, state: %s, conflict: %s, seqno: %lld\n " \ " SQL: %s", \ role, \ @@ -272,12 +274,12 @@ void WSREP_LOG(void (*fun)(const char* fmt, ...), const char* fmt, ...); #define WSREP_LOG_CONFLICT(bf_thd, victim_thd, bf_abort) \ if (wsrep_debug || wsrep_log_conflicts) \ { \ - sql_print_information( "WSREP: cluster conflict due to %s for threads:", \ - (bf_abort) ? "high priority abort" : "certification failure" \ + WSREP_INFO("cluster conflict due to %s for threads:", \ + (bf_abort) ? "high priority abort" : "certification failure" \ ); \ if (bf_thd) WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread"); \ if (victim_thd) WSREP_LOG_CONFLICT_THD(victim_thd, "Victim thread"); \ - sql_print_information("WSREP: context: %s:%d", __FILE__, __LINE__); \ + WSREP_INFO("context: %s:%d", __FILE__, __LINE__); \ } #define WSREP_PROVIDER_EXISTS \ diff --git a/sql/wsrep_server_service.cc b/sql/wsrep_server_service.cc index 32b585871d4..b51d7d2197f 100644 --- a/sql/wsrep_server_service.cc +++ b/sql/wsrep_server_service.cc @@ -162,16 +162,19 @@ void Wsrep_server_service::log_message(enum wsrep::log::level level, switch (level) { case wsrep::log::debug: - sql_print_information("debug: %s", message); + WSREP_DEBUG("%s", message); break; case wsrep::log::info: - sql_print_information("%s", message); + WSREP_INFO("%s", message); break; case wsrep::log::warning: - sql_print_warning("%s", message); + WSREP_WARN("%s", message); break; case wsrep::log::error: - sql_print_error("%s", message); + WSREP_ERROR("%s", message); + break; + case wsrep::log::unknown: + WSREP_UNKNOWN("%s", message); break; } } diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 25992459060..ffba339de4a 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -29,6 +29,7 @@ #include "wsrep_utils.h" #include "wsrep_xid.h" #include "wsrep_thd.h" +#include "wsrep_mysqld.h" #include <cstdio> #include <cstdlib> @@ -596,6 +597,7 @@ static void* sst_joiner_thread (void* a) goto err; } else { wsrep_gtid_server.domain_id= (uint32) domain_id; + wsrep_gtid_domain_id= (uint32)domain_id; } } } diff --git a/sql/wsrep_trans_observer.h b/sql/wsrep_trans_observer.h index 35b93cb4bf5..e9b4ab8af15 100644 --- a/sql/wsrep_trans_observer.h +++ b/sql/wsrep_trans_observer.h @@ -476,12 +476,18 @@ wsrep_wait_rollback_complete_and_acquire_ownership(THD *thd) DBUG_VOID_RETURN; } -static inline int wsrep_before_command(THD* thd) +static inline int wsrep_before_command(THD* thd, bool keep_command_error) { return (thd->wsrep_cs().state() != wsrep::client_state::s_none && !thd->internal_transaction() ? - thd->wsrep_cs().before_command() : 0); + thd->wsrep_cs().before_command(keep_command_error) : 0); +} + +static inline int wsrep_before_command(THD* thd) +{ + return wsrep_before_command(thd, false); } + /* Called after each command. diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index 97aca456369..6cbe5f6539a 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -944,3 +944,11 @@ void wsrep_free_status (THD* thd) { thd->wsrep_status_vars.clear(); } + +bool wsrep_gtid_domain_id_update(sys_var* self, THD *thd, enum_var_type) +{ + WSREP_DEBUG("wsrep_gtid_domain_id_update: %llu", + wsrep_gtid_domain_id); + wsrep_gtid_server.domain_id= wsrep_gtid_domain_id; + return false; +} diff --git a/sql/wsrep_var.h b/sql/wsrep_var.h index 810ed4f3dd7..fb23182dbf2 100644 --- a/sql/wsrep_var.h +++ b/sql/wsrep_var.h @@ -105,6 +105,7 @@ extern bool wsrep_debug_update UPDATE_ARGS; extern bool wsrep_gtid_seq_no_check CHECK_ARGS; +extern bool wsrep_gtid_domain_id_update UPDATE_ARGS; #else /* WITH_WSREP */ #define wsrep_provider_init(X) diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index a1b1909be48..8f9186fb923 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -2,7 +2,7 @@ Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2014, 2020, MariaDB Corporation. +Copyright (c) 2014, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -3831,12 +3831,13 @@ btr_discard_only_page_on_level( mtr_t* mtr) /*!< in: mtr */ { ulint page_level = 0; - trx_id_t max_trx_id; ut_ad(!index->is_dummy); /* Save the PAGE_MAX_TRX_ID from the leaf page. */ - max_trx_id = page_get_max_trx_id(buf_block_get_frame(block)); + const trx_id_t max_trx_id = page_get_max_trx_id(block->frame); + const rec_t* r = page_rec_get_next(page_get_infimum_rec(block->frame)); + ut_ad(rec_is_metadata(r, *index) == index->is_instant()); while (block->page.id().page_no() != dict_index_get_page(index)) { btr_cur_t cursor; @@ -3892,9 +3893,6 @@ btr_discard_only_page_on_level( rec_offs* offsets = NULL; if (index->table->instant || index->must_avoid_clear_instant_add()) { - const rec_t* r = page_rec_get_next(page_get_infimum_rec( - block->frame)); - ut_ad(rec_is_metadata(r, *index) == index->is_instant()); if (!rec_is_metadata(r, *index)) { } else if (!index->table->instant || rec_is_alter_metadata(r, *index)) { diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index 3faba416ee4..02aaa76de8b 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -410,7 +410,6 @@ buf_block_t* buf_LRU_get_free_block(bool have_mutex) mysql_mutex_assert_owner(&buf_pool.mutex); goto got_mutex; } -loop: mysql_mutex_lock(&buf_pool.mutex); got_mutex: buf_LRU_check_size_of_non_data_objects(); @@ -493,11 +492,10 @@ not_found: ++flush_failures; } - srv_stats.buf_pool_wait_free.inc(); - n_iterations++; - - goto loop; + mysql_mutex_lock(&buf_pool.mutex); + buf_pool.stat.LRU_waits++; + goto got_mutex; } /** Move the LRU_old pointer so that the length of the old blocks list diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index a20085d9c1d..764fd64d9fe 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4,7 +4,7 @@ Copyright (c) 2000, 2020, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2013, 2020, MariaDB Corporation. +Copyright (c) 2013, 2021, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -946,8 +946,7 @@ static SHOW_VAR innodb_status_variables[]= { &export_vars.innodb_buffer_pool_read_requests, SHOW_SIZE_T}, {"buffer_pool_reads", &export_vars.innodb_buffer_pool_reads, SHOW_SIZE_T}, - {"buffer_pool_wait_free", - &export_vars.innodb_buffer_pool_wait_free, SHOW_SIZE_T}, + {"buffer_pool_wait_free", &buf_pool.stat.LRU_waits, SHOW_SIZE_T}, {"buffer_pool_write_requests", &export_vars.innodb_buffer_pool_write_requests, SHOW_SIZE_T}, {"checkpoint_age", &export_vars.innodb_checkpoint_age, SHOW_SIZE_T}, @@ -4432,7 +4431,7 @@ static int innobase_close_connection(handlerton *hton, THD *thd) return 0; } -UNIV_INTERN void lock_cancel_waiting_and_release(lock_t* lock); +void lock_cancel_waiting_and_release(lock_t *lock); /** Cancel any pending lock request associated with the current THD. @sa THD::awake() @sa ha_kill_query() */ @@ -4442,6 +4441,7 @@ static void innobase_kill_query(handlerton*, THD *thd, enum thd_kill_levels) if (trx_t* trx= thd_to_trx(thd)) { + ut_ad(trx->mysql_thd == thd); #ifdef WITH_WSREP if (trx->is_wsrep() && wsrep_thd_is_aborting(thd)) /* if victim has been signaled by BF thread and/or aborting is already @@ -4450,28 +4450,13 @@ static void innobase_kill_query(handlerton*, THD *thd, enum thd_kill_levels) DBUG_VOID_RETURN; #endif /* WITH_WSREP */ lock_sys.mutex_lock(); - trx_sys.trx_list.freeze(); - trx->mutex.wr_lock(); - /* It is possible that innobase_close_connection() is concurrently - being executed on our victim. Even if the trx object is later - reused for another client connection or a background transaction, - its trx->mysql_thd will differ from our thd. - - trx_sys.trx_list is thread-safe. It's freezed to 'protect' - trx_t. However, trx_t::commit_in_memory() changes a trx_t::state - of autocommit non-locking transactions without any protection. - - At this point, trx may have been reallocated for another client - connection, or for a background operation. In that case, either - trx_t::state or trx_t::mysql_thd should not match our expectations. */ - bool cancel= trx->mysql_thd == thd && trx->state == TRX_STATE_ACTIVE && - !trx->lock.was_chosen_as_deadlock_victim; - trx_sys.trx_list.unfreeze(); - if (!cancel); - else if (lock_t *lock= trx->lock.wait_lock) + if (lock_t *lock= trx->lock.wait_lock) + { + trx->mutex.wr_lock(); lock_cancel_waiting_and_release(lock); + trx->mutex.wr_unlock(); + } lock_sys.mutex_unlock(); - trx->mutex.wr_unlock(); } DBUG_VOID_RETURN; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 459be7e22a2..9cd65526930 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -10070,6 +10070,54 @@ innobase_page_compression_try( DBUG_RETURN(false); } +static +void +dict_stats_try_drop_table(THD *thd, const table_name_t &name, + const LEX_CSTRING &table_name) +{ + char errstr[1024]; + if (dict_stats_drop_table(name.m_name, errstr, sizeof(errstr)) != DB_SUCCESS) + { + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_ALTER_INFO, + "Deleting persistent statistics" + " for table '%s' in InnoDB failed: %s", + table_name.str, + errstr); + } +} + +/** Evict the table from cache and reopen it. Drop outdated statistics. +@param thd mariadb THD entity +@param table innodb table +@param table_name user-friendly table name for errors +@param ctx ALTER TABLE context +@return newly opened table */ +static dict_table_t *innobase_reload_table(THD *thd, dict_table_t *table, + const LEX_CSTRING &table_name, + ha_innobase_inplace_ctx &ctx) +{ + char *tb_name= strdup(table->name.m_name); + dict_table_close(table, true, false); + + if (ctx.is_instant()) + { + for (auto i = ctx.old_n_v_cols; i--; ) + { + ctx.old_v_cols[i].~dict_v_col_t(); + const_cast<unsigned&>(ctx.old_n_v_cols) = 0; + } + } + + dict_sys.remove(table); + table= dict_table_open_on_name(tb_name, TRUE, TRUE, + DICT_ERR_IGNORE_FK_NOKEY); + + /* Drop outdated table stats. */ + dict_stats_try_drop_table(thd, table->name, table_name); + free(tb_name); + return table; +} + /** Commit the changes made during prepare_inplace_alter_table() and inplace_alter_table() inside the data dictionary tables, when not rebuilding the table. @@ -11186,44 +11234,19 @@ foreign_fail: Currently dict_load_column_low() is the only place where num_base for virtual columns is assigned to nonzero. */ if (ctx0->num_to_drop_vcol || ctx0->num_to_add_vcol + || (ctx0->new_table->n_v_cols && !new_clustered + && (ha_alter_info->alter_info->drop_list.elements + || ha_alter_info->alter_info->create_list.elements)) || (ctx0->is_instant() && m_prebuilt->table->n_v_cols && ha_alter_info->handler_flags & ALTER_STORED_COLUMN_ORDER)) { - /* FIXME: this workaround does not seem to work with - partitioned tables */ DBUG_ASSERT(ctx0->old_table->get_ref_count() == 1); - trx_commit_for_mysql(m_prebuilt->trx); - char tb_name[NAME_LEN * 2 + 1 + 1]; - strcpy(tb_name, m_prebuilt->table->name.m_name); - dict_table_close(m_prebuilt->table, true, false); - if (ctx0->is_instant()) { - for (unsigned i = ctx0->old_n_v_cols; i--; ) { - ctx0->old_v_cols[i].~dict_v_col_t(); - } - const_cast<unsigned&>(ctx0->old_n_v_cols) = 0; - } - dict_sys.remove(m_prebuilt->table); - m_prebuilt->table = dict_table_open_on_name( - tb_name, TRUE, TRUE, DICT_ERR_IGNORE_FK_NOKEY); - - /* Drop outdated table stats. */ - char errstr[1024]; - if (dict_stats_drop_table( - m_prebuilt->table->name.m_name, - errstr, sizeof(errstr)) - != DB_SUCCESS) { - push_warning_printf( - m_user_thd, - Sql_condition::WARN_LEVEL_WARN, - ER_ALTER_INFO, - "Deleting persistent statistics" - " for table '%s' in" - " InnoDB failed: %s", - table->s->table_name.str, - errstr); - } + m_prebuilt->table = innobase_reload_table(m_user_thd, + m_prebuilt->table, + table->s->table_name, + *ctx0); row_mysql_unlock_data_dictionary(trx); trx->free(); @@ -11283,25 +11306,12 @@ foreign_fail: old copy of the table (which was renamed to ctx->tmp_name). */ - char errstr[1024]; - DBUG_ASSERT(0 == strcmp(ctx->old_table->name.m_name, ctx->tmp_name)); - if (dict_stats_drop_table( - ctx->new_table->name.m_name, - errstr, sizeof(errstr)) - != DB_SUCCESS) { - push_warning_printf( - m_user_thd, - Sql_condition::WARN_LEVEL_WARN, - ER_ALTER_INFO, - "Deleting persistent statistics" - " for rebuilt table '%s' in" - " InnoDB failed: %s", - table->s->table_name.str, - errstr); - } + dict_stats_try_drop_table(m_user_thd, + ctx->new_table->name, + table->s->table_name); DBUG_EXECUTE_IF("ib_ddl_crash_before_commit", DBUG_SUICIDE();); diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index bcb75975244..ad2997b2c94 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -1279,6 +1279,8 @@ struct buf_pool_stat_t{ young because the first access was not long enough ago, in buf_page_peek_if_too_old() */ + /** number of waits for eviction; writes protected by buf_pool.mutex */ + ulint LRU_waits; ulint LRU_bytes; /*!< LRU size in bytes */ ulint flush_list_bytes;/*!< flush_list size in bytes */ }; @@ -1710,7 +1712,7 @@ public: static constexpr uint32_t READ_AHEAD_PAGES= 64; /** Buffer pool mutex */ - mysql_mutex_t mutex; + MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) mysql_mutex_t mutex; /** Number of pending LRU flush. */ Atomic_counter<ulint> n_flush_LRU; /** broadcast when n_flush_LRU reaches 0; protected by mutex */ @@ -1857,7 +1859,7 @@ public: /** mutex protecting flush_list, buf_page_t::set_oldest_modification() and buf_page_t::list pointers when !oldest_modification() */ - mysql_mutex_t flush_list_mutex; + MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) mysql_mutex_t flush_list_mutex; /** "hazard pointer" for flush_list scans; protected by flush_list_mutex */ FlushHp flush_hp; /** modified blocks (a subset of LRU) */ diff --git a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h index af282b378ca..e77857f40c3 100644 --- a/storage/innobase/include/que0que.h +++ b/storage/innobase/include/que0que.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -288,7 +288,6 @@ que_fork_scheduler_round_robin( /** Query thread states */ enum que_thr_state_t { QUE_THR_RUNNING, - QUE_THR_PROCEDURE_WAIT, /** in selects this means that the thread is at the end of its result set (or start, in case of a scroll cursor); in other statements, this means the thread has done its task */ diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 9e234e6763f..325c3af6591 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -112,11 +112,6 @@ struct srv_stats_t /** Store the number of write requests issued */ ulint_ctr_1_t buf_pool_write_requests; - /** Store the number of times when we had to wait for a free page - in the buffer pool. It happens when the buffer pool is full and we - need to make a flush, in order to be able to read or create a page. */ - ulint_ctr_1_t buf_pool_wait_free; - /** Number of buffer pool reads that led to the reading of a disk page */ ulint_ctr_1_t buf_pool_reads; @@ -759,8 +754,7 @@ struct export_var_t{ ulint innodb_buffer_pool_pages_old; ulint innodb_buffer_pool_read_requests; /*!< buf_pool.stat.n_page_gets */ ulint innodb_buffer_pool_reads; /*!< srv_buf_pool_reads */ - ulint innodb_buffer_pool_wait_free; /*!< srv_buf_pool_wait_free */ - ulint innodb_buffer_pool_write_requests;/*!< srv_buf_pool_write_requests */ + ulint innodb_buffer_pool_write_requests;/*!< srv_stats.buf_pool_write_requests */ ulint innodb_buffer_pool_read_ahead_rnd;/*!< srv_read_ahead_rnd */ ulint innodb_buffer_pool_read_ahead; /*!< srv_read_ahead */ ulint innodb_buffer_pool_read_ahead_evicted;/*!< srv_read_ahead evicted*/ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 97f1a670c6c..22c2f2bfe00 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -626,6 +626,20 @@ static void wsrep_assert_no_bf_bf_wait( if (UNIV_LIKELY(!wsrep_thd_is_BF(lock_rec2->trx->mysql_thd, FALSE))) return; + /* if BF - BF order is honored, we can keep trx1 waiting for the lock */ + if (wsrep_thd_order_before(trx1->mysql_thd, lock_rec2->trx->mysql_thd)) + return; + + /* avoiding BF-BF conflict assert, if victim is already aborting + or rolling back for replaying + */ + wsrep_thd_LOCK(lock_rec2->trx->mysql_thd); + if (wsrep_thd_is_aborting(lock_rec2->trx->mysql_thd)) { + wsrep_thd_UNLOCK(lock_rec2->trx->mysql_thd); + return; + } + wsrep_thd_UNLOCK(lock_rec2->trx->mysql_thd); + mtr_t mtr; if (lock_rec1) { @@ -1367,11 +1381,6 @@ lock_rec_create_low( c_lock->trx->mutex.wr_unlock(); - if (UNIV_UNLIKELY(wsrep_debug)) { - wsrep_report_bf_lock_wait(trx->mysql_thd, trx->id); - wsrep_report_bf_lock_wait(c_lock->trx->mysql_thd, c_lock->trx->id); - } - /* have to bail out here to avoid lock_set_lock... */ return(lock); } @@ -5585,6 +5594,7 @@ lock_cancel_waiting_and_release( que_thr_t* thr; lock_sys.mutex_assert_locked(); + ut_ad(lock->trx->state == TRX_STATE_ACTIVE); lock->trx->lock.cancel = true; diff --git a/storage/innobase/que/que0que.cc b/storage/innobase/que/que0que.cc index a4de6d3bf9d..db48c9bb19f 100644 --- a/storage/innobase/que/que0que.cc +++ b/storage/innobase/que/que0que.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2020, MariaDB Corporation. +Copyright (c) 2017, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -333,7 +333,6 @@ que_fork_start_command( case QUE_THR_RUNNING: case QUE_THR_LOCK_WAIT: - case QUE_THR_PROCEDURE_WAIT: ut_error; } } diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc index e98448624b3..ee7bf37f667 100644 --- a/storage/innobase/rem/rem0rec.cc +++ b/storage/innobase/rem/rem0rec.cc @@ -2735,8 +2735,23 @@ wsrep_rec_get_foreign_key( break; case DATA_BLOB: case DATA_BINARY: + case DATA_FIXBINARY: + case DATA_GEOMETRY: memcpy(buf, data, len); break; + + case DATA_FLOAT: + { + float f = mach_float_read(data); + memcpy(buf, &f, sizeof(float)); + } + break; + case DATA_DOUBLE: + { + double d = mach_double_read(data); + memcpy(buf, &d, sizeof(double)); + } + break; default: break; } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 07394d9d91a..f5992b877a3 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2000, 2018, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2020, MariaDB Corporation. +Copyright (c) 2015, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -4296,6 +4296,7 @@ row_rename_table_for_mysql( , FALSE, trx); if (err != DB_SUCCESS) { + ut_ad(err != DB_DUPLICATE_KEY); goto end; } diff --git a/storage/innobase/srv/srv0mon.cc b/storage/innobase/srv/srv0mon.cc index a8355036fc2..febbfa089f6 100644 --- a/storage/innobase/srv/srv0mon.cc +++ b/storage/innobase/srv/srv0mon.cc @@ -2,7 +2,7 @@ Copyright (c) 2010, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2012, Facebook Inc. -Copyright (c) 2013, 2020, MariaDB Corporation. +Copyright (c) 2013, 2021, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -1501,7 +1501,7 @@ srv_mon_process_existing_counter( /* innodb_buffer_pool_wait_free */ case MONITOR_OVLD_BUF_POOL_WAIT_FREE: - value = srv_stats.buf_pool_wait_free; + value = buf_pool.stat.LRU_waits; break; /* innodb_buffer_pool_read_ahead */ diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index c48cfdd4f86..dd17b21831d 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -3,7 +3,7 @@ Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. -Copyright (c) 2013, 2020, MariaDB Corporation. +Copyright (c) 2013, 2021, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -1071,9 +1071,6 @@ srv_export_innodb_status(void) export_vars.innodb_buffer_pool_write_requests = srv_stats.buf_pool_write_requests; - export_vars.innodb_buffer_pool_wait_free = - srv_stats.buf_pool_wait_free; - export_vars.innodb_buffer_pool_reads = srv_stats.buf_pool_reads; export_vars.innodb_buffer_pool_read_ahead_rnd = diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 1d4452041c3..0f3316178c9 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -405,9 +405,11 @@ void trx_t::free() MEM_NOACCESS(&n_ref, sizeof n_ref); /* do not poison mutex */ MEM_NOACCESS(&id, sizeof id); - /* state is accessed by innobase_kill_connection() */ + MEM_NOACCESS(&state, sizeof state); MEM_NOACCESS(&is_recovered, sizeof is_recovered); - /* wsrep is accessed by innobase_kill_connection() */ +#ifdef WITH_WSREP + MEM_NOACCESS(&wsrep, sizeof wsrep); +#endif read_view.mem_noaccess(); MEM_NOACCESS(&lock, sizeof lock); MEM_NOACCESS(&op_info, sizeof op_info); @@ -425,7 +427,7 @@ void trx_t::free() MEM_NOACCESS(&start_time_micro, sizeof start_time_micro); MEM_NOACCESS(&commit_lsn, sizeof commit_lsn); MEM_NOACCESS(&table_id, sizeof table_id); - /* mysql_thd is accessed by innobase_kill_connection() */ + MEM_NOACCESS(&mysql_thd, sizeof mysql_thd); MEM_NOACCESS(&mysql_log_file_name, sizeof mysql_log_file_name); MEM_NOACCESS(&mysql_log_offset, sizeof mysql_log_offset); MEM_NOACCESS(&n_mysql_tables_in_use, sizeof n_mysql_tables_in_use); diff --git a/storage/rocksdb/build_rocksdb.cmake b/storage/rocksdb/build_rocksdb.cmake index 273de1cd9ca..5047e073751 100644 --- a/storage/rocksdb/build_rocksdb.cmake +++ b/storage/rocksdb/build_rocksdb.cmake @@ -109,8 +109,8 @@ if(NOT WIN32) endif() include(CheckCCompilerFlag) -# ppc64 or ppc64le -if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64") +# ppc64 or ppc64le or powerpc64 (BSD) +if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64|powerpc64") CHECK_C_COMPILER_FLAG("-maltivec" HAS_ALTIVEC) if(HAS_ALTIVEC) message(STATUS " HAS_ALTIVEC yes") diff --git a/wsrep-lib b/wsrep-lib -Subproject 41a6e9dad79c921134e44cf974b6b7ca3b84e53 +Subproject a93955ddeef5989505cbb3a9f8bb12434146256 |