Commit 34bbf37f authored by Zhibo Zhang's avatar Zhibo Zhang Committed by Andrew Hutchings

MDEV-30188: Ensure all binlog* variables are visible as system variables

Turn the remaining three `binlog*` options binlog_do_db, binlog_ignore_db,
binlog_rows_event_max_size into global variables so that they can be
visible from the SQL user level. This is for audit / secure
configuration check purposes.

Create new MTR tests to make sure that the newly created global
variables can be visible from the command line interface.

Behavior before the code change:

    MariaDB [(none)]> SHOW GLOBAL VARIABLES WHERE
        -> Variable_name LIKE 'binlog_do_db' OR
        -> Variable_name LIKE 'binlog_ignore_db' OR
        -> Variable_name LIKE 'binlog_row_event_max_size';
    Empty set (0.001 sec)

Behavior after the code change:

    MariaDB [(none)]> SHOW GLOBAL VARIABLES WHERE
        -> Variable_name LIKE 'binlog_do_db' OR
        -> Variable_name LIKE 'binlog_ignore_db' OR
        -> Variable_name LIKE 'binlog_row_event_max_size';
    +---------------------------+-------+
    | Variable_name             | Value |
    +---------------------------+-------+
    | binlog_do_db              |       |
    | binlog_ignore_db          |       |
    | binlog_row_event_max_size | 8192  |
    +---------------------------+-------+
    3 rows in set (0.001 sec)

Note:

For `binlog_do_db` and `binlog_ignore_db`, we add a new class
`Sys_var_binlog_filter` to handle the dynamically-composable command line
options for `binlog_do_db` and `binlog_ignore_db`. Below
is the motivation:

When the users start the server with the option
    --binlog-do-db="database1" --binlog-do-db="database2"
The expected behavior is that the system should allow replication for
both `database1` and `database2`, which is the logic of the original
code.

However, when turning the variables into system variables, the
functionality does not exist any more, since system variables will only
handle the last occurrence of the option, and in this case, the system
will only be able to handle `database2`.

Copyright:

All new code of the whole pull request, including one or several files
that are either new files or modified ones, are contributed under the BSD-new
license. I am contributing on behalf of my employer Amazon Web Services, Inc.
parent 907bc68d
#
# MDEV-30188 Show "--binlog_do_db" state in SYSTEM VARIABLES
#
SELECT @@binlog_do_db AS EXPECT_NULL;
EXPECT_NULL
SET @@GLOBAL.binlog_do_db='database1';
ERROR HY000: Variable 'binlog_do_db' is a read only variable
# restart: --binlog_do_db=database1 --binlog_do_db=database2
SELECT @@binlog_do_db AS EXPECT_database1_database2;
EXPECT_database1_database2
database1,database2
#
# MDEV-30188 Show "--binlog_ignore_db" state in SYSTEM VARIABLES
#
SELECT @@binlog_ignore_db AS EXPECT_NULL;
EXPECT_NULL
SET @@GLOBAL.binlog_ignore_db='database1';
ERROR HY000: Variable 'binlog_ignore_db' is a read only variable
# restart: --binlog_ignore_db=database1 --binlog_ignore_db=database2
SELECT @@binlog_ignore_db AS EXPECT_database1_database2;
EXPECT_database1_database2
database1,database2
#
# MDEV-30188 Show "--binlog_row_event_max_size" state in SYSTEM VARIABLES
#
SELECT @@binlog_row_event_max_size AS EXPECT_8192;
EXPECT_8192
8192
SET @@GLOBAL.binlog_row_event_max_size=128;
ERROR HY000: Variable 'binlog_row_event_max_size' is a read only variable
# restart: --binlog_row_event_max_size=4096
SELECT @@binlog_row_event_max_size AS EXPECT_4096;
EXPECT_4096
4096
...@@ -412,6 +412,16 @@ NUMERIC_BLOCK_SIZE NULL ...@@ -412,6 +412,16 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON ENUM_VALUE_LIST OFF,ON
READ_ONLY NO READ_ONLY NO
COMMAND_LINE_ARGUMENT OPTIONAL COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME BINLOG_DO_DB
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE VARCHAR
VARIABLE_COMMENT Tells the primary it should log updates for the specified database, and exclude all others not explicitly mentioned.
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NULL
READ_ONLY YES
COMMAND_LINE_ARGUMENT NULL
VARIABLE_NAME BINLOG_EXPIRE_LOGS_SECONDS VARIABLE_NAME BINLOG_EXPIRE_LOGS_SECONDS
VARIABLE_SCOPE GLOBAL VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED VARIABLE_TYPE BIGINT UNSIGNED
...@@ -442,6 +452,16 @@ NUMERIC_BLOCK_SIZE NULL ...@@ -442,6 +452,16 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST MIXED,STATEMENT,ROW ENUM_VALUE_LIST MIXED,STATEMENT,ROW
READ_ONLY NO READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME BINLOG_IGNORE_DB
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE VARCHAR
VARIABLE_COMMENT Tells the primary that updates to the given database should not be logged to the binary log.
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NULL
READ_ONLY YES
COMMAND_LINE_ARGUMENT NULL
VARIABLE_NAME BINLOG_OPTIMIZE_THREAD_SCHEDULING VARIABLE_NAME BINLOG_OPTIMIZE_THREAD_SCHEDULING
VARIABLE_SCOPE GLOBAL VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BOOLEAN VARIABLE_TYPE BOOLEAN
...@@ -452,6 +472,16 @@ NUMERIC_BLOCK_SIZE NULL ...@@ -452,6 +472,16 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST OFF,ON ENUM_VALUE_LIST OFF,ON
READ_ONLY YES READ_ONLY YES
COMMAND_LINE_ARGUMENT REQUIRED COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME BINLOG_ROW_EVENT_MAX_SIZE
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT The maximum size of a row-based binary log event in bytes. Rows will be grouped into events smaller than this size if possible. The value has to be a multiple of 256.
NUMERIC_MIN_VALUE 256
NUMERIC_MAX_VALUE 4294967040
NUMERIC_BLOCK_SIZE 256
ENUM_VALUE_LIST NULL
READ_ONLY YES
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME BINLOG_ROW_IMAGE VARIABLE_NAME BINLOG_ROW_IMAGE
VARIABLE_SCOPE SESSION VARIABLE_SCOPE SESSION
VARIABLE_TYPE ENUM VARIABLE_TYPE ENUM
......
--echo #
--echo # MDEV-30188 Show "--binlog_do_db" state in SYSTEM VARIABLES
--echo #
# Confirm that "--binlog_do_db" option has the default value.
SELECT @@binlog_do_db AS EXPECT_NULL;
# `READ ONLY` variables must not be able to be reset.
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR (1238): Variable 'binlog_do_db' is a read only variable
SET @@GLOBAL.binlog_do_db='database1';
# Restart the server with "--binlog_do_db='database1' --binlog_do_db='database2'" option
--let $restart_parameters = "--binlog_do_db='database1' --binlog_do_db='database2'"
--source include/restart_mysqld.inc
SELECT @@binlog_do_db AS EXPECT_database1_database2;
--echo #
--echo # MDEV-30188 Show "--binlog_ignore_db" state in SYSTEM VARIABLES
--echo #
# Confirm that "--binlog_ignore_db" option has the default value.
SELECT @@binlog_ignore_db AS EXPECT_NULL;
# `READ ONLY` variables must not be able to be reset.
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR (1238): Variable 'binlog_ignore_db' is a read only variable
SET @@GLOBAL.binlog_ignore_db='database1';
# Restart the server with "--binlog_ignore_db='database1' --binlog_ignore_db='database2'" option
--let $restart_parameters = "--binlog_ignore_db='database1' --binlog_ignore_db='database2'"
--source include/restart_mysqld.inc
SELECT @@binlog_ignore_db AS EXPECT_database1_database2;
--echo #
--echo # MDEV-30188 Show "--binlog_row_event_max_size" state in SYSTEM VARIABLES
--echo #
SELECT @@binlog_row_event_max_size AS EXPECT_8192;
# `READ ONLY` variables must not be able to be reset.
--Error ER_INCORRECT_GLOBAL_LOCAL_VAR (1238): Variable 'binlog_row_event_max_size' is a read only variable
SET @@GLOBAL.binlog_row_event_max_size=128;
# Restart the server the server with "--binlog_row_event_max_size=4096" option
--let $restart_parameters = "--binlog_row_event_max_size=4096"
--source include/restart_mysqld.inc
SELECT @@binlog_row_event_max_size AS EXPECT_4096;
...@@ -6491,16 +6491,6 @@ struct my_option my_long_options[]= ...@@ -6491,16 +6491,6 @@ struct my_option my_long_options[]=
{"binlog-ignore-db", OPT_BINLOG_IGNORE_DB, {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB,
"Tells the master that updates to the given database should not be logged to the binary log.", "Tells the master that updates to the given database should not be logged to the binary log.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"binlog-row-event-max-size", 0,
"The maximum size of a row-based binary log event in bytes. Rows will be "
"grouped into events smaller than this size if possible. "
"The value has to be a multiple of 256.",
&opt_binlog_rows_event_max_size, &opt_binlog_rows_event_max_size,
0, GET_ULONG, REQUIRED_ARG,
/* def_value */ 8192, /* min_value */ 256, /* max_value */ UINT_MAX32-1,
/* sub_size */ 0, /* block_size */ 256,
/* app_type */ 0
},
#ifndef DISABLE_GRANT_OPTIONS #ifndef DISABLE_GRANT_OPTIONS
{"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0, {"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
......
...@@ -469,6 +469,9 @@ constexpr privilege_t PRIV_STMT_PURGE_BINLOG= BINLOG_ADMIN_ACL; ...@@ -469,6 +469,9 @@ constexpr privilege_t PRIV_STMT_PURGE_BINLOG= BINLOG_ADMIN_ACL;
// Was REPL_SLAVE_ACL prior to 10.5.2 // Was REPL_SLAVE_ACL prior to 10.5.2
constexpr privilege_t PRIV_STMT_SHOW_BINLOG_EVENTS= BINLOG_MONITOR_ACL; constexpr privilege_t PRIV_STMT_SHOW_BINLOG_EVENTS= BINLOG_MONITOR_ACL;
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_DO_DB = BINLOG_ADMIN_ACL | SUPER_ACL;
constexpr privilege_t PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_IGNORE_DB = BINLOG_ADMIN_ACL | SUPER_ACL;
/* /*
Privileges for replication related statements and commands Privileges for replication related statements and commands
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include <thr_alarm.h> #include <thr_alarm.h>
#include "slave.h" #include "slave.h"
#include "rpl_mi.h" #include "rpl_mi.h"
#include "rpl_filter.h"
#include "transaction.h" #include "transaction.h"
#include "mysqld.h" #include "mysqld.h"
#include "lock.h" #include "lock.h"
...@@ -3140,7 +3141,6 @@ static Sys_var_ulong Sys_query_prealloc_size( ...@@ -3140,7 +3141,6 @@ static Sys_var_ulong Sys_query_prealloc_size(
BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), BLOCK_SIZE(1024), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_thd_mem_root)); ON_UPDATE(fix_thd_mem_root));
// this has to be NO_CMD_LINE as the command-line option has a different name // this has to be NO_CMD_LINE as the command-line option has a different name
static Sys_var_mybool Sys_skip_external_locking( static Sys_var_mybool Sys_skip_external_locking(
"skip_external_locking", "Don't use system (external) locking", "skip_external_locking", "Don't use system (external) locking",
...@@ -5597,6 +5597,30 @@ Sys_var_rpl_filter::global_value_ptr(THD *thd, ...@@ -5597,6 +5597,30 @@ Sys_var_rpl_filter::global_value_ptr(THD *thd,
return ret; return ret;
} }
const uchar *
Sys_var_binlog_filter::global_value_ptr(THD *thd,
const LEX_CSTRING *base_name) const
{
char buf[256];
String tmp(buf, sizeof(buf), &my_charset_bin);
uchar *ret;
tmp.length(0);
switch (opt_id) {
case OPT_BINLOG_DO_DB:
binlog_filter->get_do_db(&tmp);
break;
case OPT_BINLOG_IGNORE_DB:
binlog_filter->get_ignore_db(&tmp);
break;
}
ret= (uchar *) thd->strmake(tmp.ptr(), tmp.length());
return ret;
}
static Sys_var_rpl_filter Sys_replicate_do_db( static Sys_var_rpl_filter Sys_replicate_do_db(
"replicate_do_db", OPT_REPLICATE_DO_DB, "replicate_do_db", OPT_REPLICATE_DO_DB,
"Tell the slave to restrict replication to updates of tables " "Tell the slave to restrict replication to updates of tables "
...@@ -5607,6 +5631,12 @@ static Sys_var_rpl_filter Sys_replicate_do_db( ...@@ -5607,6 +5631,12 @@ static Sys_var_rpl_filter Sys_replicate_do_db(
"actual names of table(s) being updated are checked.", "actual names of table(s) being updated are checked.",
PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_DO_DB); PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_DO_DB);
static Sys_var_binlog_filter Sys_binlog_do_db(
"binlog_do_db", OPT_BINLOG_DO_DB,
"Tells the primary it should log updates for the specified database, "
"and exclude all others not explicitly mentioned.",
PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_DO_DB);
static Sys_var_rpl_filter Sys_replicate_rewrite_db( static Sys_var_rpl_filter Sys_replicate_rewrite_db(
"replicate_rewrite_db", OPT_REPLICATE_REWRITE_DB, "replicate_rewrite_db", OPT_REPLICATE_REWRITE_DB,
"Tells the slave to replicate binlog events " "Tells the slave to replicate binlog events "
...@@ -5630,6 +5660,11 @@ static Sys_var_rpl_filter Sys_replicate_ignore_db( ...@@ -5630,6 +5660,11 @@ static Sys_var_rpl_filter Sys_replicate_ignore_db(
"actual names of table(s) being updated are checked.", "actual names of table(s) being updated are checked.",
PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_IGNORE_DB); PRIV_SET_SYSTEM_GLOBAL_VAR_REPLICATE_IGNORE_DB);
static Sys_var_binlog_filter Sys_binlog_ignore_db(
"binlog_ignore_db", OPT_BINLOG_IGNORE_DB,
"Tells the primary that updates to the given database should not be logged to the binary log.",
PRIV_SET_SYSTEM_GLOBAL_VAR_BINLOG_IGNORE_DB);
static Sys_var_rpl_filter Sys_replicate_ignore_table( static Sys_var_rpl_filter Sys_replicate_ignore_table(
"replicate_ignore_table", OPT_REPLICATE_IGNORE_TABLE, "replicate_ignore_table", OPT_REPLICATE_IGNORE_TABLE,
"Tells the slave thread not to replicate any statement that " "Tells the slave thread not to replicate any statement that "
...@@ -5656,6 +5691,15 @@ static Sys_var_charptr_fscs Sys_slave_load_tmpdir( ...@@ -5656,6 +5691,15 @@ static Sys_var_charptr_fscs Sys_slave_load_tmpdir(
READ_ONLY GLOBAL_VAR(slave_load_tmpdir), CMD_LINE(REQUIRED_ARG), READ_ONLY GLOBAL_VAR(slave_load_tmpdir), CMD_LINE(REQUIRED_ARG),
DEFAULT(0)); DEFAULT(0));
static Sys_var_ulong Sys_opt_binlog_rows_event_max_size(
"binlog_row_event_max_size",
"The maximum size of a row-based binary log event in bytes. Rows will be "
"grouped into events smaller than this size if possible. "
"The value has to be a multiple of 256.",
READ_ONLY GLOBAL_VAR(opt_binlog_rows_event_max_size), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(256, UINT_MAX32 - (UINT_MAX32 % 256)), DEFAULT(8192),
BLOCK_SIZE(256));
static Sys_var_on_access_global<Sys_var_uint, static Sys_var_on_access_global<Sys_var_uint,
PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_NET_TIMEOUT> PRIV_SET_SYSTEM_GLOBAL_VAR_SLAVE_NET_TIMEOUT>
Sys_slave_net_timeout( Sys_slave_net_timeout(
......
...@@ -797,6 +797,56 @@ class Sys_var_rpl_filter: public sys_var ...@@ -797,6 +797,56 @@ class Sys_var_rpl_filter: public sys_var
bool set_filter_value(const char *value, Master_info *mi); bool set_filter_value(const char *value, Master_info *mi);
}; };
class Sys_var_binlog_filter: public sys_var
{
private:
int opt_id;
privilege_t m_access_global;
public:
Sys_var_binlog_filter(const char *name, int getopt_id, const char *comment,
privilege_t access_global)
: sys_var(&all_sys_vars, name, comment, sys_var::READONLY+sys_var::GLOBAL, 0, NO_GETOPT,
NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
NULL, NULL, NULL), opt_id(getopt_id),
m_access_global(access_global)
{
option.var_type|= GET_STR;
}
bool do_check(THD *thd, set_var *var) override
{
DBUG_ASSERT(FALSE);
return true;
}
void session_save_default(THD *, set_var *) override
{ DBUG_ASSERT(FALSE); }
void global_save_default(THD *thd, set_var *var) override
{ DBUG_ASSERT(FALSE); }
bool session_update(THD *, set_var *) override
{
DBUG_ASSERT(FALSE);
return true;
}
bool global_update(THD *thd, set_var *var) override
{
DBUG_ASSERT(FALSE);
return true;
}
bool on_check_access_global(THD *thd) const override
{
return check_global_access(thd, m_access_global);
}
protected:
const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base)
const override;
};
/** /**
The class for string variables. Useful for strings that aren't necessarily The class for string variables. Useful for strings that aren't necessarily
\0-terminated. Otherwise the same as Sys_var_charptr. \0-terminated. Otherwise the same as Sys_var_charptr.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment