1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
|
/* Copyright (c) 2021, 2025, Oracle and/or its affiliates.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2.0,
as published by the Free Software Foundation.
This program is designed to work with certain software (including
but not limited to OpenSSL) that is licensed under separate terms,
as designated in a particular file or component or in included license
documentation. The authors of MySQL hereby grant you an additional
permission to link the program and your derivative works with the
separately licensed software that they have either included with
the program or referenced in the documentation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License, version 2.0, for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "sql/server_component/mysql_system_variable_update_imp.h"
#include <string.h>
#include <string_view>
#include <mysql/components/minimal_chassis.h>
#include <mysql/components/service_implementation.h>
#include <mysql/components/services/log_builtins.h>
#include <mysql/components/services/mysql_string.h>
#include <mysql/psi/mysql_rwlock.h>
#include <sql/mysqld.h>
#include <sql/set_var.h>
#include <sql/sql_class.h>
#include <sql/sql_lex.h>
#include <sql/sql_list.h>
#include <sql/sys_vars_shared.h>
#include <sql_string.h>
#include "sql/auth/auth_acls.h"
#include "sql/auth/sql_security_ctx.h"
#include "sql/item_func.h" // Item_func_set_user_var
#include "sql/server_component/set_variables_helper.h"
#include "storing_auto_thd.h"
/**
Return the system variable type given a type name.
*/
static enum_var_type sysvar_type(const char *type_name) {
if (type_name) {
if (!strcmp(type_name, "GLOBAL"))
return OPT_GLOBAL;
else if (!strcmp(type_name, "SESSION"))
return OPT_SESSION;
else if (!strcmp(type_name, "PERSIST"))
return OPT_PERSIST;
else if (!strcmp(type_name, "PERSIST_ONLY"))
return OPT_PERSIST_ONLY;
}
return OPT_DEFAULT;
}
/**
This is an internal method that handles preparation tasks common for
all system variable update service APIs:
- creates temporary THD for an operation, if needed
- validates that SESSION type is not used with temporary THD
@param hlp: Execution context handle.
@param variable_type: One of GLOBAL, SESSION, PERSIST, PERSIST_ONLY.
For any other value (including NULL), GLOBAL is
assumed. SESSION is not supported for a temporary THD.
@param variable_name: MySQL string of the variable name.
@param var_type: Reference to output variable type enumeration (avoids parsing
type multiple times).
@retval FALSE: Success
@retval TRUE: Failure, error set
*/
static bool prepare_thread_and_validate(Set_variables_helper &hlp,
const char *variable_type,
my_h_string variable_name,
enum_var_type &var_type) {
var_type = sysvar_type(variable_type);
if (var_type == OPT_DEFAULT) var_type = OPT_GLOBAL;
/* Use either the THD provided or create a temporary one */
if (hlp.is_auto_thd()) {
/* A session variable update for a temporary THD has no effect
and is not supported. */
if (var_type == OPT_SESSION) {
String *name = reinterpret_cast<String *>(variable_name);
LogErr(ERROR_LEVEL, ER_TMP_SESSION_FOR_VAR, name->c_ptr_safe());
return true;
}
/*
Set a temporary lock wait timeout before updating the system variable.
Some system variables, such as super-read-only, can be blocked by other
locks during the update. Should that happen, we don't want to be holding
LOCK_system_variables_hash.
*/
hlp.get_thd()->variables.lock_wait_timeout = 5;
}
// success
return false;
}
/**
Common system variable update code (used by different variable value types).
@param hlp: An execution context
@param var_type: Enum type matching one of GLOBAL, SESSION, PERSIST,
PERSIST_ONLY.
@param variable_base: MySQL string of the variable prefix, NULL if none.
@param variable_name: MySQL string of the variable name.
@param variable_value: Pointer to Item object storing the value of the correct
@retval false: Success
@retval true: Failure, error set
*/
static bool common_system_variable_update_set(Set_variables_helper &hlp,
enum_var_type var_type,
my_h_string variable_base,
my_h_string variable_name,
Item *variable_value) {
/* Cannot set system variable when server is shutting down. */
rwlock_scoped_lock rdlock(&LOCK_server_shutting_down, false, __FILE__,
__LINE__);
if (server_shutting_down) return true;
String *base = reinterpret_cast<String *>(variable_base);
String *name = reinterpret_cast<String *>(variable_name);
if (hlp.add_variable(base ? base->ptr() : nullptr, base ? base->length() : 0,
name->ptr(), name->length(), variable_value, var_type))
return true;
return hlp.execute();
}
/**
Implementation for the
@ref mysql_service_mysql_system_variable_update_string_t service.
Sets the value of a system variable to a new value specified in
variable_value. Works only for system variables taking unsigned string values.
May generate an SQL error that it stores into the current THD (if available).
@param hthd: THD session handle. If NULL, then a temporary THD will be created
and then deleted.
@param variable_type: One of GLOBAL, SESSION, PERSIST, PERSIST_ONLY.
For any other value (including NULL), GLOBAL is
assumed. SESSION is not supported for a temporary THD.
@param variable_base: MySQL string of the variable prefix, NULL if none.
@param variable_name: MySQL string of the variable name.
@param variable_value: MySQL string value to pass to the variable.
@retval FALSE: Success
@retval TRUE: Failure, error set
@sa @ref mysql_service_mysql_system_variable_update_string_t
*/
DEFINE_BOOL_METHOD(mysql_system_variable_update_imp::set_string,
(MYSQL_THD hthd, const char *variable_type,
my_h_string variable_base, my_h_string variable_name,
my_h_string variable_value)) {
try {
enum_var_type var_type;
Set_variables_helper hlp(static_cast<THD *>(hthd));
if (variable_value == nullptr) return true;
if (prepare_thread_and_validate(hlp, variable_type, variable_name,
var_type))
return true;
String *value = reinterpret_cast<String *>(variable_value);
Item *value_str = new (hlp.get_thd()->mem_root)
Item_string(value->c_ptr_safe(), value->length(), value->charset());
return common_system_variable_update_set(hlp, var_type, variable_base,
variable_name, value_str);
} catch (...) {
mysql_components_handle_std_exception(__func__);
}
return true;
}
/**
Sets the value of a system variable to a new signed integer value.
Works only for system variables taking integer or compatible values.
Passing non-NULL THD means that the operation will be executed within the
scope of existing transaction, thus any operation side effects impacting
transaction itself (for example it may generate an SQL error that it stores
into the current THD). If using existing THD, security context of the thread
is checked to make sure that required privileges exist. Passing NULL makes a
temporary THD created as a execution context (and destroyed afterwards), i.e.
no impacts on existing transactions. It doesn't make sense to change SESSION
variable on a temporary THD, so this operation will generate error.
@param hthd thread session handle. if NULL a temporary one will be created
and then deleted.
@param variable_type: One of GLOBAL, SESSION, PERSIST, PERSIST_ONLY.
For any other value (including NULL), GLOBAL is
assumed. SESSION is not supported for a temporary THD.
@param variable_base: a mysql string of the variable name prefix. NULL if
none
@param variable_name: MySQL string of the variable name
@param variable_value: long long to set as value
@retval FALSE: success
@retval TRUE: failure, error set. For error info, see THD if supplied.
*/
DEFINE_BOOL_METHOD(mysql_system_variable_update_imp::set_signed,
(MYSQL_THD hthd, const char *variable_type,
my_h_string variable_base, my_h_string variable_name,
long long variable_value)) {
try {
enum_var_type var_type;
Set_variables_helper hlp(static_cast<THD *>(hthd));
if (prepare_thread_and_validate(hlp, variable_type, variable_name,
var_type))
return true;
Item *value_num = new (hlp.get_thd()->mem_root) Item_int(variable_value);
return common_system_variable_update_set(hlp, var_type, variable_base,
variable_name, value_num);
} catch (...) {
mysql_components_handle_std_exception(__func__);
}
return true;
}
/**
Sets the value of a system variable to a new unsigned integer value.
Same analysis as for mysql_system_variable_update_integer::set_signed
applies here as well.
@param hthd thread session handle. if NULL a temporary one will be created
and then deleted.
@param variable_type: One of GLOBAL, SESSION, PERSIST, PERSIST_ONLY.
For any other value (including NULL), GLOBAL is
assumed. SESSION is not supported for a temporary THD.
@param variable_base: a mysql string of the variable name prefix. NULL if
none
@param variable_name: MySQL string of the variable name
@param variable_value: unsigned long long to set as value
@retval FALSE: success
@retval TRUE: failure, error set. For error info, see THD if supplied.
*/
DEFINE_BOOL_METHOD(mysql_system_variable_update_imp::set_unsigned,
(MYSQL_THD hthd, const char *variable_type,
my_h_string variable_base, my_h_string variable_name,
unsigned long long variable_value)) {
try {
enum_var_type var_type;
Set_variables_helper hlp(static_cast<THD *>(hthd));
if (prepare_thread_and_validate(hlp, variable_type, variable_name,
var_type))
return true;
Item *value_num = new (hlp.get_thd()->mem_root) Item_uint(variable_value);
return common_system_variable_update_set(hlp, var_type, variable_base,
variable_name, value_num);
} catch (...) {
mysql_components_handle_std_exception(__func__);
}
return true;
}
/**
Sets the value of a system variable to its default value.
Same analysis as for mysql_system_variable_update_integer::set_signed
applies here as well.
@param hthd thread session handle. if NULL a temporary one will be created
and then removed.
@param variable_type: One of GLOBAL, SESSION, PERSIST, PERSIST_ONLY.
For any other value (including NULL), GLOBAL is
assumed. SESSION is not supported for a temporary THD.
@param variable_base: a mysql string of the variable name prefix. NULL if
none
@param variable_name: MySQL string of the variable name
@retval FALSE: success
@retval TRUE: failure, error set. For error info, see THD if supplied.
*/
DEFINE_BOOL_METHOD(mysql_system_variable_update_imp::set_default,
(MYSQL_THD hthd, const char *variable_type,
my_h_string variable_base, my_h_string variable_name)) {
try {
enum_var_type var_type;
Set_variables_helper hlp(static_cast<THD *>(hthd));
if (prepare_thread_and_validate(hlp, variable_type, variable_name,
var_type))
return true;
return common_system_variable_update_set(hlp, var_type, variable_base,
variable_name, nullptr);
} catch (...) {
mysql_components_handle_std_exception(__func__);
}
return true;
}
|