From 53f4ac64507cc2701358b12d0fa41ecedc72bb89 Mon Sep 17 00:00:00 2001 From: Kamil Holubicki Date: Wed, 11 Sep 2019 15:42:11 +0200 Subject: [PATCH] PS-5629:Fixed handling of persisted bool and enum variables set as integer with persist_only option. https://jira.percona.com/browse/PS-5629 If the user sets bool/enum value providing alias iteger value, it is stored in mysqld-auto.cnf file. Then when value is read on server start, it was considered to be string literal and validated against allowed bool/enum string literals which caused value rejection and server not to start. --- .../r/percona_persist_only_bool_enum.result | 161 ++++++++++++++++++ .../t/percona_persist_only_bool_enum.test | 103 +++++++++++ sql/persisted_variable.cc | 43 ++++- sql/persisted_variable.h | 3 + 4 files changed, 307 insertions(+), 3 deletions(-) create mode 100644 mysql-test/r/percona_persist_only_bool_enum.result create mode 100644 mysql-test/t/percona_persist_only_bool_enum.test diff --git a/mysql-test/r/percona_persist_only_bool_enum.result b/mysql-test/r/percona_persist_only_bool_enum.result new file mode 100644 index 00000000000..5356d6d3f63 --- /dev/null +++ b/mysql-test/r/percona_persist_only_bool_enum.result @@ -0,0 +1,161 @@ +# +# Changing values +# +SET PERSIST_ONLY super_read_only = OFF; +SET PERSIST_ONLY binlog_row_image = FULL; +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +Variable_name Value +binlog_row_image FULL +super_read_only OFF +SELECT @@global.super_read_only; +@@global.super_read_only +0 +SELECT @@global.binlog_row_image; +@@global.binlog_row_image +FULL +# restart +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +Variable_name Value +binlog_row_image FULL +super_read_only OFF +SELECT @@global.super_read_only; +@@global.super_read_only +0 +SELECT @@global.binlog_row_image; +@@global.binlog_row_image +FULL +# +# Changing values +# +SET PERSIST_ONLY super_read_only = ON; +SET PERSIST_ONLY binlog_row_image = NOBLOB; +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +Variable_name Value +binlog_row_image FULL +super_read_only OFF +SELECT @@global.super_read_only; +@@global.super_read_only +0 +SELECT @@global.binlog_row_image; +@@global.binlog_row_image +FULL +# restart +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +Variable_name Value +binlog_row_image NOBLOB +super_read_only ON +SELECT @@global.super_read_only; +@@global.super_read_only +1 +SELECT @@global.binlog_row_image; +@@global.binlog_row_image +NOBLOB +# +# Changing values +# +SET PERSIST_ONLY super_read_only = off; +SET PERSIST_ONLY binlog_row_image = minimal; +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +Variable_name Value +binlog_row_image NOBLOB +super_read_only ON +SELECT @@global.super_read_only; +@@global.super_read_only +1 +SELECT @@global.binlog_row_image; +@@global.binlog_row_image +NOBLOB +# restart +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +Variable_name Value +binlog_row_image MINIMAL +super_read_only OFF +SELECT @@global.super_read_only; +@@global.super_read_only +0 +SELECT @@global.binlog_row_image; +@@global.binlog_row_image +MINIMAL +# +# Changing values +# +SET PERSIST_ONLY super_read_only = on; +SET PERSIST_ONLY binlog_row_image = full; +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +Variable_name Value +binlog_row_image MINIMAL +super_read_only OFF +SELECT @@global.super_read_only; +@@global.super_read_only +0 +SELECT @@global.binlog_row_image; +@@global.binlog_row_image +MINIMAL +# restart +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +Variable_name Value +binlog_row_image FULL +super_read_only ON +SELECT @@global.super_read_only; +@@global.super_read_only +1 +SELECT @@global.binlog_row_image; +@@global.binlog_row_image +FULL +# +# Changing values +# +SET PERSIST_ONLY super_read_only = 0; +SET PERSIST_ONLY binlog_row_image = 0; +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +Variable_name Value +binlog_row_image FULL +super_read_only ON +SELECT @@global.super_read_only; +@@global.super_read_only +1 +SELECT @@global.binlog_row_image; +@@global.binlog_row_image +FULL +# restart +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +Variable_name Value +binlog_row_image MINIMAL +super_read_only OFF +SELECT @@global.super_read_only; +@@global.super_read_only +0 +SELECT @@global.binlog_row_image; +@@global.binlog_row_image +MINIMAL +# +# Changing values +# +SET PERSIST_ONLY super_read_only = 1; +SET PERSIST_ONLY binlog_row_image = 2; +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +Variable_name Value +binlog_row_image MINIMAL +super_read_only OFF +SELECT @@global.super_read_only; +@@global.super_read_only +0 +SELECT @@global.binlog_row_image; +@@global.binlog_row_image +MINIMAL +# restart +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +Variable_name Value +binlog_row_image FULL +super_read_only ON +SELECT @@global.super_read_only; +@@global.super_read_only +1 +SELECT @@global.binlog_row_image; +@@global.binlog_row_image +FULL +# +# Cleanup +# +# Restart server with defaults +# restart diff --git a/mysql-test/t/percona_persist_only_bool_enum.test b/mysql-test/t/percona_persist_only_bool_enum.test new file mode 100644 index 00000000000..037ace632f5 --- /dev/null +++ b/mysql-test/t/percona_persist_only_bool_enum.test @@ -0,0 +1,103 @@ +--let $MYSQL_DATA_DIR=`select @@datadir` + +# Test dynamic bool variable super_read_only +# Test readonly enum variable binlog_row_image + +--echo # +--echo # Changing values +--echo # +SET PERSIST_ONLY super_read_only = OFF; +SET PERSIST_ONLY binlog_row_image = FULL; + +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +SELECT @@global.super_read_only; +SELECT @@global.binlog_row_image; +--source include/restart_mysqld.inc +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +SELECT @@global.super_read_only; +SELECT @@global.binlog_row_image; + +################################################################################################ +--echo # +--echo # Changing values +--echo # +SET PERSIST_ONLY super_read_only = ON; +SET PERSIST_ONLY binlog_row_image = NOBLOB; + +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +SELECT @@global.super_read_only; +SELECT @@global.binlog_row_image; +--source include/restart_mysqld.inc +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +SELECT @@global.super_read_only; +SELECT @@global.binlog_row_image; + +################################################################################################ +--echo # +--echo # Changing values +--echo # +SET PERSIST_ONLY super_read_only = off; +SET PERSIST_ONLY binlog_row_image = minimal; + +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +SELECT @@global.super_read_only; +SELECT @@global.binlog_row_image; +--source include/restart_mysqld.inc +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +SELECT @@global.super_read_only; +SELECT @@global.binlog_row_image; + +################################################################################################ +--echo # +--echo # Changing values +--echo # +SET PERSIST_ONLY super_read_only = on; +SET PERSIST_ONLY binlog_row_image = full; + +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +SELECT @@global.super_read_only; +SELECT @@global.binlog_row_image; +--source include/restart_mysqld.inc +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +SELECT @@global.super_read_only; +SELECT @@global.binlog_row_image; + +################################################################################################ +--echo # +--echo # Changing values +--echo # +SET PERSIST_ONLY super_read_only = 0; +SET PERSIST_ONLY binlog_row_image = 0; + +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +SELECT @@global.super_read_only; +SELECT @@global.binlog_row_image; +--source include/restart_mysqld.inc +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +SELECT @@global.super_read_only; +SELECT @@global.binlog_row_image; + +################################################################################################ +--echo # +--echo # Changing values +--echo # +SET PERSIST_ONLY super_read_only = 1; +SET PERSIST_ONLY binlog_row_image = 2; + +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +SELECT @@global.super_read_only; +SELECT @@global.binlog_row_image; +--source include/restart_mysqld.inc +SHOW VARIABLES WHERE Variable_name LIKE 'super_read_only' OR Variable_name LIKE 'binlog_row_image'; +SELECT @@global.super_read_only; +SELECT @@global.binlog_row_image; + +################################################################################################ +# Cleanup +--echo # +--echo # Cleanup +--echo # +--remove_file $MYSQL_DATA_DIR/mysqld-auto.cnf +--echo # Restart server with defaults +--source include/restart_mysqld.inc + diff --git a/sql/persisted_variable.cc b/sql/persisted_variable.cc index 11f9ad996f4..ea259e3073c 100644 --- a/sql/persisted_variable.cc +++ b/sql/persisted_variable.cc @@ -75,6 +75,7 @@ #include "sql/sql_lex.h" #include "sql/sql_list.h" #include "sql/sql_show.h" +#include "sql/sys_vars.h" #include "sql/sys_vars_shared.h" #include "sql/thr_malloc.h" #include "sql_string.h" @@ -598,6 +599,27 @@ bool Persisted_variables_cache::load_persist_file() { return 0; } +/** + Create value item depending on provided content + + Creates Item_int if provided string represents integer value. + Otherwise creates Item_string + + @param [in] thd Current thread + @param [in] str Content to be itemized + + @return Item object +*/ +Item *Persisted_variables_cache::create_item(THD *thd, const string &str) { + int error; + my_strtoll10(str.c_str(), nullptr, &error); + if (!error) { + return new (thd->mem_root) Item_int(str.c_str(), (uint)str.length()); + } + return new (thd->mem_root) + Item_string(str.c_str(), str.length(), &my_charset_utf8mb4_bin); +} + /** set_persist_options() will set the options read from persisted config file @@ -715,13 +737,28 @@ bool Persisted_variables_cache::set_persist_options(bool plugin_options) { res = new (thd->mem_root) Item_int(iter->value.c_str(), (uint)iter->value.length()); break; - case SHOW_CHAR: case SHOW_LEX_STRING: - case SHOW_BOOL: - case SHOW_MY_BOOL: res = new (thd->mem_root) Item_string( iter->value.c_str(), iter->value.length(), &my_charset_utf8mb4_bin); break; + case SHOW_CHAR: { + /* The only way to detect enum */ + Sys_var_enum *enum_var = dynamic_cast(sysvar); + Sys_var_multi_enum *multi_enum_var = + dynamic_cast(sysvar); + if (enum_var || multi_enum_var) { + res = create_item(thd, iter->value); + } else { + res = new (thd->mem_root) + Item_string(iter->value.c_str(), iter->value.length(), + &my_charset_utf8mb4_bin); + } + break; + } + case SHOW_BOOL: + case SHOW_MY_BOOL: + res = create_item(thd, iter->value); + break; case SHOW_CHAR_PTR: if (iter->is_null) res = new (thd->mem_root) Item_null(); diff --git a/sql/persisted_variable.h b/sql/persisted_variable.h index 2db53c1e2c6..751ffe641c2 100644 --- a/sql/persisted_variable.h +++ b/sql/persisted_variable.h @@ -40,6 +40,7 @@ class Json_dom; class THD; class set_var; class sys_var; +class Item; struct MYSQL_FILE; /** @@ -156,6 +157,8 @@ class Persisted_variables_cache { /* Helper function to extract variables from json formatted string */ bool extract_variables_from_json(const Json_dom *dom, bool is_read_only = false); + /* Helper function to create value item depending on provided content */ + Item *create_item(THD *thd, const std::string &str); private: /* Helper functions for file IO */ -- 2.17.1