1 /* Copyright (c) 2002, 2021, Oracle and/or its affiliates.
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 /* variable declarations are in sys_vars.cc now !!! */
24
25 #include "debug_sync.h"
26 #include "set_var.h"
27
28 #include "hash.h" // HASH
29 #include "auth_common.h" // SUPER_ACL
30 #include "log.h" // sql_print_warning
31 #include "mysqld.h" // system_charset_info
32 #include "sql_class.h" // THD
33 #include "sql_parse.h" // is_supported_parser_charset
34 #include "sql_select.h" // free_underlaid_joins
35 #include "sql_show.h" // append_identifier
36 #include "sys_vars_shared.h" // PolyLock_mutex
37 #include "sql_audit.h" // mysql_audit
38
39 static HASH system_variable_hash;
40 static PolyLock_mutex PLock_global_system_variables(&LOCK_global_system_variables);
41 ulonglong system_variable_hash_version= 0;
42
43 /**
44 Return variable name and length for hashing of variables.
45 */
46
get_sys_var_length(const sys_var * var,size_t * length,my_bool first)47 static uchar *get_sys_var_length(const sys_var *var, size_t *length,
48 my_bool first)
49 {
50 *length= var->name.length;
51 return (uchar*) var->name.str;
52 }
53
54 sys_var_chain all_sys_vars = { NULL, NULL };
55
sys_var_init()56 int sys_var_init()
57 {
58 DBUG_ENTER("sys_var_init");
59
60 /* Must be already initialized. */
61 assert(system_charset_info != NULL);
62
63 if (my_hash_init(&system_variable_hash, system_charset_info, 100, 0,
64 0, (my_hash_get_key) get_sys_var_length, 0, HASH_UNIQUE,
65 PSI_INSTRUMENT_ME))
66 goto error;
67
68 if (mysql_add_sys_var_chain(all_sys_vars.first))
69 goto error;
70
71 DBUG_RETURN(0);
72
73 error:
74 my_message_local(ERROR_LEVEL, "failed to initialize system variables");
75 DBUG_RETURN(1);
76 }
77
sys_var_add_options(std::vector<my_option> * long_options,int parse_flags)78 int sys_var_add_options(std::vector<my_option> *long_options, int parse_flags)
79 {
80 DBUG_ENTER("sys_var_add_options");
81
82 for (sys_var *var=all_sys_vars.first; var; var= var->next)
83 {
84 if (var->register_option(long_options, parse_flags))
85 goto error;
86 }
87
88 DBUG_RETURN(0);
89
90 error:
91 my_message_local(ERROR_LEVEL, "failed to initialize system variables");
92 DBUG_RETURN(1);
93 }
94
sys_var_end()95 void sys_var_end()
96 {
97 DBUG_ENTER("sys_var_end");
98
99 my_hash_free(&system_variable_hash);
100
101 for (sys_var *var=all_sys_vars.first; var; var= var->next)
102 var->cleanup();
103
104 DBUG_VOID_RETURN;
105 }
106
107 /**
108 sys_var constructor
109
110 @param chain variables are linked into chain for mysql_add_sys_var_chain()
111 @param name_arg the name of the variable. Must be 0-terminated and exist
112 for the liftime of the sys_var object. @sa my_option::name
113 @param comment shown in mysqld --help, @sa my_option::comment
114 @param flags_arg or'ed flag_enum values
115 @param off offset of the global variable value from the
116 &global_system_variables.
117 @param getopt_id -1 for no command-line option, otherwise @sa my_option::id
118 @param getopt_arg_type @sa my_option::arg_type
119 @param show_val_type_arg what value_ptr() returns for sql_show.cc
120 @param def_val default value, @sa my_option::def_value
121 @param lock mutex or rw_lock that protects the global variable
122 *in addition* to LOCK_global_system_variables.
123 @param binlog_status_enum @sa binlog_status_enum
124 @param on_check_func a function to be called at the end of sys_var::check,
125 put your additional checks here
126 @param on_update_func a function to be called at the end of sys_var::update,
127 any post-update activity should happen here
128 @param substitute If non-NULL, this variable is deprecated and the
129 string describes what one should use instead. If an empty string,
130 the variable is deprecated but no replacement is offered.
131 @param parse_flag either PARSE_EARLY or PARSE_NORMAL
132 */
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)133 sys_var::sys_var(sys_var_chain *chain, const char *name_arg,
134 const char *comment, int flags_arg, ptrdiff_t off,
135 int getopt_id, enum get_opt_arg_type getopt_arg_type,
136 SHOW_TYPE show_val_type_arg, longlong def_val,
137 PolyLock *lock, enum binlog_status_enum binlog_status_arg,
138 on_check_function on_check_func,
139 on_update_function on_update_func,
140 const char *substitute, int parse_flag) :
141 next(0),
142 binlog_status(binlog_status_arg),
143 flags(flags_arg), m_parse_flag(parse_flag), show_val_type(show_val_type_arg),
144 guard(lock), offset(off), on_check(on_check_func),
145 pre_update(0), on_update(on_update_func),
146 deprecation_substitute(substitute),
147 is_os_charset(FALSE)
148 {
149 /*
150 There is a limitation in handle_options() related to short options:
151 - either all short options should be declared when parsing in multiple stages,
152 - or none should be declared.
153 Because a lot of short options are used in the normal parsing phase
154 for mysqld, we enforce here that no short option is present
155 in the first (PARSE_EARLY) stage.
156 See handle_options() for details.
157 */
158 assert(parse_flag == PARSE_NORMAL || getopt_id <= 0 || getopt_id >= 255);
159
160 name.str= name_arg; // ER_NO_DEFAULT relies on 0-termination of name_arg
161 name.length= strlen(name_arg); // and so does this.
162 assert(name.length <= NAME_CHAR_LEN);
163
164 memset(&option, 0, sizeof(option));
165 option.name= name_arg;
166 option.id= getopt_id;
167 option.comment= comment;
168 option.arg_type= getopt_arg_type;
169 option.value= (uchar **)global_var_ptr();
170 option.def_value= def_val;
171
172 if (chain->last)
173 chain->last->next= this;
174 else
175 chain->first= this;
176 chain->last= this;
177 }
178
update(THD * thd,set_var * var)179 bool sys_var::update(THD *thd, set_var *var)
180 {
181 /*
182 Invoke preparatory step for updating a system variable. Doing this action
183 before we have acquired any locks allows to invoke code which acquires other
184 locks without introducing deadlocks.
185 */
186 if (pre_update && pre_update(this, thd, var))
187 return true;
188
189 enum_var_type type= var->type;
190 if (type == OPT_GLOBAL || scope() == GLOBAL)
191 {
192 /*
193 Yes, both locks need to be taken before an update, just as
194 both are taken to get a value. If we'll take only 'guard' here,
195 then value_ptr() for strings won't be safe in SHOW VARIABLES anymore,
196 to make it safe we'll need value_ptr_unlock().
197 */
198 AutoWLock lock1(&PLock_global_system_variables);
199 AutoWLock lock2(guard);
200 return global_update(thd, var) ||
201 (on_update && on_update(this, thd, OPT_GLOBAL));
202 }
203 else
204 {
205 bool locked= false;
206 if (!show_compatibility_56)
207 {
208 /* Block reads from other threads. */
209 mysql_mutex_lock(&thd->LOCK_thd_sysvar);
210 locked= true;
211 }
212
213 bool ret= session_update(thd, var) ||
214 (on_update && on_update(this, thd, OPT_SESSION));
215
216 if (locked)
217 mysql_mutex_unlock(&thd->LOCK_thd_sysvar);
218
219 /*
220 Make sure we don't session-track variables that are not actually
221 part of the session. tx_isolation and and tx_read_only for example
222 exist as GLOBAL, SESSION, and one-shot ("for next transaction only").
223 */
224 if ((var->type == OPT_SESSION) || !is_trilevel())
225 {
226 if ((!ret) &&
227 thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->is_enabled())
228 thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->mark_as_changed(thd, &(var->var->name));
229
230 if ((!ret) &&
231 thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->is_enabled())
232 thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->mark_as_changed(thd, &var->var->name);
233 }
234
235 return ret;
236 }
237 }
238
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)239 uchar *sys_var::session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
240 {
241 return session_var_ptr(target_thd);
242 }
243
global_value_ptr(THD * thd,LEX_STRING * base)244 uchar *sys_var::global_value_ptr(THD *thd, LEX_STRING *base)
245 {
246 return global_var_ptr();
247 }
248
session_var_ptr(THD * thd)249 uchar *sys_var::session_var_ptr(THD *thd)
250 { return ((uchar*)&(thd->variables)) + offset; }
251
global_var_ptr()252 uchar *sys_var::global_var_ptr()
253 { return ((uchar*)&global_system_variables) + offset; }
254
255
check(THD * thd,set_var * var)256 bool sys_var::check(THD *thd, set_var *var)
257 {
258 if ((var->value && do_check(thd, var))
259 || (on_check && on_check(this, thd, var)))
260 {
261 if (!thd->is_error())
262 {
263 char buff[STRING_BUFFER_USUAL_SIZE];
264 String str(buff, sizeof(buff), system_charset_info), *res;
265
266 if (!var->value)
267 {
268 str.set(STRING_WITH_LEN("DEFAULT"), &my_charset_latin1);
269 res= &str;
270 }
271 else if (!(res=var->value->val_str(&str)))
272 {
273 str.set(STRING_WITH_LEN("NULL"), &my_charset_latin1);
274 res= &str;
275 }
276 ErrConvString err(res);
277 my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
278 }
279 return true;
280 }
281 return false;
282 }
283
value_ptr(THD * running_thd,THD * target_thd,enum_var_type type,LEX_STRING * base)284 uchar *sys_var::value_ptr(THD *running_thd, THD *target_thd, enum_var_type type, LEX_STRING *base)
285 {
286 if (type == OPT_GLOBAL || scope() == GLOBAL)
287 {
288 mysql_mutex_assert_owner(&LOCK_global_system_variables);
289 AutoRLock lock(guard);
290 return global_value_ptr(running_thd, base);
291 }
292 else
293 return session_value_ptr(running_thd, target_thd, base);
294 }
295
value_ptr(THD * thd,enum_var_type type,LEX_STRING * base)296 uchar *sys_var::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
297 {
298 return value_ptr(thd, thd, type, base);
299 }
300
set_default(THD * thd,set_var * var)301 bool sys_var::set_default(THD *thd, set_var* var)
302 {
303 DBUG_ENTER("sys_var::set_default");
304 if (var->type == OPT_GLOBAL || scope() == GLOBAL)
305 global_save_default(thd, var);
306 else
307 session_save_default(thd, var);
308
309 bool ret= check(thd, var) || update(thd, var);
310 DBUG_RETURN(ret);
311 }
312
Sys_var_tracker(sys_var * var)313 Sys_var_tracker::Sys_var_tracker(sys_var *var)
314 {
315 m_is_dynamic = (var->cast_pluginvar() != NULL);
316 m_name = (m_is_dynamic ? current_thd->strmake(var->name) : var->name);
317 m_var = (m_is_dynamic ? NULL : var);
318 }
319
bind_system_variable(THD * thd)320 sys_var *Sys_var_tracker::bind_system_variable(THD *thd) {
321 if (!m_is_dynamic || // (1)
322 (m_var != NULL && // (2)
323 thd->state == Query_arena::STMT_INITIALIZED_FOR_SP)) // (3)
324 {
325 /*
326 Return a previous cached value of a system variable:
327
328 - if this is a static variable (1) then always return its cached value.
329
330 - if SP body evaluation is in the process (3), and if this is not
331 a resolver phase (2): the resolver phase caches the value and the
332 executor phase reuses it; this can work since SQL statements
333 referencing SP calls don't release plugins acquired by those SP
334 calls until the SPs removed from the server memory.
335 */
336 return m_var;
337 }
338
339 m_var= find_sys_var(thd, m_name.str, m_name.length);
340 if (m_var == NULL)
341 {
342 my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), m_name.str);
343 return NULL;
344 }
345
346 return m_var;
347 }
348
do_deprecated_warning(THD * thd)349 void sys_var::do_deprecated_warning(THD *thd)
350 {
351 if (deprecation_substitute != NULL)
352 {
353 char buf1[NAME_CHAR_LEN + 3];
354 strxnmov(buf1, sizeof(buf1)-1, "@@", name.str, 0);
355
356 /*
357 if deprecation_substitute is an empty string,
358 there is no replacement for the syntax
359 */
360 uint errmsg= deprecation_substitute[0] == '\0'
361 ? ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT
362 : ER_WARN_DEPRECATED_SYNTAX;
363 if (thd)
364 push_warning_printf(thd, Sql_condition::SL_WARNING,
365 ER_WARN_DEPRECATED_SYNTAX, ER(errmsg),
366 buf1, deprecation_substitute);
367 else
368 sql_print_warning(ER_DEFAULT(errmsg), buf1, deprecation_substitute);
369 }
370 }
371
372 /**
373 Throw warning (error in STRICT mode) if value for variable needed bounding.
374 Plug-in interface also uses this.
375
376 @param thd thread handle
377 @param name variable's name
378 @param fixed did we have to correct the value? (throw warn/err if so)
379 @param is_unsigned is value's type unsigned?
380 @param v variable's value
381
382 @retval true on error, false otherwise (warning or ok)
383 */
throw_bounds_warning(THD * thd,const char * name,bool fixed,bool is_unsigned,longlong v)384 bool throw_bounds_warning(THD *thd, const char *name,
385 bool fixed, bool is_unsigned, longlong v)
386 {
387 if (fixed)
388 {
389 char buf[22];
390
391 if (is_unsigned)
392 ullstr((ulonglong) v, buf);
393 else
394 llstr(v, buf);
395
396 if (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES)
397 {
398 my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buf);
399 return true;
400 }
401 push_warning_printf(thd, Sql_condition::SL_WARNING,
402 ER_TRUNCATED_WRONG_VALUE,
403 ER(ER_TRUNCATED_WRONG_VALUE), name, buf);
404 }
405 return false;
406 }
407
throw_bounds_warning(THD * thd,const char * name,bool fixed,double v)408 bool throw_bounds_warning(THD *thd, const char *name, bool fixed, double v)
409 {
410 if (fixed)
411 {
412 char buf[64];
413
414 my_gcvt(v, MY_GCVT_ARG_DOUBLE, static_cast<int>(sizeof(buf)) - 1, buf, NULL);
415
416 if (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES)
417 {
418 my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buf);
419 return true;
420 }
421 push_warning_printf(thd, Sql_condition::SL_WARNING,
422 ER_TRUNCATED_WRONG_VALUE,
423 ER(ER_TRUNCATED_WRONG_VALUE), name, buf);
424 }
425 return false;
426 }
427
charset(THD * thd)428 const CHARSET_INFO *sys_var::charset(THD *thd)
429 {
430 return is_os_charset ? thd->variables.character_set_filesystem :
431 system_charset_info;
432 }
433
434 typedef struct old_names_map_st
435 {
436 const char *old_name;
437 const char *new_name;
438 } my_old_conv;
439
440 static my_old_conv old_conv[]=
441 {
442 { "cp1251_koi8" , "cp1251" },
443 { "cp1250_latin2" , "cp1250" },
444 { "kam_latin2" , "keybcs2" },
445 { "mac_latin2" , "MacRoman" },
446 { "macce_latin2" , "MacCE" },
447 { "pc2_latin2" , "pclatin2" },
448 { "vga_latin2" , "pclatin1" },
449 { "koi8_cp1251" , "koi8r" },
450 { "win1251ukr_koi8_ukr" , "win1251ukr" },
451 { "koi8_ukr_win1251ukr" , "koi8u" },
452 { NULL , NULL }
453 };
454
get_old_charset_by_name(const char * name)455 const CHARSET_INFO *get_old_charset_by_name(const char *name)
456 {
457 my_old_conv *conv;
458
459 for (conv= old_conv; conv->old_name; conv++)
460 {
461 if (!my_strcasecmp(&my_charset_latin1, name, conv->old_name))
462 return get_charset_by_csname(conv->new_name, MY_CS_PRIMARY, MYF(0));
463 }
464 return NULL;
465 }
466
467 /****************************************************************************
468 Main handling of variables:
469 - Initialisation
470 - Searching during parsing
471 - Update loop
472 ****************************************************************************/
473
474 /**
475 Add variables to the dynamic hash of system variables
476
477 @param first Pointer to first system variable to add
478
479 @retval
480 0 SUCCESS
481 @retval
482 otherwise FAILURE
483 */
484
485
mysql_add_sys_var_chain(sys_var * first)486 int mysql_add_sys_var_chain(sys_var *first)
487 {
488 sys_var *var;
489
490 /* A write lock should be held on LOCK_system_variables_hash */
491
492 for (var= first; var; var= var->next)
493 {
494 /* this fails if there is a conflicting variable name. see HASH_UNIQUE */
495 if (my_hash_insert(&system_variable_hash, (uchar*) var))
496 {
497 my_message_local(ERROR_LEVEL, "duplicate variable name '%s'!?",
498 var->name.str);
499 goto error;
500 }
501 }
502
503 /* Update system_variable_hash version. */
504 system_variable_hash_version++;
505 return 0;
506
507 error:
508 for (; first != var; first= first->next)
509 my_hash_delete(&system_variable_hash, (uchar*) first);
510 return 1;
511 }
512
513
514 /*
515 Remove variables to the dynamic hash of system variables
516
517 SYNOPSIS
518 mysql_del_sys_var_chain()
519 first Pointer to first system variable to remove
520
521 RETURN VALUES
522 0 SUCCESS
523 otherwise FAILURE
524 */
525
mysql_del_sys_var_chain(sys_var * first)526 int mysql_del_sys_var_chain(sys_var *first)
527 {
528 int result= 0;
529
530 /* A write lock should be held on LOCK_system_variables_hash */
531
532 for (sys_var *var= first; var; var= var->next)
533 result|= my_hash_delete(&system_variable_hash, (uchar*) var);
534
535 /* Update system_variable_hash version. */
536 system_variable_hash_version++;
537
538 return result;
539 }
540
541 /*
542 Comparison function for std::sort.
543 @param a SHOW_VAR element
544 @param b SHOW_VAR element
545
546 @retval
547 True if a < b.
548 @retval
549 False if a >= b.
550 */
show_cmp(const void * a,const void * b)551 static int show_cmp(const void *a, const void *b)
552 {
553 return strcmp(((SHOW_VAR *)a)->name, ((SHOW_VAR *)b)->name);
554 }
555
556 /*
557 Number of records in the system_variable_hash.
558 Requires lock on LOCK_system_variables_hash.
559 */
get_system_variable_hash_records(void)560 ulong get_system_variable_hash_records(void)
561 {
562 return (system_variable_hash.records);
563 }
564
565 /*
566 Current version of the system_variable_hash.
567 Requires lock on LOCK_system_variables_hash.
568 */
get_system_variable_hash_version(void)569 ulonglong get_system_variable_hash_version(void)
570 {
571 return (system_variable_hash_version);
572 }
573
574 /**
575 Constructs an array of system variables for display to the user.
576
577 @param thd Current thread
578 @param show_var_array Prealloced_array of SHOW_VAR elements for display
579 @param sort If TRUE, the system variables should be sorted
580 @param query_scope OPT_GLOBAL or OPT_SESSION for SHOW GLOBAL|SESSION VARIABLES
581 @param strict Use strict scope checking
582 @retval True on error, false otherwise
583 */
enumerate_sys_vars(THD * thd,Show_var_array * show_var_array,bool sort,enum enum_var_type query_scope,bool strict)584 bool enumerate_sys_vars(THD *thd, Show_var_array *show_var_array,
585 bool sort,
586 enum enum_var_type query_scope,
587 bool strict)
588 {
589 assert(show_var_array != NULL);
590 assert(query_scope == OPT_SESSION || query_scope == OPT_GLOBAL);
591 int count= system_variable_hash.records;
592
593 /* Resize array if necessary. */
594 if (show_var_array->reserve(count+1))
595 return true;
596
597 if (show_var_array)
598 {
599 for (int i= 0; i < count; i++)
600 {
601 sys_var *sysvar= (sys_var*) my_hash_element(&system_variable_hash, i);
602
603 const my_bool *hidden=
604 getopt_constraint_get_hidden_value(sysvar->name.str,
605 sysvar->name.length, FALSE);
606
607 if (hidden && *hidden)
608 continue;
609
610 if (strict)
611 {
612 /*
613 Strict scope match (5.7). Success if this is a:
614 - global query and the variable scope is GLOBAL or SESSION, OR
615 - session query and the variable scope is SESSION or ONLY_SESSION.
616 */
617 if (!sysvar->check_scope(query_scope))
618 continue;
619 }
620 else
621 {
622 /*
623 Non-strict scope match (5.6). Success if this is a:
624 - global query and the variable scope is GLOBAL or SESSION, OR
625 - session query and the variable scope is GLOBAL, SESSION or ONLY_SESSION.
626 */
627 if (query_scope == OPT_GLOBAL && !sysvar->check_scope(query_scope))
628 continue;
629 }
630
631 /* Don't show non-visible variables. */
632 if (sysvar->not_visible())
633 continue;
634
635 SHOW_VAR show_var;
636 show_var.name= sysvar->name.str;
637 show_var.value= (char*)sysvar;
638 show_var.type= SHOW_SYS;
639 show_var.scope= SHOW_SCOPE_UNDEF; /* not used for sys vars */
640 show_var_array->push_back(show_var);
641 }
642
643 if (sort)
644 std::qsort(show_var_array->begin(), show_var_array->size(),
645 show_var_array->element_size(), show_cmp);
646
647 /* Make last element empty. */
648 show_var_array->push_back(st_mysql_show_var());
649 }
650
651 return false;
652 }
653
654 /**
655 Find a user set-table variable.
656
657 @param str Name of system variable to find
658 @param length Length of variable. zero means that we should use strlen()
659 on the variable
660
661 @retval
662 pointer pointer to variable definitions
663 @retval
664 0 Unknown variable (error message is given)
665 */
666
intern_find_sys_var(const char * str,size_t length)667 sys_var *intern_find_sys_var(const char *str, size_t length)
668 {
669 sys_var *var;
670
671 /*
672 This function is only called from the sql_plugin.cc.
673 A lock on LOCK_system_variable_hash should be held
674 */
675 var= (sys_var*) my_hash_search(&system_variable_hash,
676 (uchar*) str, length ? length : strlen(str));
677
678 /* Don't show non-visible variables. */
679 if (var && var->not_visible())
680 return NULL;
681
682 return var;
683 }
684
685
686 /**
687 Execute update of all variables.
688
689 First run a check of all variables that all updates will go ok.
690 If yes, then execute all updates, returning an error if any one failed.
691
692 This should ensure that in all normal cases none all or variables are
693 updated.
694
695 @param THD Thread id
696 @param var_list List of variables to update
697 @param free_joins Whether to free subselect joins if any. They are
698 freed by default, except for SET STATEMENT ... FOR ...
699 processing
700
701 @retval
702 0 ok
703 @retval
704 1 ERROR, message sent (normally no variables was updated)
705 @retval
706 -1 ERROR, message not sent
707 */
708
sql_set_variables(THD * thd,List<set_var_base> * var_list,bool free_joins)709 int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free_joins)
710 {
711 int error;
712 List_iterator_fast<set_var_base> it(*var_list);
713 DBUG_ENTER("sql_set_variables");
714
715 set_var_base *var;
716 while ((var=it++))
717 {
718 if ((error= var->check(thd)))
719 goto err;
720 }
721 if (!(error= MY_TEST(thd->is_error())))
722 {
723 it.rewind();
724 while ((var= it++))
725 error|= var->update(thd); // Returns 0, -1 or 1
726 }
727
728 err:
729 it.rewind();
730 while ((var= it++))
731 {
732 var->cleanup();
733 }
734 if (free_joins)
735 free_underlaid_joins(thd, thd->lex->select_lex);
736 DBUG_RETURN(error);
737 }
738
739 /**
740 This function is used to check if key management UDFs like
741 keying_key_generate/store/remove should proceed or not. If global
742 variable @@keyring_operations is OFF then above said udfs will fail.
743
744 @return Operation status
745 @retval 0 OK
746 @retval 1 ERROR, keyring operations are not allowed
747
748 @sa Sys_keyring_operations
749 */
keyring_access_test()750 bool keyring_access_test()
751 {
752 bool keyring_operations;
753 mysql_mutex_lock(&LOCK_keyring_operations);
754 keyring_operations= !opt_keyring_operations;
755 mysql_mutex_unlock(&LOCK_keyring_operations);
756 return keyring_operations;
757 }
758
759 /*****************************************************************************
760 Functions to handle SET mysql_internal_variable=const_expr
761 *****************************************************************************/
762
set_var(enum_var_type type_arg,sys_var * var_arg,const LEX_STRING * base_name_arg,Item * value_arg)763 set_var::set_var(enum_var_type type_arg, sys_var *var_arg,
764 const LEX_STRING *base_name_arg, Item *value_arg)
765 :var(NULL), type(type_arg), base(*base_name_arg), var_tracker(var_arg)
766 {
767 /*
768 If the set value is a field, change it to a string to allow things like
769 SET table_type=MYISAM;
770 */
771 if (value_arg && value_arg->type() == Item::FIELD_ITEM)
772 {
773 Item_field *item= (Item_field*) value_arg;
774 if (item->field_name)
775 {
776 if (!(value= new Item_string(item->field_name,
777 strlen(item->field_name),
778 system_charset_info))) // names are utf8
779 value= value_arg; /* Give error message later */
780 }
781 else
782 {
783 /* Both Item_field and Item_insert_value will return the type as
784 Item::FIELD_ITEM. If the item->field_name is NULL, we assume the
785 object to be Item_insert_value. */
786 value= value_arg;
787 }
788 }
789 else
790 value= value_arg;
791 }
792
793 /**
794 Verify that the supplied value is correct.
795
796 @param thd Thread handler
797
798 @return status code
799 @retval -1 Failure
800 @retval 0 Success
801 */
802
check(THD * thd)803 int set_var::check(THD *thd)
804 {
805 DBUG_ENTER("set_var::check");
806 DEBUG_SYNC(current_thd, "after_error_checking");
807
808 assert(var == NULL);
809 var= var_tracker.bind_system_variable(thd);
810 if (var == NULL)
811 {
812 DBUG_RETURN(-1);
813 }
814
815 var->do_deprecated_warning(thd);
816 if (var->is_readonly())
817 {
818 my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), var->name.str, "read only");
819 DBUG_RETURN(-1);
820 }
821 if (!var->check_scope(type))
822 {
823 int err= type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE;
824 my_error(err, MYF(0), var->name.str);
825 DBUG_RETURN(-1);
826 }
827 if (!acl_is_utility_user(thd->security_context()->priv_user().str,
828 thd->security_context()->host().str,
829 thd->security_context()->ip().str)
830 && (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL)))
831 DBUG_RETURN(1);
832 /* value is a NULL pointer if we are using SET ... = DEFAULT */
833 if (!value)
834 DBUG_RETURN(0);
835
836 if ((!value->fixed &&
837 value->fix_fields(thd, &value)) || value->check_cols(1))
838 DBUG_RETURN(-1);
839 if (var->check_update_type(value->result_type()))
840 {
841 my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), var->name.str);
842 DBUG_RETURN(-1);
843 }
844 int ret= var->check(thd, this) ? -1 : 0;
845
846 #ifndef EMBEDDED_LIBRARY
847 if (!ret && type == OPT_GLOBAL)
848 {
849 ret= mysql_audit_notify(thd, AUDIT_EVENT(MYSQL_AUDIT_GLOBAL_VARIABLE_SET),
850 var->name.str,
851 value->item_name.ptr(),
852 value->item_name.length());
853 }
854 #endif
855
856 DBUG_RETURN(ret);
857 }
858
859
860 /**
861 Set member variable `var` (used by PS).
862
863 @param thd thread handler
864
865 @retval
866 0 ok
867 @retval
868 1 ERROR
869 */
populate_sys_var(THD * thd)870 int set_var::populate_sys_var(THD *thd)
871 {
872 var= var_tracker.bind_system_variable(thd);
873 if (var == NULL)
874 {
875 return 1;
876 }
877
878 return 0;
879 }
880
881 /**
882 Check variable, but without assigning value (used by PS).
883
884 @param thd thread handler
885
886 @retval
887 0 ok
888 @retval
889 1 ERROR, message sent (normally no variables was updated)
890 @retval
891 -1 ERROR, message not sent
892 */
light_check(THD * thd)893 int set_var::light_check(THD *thd)
894 {
895 if (populate_sys_var(thd))
896 {
897 return 1;
898 }
899
900 if (!var->check_scope(type))
901 {
902 int err= type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE;
903 my_error(err, MYF(0), var->name);
904 return -1;
905 }
906 if (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL))
907 return 1;
908
909 if (value && ((!value->fixed && value->fix_fields(thd, &value)) ||
910 value->check_cols(1)))
911 return -1;
912 return 0;
913 }
914
915 /**
916 Update variable
917
918 @param thd thread handler
919 @returns 0|1 ok or ERROR
920
921 @note ERROR can be only due to abnormal operations involving
922 the server's execution evironment such as
923 out of memory, hard disk failure or the computer blows up.
924 Consider set_var::check() method if there is a need to return
925 an error due to logics.
926 */
update(THD * thd)927 int set_var::update(THD *thd)
928 {
929 assert(var != NULL);
930
931 return value ? var->update(thd, this) : var->set_default(thd, this);
932 }
933
934 /**
935 Self-print assignment
936
937 @param str string buffer to append the partial assignment to
938 */
print(THD * thd,String * str)939 void set_var::print(THD *thd, String *str)
940 {
941 str->append(type == OPT_GLOBAL ? "GLOBAL " : "SESSION ");
942 if (base.length)
943 {
944 str->append(base.str, base.length);
945 str->append(STRING_WITH_LEN("."));
946 }
947 str->append(var->name.str,var->name.length);
948 str->append(STRING_WITH_LEN("="));
949 if (value)
950 value->print(str, QT_ORDINARY);
951 else
952 str->append(STRING_WITH_LEN("DEFAULT"));
953 }
954
955
956 /*****************************************************************************
957 Functions to handle SET @user_variable=const_expr
958 *****************************************************************************/
959
check(THD * thd)960 int set_var_user::check(THD *thd)
961 {
962 /*
963 Item_func_set_user_var can't substitute something else on its place =>
964 0 can be passed as last argument (reference on item)
965 */
966 return (user_var_item->fix_fields(thd, (Item**) 0) ||
967 user_var_item->check(0)) ? -1 : 0;
968 }
969
970
971 /**
972 Check variable, but without assigning value (used by PS).
973
974 @param thd thread handler
975
976 @retval
977 0 ok
978 @retval
979 1 ERROR, message sent (normally no variables was updated)
980 @retval
981 -1 ERROR, message not sent
982 */
light_check(THD * thd)983 int set_var_user::light_check(THD *thd)
984 {
985 /*
986 Item_func_set_user_var can't substitute something else on its place =>
987 0 can be passed as last argument (reference on item)
988 */
989 return (user_var_item->fix_fields(thd, (Item**) 0));
990 }
991
992
update(THD * thd)993 int set_var_user::update(THD *thd)
994 {
995 if (user_var_item->update())
996 {
997 /* Give an error if it's not given already */
998 my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), MYF(0));
999 return -1;
1000 }
1001 if (thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->is_enabled())
1002 thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->mark_as_changed(thd, NULL);
1003 return 0;
1004 }
1005
1006
print(THD * thd,String * str)1007 void set_var_user::print(THD *thd, String *str)
1008 {
1009 user_var_item->print_assignment(str, QT_ORDINARY);
1010 }
1011
1012
1013 /*****************************************************************************
1014 Functions to handle SET PASSWORD
1015 *****************************************************************************/
1016
1017 /**
1018 Check the validity of the SET PASSWORD request
1019
1020 @param thd The current thread
1021 @return status code
1022 @retval 0 failure
1023 @retval 1 success
1024 */
check(THD * thd)1025 int set_var_password::check(THD *thd)
1026 {
1027 #ifndef NO_EMBEDDED_ACCESS_CHECKS
1028 /* Returns 1 as the function sends error to client */
1029 return check_change_password(thd, user->host.str, user->user.str,
1030 password, strlen(password)) ? 1 : 0;
1031 #else
1032 return 0;
1033 #endif
1034 }
1035
update(THD * thd)1036 int set_var_password::update(THD *thd)
1037 {
1038 #ifndef NO_EMBEDDED_ACCESS_CHECKS
1039 /* Returns 1 as the function sends error to client */
1040 return change_password(thd, user->host.str, user->user.str, password) ?
1041 1 : 0;
1042 #else
1043 return 0;
1044 #endif
1045 }
1046
print(THD * thd,String * str)1047 void set_var_password::print(THD *thd, String *str)
1048 {
1049 if (user->user.str != NULL && user->user.length > 0)
1050 {
1051 str->append(STRING_WITH_LEN("PASSWORD FOR "));
1052 append_identifier(thd, str, user->user.str, user->user.length);
1053 if (user->host.str != NULL && user->host.length > 0)
1054 {
1055 str->append(STRING_WITH_LEN("@"));
1056 append_identifier(thd, str, user->host.str, user->host.length);
1057 }
1058 str->append(STRING_WITH_LEN("="));
1059 }
1060 else
1061 str->append(STRING_WITH_LEN("PASSWORD FOR CURRENT_USER()="));
1062 str->append(STRING_WITH_LEN("<secret>"));
1063 }
1064
1065 /*****************************************************************************
1066 Functions to handle SET NAMES and SET CHARACTER SET
1067 *****************************************************************************/
1068
check(THD * thd)1069 int set_var_collation_client::check(THD *thd)
1070 {
1071 /* Currently, UCS-2 cannot be used as a client character set */
1072 if (!is_supported_parser_charset(character_set_client))
1073 {
1074 my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
1075 character_set_client->csname);
1076 return 1;
1077 }
1078 return 0;
1079 }
1080
update(THD * thd)1081 int set_var_collation_client::update(THD *thd)
1082 {
1083 thd->variables.character_set_client= character_set_client;
1084 thd->variables.character_set_results= character_set_results;
1085 thd->variables.collation_connection= collation_connection;
1086 thd->update_charset();
1087
1088 /* Mark client collation variables as changed */
1089 if (thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->is_enabled())
1090 {
1091 LEX_CSTRING cs_client= {"character_set_client",
1092 sizeof("character_set_client") - 1};
1093 thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->mark_as_changed(thd, &cs_client);
1094 LEX_CSTRING cs_results= {"character_set_results",
1095 sizeof("character_set_results") -1};
1096 thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->mark_as_changed(thd, &cs_results);
1097 LEX_CSTRING cs_connection= {"character_set_connection",
1098 sizeof("character_set_connection") - 1};
1099 thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->mark_as_changed(thd, &cs_connection);
1100 }
1101 if (thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->is_enabled())
1102 thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)->mark_as_changed(thd, NULL);
1103 thd->protocol_text.init(thd);
1104 thd->protocol_binary.init(thd);
1105 return 0;
1106 }
1107
print(THD * thd,String * str)1108 void set_var_collation_client::print(THD *thd, String *str)
1109 {
1110 str->append((set_cs_flags & SET_CS_NAMES) ? "NAMES " : "CHARACTER SET ");
1111 if (set_cs_flags & SET_CS_DEFAULT)
1112 str->append("DEFAULT");
1113 else
1114 {
1115 str->append("'");
1116 str->append(character_set_client->csname);
1117 str->append("'");
1118 if (set_cs_flags & SET_CS_COLLATE)
1119 {
1120 str->append(" COLLATE '");
1121 str->append(collation_connection->name);
1122 str->append("'");
1123 }
1124 }
1125 }
1126