Merge 10.4 into 10.5
This commit is contained in:
commit
8de233af81
@ -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"
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,3 @@
|
||||
connection node_1;
|
||||
connection node_2;
|
||||
connection node_2;
|
||||
connection node_1;
|
||||
connection node_1;
|
||||
|
@ -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;
|
||||
|
16
mysql-test/suite/galera/r/galera_bf_abort_ps.result
Normal file
16
mysql-test/suite/galera/r/galera_bf_abort_ps.result
Normal file
@ -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;
|
@ -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;
|
@ -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;
|
||||
|
@ -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;
|
||||
|
3
mysql-test/suite/galera/t/galera_bf_abort_ps.cnf
Normal file
3
mysql-test/suite/galera/t/galera_bf_abort_ps.cnf
Normal file
@ -0,0 +1,3 @@
|
||||
!include ../galera_2nodes.cnf
|
||||
[mysqltest]
|
||||
ps-protocol
|
34
mysql-test/suite/galera/t/galera_bf_abort_ps.test
Normal file
34
mysql-test/suite/galera/t/galera_bf_abort_ps.test
Normal file
@ -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;
|
@ -0,0 +1,7 @@
|
||||
!include ../galera_2nodes.cnf
|
||||
|
||||
[mysqld]
|
||||
thread-handling=pool-of-threads
|
||||
|
||||
[mysqltest]
|
||||
ps-protocol
|
54
mysql-test/suite/galera/t/galera_bf_abort_ps_threadpool.test
Normal file
54
mysql-test/suite/galera/t/galera_bf_abort_ps_threadpool.test
Normal file
@ -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;
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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 #
|
||||
@ -415,6 +413,22 @@ SET DEBUG_SYNC='RESET';
|
||||
--disconnect con2
|
||||
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
|
||||
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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';
|
||||
|
380
mysql-test/suite/rpl/r/rpl_row_vcol_crash.result
Normal file
380
mysql-test/suite/rpl/r/rpl_row_vcol_crash.result
Normal file
@ -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
|
425
mysql-test/suite/rpl/t/rpl_row_vcol_crash.test
Normal file
425
mysql-test/suite/rpl/t/rpl_row_vcol_crash.test
Normal file
@ -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
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 #
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
@ -5288,7 +5288,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;
|
||||
@ -5303,6 +5303,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
|
||||
@ -5393,27 +5395,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)
|
||||
|
||||
/*
|
||||
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;
|
||||
|
||||
for (TABLE_LIST *tables= rgi->tables_to_lock; tables;
|
||||
tables= tables->next_global)
|
||||
{
|
||||
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.
|
||||
|
||||
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)
|
||||
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)))
|
||||
{
|
||||
@ -5772,8 +5777,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))
|
||||
@ -5792,8 +5796,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);
|
||||
}
|
||||
|
122
sql/sql_base.cc
122
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",
|
||||
|
@ -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)))
|
||||
{
|
||||
|
@ -3421,7 +3421,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();
|
||||
|
@ -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]);
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
@ -1160,6 +1160,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
|
||||
|
||||
@ -1283,12 +1291,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());
|
||||
@ -2413,20 +2430,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),
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
@ -320,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -787,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 */
|
||||
|
@ -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
|
||||
@ -255,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, \
|
||||
@ -273,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 \
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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
|
||||
@ -3870,12 +3870,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;
|
||||
@ -3931,9 +3932,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)) {
|
||||
|
@ -4651,7 +4651,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() */
|
||||
@ -4661,6 +4661,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
|
||||
@ -4669,28 +4670,13 @@ static void innobase_kill_query(handlerton*, THD *thd, enum thd_kill_levels)
|
||||
DBUG_VOID_RETURN;
|
||||
#endif /* WITH_WSREP */
|
||||
lock_mutex_enter();
|
||||
trx_sys.trx_list.freeze();
|
||||
trx_mutex_enter(trx);
|
||||
/* 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_enter(trx);
|
||||
lock_cancel_waiting_and_release(lock);
|
||||
trx_mutex_exit(trx);
|
||||
}
|
||||
lock_mutex_exit();
|
||||
trx_mutex_exit(trx);
|
||||
}
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2005, 2019, Oracle and/or its affiliates. All Rights Reserved.
|
||||
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
|
||||
@ -10073,6 +10073,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.
|
||||
@ -11189,44 +11237,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();
|
||||
@ -11286,25 +11309,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(););
|
||||
|
@ -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 */
|
||||
|
@ -627,6 +627,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) {
|
||||
@ -1385,11 +1399,6 @@ lock_rec_create_low(
|
||||
|
||||
trx_mutex_exit(c_lock->trx);
|
||||
|
||||
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);
|
||||
}
|
||||
@ -5896,6 +5905,7 @@ lock_cancel_waiting_and_release(
|
||||
|
||||
ut_ad(lock_mutex_own());
|
||||
ut_ad(trx_mutex_own(lock->trx));
|
||||
ut_ad(lock->trx->state == TRX_STATE_ACTIVE);
|
||||
|
||||
lock->trx->lock.cancel = true;
|
||||
|
||||
|
@ -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
|
||||
@ -334,7 +334,6 @@ que_fork_start_command(
|
||||
|
||||
case QUE_THR_RUNNING:
|
||||
case QUE_THR_LOCK_WAIT:
|
||||
case QUE_THR_PROCEDURE_WAIT:
|
||||
ut_error;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -4335,6 +4335,8 @@ row_rename_table_for_mysql(
|
||||
"END;\n"
|
||||
, FALSE, trx);
|
||||
|
||||
ut_ad(err != DB_DUPLICATE_KEY);
|
||||
|
||||
/* SYS_TABLESPACES and SYS_DATAFILES need to be updated if
|
||||
the table is in a single-table tablespace. */
|
||||
if (err != DB_SUCCESS || !dict_table_is_file_per_table(table)) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2016, 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
|
||||
@ -407,9 +407,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);
|
||||
@ -427,7 +429,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);
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 41a6e9dad79c921134e44cf974b6b7ca3b84e538
|
||||
Subproject commit a93955ddeef5989505cbb3a9f8bb124341462569
|
Loading…
x
Reference in New Issue
Block a user