Skip to content

Commit cedb0ed

Browse files
committed
MDEV-37991 : Galera cluster crashes when granting permission to non existing user after setting max_error_count and wsrep_ignore_apply_errors to zero
There was two problems. Firsty, implementation assumed that thd->wsrep_rgi is not nullptr, this is not true for TOI. Secondly, Sql_condition_iterator was also assumed to be not nullptr, this might not be also true. Fixed by adding nullptr guard for thd->wsrep_rgi and if Sql_condition_iterator is nullptr obtain error information directly from Diagnostics_area if there is some error there.
1 parent 814787f commit cedb0ed

File tree

3 files changed

+91
-17
lines changed

3 files changed

+91
-17
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
connection node_2;
2+
connection node_1;
3+
connection node_1;
4+
connection node_2;
5+
connection node_2;
6+
SET SESSION max_error_count=0;
7+
SET GLOBAL wsrep_ignore_apply_errors = 0;
8+
GRANT SELECT ON *.* TO dummy@'localhost';
9+
ERROR 28000: Can't find any matching row in the user table
10+
SHOW WARNINGS;
11+
Level Code Message
12+
# Node_2 is on inconsistency state so kill it
13+
SET SESSION wsrep_sync_wait = 0;
14+
Killing server ...
15+
connection node_1;
16+
connection node_2;
17+
SET GLOBAL wsrep_ignore_apply_errors = DEFAULT;
18+
call mtr.add_suppression("Inconsistency detected: Inconsistent by consensus on");
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--source include/galera_cluster.inc
2+
3+
# Save original auto_increment_offset values.
4+
--let $node_1=node_1
5+
--let $node_2=node_2
6+
--source include/auto_increment_offset_save.inc
7+
8+
--connection node_2
9+
SET SESSION max_error_count=0;
10+
SET GLOBAL wsrep_ignore_apply_errors = 0;
11+
--error ER_PASSWORD_NO_MATCH
12+
GRANT SELECT ON *.* TO dummy@'localhost';
13+
SHOW WARNINGS;
14+
--echo # Node_2 is on inconsistency state so kill it
15+
SET SESSION wsrep_sync_wait = 0;
16+
--source include/kill_galera.inc
17+
18+
--let $start_mysqld_params =
19+
--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.2.expect
20+
--source include/start_mysqld.inc
21+
--source include/wait_until_ready.inc
22+
23+
--connection node_1
24+
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'
25+
--source include/wait_condition.inc
26+
27+
--connection node_2
28+
SET GLOBAL wsrep_ignore_apply_errors = DEFAULT;
29+
call mtr.add_suppression("Inconsistency detected: Inconsistent by consensus on");
30+
--source include/auto_increment_offset_restore.inc

sql/wsrep_applier.cc

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (C) 2013-2024 Codership Oy <[email protected]>
1+
/* Copyright (C) 2013-2025 Codership Oy <[email protected]>
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -88,7 +88,8 @@ static void wsrep_store_error_rli(const THD* const thd,
8888
wsrep::mutable_buffer& dst,
8989
bool const include_msg)
9090
{
91-
Slave_reporting_capability* const rli= thd->wsrep_rgi->rli;
91+
Slave_reporting_capability* const rli= thd->wsrep_rgi ?
92+
thd->wsrep_rgi->rli : nullptr;
9293
if (rli && rli->last_error().number != 0)
9394
{
9495
auto error= rli->last_error();
@@ -108,14 +109,36 @@ static void wsrep_store_error_rli(const THD* const thd,
108109
}
109110
}
110111

112+
/* Helper function to print error message */
113+
static size_t wsrep_print_error(char* dst,
114+
const size_t dst_len,
115+
const bool include_msg,
116+
const uint err_code,
117+
const char* err_str)
118+
{
119+
size_t len;
120+
if (include_msg)
121+
{
122+
len= snprintf(dst, dst_len, " %s, Error_code: %d;",
123+
err_str, err_code);
124+
}
125+
else
126+
{
127+
len= snprintf(dst, dst_len, " Error_code: %d;",
128+
err_code);
129+
}
130+
return len;
131+
}
132+
111133
/* store error from diagnostic area */
112134
static void wsrep_store_error_da(const THD* const thd,
113135
wsrep::mutable_buffer& dst,
114136
bool const include_msg)
115137
{
138+
const Diagnostics_area* da= thd->get_stmt_da();
116139
Diagnostics_area::Sql_condition_iterator it=
117-
thd->get_stmt_da()->sql_conditions();
118-
const Sql_condition* cond;
140+
da->sql_conditions();
141+
const Sql_condition* cond=it++;
119142

120143
static size_t const max_len= 2*MAX_SLAVE_ERRMSG; // 2x so that we have enough
121144

@@ -124,23 +147,26 @@ static void wsrep_store_error_da(const THD* const thd,
124147
char* slider= dst.data();
125148
const char* const buf_end= slider + max_len - 1; // -1: leave space for \0
126149

127-
for (cond= it++; cond && slider < buf_end; cond= it++)
150+
if (cond)
128151
{
129-
uint const err_code= cond->get_sql_errno();
130-
const char* const err_str= cond->get_message_text();
131-
132-
if (include_msg)
133-
{
134-
slider+= snprintf(slider, buf_end - slider, " %s, Error_code: %d;",
135-
err_str, err_code);
136-
}
137-
else
152+
for (; cond && slider < buf_end; cond= it++)
138153
{
139-
slider+= snprintf(slider, buf_end - slider, " Error_code: %d;",
140-
err_code);
154+
uint const err_code= cond->get_sql_errno();
155+
const char* const err_str= cond->get_message_text();
156+
slider+= wsrep_print_error(slider, buf_end-slider,
157+
include_msg, err_code, err_str);
141158
}
142159
}
143-
160+
else if (da->is_error())
161+
{
162+
// For example during TOI SQL_condition_iterator
163+
// could be nullptr, get error from Diagnostics
164+
// area directly.
165+
uint const err_code= da->sql_errno();
166+
const char* const err_str= da->message();
167+
slider+= wsrep_print_error(slider, buf_end-slider,
168+
include_msg, err_code, err_str);
169+
}
144170
if (slider != dst.data())
145171
{
146172
*slider= '\0';

0 commit comments

Comments
 (0)