From 79ba84a702ae83db20e9a285927313a586d9721d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 26 Jul 2024 09:04:30 +0300 Subject: [PATCH 1/2] MDEV-34647 : 'INSERT...SELECT' on MyISAM table suddenly replicated by Galera Replication of MyISAM and Aria DML is experimental and best effort only. Earlier change make INSERT SELECT on both MyISAM and Aria to replicate using TOI and STATEMENT replication. Replication should happen only if user has set needed wsrep_mode setting. --- mysql-test/suite/galera/r/MDEV-34647.result | 101 ++++++++++++++++++++ mysql-test/suite/galera/r/mdev-22063.result | 4 + mysql-test/suite/galera/t/MDEV-34647.test | 52 ++++++++++ mysql-test/suite/galera/t/mdev-22063.test | 8 ++ sql/sql_parse.cc | 11 ++- 5 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/galera/r/MDEV-34647.result create mode 100644 mysql-test/suite/galera/t/MDEV-34647.test diff --git a/mysql-test/suite/galera/r/MDEV-34647.result b/mysql-test/suite/galera/r/MDEV-34647.result new file mode 100644 index 0000000000000..0333f14ece1d6 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-34647.result @@ -0,0 +1,101 @@ +connection node_2; +connection node_1; +create table t1(id serial, val varchar(100)) engine=myisam; +insert into t1 values(null, 'a'); +insert into t1 values(null, 'b'); +insert into t1 select null, 'c'; +insert into t1 select null, 'd' from t1; +select * from t1; +id val +1 a +3 b +5 c +7 d +9 d +11 d +create table t2(id serial, val varchar(100)) engine=aria; +insert into t2 values(null, 'a'); +insert into t2 values(null, 'b'); +insert into t2 select null, 'c'; +insert into t2 select null, 'd' from t2; +select * from t2; +id val +1 a +3 b +5 c +7 d +9 d +11 d +create table t3(id serial, val varchar(100)) engine=innodb; +insert into t3 values(null, 'a'); +insert into t3 values(null, 'b'); +insert into t3 select null, 'c'; +insert into t3 select null, 'd' from t3; +select * from t3; +id val +1 a +3 b +5 c +7 d +9 d +11 d +set global wsrep_mode='REPLICATE_MYISAM,REPLICATE_ARIA'; +create table t4(id serial, val varchar(100)) engine=myisam; +insert into t4 values(null, 'a'); +insert into t4 values(null, 'b'); +insert into t4 select null, 'c'; +insert into t4 select null, 'd' from t4; +select * from t4; +id val +1 a +2 b +3 c +4 d +5 d +6 d +create table t5(id serial, val varchar(100)) engine=myisam; +insert into t5 values(null, 'a'); +insert into t5 values(null, 'b'); +insert into t5 select null, 'c'; +insert into t5 select null, 'd' from t5; +select * from t2; +id val +1 a +3 b +5 c +7 d +9 d +11 d +connection node_2; +select * from t1; +id val +select * from t2; +id val +select * from t3; +id val +1 a +3 b +5 c +7 d +9 d +11 d +select * from t4; +id val +1 a +2 b +3 c +4 d +5 d +6 d +select * from t5; +id val +1 a +2 b +3 c +4 d +5 d +6 d +set global wsrep_mode=default; +connection node_1; +drop table t1,t2,t3,t4,t5; +set global wsrep_mode=default; diff --git a/mysql-test/suite/galera/r/mdev-22063.result b/mysql-test/suite/galera/r/mdev-22063.result index 155d1ebbe4ffd..15d86661650b7 100644 --- a/mysql-test/suite/galera/r/mdev-22063.result +++ b/mysql-test/suite/galera/r/mdev-22063.result @@ -17,12 +17,14 @@ SELECT * FROM s; next_not_cached_value minimum_value maximum_value start_value increment cache_size cycle_option cycle_count 1 1 9223372036854775806 1 1 1000 0 0 connection node_2; +SET GLOBAL WSREP_MODE='REPLICATE_ARIA,REPLICATE_MYISAM'; SELECT * FROM t1; a SELECT * FROM s; next_not_cached_value minimum_value maximum_value start_value increment cache_size cycle_option cycle_count 1 1 9223372036854775806 1 1 1000 0 0 connection node_1; +SET GLOBAL WSREP_MODE='REPLICATE_ARIA,REPLICATE_MYISAM'; DROP TABLE t1; DROP SEQUENCE s; # Case 2 REPLACE INTO ... SELECT with error @@ -239,3 +241,5 @@ pk DROP TABLE t1; DROP VIEW view_t1; SET GLOBAL wsrep_mode=DEFAULT; +connection node_2; +SET GLOBAL wsrep_mode=DEFAULT; diff --git a/mysql-test/suite/galera/t/MDEV-34647.test b/mysql-test/suite/galera/t/MDEV-34647.test new file mode 100644 index 0000000000000..db776681aa186 --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-34647.test @@ -0,0 +1,52 @@ +--source include/galera_cluster.inc +--source include/have_aria.inc + +create table t1(id serial, val varchar(100)) engine=myisam; +insert into t1 values(null, 'a'); +insert into t1 values(null, 'b'); +insert into t1 select null, 'c'; +insert into t1 select null, 'd' from t1; +select * from t1; + +create table t2(id serial, val varchar(100)) engine=aria; +insert into t2 values(null, 'a'); +insert into t2 values(null, 'b'); +insert into t2 select null, 'c'; +insert into t2 select null, 'd' from t2; +select * from t2; + +create table t3(id serial, val varchar(100)) engine=innodb; +insert into t3 values(null, 'a'); +insert into t3 values(null, 'b'); +insert into t3 select null, 'c'; +insert into t3 select null, 'd' from t3; +select * from t3; + +set global wsrep_mode='REPLICATE_MYISAM,REPLICATE_ARIA'; + +create table t4(id serial, val varchar(100)) engine=myisam; +insert into t4 values(null, 'a'); +insert into t4 values(null, 'b'); +insert into t4 select null, 'c'; +insert into t4 select null, 'd' from t4; +select * from t4; + +create table t5(id serial, val varchar(100)) engine=myisam; +insert into t5 values(null, 'a'); +insert into t5 values(null, 'b'); +insert into t5 select null, 'c'; +insert into t5 select null, 'd' from t5; +select * from t2; + + +--connection node_2 +select * from t1; +select * from t2; +select * from t3; +select * from t4; +select * from t5; +set global wsrep_mode=default; + +--connection node_1 +drop table t1,t2,t3,t4,t5; +set global wsrep_mode=default; diff --git a/mysql-test/suite/galera/t/mdev-22063.test b/mysql-test/suite/galera/t/mdev-22063.test index d3ddb164d3daa..e44c89af52472 100644 --- a/mysql-test/suite/galera/t/mdev-22063.test +++ b/mysql-test/suite/galera/t/mdev-22063.test @@ -16,6 +16,7 @@ SELECT * FROM t1; SELECT * FROM s; --connection node_2 +SET GLOBAL WSREP_MODE='REPLICATE_ARIA,REPLICATE_MYISAM'; --let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1' --source include/wait_condition.inc --let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 's' @@ -27,6 +28,7 @@ SELECT * FROM t1; SELECT * FROM s; --connection node_1 +SET GLOBAL WSREP_MODE='REPLICATE_ARIA,REPLICATE_MYISAM'; DROP TABLE t1; DROP SEQUENCE s; @@ -182,3 +184,9 @@ SELECT * FROM t1; DROP TABLE t1; DROP VIEW view_t1; SET GLOBAL wsrep_mode=DEFAULT; + +--connection node_1 +SET GLOBAL wsrep_mode=DEFAULT; + +--connection node_2 +SET GLOBAL wsrep_mode=DEFAULT; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index ea7b8325af25a..38fd969fff85f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4719,7 +4719,16 @@ mysql_execute_command(THD *thd, bool is_called_from_prepared_stmt) // For !InnoDB we start TOI if it is not yet started and hope for the best if (!is_innodb && !wsrep_toi) - WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL); + { + const legacy_db_type db_type= first_table->table->file->partition_ht()->db_type; + const bool replicate= + ((db_type == DB_TYPE_MYISAM && wsrep_check_mode(WSREP_MODE_REPLICATE_MYISAM)) || + (db_type == DB_TYPE_ARIA && wsrep_check_mode(WSREP_MODE_REPLICATE_ARIA))); + + /* Currently we support TOI for MyISAM and Aria only. */ + if (replicate) + WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL); + } } #endif /* WITH_WSREP */ /* From 5150106c6fe39ea711730a92f5dd69d1d9be5473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 2 Aug 2024 13:27:21 +0300 Subject: [PATCH 2/2] MDEV-30653 : With wsrep_mode=REPLICATE_ARIA only part of mixed-engine transactions is replicated For both MyISAM and Aria Galera replication is experimental. Problem was that both MyISAM and Aria do not support 2PC that is required if more than one storage engine participates transaction. For Galera we return error if transaction contains DML for MyISAM or Aria even if user has requested replication for them. --- mysql-test/suite/galera/r/MDEV-30653.result | 176 ++++++++++++++++++ .../r/galera_var_replicate_aria_on.result | 22 +-- .../r/galera_var_replicate_myisam_on.result | 28 +-- mysql-test/suite/galera/t/MDEV-30653.test | 156 ++++++++++++++++ .../t/galera_var_replicate_aria_on.test | 27 +-- .../t/galera_var_replicate_myisam_on.test | 26 +-- sql/sql_class.h | 5 + sql/sql_parse.cc | 13 ++ sql/wsrep_mysqld.cc | 26 +-- 9 files changed, 383 insertions(+), 96 deletions(-) create mode 100644 mysql-test/suite/galera/r/MDEV-30653.result create mode 100644 mysql-test/suite/galera/t/MDEV-30653.test diff --git a/mysql-test/suite/galera/r/MDEV-30653.result b/mysql-test/suite/galera/r/MDEV-30653.result new file mode 100644 index 0000000000000..a3233960416f0 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-30653.result @@ -0,0 +1,176 @@ +connection node_2; +connection node_1; +connection node_1; +create table t1 (id serial not null primary key, val int) engine=innodb; +create table t2 (id serial not null primary key, val int) engine=aria; +insert into t1 values(1, 23); +insert into t2 values(2, 42); +begin; +update t1 set val=24 where id=1; +update t2 set val=41 where id=2; +commit; +ERROR HY000: Transactional commit not supported by involved engine(s) +SELECT * FROM t1; +id val +1 23 +SELECT * FROM t2; +id val +2 41 +connection node_2; +SELECT * FROM t1; +id val +1 23 +SELECT * FROM t2; +id val +DROP TABLE t1, t2; +connection node_1; +SET GLOBAL wsrep_mode='REPLICATE_ARIA'; +create table t1 (id serial not null primary key, val int) engine=innodb; +create table t2 (id serial not null primary key, val int) engine=aria; +insert into t1 values(1, 23); +insert into t2 values(2, 42); +begin; +update t1 set val=24 where id=1; +update t2 set val=41 where id=2; +ERROR HY000: Galera does not support transactions containing engines not supporting 2 phase commit +commit; +SELECT * FROM t1; +id val +1 24 +SELECT * FROM t2; +id val +2 42 +connection node_2; +SELECT * FROM t1; +id val +1 24 +SELECT * FROM t2; +id val +2 42 +DROP TABLE t1, t2; +connection node_1; +SET GLOBAL wsrep_mode=''; +connection node_1; +SET GLOBAL wsrep_mode='REPLICATE_MYISAM'; +create table t1 (id serial not null primary key, val int) engine=innodb; +create table t2 (id serial not null primary key, val int) engine=myisam; +insert into t1 values(1, 23); +insert into t2 values(2, 42); +begin; +update t1 set val=24 where id=1; +update t2 set val=41 where id=2; +ERROR HY000: Galera does not support transactions containing engines not supporting 2 phase commit +commit; +SELECT * FROM t1; +id val +1 24 +SELECT * FROM t2; +id val +2 42 +connection node_2; +SELECT * FROM t1; +id val +1 24 +SELECT * FROM t2; +id val +2 42 +DROP TABLE t1, t2; +connection node_1; +SET GLOBAL wsrep_mode='REPLICATE_MYISAM,REPLICATE_ARIA'; +create table t1 (id serial not null primary key, val int) engine=innodb; +create table t2 (id serial not null primary key, val int) engine=myisam; +create table t3 (id serial not null primary key, val int) engine=aria; +insert into t1 values(1, 23); +insert into t2 values(2, 42); +insert into t3 values(3, 23); +begin; +update t1 set val=24 where id=1; +update t2 set val=41 where id=2; +ERROR HY000: Galera does not support transactions containing engines not supporting 2 phase commit +update t3 set val=24 where id=3; +ERROR HY000: Galera does not support transactions containing engines not supporting 2 phase commit +commit; +SELECT * FROM t1; +id val +1 24 +SELECT * FROM t2; +id val +2 42 +SELECT * FROM t3; +id val +3 23 +connection node_2; +SELECT * FROM t1; +id val +1 24 +SELECT * FROM t2; +id val +2 42 +SELECT * FROM t3; +id val +3 23 +DROP TABLE t1,t2,t3; +connection node_1; +SET GLOBAL wsrep_mode='REPLICATE_MYISAM,REPLICATE_ARIA'; +create table t1 (id serial not null primary key, val int) engine=innodb; +create table t2 (id serial not null primary key, val int) engine=myisam; +create table t3 (id serial not null primary key, val int) engine=aria; +insert into t1 values(1, 23); +insert into t2 values(2, 42); +insert into t3 values(3, 23); +begin; +update t2 set val=411 where id=2; +ERROR HY000: Galera does not support transactions containing engines not supporting 2 phase commit +update t3 set val=500 where id=3; +ERROR HY000: Galera does not support transactions containing engines not supporting 2 phase commit +update t1 set val=241 where id=1; +commit; +SELECT * FROM t1; +id val +1 241 +SELECT * FROM t2; +id val +2 42 +SELECT * FROM t3; +id val +3 23 +connection node_2; +SELECT * FROM t1; +id val +1 241 +SELECT * FROM t2; +id val +2 42 +SELECT * FROM t3; +id val +3 23 +DROP TABLE t1, t2, t3; +connection node_1; +create table t1 (id serial not null primary key, val int) engine=myisam; +create table t2 (id serial not null primary key, val int) engine=aria; +insert into t1 values(1, 23); +insert into t2 values(2, 42); +begin; +update t1 set val=411 where id=2; +ERROR HY000: Galera does not support transactions containing engines not supporting 2 phase commit +commit; +begin; +update t2 set val=411 where id=2; +ERROR HY000: Galera does not support transactions containing engines not supporting 2 phase commit +commit; +SELECT * FROM t1; +id val +1 23 +SELECT * FROM t2; +id val +2 42 +connection node_2; +SELECT * FROM t1; +id val +1 23 +SELECT * FROM t2; +id val +2 42 +DROP TABLE t1, t2; +connection node_1; +SET GLOBAL wsrep_mode=''; diff --git a/mysql-test/suite/galera/r/galera_var_replicate_aria_on.result b/mysql-test/suite/galera/r/galera_var_replicate_aria_on.result index 91c07ba6681e7..d7c974a87bc5e 100644 --- a/mysql-test/suite/galera/r/galera_var_replicate_aria_on.result +++ b/mysql-test/suite/galera/r/galera_var_replicate_aria_on.result @@ -103,33 +103,19 @@ connection node_1; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES (2); +ERROR HY000: Galera does not support transactions containing engines not supporting 2 phase commit INSERT INTO t2 VALUES (2); ROLLBACK; -Warnings: -Warning 1196 Some non-transactional changed tables couldn't be rolled back connection node_2; -SELECT COUNT(*) AS EXPECT_2 FROM t1; -EXPECT_2 -2 +SELECT COUNT(*) AS EXPECT_1 FROM t1; +EXPECT_1 +1 SELECT COUNT(*) AS EXPECT_1 FROM t2; EXPECT_1 1 connection node_1; DROP TABLE t1,t2; connection node_1; -CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=Aria; -CREATE TABLE t2 (f2 INTEGER PRIMARY KEY) ENGINE=InnoDB; -START TRANSACTION; -INSERT INTO t1 VALUES (1); -INSERT INTO t2 VALUES (1); -connection node_2; -INSERT INTO t1 VALUES (1); -ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -connection node_1; -COMMIT; -ERROR HY000: Transactional commit not supported by involved engine(s) -DROP TABLE t1,t2; -connection node_1; CREATE TABLE t1 (i INT NOT NULL PRIMARY KEY) ENGINE=INNODB; INSERT INTO t1 VALUES(1); SELECT * FROM t1; diff --git a/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result b/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result index d8463f6732f46..02ae7a62203b6 100644 --- a/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result +++ b/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result @@ -57,44 +57,32 @@ CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB; SET AUTOCOMMIT=OFF; START TRANSACTION; INSERT INTO t1 VALUES (1); +ERROR HY000: Galera does not support transactions containing engines not supporting 2 phase commit INSERT INTO t2 VALUES (1); COMMIT; connection node_2; -SELECT COUNT(*) AS EXPECT_1 FROM t1; -EXPECT_1 -1 +SELECT COUNT(*) AS EXPECT_0 FROM t1; +EXPECT_0 +0 SELECT COUNT(*) AS EXPECT_1 FROM t2; EXPECT_1 1 connection node_1; START TRANSACTION; INSERT INTO t1 VALUES (2); +ERROR HY000: Galera does not support transactions containing engines not supporting 2 phase commit INSERT INTO t2 VALUES (2); ROLLBACK; -Warnings: -Warning 1196 Some non-transactional changed tables couldn't be rolled back connection node_2; -SELECT COUNT(*) AS EXPECT_2 FROM t1; -EXPECT_2 -2 +SELECT COUNT(*) AS EXPECT_0 FROM t1; +EXPECT_0 +0 SELECT COUNT(*) AS EXPECT_1 FROM t2; EXPECT_1 1 DROP TABLE t1; DROP TABLE t2; connection node_1; -CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=MyISAM; -CREATE TABLE t2 (f2 INTEGER PRIMARY KEY) ENGINE=InnoDB; -START TRANSACTION; -INSERT INTO t1 VALUES (1); -INSERT INTO t2 VALUES (1); -connection node_2; -INSERT INTO t1 VALUES (1); -ERROR 23000: Duplicate entry '1' for key 'PRIMARY' -connection node_1; -COMMIT; -DROP TABLE t1, t2; -connection node_1; CREATE TABLE t1 (id INT NOT NULL PRIMARY KEY, b INT) ENGINE=MyISAM; INSERT INTO t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10); PREPARE upd from 'update t1 set b = 100 where id = 5'; diff --git a/mysql-test/suite/galera/t/MDEV-30653.test b/mysql-test/suite/galera/t/MDEV-30653.test new file mode 100644 index 0000000000000..f3ac47320d8fe --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-30653.test @@ -0,0 +1,156 @@ +--source include/galera_cluster.inc +--source include/have_aria.inc + +--connection node_1 +create table t1 (id serial not null primary key, val int) engine=innodb; +create table t2 (id serial not null primary key, val int) engine=aria; + +insert into t1 values(1, 23); +insert into t2 values(2, 42); + +begin; +update t1 set val=24 where id=1; +update t2 set val=41 where id=2; +--error ER_ERROR_DURING_COMMIT +commit; + +SELECT * FROM t1; +SELECT * FROM t2; + +--connection node_2 +SELECT * FROM t1; +SELECT * FROM t2; +DROP TABLE t1, t2; + +--connection node_1 +SET GLOBAL wsrep_mode='REPLICATE_ARIA'; +create table t1 (id serial not null primary key, val int) engine=innodb; +create table t2 (id serial not null primary key, val int) engine=aria; + +insert into t1 values(1, 23); +insert into t2 values(2, 42); + +begin; +update t1 set val=24 where id=1; +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +update t2 set val=41 where id=2; +commit; + +SELECT * FROM t1; +SELECT * FROM t2; + +--connection node_2 +SELECT * FROM t1; +SELECT * FROM t2; +DROP TABLE t1, t2; + +--connection node_1 +SET GLOBAL wsrep_mode=''; + +--connection node_1 +SET GLOBAL wsrep_mode='REPLICATE_MYISAM'; +create table t1 (id serial not null primary key, val int) engine=innodb; +create table t2 (id serial not null primary key, val int) engine=myisam; + +insert into t1 values(1, 23); +insert into t2 values(2, 42); + +begin; +update t1 set val=24 where id=1; +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +update t2 set val=41 where id=2; +commit; + +SELECT * FROM t1; +SELECT * FROM t2; + +--connection node_2 +SELECT * FROM t1; +SELECT * FROM t2; +DROP TABLE t1, t2; + +--connection node_1 +SET GLOBAL wsrep_mode='REPLICATE_MYISAM,REPLICATE_ARIA'; +create table t1 (id serial not null primary key, val int) engine=innodb; +create table t2 (id serial not null primary key, val int) engine=myisam; +create table t3 (id serial not null primary key, val int) engine=aria; + +insert into t1 values(1, 23); +insert into t2 values(2, 42); +insert into t3 values(3, 23); + +begin; +update t1 set val=24 where id=1; +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +update t2 set val=41 where id=2; +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +update t3 set val=24 where id=3; +commit; + +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +--connection node_2 +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; +DROP TABLE t1,t2,t3; + +--connection node_1 +SET GLOBAL wsrep_mode='REPLICATE_MYISAM,REPLICATE_ARIA'; +create table t1 (id serial not null primary key, val int) engine=innodb; +create table t2 (id serial not null primary key, val int) engine=myisam; +create table t3 (id serial not null primary key, val int) engine=aria; + +insert into t1 values(1, 23); +insert into t2 values(2, 42); +insert into t3 values(3, 23); + +begin; +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +update t2 set val=411 where id=2; +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +update t3 set val=500 where id=3; +update t1 set val=241 where id=1; +commit; + +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; + +--connection node_2 +SELECT * FROM t1; +SELECT * FROM t2; +SELECT * FROM t3; +DROP TABLE t1, t2, t3; + + +--connection node_1 +create table t1 (id serial not null primary key, val int) engine=myisam; +create table t2 (id serial not null primary key, val int) engine=aria; + +insert into t1 values(1, 23); +insert into t2 values(2, 42); +# +# Currently, we can't support single table transactional DML +# +begin; +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +update t1 set val=411 where id=2; +commit; +begin; +--error ER_GALERA_REPLICATION_NOT_SUPPORTED +update t2 set val=411 where id=2; +commit; + +SELECT * FROM t1; +SELECT * FROM t2; + +--connection node_2 +SELECT * FROM t1; +SELECT * FROM t2; +DROP TABLE t1, t2; + +--connection node_1 +SET GLOBAL wsrep_mode=''; diff --git a/mysql-test/suite/galera/t/galera_var_replicate_aria_on.test b/mysql-test/suite/galera/t/galera_var_replicate_aria_on.test index ac9a79e61962c..64e9c2334e2db 100644 --- a/mysql-test/suite/galera/t/galera_var_replicate_aria_on.test +++ b/mysql-test/suite/galera/t/galera_var_replicate_aria_on.test @@ -107,41 +107,18 @@ SELECT COUNT(*) AS EXPECT_1 FROM t2; --connection node_1 SET AUTOCOMMIT=OFF; START TRANSACTION; +--error ER_GALERA_REPLICATION_NOT_SUPPORTED INSERT INTO t1 VALUES (2); INSERT INTO t2 VALUES (2); ROLLBACK; --connection node_2 -SELECT COUNT(*) AS EXPECT_2 FROM t1; +SELECT COUNT(*) AS EXPECT_1 FROM t1; SELECT COUNT(*) AS EXPECT_1 FROM t2; --connection node_1 DROP TABLE t1,t2; -# -# Transaction conflict -# - ---connection node_1 -CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=Aria; -CREATE TABLE t2 (f2 INTEGER PRIMARY KEY) ENGINE=InnoDB; - -START TRANSACTION; -INSERT INTO t1 VALUES (1); -INSERT INTO t2 VALUES (1); - ---connection node_2 -# The Aria update is replicated immediately, so a duplicate key error happens even before the COMMIT ---error ER_DUP_ENTRY -INSERT INTO t1 VALUES (1); - ---connection node_1 - ---error ER_ERROR_DURING_COMMIT -COMMIT; - -DROP TABLE t1,t2; - --connection node_1 CREATE TABLE t1 (i INT NOT NULL PRIMARY KEY) ENGINE=INNODB; INSERT INTO t1 VALUES(1); diff --git a/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test b/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test index f405ebfdc4627..664838206e707 100644 --- a/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test +++ b/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test @@ -81,12 +81,13 @@ CREATE TABLE t1 (f1 INTEGER) ENGINE=MyISAM; CREATE TABLE t2 (f1 INTEGER) ENGINE=InnoDB; SET AUTOCOMMIT=OFF; START TRANSACTION; +--error ER_GALERA_REPLICATION_NOT_SUPPORTED INSERT INTO t1 VALUES (1); INSERT INTO t2 VALUES (1); COMMIT; --connection node_2 -SELECT COUNT(*) AS EXPECT_1 FROM t1; +SELECT COUNT(*) AS EXPECT_0 FROM t1; SELECT COUNT(*) AS EXPECT_1 FROM t2; # @@ -95,37 +96,18 @@ SELECT COUNT(*) AS EXPECT_1 FROM t2; --connection node_1 START TRANSACTION; +--error ER_GALERA_REPLICATION_NOT_SUPPORTED INSERT INTO t1 VALUES (2); INSERT INTO t2 VALUES (2); ROLLBACK; --connection node_2 -SELECT COUNT(*) AS EXPECT_2 FROM t1; +SELECT COUNT(*) AS EXPECT_0 FROM t1; SELECT COUNT(*) AS EXPECT_1 FROM t2; DROP TABLE t1; DROP TABLE t2; -# -# Transaction conflict -# - ---connection node_1 -CREATE TABLE t1 (f1 INTEGER PRIMARY KEY) ENGINE=MyISAM; -CREATE TABLE t2 (f2 INTEGER PRIMARY KEY) ENGINE=InnoDB; - -START TRANSACTION; -INSERT INTO t1 VALUES (1); -INSERT INTO t2 VALUES (1); - ---connection node_2 -# The MyISAM update is replicated immediately, so a duplicate key error happens even before the COMMIT ---error ER_DUP_ENTRY -INSERT INTO t1 VALUES (1); - ---connection node_1 -COMMIT; -DROP TABLE t1, t2; # # Test prepared staments # diff --git a/sql/sql_class.h b/sql/sql_class.h index a347700f72f0e..e197d06f63b99 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -7539,6 +7539,11 @@ class select_dumpvar :public select_result_interceptor { DDL statement that may be subject to error filtering. */ #define CF_WSREP_MAY_IGNORE_ERRORS (1U << 24) +/** + Basic DML statements that create writeset. +*/ +#define CF_WSREP_BASIC_DML (1u << 25) + #endif /* WITH_WSREP */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 38fd969fff85f..bb89b9087a639 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -895,6 +895,19 @@ void init_update_queries(void) sql_command_flags[SQLCOM_DROP_TABLE]|= CF_WSREP_MAY_IGNORE_ERRORS; sql_command_flags[SQLCOM_DROP_INDEX]|= CF_WSREP_MAY_IGNORE_ERRORS; sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_WSREP_MAY_IGNORE_ERRORS; + /* + Basic DML-statements that create writeset. + */ + sql_command_flags[SQLCOM_INSERT]|= CF_WSREP_BASIC_DML; + sql_command_flags[SQLCOM_INSERT_SELECT]|= CF_WSREP_BASIC_DML; + sql_command_flags[SQLCOM_REPLACE]|= CF_WSREP_BASIC_DML; + sql_command_flags[SQLCOM_REPLACE_SELECT]|= CF_WSREP_BASIC_DML; + sql_command_flags[SQLCOM_UPDATE]|= CF_WSREP_BASIC_DML; + sql_command_flags[SQLCOM_UPDATE_MULTI]|= CF_WSREP_BASIC_DML; + sql_command_flags[SQLCOM_LOAD]|= CF_WSREP_BASIC_DML; + sql_command_flags[SQLCOM_DELETE]|= CF_WSREP_BASIC_DML; + sql_command_flags[SQLCOM_DELETE_MULTI]|= CF_WSREP_BASIC_DML; + #endif /* WITH_WSREP */ } diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 471be8ec998ad..39acfd14c239c 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -1400,26 +1400,30 @@ bool wsrep_check_mode_after_open_table (THD *thd, TABLE_LIST *tables) { enum_sql_command sql_command= thd->lex->sql_command; - bool is_dml_stmt= thd->get_command() != COM_STMT_PREPARE && - (sql_command == SQLCOM_INSERT || - sql_command == SQLCOM_INSERT_SELECT || - sql_command == SQLCOM_REPLACE || - sql_command == SQLCOM_REPLACE_SELECT || - sql_command == SQLCOM_UPDATE || - sql_command == SQLCOM_UPDATE_MULTI || - sql_command == SQLCOM_LOAD || - sql_command == SQLCOM_DELETE); + bool is_dml_stmt= (thd->get_command() != COM_STMT_PREPARE && + (sql_command_flags[sql_command] & CF_WSREP_BASIC_DML)); if (!is_dml_stmt) return true; const legacy_db_type db_type= hton->db_type; - bool replicate= ((db_type == DB_TYPE_MYISAM && wsrep_check_mode(WSREP_MODE_REPLICATE_MYISAM)) || - (db_type == DB_TYPE_ARIA && wsrep_check_mode(WSREP_MODE_REPLICATE_ARIA))); + const bool replicate= ((db_type == DB_TYPE_MYISAM && wsrep_check_mode(WSREP_MODE_REPLICATE_MYISAM)) || + (db_type == DB_TYPE_ARIA && wsrep_check_mode(WSREP_MODE_REPLICATE_ARIA))); TABLE *tbl= tables->table; if (replicate) { + const bool in_trans= (thd->variables.option_bits & OPTION_BEGIN); + /* If wsrep already has changes it means we are inside a transaction OR + if begin has issued we are inside a transaction. Do not allow DML + to MyISAM or Aria then. */ + if (wsrep_has_changes(thd) || in_trans) + { + my_message(ER_GALERA_REPLICATION_NOT_SUPPORTED, + "Galera does not support transactions containing engines " + "not supporting 2 phase commit", MYF(0)); + return false; + } /* It is not recommended to replicate MyISAM as it lacks rollback feature but if user demands then actions are replicated using TOI. Following code will kick-start the TOI but this has to be done only once