mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
MDEV-28750 : Assertion `trans_safe || !updated || thd->transaction->stmt.modified_non_trans_table' failed in virtual bool multi_update::send_eof()
Problem was that in multi-table update that contains tables that are not transactional and tables that are transactional error handling does not work correctly if write set size is limited. Because, Galera replication for MyISAM is experimental it is better to avoid multi-table updates in this case. Fixed by not allowing multi-table updates if statement contains non transactional and transactional tables and write set size is limited.
This commit is contained in:
committed by
Jan Lindström
parent
e78756fe20
commit
1f34996880
112
mysql-test/suite/galera/r/galera_max_ws_rows.result
Normal file
112
mysql-test/suite/galera/r/galera_max_ws_rows.result
Normal file
@@ -0,0 +1,112 @@
|
||||
connection node_2;
|
||||
connection node_1;
|
||||
CREATE TABLE ti (a INT UNSIGNED, b SMALLINT, id BIGINT NOT NULL, KEY(b), PRIMARY KEY(id)) ENGINE=InnoDB;
|
||||
CREATE TABLE tm (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=MyISAM;
|
||||
SET GLOBAL wsrep_max_ws_rows=2;
|
||||
START TRANSACTION;
|
||||
INSERT INTO tm SET b=NULL, a=2;
|
||||
INSERT INTO ti VALUES (1,2,4);
|
||||
UPDATE tm AS t1 SET t1.a=t1.a * 2;
|
||||
UPDATE ti AS t1 SET t1.a=t1.a * 2;
|
||||
UPDATE tm AS t1 SET t1.a=t1.a * 2;
|
||||
UPDATE ti AS t1 SET t1.a=t1.a * 2;
|
||||
ERROR HY000: Some non-transactional changed tables couldn't be rolled back
|
||||
SHOW WARNINGS;
|
||||
Level Code Message
|
||||
Error 1196 Some non-transactional changed tables couldn't be rolled back
|
||||
Error 1180 wsrep_max_ws_rows exceeded
|
||||
Error 1030 Got error 1180 "Unknown error 1180" from storage engine InnoDB
|
||||
COMMIT;
|
||||
SELECT * FROM ti;
|
||||
a b id
|
||||
SELECT * from tm;
|
||||
a b
|
||||
8 NULL
|
||||
DROP TABLE ti,tm;
|
||||
CREATE TABLE ti (a INT UNSIGNED, b SMALLINT, id BIGINT NOT NULL, KEY(b), PRIMARY KEY(id)) ENGINE=InnoDB;
|
||||
CREATE TABLE tm (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=MyISAM;
|
||||
SET GLOBAL wsrep_max_ws_rows=2;
|
||||
START TRANSACTION;
|
||||
INSERT INTO tm SET b=NULL, a=2;
|
||||
SET sql_mode=only_full_group_by;
|
||||
INSERT INTO ti VALUES (1,2,4);
|
||||
UPDATE tm AS t1, ti AS t2 SET t1.a=t1.a * 2, t2.a=t2.a * 2;
|
||||
ERROR HY000: Galera replication not supported
|
||||
UPDATE tm AS t1, ti AS t2 SET t1.a=t1.a * 2, t2.a=t2.a * 2;
|
||||
ERROR HY000: Galera replication not supported
|
||||
COMMIT;
|
||||
SELECT * FROM ti;
|
||||
a b id
|
||||
1 2 4
|
||||
SELECT * from tm;
|
||||
a b
|
||||
2 NULL
|
||||
DROP TABLE ti,tm;
|
||||
CREATE TABLE ti (a INT UNSIGNED, b SMALLINT, id BIGINT NOT NULL, KEY(b), PRIMARY KEY(id)) ENGINE=InnoDB;
|
||||
CREATE TABLE tm (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=MyISAM;
|
||||
START TRANSACTION;
|
||||
INSERT INTO tm SET b=NULL, a=2;
|
||||
SET sql_mode=only_full_group_by;
|
||||
INSERT INTO ti VALUES (1,2,4);
|
||||
SET GLOBAL wsrep_max_ws_rows=2;
|
||||
ERROR HY000: WSREP transaction is already active
|
||||
set GLOBAL wsrep_max_ws_size=2047;
|
||||
ERROR HY000: WSREP transaction is already active
|
||||
COMMIT;
|
||||
SELECT * FROM ti;
|
||||
a b id
|
||||
1 2 4
|
||||
SELECT * from tm;
|
||||
a b
|
||||
2 NULL
|
||||
DROP TABLE ti,tm;
|
||||
CREATE TABLE ti (a INT UNSIGNED, b SMALLINT, id BIGINT NOT NULL, KEY(b), PRIMARY KEY(id)) ENGINE=InnoDB;
|
||||
CREATE TABLE tm (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=InnoDB;
|
||||
SET GLOBAL wsrep_max_ws_rows=2;
|
||||
START TRANSACTION;
|
||||
INSERT INTO tm SET b=NULL, a=2;
|
||||
INSERT INTO ti VALUES (1,2,4);
|
||||
UPDATE tm AS t1, ti AS t2 SET t1.a=t1.a * 2, t2.a=t2.a * 2;
|
||||
ERROR HY000: wsrep_max_ws_rows exceeded
|
||||
UPDATE tm AS t1, ti AS t2 SET t1.a=t1.a * 2, t2.a=t2.a * 2;
|
||||
COMMIT;
|
||||
SELECT * FROM ti;
|
||||
a b id
|
||||
SELECT * from tm;
|
||||
a b
|
||||
DROP TABLE ti,tm;
|
||||
CREATE TABLE ti (a INT UNSIGNED, b SMALLINT, id BIGINT NOT NULL, KEY(b), PRIMARY KEY(id)) ENGINE=InnoDB;
|
||||
CREATE TABLE tm (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=MyISAM;
|
||||
SET GLOBAL wsrep_max_ws_rows=0;
|
||||
START TRANSACTION;
|
||||
INSERT INTO tm SET b=NULL, a=2;
|
||||
INSERT INTO ti VALUES (1,2,4);
|
||||
UPDATE tm AS t1, ti AS t2 SET t1.a=t1.a * 2, t2.a=t2.a * 2;
|
||||
UPDATE tm AS t1, ti AS t2 SET t1.a=t1.a * 2, t2.a=t2.a * 2;
|
||||
COMMIT;
|
||||
SELECT * FROM ti;
|
||||
a b id
|
||||
4 2 4
|
||||
SELECT * from tm;
|
||||
a b
|
||||
8 NULL
|
||||
DROP TABLE ti,tm;
|
||||
CREATE TABLE t1 (col INT);
|
||||
INSERT INTO t1 VALUES (0xF4AB);
|
||||
CREATE TEMPORARY TABLE t1 (c1 INT) ENGINE=mrg_myisam UNION=(t1) insert_method=FIRST;
|
||||
SET GLOBAL wsrep_max_ws_rows=1;
|
||||
DROP TABLES t1;
|
||||
INSERT INTO t1 VALUES (6373);
|
||||
CREATE TABLE t2 ENGINE=heap SELECT * FROM t1;
|
||||
DROP TABLE t1, t2;
|
||||
SET default_storage_engine="HEAP";
|
||||
CREATE TABLE t1 (f1 BIGINT);
|
||||
SET GLOBAL wsrep_max_ws_rows = 1;
|
||||
INSERT INTO t1 VALUES (NOW()),(NOW()),(NOW());
|
||||
SELECT COUNT(*) AS EXPECT_3 FROM t1;
|
||||
EXPECT_3
|
||||
3
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (i INT) ENGINE=MyISAM DEFAULT CHARSET=utf8 SELECT 1 as i;
|
||||
DROP TABLE t1;
|
||||
SET GLOBAL wsrep_max_ws_rows=0;
|
||||
@@ -125,6 +125,7 @@ CREATE TABLE t1(c1 INT)ENGINE = INNODB;
|
||||
SET GLOBAL wsrep_max_ws_rows= DEFAULT;
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
COMMIT;
|
||||
SET GLOBAL wsrep_max_ws_rows= 1;
|
||||
ALTER TABLE t1 CHANGE COLUMN c1 c1 BIGINT;
|
||||
connection node_2;
|
||||
|
||||
104
mysql-test/suite/galera/t/galera_max_ws_rows.test
Normal file
104
mysql-test/suite/galera/t/galera_max_ws_rows.test
Normal file
@@ -0,0 +1,104 @@
|
||||
--source include/galera_cluster.inc
|
||||
|
||||
#
|
||||
# MDEV-28750 Assertion `trans_safe || !updated || thd->transaction->stmt.modified_non_trans_table' failed in virtual bool multi_update::send_eof()
|
||||
#
|
||||
CREATE TABLE ti (a INT UNSIGNED, b SMALLINT, id BIGINT NOT NULL, KEY(b), PRIMARY KEY(id)) ENGINE=InnoDB;
|
||||
CREATE TABLE tm (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=MyISAM;
|
||||
SET GLOBAL wsrep_max_ws_rows=2;
|
||||
START TRANSACTION;
|
||||
INSERT INTO tm SET b=NULL, a=2;
|
||||
INSERT INTO ti VALUES (1,2,4);
|
||||
UPDATE tm AS t1 SET t1.a=t1.a * 2;
|
||||
UPDATE ti AS t1 SET t1.a=t1.a * 2;
|
||||
UPDATE tm AS t1 SET t1.a=t1.a * 2;
|
||||
--error ER_WARNING_NOT_COMPLETE_ROLLBACK
|
||||
UPDATE ti AS t1 SET t1.a=t1.a * 2;
|
||||
SHOW WARNINGS;
|
||||
COMMIT;
|
||||
SELECT * FROM ti;
|
||||
SELECT * from tm;
|
||||
DROP TABLE ti,tm;
|
||||
|
||||
CREATE TABLE ti (a INT UNSIGNED, b SMALLINT, id BIGINT NOT NULL, KEY(b), PRIMARY KEY(id)) ENGINE=InnoDB;
|
||||
CREATE TABLE tm (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=MyISAM;
|
||||
SET GLOBAL wsrep_max_ws_rows=2;
|
||||
START TRANSACTION;
|
||||
INSERT INTO tm SET b=NULL, a=2;
|
||||
SET sql_mode=only_full_group_by;
|
||||
INSERT INTO ti VALUES (1,2,4);
|
||||
--error ER_GALERA_REPLICATION_NOT_SUPPORTED
|
||||
UPDATE tm AS t1, ti AS t2 SET t1.a=t1.a * 2, t2.a=t2.a * 2;
|
||||
--error ER_GALERA_REPLICATION_NOT_SUPPORTED
|
||||
UPDATE tm AS t1, ti AS t2 SET t1.a=t1.a * 2, t2.a=t2.a * 2;
|
||||
COMMIT;
|
||||
SELECT * FROM ti;
|
||||
SELECT * from tm;
|
||||
DROP TABLE ti,tm;
|
||||
|
||||
CREATE TABLE ti (a INT UNSIGNED, b SMALLINT, id BIGINT NOT NULL, KEY(b), PRIMARY KEY(id)) ENGINE=InnoDB;
|
||||
CREATE TABLE tm (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=MyISAM;
|
||||
START TRANSACTION;
|
||||
INSERT INTO tm SET b=NULL, a=2;
|
||||
SET sql_mode=only_full_group_by;
|
||||
INSERT INTO ti VALUES (1,2,4);
|
||||
--error ER_WRONG_ARGUMENTS
|
||||
SET GLOBAL wsrep_max_ws_rows=2;
|
||||
--error ER_WRONG_ARGUMENTS
|
||||
set GLOBAL wsrep_max_ws_size=2047;
|
||||
COMMIT;
|
||||
SELECT * FROM ti;
|
||||
SELECT * from tm;
|
||||
DROP TABLE ti,tm;
|
||||
|
||||
CREATE TABLE ti (a INT UNSIGNED, b SMALLINT, id BIGINT NOT NULL, KEY(b), PRIMARY KEY(id)) ENGINE=InnoDB;
|
||||
CREATE TABLE tm (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=InnoDB;
|
||||
SET GLOBAL wsrep_max_ws_rows=2;
|
||||
START TRANSACTION;
|
||||
INSERT INTO tm SET b=NULL, a=2;
|
||||
INSERT INTO ti VALUES (1,2,4);
|
||||
--error ER_ERROR_DURING_COMMIT
|
||||
UPDATE tm AS t1, ti AS t2 SET t1.a=t1.a * 2, t2.a=t2.a * 2;
|
||||
UPDATE tm AS t1, ti AS t2 SET t1.a=t1.a * 2, t2.a=t2.a * 2;
|
||||
COMMIT;
|
||||
SELECT * FROM ti;
|
||||
SELECT * from tm;
|
||||
DROP TABLE ti,tm;
|
||||
|
||||
CREATE TABLE ti (a INT UNSIGNED, b SMALLINT, id BIGINT NOT NULL, KEY(b), PRIMARY KEY(id)) ENGINE=InnoDB;
|
||||
CREATE TABLE tm (a INT PRIMARY KEY, b MEDIUMTEXT) ENGINE=MyISAM;
|
||||
SET GLOBAL wsrep_max_ws_rows=0;
|
||||
START TRANSACTION;
|
||||
INSERT INTO tm SET b=NULL, a=2;
|
||||
INSERT INTO ti VALUES (1,2,4);
|
||||
UPDATE tm AS t1, ti AS t2 SET t1.a=t1.a * 2, t2.a=t2.a * 2;
|
||||
UPDATE tm AS t1, ti AS t2 SET t1.a=t1.a * 2, t2.a=t2.a * 2;
|
||||
COMMIT;
|
||||
SELECT * FROM ti;
|
||||
SELECT * from tm;
|
||||
DROP TABLE ti,tm;
|
||||
|
||||
#
|
||||
# MDEV-25548 Assertion `transactional_table || !changed || thd->transaction.stmt.modified_non_trans_table' failed.
|
||||
#
|
||||
CREATE TABLE t1 (col INT);
|
||||
INSERT INTO t1 VALUES (0xF4AB);
|
||||
CREATE TEMPORARY TABLE t1 (c1 INT) ENGINE=mrg_myisam UNION=(t1) insert_method=FIRST;
|
||||
SET GLOBAL wsrep_max_ws_rows=1;
|
||||
DROP TABLES t1;
|
||||
INSERT INTO t1 VALUES (6373);
|
||||
CREATE TABLE t2 ENGINE=heap SELECT * FROM t1;
|
||||
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
SET default_storage_engine="HEAP";
|
||||
CREATE TABLE t1 (f1 BIGINT);
|
||||
SET GLOBAL wsrep_max_ws_rows = 1;
|
||||
INSERT INTO t1 VALUES (NOW()),(NOW()),(NOW());
|
||||
SELECT COUNT(*) AS EXPECT_3 FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 (i INT) ENGINE=MyISAM DEFAULT CHARSET=utf8 SELECT 1 as i;
|
||||
DROP TABLE t1;
|
||||
|
||||
SET GLOBAL wsrep_max_ws_rows=0;
|
||||
@@ -159,6 +159,7 @@ CREATE TABLE t1(c1 INT)ENGINE = INNODB;
|
||||
SET GLOBAL wsrep_max_ws_rows= DEFAULT;
|
||||
INSERT INTO t1 VALUES(1);
|
||||
INSERT INTO t1 SELECT * FROM t1;
|
||||
COMMIT;
|
||||
SET GLOBAL wsrep_max_ws_rows= 1;
|
||||
ALTER TABLE t1 CHANGE COLUMN c1 c1 BIGINT;
|
||||
|
||||
|
||||
@@ -46,6 +46,11 @@
|
||||
#include "sql_insert.h" // For vers_insert_history_row() that may be
|
||||
// needed for System Versioning.
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
#include "wsrep_mysqld.h" // wsrep_max_ws_rows, wsrep_max_ws_size
|
||||
#include "wsrep_binlog.h" // WSREP_MAX_WS_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
True if the table's input and output record buffers are comparable using
|
||||
compare_record(TABLE*).
|
||||
@@ -2029,6 +2034,36 @@ bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List<Item> *fields,
|
||||
if (select_lex->vers_setup_conds(thd, table_list))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
#ifdef WITH_WSREP
|
||||
if (WSREP(thd))
|
||||
{
|
||||
bool transactional= false;
|
||||
bool non_trans= false;
|
||||
for (TABLE_LIST *tablel= table_list; tablel; tablel= tablel->next_global)
|
||||
{
|
||||
TABLE *table= tablel->table;
|
||||
if (table->file->has_transactions_and_rollback())
|
||||
transactional= true;
|
||||
else
|
||||
non_trans= true;
|
||||
}
|
||||
/* In multi-table update Galera does not support update to both
|
||||
transactional and non-transactional engines if write-set
|
||||
size is limited. */
|
||||
bool limited = (wsrep_max_ws_rows || wsrep_max_ws_size != WSREP_MAX_WS_SIZE);
|
||||
if (transactional && non_trans && limited)
|
||||
{
|
||||
my_error(ER_GALERA_REPLICATION_NOT_SUPPORTED, MYF(0));
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_GALERA_REPLICATION_NOT_SUPPORTED,
|
||||
"Galera does not support multi-table update",
|
||||
" to both transactional and non-transactional engines"
|
||||
" if write-set size is limited.");
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
#endif /* WITH_WSREP */
|
||||
|
||||
res= mysql_select(thd,
|
||||
table_list, total_list, conds,
|
||||
select_lex->order_list.elements,
|
||||
|
||||
@@ -6215,7 +6215,7 @@ static Sys_var_charptr Sys_wsrep_start_position (
|
||||
CMD_LINE(REQUIRED_ARG),
|
||||
DEFAULT(WSREP_START_POSITION_ZERO),
|
||||
NO_MUTEX_GUARD, NOT_IN_BINLOG,
|
||||
ON_CHECK(wsrep_start_position_check),
|
||||
ON_CHECK(wsrep_start_position_check),
|
||||
ON_UPDATE(wsrep_start_position_update));
|
||||
|
||||
static Sys_var_ulong Sys_wsrep_max_ws_size (
|
||||
@@ -6228,7 +6228,9 @@ static Sys_var_ulong Sys_wsrep_max_ws_size (
|
||||
static Sys_var_ulong Sys_wsrep_max_ws_rows (
|
||||
"wsrep_max_ws_rows", "Max number of rows in write set",
|
||||
GLOBAL_VAR(wsrep_max_ws_rows), CMD_LINE(REQUIRED_ARG),
|
||||
VALID_RANGE(0, 1048576), DEFAULT(0), BLOCK_SIZE(1));
|
||||
VALID_RANGE(0, 1048576), DEFAULT(0),
|
||||
BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG,
|
||||
ON_CHECK(wsrep_max_ws_rows_check), ON_UPDATE(0));
|
||||
|
||||
static Sys_var_charptr Sys_wsrep_notify_cmd(
|
||||
"wsrep_notify_cmd", "",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* Copyright 2008-2025 Codership Oy <http://www.codership.com>
|
||||
Copyright 2025-2026 MariaDB plc <http://www.mariadb.com>
|
||||
|
||||
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
|
||||
@@ -1005,6 +1006,11 @@ bool wsrep_max_ws_size_check(sys_var *self, THD* thd, set_var* var)
|
||||
my_message(ER_WRONG_ARGUMENTS, "WSREP (galera) not started", MYF(0));
|
||||
return true;
|
||||
}
|
||||
if (thd->wsrep_trx().active())
|
||||
{
|
||||
my_message(ER_WRONG_ARGUMENTS, "WSREP transaction is active", MYF(0));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1231,3 +1237,20 @@ bool wsrep_slave_threads_check (sys_var *self, THD* thd, set_var* var)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wsrep_max_ws_rows_check(sys_var *self, THD* thd, set_var* var)
|
||||
{
|
||||
unsigned long long max_rows= (unsigned long long)var->save_result.ulonglong_value;
|
||||
|
||||
// Default 0 is always allowed
|
||||
if (max_rows == 0)
|
||||
return false;
|
||||
|
||||
// Note that we allow changing this even when WSREP is not on
|
||||
if (thd->wsrep_trx().active())
|
||||
{
|
||||
my_message(ER_WRONG_ARGUMENTS, "WSREP transaction is active", MYF(0));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* Copyright (C) 2013-2025 Codership Oy <info@codership.com>
|
||||
Copyright (C) 2025-2026 MariaDB plc <http://www.mariadb.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -101,6 +102,7 @@ extern bool wsrep_trx_fragment_unit_update UPDATE_ARGS;
|
||||
|
||||
extern bool wsrep_max_ws_size_check CHECK_ARGS;
|
||||
extern bool wsrep_max_ws_size_update UPDATE_ARGS;
|
||||
extern bool wsrep_max_ws_rows_check CHECK_ARGS;
|
||||
|
||||
extern bool wsrep_reject_queries_update UPDATE_ARGS;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user