Skip to content
/ server Public
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions mysql-test/suite/galera/r/galera_max_ws_rows.result
Original file line number Diff line number Diff line change
@@ -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;
1 change: 1 addition & 0 deletions mysql-test/suite/galera/r/galera_var_max_ws_rows.result
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
104 changes: 104 additions & 0 deletions mysql-test/suite/galera/t/galera_max_ws_rows.test
Original file line number Diff line number Diff line change
@@ -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;
1 change: 1 addition & 0 deletions mysql-test/suite/galera/t/galera_var_max_ws_rows.test
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
35 changes: 35 additions & 0 deletions sql/sql_update.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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*).
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 4 additions & 2 deletions sql/sys_vars.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -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", "",
Expand Down
23 changes: 23 additions & 0 deletions sql/wsrep_var.cc
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
2 changes: 2 additions & 0 deletions sql/wsrep_var.h
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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;

Expand Down