Merge 10.5 into 10.6

This commit is contained in:
Marko Mäkelä 2021-01-11 17:32:08 +02:00
commit 666565c7f0
72 changed files with 1600 additions and 330 deletions

View File

@ -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"

View File

@ -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

View File

@ -1,5 +1,3 @@
connection node_1;
connection node_2;
connection node_2;
connection node_1;
connection node_1;

View File

@ -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;

View 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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -0,0 +1,3 @@
!include ../galera_2nodes.cnf
[mysqltest]
ps-protocol

View 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;

View File

@ -0,0 +1,7 @@
!include ../galera_2nodes.cnf
[mysqld]
thread-handling=pool-of-threads
[mysqltest]
ps-protocol

View 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;

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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';

View 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

View 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

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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 #

View File

@ -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

View File

@ -115,7 +115,7 @@ ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|AARCH64")
COMPILE_FLAGS "-march=armv8-a+crc+crypto")
ENDIF()
ENDIF()
ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64")
ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64|powerpc64")
SET(MYSYS_SOURCES ${MYSYS_SOURCES} crc32/crc32_ppc64.c crc32/crc32c_ppc.c)
SET_SOURCE_FILES_PROPERTIES(crc32/crc32_ppc64.c crc32/crc32c_ppc.c PROPERTIES
COMPILE_FLAGS "${COMPILE_FLAGS} -maltivec -mvsx -mpower8-vector -mcrypto -mpower8-vector")

View File

@ -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)
{

View File

@ -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

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2019, Oracle and/or its affiliates.
Copyright (c) 2009, 2020, MariaDB
Copyright (c) 2009, 2021, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -5287,7 +5287,7 @@ int Rows_log_event::do_add_row_data(uchar *row_data, size_t length)
There was the same problem with MERGE MYISAM tables and so here we try to
go the same way.
*/
static void restore_empty_query_table_list(LEX *lex)
inline void restore_empty_query_table_list(LEX *lex)
{
if (lex->first_not_own_table())
(*lex->first_not_own_table()->prev_global)= NULL;
@ -5302,6 +5302,8 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
TABLE* table;
DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)");
int error= 0;
LEX *lex= thd->lex;
uint8 new_trg_event_map= get_trg_event_map();
/*
If m_table_id == ~0ULL, then we have a dummy event that does not
contain any data. In that case, we just remove all tables in the
@ -5392,27 +5394,30 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
};);
if (slave_run_triggers_for_rbr)
/*
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)))
{
@ -5771,8 +5776,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
}
/* remove trigger's tables */
if (slave_run_triggers_for_rbr)
restore_empty_query_table_list(thd->lex);
restore_empty_query_table_list(thd->lex);
#if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE)
if (WSREP(thd) && wsrep_thd_is_applying(thd))
@ -5791,8 +5795,7 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
DBUG_RETURN(error);
err:
if (slave_run_triggers_for_rbr)
restore_empty_query_table_list(thd->lex);
restore_empty_query_table_list(thd->lex);
rgi->slave_close_thread_tables(thd);
DBUG_RETURN(error);
}

View File

@ -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",

View File

@ -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)))
{

View File

@ -3463,7 +3463,7 @@ public:
void update_all_stats();
void update_stats(void);
void change_user(void);
void cleanup(void);
void cleanup(bool have_mutex=false);
void cleanup_after_query();
void free_connection();
void reset_for_reuse();

View File

@ -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]);

View File

@ -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)

View File

@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates.
Copyright (c) 2008, 2020, MariaDB
Copyright (c) 2008, 2021, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -1140,6 +1140,14 @@ static bool wsrep_tables_accessible_when_detached(const TABLE_LIST *tables)
}
return true;
}
static bool wsrep_command_no_result(char command)
{
return (command == COM_STMT_PREPARE ||
command == COM_STMT_FETCH ||
command == COM_STMT_SEND_LONG_DATA ||
command == COM_STMT_CLOSE);
}
#endif /* WITH_WSREP */
#ifndef EMBEDDED_LIBRARY
static enum enum_server_command fetch_command(THD *thd, char *packet)
@ -1278,12 +1286,21 @@ bool do_command(THD *thd)
#ifdef WITH_WSREP
DEBUG_SYNC(thd, "wsrep_before_before_command");
/*
Aborted by background rollbacker thread.
Handle error here and jump straight to out
If this command does not return a result, then we
instruct wsrep_before_command() to skip result handling.
This causes BF aborted transaction to roll back but keep
the error state until next command which is able to return
a result to the client.
*/
if (unlikely(wsrep_service_started) && wsrep_before_command(thd))
if (unlikely(wsrep_service_started) &&
wsrep_before_command(thd, wsrep_command_no_result(command)))
{
thd->store_globals();
/*
Aborted by background rollbacker thread.
Handle error here and jump straight to out.
Notice that thd->store_globals() is called
in wsrep_before_command().
*/
WSREP_LOG_THD(thd, "enter found BF aborted");
DBUG_ASSERT(!thd->mdl_context.has_locks());
DBUG_ASSERT(!thd->get_stmt_da()->is_set());
@ -2269,20 +2286,12 @@ dispatch_end:
*/
if (unlikely(wsrep_service_started))
{
/*
BF aborted before sending response back to client
*/
if (thd->killed == KILL_QUERY)
{
WSREP_DEBUG("THD is killed at dispatch_end");
}
wsrep_after_command_before_result(thd);
if (wsrep_current_error(thd) &&
!(command == COM_STMT_PREPARE ||
command == COM_STMT_FETCH ||
command == COM_STMT_SEND_LONG_DATA ||
command == COM_STMT_CLOSE
))
if (wsrep_current_error(thd) && !wsrep_command_no_result(command))
{
/* todo: Pass wsrep client state current error to override */
wsrep_override_error(thd, wsrep_current_error(thd),

View File

@ -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.
*/

View File

@ -2487,6 +2487,7 @@ int multi_update::send_data(List<Item> &not_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> &not_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);

View File

@ -6051,8 +6051,10 @@ static Sys_var_uint Sys_wsrep_gtid_domain_id(
"wsrep_gtid_domain_id", "When wsrep_gtid_mode is set, this value is "
"used as gtid_domain_id for galera transactions and also copied to the "
"joiner nodes during state transfer. It is ignored, otherwise.",
GLOBAL_VAR(wsrep_gtid_server.domain_id), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, UINT_MAX32), DEFAULT(0), BLOCK_SIZE(1));
GLOBAL_VAR(wsrep_gtid_domain_id), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, UINT_MAX32), DEFAULT(0), BLOCK_SIZE(1),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(wsrep_gtid_domain_id_update));
static Sys_var_ulonglong Sys_wsrep_gtid_seq_no(
"wsrep_gtid_seq_no",

View File

@ -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;

View File

@ -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)

View File

@ -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:

View File

@ -1,5 +1,5 @@
/* Copyright 2008-2015 Codership Oy <http://www.codership.com>
Copyright (c) 2020, MariaDB
Copyright (c) 2020, 2021, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -110,6 +110,7 @@ ulong wsrep_mysql_replication_bundle;
bool wsrep_gtid_mode; // Enable WSREP native GTID support
Wsrep_gtid_server wsrep_gtid_server;
uint wsrep_gtid_domain_id=0; // Domain id on above structure
/* Other configuration variables and their default values. */
my_bool wsrep_incremental_data_collection= 0; // Incremental data collection
@ -319,29 +320,31 @@ wsp::node_status local_status;
*/
Wsrep_schema *wsrep_schema= 0;
static void wsrep_log_cb(wsrep::log::level level, const char *msg)
static void wsrep_log_cb(wsrep::log::level level,
const char*, const char *msg)
{
/*
Silence all wsrep related logging from lib and provider if
wsrep is not enabled.
*/
if (WSREP_ON)
{
switch (level) {
case wsrep::log::info:
sql_print_information("WSREP: %s", msg);
break;
case wsrep::log::warning:
sql_print_warning("WSREP: %s", msg);
break;
case wsrep::log::error:
sql_print_error("WSREP: %s", msg);
if (!WSREP_ON) return;
switch (level) {
case wsrep::log::info:
WSREP_INFO("%s", msg);
break;
case wsrep::log::warning:
WSREP_WARN("%s", msg);
break;
case wsrep::log::error:
WSREP_ERROR("%s", msg);
break;
case wsrep::log::debug:
WSREP_DEBUG("%s", msg);
break;
case wsrep::log::unknown:
WSREP_UNKNOWN("%s", msg);
break;
case wsrep::log::debug:
if (wsrep_debug) sql_print_information ("[Debug] WSREP: %s", msg);
default:
break;
}
}
}
@ -786,6 +789,7 @@ int wsrep_init_server()
void wsrep_init_globals()
{
wsrep_gtid_server.domain_id= wsrep_gtid_domain_id;
wsrep_init_sidno(Wsrep_server_state::instance().connected_gtid().id());
wsrep_init_gtid();
/* Recover last written wsrep gtid */

View File

@ -1,5 +1,5 @@
/* Copyright 2008-2017 Codership Oy <http://www.codership.com>
Copyright (c) 2020, MariaDB
Copyright (c) 2020, 2021, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -101,6 +101,7 @@ extern ulong wsrep_running_rollbacker_threads;
extern bool wsrep_new_cluster;
extern bool wsrep_gtid_mode;
extern my_bool wsrep_strict_ddl;
extern uint wsrep_gtid_domain_id;
enum enum_wsrep_reject_types {
WSREP_REJECT_NONE, /* nothing rejected */
@ -254,10 +255,11 @@ void WSREP_LOG(void (*fun)(const char* fmt, ...), const char* fmt, ...);
#define WSREP_INFO(...) sql_print_information( "WSREP: " __VA_ARGS__)
#define WSREP_WARN(...) sql_print_warning( "WSREP: " __VA_ARGS__)
#define WSREP_ERROR(...) sql_print_error( "WSREP: " __VA_ARGS__)
#define WSREP_UNKNOWN(fmt, ...) WSREP_ERROR("UNKNOWN: " fmt, ##__VA_ARGS__)
#define WSREP_LOG_CONFLICT_THD(thd, role) \
sql_print_information( \
"WSREP: %s: \n " \
WSREP_INFO( \
"%s: \n " \
" THD: %lu, mode: %s, state: %s, conflict: %s, seqno: %lld\n " \
" SQL: %s", \
role, \
@ -272,12 +274,12 @@ void WSREP_LOG(void (*fun)(const char* fmt, ...), const char* fmt, ...);
#define WSREP_LOG_CONFLICT(bf_thd, victim_thd, bf_abort) \
if (wsrep_debug || wsrep_log_conflicts) \
{ \
sql_print_information( "WSREP: cluster conflict due to %s for threads:", \
(bf_abort) ? "high priority abort" : "certification failure" \
WSREP_INFO("cluster conflict due to %s for threads:", \
(bf_abort) ? "high priority abort" : "certification failure" \
); \
if (bf_thd) WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread"); \
if (victim_thd) WSREP_LOG_CONFLICT_THD(victim_thd, "Victim thread"); \
sql_print_information("WSREP: context: %s:%d", __FILE__, __LINE__); \
WSREP_INFO("context: %s:%d", __FILE__, __LINE__); \
}
#define WSREP_PROVIDER_EXISTS \

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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.

View File

@ -944,3 +944,11 @@ void wsrep_free_status (THD* thd)
{
thd->wsrep_status_vars.clear();
}
bool wsrep_gtid_domain_id_update(sys_var* self, THD *thd, enum_var_type)
{
WSREP_DEBUG("wsrep_gtid_domain_id_update: %llu",
wsrep_gtid_domain_id);
wsrep_gtid_server.domain_id= wsrep_gtid_domain_id;
return false;
}

View File

@ -105,6 +105,7 @@ extern bool wsrep_debug_update UPDATE_ARGS;
extern bool wsrep_gtid_seq_no_check CHECK_ARGS;
extern bool wsrep_gtid_domain_id_update UPDATE_ARGS;
#else /* WITH_WSREP */
#define wsrep_provider_init(X)

View File

@ -2,7 +2,7 @@
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2014, 2020, MariaDB Corporation.
Copyright (c) 2014, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -3831,12 +3831,13 @@ btr_discard_only_page_on_level(
mtr_t* mtr) /*!< in: mtr */
{
ulint page_level = 0;
trx_id_t max_trx_id;
ut_ad(!index->is_dummy);
/* Save the PAGE_MAX_TRX_ID from the leaf page. */
max_trx_id = page_get_max_trx_id(buf_block_get_frame(block));
const trx_id_t max_trx_id = page_get_max_trx_id(block->frame);
const rec_t* r = page_rec_get_next(page_get_infimum_rec(block->frame));
ut_ad(rec_is_metadata(r, *index) == index->is_instant());
while (block->page.id().page_no() != dict_index_get_page(index)) {
btr_cur_t cursor;
@ -3892,9 +3893,6 @@ btr_discard_only_page_on_level(
rec_offs* offsets = NULL;
if (index->table->instant || index->must_avoid_clear_instant_add()) {
const rec_t* r = page_rec_get_next(page_get_infimum_rec(
block->frame));
ut_ad(rec_is_metadata(r, *index) == index->is_instant());
if (!rec_is_metadata(r, *index)) {
} else if (!index->table->instant
|| rec_is_alter_metadata(r, *index)) {

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation.
Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -410,7 +410,6 @@ buf_block_t* buf_LRU_get_free_block(bool have_mutex)
mysql_mutex_assert_owner(&buf_pool.mutex);
goto got_mutex;
}
loop:
mysql_mutex_lock(&buf_pool.mutex);
got_mutex:
buf_LRU_check_size_of_non_data_objects();
@ -493,11 +492,10 @@ not_found:
++flush_failures;
}
srv_stats.buf_pool_wait_free.inc();
n_iterations++;
goto loop;
mysql_mutex_lock(&buf_pool.mutex);
buf_pool.stat.LRU_waits++;
goto got_mutex;
}
/** Move the LRU_old pointer so that the length of the old blocks list

View File

@ -4,7 +4,7 @@ Copyright (c) 2000, 2020, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, 2020, MariaDB Corporation.
Copyright (c) 2013, 2021, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@ -946,8 +946,7 @@ static SHOW_VAR innodb_status_variables[]= {
&export_vars.innodb_buffer_pool_read_requests, SHOW_SIZE_T},
{"buffer_pool_reads",
&export_vars.innodb_buffer_pool_reads, SHOW_SIZE_T},
{"buffer_pool_wait_free",
&export_vars.innodb_buffer_pool_wait_free, SHOW_SIZE_T},
{"buffer_pool_wait_free", &buf_pool.stat.LRU_waits, SHOW_SIZE_T},
{"buffer_pool_write_requests",
&export_vars.innodb_buffer_pool_write_requests, SHOW_SIZE_T},
{"checkpoint_age", &export_vars.innodb_checkpoint_age, SHOW_SIZE_T},
@ -4432,7 +4431,7 @@ static int innobase_close_connection(handlerton *hton, THD *thd)
return 0;
}
UNIV_INTERN void lock_cancel_waiting_and_release(lock_t* lock);
void lock_cancel_waiting_and_release(lock_t *lock);
/** Cancel any pending lock request associated with the current THD.
@sa THD::awake() @sa ha_kill_query() */
@ -4442,6 +4441,7 @@ static void innobase_kill_query(handlerton*, THD *thd, enum thd_kill_levels)
if (trx_t* trx= thd_to_trx(thd))
{
ut_ad(trx->mysql_thd == thd);
#ifdef WITH_WSREP
if (trx->is_wsrep() && wsrep_thd_is_aborting(thd))
/* if victim has been signaled by BF thread and/or aborting is already
@ -4450,28 +4450,13 @@ static void innobase_kill_query(handlerton*, THD *thd, enum thd_kill_levels)
DBUG_VOID_RETURN;
#endif /* WITH_WSREP */
lock_sys.mutex_lock();
trx_sys.trx_list.freeze();
trx->mutex.wr_lock();
/* It is possible that innobase_close_connection() is concurrently
being executed on our victim. Even if the trx object is later
reused for another client connection or a background transaction,
its trx->mysql_thd will differ from our thd.
trx_sys.trx_list is thread-safe. It's freezed to 'protect'
trx_t. However, trx_t::commit_in_memory() changes a trx_t::state
of autocommit non-locking transactions without any protection.
At this point, trx may have been reallocated for another client
connection, or for a background operation. In that case, either
trx_t::state or trx_t::mysql_thd should not match our expectations. */
bool cancel= trx->mysql_thd == thd && trx->state == TRX_STATE_ACTIVE &&
!trx->lock.was_chosen_as_deadlock_victim;
trx_sys.trx_list.unfreeze();
if (!cancel);
else if (lock_t *lock= trx->lock.wait_lock)
if (lock_t *lock= trx->lock.wait_lock)
{
trx->mutex.wr_lock();
lock_cancel_waiting_and_release(lock);
trx->mutex.wr_unlock();
}
lock_sys.mutex_unlock();
trx->mutex.wr_unlock();
}
DBUG_VOID_RETURN;

View File

@ -10070,6 +10070,54 @@ innobase_page_compression_try(
DBUG_RETURN(false);
}
static
void
dict_stats_try_drop_table(THD *thd, const table_name_t &name,
const LEX_CSTRING &table_name)
{
char errstr[1024];
if (dict_stats_drop_table(name.m_name, errstr, sizeof(errstr)) != DB_SUCCESS)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_ALTER_INFO,
"Deleting persistent statistics"
" for table '%s' in InnoDB failed: %s",
table_name.str,
errstr);
}
}
/** Evict the table from cache and reopen it. Drop outdated statistics.
@param thd mariadb THD entity
@param table innodb table
@param table_name user-friendly table name for errors
@param ctx ALTER TABLE context
@return newly opened table */
static dict_table_t *innobase_reload_table(THD *thd, dict_table_t *table,
const LEX_CSTRING &table_name,
ha_innobase_inplace_ctx &ctx)
{
char *tb_name= strdup(table->name.m_name);
dict_table_close(table, true, false);
if (ctx.is_instant())
{
for (auto i = ctx.old_n_v_cols; i--; )
{
ctx.old_v_cols[i].~dict_v_col_t();
const_cast<unsigned&>(ctx.old_n_v_cols) = 0;
}
}
dict_sys.remove(table);
table= dict_table_open_on_name(tb_name, TRUE, TRUE,
DICT_ERR_IGNORE_FK_NOKEY);
/* Drop outdated table stats. */
dict_stats_try_drop_table(thd, table->name, table_name);
free(tb_name);
return table;
}
/** Commit the changes made during prepare_inplace_alter_table()
and inplace_alter_table() inside the data dictionary tables,
when not rebuilding the table.
@ -11186,44 +11234,19 @@ foreign_fail:
Currently dict_load_column_low() is the only place where
num_base for virtual columns is assigned to nonzero. */
if (ctx0->num_to_drop_vcol || ctx0->num_to_add_vcol
|| (ctx0->new_table->n_v_cols && !new_clustered
&& (ha_alter_info->alter_info->drop_list.elements
|| ha_alter_info->alter_info->create_list.elements))
|| (ctx0->is_instant()
&& m_prebuilt->table->n_v_cols
&& ha_alter_info->handler_flags & ALTER_STORED_COLUMN_ORDER)) {
/* FIXME: this workaround does not seem to work with
partitioned tables */
DBUG_ASSERT(ctx0->old_table->get_ref_count() == 1);
trx_commit_for_mysql(m_prebuilt->trx);
char tb_name[NAME_LEN * 2 + 1 + 1];
strcpy(tb_name, m_prebuilt->table->name.m_name);
dict_table_close(m_prebuilt->table, true, false);
if (ctx0->is_instant()) {
for (unsigned i = ctx0->old_n_v_cols; i--; ) {
ctx0->old_v_cols[i].~dict_v_col_t();
}
const_cast<unsigned&>(ctx0->old_n_v_cols) = 0;
}
dict_sys.remove(m_prebuilt->table);
m_prebuilt->table = dict_table_open_on_name(
tb_name, TRUE, TRUE, DICT_ERR_IGNORE_FK_NOKEY);
/* Drop outdated table stats. */
char errstr[1024];
if (dict_stats_drop_table(
m_prebuilt->table->name.m_name,
errstr, sizeof(errstr))
!= DB_SUCCESS) {
push_warning_printf(
m_user_thd,
Sql_condition::WARN_LEVEL_WARN,
ER_ALTER_INFO,
"Deleting persistent statistics"
" for table '%s' in"
" InnoDB failed: %s",
table->s->table_name.str,
errstr);
}
m_prebuilt->table = innobase_reload_table(m_user_thd,
m_prebuilt->table,
table->s->table_name,
*ctx0);
row_mysql_unlock_data_dictionary(trx);
trx->free();
@ -11283,25 +11306,12 @@ foreign_fail:
old copy of the table (which was renamed to
ctx->tmp_name). */
char errstr[1024];
DBUG_ASSERT(0 == strcmp(ctx->old_table->name.m_name,
ctx->tmp_name));
if (dict_stats_drop_table(
ctx->new_table->name.m_name,
errstr, sizeof(errstr))
!= DB_SUCCESS) {
push_warning_printf(
m_user_thd,
Sql_condition::WARN_LEVEL_WARN,
ER_ALTER_INFO,
"Deleting persistent statistics"
" for rebuilt table '%s' in"
" InnoDB failed: %s",
table->s->table_name.str,
errstr);
}
dict_stats_try_drop_table(m_user_thd,
ctx->new_table->name,
table->s->table_name);
DBUG_EXECUTE_IF("ib_ddl_crash_before_commit",
DBUG_SUICIDE(););

View File

@ -1279,6 +1279,8 @@ struct buf_pool_stat_t{
young because the first access
was not long enough ago, in
buf_page_peek_if_too_old() */
/** number of waits for eviction; writes protected by buf_pool.mutex */
ulint LRU_waits;
ulint LRU_bytes; /*!< LRU size in bytes */
ulint flush_list_bytes;/*!< flush_list size in bytes */
};
@ -1710,7 +1712,7 @@ public:
static constexpr uint32_t READ_AHEAD_PAGES= 64;
/** Buffer pool mutex */
mysql_mutex_t mutex;
MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) mysql_mutex_t mutex;
/** Number of pending LRU flush. */
Atomic_counter<ulint> n_flush_LRU;
/** broadcast when n_flush_LRU reaches 0; protected by mutex */
@ -1857,7 +1859,7 @@ public:
/** mutex protecting flush_list, buf_page_t::set_oldest_modification()
and buf_page_t::list pointers when !oldest_modification() */
mysql_mutex_t flush_list_mutex;
MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) mysql_mutex_t flush_list_mutex;
/** "hazard pointer" for flush_list scans; protected by flush_list_mutex */
FlushHp flush_hp;
/** modified blocks (a subset of LRU) */

View File

@ -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 */

View File

@ -112,11 +112,6 @@ struct srv_stats_t
/** Store the number of write requests issued */
ulint_ctr_1_t buf_pool_write_requests;
/** Store the number of times when we had to wait for a free page
in the buffer pool. It happens when the buffer pool is full and we
need to make a flush, in order to be able to read or create a page. */
ulint_ctr_1_t buf_pool_wait_free;
/** Number of buffer pool reads that led to the reading of
a disk page */
ulint_ctr_1_t buf_pool_reads;
@ -759,8 +754,7 @@ struct export_var_t{
ulint innodb_buffer_pool_pages_old;
ulint innodb_buffer_pool_read_requests; /*!< buf_pool.stat.n_page_gets */
ulint innodb_buffer_pool_reads; /*!< srv_buf_pool_reads */
ulint innodb_buffer_pool_wait_free; /*!< srv_buf_pool_wait_free */
ulint innodb_buffer_pool_write_requests;/*!< srv_buf_pool_write_requests */
ulint innodb_buffer_pool_write_requests;/*!< srv_stats.buf_pool_write_requests */
ulint innodb_buffer_pool_read_ahead_rnd;/*!< srv_read_ahead_rnd */
ulint innodb_buffer_pool_read_ahead; /*!< srv_read_ahead */
ulint innodb_buffer_pool_read_ahead_evicted;/*!< srv_read_ahead evicted*/

View File

@ -626,6 +626,20 @@ static void wsrep_assert_no_bf_bf_wait(
if (UNIV_LIKELY(!wsrep_thd_is_BF(lock_rec2->trx->mysql_thd, FALSE)))
return;
/* if BF - BF order is honored, we can keep trx1 waiting for the lock */
if (wsrep_thd_order_before(trx1->mysql_thd, lock_rec2->trx->mysql_thd))
return;
/* avoiding BF-BF conflict assert, if victim is already aborting
or rolling back for replaying
*/
wsrep_thd_LOCK(lock_rec2->trx->mysql_thd);
if (wsrep_thd_is_aborting(lock_rec2->trx->mysql_thd)) {
wsrep_thd_UNLOCK(lock_rec2->trx->mysql_thd);
return;
}
wsrep_thd_UNLOCK(lock_rec2->trx->mysql_thd);
mtr_t mtr;
if (lock_rec1) {
@ -1367,11 +1381,6 @@ lock_rec_create_low(
c_lock->trx->mutex.wr_unlock();
if (UNIV_UNLIKELY(wsrep_debug)) {
wsrep_report_bf_lock_wait(trx->mysql_thd, trx->id);
wsrep_report_bf_lock_wait(c_lock->trx->mysql_thd, c_lock->trx->id);
}
/* have to bail out here to avoid lock_set_lock... */
return(lock);
}
@ -5585,6 +5594,7 @@ lock_cancel_waiting_and_release(
que_thr_t* thr;
lock_sys.mutex_assert_locked();
ut_ad(lock->trx->state == TRX_STATE_ACTIVE);
lock->trx->lock.cancel = true;

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation.
Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -333,7 +333,6 @@ que_fork_start_command(
case QUE_THR_RUNNING:
case QUE_THR_LOCK_WAIT:
case QUE_THR_PROCEDURE_WAIT:
ut_error;
}
}

View File

@ -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;
}

View File

@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 2000, 2018, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, 2020, MariaDB Corporation.
Copyright (c) 2015, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -4296,6 +4296,7 @@ row_rename_table_for_mysql(
, FALSE, trx);
if (err != DB_SUCCESS) {
ut_ad(err != DB_DUPLICATE_KEY);
goto end;
}

View File

@ -2,7 +2,7 @@
Copyright (c) 2010, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, 2020, MariaDB Corporation.
Copyright (c) 2013, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@ -1501,7 +1501,7 @@ srv_mon_process_existing_counter(
/* innodb_buffer_pool_wait_free */
case MONITOR_OVLD_BUF_POOL_WAIT_FREE:
value = srv_stats.buf_pool_wait_free;
value = buf_pool.stat.LRU_waits;
break;
/* innodb_buffer_pool_read_ahead */

View File

@ -3,7 +3,7 @@
Copyright (c) 1995, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2013, 2020, MariaDB Corporation.
Copyright (c) 2013, 2021, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@ -1071,9 +1071,6 @@ srv_export_innodb_status(void)
export_vars.innodb_buffer_pool_write_requests =
srv_stats.buf_pool_write_requests;
export_vars.innodb_buffer_pool_wait_free =
srv_stats.buf_pool_wait_free;
export_vars.innodb_buffer_pool_reads = srv_stats.buf_pool_reads;
export_vars.innodb_buffer_pool_read_ahead_rnd =

View File

@ -405,9 +405,11 @@ void trx_t::free()
MEM_NOACCESS(&n_ref, sizeof n_ref);
/* do not poison mutex */
MEM_NOACCESS(&id, sizeof id);
/* state is accessed by innobase_kill_connection() */
MEM_NOACCESS(&state, sizeof state);
MEM_NOACCESS(&is_recovered, sizeof is_recovered);
/* wsrep is accessed by innobase_kill_connection() */
#ifdef WITH_WSREP
MEM_NOACCESS(&wsrep, sizeof wsrep);
#endif
read_view.mem_noaccess();
MEM_NOACCESS(&lock, sizeof lock);
MEM_NOACCESS(&op_info, sizeof op_info);
@ -425,7 +427,7 @@ void trx_t::free()
MEM_NOACCESS(&start_time_micro, sizeof start_time_micro);
MEM_NOACCESS(&commit_lsn, sizeof commit_lsn);
MEM_NOACCESS(&table_id, sizeof table_id);
/* mysql_thd is accessed by innobase_kill_connection() */
MEM_NOACCESS(&mysql_thd, sizeof mysql_thd);
MEM_NOACCESS(&mysql_log_file_name, sizeof mysql_log_file_name);
MEM_NOACCESS(&mysql_log_offset, sizeof mysql_log_offset);
MEM_NOACCESS(&n_mysql_tables_in_use, sizeof n_mysql_tables_in_use);

View File

@ -109,8 +109,8 @@ if(NOT WIN32)
endif()
include(CheckCCompilerFlag)
# ppc64 or ppc64le
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64")
# ppc64 or ppc64le or powerpc64 (BSD)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ppc64|powerpc64")
CHECK_C_COMPILER_FLAG("-maltivec" HAS_ALTIVEC)
if(HAS_ALTIVEC)
message(STATUS " HAS_ALTIVEC yes")

@ -1 +1 @@
Subproject commit 41a6e9dad79c921134e44cf974b6b7ca3b84e538
Subproject commit a93955ddeef5989505cbb3a9f8bb124341462569