1 /* Copyright (c) 2002, 2013, 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 /* variable declarations are in sys_vars.cc now !!! */
24 
25 #include "my_global.h"                          /* NO_EMBEDDED_ACCESS_CHECKS */
26 #include "sql_class.h"                   // set_var.h: session_var_ptr
27 #include "set_var.h"
28 #include "sql_priv.h"
29 #include "unireg.h"
30 #include "mysqld.h"                             // lc_messages_dir
31 #include "sys_vars_shared.h"
32 #include "transaction.h"
33 #include "sql_locale.h"                         // my_locale_by_number,
34                                                 // my_locale_by_name
35 #include "strfunc.h"      // find_set_from_flags, find_set
36 #include "sql_parse.h"    // check_global_access
37 #include "sql_table.h"  // reassign_keycache_tables
38 #include "sql_time.h"   // date_time_format_copy,
39                         // date_time_format_make
40 #include "derror.h"
41 #include "tztime.h"     // my_tz_find, my_tz_SYSTEM, struct Time_zone
42 #include "sql_acl.h"    // SUPER_ACL
43 #include "sql_select.h" // free_underlaid_joins
44 #include "sql_show.h"   // make_default_log_name, append_identifier
45 #include "sql_view.h"   // updatable_views_with_limit_typelib
46 #include "lock.h"                               // lock_global_read_lock,
47                                                 // make_global_read_lock_block_commit,
48                                                 // unlock_global_read_lock
49 
50 static HASH system_variable_hash;
51 static PolyLock_mutex PLock_global_system_variables(&LOCK_global_system_variables);
52 
53 /**
54   Return variable name and length for hashing of variables.
55 */
56 
get_sys_var_length(const sys_var * var,size_t * length,my_bool first)57 static uchar *get_sys_var_length(const sys_var *var, size_t *length,
58                                  my_bool first)
59 {
60   *length= var->name.length;
61   return (uchar*) var->name.str;
62 }
63 
64 sys_var_chain all_sys_vars = { NULL, NULL };
65 
sys_var_init()66 int sys_var_init()
67 {
68   DBUG_ENTER("sys_var_init");
69 
70   /* Must be already initialized. */
71   DBUG_ASSERT(system_charset_info != NULL);
72 
73   if (my_hash_init(&system_variable_hash, system_charset_info, 100, 0,
74                    0, (my_hash_get_key) get_sys_var_length, 0, HASH_UNIQUE))
75     goto error;
76 
77   if (mysql_add_sys_var_chain(all_sys_vars.first))
78     goto error;
79 
80   DBUG_RETURN(0);
81 
82 error:
83   fprintf(stderr, "failed to initialize System variables");
84   DBUG_RETURN(1);
85 }
86 
sys_var_add_options(std::vector<my_option> * long_options,int parse_flags)87 int sys_var_add_options(std::vector<my_option> *long_options, int parse_flags)
88 {
89   DBUG_ENTER("sys_var_add_options");
90 
91   for (sys_var *var=all_sys_vars.first; var; var= var->next)
92   {
93     if (var->register_option(long_options, parse_flags))
94       goto error;
95   }
96 
97   DBUG_RETURN(0);
98 
99 error:
100   fprintf(stderr, "failed to initialize System variables");
101   DBUG_RETURN(1);
102 }
103 
sys_var_end()104 void sys_var_end()
105 {
106   DBUG_ENTER("sys_var_end");
107 
108   my_hash_free(&system_variable_hash);
109 
110   for (sys_var *var=all_sys_vars.first; var; var= var->next)
111     var->cleanup();
112 
113   DBUG_VOID_RETURN;
114 }
115 
116 /**
117   sys_var constructor
118 
119   @param chain     variables are linked into chain for mysql_add_sys_var_chain()
120   @param name_arg  the name of the variable. Must be 0-terminated and exist
121                    for the liftime of the sys_var object. @sa my_option::name
122   @param comment   shown in mysqld --help, @sa my_option::comment
123   @param flags_arg or'ed flag_enum values
124   @param off       offset of the global variable value from the
125                    &global_system_variables.
126   @param getopt_id -1 for no command-line option, otherwise @sa my_option::id
127   @param getopt_arg_type @sa my_option::arg_type
128   @param show_val_type_arg what value_ptr() returns for sql_show.cc
129   @param def_val   default value, @sa my_option::def_value
130   @param lock      mutex or rw_lock that protects the global variable
131                    *in addition* to LOCK_global_system_variables.
132   @param binlog_status_enum @sa binlog_status_enum
133   @param on_check_func a function to be called at the end of sys_var::check,
134                    put your additional checks here
135   @param on_update_func a function to be called at the end of sys_var::update,
136                    any post-update activity should happen here
137   @param substitute If non-NULL, this variable is deprecated and the
138   string describes what one should use instead. If an empty string,
139   the variable is deprecated but no replacement is offered.
140   @param parse_flag either PARSE_EARLY or PARSE_NORMAL
141 */
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)142 sys_var::sys_var(sys_var_chain *chain, const char *name_arg,
143                  const char *comment, int flags_arg, ptrdiff_t off,
144                  int getopt_id, enum get_opt_arg_type getopt_arg_type,
145                  SHOW_TYPE show_val_type_arg, longlong def_val,
146                  PolyLock *lock, enum binlog_status_enum binlog_status_arg,
147                  on_check_function on_check_func,
148                  on_update_function on_update_func,
149                  const char *substitute, int parse_flag) :
150   next(0),
151   binlog_status(binlog_status_arg),
152   flags(flags_arg), m_parse_flag(parse_flag), show_val_type(show_val_type_arg),
153   guard(lock), offset(off), on_check(on_check_func), on_update(on_update_func),
154   deprecation_substitute(substitute),
155   is_os_charset(FALSE)
156 {
157   /*
158     There is a limitation in handle_options() related to short options:
159     - either all short options should be declared when parsing in multiple stages,
160     - or none should be declared.
161     Because a lot of short options are used in the normal parsing phase
162     for mysqld, we enforce here that no short option is present
163     in the first (PARSE_EARLY) stage.
164     See handle_options() for details.
165   */
166   DBUG_ASSERT(parse_flag == PARSE_NORMAL || getopt_id <= 0 || getopt_id >= 255);
167 
168   name.str= name_arg;     // ER_NO_DEFAULT relies on 0-termination of name_arg
169   name.length= strlen(name_arg);                // and so does this.
170   DBUG_ASSERT(name.length <= NAME_CHAR_LEN);
171 
172   memset(&option, 0, sizeof(option));
173   option.name= name_arg;
174   option.id= getopt_id;
175   option.comment= comment;
176   option.arg_type= getopt_arg_type;
177   option.value= (uchar **)global_var_ptr();
178   option.def_value= def_val;
179 
180   if (chain->last)
181     chain->last->next= this;
182   else
183     chain->first= this;
184   chain->last= this;
185 }
186 
update(THD * thd,set_var * var)187 bool sys_var::update(THD *thd, set_var *var)
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     return session_update(thd, var) ||
205       (on_update && on_update(this, thd, OPT_SESSION));
206 }
207 
session_value_ptr(THD * thd,LEX_STRING * base)208 uchar *sys_var::session_value_ptr(THD *thd, LEX_STRING *base)
209 {
210   return session_var_ptr(thd);
211 }
212 
global_value_ptr(THD * thd,LEX_STRING * base)213 uchar *sys_var::global_value_ptr(THD *thd, LEX_STRING *base)
214 {
215   return global_var_ptr();
216 }
217 
check(THD * thd,set_var * var)218 bool sys_var::check(THD *thd, set_var *var)
219 {
220   if ((var->value && do_check(thd, var))
221       || (on_check && on_check(this, thd, var)))
222   {
223     if (!thd->is_error())
224     {
225       char buff[STRING_BUFFER_USUAL_SIZE];
226       String str(buff, sizeof(buff), system_charset_info), *res;
227 
228       if (!var->value)
229       {
230         str.set(STRING_WITH_LEN("DEFAULT"), &my_charset_latin1);
231         res= &str;
232       }
233       else if (!(res=var->value->val_str(&str)))
234       {
235         str.set(STRING_WITH_LEN("NULL"), &my_charset_latin1);
236         res= &str;
237       }
238       ErrConvString err(res);
239       my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
240     }
241     return true;
242   }
243   return false;
244 }
245 
value_ptr(THD * thd,enum_var_type type,LEX_STRING * base)246 uchar *sys_var::value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
247 {
248   if (type == OPT_GLOBAL || scope() == GLOBAL)
249   {
250     mysql_mutex_assert_owner(&LOCK_global_system_variables);
251     AutoRLock lock(guard);
252     return global_value_ptr(thd, base);
253   }
254   else
255     return session_value_ptr(thd, base);
256 }
257 
set_default(THD * thd,set_var * var)258 bool sys_var::set_default(THD *thd, set_var* var)
259 {
260   if (var->type == OPT_GLOBAL || scope() == GLOBAL)
261     global_save_default(thd, var);
262   else
263     session_save_default(thd, var);
264 
265   return check(thd, var) || update(thd, var);
266 }
267 
do_deprecated_warning(THD * thd)268 void sys_var::do_deprecated_warning(THD *thd)
269 {
270   if (deprecation_substitute != NULL)
271   {
272     char buf1[NAME_CHAR_LEN + 3];
273     strxnmov(buf1, sizeof(buf1)-1, "@@", name.str, 0);
274 
275     /*
276        if deprecation_substitute is an empty string,
277        there is no replacement for the syntax
278     */
279     uint errmsg= deprecation_substitute[0] == '\0'
280       ? ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT
281       : ER_WARN_DEPRECATED_SYNTAX;
282     if (thd)
283       push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
284                           ER_WARN_DEPRECATED_SYNTAX, ER(errmsg),
285                           buf1, deprecation_substitute);
286     else
287       sql_print_warning(ER_DEFAULT(errmsg), buf1, deprecation_substitute);
288   }
289 }
290 
291 /**
292   Throw warning (error in STRICT mode) if value for variable needed bounding.
293   Plug-in interface also uses this.
294 
295   @param thd         thread handle
296   @param name        variable's name
297   @param fixed       did we have to correct the value? (throw warn/err if so)
298   @param is_unsigned is value's type unsigned?
299   @param v           variable's value
300 
301   @retval         true on error, false otherwise (warning or ok)
302  */
throw_bounds_warning(THD * thd,const char * name,bool fixed,bool is_unsigned,longlong v)303 bool throw_bounds_warning(THD *thd, const char *name,
304                           bool fixed, bool is_unsigned, longlong v)
305 {
306   if (fixed)
307   {
308     char buf[22];
309 
310     if (is_unsigned)
311       ullstr((ulonglong) v, buf);
312     else
313       llstr(v, buf);
314 
315     if (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES)
316     {
317       my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buf);
318       return true;
319     }
320     push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
321                         ER_TRUNCATED_WRONG_VALUE,
322                         ER(ER_TRUNCATED_WRONG_VALUE), name, buf);
323   }
324   return false;
325 }
326 
throw_bounds_warning(THD * thd,const char * name,bool fixed,double v)327 bool throw_bounds_warning(THD *thd, const char *name, bool fixed, double v)
328 {
329   if (fixed)
330   {
331     char buf[64];
332 
333     my_gcvt(v, MY_GCVT_ARG_DOUBLE, sizeof(buf) - 1, buf, NULL);
334 
335     if (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES)
336     {
337       my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buf);
338       return true;
339     }
340     push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
341                         ER_TRUNCATED_WRONG_VALUE,
342                         ER(ER_TRUNCATED_WRONG_VALUE), name, buf);
343   }
344   return false;
345 }
346 
charset(THD * thd)347 const CHARSET_INFO *sys_var::charset(THD *thd)
348 {
349   return is_os_charset ? thd->variables.character_set_filesystem :
350     system_charset_info;
351 }
352 
353 typedef struct old_names_map_st
354 {
355   const char *old_name;
356   const char *new_name;
357 } my_old_conv;
358 
359 static my_old_conv old_conv[]=
360 {
361   {     "cp1251_koi8"           ,       "cp1251"        },
362   {     "cp1250_latin2"         ,       "cp1250"        },
363   {     "kam_latin2"            ,       "keybcs2"       },
364   {     "mac_latin2"            ,       "MacRoman"      },
365   {     "macce_latin2"          ,       "MacCE"         },
366   {     "pc2_latin2"            ,       "pclatin2"      },
367   {     "vga_latin2"            ,       "pclatin1"      },
368   {     "koi8_cp1251"           ,       "koi8r"         },
369   {     "win1251ukr_koi8_ukr"   ,       "win1251ukr"    },
370   {     "koi8_ukr_win1251ukr"   ,       "koi8u"         },
371   {     NULL                    ,       NULL            }
372 };
373 
get_old_charset_by_name(const char * name)374 const CHARSET_INFO *get_old_charset_by_name(const char *name)
375 {
376   my_old_conv *conv;
377 
378   for (conv= old_conv; conv->old_name; conv++)
379   {
380     if (!my_strcasecmp(&my_charset_latin1, name, conv->old_name))
381       return get_charset_by_csname(conv->new_name, MY_CS_PRIMARY, MYF(0));
382   }
383   return NULL;
384 }
385 
386 /****************************************************************************
387   Main handling of variables:
388   - Initialisation
389   - Searching during parsing
390   - Update loop
391 ****************************************************************************/
392 
393 /**
394   Add variables to the dynamic hash of system variables
395 
396   @param first       Pointer to first system variable to add
397 
398   @retval
399     0           SUCCESS
400   @retval
401     otherwise   FAILURE
402 */
403 
404 
mysql_add_sys_var_chain(sys_var * first)405 int mysql_add_sys_var_chain(sys_var *first)
406 {
407   sys_var *var;
408 
409   /* A write lock should be held on LOCK_system_variables_hash */
410 
411   for (var= first; var; var= var->next)
412   {
413     /* this fails if there is a conflicting variable name. see HASH_UNIQUE */
414     if (my_hash_insert(&system_variable_hash, (uchar*) var))
415     {
416       fprintf(stderr, "*** duplicate variable name '%s' ?\n", var->name.str);
417       goto error;
418     }
419   }
420   return 0;
421 
422 error:
423   for (; first != var; first= first->next)
424     my_hash_delete(&system_variable_hash, (uchar*) first);
425   return 1;
426 }
427 
428 
429 /*
430   Remove variables to the dynamic hash of system variables
431 
432   SYNOPSIS
433     mysql_del_sys_var_chain()
434     first       Pointer to first system variable to remove
435 
436   RETURN VALUES
437     0           SUCCESS
438     otherwise   FAILURE
439 */
440 
mysql_del_sys_var_chain(sys_var * first)441 int mysql_del_sys_var_chain(sys_var *first)
442 {
443   int result= 0;
444 
445   /* A write lock should be held on LOCK_system_variables_hash */
446 
447   for (sys_var *var= first; var; var= var->next)
448     result|= my_hash_delete(&system_variable_hash, (uchar*) var);
449 
450   return result;
451 }
452 
453 
show_cmp(SHOW_VAR * a,SHOW_VAR * b)454 static int show_cmp(SHOW_VAR *a, SHOW_VAR *b)
455 {
456   return strcmp(a->name, b->name);
457 }
458 
459 
460 /**
461   Constructs an array of system variables for display to the user.
462 
463   @param thd       current thread
464   @param sorted    If TRUE, the system variables should be sorted
465   @param type      OPT_GLOBAL or OPT_SESSION for SHOW GLOBAL|SESSION VARIABLES
466 
467   @retval
468     pointer     Array of SHOW_VAR elements for display
469   @retval
470     NULL        FAILURE
471 */
472 
enumerate_sys_vars(THD * thd,bool sorted,enum enum_var_type type)473 SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type)
474 {
475   int count= system_variable_hash.records, i;
476   int size= sizeof(SHOW_VAR) * (count + 1);
477   SHOW_VAR *result= (SHOW_VAR*) thd->alloc(size);
478 
479   if (result)
480   {
481     SHOW_VAR *show= result;
482 
483     for (i= 0; i < count; i++)
484     {
485       sys_var *var= (sys_var*) my_hash_element(&system_variable_hash, i);
486       const my_bool *hidden=
487         getopt_constraint_get_hidden_value(var->name.str, var->name.length,
488                                            FALSE);
489 
490       if (hidden && *hidden)
491         continue;
492 
493       // don't show session-only variables in SHOW GLOBAL VARIABLES
494       if (type == OPT_GLOBAL && var->check_type(type))
495         continue;
496 
497       /* don't show non-visible variables */
498       if (var->not_visible())
499         continue;
500 
501       show->name= var->name.str;
502       show->value= (char*) var;
503       show->type= SHOW_SYS;
504       show++;
505     }
506 
507     /* sort into order */
508     if (sorted)
509       my_qsort(result, show-result, sizeof(SHOW_VAR),
510                (qsort_cmp) show_cmp);
511 
512     /* make last element empty */
513     memset(show, 0, sizeof(SHOW_VAR));
514   }
515   return result;
516 }
517 
518 /**
519   Find a user set-table variable.
520 
521   @param str       Name of system variable to find
522   @param length    Length of variable.  zero means that we should use strlen()
523                    on the variable
524 
525   @retval
526     pointer     pointer to variable definitions
527   @retval
528     0           Unknown variable (error message is given)
529 */
530 
intern_find_sys_var(const char * str,uint length)531 sys_var *intern_find_sys_var(const char *str, uint length)
532 {
533   sys_var *var;
534 
535   /*
536     This function is only called from the sql_plugin.cc.
537     A lock on LOCK_system_variable_hash should be held
538   */
539   var= (sys_var*) my_hash_search(&system_variable_hash,
540                               (uchar*) str, length ? length : strlen(str));
541 
542   /* Don't show non-visible variables. */
543   if (var && var->not_visible())
544     return NULL;
545 
546   return var;
547 }
548 
549 
550 /**
551   Execute update of all variables.
552 
553   First run a check of all variables that all updates will go ok.
554   If yes, then execute all updates, returning an error if any one failed.
555 
556   This should ensure that in all normal cases none all or variables are
557   updated.
558 
559   @param THD            Thread id
560   @param var_list       List of variables to update
561   @param free_joins     Whether to free subselect joins if any. They are
562                         freed by default, except for SET STATEMENT ... FOR ...
563                         processing
564 
565   @retval
566     0   ok
567   @retval
568     1   ERROR, message sent (normally no variables was updated)
569   @retval
570     -1  ERROR, message not sent
571 */
572 
sql_set_variables(THD * thd,List<set_var_base> * var_list,bool free_joins)573 int sql_set_variables(THD *thd, List<set_var_base> *var_list, bool free_joins)
574 {
575   int error;
576   List_iterator_fast<set_var_base> it(*var_list);
577   DBUG_ENTER("sql_set_variables");
578 
579   set_var_base *var;
580   while ((var=it++))
581   {
582     if ((error= var->check(thd)))
583       goto err;
584   }
585   if (!(error= MY_TEST(thd->is_error())))
586   {
587     it.rewind();
588     while ((var= it++))
589       error|= var->update(thd);         // Returns 0, -1 or 1
590   }
591 
592 err:
593   if (free_joins)
594     free_underlaid_joins(thd, &thd->lex->select_lex);
595   DBUG_RETURN(error);
596 }
597 
598 /*****************************************************************************
599   Functions to handle SET mysql_internal_variable=const_expr
600 *****************************************************************************/
601 
602 /**
603   Verify that the supplied value is correct.
604 
605   @param thd Thread handler
606 
607   @return status code
608    @retval -1 Failure
609    @retval 0 Success
610  */
611 
check(THD * thd)612 int set_var::check(THD *thd)
613 {
614   var->do_deprecated_warning(thd);
615   if (var->is_readonly())
616   {
617     my_error(ER_INCORRECT_GLOBAL_LOCAL_VAR, MYF(0), var->name.str, "read only");
618     return -1;
619   }
620   if (var->check_type(type))
621   {
622     int err= type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE;
623     my_error(err, MYF(0), var->name.str);
624     return -1;
625   }
626   if (!acl_is_utility_user(thd->security_ctx->priv_user,
627                            thd->security_ctx->get_host()->ptr(),
628                            thd->security_ctx->get_ip()->ptr())
629       && (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL)))
630     return 1;
631   /* value is a NULL pointer if we are using SET ... = DEFAULT */
632   if (!value)
633     return 0;
634 
635   if ((!value->fixed &&
636        value->fix_fields(thd, &value)) || value->check_cols(1))
637     return -1;
638   if (var->check_update_type(value->result_type()))
639   {
640     my_error(ER_WRONG_TYPE_FOR_VAR, MYF(0), var->name.str);
641     return -1;
642   }
643   return var->check(thd, this) ? -1 : 0;
644 }
645 
646 
647 /**
648   Check variable, but without assigning value (used by PS).
649 
650   @param thd            thread handler
651 
652   @retval
653     0   ok
654   @retval
655     1   ERROR, message sent (normally no variables was updated)
656   @retval
657     -1   ERROR, message not sent
658 */
light_check(THD * thd)659 int set_var::light_check(THD *thd)
660 {
661   if (var->check_type(type))
662   {
663     int err= type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE;
664     my_error(err, MYF(0), var->name);
665     return -1;
666   }
667   if (type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL))
668     return 1;
669 
670   if (value && ((!value->fixed && value->fix_fields(thd, &value)) ||
671                 value->check_cols(1)))
672     return -1;
673   return 0;
674 }
675 
676 /**
677   Update variable
678 
679   @param   thd    thread handler
680   @returns 0|1    ok or ERROR
681 
682   @note ERROR can be only due to abnormal operations involving
683   the server's execution evironment such as
684   out of memory, hard disk failure or the computer blows up.
685   Consider set_var::check() method if there is a need to return
686   an error due to logics.
687 */
update(THD * thd)688 int set_var::update(THD *thd)
689 {
690   return value ? var->update(thd, this) : var->set_default(thd, this);
691 }
692 
693 /**
694   Self-print assignment
695 
696   @param   str    string buffer to append the partial assignment to
697 */
print(THD * thd,String * str)698 void set_var::print(THD *thd, String *str)
699 {
700   str->append(type == OPT_GLOBAL ? "GLOBAL " : "SESSION ");
701   if (base.length)
702   {
703     str->append(base.str, base.length);
704     str->append(STRING_WITH_LEN("."));
705   }
706   str->append(var->name.str,var->name.length);
707   str->append(STRING_WITH_LEN("="));
708   if (value)
709     value->print(str, QT_ORDINARY);
710   else
711     str->append(STRING_WITH_LEN("DEFAULT"));
712 }
713 
714 
715 /*****************************************************************************
716   Functions to handle SET @user_variable=const_expr
717 *****************************************************************************/
718 
check(THD * thd)719 int set_var_user::check(THD *thd)
720 {
721   /*
722     Item_func_set_user_var can't substitute something else on its place =>
723     0 can be passed as last argument (reference on item)
724   */
725   return (user_var_item->fix_fields(thd, (Item**) 0) ||
726           user_var_item->check(0)) ? -1 : 0;
727 }
728 
729 
730 /**
731   Check variable, but without assigning value (used by PS).
732 
733   @param thd            thread handler
734 
735   @retval
736     0   ok
737   @retval
738     1   ERROR, message sent (normally no variables was updated)
739   @retval
740     -1   ERROR, message not sent
741 */
light_check(THD * thd)742 int set_var_user::light_check(THD *thd)
743 {
744   /*
745     Item_func_set_user_var can't substitute something else on its place =>
746     0 can be passed as last argument (reference on item)
747   */
748   return (user_var_item->fix_fields(thd, (Item**) 0));
749 }
750 
751 
update(THD * thd)752 int set_var_user::update(THD *thd)
753 {
754   if (user_var_item->update())
755   {
756     /* Give an error if it's not given already */
757     my_message(ER_SET_CONSTANTS_ONLY, ER(ER_SET_CONSTANTS_ONLY), MYF(0));
758     return -1;
759   }
760   return 0;
761 }
762 
763 
print(THD * thd,String * str)764 void set_var_user::print(THD *thd, String *str)
765 {
766   user_var_item->print_assignment(str, QT_ORDINARY);
767 }
768 
769 
770 /*****************************************************************************
771   Functions to handle SET PASSWORD
772 *****************************************************************************/
773 
774 /**
775   Check the validity of the SET PASSWORD request
776 
777   User name and no host is used for SET PASSWORD =
778   No user name and no host used for SET PASSWORD for CURRENT_USER() =
779 
780   @param  thd  The current thread
781   @return      status code
782   @retval 0    failure
783   @retval 1    success
784 */
check(THD * thd)785 int set_var_password::check(THD *thd)
786 {
787 #ifndef NO_EMBEDDED_ACCESS_CHECKS
788   if (!user->host.str)
789   {
790     DBUG_ASSERT(thd->security_ctx->priv_host);
791     user->host.str= (char *) thd->security_ctx->priv_host;
792     user->host.length= strlen(thd->security_ctx->priv_host);
793   }
794   /*
795     In case of anonymous user, user->user is set to empty string with length 0.
796     But there might be case when user->user.str could be NULL. For Ex:
797     "set password for current_user() = password('xyz');". In this case,
798     set user information as of the current user.
799   */
800   if (!user->user.str)
801   {
802     DBUG_ASSERT(thd->security_ctx->user);
803     user->user.str= (char *) thd->security_ctx->user;
804     user->user.length= strlen(thd->security_ctx->user);
805   }
806   /* Returns 1 as the function sends error to client */
807   return check_change_password(thd, user->host.str, user->user.str,
808                                password, strlen(password)) ? 1 : 0;
809 #else
810   return 0;
811 #endif
812 }
813 
update(THD * thd)814 int set_var_password::update(THD *thd)
815 {
816 #ifndef NO_EMBEDDED_ACCESS_CHECKS
817   /* Returns 1 as the function sends error to client */
818   return change_password(thd, user->host.str, user->user.str, password) ?
819           1 : 0;
820 #else
821   return 0;
822 #endif
823 }
824 
print(THD * thd,String * str)825 void set_var_password::print(THD *thd, String *str)
826 {
827   if (user->user.str != NULL && user->user.length > 0)
828   {
829     str->append(STRING_WITH_LEN("PASSWORD FOR "));
830     append_identifier(thd, str, user->user.str, user->user.length);
831     if (user->host.str != NULL && user->host.length > 0)
832     {
833       str->append(STRING_WITH_LEN("@"));
834       append_identifier(thd, str, user->host.str, user->host.length);
835     }
836     str->append(STRING_WITH_LEN("="));
837   }
838   else
839     str->append(STRING_WITH_LEN("PASSWORD FOR CURRENT_USER()="));
840   str->append(STRING_WITH_LEN("<secret>"));
841 }
842 
843 /*****************************************************************************
844   Functions to handle SET NAMES and SET CHARACTER SET
845 *****************************************************************************/
846 
check(THD * thd)847 int set_var_collation_client::check(THD *thd)
848 {
849   /* Currently, UCS-2 cannot be used as a client character set */
850   if (!is_supported_parser_charset(character_set_client))
851   {
852     my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
853              character_set_client->csname);
854     return 1;
855   }
856   return 0;
857 }
858 
update(THD * thd)859 int set_var_collation_client::update(THD *thd)
860 {
861   thd->variables.character_set_client= character_set_client;
862   thd->variables.character_set_results= character_set_results;
863   thd->variables.collation_connection= collation_connection;
864   thd->update_charset();
865   thd->protocol_text.init(thd);
866   thd->protocol_binary.init(thd);
867   return 0;
868 }
869 
print(THD * thd,String * str)870 void set_var_collation_client::print(THD *thd, String *str)
871 {
872   str->append((set_cs_flags & SET_CS_NAMES) ? "NAMES " : "CHARACTER SET ");
873   if (set_cs_flags & SET_CS_DEFAULT)
874     str->append("DEFAULT");
875   else
876   {
877     str->append("'");
878     str->append(character_set_client->csname);
879     str->append("'");
880     if (set_cs_flags & SET_CS_COLLATE)
881     {
882       str->append(" COLLATE '");
883       str->append(collation_connection->name);
884       str->append("'");
885     }
886   }
887 }
888