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