1 /* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include "sql/set_var.h"
24
25 #include <string.h>
26 #include <sys/types.h>
27 #include <cstdlib>
28 #include <utility>
29
30 #include "m_ctype.h"
31 #include "m_string.h"
32 #include "map_helpers.h"
33 #include "my_dbug.h"
34 #include "my_io.h"
35 #include "my_loglevel.h"
36 #include "my_sys.h"
37 #include "mysql/components/services/log_builtins.h"
38 #include "mysql/components/services/log_shared.h"
39 #include "mysql/plugin_audit.h"
40 #include "mysql/psi/mysql_mutex.h"
41 #include "mysql/psi/mysql_rwlock.h"
42 #include "mysql/psi/psi_base.h"
43 #include "mysqld_error.h"
44 #include "sql/auth/auth_acls.h"
45 #include "sql/auth/auth_common.h" // SUPER_ACL, generate_password
46 #include "sql/auth/sql_security_ctx.h"
47 #include "sql/derror.h" // ER_THD
48 #include "sql/enum_query_type.h"
49 #include "sql/item.h"
50 #include "sql/item_func.h"
51 #include "sql/log.h"
52 #include "sql/mysqld.h" // system_charset_info
53 #include "sql/persisted_variable.h"
54 #include "sql/protocol_classic.h"
55 #include "sql/session_tracker.h"
56 #include "sql/sql_audit.h" // mysql_audit
57 #include "sql/sql_base.h" // lock_tables
58 #include "sql/sql_class.h" // THD
59 #include "sql/sql_error.h"
60 #include "sql/sql_lex.h"
61 #include "sql/sql_list.h"
62 #include "sql/sql_parse.h" // is_supported_parser_charset
63 #include "sql/sql_select.h" // free_underlaid_joins
64 #include "sql/sql_show.h" // append_identifier
65 #include "sql/sys_vars_shared.h" // PolyLock_mutex
66 #include "sql/system_variables.h"
67 #include "sql/table.h"
68 #include "sql_string.h"
69
70 using std::min;
71 using std::string;
72
73 static collation_unordered_map<string, sys_var *> *system_variable_hash;
74 static PolyLock_mutex PLock_global_system_variables(
75 &LOCK_global_system_variables);
76 ulonglong system_variable_hash_version = 0;
77
get_system_variable_hash(void)78 collation_unordered_map<string, sys_var *> *get_system_variable_hash(void) {
79 return system_variable_hash;
80 }
81
82 /** list of variables that shouldn't be persisted in all cases */
83 static collation_unordered_set<string> *never_persistable_vars;
84
85 /**
86 Get source of a given system variable given its name and name length.
87 */
get_sysvar_source(const char * name,uint length,enum enum_variable_source * source)88 bool get_sysvar_source(const char *name, uint length,
89 enum enum_variable_source *source) {
90 DBUG_TRACE;
91
92 bool ret = false;
93 sys_var *sysvar = nullptr;
94
95 mysql_rwlock_wrlock(&LOCK_system_variables_hash);
96
97 /* system_variable_hash should have been initialized. */
98 DBUG_ASSERT(get_system_variable_hash() != nullptr);
99 std::string str(name, length);
100 sysvar = find_or_nullptr(*get_system_variable_hash(), str);
101
102 if (sysvar == nullptr) {
103 ret = true;
104 } else {
105 *source = sysvar->get_source();
106 }
107
108 mysql_rwlock_unlock(&LOCK_system_variables_hash);
109 return ret;
110 }
111
112 sys_var_chain all_sys_vars = {nullptr, nullptr};
113
sys_var_init()114 int sys_var_init() {
115 DBUG_TRACE;
116
117 /* Must be already initialized. */
118 DBUG_ASSERT(system_charset_info != nullptr);
119
120 system_variable_hash = new collation_unordered_map<string, sys_var *>(
121 system_charset_info, PSI_INSTRUMENT_ME);
122
123 never_persistable_vars = new collation_unordered_set<string>(
124 {PERSIST_ONLY_ADMIN_X509_SUBJECT, PERSISTED_GLOBALS_LOAD},
125 system_charset_info, PSI_INSTRUMENT_ME);
126
127 if (mysql_add_sys_var_chain(all_sys_vars.first)) goto error;
128
129 return 0;
130
131 error:
132 LogErr(ERROR_LEVEL, ER_FAILED_TO_INIT_SYS_VAR);
133 return 1;
134 }
135
sys_var_add_options(std::vector<my_option> * long_options,int parse_flags)136 int sys_var_add_options(std::vector<my_option> *long_options, int parse_flags) {
137 DBUG_TRACE;
138
139 for (sys_var *var = all_sys_vars.first; var; var = var->next) {
140 if (var->register_option(long_options, parse_flags)) goto error;
141 }
142
143 return 0;
144
145 error:
146 LogErr(ERROR_LEVEL, ER_FAILED_TO_INIT_SYS_VAR);
147 return 1;
148 }
149
sys_var_end()150 void sys_var_end() {
151 DBUG_TRACE;
152
153 delete system_variable_hash;
154 delete never_persistable_vars;
155 system_variable_hash = nullptr;
156
157 for (sys_var *var = all_sys_vars.first; var; var = var->next) var->cleanup();
158 }
159
160 /**
161 This function will check for necessary privileges needed to perform RESET
162 PERSIST or SET PERSIST[_ONLY] operation.
163
164 @param [in] thd Pointer to connection handle.
165 @param [in] static_variable describes if variable is static or dynamic
166
167 @return 0 Success
168 @return 1 Failure
169 */
check_priv(THD * thd,bool static_variable)170 bool check_priv(THD *thd, bool static_variable) {
171 Security_context *sctx = thd->security_context();
172 /* for dynamic variables user needs SUPER_ACL or SYSTEM_VARIABLES_ADMIN */
173 if (!static_variable) {
174 if (!sctx->check_access(SUPER_ACL) &&
175 !(sctx->has_global_grant(STRING_WITH_LEN("SYSTEM_VARIABLES_ADMIN"))
176 .first)) {
177 my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0),
178 "SUPER or SYSTEM_VARIABLES_ADMIN");
179 return true;
180 }
181 } else {
182 /*
183 for static variables user needs both SYSTEM_VARIABLES_ADMIN and
184 PERSIST_RO_VARIABLES_ADMIN
185 */
186 if (!(sctx->has_global_grant(STRING_WITH_LEN("SYSTEM_VARIABLES_ADMIN"))
187 .first &&
188 sctx->has_global_grant(STRING_WITH_LEN("PERSIST_RO_VARIABLES_ADMIN"))
189 .first)) {
190 my_error(ER_PERSIST_ONLY_ACCESS_DENIED_ERROR, MYF(0),
191 "SYSTEM_VARIABLES_ADMIN and PERSIST_RO_VARIABLES_ADMIN");
192 return true;
193 }
194 }
195 return false;
196 }
197
198 /**
199 sys_var constructor
200
201 @param chain variables are linked into chain for mysql_add_sys_var_chain()
202 @param name_arg the name of the variable. Must be 0-terminated and exist
203 for the liftime of the sys_var object. @sa my_option::name
204 @param comment shown in mysqld --help, @sa my_option::comment
205 @param flags_arg or'ed flag_enum values
206 @param off offset of the global variable value from the
207 &global_system_variables.
208 @param getopt_id -1 for no command-line option, otherwise @sa my_option::id
209 @param getopt_arg_type no|optional|required value @sa my_option::arg_type
210 @param show_val_type_arg what value_ptr() returns for sql_show.cc
211 @param def_val default value, @sa my_option::def_value
212 @param lock mutex or rw_lock that protects the global variable
213 *in addition* to LOCK_global_system_variables.
214 @param binlog_status_arg if the sysvar will be written to binlog or not @sa
215 binlog_status_enum
216 @param on_check_func a function to be called at the end of sys_var::check,
217 put your additional checks here
218 @param on_update_func a function to be called at the end of sys_var::update,
219 any post-update activity should happen here
220 @param substitute If non-NULL, this variable is deprecated and the
221 string describes what one should use instead. If an empty string,
222 the variable is deprecated but no replacement is offered.
223 @param parse_flag either PARSE_EARLY or PARSE_NORMAL
224 */
sys_var(sys_var_chain * chain,const char * name_arg,const char * comment,int flags_arg,ptrdiff_t off,int getopt_id,enum get_opt_arg_type getopt_arg_type,SHOW_TYPE show_val_type_arg,longlong def_val,PolyLock * lock,enum binlog_status_enum binlog_status_arg,on_check_function on_check_func,on_update_function on_update_func,const char * substitute,int parse_flag)225 sys_var::sys_var(sys_var_chain *chain, const char *name_arg,
226 const char *comment, int flags_arg, ptrdiff_t off,
227 int getopt_id, enum get_opt_arg_type getopt_arg_type,
228 SHOW_TYPE show_val_type_arg, longlong def_val, PolyLock *lock,
229 enum binlog_status_enum binlog_status_arg,
230 on_check_function on_check_func,
231 on_update_function on_update_func, const char *substitute,
232 int parse_flag)
233 : next(nullptr),
234 binlog_status(binlog_status_arg),
235 flags(flags_arg),
236 m_parse_flag(parse_flag),
237 show_val_type(show_val_type_arg),
238 guard(lock),
239 offset(off),
240 on_check(on_check_func),
241 on_update(on_update_func),
242 deprecation_substitute(substitute),
243 is_os_charset(false) {
244 /*
245 There is a limitation in handle_options() related to short options:
246 - either all short options should be declared when parsing in multiple
247 stages,
248 - or none should be declared.
249 Because a lot of short options are used in the normal parsing phase
250 for mysqld, we enforce here that no short option is present
251 in the first (PARSE_EARLY) stage.
252 See handle_options() for details.
253 */
254 DBUG_ASSERT(parse_flag == PARSE_NORMAL || getopt_id <= 0 || getopt_id >= 255);
255
256 name.str = name_arg; // ER_NO_DEFAULT relies on 0-termination of name_arg
257 name.length = strlen(name_arg); // and so does this.
258 DBUG_ASSERT(name.length <= NAME_CHAR_LEN);
259
260 memset(&option, 0, sizeof(option));
261 option.name = name_arg;
262 option.id = getopt_id;
263 option.comment = comment;
264 option.arg_type = getopt_arg_type;
265 option.value = (uchar **)global_var_ptr();
266 option.def_value = def_val;
267
268 /* set default values */
269 source.m_source = enum_variable_source::COMPILED;
270
271 timestamp = 0;
272 user[0] = '\0';
273 host[0] = '\0';
274
275 memset(source.m_path_name, 0, FN_REFLEN);
276 option.arg_source = &source;
277
278 if (chain->last)
279 chain->last->next = this;
280 else
281 chain->first = this;
282 chain->last = this;
283 }
284
update(THD * thd,set_var * var)285 bool sys_var::update(THD *thd, set_var *var) {
286 enum_var_type type = var->type;
287 if (type == OPT_GLOBAL || type == OPT_PERSIST || scope() == GLOBAL) {
288 /*
289 Yes, both locks need to be taken before an update, just as
290 both are taken to get a value. If we'll take only 'guard' here,
291 then value_ptr() for strings won't be safe in SHOW VARIABLES anymore,
292 to make it safe we'll need value_ptr_unlock().
293 */
294 AutoWLock lock1(&PLock_global_system_variables);
295 AutoWLock lock2(guard);
296 return global_update(thd, var) ||
297 (on_update && on_update(this, thd, OPT_GLOBAL));
298 } else {
299 /* Block reads from other threads. */
300 mysql_mutex_lock(&thd->LOCK_thd_sysvar);
301
302 bool ret = session_update(thd, var) ||
303 (on_update && on_update(this, thd, OPT_SESSION));
304
305 mysql_mutex_unlock(&thd->LOCK_thd_sysvar);
306
307 /*
308 Make sure we don't session-track variables that are not actually
309 part of the session. tx_isolation and and tx_read_only for example
310 exist as GLOBAL, SESSION, and one-shot ("for next transaction only").
311 */
312 if ((var->type == OPT_SESSION) || !is_trilevel()) {
313 if ((!ret) && thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)
314 ->is_enabled())
315 thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)
316 ->mark_as_changed(thd, &(var->var->name));
317
318 if ((!ret) &&
319 thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)
320 ->is_enabled())
321 thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)
322 ->mark_as_changed(thd, &var->var->name);
323 }
324
325 return ret;
326 }
327 }
328
session_value_ptr(THD *,THD * target_thd,LEX_STRING *)329 const uchar *sys_var::session_value_ptr(THD *, THD *target_thd, LEX_STRING *) {
330 return session_var_ptr(target_thd);
331 }
332
global_value_ptr(THD *,LEX_STRING *)333 const uchar *sys_var::global_value_ptr(THD *, LEX_STRING *) {
334 return global_var_ptr();
335 }
336
session_var_ptr(THD * thd)337 uchar *sys_var::session_var_ptr(THD *thd) {
338 return ((uchar *)&(thd->variables)) + offset;
339 }
340
global_var_ptr()341 uchar *sys_var::global_var_ptr() {
342 return ((uchar *)&global_system_variables) + offset;
343 }
344
check(THD * thd,set_var * var)345 bool sys_var::check(THD *thd, set_var *var) {
346 if ((var->value && do_check(thd, var)) ||
347 (on_check && on_check(this, thd, var))) {
348 if (!thd->is_error()) {
349 char buff[STRING_BUFFER_USUAL_SIZE];
350 String str(buff, sizeof(buff), system_charset_info), *res;
351
352 if (!var->value) {
353 str.set(STRING_WITH_LEN("DEFAULT"), &my_charset_latin1);
354 res = &str;
355 } else if (!(res = var->value->val_str(&str))) {
356 str.set(STRING_WITH_LEN("NULL"), &my_charset_latin1);
357 res = &str;
358 }
359 ErrConvString err(res);
360 my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
361 }
362 return true;
363 }
364 return false;
365 }
366
value_ptr(THD * running_thd,THD * target_thd,enum_var_type type,LEX_STRING * base)367 const uchar *sys_var::value_ptr(THD *running_thd, THD *target_thd,
368 enum_var_type type, LEX_STRING *base) {
369 if (type == OPT_GLOBAL || type == OPT_PERSIST || scope() == GLOBAL) {
370 mysql_mutex_assert_owner(&LOCK_global_system_variables);
371 AutoRLock lock(guard);
372 return global_value_ptr(running_thd, base);
373 } else
374 return session_value_ptr(running_thd, target_thd, base);
375 }
376
value_ptr(THD * thd,enum_var_type type,LEX_STRING * base)377 const uchar *sys_var::value_ptr(THD *thd, enum_var_type type,
378 LEX_STRING *base) {
379 return value_ptr(thd, thd, type, base);
380 }
381
set_default(THD * thd,set_var * var)382 bool sys_var::set_default(THD *thd, set_var *var) {
383 DBUG_TRACE;
384 if (var->is_global_persist() || scope() == GLOBAL)
385 global_save_default(thd, var);
386 else
387 session_save_default(thd, var);
388
389 bool ret = check(thd, var) || update(thd, var);
390 return ret;
391 }
392
set_user_host(THD * thd)393 void sys_var::set_user_host(THD *thd) {
394 memset(user, 0, sizeof(user));
395 memset(host, 0, sizeof(host));
396 Security_context *sctx = thd->security_context();
397 bool truncated = false;
398 if (sctx->user().length > 0) {
399 truncated = set_and_truncate(user, thd->security_context()->user().str,
400 sizeof(user));
401 if (truncated) {
402 LogErr(WARNING_LEVEL, ER_USERNAME_TRUNKATED, sctx->user().str,
403 USERNAME_CHAR_LENGTH);
404 }
405 }
406 if (sctx->host().length > 0) {
407 truncated = set_and_truncate(host, thd->security_context()->host().str,
408 sizeof(host));
409 if (truncated) {
410 LogErr(WARNING_LEVEL, ER_HOSTNAME_TRUNKATED, sctx->host().str,
411 HOSTNAME_LENGTH);
412 }
413 }
414 }
415
do_deprecated_warning(THD * thd)416 void sys_var::do_deprecated_warning(THD *thd) {
417 if (deprecation_substitute != nullptr) {
418 char buf1[NAME_CHAR_LEN + 3];
419 strxnmov(buf1, sizeof(buf1) - 1, "@@", name.str, 0);
420
421 /*
422 if deprecation_substitute is an empty string,
423 there is no replacement for the syntax
424 */
425 uint errmsg = deprecation_substitute[0] == '\0'
426 ? ER_DEPRECATE_MSG_NO_REPLACEMENT
427 : ER_DEPRECATE_MSG_WITH_REPLACEMENT;
428 if (thd)
429 push_warning_printf(
430 thd, Sql_condition::SL_WARNING, ER_WARN_DEPRECATED_SYNTAX,
431 ER_THD_NONCONST(thd, errmsg), buf1, deprecation_substitute);
432 else
433 LogErr(WARNING_LEVEL, errmsg, buf1, deprecation_substitute);
434 }
435 }
436
copy_value(THD * thd)437 Item *sys_var::copy_value(THD *thd) {
438 LEX_STRING str;
439 const uchar *val_ptr = session_value_ptr(thd, thd, &str);
440 switch (get_var_type()) {
441 case GET_INT:
442 return new Item_int(*pointer_cast<const int *>(val_ptr));
443 case GET_UINT:
444 return new Item_int(
445 static_cast<ulonglong>(*pointer_cast<const uint *>(val_ptr)));
446 case GET_LONG:
447 return new Item_int(
448 static_cast<longlong>(*pointer_cast<const long *>(val_ptr)));
449 case GET_ULONG:
450 return new Item_int(
451 static_cast<ulonglong>(*pointer_cast<const ulong *>(val_ptr)));
452 case GET_LL:
453 return new Item_int(*pointer_cast<const longlong *>(val_ptr));
454 case GET_ULL:
455 return new Item_int(*pointer_cast<const ulonglong *>(val_ptr));
456 case GET_BOOL:
457 return new Item_int(*pointer_cast<const bool *>(val_ptr));
458 case GET_ENUM:
459 case GET_SET:
460 case GET_FLAGSET:
461 case GET_STR_ALLOC:
462 case GET_STR:
463 case GET_NO_ARG:
464 case GET_PASSWORD: {
465 const char *tmp_str_val = pointer_cast<const char *>(val_ptr);
466 return new Item_string(tmp_str_val, strlen(tmp_str_val),
467 system_charset_info);
468 }
469 case GET_DOUBLE:
470 return new Item_float(*pointer_cast<const double *>(val_ptr),
471 DECIMAL_NOT_SPECIFIED);
472 default:
473 DBUG_ASSERT(0);
474 }
475 return nullptr;
476 }
477
478 /**
479 Throw warning (error in STRICT mode) if value for variable needed bounding.
480 Plug-in interface also uses this.
481
482 @param thd thread handle
483 @param name variable's name
484 @param fixed did we have to correct the value? (throw warn/err if so)
485 @param is_unsigned is value's type unsigned?
486 @param v variable's value
487
488 @retval true on error, false otherwise (warning or ok)
489 */
throw_bounds_warning(THD * thd,const char * name,bool fixed,bool is_unsigned,longlong v)490 bool throw_bounds_warning(THD *thd, const char *name, bool fixed,
491 bool is_unsigned, longlong v) {
492 if (fixed) {
493 char buf[22];
494
495 if (is_unsigned)
496 ullstr((ulonglong)v, buf);
497 else
498 llstr(v, buf);
499
500 if (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) {
501 my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buf);
502 return true;
503 }
504 push_warning_printf(thd, Sql_condition::SL_WARNING,
505 ER_TRUNCATED_WRONG_VALUE,
506 ER_THD(thd, ER_TRUNCATED_WRONG_VALUE), name, buf);
507 }
508 return false;
509 }
510
throw_bounds_warning(THD * thd,const char * name,bool fixed,double v)511 bool throw_bounds_warning(THD *thd, const char *name, bool fixed, double v) {
512 if (fixed) {
513 char buf[64];
514
515 my_gcvt(v, MY_GCVT_ARG_DOUBLE, static_cast<int>(sizeof(buf)) - 1, buf,
516 nullptr);
517
518 if (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) {
519 my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buf);
520 return true;
521 }
522 push_warning_printf(thd, Sql_condition::SL_WARNING,
523 ER_TRUNCATED_WRONG_VALUE,
524 ER_THD(thd, ER_TRUNCATED_WRONG_VALUE), name, buf);
525 }
526 return false;
527 }
528
charset(THD * thd)529 const CHARSET_INFO *sys_var::charset(THD *thd) {
530 return is_os_charset ? thd->variables.character_set_filesystem
531 : system_charset_info;
532 }
533
534 struct my_old_conv {
535 const char *old_name;
536 const char *new_name;
537 };
538
539 static my_old_conv old_conv[] = {{"cp1251_koi8", "cp1251"},
540 {"cp1250_latin2", "cp1250"},
541 {"kam_latin2", "keybcs2"},
542 {"mac_latin2", "MacRoman"},
543 {"macce_latin2", "MacCE"},
544 {"pc2_latin2", "pclatin2"},
545 {"vga_latin2", "pclatin1"},
546 {"koi8_cp1251", "koi8r"},
547 {"win1251ukr_koi8_ukr", "win1251ukr"},
548 {"koi8_ukr_win1251ukr", "koi8u"},
549 {nullptr, nullptr}};
550
get_old_charset_by_name(const char * name)551 const CHARSET_INFO *get_old_charset_by_name(const char *name) {
552 my_old_conv *conv;
553
554 for (conv = old_conv; conv->old_name; conv++) {
555 if (!my_strcasecmp(&my_charset_latin1, name, conv->old_name))
556 return get_charset_by_csname(conv->new_name, MY_CS_PRIMARY, MYF(0));
557 }
558 return nullptr;
559 }
560
561 /****************************************************************************
562 Main handling of variables:
563 - Initialisation
564 - Searching during parsing
565 - Update loop
566 ****************************************************************************/
567
568 /**
569 Add variables to the dynamic hash of system variables
570
571 @param first Pointer to first system variable to add
572
573 @retval
574 0 SUCCESS
575 @retval
576 otherwise FAILURE
577 */
578
mysql_add_sys_var_chain(sys_var * first)579 int mysql_add_sys_var_chain(sys_var *first) {
580 sys_var *var;
581
582 /* A write lock should be held on LOCK_system_variables_hash */
583
584 for (var = first; var; var = var->next) {
585 /* this fails if there is a conflicting variable name. */
586 if (!system_variable_hash->emplace(to_string(var->name), var).second) {
587 LogErr(ERROR_LEVEL, ER_DUPLICATE_SYS_VAR, var->name.str);
588 goto error;
589 }
590 }
591
592 /* Update system_variable_hash version. */
593 system_variable_hash_version++;
594 return 0;
595
596 error:
597 for (; first != var; first = first->next)
598 system_variable_hash->erase(to_string(var->name));
599 return 1;
600 }
601
602 /*
603 Remove variables to the dynamic hash of system variables
604
605 SYNOPSIS
606 mysql_del_sys_var_chain()
607 first Pointer to first system variable to remove
608
609 RETURN VALUES
610 0 SUCCESS
611 otherwise FAILURE
612 */
613
mysql_del_sys_var_chain(sys_var * first)614 int mysql_del_sys_var_chain(sys_var *first) {
615 int result = 0;
616
617 /* A write lock should be held on LOCK_system_variables_hash */
618
619 for (sys_var *var = first; var; var = var->next)
620 result |= !system_variable_hash->erase(to_string(var->name));
621
622 /* Update system_variable_hash version. */
623 system_variable_hash_version++;
624
625 return result;
626 }
627
628 /*
629 Comparison function for std::sort.
630 @param a SHOW_VAR element
631 @param b SHOW_VAR element
632
633 @retval
634 True if a < b.
635 @retval
636 False if a >= b.
637 */
show_cmp(const void * a,const void * b)638 static int show_cmp(const void *a, const void *b) {
639 return strcmp(static_cast<const SHOW_VAR *>(a)->name,
640 static_cast<const SHOW_VAR *>(b)->name);
641 }
642
643 /*
644 Number of records in the system_variable_hash.
645 Requires lock on LOCK_system_variables_hash.
646 */
get_system_variable_hash_records(void)647 ulong get_system_variable_hash_records(void) {
648 return (system_variable_hash->size());
649 }
650
651 /*
652 Current version of the system_variable_hash.
653 Requires lock on LOCK_system_variables_hash.
654 */
get_system_variable_hash_version(void)655 ulonglong get_system_variable_hash_version(void) {
656 return (system_variable_hash_version);
657 }
658
659 /**
660 Constructs an array of system variables for display to the user.
661
662 @param show_var_array Prealloced_array of SHOW_VAR elements for display
663 @param sort If true, the system variables should be sorted
664 @param query_scope OPT_GLOBAL or OPT_SESSION for SHOW GLOBAL|SESSION
665 VARIABLES
666 @param strict Use strict scope checking
667 @retval True on error, false otherwise
668 */
enumerate_sys_vars(Show_var_array * show_var_array,bool sort,enum enum_var_type query_scope,bool strict)669 bool enumerate_sys_vars(Show_var_array *show_var_array, bool sort,
670 enum enum_var_type query_scope, bool strict) {
671 DBUG_ASSERT(show_var_array != nullptr);
672 DBUG_ASSERT(query_scope == OPT_SESSION || query_scope == OPT_GLOBAL);
673 int count = system_variable_hash->size();
674
675 /* Resize array if necessary. */
676 if (show_var_array->reserve(count + 1)) return true;
677
678 if (show_var_array) {
679 for (const auto &key_and_value : *system_variable_hash) {
680 sys_var *sysvar = key_and_value.second;
681
682 if (strict) {
683 /*
684 Strict scope match (5.7). Success if this is a:
685 - global query and the variable scope is GLOBAL or SESSION, OR
686 - session query and the variable scope is SESSION or ONLY_SESSION.
687 */
688 if (!sysvar->check_scope(query_scope)) continue;
689 } else {
690 /*
691 Non-strict scope match (5.6). Success if this is a:
692 - global query and the variable scope is GLOBAL or SESSION, OR
693 - session query and the variable scope is GLOBAL, SESSION or
694 ONLY_SESSION.
695 */
696 if (query_scope == OPT_GLOBAL && !sysvar->check_scope(query_scope))
697 continue;
698 }
699
700 /* Don't show non-visible variables. */
701 if (sysvar->not_visible()) continue;
702
703 SHOW_VAR show_var;
704 show_var.name = sysvar->name.str;
705 show_var.value = (char *)sysvar;
706 show_var.type = SHOW_SYS;
707 show_var.scope = SHOW_SCOPE_UNDEF; /* not used for sys vars */
708 show_var_array->push_back(show_var);
709 }
710
711 if (sort)
712 std::qsort(show_var_array->begin(), show_var_array->size(),
713 show_var_array->element_size(), show_cmp);
714
715 /* Make last element empty. */
716 show_var_array->push_back(SHOW_VAR());
717 }
718
719 return false;
720 }
721
722 /**
723 Find a user set-table variable.
724
725 @param str Name of system variable to find
726 @param length Length of variable. zero means that we should use strlen()
727 on the variable
728
729 @retval
730 pointer pointer to variable definitions
731 @retval
732 0 Unknown variable (error message is given)
733 */
734
intern_find_sys_var(const char * str,size_t length)735 sys_var *intern_find_sys_var(const char *str, size_t length) {
736 sys_var *var;
737
738 /*
739 This function is only called from the sql_plugin.cc.
740 A lock on LOCK_system_variable_hash should be held
741 */
742 var = find_or_nullptr(*system_variable_hash,
743 string(str, length ? length : strlen(str)));
744
745 /* Don't show non-visible variables. */
746 if (var && var->not_visible()) return nullptr;
747
748 return var;
749 }
750
751 /**
752 Execute update of all variables.
753
754 First run a check of all variables that all updates will go ok.
755 If yes, then execute all updates, returning an error if any one failed.
756
757 This should ensure that in all normal cases none all or variables are
758 updated.
759
760 @param thd Thread id
761 @param var_list List of variables to update
762 @param opened True means tables are open and this function will lock
763 them.
764
765 @retval
766 0 ok
767 @retval
768 1 ERROR, message sent (normally no variables was updated)
769 @retval
770 -1 ERROR, message not sent
771 */
772
sql_set_variables(THD * thd,List<set_var_base> * var_list,bool opened)773 int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool opened) {
774 int error;
775 List_iterator_fast<set_var_base> it(*var_list);
776 DBUG_TRACE;
777
778 LEX *lex = thd->lex;
779 set_var_base *var;
780 while ((var = it++)) {
781 if ((error = var->resolve(thd))) goto err;
782 }
783 if ((error = thd->is_error())) goto err;
784
785 if (opened && lock_tables(thd, lex->query_tables, lex->table_count, 0)) {
786 error = 1;
787 goto err;
788 }
789 it.rewind();
790 while ((var = it++)) {
791 if ((error = var->check(thd))) goto err;
792 }
793 if ((error = thd->is_error())) goto err;
794
795 it.rewind();
796 while ((var = it++)) {
797 if ((error = var->update(thd))) // Returns 0, -1 or 1
798 goto err;
799 }
800 if (!error) {
801 /* At this point SET statement is considered a success. */
802 Persisted_variables_cache *pv = nullptr;
803 it.rewind();
804 while ((var = it++)) {
805 set_var *setvar = dynamic_cast<set_var *>(var);
806 if (setvar &&
807 (setvar->type == OPT_PERSIST || setvar->type == OPT_PERSIST_ONLY)) {
808 pv = Persisted_variables_cache::get_instance();
809 /* update in-memory copy of persistent options */
810 if (pv->set_variable(thd, setvar)) return 1;
811 }
812 }
813 /* flush all persistent options to a file */
814 if (pv && pv->flush_to_file()) {
815 my_error(ER_VARIABLE_NOT_PERSISTED, MYF(0));
816 return 1;
817 }
818 }
819 err:
820 free_underlaid_joins(thd, thd->lex->select_lex);
821 return error;
822 }
823
824 /**
825 This function is used to check if key management UDFs like
826 keying_key_generate/store/remove should proceed or not. If global
827 variable @@keyring_operations is OFF then above said udfs will fail.
828
829 @return Operation status
830 @retval 0 OK
831 @retval 1 ERROR, keyring operations are not allowed
832
833 @sa Sys_keyring_operations
834 */
keyring_access_test()835 bool keyring_access_test() {
836 bool keyring_operations;
837 mysql_mutex_lock(&LOCK_keyring_operations);
838 keyring_operations = !opt_keyring_operations;
839 mysql_mutex_unlock(&LOCK_keyring_operations);
840 return keyring_operations;
841 }
842
843 /*****************************************************************************
844 Functions to handle SET mysql_internal_variable=const_expr
845 *****************************************************************************/
846
set_var(enum_var_type type_arg,sys_var * var_arg,LEX_CSTRING base_name_arg,Item * value_arg)847 set_var::set_var(enum_var_type type_arg, sys_var *var_arg,
848 LEX_CSTRING base_name_arg, Item *value_arg)
849 : var(var_arg), type(type_arg), base(base_name_arg) {
850 /*
851 If the set value is a field, change it to a string to allow things like
852 SET table_type=MYISAM;
853 */
854 if (value_arg && value_arg->type() == Item::FIELD_ITEM) {
855 Item_field *item = (Item_field *)value_arg;
856 if (item->field_name) {
857 if (!(value = new Item_string(item->field_name, strlen(item->field_name),
858 system_charset_info))) // names are utf8
859 value = value_arg; /* Give error message later */
860 } else {
861 /* Both Item_field and Item_insert_value will return the type as
862 Item::FIELD_ITEM. If the item->field_name is NULL, we assume the
863 object to be Item_insert_value. */
864 value = value_arg;
865 }
866 } else
867 value = value_arg;
868 }
869
870 /**
871 global X509 subject name to require from the client session
872 to allow SET PERSIST[_ONLY] on sys_var::NOTPERSIST variables
873
874 @sa set_var::resolve
875 */
876 char *sys_var_persist_only_admin_x509_subject = nullptr;
877
878 /**
879 Checks if a THD can set non-persist variables
880
881 Requires that:
882 * the session uses SSL
883 * the peer has presented a valid certificate
884 * the certificate has a certain subject name
885
886 The format checked is deliberately kept the same as the
887 other SSL system and status variables representing names.
888 Hence X509_NAME_oneline is used.
889
890 @retval true the THD can set NON_PERSIST variables
891 @retval false usual restrictions apply
892 @param thd the THD handle
893 @param var the variable to be set
894 @param setvar_type the operation to check against.
895
896 @sa sys_variables_admin_dn
897 */
can_persist_non_persistent_var(THD * thd,sys_var * var,enum_var_type setvar_type)898 static bool can_persist_non_persistent_var(THD *thd, sys_var *var,
899 enum_var_type setvar_type) {
900 SSL *ssl = nullptr;
901 X509 *cert = nullptr;
902 char *ptr = nullptr;
903 bool result = false;
904
905 /* Bail off if no subject is set */
906 if (likely(!sys_var_persist_only_admin_x509_subject ||
907 !sys_var_persist_only_admin_x509_subject[0]))
908 return false;
909
910 /* Can't persist read only variables without command line support */
911 if (unlikely(setvar_type == OPT_PERSIST_ONLY &&
912 !var->is_settable_at_command_line() &&
913 (var->is_readonly() || var->is_persist_readonly())))
914 return false;
915
916 /* do not allow setting the controlling variables */
917 if (never_persistable_vars->find(var->name.str) !=
918 never_persistable_vars->end())
919 return false;
920
921 ssl = thd->get_ssl();
922 if (!ssl) return false;
923
924 cert = SSL_get_peer_certificate(ssl);
925 if (!cert) goto done;
926
927 ptr = X509_NAME_oneline(X509_get_subject_name(cert), nullptr, 0);
928 if (!ptr) goto done;
929
930 result = !strcmp(sys_var_persist_only_admin_x509_subject, ptr);
931 done:
932 if (ptr) OPENSSL_free(ptr);
933 if (cert) X509_free(cert);
934 return result;
935 }
936
937 /**
938 Resolve the variable assignment
939
940 @param thd Thread handler
941
942 @return status code
943 @retval -1 Failure
944 @retval 0 Success
945 */
946
resolve(THD * thd)947 int set_var::resolve(THD *thd) {
948 DBUG_TRACE;
949 var->do_deprecated_warning(thd);
950 if (var->is_readonly()) {
951 if (type != OPT_PERSIST_ONLY) {
952 my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), var->name.str,
953 "read only");
954 return -1;
955 }
956 if (type == OPT_PERSIST_ONLY && var->is_non_persistent() &&
957 !can_persist_non_persistent_var(thd, var, type)) {
958 my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), var->name.str,
959 "non persistent read only");
960 return -1;
961 }
962 }
963 if (!var->check_scope(type)) {
964 int err = (is_global_persist()) ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE;
965 my_error(err, MYF(0), var->name.str);
966 return -1;
967 }
968 if (type == OPT_GLOBAL || type == OPT_PERSIST) {
969 /* Either the user has SUPER_ACL or she has SYSTEM_VARIABLES_ADMIN */
970 if (check_priv(thd, false)) return 1;
971 }
972 if (type == OPT_PERSIST_ONLY) {
973 if (check_priv(thd, true)) return 1;
974 }
975
976 /* check if read/write non-persistent variables can be persisted */
977 if ((type == OPT_PERSIST || type == OPT_PERSIST_ONLY) &&
978 var->is_non_persistent() &&
979 !can_persist_non_persistent_var(thd, var, type)) {
980 my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), var->name.str,
981 "non persistent");
982 return -1;
983 }
984
985 /* value is a NULL pointer if we are using SET ... = DEFAULT */
986 if (!value) return 0;
987
988 if ((!value->fixed && value->fix_fields(thd, &value)) || value->check_cols(1))
989 return -1;
990
991 return 0;
992 }
993
994 /**
995 Verify that the supplied value is correct.
996
997 @param thd Thread handler
998
999 @return status code
1000 @retval -1 Failure
1001 @retval 0 Success
1002 */
1003
check(THD * thd)1004 int set_var::check(THD *thd) {
1005 DBUG_TRACE;
1006
1007 /* value is a NULL pointer if we are using SET ... = DEFAULT */
1008 if (!value) return 0;
1009
1010 if (var->check_update_type(value->result_type())) {
1011 my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), var->name.str);
1012 return -1;
1013 }
1014 int ret = (type != OPT_PERSIST_ONLY && var->check(thd, this)) ? -1 : 0;
1015
1016 if (!ret && (is_global_persist())) {
1017 ret = mysql_audit_notify(thd, AUDIT_EVENT(MYSQL_AUDIT_GLOBAL_VARIABLE_SET),
1018 var->name.str, value->item_name.ptr(),
1019 value->item_name.length());
1020 }
1021
1022 return ret;
1023 }
1024
1025 /**
1026 Check variable, but without assigning value (used by PS).
1027
1028 @param thd thread handler
1029
1030 @retval
1031 0 ok
1032 @retval
1033 1 ERROR, message sent (normally no variables was updated)
1034 @retval
1035 -1 ERROR, message not sent
1036 */
light_check(THD * thd)1037 int set_var::light_check(THD *thd) {
1038 if (!var->check_scope(type)) {
1039 int err = (is_global_persist()) ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE;
1040 my_error(err, MYF(0), var->name.str);
1041 return -1;
1042 }
1043 Security_context *sctx = thd->security_context();
1044 if ((type == OPT_GLOBAL || type == OPT_PERSIST) &&
1045 !(sctx->check_access(SUPER_ACL) ||
1046 sctx->has_global_grant(STRING_WITH_LEN("SYSTEM_VARIABLES_ADMIN"))
1047 .first))
1048 return 1;
1049
1050 if ((type == OPT_PERSIST_ONLY) &&
1051 !(sctx->has_global_grant(STRING_WITH_LEN("PERSIST_RO_VARIABLES_ADMIN"))
1052 .first &&
1053 sctx->has_global_grant(STRING_WITH_LEN("SYSTEM_VARIABLES_ADMIN"))
1054 .first))
1055 return 1;
1056
1057 if (value && ((!value->fixed && value->fix_fields(thd, &value)) ||
1058 value->check_cols(1)))
1059 return -1;
1060 return 0;
1061 }
1062
1063 /**
1064 Update variable source, user, host and timestamp values.
1065 */
1066
update_source_user_host_timestamp(THD * thd)1067 void set_var::update_source_user_host_timestamp(THD *thd) {
1068 var->set_source(enum_variable_source::DYNAMIC);
1069 var->set_source_name(EMPTY_CSTR.str);
1070 var->set_user_host(thd);
1071 var->set_timestamp();
1072 }
1073
1074 /**
1075 Update variable
1076
1077 @param thd thread handler
1078 @returns 0|1 ok or ERROR
1079
1080 @note ERROR can be only due to abnormal operations involving
1081 the server's execution evironment such as
1082 out of memory, hard disk failure or the computer blows up.
1083 Consider set_var::check() method if there is a need to return
1084 an error due to logics.
1085 */
update(THD * thd)1086 int set_var::update(THD *thd) {
1087 int ret = 0;
1088 /* for persist only syntax do not update the value */
1089 if (type != OPT_PERSIST_ONLY) {
1090 if (value)
1091 ret = (int)var->update(thd, this);
1092 else
1093 ret = (int)var->set_default(thd, this);
1094 }
1095 /*
1096 For PERSIST_ONLY syntax we dont change the value of the variable
1097 for the current session, thus we should not change variables
1098 source/timestamp/user/host.
1099 */
1100 if (ret == 0 && type != OPT_PERSIST_ONLY) {
1101 update_source_user_host_timestamp(thd);
1102 }
1103 return ret;
1104 }
1105
print_short(const THD * thd,String * str)1106 void set_var::print_short(const THD *thd, String *str) {
1107 str->append(var->name.str, var->name.length);
1108 str->append(STRING_WITH_LEN("="));
1109 if (value)
1110 value->print(thd, str, QT_ORDINARY);
1111 else
1112 str->append(STRING_WITH_LEN("DEFAULT"));
1113 }
1114
1115 /**
1116 Self-print assignment
1117
1118 @param thd Thread handle
1119 @param str String buffer to append the partial assignment to.
1120 */
print(const THD * thd,String * str)1121 void set_var::print(const THD *thd, String *str) {
1122 switch (type) {
1123 case OPT_PERSIST:
1124 str->append("PERSIST ");
1125 break;
1126 case OPT_PERSIST_ONLY:
1127 str->append("PERSIST_ONLY ");
1128 break;
1129 case OPT_GLOBAL:
1130 str->append("GLOBAL ");
1131 break;
1132 default:
1133 str->append("SESSION ");
1134 }
1135 if (base.length) {
1136 str->append(base.str, base.length);
1137 str->append(STRING_WITH_LEN("."));
1138 }
1139 print_short(thd, str);
1140 }
1141
1142 /*****************************************************************************
1143 Functions to handle SET @user_variable=const_expr
1144 *****************************************************************************/
1145
resolve(THD * thd)1146 int set_var_user::resolve(THD *thd) {
1147 /*
1148 Item_func_set_user_var can't substitute something else on its place =>
1149 0 can be passed as last argument (reference on item)
1150 */
1151 return user_var_item->fix_fields(thd, nullptr) ? -1 : 0;
1152 }
1153
check(THD *)1154 int set_var_user::check(THD *) {
1155 /*
1156 Item_func_set_user_var can't substitute something else on its place =>
1157 0 can be passed as last argument (reference on item)
1158 */
1159 return user_var_item->check(false) ? -1 : 0;
1160 }
1161
1162 /**
1163 Check variable, but without assigning value (used by PS).
1164
1165 @param thd thread handler
1166
1167 @retval
1168 0 ok
1169 @retval
1170 1 ERROR, message sent (normally no variables was updated)
1171 @retval
1172 -1 ERROR, message not sent
1173 */
light_check(THD * thd)1174 int set_var_user::light_check(THD *thd) {
1175 /*
1176 Item_func_set_user_var can't substitute something else on its place =>
1177 0 can be passed as last argument (reference on item)
1178 */
1179 return (user_var_item->fix_fields(thd, (Item **)nullptr));
1180 }
1181
update(THD * thd)1182 int set_var_user::update(THD *thd) {
1183 if (user_var_item->update()) {
1184 /* Give an error if it's not given already */
1185 my_error(ER_SET_CONSTANTS_ONLY, MYF(0));
1186 return -1;
1187 }
1188 if (thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)
1189 ->is_enabled())
1190 thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)
1191 ->mark_as_changed(thd, nullptr);
1192 return 0;
1193 }
1194
print(const THD * thd,String * str)1195 void set_var_user::print(const THD *thd, String *str) {
1196 user_var_item->print_assignment(thd, str, QT_ORDINARY);
1197 }
1198
1199 /*****************************************************************************
1200 Functions to handle SET PASSWORD
1201 *****************************************************************************/
1202
set_var_password(LEX_USER * user_arg,char * password_arg,char * current_password_arg,bool retain_current,bool gen_pass)1203 set_var_password::set_var_password(LEX_USER *user_arg, char *password_arg,
1204 char *current_password_arg,
1205 bool retain_current, bool gen_pass)
1206 : user(user_arg),
1207 password(password_arg),
1208 current_password(current_password_arg),
1209 retain_current_password(retain_current),
1210 generate_password(gen_pass) {
1211 if (current_password != nullptr) {
1212 user_arg->uses_replace_clause = true;
1213 user_arg->current_auth.str = current_password_arg;
1214 user_arg->current_auth.length = strlen(current_password_arg);
1215 }
1216 user_arg->retain_current_password = retain_current_password;
1217 }
1218
~set_var_password()1219 set_var_password::~set_var_password() {
1220 // We copied the generated password buffer to circumvent
1221 // the password nullification code in change_password()
1222 if (generate_password) my_free(password);
1223 }
1224
1225 /**
1226 Check the validity of the SET PASSWORD request
1227
1228 @param thd The current thread
1229 @return status code
1230 @retval 0 failure
1231 @retval 1 success
1232 */
check(THD * thd)1233 int set_var_password::check(THD *thd) {
1234 /* Returns 1 as the function sends error to client */
1235 return check_change_password(thd, user->host.str, user->user.str,
1236 retain_current_password)
1237 ? 1
1238 : 0;
1239 }
1240
update(THD * thd)1241 int set_var_password::update(THD *thd) {
1242 if (generate_password) {
1243 thd->m_disable_password_validation = true;
1244 std::string generated_password;
1245 generate_random_password(&generated_password,
1246 thd->variables.generated_random_password_length);
1247 /*
1248 We need to copy the password buffer here because it will be set to \0
1249 later by change_password() and since we're generated a random password
1250 we need to retain it until it can be sent to the client.
1251 Because set_var_password never will get its destructor called we also
1252 need to move the string allocated memory to the THD mem root.
1253 */
1254 password = thd->mem_strdup(generated_password.c_str());
1255 str_generated_password = thd->mem_strdup(generated_password.c_str());
1256 }
1257 /* Returns 1 as the function sends error to client */
1258 auto res = change_password(thd, user, password, current_password,
1259 retain_current_password)
1260 ? 1
1261 : 0;
1262 return res;
1263 }
1264
print(const THD * thd,String * str)1265 void set_var_password::print(const THD *thd, String *str) {
1266 if (user->user.str != nullptr && user->user.length > 0) {
1267 str->append(STRING_WITH_LEN("PASSWORD FOR "));
1268 append_identifier(thd, str, user->user.str, user->user.length);
1269 if (user->host.str != nullptr && user->host.length > 0) {
1270 str->append(STRING_WITH_LEN("@"));
1271 append_identifier(thd, str, user->host.str, user->host.length);
1272 }
1273 str->append(STRING_WITH_LEN("="));
1274 } else
1275 str->append(STRING_WITH_LEN("PASSWORD FOR CURRENT_USER()="));
1276 str->append(STRING_WITH_LEN("<secret>"));
1277 if (user->uses_replace_clause) {
1278 str->append(STRING_WITH_LEN(" REPLACE <secret>"));
1279 }
1280 if (user->retain_current_password) {
1281 str->append(STRING_WITH_LEN(" RETAIN CURRENT PASSWORD"));
1282 }
1283 }
1284
1285 /*****************************************************************************
1286 Functions to handle SET NAMES and SET CHARACTER SET
1287 *****************************************************************************/
1288
check(THD *)1289 int set_var_collation_client::check(THD *) {
1290 /* Currently, UCS-2 cannot be used as a client character set */
1291 if (!is_supported_parser_charset(character_set_client)) {
1292 my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
1293 character_set_client->csname);
1294 return 1;
1295 }
1296 return 0;
1297 }
1298
update(THD * thd)1299 int set_var_collation_client::update(THD *thd) {
1300 thd->variables.character_set_client = character_set_client;
1301 thd->variables.character_set_results = character_set_results;
1302 thd->variables.collation_connection = collation_connection;
1303 thd->update_charset();
1304
1305 /* Mark client collation variables as changed */
1306 if (thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->is_enabled()) {
1307 LEX_CSTRING cs_client = {"character_set_client",
1308 sizeof("character_set_client") - 1};
1309 thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)
1310 ->mark_as_changed(thd, &cs_client);
1311 LEX_CSTRING cs_results = {"character_set_results",
1312 sizeof("character_set_results") - 1};
1313 thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)
1314 ->mark_as_changed(thd, &cs_results);
1315 LEX_CSTRING cs_connection = {"character_set_connection",
1316 sizeof("character_set_connection") - 1};
1317 thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)
1318 ->mark_as_changed(thd, &cs_connection);
1319 }
1320 if (thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)
1321 ->is_enabled())
1322 thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)
1323 ->mark_as_changed(thd, nullptr);
1324 thd->protocol_text->init(thd);
1325 thd->protocol_binary->init(thd);
1326 return 0;
1327 }
1328
print(const THD *,String * str)1329 void set_var_collation_client::print(const THD *, String *str) {
1330 str->append((set_cs_flags & SET_CS_NAMES) ? "NAMES " : "CHARACTER SET ");
1331 if (set_cs_flags & SET_CS_DEFAULT)
1332 str->append("DEFAULT");
1333 else {
1334 str->append("'");
1335 str->append(character_set_client->csname);
1336 str->append("'");
1337 if (set_cs_flags & SET_CS_COLLATE) {
1338 str->append(" COLLATE '");
1339 str->append(collation_connection->name);
1340 str->append("'");
1341 }
1342 }
1343 }
1344