Merge 10.4 into 10.5

This commit is contained in:
Marko Mäkelä 2021-01-11 16:29:51 +02:00
commit 8de233af81
62 changed files with 1570 additions and 302 deletions

View File

@ -180,7 +180,7 @@ IF(WIN32)
MARK_AS_ADVANCED(SIGNCODE) MARK_AS_ADVANCED(SIGNCODE)
IF(SIGNCODE) IF(SIGNCODE)
SET(SIGNTOOL_PARAMETERS SET(SIGNTOOL_PARAMETERS
/a /t http://timestamp.verisign.com/scripts/timstamp.dll /a /t http://timestamp.globalsign.com/scripts/timstamp.dll
CACHE STRING "parameters for signtool (list)") CACHE STRING "parameters for signtool (list)")
FIND_PROGRAM(SIGNTOOL_EXECUTABLE signtool FIND_PROGRAM(SIGNTOOL_EXECUTABLE signtool
PATHS "$ENV{ProgramFiles}/Microsoft SDKs/Windows/v7.0A/bin" PATHS "$ENV{ProgramFiles}/Microsoft SDKs/Windows/v7.0A/bin"

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 id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY <derived4> ALL NULL NULL NULL NULL 24 1 PRIMARY <derived4> ALL NULL NULL NULL NULL 24
4 DERIVED folks ALL NULL NULL NULL NULL 12 Using where 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 5 RECURSIVE UNION <derived4> ALL NULL NULL NULL NULL 24
NULL UNION RESULT <union4,6,5> ALL NULL NULL NULL NULL NULL NULL UNION RESULT <union4,6,5> ALL NULL NULL NULL NULL NULL
3 DERIVED folks ALL NULL NULL NULL NULL 12 Using where 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 t1 ALL NULL NULL NULL NULL 4 Using where
3 RECURSIVE UNION <derived2> ref key0 key0 9 test.t1.c 2 3 RECURSIVE UNION <derived2> ref key0 key0 9 test.t1.c 2
NULL UNION RESULT <union2,3> ALL NULL NULL NULL NULL NULL 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 with recursive r_cte as
( select * from t1 as s ( select * from t1 as s
union union

View File

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

View File

@ -1,10 +1,13 @@
connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2;
connection node_2a; connection node_2a;
connection node_2;
connection node_1; connection node_1;
connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
connection node_3;
RESET MASTER; RESET MASTER;
connection node_2a; connection node_2a;
START SLAVE; START SLAVE;
connection node_1; connection node_3;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)) engine=innodb; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)) engine=innodb;
INSERT INTO t1 VALUES (1, 'a'); INSERT INTO t1 VALUES (1, 'a');
INSERT INTO t1 VALUES (3, 'a'); INSERT INTO t1 VALUES (3, 'a');
@ -18,15 +21,14 @@ f1 f2
UPDATE t1 SET f2 = 'c' WHERE f1 > 1; UPDATE t1 SET f2 = 'c' WHERE f1 > 1;
connection node_2a; connection node_2a;
SET SESSION wsrep_sync_wait = 0; SET SESSION wsrep_sync_wait = 0;
connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3; connection node_1;
connection node_3;
SET SESSION wsrep_sync_wait = 0; SET SESSION wsrep_sync_wait = 0;
connection node_2a; 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"; SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb";
connection node_3;
INSERT INTO test.t1 VALUES (2, 'b');
connection node_1; connection node_1;
INSERT INTO test.t1 VALUES (2, 'b');
connection node_3;
COMMIT; COMMIT;
connection node_2a; connection node_2a;
SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 0;
@ -35,8 +37,8 @@ SET GLOBAL debug_dbug = "";
SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb"; SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
connection node_2a; connection node_2a;
SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'dbug=';
SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_master_enter_sync';
connection node_1; connection node_3;
SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'a'; SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'a';
COUNT(*) = 1 COUNT(*) = 1
1 1
@ -61,7 +63,7 @@ SET DEBUG_SYNC = "RESET";
# #
# test phase with real abort # test phase with real abort
# #
connection node_1; connection node_3;
set binlog_format=ROW; set binlog_format=ROW;
insert into t1 values (4, 'd'); insert into t1 values (4, 'd');
SET AUTOCOMMIT=ON; SET AUTOCOMMIT=ON;
@ -70,9 +72,9 @@ UPDATE t1 SET f2 = 'd' WHERE f1 = 3;
connection node_2a; connection node_2a;
SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_enter_sync'; SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_enter_sync';
SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb"; SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb";
connection node_3;
UPDATE test.t1 SET f2 = 'e' WHERE f1 = 3;
connection node_1; connection node_1;
UPDATE test.t1 SET f2 = 'e' WHERE f1 = 3;
connection node_3;
COMMIT; COMMIT;
connection node_2a; connection node_2a;
SET GLOBAL debug_dbug = ""; SET GLOBAL debug_dbug = "";
@ -90,6 +92,6 @@ set session wsrep_sync_wait=0;
STOP SLAVE; STOP SLAVE;
RESET SLAVE; RESET SLAVE;
DROP TABLE t1; DROP TABLE t1;
connection node_1; connection node_3;
DROP TABLE t1; DROP TABLE t1;
RESET MASTER; 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/galera_cluster.inc
--source include/have_debug.inc --source include/have_debug.inc
--source include/have_debug_sync.inc --source include/have_debug_sync.inc
--source include/galera_have_debug_sync.inc
CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB; CREATE TABLE t1 (f1 INT PRIMARY KEY) ENGINE=InnoDB;

View File

@ -18,9 +18,10 @@
#--source suite/galera/include/galera_have_debug_sync.inc #--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; RESET MASTER;
--connection node_2a --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 --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 --enable_query_log
START SLAVE; START SLAVE;
--connection node_1 --connection node_3
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)) engine=innodb; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)) engine=innodb;
INSERT INTO t1 VALUES (1, 'a'); INSERT INTO t1 VALUES (1, 'a');
INSERT INTO t1 VALUES (3, 'a'); INSERT INTO t1 VALUES (3, 'a');
@ -63,15 +64,14 @@ SET SESSION wsrep_sync_wait = 0;
--source include/wait_condition.inc --source include/wait_condition.inc
# wait for create table and inserts to be replicated in cluster # 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_1
--connection node_3
SET SESSION wsrep_sync_wait = 0; SET SESSION wsrep_sync_wait = 0;
--let $wait_condition = SELECT COUNT(*) = 2 FROM test.t1; --let $wait_condition = SELECT COUNT(*) = 2 FROM test.t1;
--source include/wait_condition.inc --source include/wait_condition.inc
--connection node_2a --connection node_2a
# Block the future commit of async replication # 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 --source include/galera_set_sync_point.inc
# block also the applier before applying begins # 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 # now inject a conflicting insert from node 3, it will replicate with
# earlier seqno (than async transaction) and pause before applying in node 2 # 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'); INSERT INTO test.t1 VALUES (2, 'b');
# #
# send the update from master, this will succeed here, beceuase of async replication. # 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, # async replication will apply this in node 2 and pause before commit phase,
--connection node_1 --connection node_3
--error 0 --error 0
COMMIT; COMMIT;
@ -108,7 +108,7 @@ SET DEBUG_SYNC = "now SIGNAL signal.wsrep_apply_cb";
--source include/galera_clear_sync_point.inc --source include/galera_clear_sync_point.inc
--source include/galera_signal_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 = 'a';
SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c'; SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c';
@ -139,7 +139,7 @@ SET DEBUG_SYNC = "RESET";
--echo # test phase with real abort --echo # test phase with real abort
--echo # --echo #
--connection node_1 --connection node_3
set binlog_format=ROW; 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"; SET GLOBAL debug_dbug = "d,sync.wsrep_apply_cb";
# Inject a conflicting update from node 3 # Inject a conflicting update from node 3
--connection node_3 --connection node_1
UPDATE test.t1 SET f2 = 'e' WHERE f1 = 3; UPDATE test.t1 SET f2 = 'e' WHERE f1 = 3;
# send the update from master # send the update from master
--connection node_1 --connection node_3
--error 0 --error 0
COMMIT; COMMIT;
@ -195,6 +195,6 @@ RESET SLAVE;
DROP TABLE t1; DROP TABLE t1;
--connection node_1 --connection node_3
DROP TABLE t1; DROP TABLE t1;
RESET MASTER; 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); INSERT INTO t1 VALUES (1), (1);
--connection node_2 --connection node_2
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t1';
--source include/wait_condition.inc
SET SESSION wsrep_OSU_method = "RSU"; SET SESSION wsrep_OSU_method = "RSU";
--error ER_DUP_ENTRY --error ER_DUP_ENTRY
ALTER TABLE t1 ADD PRIMARY KEY (f1); ALTER TABLE t1 ADD PRIMARY KEY (f1);

View File

@ -9,6 +9,9 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (1);
--connection node_2 --connection node_2
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t1';
--source include/wait_condition.inc
ALTER TABLE t1 ADD COLUMN f2 INTEGER; ALTER TABLE t1 ADD COLUMN f2 INTEGER;
INSERT INTO t1 VALUES (2, 3); INSERT INTO t1 VALUES (2, 3);

View File

@ -10,6 +10,9 @@ CREATE TABLE t1 (id INT PRIMARY KEY) ENGINE=InnoDB;
INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (1);
--connection node_2 --connection node_2
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t1';
--source include/wait_condition.inc
ALTER TABLE t1 ADD COLUMN f2 INTEGER, LOCK=SHARED; ALTER TABLE t1 ADD COLUMN f2 INTEGER, LOCK=SHARED;
--connection node_1 --connection node_1

View File

@ -14,6 +14,9 @@ CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) Engine=InnoDB;
INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (1);
--connection node_2 --connection node_2
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t1';
--source include/wait_condition.inc
TRUNCATE TABLE t1; TRUNCATE TABLE t1;
SELECT COUNT(*) = 0 FROM t1; SELECT COUNT(*) = 0 FROM t1;

View File

@ -67,6 +67,9 @@ CREATE TEMPORARY TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
INSERT INTO t1 VALUES (2); INSERT INTO t1 VALUES (2);
--connection node_2 --connection node_2
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t1';
--source include/wait_condition.inc
TRUNCATE TABLE t1; TRUNCATE TABLE t1;
SELECT COUNT(*) = 0 FROM t1; SELECT COUNT(*) = 0 FROM t1;

View File

@ -15,6 +15,9 @@ START TRANSACTION;
INSERT INTO t1 VALUES (2, 0); INSERT INTO t1 VALUES (2, 0);
--connection node_2 --connection node_2
--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'test/t1';
--source include/wait_condition.inc
ALTER TABLE t1 DROP COLUMN f2; ALTER TABLE t1 DROP COLUMN f2;
--connection node_1 --connection node_1

View File

@ -121,19 +121,5 @@ SELECT index_name, stat_name, stat_description
FROM mysql.innodb_index_stats FROM mysql.innodb_index_stats
WHERE database_name = 'test' AND table_name = 't'; WHERE database_name = 'test' AND table_name = 't';
index_name stat_name stat_description index_name stat_name stat_description
GEN_CLUST_INDEX n_diff_pfx01 DB_ROW_ID # MDEV-24564 FIXME: Do reload statistics after the above ALTER TABLE!
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
DROP TABLE t; DROP TABLE t;

View File

@ -52,5 +52,6 @@ ALTER TABLE t DROP INDEX vidxcd;
SELECT index_name, stat_name, stat_description SELECT index_name, stat_name, stat_description
FROM mysql.innodb_index_stats FROM mysql.innodb_index_stats
WHERE database_name = 'test' AND table_name = 't'; WHERE database_name = 'test' AND table_name = 't';
-- echo # MDEV-24564 FIXME: Do reload statistics after the above ALTER TABLE!
DROP TABLE t; 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; SELECT * FROM t1 WHERE y BETWEEN 2012 AND 2016 FOR UPDATE;
y i b vi y i b vi
DROP TABLE t1; 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'; WHERE variable_name = 'innodb_instant_alter_column';
instants instants
22 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 # 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; disconnect con2;
DROP TABLE t1; 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 # MDEV-22867 Assertion instant.n_core_fields == n_core_fields
# in dict_index_t::instant_add_field # in dict_index_t::instant_add_field
# #
@ -408,3 +421,4 @@ Table Op Msg_type Msg_text
test.t1 check status OK test.t1 check status OK
DROP TABLE t1; DROP TABLE t1;
SET DEBUG_SYNC=RESET; 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); INSERT INTO t1 (i) VALUES (1),(2);
SELECT * FROM t1 WHERE y BETWEEN 2012 AND 2016 FOR UPDATE; SELECT * FROM t1 WHERE y BETWEEN 2012 AND 2016 FOR UPDATE;
DROP TABLE t1; 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 FROM information_schema.global_status
WHERE variable_name = 'innodb_instant_alter_column'; WHERE variable_name = 'innodb_instant_alter_column';
SET GLOBAL innodb_purge_rseg_truncate_frequency = @save_frequency;
--echo # --echo #
--echo # MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col --echo # MDEV-21045 AddressSanitizer: use-after-poison in mem_heap_dup / row_log_table_get_pk_col
--echo # --echo #
@ -415,6 +413,22 @@ SET DEBUG_SYNC='RESET';
--disconnect con2 --disconnect con2
DROP TABLE t1; 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 #
--echo # MDEV-22867 Assertion instant.n_core_fields == n_core_fields --echo # MDEV-22867 Assertion instant.n_core_fields == n_core_fields
--echo # in dict_index_t::instant_add_field --echo # in dict_index_t::instant_add_field
@ -460,3 +474,5 @@ INSERT INTO t1 VALUES (2),(3),(4);
CHECK TABLE t1; CHECK TABLE t1;
DROP TABLE t1; DROP TABLE t1;
SET DEBUG_SYNC=RESET; 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; disconnect cn1;
drop user user1@localhost; drop user user1@localhost;
set global server_audit_events=''; set global server_audit_events='';
set global server_audit_incl_users='root, plug_dest';
CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest'; CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd'; CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd';
connect(localhost,plug,plug_dest,test,MYSQL_PORT,MYSQL_SOCK); connect(localhost,plug,plug_dest,test,MYSQL_PORT,MYSQL_SOCK);
@ -277,7 +278,7 @@ server_audit_file_path
server_audit_file_rotate_now OFF server_audit_file_rotate_now OFF
server_audit_file_rotate_size 1000000 server_audit_file_rotate_size 1000000
server_audit_file_rotations 9 server_audit_file_rotations 9
server_audit_incl_users root server_audit_incl_users root, plug_dest
server_audit_logging ON server_audit_logging ON
server_audit_mode 1 server_audit_mode 1
server_audit_output_type file server_audit_output_type file
@ -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,roles_mapping,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,global_priv, 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_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,db,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,columns_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,root,localhost,ID,ID,QUERY,sa_db,'GRANT PROXY ON plug_dest TO plug',0
TIME,HOSTNAME,plug,localhost,ID,0,CONNECT,test,,0 TIME,HOSTNAME,plug,localhost,ID,0,CONNECT,test,,0
TIME,HOSTNAME,plug,localhost,ID,0,PROXY_CONNECT,test,`plug_dest`@`%`,0 TIME,HOSTNAME,plug,localhost,ID,0,PROXY_CONNECT,test,`plug_dest`@`%`,0
TIME,HOSTNAME,plug,localhost,ID,ID,QUERY,test,'select USER(),CURRENT_USER()',0
TIME,HOSTNAME,plug,localhost,ID,0,DISCONNECT,test,,0 TIME,HOSTNAME,plug,localhost,ID,0,DISCONNECT,test,,0
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,db,
TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv, TIME,HOSTNAME,root,localhost,ID,ID,WRITE,mysql,tables_priv,

View File

@ -173,6 +173,7 @@ source include/wait_until_count_sessions.inc;
drop user user1@localhost; drop user user1@localhost;
set global server_audit_events=''; set global server_audit_events='';
set global server_audit_incl_users='root, plug_dest';
CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest'; CREATE USER plug IDENTIFIED WITH 'test_plugin_server' AS 'plug_dest';
CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd'; CREATE USER plug_dest IDENTIFIED BY 'plug_dest_passwd';

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; stop slave;
set global rpl_semi_sync_slave_enabled = 1; set global rpl_semi_sync_slave_enabled = 1;
start slave; 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%'; show status like 'rpl_semi_sync_slave%';
connection master; connection master;
CREATE TABLE t1(a INT) ENGINE=InnoDB; CREATE TABLE t1(a INT) ENGINE=InnoDB;
sync_slave_with_master; sync_slave_with_master;
@ -190,6 +194,12 @@ connection con1;
INSERT INTO t1 values (2); INSERT INTO t1 values (2);
sync_slave_with_master; sync_slave_with_master;
connection con1; 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_clients';
show status like 'Rpl_semi_sync_master_status'; show status like 'Rpl_semi_sync_master_status';
@ -259,7 +269,12 @@ START SLAVE IO_THREAD;
--echo ######################################################### --echo #########################################################
connection con1; connection con1;
SET GLOBAL rpl_semi_sync_master_enabled = 0; 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'; show status like 'Rpl_semi_sync_master_clients';
INSERT INTO t1 VALUES (1); INSERT INTO t1 VALUES (1);
SET GLOBAL rpl_semi_sync_master_enabled = 1; SET GLOBAL rpl_semi_sync_master_enabled = 1;
INSERT INTO t1 VALUES (2); 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 BY SYSTEM_TIME INTERVAL 7 SECOND STARTS TIMESTAMP'2018-04-11 17:00:04'
(PARTITION `ver_p1` HISTORY ENGINE = DEFAULT_ENGINE, (PARTITION `ver_p1` HISTORY ENGINE = DEFAULT_ENGINE,
PARTITION `ver_pn` CURRENT 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 # 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); (partition p1 history, partition pn current);
alter table t1 add partition (partition p2); alter table t1 add partition (partition p2);
ERROR HY000: Wrong partitioning type, expected type: `SYSTEM_TIME` 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; drop table t1;
# #
# MDEV-22178 Assertion `info->alias.str' failed in partition_info::check_partition_info instead of ER_VERS_WRONG_PARTS # 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; UPDATE IGNORE t1 SET f = 1;
REPLACE t1 SELECT * FROM t1; REPLACE t1 SELECT * FROM t1;
DROP TABLE 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); partition ver_pn current);
--replace_result $default_engine DEFAULT_ENGINE --replace_result $default_engine DEFAULT_ENGINE
show create table t1; show create table t1;
set timestamp= default;
--echo # --echo #
--echo # MDEV-19175 Server crashes in ha_partition::vers_can_native upon INSERT DELAYED into versioned partitioned table --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 --error ER_PARTITION_WRONG_TYPE
alter table t1 add partition (partition p2); 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 # 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; drop table t1;
--echo # --echo #

View File

@ -59,4 +59,22 @@ UPDATE IGNORE t1 SET f = 1;
REPLACE t1 SELECT * FROM t1; REPLACE t1 SELECT * FROM t1;
DROP TABLE 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 --source suite/versioning/common_finish.inc

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; int result;
if (!name) if (!name)
return 0; return 0;
len= strlen(name);
if (take_lock) if (take_lock)
flogger_mutex_lock(&lock_operations); flogger_mutex_lock(&lock_operations);
if (incl_user_coll.n_users) if (incl_user_coll.n_users)
result= coll_search(&incl_user_coll, name, len) != 0; {
result= coll_search(&incl_user_coll, name, len) != 0 ||
(proxy && coll_search(&incl_user_coll, proxy, proxy_len) != 0);
}
else if (excl_user_coll.n_users) else if (excl_user_coll.n_users)
result= coll_search(&excl_user_coll, name, len) == 0; {
result= coll_search(&excl_user_coll, name, len) == 0 &&
(proxy && coll_search(&excl_user_coll, proxy, proxy_len) == 0);
}
else else
result= 1; result= 1;
@ -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) && if (event_class == MYSQL_AUDIT_GENERAL_CLASS && FILTER(EVENT_QUERY) &&
cn && (cn->log_always || do_log_user(cn->user, 1))) cn && (cn->log_always || do_log_user(cn->user, cn->user_length,
cn->proxy, cn->proxy_length,
1)))
{ {
const struct mysql_event_general *event = const struct mysql_event_general *event =
(const struct mysql_event_general *) ev; (const struct mysql_event_general *) ev;
@ -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 *event =
(const struct mysql_event_table *) ev; (const struct mysql_event_table *) ev;
if (do_log_user(event->user, 1)) if (do_log_user(event->user, (int) SAFE_STRLEN(event->user),
cn->proxy, cn->proxy_length, 1))
{ {
switch (event->event_subclass) switch (event->event_subclass)
{ {

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2000, 2018, Oracle and/or its affiliates. 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2000, 2019, Oracle and/or its affiliates. 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -5288,7 +5288,7 @@ int Rows_log_event::do_add_row_data(uchar *row_data, size_t length)
There was the same problem with MERGE MYISAM tables and so here we try to There was the same problem with MERGE MYISAM tables and so here we try to
go the same way. go the same way.
*/ */
static void restore_empty_query_table_list(LEX *lex) inline void restore_empty_query_table_list(LEX *lex)
{ {
if (lex->first_not_own_table()) if (lex->first_not_own_table())
(*lex->first_not_own_table()->prev_global)= NULL; (*lex->first_not_own_table()->prev_global)= NULL;
@ -5303,6 +5303,8 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
TABLE* table; TABLE* table;
DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)"); DBUG_ENTER("Rows_log_event::do_apply_event(Relay_log_info*)");
int error= 0; int error= 0;
LEX *lex= thd->lex;
uint8 new_trg_event_map= get_trg_event_map();
/* /*
If m_table_id == ~0ULL, then we have a dummy event that does not If m_table_id == ~0ULL, then we have a dummy event that does not
contain any data. In that case, we just remove all tables in the contain any data. In that case, we just remove all tables in the
@ -5393,10 +5395,6 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(action))); DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
};); };);
if (slave_run_triggers_for_rbr)
{
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 Trigger's procedures work with global table list. So we have to add
@ -5410,10 +5408,17 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
for (TABLE_LIST *tables= rgi->tables_to_lock; tables; for (TABLE_LIST *tables= rgi->tables_to_lock; tables;
tables= tables->next_global) tables= tables->next_global)
{
if (slave_run_triggers_for_rbr)
{ {
tables->trg_event_map= new_trg_event_map; tables->trg_event_map= new_trg_event_map;
lex->query_tables_last= &tables->next_global; lex->query_tables_last= &tables->next_global;
} }
else if (!WSREP_ON)
{
tables->slave_fk_event_map= new_trg_event_map;
lex->query_tables_last= &tables->next_global;
}
} }
if (unlikely(open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0))) if (unlikely(open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0)))
{ {
@ -5772,7 +5777,6 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
} }
/* remove trigger's tables */ /* remove trigger's tables */
if (slave_run_triggers_for_rbr)
restore_empty_query_table_list(thd->lex); restore_empty_query_table_list(thd->lex);
#if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE) #if defined(WITH_WSREP) && defined(HAVE_QUERY_CACHE)
@ -5792,7 +5796,6 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
DBUG_RETURN(error); DBUG_RETURN(error);
err: err:
if (slave_run_triggers_for_rbr)
restore_empty_query_table_list(thd->lex); restore_empty_query_table_list(thd->lex);
rgi->slave_close_thread_tables(thd); rgi->slave_close_thread_tables(thd);
DBUG_RETURN(error); DBUG_RETURN(error);

View File

@ -4591,7 +4591,72 @@ add_internal_tables(THD *thd, Query_tables_list *prelocking_ctx,
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
/**
Extend the table_list to include foreign tables for prelocking.
@param[in] thd Thread context.
@param[in] prelocking_ctx Prelocking context of the statement.
@param[in] table_list Table list element for table.
@param[in] sp Routine body.
@param[out] need_prelocking Set to TRUE if method detects that prelocking
required, not changed otherwise.
@retval FALSE Success.
@retval TRUE Failure (OOM).
*/
inline bool
prepare_fk_prelocking_list(THD *thd, Query_tables_list *prelocking_ctx,
TABLE_LIST *table_list, bool *need_prelocking,
uint8 op)
{
DBUG_ENTER("prepare_fk_prelocking_list");
List <FOREIGN_KEY_INFO> fk_list;
List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list);
FOREIGN_KEY_INFO *fk;
Query_arena *arena, backup;
TABLE *table= table_list->table;
arena= thd->activate_stmt_arena_if_needed(&backup);
table->file->get_parent_foreign_key_list(thd, &fk_list);
if (unlikely(thd->is_error()))
{
if (arena)
thd->restore_active_arena(arena, &backup);
return TRUE;
}
*need_prelocking= TRUE;
while ((fk= fk_list_it++))
{
// FK_OPTION_RESTRICT and FK_OPTION_NO_ACTION only need read access
thr_lock_type lock_type;
if ((op & (1 << TRG_EVENT_DELETE) && fk_modifies_child(fk->delete_method))
|| (op & (1 << TRG_EVENT_UPDATE) && fk_modifies_child(fk->update_method)))
lock_type= TL_WRITE_ALLOW_WRITE;
else
lock_type= TL_READ;
if (table_already_fk_prelocked(prelocking_ctx->query_tables,
fk->foreign_db, fk->foreign_table,
lock_type))
continue;
TABLE_LIST *tl= (TABLE_LIST *) thd->alloc(sizeof(TABLE_LIST));
tl->init_one_table_for_prelocking(fk->foreign_db,
fk->foreign_table,
NULL, lock_type,
TABLE_LIST::PRELOCK_FK,
table_list->belong_to_view, op,
&prelocking_ctx->query_tables_last,
table_list->for_insert_data);
}
if (arena)
thd->restore_active_arena(arena, &backup);
DBUG_RETURN(FALSE);
}
/** /**
Defines how prelocking algorithm for DML statements should handle table list Defines how prelocking algorithm for DML statements should handle table list
@ -4638,52 +4703,19 @@ handle_table(THD *thd, Query_tables_list *prelocking_ctx,
if (table->file->referenced_by_foreign_key()) if (table->file->referenced_by_foreign_key())
{ {
List <FOREIGN_KEY_INFO> fk_list; if (prepare_fk_prelocking_list(thd, prelocking_ctx, table_list,
List_iterator<FOREIGN_KEY_INFO> fk_list_it(fk_list); need_prelocking,
FOREIGN_KEY_INFO *fk; table_list->trg_event_map))
Query_arena *arena, backup; return TRUE;
}
arena= thd->activate_stmt_arena_if_needed(&backup); }
else if (table_list->slave_fk_event_map &&
table->file->get_parent_foreign_key_list(thd, &fk_list); table->file->referenced_by_foreign_key())
if (unlikely(thd->is_error()))
{ {
if (arena) if (prepare_fk_prelocking_list(thd, prelocking_ctx, table_list,
thd->restore_active_arena(arena, &backup); need_prelocking,
DBUG_RETURN(TRUE); table_list->slave_fk_event_map))
} 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);
}
} }
/* Open any tables used by DEFAULT (like sequence tables) */ /* Open any tables used by DEFAULT (like sequence tables) */

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2000, 2015, Oracle and/or its affiliates. Copyright (c) 2000, 2015, Oracle and/or its affiliates.
Copyright (c) 2008, 2020, MariaDB Corporation. Copyright (c) 2008, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -1531,15 +1531,28 @@ void THD::reset_db(const LEX_CSTRING *new_db)
/* Do operations that may take a long time */ /* Do operations that may take a long time */
void THD::cleanup(void) void THD::cleanup(bool have_mutex)
{ {
DBUG_ENTER("THD::cleanup"); DBUG_ENTER("THD::cleanup");
DBUG_ASSERT(cleanup_done == 0); DBUG_ASSERT(cleanup_done == 0);
if (have_mutex)
set_killed_no_mutex(KILL_CONNECTION,0,0);
else
set_killed(KILL_CONNECTION); set_killed(KILL_CONNECTION);
#ifdef WITH_WSREP #ifdef WITH_WSREP
if (wsrep_cs().state() != wsrep::client_state::s_none) if (wsrep_cs().state() != wsrep::client_state::s_none)
{ {
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_cs().cleanup();
} }
wsrep_client_thread= false; wsrep_client_thread= false;
@ -1614,16 +1627,38 @@ void THD::cleanup(void)
void THD::free_connection() void THD::free_connection()
{ {
DBUG_ASSERT(free_connection_done == 0); DBUG_ASSERT(free_connection_done == 0);
my_free((char*) db.str); /* 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; db= null_clex_str;
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
if (net.vio) if (net.vio)
vio_delete(net.vio); vio_delete(net.vio);
net.vio= 0; net.vio= nullptr;
net_end(&net); net_end(&net);
#endif #endif
if (!cleanup_done) if (!cleanup_done)
cleanup(); cleanup(true); // We have locked THD::LOCK_thd_kill
ha_close_connection(this); ha_close_connection(this);
plugin_thdvar_cleanup(this); plugin_thdvar_cleanup(this);
mysql_audit_free_thd(this); mysql_audit_free_thd(this);
@ -1635,6 +1670,8 @@ void THD::free_connection()
profiling.restart(); // Reset profiling profiling.restart(); // Reset profiling
#endif #endif
debug_sync_reset_thread(this); 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) if (!status_in_global)
add_status_to_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) if (!free_connection_done)
free_connection(); free_connection();
#ifdef WITH_WSREP #ifdef WITH_WSREP
if (wsrep_rgi != NULL) {
delete wsrep_rgi;
wsrep_rgi = NULL;
}
mysql_cond_destroy(&COND_wsrep_thd); mysql_cond_destroy(&COND_wsrep_thd);
#endif #endif
mdl_context.destroy(); mdl_context.destroy();
@ -3154,12 +3177,12 @@ static File create_file(THD *thd, char *path, sql_exchange *exchange,
} }
/* Create the file world readable */ /* Create the file world readable */
if ((file= mysql_file_create(key_select_to_file, if ((file= mysql_file_create(key_select_to_file,
path, 0666, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0) path, 0644, O_WRONLY|O_EXCL, MYF(MY_WME))) < 0)
return file; return file;
#ifdef HAVE_FCHMOD #ifdef HAVE_FCHMOD
(void) fchmod(file, 0666); // Because of umask() (void) fchmod(file, 0644); // Because of umask()
#else #else
(void) chmod(path, 0666); (void) chmod(path, 0644);
#endif #endif
if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME))) if (init_io_cache(cache, file, 0L, WRITE_CACHE, 0L, 1, MYF(MY_WME)))
{ {

View File

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

View File

@ -2027,6 +2027,8 @@ int write_record(THD *thd, TABLE *table, COPY_INFO *info, select_result *sink)
if (likely(!error)) if (likely(!error))
{ {
info->deleted++; info->deleted++;
if (!table->file->has_transactions())
thd->transaction->stmt.modified_non_trans_table= TRUE;
if (table->versioned(VERS_TIMESTAMP)) if (table->versioned(VERS_TIMESTAMP))
{ {
store_record(table, record[2]); store_record(table, record[2]);

View File

@ -5467,16 +5467,16 @@ void st_select_lex::set_explain_type(bool on_the_fly)
/* /*
pos_in_table_list=NULL for e.g. post-join aggregation JOIN_TABs. pos_in_table_list=NULL for e.g. post-join aggregation JOIN_TABs.
*/ */
if (!tab->table); if (!(tab->table && tab->table->pos_in_table_list))
else if (const TABLE_LIST *pos= tab->table->pos_in_table_list) continue;
{ TABLE_LIST *tbl= tab->table->pos_in_table_list;
if (pos->with && pos->with->is_recursive) if (tbl->with && tbl->with->is_recursive &&
tbl->is_with_table_recursive_reference())
{ {
uses_cte= true; uses_cte= true;
break; break;
} }
} }
}
if (uses_cte) if (uses_cte)
type= "RECURSIVE UNION"; type= "RECURSIVE UNION";
} }

View File

@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2017, Oracle and/or its affiliates. /* 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -1160,6 +1160,14 @@ static bool wsrep_tables_accessible_when_detached(const TABLE_LIST *tables)
} }
return true; 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 */ #endif /* WITH_WSREP */
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
@ -1283,12 +1291,21 @@ bool do_command(THD *thd)
#ifdef WITH_WSREP #ifdef WITH_WSREP
DEBUG_SYNC(thd, "wsrep_before_before_command"); DEBUG_SYNC(thd, "wsrep_before_before_command");
/* /*
Aborted by background rollbacker thread. If this command does not return a result, then we
Handle error here and jump straight to out 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"); WSREP_LOG_THD(thd, "enter found BF aborted");
DBUG_ASSERT(!thd->mdl_context.has_locks()); DBUG_ASSERT(!thd->mdl_context.has_locks());
DBUG_ASSERT(!thd->get_stmt_da()->is_set()); DBUG_ASSERT(!thd->get_stmt_da()->is_set());
@ -2413,20 +2430,12 @@ dispatch_end:
*/ */
if (unlikely(wsrep_service_started)) if (unlikely(wsrep_service_started))
{ {
/*
BF aborted before sending response back to client
*/
if (thd->killed == KILL_QUERY) if (thd->killed == KILL_QUERY)
{ {
WSREP_DEBUG("THD is killed at dispatch_end"); WSREP_DEBUG("THD is killed at dispatch_end");
} }
wsrep_after_command_before_result(thd); wsrep_after_command_before_result(thd);
if (wsrep_current_error(thd) && if (wsrep_current_error(thd) && !wsrep_command_no_result(command))
!(command == COM_STMT_PREPARE ||
command == COM_STMT_FETCH ||
command == COM_STMT_SEND_LONG_DATA ||
command == COM_STMT_CLOSE
))
{ {
/* todo: Pass wsrep client state current error to override */ /* todo: Pass wsrep client state current error to override */
wsrep_override_error(thd, wsrep_current_error(thd), 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) 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -117,6 +117,8 @@ When one supplies long data for a placeholder:
#include <mysql.h> #include <mysql.h>
#else #else
#include <mysql_com.h> #include <mysql_com.h>
/* Constants defining bits in parameter type flags. Flags are read from high byte of short value */
static const uint PARAMETER_FLAG_UNSIGNED= 128U << 8;
#endif #endif
#include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL #include "lock.h" // MYSQL_OPEN_FORCE_SHARED_MDL
#include "sql_handler.h" #include "sql_handler.h"
@ -127,9 +129,6 @@ When one supplies long data for a placeholder:
#include "wsrep_trans_observer.h" #include "wsrep_trans_observer.h"
#endif /* WITH_WSREP */ #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. 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; TABLE_LIST *cur_table;
DBUG_ENTER("multi_update::send_data"); DBUG_ENTER("multi_update::send_data");
int error= 0;
for (cur_table= update_tables; cur_table; cur_table= cur_table->next_local) 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++; found++;
if (!can_compare_record || compare_record(table)) if (!can_compare_record || compare_record(table))
{ {
int error;
if ((error= cur_table->view_check_option(thd, ignore)) != if ((error= cur_table->view_check_option(thd, ignore)) !=
VIEW_CHECK_OK) VIEW_CHECK_OK)
@ -2616,7 +2616,6 @@ error:
} }
else else
{ {
int error;
TABLE *tmp_table= tmp_tables[offset]; TABLE *tmp_table= tmp_tables[offset];
if (copy_funcs(tmp_table_param[offset].items_to_copy, thd)) if (copy_funcs(tmp_table_param[offset].items_to_copy, thd))
DBUG_RETURN(1); DBUG_RETURN(1);

View File

@ -2547,8 +2547,12 @@ struct TABLE_LIST
Indicates what triggers we need to pre-load for this TABLE_LIST Indicates what triggers we need to pre-load for this TABLE_LIST
when opening an associated TABLE. This is filled after when opening an associated TABLE. This is filled after
the parsed tree is created. the parsed tree is created.
slave_fk_event_map is filled on the slave side with bitmaps value
representing row-based event operation to help find and prelock
possible FK constrain-related child tables.
*/ */
uint8 trg_event_map; uint8 trg_event_map, slave_fk_event_map;
/* TRUE <=> this table is a const one and was optimized away. */ /* TRUE <=> this table is a const one and was optimized away. */
bool optimized_away; bool optimized_away;

View File

@ -73,7 +73,7 @@ bool Wsrep_client_service::interrupted(
Locking order is: Locking order is:
1) LOCK_thd_data 1) LOCK_thd_data
2) LOCK_thd_kill */ 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); mysql_mutex_lock(&m_thd->LOCK_thd_kill);
bool ret= (m_thd->killed != NOT_KILLED); bool ret= (m_thd->killed != NOT_KILLED);
if (ret) if (ret)

View File

@ -44,7 +44,7 @@ public:
void wait(wsrep::unique_lock<wsrep::mutex>& lock) 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); mysql_cond_wait(&m_cond, mutex);
} }
private: private:

View File

@ -1,5 +1,5 @@
/* Copyright 2008-2015 Codership Oy <http://www.codership.com> /* 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -320,29 +320,31 @@ wsp::node_status local_status;
*/ */
Wsrep_schema *wsrep_schema= 0; 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 Silence all wsrep related logging from lib and provider if
wsrep is not enabled. wsrep is not enabled.
*/ */
if (WSREP_ON) if (!WSREP_ON) return;
{
switch (level) { switch (level) {
case wsrep::log::info: case wsrep::log::info:
sql_print_information("WSREP: %s", msg); WSREP_INFO("%s", msg);
break; break;
case wsrep::log::warning: case wsrep::log::warning:
sql_print_warning("WSREP: %s", msg); WSREP_WARN("%s", msg);
break; break;
case wsrep::log::error: case wsrep::log::error:
sql_print_error("WSREP: %s", msg); WSREP_ERROR("%s", msg);
break; break;
case wsrep::log::debug: case wsrep::log::debug:
if (wsrep_debug) sql_print_information ("[Debug] WSREP: %s", msg); WSREP_DEBUG("%s", msg);
default: break;
case wsrep::log::unknown:
WSREP_UNKNOWN("%s", msg);
break; break;
}
} }
} }
@ -787,6 +789,7 @@ int wsrep_init_server()
void wsrep_init_globals() 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_sidno(Wsrep_server_state::instance().connected_gtid().id());
wsrep_init_gtid(); wsrep_init_gtid();
/* Recover last written wsrep gtid */ /* Recover last written wsrep gtid */

View File

@ -1,5 +1,5 @@
/* Copyright 2008-2017 Codership Oy <http://www.codership.com> /* 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 This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
@ -255,10 +255,11 @@ void WSREP_LOG(void (*fun)(const char* fmt, ...), const char* fmt, ...);
#define WSREP_INFO(...) sql_print_information( "WSREP: " __VA_ARGS__) #define WSREP_INFO(...) sql_print_information( "WSREP: " __VA_ARGS__)
#define WSREP_WARN(...) sql_print_warning( "WSREP: " __VA_ARGS__) #define WSREP_WARN(...) sql_print_warning( "WSREP: " __VA_ARGS__)
#define WSREP_ERROR(...) sql_print_error( "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) \ #define WSREP_LOG_CONFLICT_THD(thd, role) \
sql_print_information( \ WSREP_INFO( \
"WSREP: %s: \n " \ "%s: \n " \
" THD: %lu, mode: %s, state: %s, conflict: %s, seqno: %lld\n " \ " THD: %lu, mode: %s, state: %s, conflict: %s, seqno: %lld\n " \
" SQL: %s", \ " SQL: %s", \
role, \ role, \
@ -273,12 +274,12 @@ void WSREP_LOG(void (*fun)(const char* fmt, ...), const char* fmt, ...);
#define WSREP_LOG_CONFLICT(bf_thd, victim_thd, bf_abort) \ #define WSREP_LOG_CONFLICT(bf_thd, victim_thd, bf_abort) \
if (wsrep_debug || wsrep_log_conflicts) \ if (wsrep_debug || wsrep_log_conflicts) \
{ \ { \
sql_print_information( "WSREP: cluster conflict due to %s for threads:", \ WSREP_INFO("cluster conflict due to %s for threads:", \
(bf_abort) ? "high priority abort" : "certification failure" \ (bf_abort) ? "high priority abort" : "certification failure" \
); \ ); \
if (bf_thd) WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread"); \ if (bf_thd) WSREP_LOG_CONFLICT_THD(bf_thd, "Winning thread"); \
if (victim_thd) WSREP_LOG_CONFLICT_THD(victim_thd, "Victim 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 \ #define WSREP_PROVIDER_EXISTS \

View File

@ -162,16 +162,19 @@ void Wsrep_server_service::log_message(enum wsrep::log::level level,
switch (level) switch (level)
{ {
case wsrep::log::debug: case wsrep::log::debug:
sql_print_information("debug: %s", message); WSREP_DEBUG("%s", message);
break; break;
case wsrep::log::info: case wsrep::log::info:
sql_print_information("%s", message); WSREP_INFO("%s", message);
break; break;
case wsrep::log::warning: case wsrep::log::warning:
sql_print_warning("%s", message); WSREP_WARN("%s", message);
break; break;
case wsrep::log::error: case wsrep::log::error:
sql_print_error("%s", message); WSREP_ERROR("%s", message);
break;
case wsrep::log::unknown:
WSREP_UNKNOWN("%s", message);
break; break;
} }
} }

View File

@ -29,6 +29,7 @@
#include "wsrep_utils.h" #include "wsrep_utils.h"
#include "wsrep_xid.h" #include "wsrep_xid.h"
#include "wsrep_thd.h" #include "wsrep_thd.h"
#include "wsrep_mysqld.h"
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
@ -596,6 +597,7 @@ static void* sst_joiner_thread (void* a)
goto err; goto err;
} else { } else {
wsrep_gtid_server.domain_id= (uint32) domain_id; 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; 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 && return (thd->wsrep_cs().state() != wsrep::client_state::s_none &&
!thd->internal_transaction() ? !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. Called after each command.

View File

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

View File

@ -4651,7 +4651,7 @@ static int innobase_close_connection(handlerton *hton, THD *thd)
return 0; 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. /** Cancel any pending lock request associated with the current THD.
@sa THD::awake() @sa ha_kill_query() */ @sa THD::awake() @sa ha_kill_query() */
@ -4661,6 +4661,7 @@ static void innobase_kill_query(handlerton*, THD *thd, enum thd_kill_levels)
if (trx_t* trx= thd_to_trx(thd)) if (trx_t* trx= thd_to_trx(thd))
{ {
ut_ad(trx->mysql_thd == thd);
#ifdef WITH_WSREP #ifdef WITH_WSREP
if (trx->is_wsrep() && wsrep_thd_is_aborting(thd)) if (trx->is_wsrep() && wsrep_thd_is_aborting(thd))
/* if victim has been signaled by BF thread and/or aborting is already /* if victim has been signaled by BF thread and/or aborting is already
@ -4669,29 +4670,14 @@ static void innobase_kill_query(handlerton*, THD *thd, enum thd_kill_levels)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
lock_mutex_enter(); lock_mutex_enter();
trx_sys.trx_list.freeze(); if (lock_t *lock= trx->lock.wait_lock)
{
trx_mutex_enter(trx); trx_mutex_enter(trx);
/* It is possible that innobase_close_connection() is concurrently
being executed on our victim. Even if the trx object is later
reused for another client connection or a background transaction,
its trx->mysql_thd will differ from our thd.
trx_sys.trx_list is thread-safe. It's freezed to 'protect'
trx_t. However, trx_t::commit_in_memory() changes a trx_t::state
of autocommit non-locking transactions without any protection.
At this point, trx may have been reallocated for another client
connection, or for a background operation. In that case, either
trx_t::state or trx_t::mysql_thd should not match our expectations. */
bool cancel= trx->mysql_thd == thd && trx->state == TRX_STATE_ACTIVE &&
!trx->lock.was_chosen_as_deadlock_victim;
trx_sys.trx_list.unfreeze();
if (!cancel);
else if (lock_t *lock= trx->lock.wait_lock)
lock_cancel_waiting_and_release(lock); lock_cancel_waiting_and_release(lock);
lock_mutex_exit();
trx_mutex_exit(trx); trx_mutex_exit(trx);
} }
lock_mutex_exit();
}
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 2005, 2019, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2005, 2019, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2020, MariaDB Corporation. Copyright (c) 2013, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@ -10073,6 +10073,54 @@ innobase_page_compression_try(
DBUG_RETURN(false); 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() /** Commit the changes made during prepare_inplace_alter_table()
and inplace_alter_table() inside the data dictionary tables, and inplace_alter_table() inside the data dictionary tables,
when not rebuilding the table. when not rebuilding the table.
@ -11189,44 +11237,19 @@ foreign_fail:
Currently dict_load_column_low() is the only place where Currently dict_load_column_low() is the only place where
num_base for virtual columns is assigned to nonzero. */ num_base for virtual columns is assigned to nonzero. */
if (ctx0->num_to_drop_vcol || ctx0->num_to_add_vcol 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() || (ctx0->is_instant()
&& m_prebuilt->table->n_v_cols && m_prebuilt->table->n_v_cols
&& ha_alter_info->handler_flags & ALTER_STORED_COLUMN_ORDER)) { && 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); DBUG_ASSERT(ctx0->old_table->get_ref_count() == 1);
trx_commit_for_mysql(m_prebuilt->trx); trx_commit_for_mysql(m_prebuilt->trx);
char tb_name[NAME_LEN * 2 + 1 + 1]; m_prebuilt->table = innobase_reload_table(m_user_thd,
strcpy(tb_name, m_prebuilt->table->name.m_name); m_prebuilt->table,
dict_table_close(m_prebuilt->table, true, false); table->s->table_name,
if (ctx0->is_instant()) { *ctx0);
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);
}
row_mysql_unlock_data_dictionary(trx); row_mysql_unlock_data_dictionary(trx);
trx->free(); trx->free();
@ -11286,25 +11309,12 @@ foreign_fail:
old copy of the table (which was renamed to old copy of the table (which was renamed to
ctx->tmp_name). */ ctx->tmp_name). */
char errstr[1024];
DBUG_ASSERT(0 == strcmp(ctx->old_table->name.m_name, DBUG_ASSERT(0 == strcmp(ctx->old_table->name.m_name,
ctx->tmp_name)); ctx->tmp_name));
if (dict_stats_drop_table( dict_stats_try_drop_table(m_user_thd,
ctx->new_table->name.m_name, ctx->new_table->name,
errstr, sizeof(errstr)) table->s->table_name);
!= 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);
}
DBUG_EXECUTE_IF("ib_ddl_crash_before_commit", DBUG_EXECUTE_IF("ib_ddl_crash_before_commit",
DBUG_SUICIDE();); DBUG_SUICIDE(););

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2017, 2020, MariaDB Corporation. Copyright (c) 2017, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@ -288,7 +288,6 @@ que_fork_scheduler_round_robin(
/** Query thread states */ /** Query thread states */
enum que_thr_state_t { enum que_thr_state_t {
QUE_THR_RUNNING, QUE_THR_RUNNING,
QUE_THR_PROCEDURE_WAIT,
/** in selects this means that the thread is at the end of its /** in selects this means that the thread is at the end of its
result set (or start, in case of a scroll cursor); in other result set (or start, in case of a scroll cursor); in other
statements, this means the thread has done its task */ statements, this means the thread has done its task */

View File

@ -627,6 +627,20 @@ static void wsrep_assert_no_bf_bf_wait(
if (UNIV_LIKELY(!wsrep_thd_is_BF(lock_rec2->trx->mysql_thd, FALSE))) if (UNIV_LIKELY(!wsrep_thd_is_BF(lock_rec2->trx->mysql_thd, FALSE)))
return; 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; mtr_t mtr;
if (lock_rec1) { if (lock_rec1) {
@ -1385,11 +1399,6 @@ lock_rec_create_low(
trx_mutex_exit(c_lock->trx); trx_mutex_exit(c_lock->trx);
if (UNIV_UNLIKELY(wsrep_debug)) {
wsrep_report_bf_lock_wait(trx->mysql_thd, trx->id);
wsrep_report_bf_lock_wait(c_lock->trx->mysql_thd, c_lock->trx->id);
}
/* have to bail out here to avoid lock_set_lock... */ /* have to bail out here to avoid lock_set_lock... */
return(lock); return(lock);
} }
@ -5896,6 +5905,7 @@ lock_cancel_waiting_and_release(
ut_ad(lock_mutex_own()); ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(lock->trx)); ut_ad(trx_mutex_own(lock->trx));
ut_ad(lock->trx->state == TRX_STATE_ACTIVE);
lock->trx->lock.cancel = true; lock->trx->lock.cancel = true;

View File

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

View File

@ -2735,8 +2735,23 @@ wsrep_rec_get_foreign_key(
break; break;
case DATA_BLOB: case DATA_BLOB:
case DATA_BINARY: case DATA_BINARY:
case DATA_FIXBINARY:
case DATA_GEOMETRY:
memcpy(buf, data, len); memcpy(buf, data, len);
break; 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: default:
break; break;
} }

View File

@ -4335,6 +4335,8 @@ row_rename_table_for_mysql(
"END;\n" "END;\n"
, FALSE, trx); , FALSE, trx);
ut_ad(err != DB_DUPLICATE_KEY);
/* SYS_TABLESPACES and SYS_DATAFILES need to be updated if /* SYS_TABLESPACES and SYS_DATAFILES need to be updated if
the table is in a single-table tablespace. */ the table is in a single-table tablespace. */
if (err != DB_SUCCESS || !dict_table_is_file_per_table(table)) { if (err != DB_SUCCESS || !dict_table_is_file_per_table(table)) {

View File

@ -1,7 +1,7 @@
/***************************************************************************** /*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, 2020, MariaDB Corporation. Copyright (c) 2015, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@ -407,9 +407,11 @@ void trx_t::free()
MEM_NOACCESS(&n_ref, sizeof n_ref); MEM_NOACCESS(&n_ref, sizeof n_ref);
/* do not poison mutex */ /* do not poison mutex */
MEM_NOACCESS(&id, sizeof id); MEM_NOACCESS(&id, sizeof id);
/* state is accessed by innobase_kill_connection() */ MEM_NOACCESS(&state, sizeof state);
MEM_NOACCESS(&is_recovered, sizeof is_recovered); MEM_NOACCESS(&is_recovered, sizeof is_recovered);
/* wsrep is accessed by innobase_kill_connection() */ #ifdef WITH_WSREP
MEM_NOACCESS(&wsrep, sizeof wsrep);
#endif
read_view.mem_noaccess(); read_view.mem_noaccess();
MEM_NOACCESS(&lock, sizeof lock); MEM_NOACCESS(&lock, sizeof lock);
MEM_NOACCESS(&op_info, sizeof op_info); MEM_NOACCESS(&op_info, sizeof op_info);
@ -427,7 +429,7 @@ void trx_t::free()
MEM_NOACCESS(&start_time_micro, sizeof start_time_micro); MEM_NOACCESS(&start_time_micro, sizeof start_time_micro);
MEM_NOACCESS(&commit_lsn, sizeof commit_lsn); MEM_NOACCESS(&commit_lsn, sizeof commit_lsn);
MEM_NOACCESS(&table_id, sizeof table_id); MEM_NOACCESS(&table_id, sizeof table_id);
/* mysql_thd is accessed by innobase_kill_connection() */ MEM_NOACCESS(&mysql_thd, sizeof mysql_thd);
MEM_NOACCESS(&mysql_log_file_name, sizeof mysql_log_file_name); MEM_NOACCESS(&mysql_log_file_name, sizeof mysql_log_file_name);
MEM_NOACCESS(&mysql_log_offset, sizeof mysql_log_offset); MEM_NOACCESS(&mysql_log_offset, sizeof mysql_log_offset);
MEM_NOACCESS(&n_mysql_tables_in_use, sizeof n_mysql_tables_in_use); MEM_NOACCESS(&n_mysql_tables_in_use, sizeof n_mysql_tables_in_use);

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