From 9f00827da4e4b80b816d22ef77fcb525ae68a837 Mon Sep 17 00:00:00 2001 From: Tian Xia Date: Mon, 8 Aug 2016 09:34:06 -0700 Subject: [PATCH] Add a variable for appending a custom message to server read_only error Summary: 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. Squash with https://reviews.facebook.net/D61383 Test Plan: Added tests. Reviewers: santoshb Reviewed By: santoshb Subscribers: webscalesql-eng, ebergen Differential Revision: https://reviews.facebook.net/D61713 --- mysql-test/r/bug58669.result | 1 + .../r/mysqld--help-notwin-profiling.result | 4 +++ mysql-test/r/mysqld--help-notwin.result | 4 +++ mysql-test/suite/rpl/r/rpl_read_only.result | 6 ++++ mysql-test/suite/rpl/t/rpl_read_only.test | 13 +++++++++ .../r/read_only_error_msg_extra_basic.result | 20 +++++++++++++ .../t/read_only_error_msg_extra_basic.test | 28 +++++++++++++++++++ sql/mysqld.cc | 1 + sql/mysqld.h | 1 + sql/share/errmsg-utf8.txt | 3 ++ sql/sql_parse.cc | 6 ++++ sql/sys_vars.cc | 20 +++++++++++++ 12 files changed, 107 insertions(+) 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 e33a3fb83b83..f548c68ebdf6 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 ON 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-profiling.result b/mysql-test/r/mysqld--help-notwin-profiling.result index f7c58552b376..4ce4e0b37ba3 100644 --- a/mysql-test/r/mysqld--help-notwin-profiling.result +++ b/mysql-test/r/mysqld--help-notwin-profiling.result @@ -872,6 +872,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 (slave) 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 @@ -1796,6 +1799,7 @@ range-alloc-block-size 4096 rbr-idempotent-tables (No default value) read-buffer-size 131072 read-only FALSE +read-only-error-msg-extra read-only-slave TRUE read-rnd-buffer-size 262144 relay-log (No default value) diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result index 84ecfcb7546c..c1a9411d66fb 100644 --- a/mysql-test/r/mysqld--help-notwin.result +++ b/mysql-test/r/mysqld--help-notwin.result @@ -870,6 +870,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 (slave) 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 @@ -1793,6 +1796,7 @@ range-alloc-block-size 4096 rbr-idempotent-tables (No default value) read-buffer-size 131072 read-only FALSE +read-only-error-msg-extra read-only-slave TRUE read-rnd-buffer-size 262144 relay-log (No default value) diff --git a/mysql-test/suite/rpl/r/rpl_read_only.result b/mysql-test/suite/rpl/r/rpl_read_only.result index 0dba2f430cde..4200e1458dd8 100644 --- a/mysql-test/suite/rpl/r/rpl_read_only.result +++ b/mysql-test/suite/rpl/r/rpl_read_only.result @@ -121,6 +121,12 @@ 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 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 +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 +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 t1; drop table t2; diff --git a/mysql-test/suite/rpl/t/rpl_read_only.test b/mysql-test/suite/rpl/t/rpl_read_only.test index 241bdb862bba..a036a83f505f 100644 --- a/mysql-test/suite/rpl/t/rpl_read_only.test +++ b/mysql-test/suite/rpl/t/rpl_read_only.test @@ -15,6 +15,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; @@ -119,6 +120,18 @@ insert into t1 values(1006); --replace_result $MASTER_MYPORT MASTER_PORT --error ER_OPTION_PREVENTS_STATEMENT_EXTRA_INFO 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_EXTRA_INFO +insert into t1 values(1006); +--replace_result $MASTER_MYPORT MASTER_PORT +--error ER_OPTION_PREVENTS_STATEMENT_EXTRA_INFO +insert into t2 values(2006); +connection slave2_root; +set global read_only_error_msg_extra = default; # Verify read_only cannot be disabled on slave connection slave; 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..2b12ac3fbaee --- /dev/null +++ b/mysql-test/suite/sys_vars/r/read_only_error_msg_extra_basic.result @@ -0,0 +1,20 @@ +set @@global.read_only_error_msg_extra='Not in read_only'; +ERROR HY000: The system variable read_only_error_msg_extra can only be set in read-only (super) status. +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..ea1aae4b46da --- /dev/null +++ b/mysql-test/suite/sys_vars/t/read_only_error_msg_extra_basic.test @@ -0,0 +1,28 @@ +--source include/not_embedded.inc + +# Cannot set the value if server is not in read_only +--error ER_VARIABLE_NOT_SETTABLE_WITHOUT_READ_ONLY +set @@global.read_only_error_msg_extra='Not in read_only'; + +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/sql/mysqld.cc b/sql/mysqld.cc index ec7e7065cc4c..10caea9841df 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -504,6 +504,7 @@ my_bool block_create_myisam = FALSE; my_bool block_create_memory = FALSE; my_bool block_create_no_primary_key = FALSE; my_bool read_only= 0, opt_readonly= 0; +char* opt_read_only_error_msg_extra; my_bool super_read_only = 0, opt_super_readonly = 0; my_bool use_temp_pool, relay_log_purge; my_bool relay_log_recovery; diff --git a/sql/mysqld.h b/sql/mysqld.h index 1b8904c41501..966c97eb1f4e 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -296,6 +296,7 @@ extern ulong slave_run_triggers_for_rbr; extern ulonglong slave_type_conversions_options; extern ulonglong admission_control_filter; extern my_bool read_only, opt_readonly, super_read_only, opt_super_readonly; +extern char* opt_read_only_error_msg_extra; extern my_bool send_error_before_closing_timed_out_connection; extern my_bool allow_document_type; extern my_bool block_create_myisam; diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index a9ab4736f82c..f7bd4b4e72b8 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -7229,6 +7229,9 @@ ER_CONNECTION_TIMEOUT ER_OPTION_PREVENTS_STATEMENT_EXTRA_INFO eng "The MySQL server is running with the %s option so it cannot execute this statement. %s" + +ER_VARIABLE_NOT_SETTABLE_WITHOUT_READ_ONLY + eng "The system variable %.200s can only be set in read-only (super) status." # # End of 5.6 error messages. # diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8a9364563b24..61c12122246c 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -9920,6 +9920,12 @@ int get_active_master_info(std::string *str_ptr) *str_ptr += active_mi->host; *str_ptr += ", master_port: "; *str_ptr += std::to_string(active_mi->port); + const char *extra_str = opt_read_only_error_msg_extra; + if (extra_str && extra_str[0]) + { + *str_ptr += ". "; + *str_ptr += extra_str; + } return ER_OPTION_PREVENTS_STATEMENT_EXTRA_INFO; } #endif diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 758a81d921e8..71f2bc27f86d 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -5505,3 +5505,23 @@ static Sys_var_uint Sys_select_into_file_fsync_timeout( "SELECT INTO OUTFILE", SESSION_VAR(select_into_file_fsync_timeout), CMD_LINE(OPT_ARG), VALID_RANGE(0, UINT_MAX), DEFAULT(0), BLOCK_SIZE(1)); + +static bool check_read_only_error_msg_extra( + sys_var *self, THD *thd, set_var *var) +{ + if (!opt_readonly && !opt_super_readonly) + { + my_error(ER_VARIABLE_NOT_SETTABLE_WITHOUT_READ_ONLY, + MYF(0), + var->var->name.str); + return true; + } + return false; +} +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, + ON_CHECK(check_read_only_error_msg_extra));