Merge 10.2 into 10.3 (except MDEV-17556)
The fix of MDEV-17556 (commit e25623e78a3efde05e30070dc7362f8dc0d8c459 and commit 61a362c9493df63dc588fcb71409537ae56ab9c8) has been omitted due to conflicts and will have to be applied separately later.
This commit is contained in:
commit
5a1a714187
@ -182,7 +182,7 @@ IF(WIN32)
|
|||||||
MARK_AS_ADVANCED(SIGNCODE)
|
MARK_AS_ADVANCED(SIGNCODE)
|
||||||
IF(SIGNCODE)
|
IF(SIGNCODE)
|
||||||
SET(SIGNTOOL_PARAMETERS
|
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)")
|
CACHE STRING "parameters for signtool (list)")
|
||||||
FIND_PROGRAM(SIGNTOOL_EXECUTABLE signtool
|
FIND_PROGRAM(SIGNTOOL_EXECUTABLE signtool
|
||||||
PATHS "$ENV{ProgramFiles}/Microsoft SDKs/Windows/v7.0A/bin"
|
PATHS "$ENV{ProgramFiles}/Microsoft SDKs/Windows/v7.0A/bin"
|
||||||
|
@ -9,6 +9,9 @@ CREATE TABLE t1 (f1 INTEGER) Engine=InnoDB;
|
|||||||
INSERT INTO t1 VALUES (1), (1);
|
INSERT INTO t1 VALUES (1), (1);
|
||||||
|
|
||||||
--connection node_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
|
||||||
|
|
||||||
SET SESSION wsrep_OSU_method = "RSU";
|
SET SESSION wsrep_OSU_method = "RSU";
|
||||||
--error ER_DUP_ENTRY
|
--error ER_DUP_ENTRY
|
||||||
ALTER TABLE t1 ADD PRIMARY KEY (f1);
|
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);
|
INSERT INTO t1 VALUES (1);
|
||||||
|
|
||||||
--connection node_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
|
||||||
|
|
||||||
ALTER TABLE t1 ADD COLUMN f2 INTEGER;
|
ALTER TABLE t1 ADD COLUMN f2 INTEGER;
|
||||||
INSERT INTO t1 VALUES (2, 3);
|
INSERT INTO t1 VALUES (2, 3);
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@ CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
|
|||||||
INSERT INTO t1 VALUES (1);
|
INSERT INTO t1 VALUES (1);
|
||||||
|
|
||||||
--connection node_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
|
||||||
|
|
||||||
ALTER TABLE t1 ADD COLUMN f2 INTEGER, LOCK=SHARED;
|
ALTER TABLE t1 ADD COLUMN f2 INTEGER, LOCK=SHARED;
|
||||||
|
|
||||||
--connection node_1
|
--connection node_1
|
||||||
|
@ -14,6 +14,9 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
|
|||||||
INSERT INTO t1 VALUES (1);
|
INSERT INTO t1 VALUES (1);
|
||||||
|
|
||||||
--connection node_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;
|
TRUNCATE TABLE t1;
|
||||||
SELECT COUNT(*) = 0 FROM t1;
|
SELECT COUNT(*) = 0 FROM t1;
|
||||||
|
|
||||||
|
@ -67,6 +67,9 @@ CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
|
|||||||
INSERT INTO t1 VALUES (2);
|
INSERT INTO t1 VALUES (2);
|
||||||
|
|
||||||
--connection node_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;
|
TRUNCATE TABLE t1;
|
||||||
|
|
||||||
SELECT COUNT(*) = 0 FROM t1;
|
SELECT COUNT(*) = 0 FROM t1;
|
||||||
|
@ -227,6 +227,7 @@ set global server_audit_logging= on;
|
|||||||
disconnect cn1;
|
disconnect cn1;
|
||||||
drop user user1@localhost;
|
drop user user1@localhost;
|
||||||
set global server_audit_events='';
|
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 IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
|
||||||
CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd';
|
CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd';
|
||||||
connect(localhost,plug,plug_dest,test,MYSQL_PORT,MYSQL_SOCK);
|
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_now OFF
|
||||||
server_audit_file_rotate_size 1000000
|
server_audit_file_rotate_size 1000000
|
||||||
server_audit_file_rotations 9
|
server_audit_file_rotations 9
|
||||||
server_audit_incl_users root
|
server_audit_incl_users root, plug_dest
|
||||||
server_audit_logging ON
|
server_audit_logging ON
|
||||||
server_audit_mode 1
|
server_audit_mode 1
|
||||||
server_audit_output_type file
|
server_audit_output_type file
|
||||||
@ -419,6 +420,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,procs_priv,
|
|||||||
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv,
|
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,roles_mapping,
|
||||||
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_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,user,
|
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user,
|
||||||
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db,
|
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,tables_priv,
|
||||||
@ -442,6 +444,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,proxies_priv,
|
|||||||
TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'GRANT PROXY ON plug_dest TO plug',0
|
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,CONNECT,test,,0
|
||||||
TIME,HOSTNAME,plug,localhost,ID,0,PROXY_CONNECT,test,`plug_dest`@`%`,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,plug,localhost,ID,0,DISCONNECT,test,,0
|
||||||
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user,
|
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,user,
|
||||||
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db,
|
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db,
|
||||||
|
@ -173,6 +173,7 @@ source include/wait_until_count_sessions.inc;
|
|||||||
drop user user1@localhost;
|
drop user user1@localhost;
|
||||||
|
|
||||||
set global server_audit_events='';
|
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 IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
|
||||||
CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd';
|
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
|
@ -1580,22 +1580,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;
|
int result;
|
||||||
|
|
||||||
if (!name)
|
if (!name)
|
||||||
return 0;
|
return 0;
|
||||||
len= strlen(name);
|
|
||||||
|
|
||||||
if (take_lock)
|
if (take_lock)
|
||||||
flogger_mutex_lock(&lock_operations);
|
flogger_mutex_lock(&lock_operations);
|
||||||
|
|
||||||
if (incl_user_coll.n_users)
|
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)
|
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
|
else
|
||||||
result= 1;
|
result= 1;
|
||||||
|
|
||||||
@ -2136,7 +2141,9 @@ void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event_class == MYSQL_AUDIT_GENERAL_CLASS && FILTER(EVENT_QUERY) &&
|
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 *event =
|
||||||
(const struct mysql_event_general *) ev;
|
(const struct mysql_event_general *) ev;
|
||||||
@ -2156,7 +2163,8 @@ void auditing(MYSQL_THD thd, unsigned int event_class, const void *ev)
|
|||||||
{
|
{
|
||||||
const struct mysql_event_table *event =
|
const struct mysql_event_table *event =
|
||||||
(const struct mysql_event_table *) ev;
|
(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)
|
switch (event->event_subclass)
|
||||||
{
|
{
|
||||||
|
@ -11232,7 +11232,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
|
There was the same problem with MERGE MYISAM tables and so here we try to
|
||||||
go the same way.
|
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())
|
if (lex->first_not_own_table())
|
||||||
(*lex->first_not_own_table()->prev_global)= NULL;
|
(*lex->first_not_own_table()->prev_global)= NULL;
|
||||||
@ -11247,6 +11247,8 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
|
|||||||
TABLE* table;
|
TABLE* table;
|
||||||
DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)");
|
DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)");
|
||||||
int error= 0;
|
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
|
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
|
contain any data. In that case, we just remove all tables in the
|
||||||
@ -11337,27 +11339,29 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
|
|||||||
DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
|
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;
|
if (slave_run_triggers_for_rbr)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
tables->trg_event_map= new_trg_event_map;
|
tables->trg_event_map= new_trg_event_map;
|
||||||
lex->query_tables_last= &tables->next_global;
|
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)))
|
if (unlikely(open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0)))
|
||||||
{
|
{
|
||||||
@ -11707,8 +11711,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* remove trigger's tables */
|
/* 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 defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE)
|
||||||
if (WSREP(thd) && thd->wsrep_exec_mode == REPL_RECV)
|
if (WSREP(thd) && thd->wsrep_exec_mode == REPL_RECV)
|
||||||
@ -11727,8 +11730,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
|
|||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
|
|
||||||
err:
|
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);
|
rgi->slave_close_thread_tables(thd);
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
|
122
sql/sql_base.cc
122
sql/sql_base.cc
@ -4508,7 +4508,72 @@ add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx,
|
|||||||
DBUG_RETURN(FALSE);
|
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
|
Defines how prelocking algorithm for DML statements should handle table list
|
||||||
@ -4555,53 +4620,20 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
|
|||||||
|
|
||||||
if (table->file->referenced_by_foreign_key())
|
if (table->file->referenced_by_foreign_key())
|
||||||
{
|
{
|
||||||
List <FOREIGN_KEY_INFO> fk_list;
|
if (prepare_fk_prelocking_list(thd, prelocking_ctx, table_list,
|
||||||
List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list);
|
need_prelocking,
|
||||||
FOREIGN_KEY_INFO *fk;
|
table_list->trg_event_map))
|
||||||
Query_arena *arena, backup;
|
return TRUE;
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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) */
|
/* Open any tables used by DEFAULT (like sequence tables) */
|
||||||
DBUG_PRINT("info", ("table: %p name: %s db: %s flags: %u",
|
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) 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
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -1458,12 +1458,15 @@ void THD::reset_db(const LEX_CSTRING *new_db)
|
|||||||
|
|
||||||
/* Do operations that may take a long time */
|
/* Do operations that may take a long time */
|
||||||
|
|
||||||
void THD::cleanup(void)
|
void THD::cleanup(bool have_mutex)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("THD::cleanup");
|
DBUG_ENTER("THD::cleanup");
|
||||||
DBUG_ASSERT(cleanup_done == 0);
|
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 ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
|
#ifdef ENABLE_WHEN_BINLOG_WILL_BE_ABLE_TO_PREPARE
|
||||||
if (transaction.xid_state.xa_state == XA_PREPARED)
|
if (transaction.xid_state.xa_state == XA_PREPARED)
|
||||||
{
|
{
|
||||||
@ -1541,7 +1544,29 @@ void THD::cleanup(void)
|
|||||||
void THD::free_connection()
|
void THD::free_connection()
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(free_connection_done == 0);
|
DBUG_ASSERT(free_connection_done == 0);
|
||||||
my_free((char*) db.str);
|
/* Check that we have already called thd->unlink() */
|
||||||
|
DBUG_ASSERT(prev == 0 && next == 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
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= 0;
|
||||||
|
#endif /* WITH_WSREP */
|
||||||
|
my_free(const_cast<char*>(db.str));
|
||||||
db= null_clex_str;
|
db= null_clex_str;
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
if (net.vio)
|
if (net.vio)
|
||||||
@ -1549,8 +1574,8 @@ void THD::free_connection()
|
|||||||
net.vio= 0;
|
net.vio= 0;
|
||||||
net_end(&net);
|
net_end(&net);
|
||||||
#endif
|
#endif
|
||||||
if (!cleanup_done)
|
if (!cleanup_done)
|
||||||
cleanup();
|
cleanup(true); // We have locked THD::LOCK_thd_kill
|
||||||
ha_close_connection(this);
|
ha_close_connection(this);
|
||||||
plugin_thdvar_cleanup(this);
|
plugin_thdvar_cleanup(this);
|
||||||
mysql_audit_free_thd(this);
|
mysql_audit_free_thd(this);
|
||||||
@ -1561,6 +1586,8 @@ void THD::free_connection()
|
|||||||
#if defined(ENABLED_PROFILING)
|
#if defined(ENABLED_PROFILING)
|
||||||
profiling.restart(); // Reset profiling
|
profiling.restart(); // Reset profiling
|
||||||
#endif
|
#endif
|
||||||
|
mysql_mutex_unlock(&LOCK_thd_kill);
|
||||||
|
mysql_mutex_unlock(&LOCK_thd_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1620,9 +1647,6 @@ THD::~THD()
|
|||||||
mysql_mutex_lock(&LOCK_thd_kill);
|
mysql_mutex_lock(&LOCK_thd_kill);
|
||||||
mysql_mutex_unlock(&LOCK_thd_kill);
|
mysql_mutex_unlock(&LOCK_thd_kill);
|
||||||
|
|
||||||
#ifdef WITH_WSREP
|
|
||||||
delete wsrep_rgi;
|
|
||||||
#endif
|
|
||||||
if (!free_connection_done)
|
if (!free_connection_done)
|
||||||
free_connection();
|
free_connection();
|
||||||
|
|
||||||
@ -3070,12 +3094,12 @@ static File create_file(THD *thd, char *path, sql_exchange *exchange,
|
|||||||
}
|
}
|
||||||
/* Create the file world readable */
|
/* Create the file world readable */
|
||||||
if ((file= mysql_file_create(key_select_to_file,
|
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;
|
return file;
|
||||||
#ifdef HAVE_FCHMOD
|
#ifdef HAVE_FCHMOD
|
||||||
(void) fchmod(file, 0666); // Because of umask()
|
(void) fchmod(file, 0644); // Because of umask()
|
||||||
#else
|
#else
|
||||||
(void) chmod(path, 0666);
|
(void) chmod(path, 0644);
|
||||||
#endif
|
#endif
|
||||||
if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
|
if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
|
||||||
{
|
{
|
||||||
|
@ -3291,7 +3291,7 @@ public:
|
|||||||
void update_all_stats();
|
void update_all_stats();
|
||||||
void update_stats(void);
|
void update_stats(void);
|
||||||
void change_user(void);
|
void change_user(void);
|
||||||
void cleanup(void);
|
void cleanup(bool have_mutex=false);
|
||||||
void cleanup_after_query();
|
void cleanup_after_query();
|
||||||
void free_connection();
|
void free_connection();
|
||||||
void reset_for_reuse();
|
void reset_for_reuse();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Copyright (c) 2002, 2015, Oracle and/or its affiliates.
|
/* Copyright (c) 2002, 2015, Oracle and/or its affiliates.
|
||||||
Copyright (c) 2008, 2019, MariaDB
|
Copyright (c) 2008, 2021, MariaDB
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -117,15 +117,14 @@ When one supplies long data for a placeholder:
|
|||||||
#include <mysql.h>
|
#include <mysql.h>
|
||||||
#else
|
#else
|
||||||
#include <mysql_com.h>
|
#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
|
#endif
|
||||||
#include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL
|
#include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL
|
||||||
#include "sql_handler.h"
|
#include "sql_handler.h"
|
||||||
#include "transaction.h" // trans_rollback_implicit
|
#include "transaction.h" // trans_rollback_implicit
|
||||||
#include "wsrep_mysqld.h"
|
#include "wsrep_mysqld.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;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A result class used to send cursor rows using the binary protocol.
|
A result class used to send cursor rows using the binary protocol.
|
||||||
*/
|
*/
|
||||||
|
@ -2484,8 +2484,12 @@ struct TABLE_LIST
|
|||||||
Indicates what triggers we need to pre-load for this TABLE_LIST
|
Indicates what triggers we need to pre-load for this TABLE_LIST
|
||||||
when opening an associated TABLE. This is filled after
|
when opening an associated TABLE. This is filled after
|
||||||
the parsed tree is created.
|
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. */
|
/* TRUE <=> this table is a const one and was optimized away. */
|
||||||
bool optimized_away;
|
bool optimized_away;
|
||||||
|
|
||||||
|
@ -5082,29 +5082,15 @@ static void innobase_kill_query(handlerton*, THD* thd, enum thd_kill_levels)
|
|||||||
|
|
||||||
if (trx_t* trx= thd_to_trx(thd))
|
if (trx_t* trx= thd_to_trx(thd))
|
||||||
{
|
{
|
||||||
|
ut_ad(trx->mysql_thd == thd);
|
||||||
lock_mutex_enter();
|
lock_mutex_enter();
|
||||||
mutex_enter(&trx_sys.mutex);
|
if (lock_t *lock= trx->lock.wait_lock)
|
||||||
trx_mutex_enter(trx);
|
{
|
||||||
/* It is possible that innobase_close_connection() is concurrently
|
trx_mutex_enter(trx);
|
||||||
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_t::state changes are protected by trx_t::mutex, and
|
|
||||||
trx_sys.trx_list is protected by trx_sys.mutex, in
|
|
||||||
both trx_create() and trx_t::free().
|
|
||||||
|
|
||||||
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;
|
|
||||||
mutex_exit(&trx_sys.mutex);
|
|
||||||
if (!cancel);
|
|
||||||
else if (lock_t *lock= trx->lock.wait_lock)
|
|
||||||
lock_cancel_waiting_and_release(lock);
|
lock_cancel_waiting_and_release(lock);
|
||||||
|
trx_mutex_exit(trx);
|
||||||
|
}
|
||||||
lock_mutex_exit();
|
lock_mutex_exit();
|
||||||
trx_mutex_exit(trx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
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
|
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
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@ -303,7 +303,6 @@ que_fork_scheduler_round_robin(
|
|||||||
/** Query thread states */
|
/** Query thread states */
|
||||||
enum que_thr_state_t {
|
enum que_thr_state_t {
|
||||||
QUE_THR_RUNNING,
|
QUE_THR_RUNNING,
|
||||||
QUE_THR_PROCEDURE_WAIT,
|
|
||||||
/** in selects this means that the thread is at the end of its
|
/** 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
|
result set (or start, in case of a scroll cursor); in other
|
||||||
statements, this means the thread has done its task */
|
statements, this means the thread has done its task */
|
||||||
|
@ -6153,6 +6153,7 @@ lock_cancel_waiting_and_release(
|
|||||||
|
|
||||||
ut_ad(lock_mutex_own());
|
ut_ad(lock_mutex_own());
|
||||||
ut_ad(trx_mutex_own(lock->trx));
|
ut_ad(trx_mutex_own(lock->trx));
|
||||||
|
ut_ad(lock->trx->state == TRX_STATE_ACTIVE);
|
||||||
|
|
||||||
lock->trx->lock.cancel = true;
|
lock->trx->lock.cancel = true;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
|
|
||||||
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
|
||||||
Copyright (c) 2017, 2018, 2020 MariaDB Corporation.
|
Copyright (c) 2017, 2021, MariaDB Corporation.
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
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
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
@ -349,7 +349,6 @@ que_fork_start_command(
|
|||||||
|
|
||||||
case QUE_THR_RUNNING:
|
case QUE_THR_RUNNING:
|
||||||
case QUE_THR_LOCK_WAIT:
|
case QUE_THR_LOCK_WAIT:
|
||||||
case QUE_THR_PROCEDURE_WAIT:
|
|
||||||
ut_error;
|
ut_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -410,7 +410,7 @@ void trx_t::free()
|
|||||||
/* do not poison mutex */
|
/* do not poison mutex */
|
||||||
MEM_NOACCESS(&id, sizeof id);
|
MEM_NOACCESS(&id, sizeof id);
|
||||||
MEM_NOACCESS(&no, sizeof no);
|
MEM_NOACCESS(&no, sizeof no);
|
||||||
/* state is accessed by innobase_kill_connection() */
|
MEM_NOACCESS(&state, sizeof state);
|
||||||
MEM_NOACCESS(&is_recovered, sizeof is_recovered);
|
MEM_NOACCESS(&is_recovered, sizeof is_recovered);
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
MEM_NOACCESS(&wsrep, sizeof wsrep);
|
MEM_NOACCESS(&wsrep, sizeof wsrep);
|
||||||
@ -435,7 +435,7 @@ void trx_t::free()
|
|||||||
MEM_NOACCESS(&start_time_micro, sizeof start_time_micro);
|
MEM_NOACCESS(&start_time_micro, sizeof start_time_micro);
|
||||||
MEM_NOACCESS(&commit_lsn, sizeof commit_lsn);
|
MEM_NOACCESS(&commit_lsn, sizeof commit_lsn);
|
||||||
MEM_NOACCESS(&table_id, sizeof table_id);
|
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_file_name, sizeof mysql_log_file_name);
|
||||||
MEM_NOACCESS(&mysql_log_offset, sizeof mysql_log_offset);
|
MEM_NOACCESS(&mysql_log_offset, sizeof mysql_log_offset);
|
||||||
MEM_NOACCESS(&n_mysql_tables_in_use, sizeof n_mysql_tables_in_use);
|
MEM_NOACCESS(&n_mysql_tables_in_use, sizeof n_mysql_tables_in_use);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user