1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

MDEV-15935 Adding global/session system var redirect_url

Adding a global/session var `redirect_url' of string type. The initial
value is empty. Can be supplied in mysqld with --redirect-url or set
in --init-connect. A valid redirect_url should be of the format

{mysql,mariadb}://host[:port]

where <host> is an arbitrary string not containing colons, and <port>
is a number between 0 and 65535 inclusive.

The variable will be used by the server to notify clients that they
should connect to another server, specified by the value of the
variable, if not empty.

The notification is done by the inclusion of the variable in
session_track_system_variable.
This commit is contained in:
Yuchen Pei
2023-09-13 11:49:57 +10:00
parent 6151bde48c
commit 5af70decca
12 changed files with 286 additions and 16 deletions

View File

@ -1064,6 +1064,8 @@ The following specify which files/extra groups are read (specified before remain
--read-rnd-buffer-size=#
When reading rows in sorted order after a sort, the rows
are read through this buffer to avoid a disk seeks
--redirect-url=name URL of another server to redirect clients to. Empty
string means no redirection
--relay-log=name The location and name to use for relay logs.
--relay-log-index=name
The location and name to use for the file that keeps a
@ -1838,6 +1840,7 @@ read-binlog-speed-limit 0
read-buffer-size 131072
read-only FALSE
read-rnd-buffer-size 262144
redirect-url
relay-log (No default value)
relay-log-index (No default value)
relay-log-info-file relay-log.info
@ -1869,7 +1872,7 @@ secure-timestamp NO
server-id 1
session-track-schema TRUE
session-track-state-change FALSE
session-track-system-variables autocommit,character_set_client,character_set_connection,character_set_results,time_zone
session-track-system-variables autocommit,character_set_client,character_set_connection,character_set_results,redirect_url,time_zone
session-track-transaction-info OFF
show-slave-auth-info FALSE
silent-startup FALSE

View File

@ -0,0 +1,13 @@
#
# MDEV-32254 Server crashes when adding records to table after setting redirect_url with empty variable
#
set @old_redirect_url=@@global.redirect_url;
set global redirect_url=@empty_value;
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'NULL'
CREATE TABLE t (c1 INT) ENGINE=INNODB;
INSERT INTO t VALUES (1),(1);
drop table t;
set global redirect_url=@old_redirect_url;
#
# end of test mdev_32254
#

View File

@ -0,0 +1,81 @@
#
# MDEV-15935 Connection Redirection Mechanism in MariaDB Client/Server Protocol
#
connect con,localhost,anyone_but_root;
select @@redirect_url;
@@redirect_url
mysql://foobar
connection default;
set @old_global_redirect_url=@@global.redirect_url;
set @old_session_redirect_url=@@session.redirect_url;
set @old_session_track_system_variables=@@session_track_system_variables;
set session_track_system_variables="";
select @@global.redirect_url;
@@global.redirect_url
set global redirect_url=default;
select @@global.redirect_url;
@@global.redirect_url
set global redirect_url="mariadb.org";
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'mariadb.org'
set global redirect_url="https://mariadb.org";
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'https://mariadb.org'
set global redirect_url="mysql://mariadb.org:";
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'mysql://mariadb.org:'
set global redirect_url="mysql://mariadb.org:hello";
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'mysql://mariadb.org:hello'
set global redirect_url="mysql://";
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'mysql://'
set global redirect_url="mysql://mariadb.org";
select @@global.redirect_url;
@@global.redirect_url
mysql://mariadb.org
set global redirect_url="mysql://mariadb.org:12a";
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'mysql://mariadb.org:12a'
set global redirect_url="mysql://mariadb.org:66666";
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'mysql://mariadb.org:66666'
set global redirect_url="mysql://mariadb.org:12345";
select @@global.redirect_url;
@@global.redirect_url
mysql://mariadb.org:12345
set global redirect_url="maria";
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'maria'
set global redirect_url="mariadb://mariadb.org:";
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'mariadb://mariadb.org:'
set global redirect_url="mariadb://mariadb.org:hello";
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'mariadb://mariadb.org:hello'
set global redirect_url="mariadb://";
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'mariadb://'
set global redirect_url="mariadb://mariadb.org";
select @@global.redirect_url;
@@global.redirect_url
mariadb://mariadb.org
set global redirect_url="mariadb://mariadb.org:12a";
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'mariadb://mariadb.org:12a'
set global redirect_url="mariadb://mariadb.org:66666";
ERROR 42000: Variable 'redirect_url' can't be set to the value of 'mariadb://mariadb.org:66666'
set global redirect_url="mariadb://mariadb.org:12345";
select @@global.redirect_url;
@@global.redirect_url
mariadb://mariadb.org:12345
select @@session.redirect_url;
@@session.redirect_url
set session redirect_url=default;
select @@session.redirect_url;
@@session.redirect_url
mariadb://mariadb.org:12345
set session redirect_url="mysql://localhost";
select @@session.redirect_url;
@@session.redirect_url
mysql://localhost
select @@global.redirect_url;
@@global.redirect_url
mariadb://mariadb.org:12345
set global redirect_url=@old_global_redirect_url;
set session redirect_url=@old_session_redirect_url;
set session session_track_system_variables=@old_session_track_system_variables;
#
# end of test MDEV-15935
#

View File

@ -5,20 +5,20 @@
# Global - default
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
autocommit,character_set_client,character_set_connection,character_set_results,redirect_url,time_zone
# Session - default
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
autocommit,character_set_client,character_set_connection,character_set_results,redirect_url,time_zone
# via INFORMATION_SCHEMA.GLOBAL_VARIABLES
SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES WHERE VARIABLE_NAME LIKE 'session_track_system_variables' ORDER BY VARIABLE_NAME;
VARIABLE_NAME VARIABLE_VALUE
SESSION_TRACK_SYSTEM_VARIABLES autocommit,character_set_client,character_set_connection,character_set_results,time_zone
SESSION_TRACK_SYSTEM_VARIABLES autocommit,character_set_client,character_set_connection,character_set_results,redirect_url,time_zone
# via INFORMATION_SCHEMA.SESSION_VARIABLES
SELECT * FROM INFORMATION_SCHEMA.SESSION_VARIABLES WHERE VARIABLE_NAME LIKE 'session_track_system_variables' ORDER BY VARIABLE_NAME;
VARIABLE_NAME VARIABLE_VALUE
SESSION_TRACK_SYSTEM_VARIABLES autocommit,character_set_client,character_set_connection,character_set_results,time_zone
SESSION_TRACK_SYSTEM_VARIABLES autocommit,character_set_client,character_set_connection,character_set_results,redirect_url,time_zone
SET @global_saved_tmp = @@global.session_track_system_variables;
# Altering global variable's value
@ -28,7 +28,7 @@ SELECT @@global.session_track_system_variables;
autocommit
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
autocommit,character_set_client,character_set_connection,character_set_results,redirect_url,time_zone
# Altering session variable's value
SET @@session.session_track_system_variables='autocommit';
@ -66,25 +66,25 @@ SET @@session.session_track_system_variables = DEFAULT;
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
autocommit,character_set_client,character_set_connection,character_set_results,redirect_url,time_zone
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
autocommit,character_set_client,character_set_connection,character_set_results,redirect_url,time_zone
# Variables' values in a new session (con2).
connect con2,"127.0.0.1",root,,test,$MASTER_MYPORT,;
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
autocommit,character_set_client,character_set_connection,character_set_results,redirect_url,time_zone
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
autocommit,character_set_client,character_set_connection,character_set_results,redirect_url,time_zone
# Altering session should not affect global.
SET @@session.session_track_system_variables = 'sql_mode';
SELECT @@global.session_track_system_variables;
@@global.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
autocommit,character_set_client,character_set_connection,character_set_results,redirect_url,time_zone
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
sql_mode
@ -98,7 +98,7 @@ SELECT @@global.session_track_system_variables;
sql_mode
SELECT @@session.session_track_system_variables;
@@session.session_track_system_variables
autocommit,character_set_client,character_set_connection,character_set_results,time_zone
autocommit,character_set_client,character_set_connection,character_set_results,redirect_url,time_zone
# Switching to the default connection.
connection default;

View File

@ -3412,6 +3412,16 @@ NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME REDIRECT_URL
VARIABLE_SCOPE SESSION
VARIABLE_TYPE VARCHAR
VARIABLE_COMMENT URL of another server to redirect clients to. Empty string means no redirection
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME RELAY_LOG
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE VARCHAR

View File

@ -0,0 +1,17 @@
--echo #
--echo # MDEV-32254 Server crashes when adding records to table after setting redirect_url with empty variable
--echo #
--source include/have_innodb.inc
# redirect_url is undefined in embedded.
--source include/not_embedded.inc
set @old_redirect_url=@@global.redirect_url;
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url=@empty_value;
CREATE TABLE t (c1 INT) ENGINE=INNODB;
INSERT INTO t VALUES (1),(1);
drop table t;
set global redirect_url=@old_redirect_url;
--echo #
--echo # end of test mdev_32254
--echo #

View File

@ -0,0 +1 @@
--init-connect="set redirect_url='mysql://foobar'"

View File

@ -0,0 +1,74 @@
--echo #
--echo # MDEV-15935 Connection Redirection Mechanism in MariaDB Client/Server Protocol
--echo #
# redirect_url is undefined in embedded.
--source include/not_embedded.inc
# We need to connect as a non super user for the init-connect to take
# effect
--source include/add_anonymous_users.inc
connect (con,localhost,anyone_but_root);
select @@redirect_url;
connection default;
--source include/delete_anonymous_users.inc
set @old_global_redirect_url=@@global.redirect_url;
set @old_session_redirect_url=@@session.redirect_url;
set @old_session_track_system_variables=@@session_track_system_variables;
set session_track_system_variables="";
select @@global.redirect_url;
set global redirect_url=default;
select @@global.redirect_url;
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url="mariadb.org";
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url="https://mariadb.org";
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url="mysql://mariadb.org:";
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url="mysql://mariadb.org:hello";
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url="mysql://";
set global redirect_url="mysql://mariadb.org";
select @@global.redirect_url;
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url="mysql://mariadb.org:12a";
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url="mysql://mariadb.org:66666";
set global redirect_url="mysql://mariadb.org:12345";
select @@global.redirect_url;
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url="maria";
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url="mariadb://mariadb.org:";
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url="mariadb://mariadb.org:hello";
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url="mariadb://";
set global redirect_url="mariadb://mariadb.org";
select @@global.redirect_url;
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url="mariadb://mariadb.org:12a";
--error ER_WRONG_VALUE_FOR_VAR
set global redirect_url="mariadb://mariadb.org:66666";
set global redirect_url="mariadb://mariadb.org:12345";
select @@global.redirect_url;
select @@session.redirect_url;
# Test that session default is global value
set session redirect_url=default;
select @@session.redirect_url;
set session redirect_url="mysql://localhost";
select @@session.redirect_url;
select @@global.redirect_url;
set global redirect_url=@old_global_redirect_url;
set session redirect_url=@old_session_redirect_url;
set session session_track_system_variables=@old_session_track_system_variables;
--echo #
--echo # end of test MDEV-15935
--echo #

View File

@ -883,6 +883,7 @@ typedef struct system_variables
Time_zone *time_zone;
char *session_track_system_variables;
char *redirect_url;
/* Some wsrep variables */
ulonglong wsrep_trx_fragment_size;

View File

@ -3278,6 +3278,8 @@ void plugin_thdvar_init(THD *thd)
/* This and all other variable cleanups are here for COM_CHANGE_USER :( */
#ifndef EMBEDDED_LIBRARY
thd->session_tracker.sysvars.deinit(thd);
my_free(thd->variables.redirect_url);
thd->variables.redirect_url= 0;
#endif
my_free((char*) thd->variables.default_master_connection.str);
thd->variables.default_master_connection.str= 0;
@ -3311,7 +3313,12 @@ void plugin_thdvar_init(THD *thd)
MYF(MY_WME | MY_THREAD_SPECIFIC));
#ifndef EMBEDDED_LIBRARY
thd->session_tracker.sysvars.init(thd);
thd->variables.redirect_url=
my_strdup(key_memory_Sys_var_charptr_value,
global_system_variables.redirect_url,
MYF(MY_WME | MY_THREAD_SPECIFIC));
#endif
DBUG_VOID_RETURN;
}
@ -3379,6 +3386,8 @@ void plugin_thdvar_cleanup(THD *thd)
#ifndef EMBEDDED_LIBRARY
thd->session_tracker.sysvars.deinit(thd);
my_free(thd->variables.redirect_url);
thd->variables.redirect_url= 0;
#endif
my_free((char*) thd->variables.default_master_connection.str);
thd->variables.default_master_connection.str= 0;

View File

@ -6894,13 +6894,73 @@ static Sys_var_ulonglong Sys_max_session_mem_used(
DEFAULT(LONGLONG_MAX), BLOCK_SIZE(1));
#ifndef EMBEDDED_LIBRARY
/**
Validate a redirect_url string.
A valid string is either empty, or of the format mysql://host[:port],
where host is an arbitrary string without any colon ':'.
@param str A string to validate
@param len Length of the string
@retval false The string is valid
@retval true The string is invalid
*/
static bool sysvar_validate_redirect_url(sys_var *self, THD *thd,
set_var *var)
{
/* NULL is invalid. */
if (check_not_null(self, thd, var))
return true;
char *str= var->save_result.string_value.str;
size_t len= var->save_result.string_value.length;
LEX_CSTRING mysql_prefix= {STRING_WITH_LEN("mysql://")};
LEX_CSTRING maria_prefix= {STRING_WITH_LEN("mariadb://")};
/* Empty string is valid */
if (len == 0)
return false;
const char* end= str + len;
if (!strncmp(str, mysql_prefix.str, mysql_prefix.length))
str+= mysql_prefix.length;
else if (!strncmp(str, maria_prefix.str, maria_prefix.length))
str+= maria_prefix.length;
else
return true;
/* Host name cannot be empty */
if (str == end)
return true;
/* Find the colon, if any */
while (str < end && *str != ':')
str++;
/* Found colon */
if (str < end)
{
/* Should have at least one number after the colon */
if (str + 1 == end)
return true;
int p= 0;
while (str < end && isdigit(*++str))
if ((p= p * 10 + (*str - '0')) > 65535)
return true;
/* Should be all numbers after the colon */
if (str < end)
return true;
}
return false;
}
static Sys_var_charptr Sys_redirect_url(
"redirect_url",
"URL of another server to redirect clients to. "
"Empty string means no redirection",
SESSION_VAR(redirect_url), CMD_LINE(REQUIRED_ARG), DEFAULT(""),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(sysvar_validate_redirect_url));
static Sys_var_sesvartrack Sys_track_session_sys_vars(
"session_track_system_variables",
"Track changes in registered system variables. ",
CMD_LINE(REQUIRED_ARG),
DEFAULT("autocommit,character_set_client,character_set_connection,"
"character_set_results,time_zone"));
"character_set_results,redirect_url,time_zone"));
static bool update_session_track_schema(sys_var *self, THD *thd,
enum_var_type type)

View File

@ -495,9 +495,10 @@ public:
Note that the memory management for SESSION_VAR's is manual, the
value must be strdup'ed in THD::init() and freed in
plugin_thdvar_cleanup(). TODO: it should be done automatically when
we'll have more session string variables to justify it. Maybe some
kind of a loop over all variables, like sys_var_end() in set_var.cc?
plugin_thdvar_cleanup(), see e.g. redirect_url. TODO: it should be
done automatically when we'll have more session string variables to
justify it. Maybe some kind of a loop over all variables, like
sys_var_end() in set_var.cc?
*/
class Sys_var_charptr: public sys_var
{