Skip to content

Commit 79f8bff

Browse files
committed
BUG# 35020512 - Provide an option in mysqldump to disable
FLUSH TABLES WITH READ LOCK so that RELOAD privilege is not required [mysql-5.7] Problem: ------- Starting mysqldump with --single-transaction is throwing the below error for users without the RELOAD privilege: mysqldump: Couldn't execute 'FLUSH TABLES': Access denied; you need (at least one of) the RELOAD privilege(s) for this operation (1227) Analysis: --------- The changes made in the bug fix of 33630199 caused a regression in which whenever user passes --single-transaction, mysqldump tries to perform FLUSH TABLES WITH READ LOCK. Now "FLUSH TABLES" operation requires the users to have the RELOAD privilege, and many dump users do not have this privilege. This FLUSH TABLES was required in the case of bug 33630199 where it had issues with GTID consistency, and FLUSH TABLES was solving this issue, but the FLUSH TABLES is not required for every dump started with --single-transaction. It is needed only when the server has GTIDs enabled and --set-gtid-purged is set to ON or AUTO. This is how it was checking if FLUSH TABLES is needed, previously: if ((opt_lock_all_tables || opt_master_data || (opt_single_transaction && flush_logs)) && do_flush_tables_read_lock(mysql)) goto err; after the bug fix of 33630199, it was changed to this if ((opt_lock_all_tables || opt_master_data || opt_single_transaction) && do_flush_tables_read_lock(mysql)) goto err; and this, performs FLUSH TABLES every time the user passes --single-transaction. Fix: ---- The fix is to perform FLUSH TABLES only when GTIDs are enabled on the server, AND --set-gtid-purged is set to ON /or/ AUTO No need to perform FLUSH TABLES for every dump started with --single-transaction. Restored the previous if block, with one additional check for condition mentioned above. Change-Id: I08bcf3813b6a9d405863c1e9f667c85b3e059288
1 parent da1f0f9 commit 79f8bff

File tree

4 files changed

+132
-35
lines changed

4 files changed

+132
-35
lines changed

client/mysqldump.c

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -603,7 +603,7 @@ char check_if_ignore_table(const char *table_name, char *table_type);
603603
static char *primary_key_fields(const char *table_name);
604604
static my_bool get_view_structure(char *table, char* db);
605605
static my_bool dump_all_views_in_db(char *database);
606-
static int get_gtid_mode(MYSQL* mysql);
606+
static my_bool get_gtid_mode(MYSQL* mysql);
607607
static int dump_all_tablespaces();
608608
static int dump_tablespaces_for_tables(char *db, char **table_names, int tables);
609609
static int dump_tablespaces_for_databases(char** databases);
@@ -5880,19 +5880,16 @@ static my_bool get_gtids_executed(MYSQL* mysql, MYSQL_RES** gtid_executed)
58805880
/**
58815881
This function checks if GTIDs are enabled on the server.
58825882
5883-
@param[in] mysql the connection to the server
5883+
@param[in] mysql the connection to the server
58845884
5885-
@retval 1 if GTIDs are enabled on the server
5886-
5887-
@retval 0 if GTIDs are disabled on the server
5888-
5889-
@retval EX_MYSQLERR error, query execution failed
5885+
@retval TRUE if GTIDs are enabled on the server
58905886
5887+
@retval FALSE if GTIDs are disabled on the server
58915888
*/
5892-
static int get_gtid_mode(MYSQL* mysql)
5889+
static my_bool get_gtid_mode(MYSQL* mysql)
58935890
{
58945891
char* gtid_mode_val = 0;
5895-
int gtid_mode = 0;
5892+
my_bool gtid_mode = FALSE;
58965893
MYSQL_RES* gtid_mode_res;
58975894
MYSQL_ROW gtid_mode_row;
58985895

@@ -5902,7 +5899,7 @@ static int get_gtid_mode(MYSQL* mysql)
59025899
*/
59035900
if (mysql_query_with_error_report(mysql, &gtid_mode_res,
59045901
"SHOW VARIABLES LIKE 'gtid_mode'"))
5905-
return EX_MYSQLERR;
5902+
return FALSE;
59065903

59075904
gtid_mode_row = mysql_fetch_row(gtid_mode_res);
59085905

@@ -5911,7 +5908,7 @@ static int get_gtid_mode(MYSQL* mysql)
59115908
get the gtid_mode value from the second column.
59125909
*/
59135910
gtid_mode_val = gtid_mode_row ? (char*)gtid_mode_row[1] : NULL;
5914-
gtid_mode = (gtid_mode_val && strcmp(gtid_mode_val, "OFF")) ? 1 : 0;
5911+
gtid_mode = (gtid_mode_val && strcmp(gtid_mode_val, "OFF")) ? TRUE : FALSE;
59155912
mysql_free_result(gtid_mode_res);
59165913

59175914
return gtid_mode;
@@ -6045,6 +6042,8 @@ static my_bool add_set_gtid_purged(MYSQL *mysql_con,
60456042
SELECT @@GLOBAL.GTID_EXECUTED
60466043
has been provided in gtid_array
60476044
6045+
@param[in] is_gtid_enabled TRUE if server has gtid_mode ON
6046+
60486047
@retval FALSE successful according to the value
60496048
of opt_set_gtid_purged.
60506049
@@ -6053,19 +6052,13 @@ static my_bool add_set_gtid_purged(MYSQL *mysql_con,
60536052

60546053
static my_bool process_set_gtid_purged(MYSQL* mysql_con, my_bool flag,
60556054
MY_GTID_ARRAY *gtid_array,
6056-
my_bool gtid_executed_provided)
6055+
my_bool gtid_executed_provided,
6056+
my_bool is_gtid_enabled)
60576057
{
6058-
int gtid_mode = 0;
6059-
60606058
if (opt_set_gtid_purged_mode == SET_GTID_PURGED_OFF)
60616059
return FALSE; /* nothing to be done */
60626060

6063-
gtid_mode = get_gtid_mode(mysql_con);
6064-
6065-
if(gtid_mode == EX_MYSQLERR)
6066-
return TRUE;
6067-
6068-
if (gtid_mode)
6061+
if (is_gtid_enabled)
60696062
{
60706063
/*
60716064
For any gtid_mode !=OFF and irrespective of --set-gtid-purged
@@ -6366,9 +6359,9 @@ static void dynstr_realloc_checked(DYNAMIC_STRING *str, size_t additional_size)
63666359
int main(int argc, char **argv)
63676360
{
63686361
MY_GTID_ARRAY* gtid_arr = NULL;
6362+
my_bool server_has_gtid_enabled = FALSE;
63696363
my_bool single_trans_with_gtid_enabled = FALSE;
63706364
my_ulonglong idx = 0;
6371-
int server_has_gtid_enabled = 0;
63726365
char bin_log_name[FN_REFLEN];
63736366
int exit_code, md_result_fd;
63746367
MY_INIT("mysqldump");
@@ -6410,8 +6403,16 @@ int main(int argc, char **argv)
64106403
if (opt_slave_data && do_stop_slave_sql(mysql))
64116404
goto err;
64126405

6406+
/* check if server has GTIDs enabled */
6407+
server_has_gtid_enabled = get_gtid_mode(mysql);
6408+
6409+
single_trans_with_gtid_enabled =
6410+
(server_has_gtid_enabled && opt_single_transaction &&
6411+
(opt_set_gtid_purged_mode != SET_GTID_PURGED_OFF));
6412+
64136413
if ((opt_lock_all_tables || opt_master_data ||
6414-
opt_single_transaction) &&
6414+
(opt_single_transaction && (flush_logs ||
6415+
single_trans_with_gtid_enabled))) &&
64156416
do_flush_tables_read_lock(mysql))
64166417
goto err;
64176418

@@ -6420,8 +6421,9 @@ int main(int argc, char **argv)
64206421
this causes implicit commit starting mysql-5.5.
64216422
*/
64226423
if (opt_lock_all_tables || opt_master_data ||
6423-
opt_single_transaction ||
6424-
opt_delete_master_logs)
6424+
(opt_single_transaction && (flush_logs ||
6425+
single_trans_with_gtid_enabled)) ||
6426+
opt_delete_master_logs)
64256427
{
64266428
if (flush_logs || opt_delete_master_logs)
64276429
{
@@ -6447,15 +6449,6 @@ int main(int argc, char **argv)
64476449
if (opt_single_transaction && start_transaction(mysql))
64486450
goto err;
64496451

6450-
/* check if server has GTIDs enabled */
6451-
if((server_has_gtid_enabled = get_gtid_mode(mysql)) == EX_MYSQLERR)
6452-
goto err;
6453-
6454-
single_trans_with_gtid_enabled =
6455-
(server_has_gtid_enabled && opt_single_transaction &&
6456-
(opt_set_gtid_purged_mode != SET_GTID_PURGED_OFF));
6457-
6458-
64596452
if (single_trans_with_gtid_enabled)
64606453
{
64616454
/*
@@ -6502,7 +6495,7 @@ int main(int argc, char **argv)
65026495

65036496
/* Process opt_set_gtid_purged and add SET disable binlog if required. */
65046497
if (process_set_gtid_purged(mysql, FALSE, gtid_arr,
6505-
single_trans_with_gtid_enabled))
6498+
single_trans_with_gtid_enabled, server_has_gtid_enabled))
65066499
goto err;
65076500

65086501
if (opt_master_data && do_show_master_status(mysql))
@@ -6559,7 +6552,7 @@ int main(int argc, char **argv)
65596552

65606553
/* Process opt_set_gtid_purged and add SET @@GLOBAL.GTID_PURGED if required. */
65616554
if (process_set_gtid_purged(mysql, TRUE, gtid_arr,
6562-
single_trans_with_gtid_enabled))
6555+
single_trans_with_gtid_enabled, server_has_gtid_enabled))
65636556
goto err;
65646557

65656558
/* add 'START SLAVE' to end of dump */
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Create the test database
2+
CREATE DATABASE bug_test;
3+
USE bug_test;
4+
# Create the test table
5+
CREATE TABLE bug(n INT);
6+
# Enter random data which could be dumped
7+
INSERT INTO bug VALUES(10);
8+
INSERT INTO bug VALUES(20);
9+
INSERT INTO bug VALUES(30);
10+
# Create the test user
11+
CREATE USER test@localhost;
12+
# Grant only SELECT privilege on the test database
13+
GRANT SELECT ON bug_test.* TO test@localhost;
14+
SHOW GRANTS FOR test@localhost;
15+
Grants for test@localhost
16+
GRANT USAGE ON *.* TO 'test'@'localhost'
17+
GRANT SELECT ON `bug_test`.* TO 'test'@'localhost'
18+
# Create the dump file
19+
# Start the dump tests
20+
# ----- Test 1 -----
21+
# GTID enabled on the server, --set-gtid-purged is set to it's default value (AUTO).
22+
# Should fail because of insufficient privileges.
23+
# Start the dump
24+
# ----- Test 1 succeeded -----
25+
# ----- Test 2 -----
26+
# GTID enabled on the server, --set-gtid-purged is set to OFF
27+
# Should succeed
28+
# ----- Test 2 succeeded -----
29+
# ----- Test 3 -----
30+
# Increase the privileges of test user by granting RELOAD privilege
31+
GRANT RELOAD ON *.* TO test@localhost;
32+
SHOW GRANTS FOR test@localhost;
33+
Grants for test@localhost
34+
GRANT RELOAD ON *.* TO 'test'@'localhost'
35+
GRANT SELECT ON `bug_test`.* TO 'test'@'localhost'
36+
# Start the dump with --set-gtid-purged=ON
37+
# Should succeed
38+
# ----- Test 3 succeeded -----
39+
# ----- End of tests -----
40+
DROP USER test@localhost;
41+
DROP DATABASE bug_test;
42+
RESET MASTER;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--gtid-mode=ON --enforce-gtid-consistency --log-bin=ON
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#
2+
# BUG 35020512 - Provide an option in mysqldump to disable
3+
# 'FLUSH TABLES WITH READ LOCK' so that RELOAD privilege is not required
4+
#
5+
6+
# Test is not required to run against embedded server
7+
--source include/not_embedded.inc
8+
9+
--echo # Create the test database
10+
CREATE DATABASE bug_test;
11+
USE bug_test;
12+
13+
--echo # Create the test table
14+
CREATE TABLE bug(n INT);
15+
16+
--echo # Enter random data which could be dumped
17+
INSERT INTO bug VALUES(10);
18+
INSERT INTO bug VALUES(20);
19+
INSERT INTO bug VALUES(30);
20+
21+
--echo # Create the test user
22+
CREATE USER test@localhost;
23+
24+
--echo # Grant only SELECT privilege on the test database
25+
GRANT SELECT ON bug_test.* TO test@localhost;
26+
SHOW GRANTS FOR test@localhost;
27+
28+
--echo # Create the dump file
29+
let $mysqldumpfile = $MYSQLTEST_VARDIR/tmp/bug35020512_dump.sql;
30+
31+
--echo # Start the dump tests
32+
--echo # ----- Test 1 -----
33+
--echo # GTID enabled on the server, --set-gtid-purged is set to it's default value (AUTO).
34+
--echo # Should fail because of insufficient privileges.
35+
--echo # Start the dump
36+
--error 2
37+
--exec $MYSQL_DUMP bug_test -utest --single-transaction --no-tablespaces> $mysqldumpfile
38+
--echo # ----- Test 1 succeeded -----
39+
40+
--echo # ----- Test 2 -----
41+
--echo # GTID enabled on the server, --set-gtid-purged is set to OFF
42+
--echo # Should succeed
43+
--exec $MYSQL_DUMP bug_test -utest --single-transaction --set-gtid-purged=off --no-tablespaces > $mysqldumpfile
44+
--echo # ----- Test 2 succeeded -----
45+
46+
--echo # ----- Test 3 -----
47+
--echo # Increase the privileges of test user by granting RELOAD privilege
48+
GRANT RELOAD ON *.* TO test@localhost;
49+
SHOW GRANTS FOR test@localhost;
50+
--echo # Start the dump with --set-gtid-purged=ON
51+
--echo # Should succeed
52+
--exec $MYSQL_DUMP bug_test -utest --single-transaction --set-gtid-purged=ON --no-tablespaces > $mysqldumpfile
53+
--echo # ----- Test 3 succeeded -----
54+
55+
--echo # ----- End of tests -----
56+
57+
# Cleanup
58+
DROP USER test@localhost;
59+
DROP DATABASE bug_test;
60+
RESET MASTER;
61+
--remove_file $mysqldumpfile

0 commit comments

Comments
 (0)