From 07541bf30fc5d161d4ffd666810d50db29703946 Mon Sep 17 00:00:00 2001 From: Tian Xia Date: Tue, 5 Mar 2019 17:40:30 -0800 Subject: [PATCH] FB8-76: Add current master host:port to server read only error when available (#958) (#958) Summary: Jira ticket: https://jira.percona.com/browse/FB8-76 Reference Patch: https://github.com/facebook/mysql-5.6/commit/270854f Reference Patch: https://github.com/facebook/mysql-5.6/commit/9f00827 Reference Patch: https://github.com/facebook/mysql-5.6/commit/3e50e46 Reference Patch: https://github.com/facebook/mysql-5.6/commit/9f18725 When a server is in read_only, we append the current master_host and master_port to the error message, if the server is a slave. The master_host could be either hostname or ip address, depending on how a slave is connected to the master. A new generic error code `ER_OPTION_PREVENTS_STATEMENT_EXTRA_INFO` is added, so that we can append any additional info to the fixed error message. Proposing a way to set a custom message in the `--read-only (super)` error. Note: the variable can only be set when server is in read-only (super) state. p.s. I am hesitant to add a mutex for the variable, so we will get a snapshot of the current pointer of the variable (const char*) when printing the error. Per request, we allow setting read_only_error_msg_extra without being in read_only state. The custom message can be set/reset at any time. D61383 added a new error code to allow appending extra info to read_only error message. The new error code breaks existing dependencies which expects to receive code 1290. Reverting back to use the old error, and extending the 1290 error message instead of adding a new one. This involves updating many files (which was the motivation I added a new one in D61383). Ideally we should have a more elegant solution to send extra info back to clients, which will be worked on separately. This is to fix the broken dependencies. Pull Request resolved: https://github.com/facebook/mysql-5.6/pull/958 Reviewed By: lloyd Differential Revision: D14137345 Pulled By: lth --- mysql-test/r/bug58669.result | 1 + mysql-test/r/mysqld--help-notwin.result | 4 ++ .../r/rpl_gtid_while_super_read_only.result | 62 +++++++++---------- .../t/rpl_gtid_while_super_read_only.test | 33 ++++++++++ .../suite/rpl_nogtid/r/rpl_read_only.result | 6 +- .../rpl_nogtid/r/rpl_read_only_myisam.result | 6 +- .../suite/rpl_nogtid/t/rpl_read_only.test | 13 ++++ .../rpl_nogtid/t/rpl_read_only_myisam.test | 11 ++++ .../r/read_only_error_msg_extra_basic.result | 22 +++++++ .../t/read_only_error_msg_extra_basic.test | 25 ++++++++ share/messages_to_clients.txt | 12 ++-- sql/auth/sql_authorization.cc | 5 +- sql/auth/sql_user_table.cc | 4 +- sql/dd/impl/sdi_file.cc | 2 +- sql/mysqld.cc | 1 + sql/mysqld.h | 1 + sql/query_result.cc | 2 +- sql/rpl_replica.cc | 23 +++++++ sql/rpl_replica.h | 1 + sql/sql_load.cc | 5 +- sql/sql_parse.cc | 2 +- sql/sys_vars.cc | 9 ++- 22 files changed, 202 insertions(+), 48 deletions(-) create mode 100644 mysql-test/suite/sys_vars/r/read_only_error_msg_extra_basic.result create mode 100644 mysql-test/suite/sys_vars/t/read_only_error_msg_extra_basic.test diff --git a/mysql-test/r/bug58669.result b/mysql-test/r/bug58669.result index 0e88f0fb8450..25125c3bdcdf 100644 --- a/mysql-test/r/bug58669.result +++ b/mysql-test/r/bug58669.result @@ -11,6 +11,7 @@ user1@localhost SHOW VARIABLES LIKE "read_only%"; Variable_name Value read_only ON +read_only_error_msg_extra read_only_slave OFF INSERT INTO db1.t1 VALUES (1); ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result index 20ea1627e8a1..a1bb19e61912 100644 --- a/mysql-test/r/mysqld--help-notwin.result +++ b/mysql-test/r/mysqld--help-notwin.result @@ -1131,6 +1131,9 @@ The following options may be given as the first argument: --read-only Make all non-temporary tables read-only, with the exception for replication applier threads and users with the SUPER privilege. + --read-only-error-msg-extra[=name] + Set this variable to print out extra error information, + which will be appended to read_only error messages. --read-only-slave Blocks disabling read_only if the server is a slave. This is helpful in asserting that read_only is never disabled on a slave. Slave with read_only=0 may generate new GTID @@ -2564,6 +2567,7 @@ range-alloc-block-size 4096 range-optimizer-max-mem-size 8388608 read-buffer-size 131072 read-only FALSE +read-only-error-msg-extra read-only-slave TRUE read-rnd-buffer-size 262144 regexp-stack-limit 8000000 diff --git a/mysql-test/suite/rpl_gtid/r/rpl_gtid_while_super_read_only.result b/mysql-test/suite/rpl_gtid/r/rpl_gtid_while_super_read_only.result index 666aa8f5cdca..7e0c1609ce73 100644 --- a/mysql-test/suite/rpl_gtid/r/rpl_gtid_while_super_read_only.result +++ b/mysql-test/suite/rpl_gtid/r/rpl_gtid_while_super_read_only.result @@ -119,7 +119,7 @@ ALTER INSTANCE ROTATE BINLOG MASTER KEY; ALTER INSTANCE RELOAD TLS; include/gtid_step_assert.inc [count=0, only_count=0] ALTER INSTANCE ROTATE INNODB MASTER KEY; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT #### 6(a) FLUSH STATEMENTS AND CHECK GTID EXCECUTED [connection slave] FLUSH LOGS; @@ -210,7 +210,7 @@ SET GTID_NEXT = 'AUTOMATIC'; include/gtid_step_assert.inc [count=1, only_count=1] SET GTID_NEXT = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:3'; START TRANSACTION READ WRITE; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT SET GTID_NEXT = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa:4'; START TRANSACTION READ ONLY; COMMIT; @@ -234,57 +234,57 @@ PARTITION BY RANGE(c1) PARTITION p2 VALUES LESS THAN (10)); SET GLOBAL SUPER_READ_ONLY = ON; CREATE TABLE t_test(c1 INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT CREATE SPATIAL REFERENCE SYSTEM 13001000 NAME 'TEST13001000 Long-Lat WGS 84' DEFINITION 'GEOGCS["Long-Lat WGS 84",DATUM["World Geodetic System 1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.017453292519943278,AUTHORITY["EPSG","9122"]],AXIS["Lon",EAST],AXIS["Lat",NORTH],AUTHORITY["EPSG","4326"]]'; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'Remote', HOST '198.51.100.106', DATABASE 'test'); -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT CREATE LOGFILE GROUP lg1 ADD UNDOFILE 'undo.dat' INITIAL_SIZE = 10M; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT ALTER TABLE t_part TRUNCATE PARTITION p0, p1; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT ALTER TABLE t_hash DISCARD TABLESPACE; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT ALTER TABLE t_hash IMPORT TABLESPACE; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT ALTER TABLE t_hash COALESCE PARTITION 1; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT ALTER TABLE t_nopart1 REMOVE PARTITIONING; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT ALTER TABLE t_part EXCHANGE PARTITION sp00 WITH TABLE t_nopart1; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT ALTER TABLE t_part REBUILD PARTITION p0; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT ALTER TABLE t_part1 REORGANIZE PARTITION p1,p2 INTO (PARTITION p3 VALUES LESS THAN (300)); -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT ALTER TABLE t_part ADD PARTITION (PARTITION p3 VALUES LESS THAN (300)); -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT ALTER TABLE t_part DROP PARTITION p3; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT #### 10. [UN]INSTALL [PLUGIN | COMPONENT] include/gtid_step_reset.inc include/gtid_step_assert.inc [count=0, only_count=0] #### 11. [OPTIMIZE | ANALYZE | REPAIR] TABLE REPAIR TABLE t1; Table Op Msg_type Msg_text -test.t1 repair Error The MySQL server is running with the --super-read-only option so it cannot execute this statement +test.t1 repair Error The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT test.t1 repair error Corrupt include/gtid_step_assert.inc [count=1, only_count=0] ANALYZE TABLE t1; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT OPTIMIZE TABLE t1; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT #### 12. ALTER TABLE ... [OPTIMIZE | ANALYZE | REPAIR] PARTITION. include/gtid_step_reset.inc ALTER TABLE t_part OPTIMIZE PARTITION p0, p1; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT include/gtid_step_assert.inc [count=0, only_count=0] ALTER TABLE t_part ANALYZE PARTITION p0; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT include/gtid_step_assert.inc [count=0, only_count=0] ALTER TABLE t_part REPAIR PARTITION p0, p1; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT include/gtid_step_assert.inc [count=0, only_count=0] #### 13. Run GRANT, REVOKE, CREATE USER, DROP USER in a way that it #### fails, e.g., create two users where the second already exists. @@ -293,33 +293,33 @@ CREATE USER 'u1'@localhost IDENTIFIED BY ''; SET @@global.super_read_only = 1; include/gtid_step_reset.inc CREATE USER u1,u2; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT include/gtid_step_assert.inc [count=0, only_count=0] GRANT ALL ON *.* To u1,u2; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT include/gtid_step_assert.inc [count=0, only_count=0] REVOKE ALL ON *.* from u1; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT include/gtid_step_assert.inc [count=0, only_count=0] DROP USER u1; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT include/gtid_step_assert.inc [count=0, only_count=0] DROP USER u1,u2; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT include/gtid_step_assert.inc [count=0, only_count=0] #### 14. Run DML on mysql.gtid_executed, slave_master_info, #### slave_relay_log_info, and slave_worker_info tables. UPDATE mysql.slave_master_info SET Retry_count = Retry_count + 1; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT include/gtid_step_assert.inc [count=0, only_count=0] UPDATE mysql.slave_relay_log_info SET Sql_delay = Sql_delay + 1; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT include/gtid_step_assert.inc [count=0, only_count=0] UPDATE mysql.slave_worker_info SET Relay_log_pos = Relay_log_pos + 1; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT include/gtid_step_assert.inc [count=0, only_count=0] UPDATE mysql.gtid_executed SET interval_end = interval_end + 1; -ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --super-read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT include/gtid_step_assert.inc [count=0, only_count=0] #### 15. Cleanup SET GLOBAL READ_ONLY = OFF; diff --git a/mysql-test/suite/rpl_gtid/t/rpl_gtid_while_super_read_only.test b/mysql-test/suite/rpl_gtid/t/rpl_gtid_while_super_read_only.test index 4061ee6b3822..d14c6439d37d 100644 --- a/mysql-test/suite/rpl_gtid/t/rpl_gtid_while_super_read_only.test +++ b/mysql-test/suite/rpl_gtid/t/rpl_gtid_while_super_read_only.test @@ -300,6 +300,7 @@ ALTER INSTANCE RELOAD TLS; --let $gtid_step_count = 0 --source include/gtid_step_assert.inc +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER INSTANCE ROTATE INNODB MASTER KEY; @@ -485,6 +486,7 @@ SET GTID_NEXT = 'AUTOMATIC'; --source include/gtid_step_assert.inc eval SET GTID_NEXT = '$uuida:3'; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT START TRANSACTION READ WRITE; @@ -520,46 +522,60 @@ PARTITION BY RANGE(c1) PARTITION p2 VALUES LESS THAN (10)); SET GLOBAL SUPER_READ_ONLY = ON; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT CREATE TABLE t_test(c1 INT NOT NULL PRIMARY KEY) ENGINE=InnoDB; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT CREATE SPATIAL REFERENCE SYSTEM 13001000 NAME 'TEST13001000 Long-Lat WGS 84' DEFINITION 'GEOGCS["Long-Lat WGS 84",DATUM["World Geodetic System 1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.017453292519943278,AUTHORITY["EPSG","9122"]],AXIS["Lon",EAST],AXIS["Lat",NORTH],AUTHORITY["EPSG","4326"]]'; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT CREATE SERVER s1 FOREIGN DATA WRAPPER mysql OPTIONS (USER 'Remote', HOST '198.51.100.106', DATABASE 'test'); +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT CREATE LOGFILE GROUP lg1 ADD UNDOFILE 'undo.dat' INITIAL_SIZE = 10M; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER TABLE t_part TRUNCATE PARTITION p0, p1; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER TABLE t_hash DISCARD TABLESPACE; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER TABLE t_hash IMPORT TABLESPACE; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER TABLE t_hash COALESCE PARTITION 1; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER TABLE t_nopart1 REMOVE PARTITIONING; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER TABLE t_part EXCHANGE PARTITION sp00 WITH TABLE t_nopart1; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER TABLE t_part REBUILD PARTITION p0; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER TABLE t_part1 REORGANIZE PARTITION p1,p2 INTO (PARTITION p3 VALUES LESS THAN (300)); +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER TABLE t_part ADD PARTITION (PARTITION p3 VALUES LESS THAN (300)); +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER TABLE t_part DROP PARTITION p3; @@ -569,9 +585,11 @@ ALTER TABLE t_part DROP PARTITION p3; --source include/gtid_step_reset.inc # behavior changed with "D27213990 allow install/uninstall plugin when enable_super_log_bin_read_only is enabled" +#--replace_result $MASTER_MYPORT MASTER_PORT #--error ER_OPTION_PREVENTS_STATEMENT #INSTALL PLUGIN keyring_file SONAME 'keyring_file.so'; # +#--replace_result $MASTER_MYPORT MASTER_PORT #--error ER_OPTION_PREVENTS_STATEMENT #UNINSTALL PLUGIN keyring_file; @@ -582,14 +600,17 @@ ALTER TABLE t_part DROP PARTITION p3; --echo #### 11. [OPTIMIZE | ANALYZE | REPAIR] TABLE ######################################################################## +--replace_result $MASTER_MYPORT MASTER_PORT REPAIR TABLE t1; --let $gtid_step_count = 1 --source include/gtid_step_assert.inc +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ANALYZE TABLE t1; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT OPTIMIZE TABLE t1; @@ -599,16 +620,19 @@ OPTIMIZE TABLE t1; ######################################################################## --source include/gtid_step_reset.inc +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER TABLE t_part OPTIMIZE PARTITION p0, p1; --let $gtid_step_count = 0 --source include/gtid_step_assert.inc +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER TABLE t_part ANALYZE PARTITION p0; --let $gtid_step_count = 0 --source include/gtid_step_assert.inc +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT ALTER TABLE t_part REPAIR PARTITION p0, p1; --let $gtid_step_count = 0 @@ -623,26 +647,31 @@ CREATE USER 'u1'@localhost IDENTIFIED BY ''; SET @@global.super_read_only = 1; --source include/gtid_step_reset.inc +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT CREATE USER u1,u2; --let $gtid_step_count = 0 --source include/gtid_step_assert.inc +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT GRANT ALL ON *.* To u1,u2; --let $gtid_step_count = 0 --source include/gtid_step_assert.inc +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT REVOKE ALL ON *.* from u1; --let $gtid_step_count = 0 --source include/gtid_step_assert.inc +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT DROP USER u1; --let $gtid_step_count = 0 --source include/gtid_step_assert.inc +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT DROP USER u1,u2; --let $gtid_step_count = 0 @@ -653,21 +682,25 @@ DROP USER u1,u2; --echo #### slave_relay_log_info, and slave_worker_info tables. ######################################################################## +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT UPDATE mysql.slave_master_info SET Retry_count = Retry_count + 1; --let $gtid_step_count = 0 --source include/gtid_step_assert.inc +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT UPDATE mysql.slave_relay_log_info SET Sql_delay = Sql_delay + 1; --let $gtid_step_count = 0 --source include/gtid_step_assert.inc +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT UPDATE mysql.slave_worker_info SET Relay_log_pos = Relay_log_pos + 1; --let $gtid_step_count = 0 --source include/gtid_step_assert.inc +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT UPDATE mysql.gtid_executed SET interval_end = interval_end + 1; --let $gtid_step_count = 0 diff --git a/mysql-test/suite/rpl_nogtid/r/rpl_read_only.result b/mysql-test/suite/rpl_nogtid/r/rpl_read_only.result index 80e1484ce007..e01f43803e8c 100644 --- a/mysql-test/suite/rpl_nogtid/r/rpl_read_only.result +++ b/mysql-test/suite/rpl_nogtid/r/rpl_read_only.result @@ -78,7 +78,11 @@ a 1004 1005 insert into t1 values(1006); -ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT +set global read_only_error_msg_extra = "This is a custom message"; +insert into t1 values(1006); +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT. This is a custom message +set global read_only_error_msg_extra = default; drop user test; drop table t1; include/sync_slave_sql_with_master.inc diff --git a/mysql-test/suite/rpl_nogtid/r/rpl_read_only_myisam.result b/mysql-test/suite/rpl_nogtid/r/rpl_read_only_myisam.result index 4cabf719821c..16417c72c2d6 100644 --- a/mysql-test/suite/rpl_nogtid/r/rpl_read_only_myisam.result +++ b/mysql-test/suite/rpl_nogtid/r/rpl_read_only_myisam.result @@ -78,7 +78,11 @@ a 2004 2005 insert into t2 values(2006); -ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT +set global read_only_error_msg_extra = "This is a custom message"; +insert into t2 values(2006); +ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement. Current master_host: 127.0.0.1, master_port: MASTER_PORT. This is a custom message +set global read_only_error_msg_extra = default; drop user test; drop table t2; include/sync_slave_sql_with_master.inc diff --git a/mysql-test/suite/rpl_nogtid/t/rpl_read_only.test b/mysql-test/suite/rpl_nogtid/t/rpl_read_only.test index bca5b1573440..f8b312af6eb0 100644 --- a/mysql-test/suite/rpl_nogtid/t/rpl_read_only.test +++ b/mysql-test/suite/rpl_nogtid/t/rpl_read_only.test @@ -14,6 +14,7 @@ create user test; connect (master2,127.0.0.1,test,,test,$MASTER_MYPORT,); connect (slave2,127.0.0.1,test,,test,$SLAVE_MYPORT,); +connect (slave2_root,127.0.0.1,root,,test,$SLAVE_MYPORT,); connection master1; @@ -95,8 +96,20 @@ select * from t1; # Non root user can not write on the slave connection slave2; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT insert into t1 values(1006); +--replace_result $MASTER_MYPORT MASTER_PORT +# set extra info for the error message +connection slave2_root; +set global read_only_error_msg_extra = "This is a custom message"; +connection slave2; +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_OPTION_PREVENTS_STATEMENT +insert into t1 values(1006); +--replace_result $MASTER_MYPORT MASTER_PORT +connection slave2_root; +set global read_only_error_msg_extra = default; ## Cleanup connection master; diff --git a/mysql-test/suite/rpl_nogtid/t/rpl_read_only_myisam.test b/mysql-test/suite/rpl_nogtid/t/rpl_read_only_myisam.test index c70d6c23b4d2..b91b0084cab9 100644 --- a/mysql-test/suite/rpl_nogtid/t/rpl_read_only_myisam.test +++ b/mysql-test/suite/rpl_nogtid/t/rpl_read_only_myisam.test @@ -16,6 +16,7 @@ create user test; connect (master2,127.0.0.1,test,,test,$MASTER_MYPORT,); connect (slave2,127.0.0.1,test,,test,$SLAVE_MYPORT,); +connect (slave2_root,127.0.0.1,root,,test,$SLAVE_MYPORT,); connection master1; @@ -99,8 +100,18 @@ select * from t2; # Non root user can not write on the slave connection slave2; +--replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT insert into t2 values(2006); +# set extra info for the error message +connection slave2_root; +set global read_only_error_msg_extra = "This is a custom message"; +connection slave2; +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_OPTION_PREVENTS_STATEMENT +insert into t2 values(2006); +connection slave2_root; +set global read_only_error_msg_extra = default; ## Cleanup connection master; diff --git a/mysql-test/suite/sys_vars/r/read_only_error_msg_extra_basic.result b/mysql-test/suite/sys_vars/r/read_only_error_msg_extra_basic.result new file mode 100644 index 000000000000..639238d352b9 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/read_only_error_msg_extra_basic.result @@ -0,0 +1,22 @@ +set @@global.read_only_error_msg_extra='Custom message before read_only'; +select @@global.read_only_error_msg_extra; +@@global.read_only_error_msg_extra +Custom message before read_only +set global read_only = true; +set @@global.read_only_error_msg_extra = default; +select @@global.read_only_error_msg_extra; +@@global.read_only_error_msg_extra + +set @saved_read_only_error_msg_extra = @@global.read_only_error_msg_extra; +set @@global.read_only_error_msg_extra='This is a custom message'; +set global super_read_only = true; +set @@global.read_only_error_msg_extra='This is another custom message'; +set @@global.read_only_error_msg_extra=1; +ERROR 42000: Incorrect argument type to variable 'read_only_error_msg_extra' +select @@session.read_only_error_msg_extra; +ERROR HY000: Variable 'read_only_error_msg_extra' is a GLOBAL variable +set @@session.read_only_error_msg_extra='This is a custom message'; +ERROR HY000: Variable 'read_only_error_msg_extra' is a GLOBAL variable and should be set with SET GLOBAL +set global read_only_error_msg_extra = @saved_read_only_error_msg_extra; +set global super_read_only = false; +set global read_only = false; diff --git a/mysql-test/suite/sys_vars/t/read_only_error_msg_extra_basic.test b/mysql-test/suite/sys_vars/t/read_only_error_msg_extra_basic.test new file mode 100644 index 000000000000..ec3b22f73037 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/read_only_error_msg_extra_basic.test @@ -0,0 +1,25 @@ +set @@global.read_only_error_msg_extra='Custom message before read_only'; +select @@global.read_only_error_msg_extra; + +set global read_only = true; +set @@global.read_only_error_msg_extra = default; +select @@global.read_only_error_msg_extra; +set @saved_read_only_error_msg_extra = @@global.read_only_error_msg_extra; + +set @@global.read_only_error_msg_extra='This is a custom message'; + +set global super_read_only = true; +set @@global.read_only_error_msg_extra='This is another custom message'; + +--error ER_WRONG_TYPE_FOR_VAR +set @@global.read_only_error_msg_extra=1; + +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.read_only_error_msg_extra; +--error ER_GLOBAL_VARIABLE +set @@session.read_only_error_msg_extra='This is a custom message'; + +set global read_only_error_msg_extra = @saved_read_only_error_msg_extra; + +set global super_read_only = false; +set global read_only = false; diff --git a/share/messages_to_clients.txt b/share/messages_to_clients.txt index 11e99ad424b4..d663535f5db8 100644 --- a/share/messages_to_clients.txt +++ b/share/messages_to_clients.txt @@ -5120,12 +5120,12 @@ ER_FEATURE_DISABLED spa "El recurso '%s' fue deshabilitado; usted necesita construir MySQL con '%s' para tener eso funcionando" swe "'%s' är inte aktiverad; För att aktivera detta måste du bygga om MySQL med '%s' definierad" ER_OPTION_PREVENTS_STATEMENT - eng "The MySQL server is running with the %s option so it cannot execute this statement" - ger "Der MySQL-Server läuft mit der Option %s und kann diese Anweisung deswegen nicht ausführen" - jpn "MySQLサーバーが %s オプションで実行されているので、このステートメントは実行できません。" - por "O servidor MySQL está rodando com a opção %s razão pela qual não pode executar esse commando" - spa "El servidor MySQL está rodando con la opción %s tal que no puede ejecutar este comando" - swe "MySQL är startad med %s. Pga av detta kan du inte använda detta kommando" + eng "The MySQL server is running with the %s option so it cannot execute this statement%s" + ger "Der MySQL-Server läuft mit der Option %s und kann diese Anweisung deswegen nicht ausführen%s" + jpn "MySQLサーバーが %s オプションで実行されているので、このステートメントは実行できません。%s" + por "O servidor MySQL está rodando com a opção %s razão pela qual não pode executar esse commando%s" + spa "El servidor MySQL está rodando con la opción %s tal que no puede ejecutar este comando%s" + swe "MySQL är startad med %s. Pga av detta kan du inte använda detta kommando%s" ER_DUPLICATED_VALUE_IN_TYPE eng "Column '%-.100s' has duplicated value '%-.64s' in %s" ger "Feld '%-.100s' hat doppelten Wert '%-.64s' in %s" diff --git a/sql/auth/sql_authorization.cc b/sql/auth/sql_authorization.cc index 100f019ffe56..b583b810e642 100644 --- a/sql/auth/sql_authorization.cc +++ b/sql/auth/sql_authorization.cc @@ -106,6 +106,7 @@ #include "sql/mysqld.h" /* lower_case_table_names */ #include "sql/nested_join.h" #include "sql/protocol.h" +#include "sql/rpl_replica.h" /* get_active_master_info */ #include "sql/sp.h" /* sp_exist_routines */ #include "sql/sql_admin.h" // enum role_enum #include "sql/sql_alter.h" @@ -1880,13 +1881,15 @@ bool check_readonly(THD *thd, bool err_if_readonly) { */ void err_readonly(THD *thd) { + std::string extra_info = get_active_master_info(); my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), thd->security_context()->check_access(SUPER_ACL) || thd->security_context() ->has_global_grant(STRING_WITH_LEN("CONNECTION_ADMIN")) .first ? "--super-read-only" - : "--read-only"); + : "--read-only", + extra_info.c_str()); } /** diff --git a/sql/auth/sql_user_table.cc b/sql/auth/sql_user_table.cc index 9239cffaaac7..9d1a5711f973 100644 --- a/sql/auth/sql_user_table.cc +++ b/sql/auth/sql_user_table.cc @@ -1953,7 +1953,7 @@ int replace_routine_table(THD *thd, GRANT_NAME *grant_name, TABLE *table, DBUG_TRACE; if (!initialized) { - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables", ""); return -1; } @@ -2362,7 +2362,7 @@ int open_grant_tables(THD *thd, Table_ref *tables, bool *transactional_tables) { DBUG_TRACE; if (!initialized) { - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables", ""); return -1; } diff --git a/sql/dd/impl/sdi_file.cc b/sql/dd/impl/sdi_file.cc index 0aa280270dc0..adbcfc33343a 100644 --- a/sql/dd/impl/sdi_file.cc +++ b/sql/dd/impl/sdi_file.cc @@ -190,7 +190,7 @@ bool expand_sdi_pattern(const Dir_pat_tuple &dpt, x.append(opt_secure_file_priv); x.append("'"); /* Read only allowed from within dir specified by secure_file_priv */ - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), x.c_str()); + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), x.c_str(), ""); return true; } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 04512c33c680..30eb6548749a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1277,6 +1277,7 @@ handlerton *temptable_hton; handlerton *myisam_hton; handlerton *innodb_hton; +char *opt_read_only_error_msg_extra; char *opt_disabled_storage_engines; uint opt_server_id_bits = 0; ulong opt_server_id_mask = 0; diff --git a/sql/mysqld.h b/sql/mysqld.h index d8bb414ee3af..1628f0919308 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -212,6 +212,7 @@ extern ulonglong replica_type_conversions_options; extern bool read_only, opt_readonly; extern bool super_read_only, opt_super_readonly; extern bool send_error_before_closing_timed_out_connection; +extern char *opt_read_only_error_msg_extra; extern bool lower_case_file_system; extern bool opt_require_secure_transport; diff --git a/sql/query_result.cc b/sql/query_result.cc index 86779e50f6a1..663caf149548 100644 --- a/sql/query_result.cc +++ b/sql/query_result.cc @@ -218,7 +218,7 @@ static File create_file(THD *thd, char *path, sql_exchange *exchange, if (!is_secure_file_path(path)) { /* Write only allowed to dir or subdir specified by secure_file_priv */ - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv", ""); return -1; } diff --git a/sql/rpl_replica.cc b/sql/rpl_replica.cc index 29c3ea680695..c566a37ac67f 100644 --- a/sql/rpl_replica.cc +++ b/sql/rpl_replica.cc @@ -11208,6 +11208,29 @@ static int check_slave_sql_config_conflict(const Relay_log_info *rli) { return 0; } +// This function will generate the string containing current master host and +// port info if available. +std::string get_active_master_info() { + std::string str_ptr; + + channel_map.rdlock(); + Master_info *mi = channel_map.get_default_channel_mi(); + + if (Master_info::is_configured(mi)) { + str_ptr = ". Current master_host: "; + str_ptr += mi->host; + str_ptr += ", master_port: "; + str_ptr += std::to_string(mi->port); + if (opt_read_only_error_msg_extra && opt_read_only_error_msg_extra[0]) { + str_ptr += ". "; + str_ptr += opt_read_only_error_msg_extra; + } + } + + channel_map.unlock(); + return str_ptr; +} + /** Purge Group Replication channels relay logs after this server being a recipient of clone. diff --git a/sql/rpl_replica.h b/sql/rpl_replica.h index c28a852fcc40..c48aa8bcad76 100644 --- a/sql/rpl_replica.h +++ b/sql/rpl_replica.h @@ -582,6 +582,7 @@ bool start_slave_thread(PSI_thread_key thread_key, my_start_routine h_func, std::atomic *slave_running, std::atomic *slave_run_id, Master_info *mi); +std::string get_active_master_info(); bool show_slave_status(THD *thd, Master_info *mi); bool show_slave_status(THD *thd); diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 6b691936dafe..27c0c5671003 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -890,12 +890,13 @@ bool Sql_cmd_load_table::execute_inner(THD *thd, bug. */ LogErr(ERROR_LEVEL, ER_LOAD_DATA_INFILE_FAILED_IN_UNEXPECTED_WAY); - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--replica-load-tmpdir"); + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--replica-load-tmpdir", + ""); return true; } } else if (!is_secure_file_path(name)) { /* Read only allowed from within dir specified by secure_file_priv */ - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv"); + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--secure-file-priv", ""); return true; } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b207e4a9e91a..005b5329618f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3391,7 +3391,7 @@ int mysql_execute_command(THD *thd, bool first_level) { /* Check if the statement fulfill the requirements on ACL CACHE */ if (!command_satisfy_acl_cache_requirement(lex->sql_command)) { - my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables"); + my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables", ""); goto error; } diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index d1236cf6c527..9fad37ff5706 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2136,7 +2136,7 @@ static bool event_scheduler_check(sys_var *, THD *, set_var *var) { if (var->save_result.ulonglong_value == Events::EVENTS_DISABLED) return true; if (Events::opt_event_scheduler == Events::EVENTS_DISABLED) { my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), - "--event-scheduler=DISABLED or --skip-grant-tables"); + "--event-scheduler=DISABLED or --skip-grant-tables", ""); return true; } return false; @@ -7880,3 +7880,10 @@ static Sys_var_bool Sys_send_error_before_closing_timed_out_connection( "Send error before closing connections due to timeout.", GLOBAL_VAR(send_error_before_closing_timed_out_connection), CMD_LINE(OPT_ARG), DEFAULT(true)); + +static Sys_var_charptr Sys_read_only_error_msg_extra( + "read_only_error_msg_extra", + "Set this variable to print out extra error information, " + "which will be appended to read_only error messages.", + GLOBAL_VAR(opt_read_only_error_msg_extra), CMD_LINE(OPT_ARG), + IN_SYSTEM_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG);