1 /* Copyright (c) 2002, 2014, 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 /**
24   @file
25   "private" interface to sys_var - server configuration variables.
26 
27   This header is included only by the file that contains declarations
28   of sys_var variables (sys_vars.cc).
29 */
30 
31 #include "sys_vars_shared.h"
32 #include <my_getopt.h>
33 #include <my_bit.h>
34 #include <my_dir.h>
35 #include "keycaches.h"
36 #include "strfunc.h"
37 #include "tztime.h"     // my_tz_find, my_tz_SYSTEM, struct Time_zone
38 #include "rpl_gtid.h"
39 #include <ctype.h>
40 
41 /*
42   a set of mostly trivial (as in f(X)=X) defines below to make system variable
43   declarations more readable
44 */
45 #define VALID_RANGE(X,Y) X,Y
46 #define DEFAULT(X) X
47 #define BLOCK_SIZE(X) X
48 #define GLOBAL_VAR(X) sys_var::GLOBAL, (((char*)&(X))-(char*)&global_system_variables), sizeof(X)
49 #define SESSION_VAR(X) sys_var::SESSION, offsetof(SV, X), sizeof(((SV *)0)->X)
50 #define SESSION_ONLY(X) sys_var::ONLY_SESSION, offsetof(SV, X), sizeof(((SV *)0)->X)
51 #define NO_CMD_LINE CMD_LINE(NO_ARG, -1)
52 /*
53   the define below means that there's no *second* mutex guard,
54   LOCK_global_system_variables always guards all system variables
55 */
56 #define NO_MUTEX_GUARD ((PolyLock*)0)
57 #define IN_BINLOG sys_var::SESSION_VARIABLE_IN_BINLOG
58 #define NOT_IN_BINLOG sys_var::VARIABLE_NOT_IN_BINLOG
59 #define ON_READ(X) X
60 #define ON_CHECK(X) X
61 #define ON_UPDATE(X) X
62 #define READ_ONLY sys_var::READONLY+
63 #define NOT_VISIBLE sys_var::INVISIBLE+
64 // this means that Sys_var_charptr initial value was malloc()ed
65 #define PREALLOCATED sys_var::ALLOCATED+
66 /*
67   Sys_var_bit meaning is reversed, like in
68   @@foreign_key_checks <-> OPTION_NO_FOREIGN_KEY_CHECKS
69 */
70 #define REVERSE(X) ~(X)
71 #define DEPRECATED(X) X
72 
73 #define session_var(THD, TYPE) (*(TYPE*)session_var_ptr(THD))
74 #define global_var(TYPE) (*(TYPE*)global_var_ptr())
75 
76 #if SIZEOF_OFF_T > 4 && defined(BIG_TABLES)
77 #define GET_HA_ROWS GET_ULL
78 #else
79 #define GET_HA_ROWS GET_ULONG
80 #endif
81 
82 enum charset_enum {IN_SYSTEM_CHARSET, IN_FS_CHARSET};
83 
84 static const char *bool_values[3]= {"OFF", "ON", 0};
85 
86 /**
87   A small wrapper class to pass getopt arguments as a pair
88   to the Sys_var_* constructors. It improves type safety and helps
89   to catch errors in the argument order.
90 */
91 struct CMD_LINE
92 {
93   int id;
94   enum get_opt_arg_type arg_type;
95   CMD_LINE(enum get_opt_arg_type getopt_arg_type, int getopt_id=0)
idCMD_LINE96     : id(getopt_id), arg_type(getopt_arg_type) {}
97 };
98 
99 /**
100   Sys_var_integer template is used to generate Sys_var_* classes
101   for variables that represent the value as a signed or unsigned integer.
102   They are Sys_var_uint, Sys_var_ulong, Sys_var_harows, Sys_var_ulonglong,
103   and Sys_var_long.
104 
105   An integer variable has a minimal and maximal values, and a "block_size"
106   (any valid value of the variable must be divisible by the block_size).
107 
108   Class specific constructor arguments: min, max, block_size
109   Backing store: uint, ulong, ha_rows, ulonglong, long, depending on the
110   Sys_var_*
111 */
112 template
113   <typename T, ulong ARGT, enum enum_mysql_show_type SHOWT, bool SIGNED>
114 class Sys_var_integer: public sys_var
115 {
116 public:
117   Sys_var_integer(const char *name_arg,
118           const char *comment, int flag_args, ptrdiff_t off, size_t size,
119           CMD_LINE getopt,
120           T min_val, T max_val, T def_val, uint block_size, PolyLock *lock=0,
121           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
122           on_check_function on_check_func=0,
123           on_update_function on_update_func=0,
124           const char *substitute=0,
125           int parse_flag= PARSE_NORMAL)
126     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
127               getopt.arg_type, SHOWT, def_val, lock, binlog_status_arg,
128               on_check_func, on_update_func,
129               substitute, parse_flag)
130   {
131     option.var_type= ARGT;
132     option.min_value= min_val;
133     option.max_value= max_val;
134     option.block_size= block_size;
135     option.u_max_value= (uchar**)max_var_ptr();
136     if (max_var_ptr())
137       *max_var_ptr()= max_val;
138 
139     // Do not set global_var for Sys_var_keycache objects
140     if (offset >= 0)
141       global_var(T)= def_val;
142 
143     DBUG_ASSERT(size == sizeof(T));
144     DBUG_ASSERT(min_val < max_val);
145     DBUG_ASSERT(min_val <= def_val);
146     DBUG_ASSERT(max_val >= def_val);
147     DBUG_ASSERT(block_size > 0);
148     DBUG_ASSERT(def_val % block_size == 0);
149   }
150   bool do_check(THD *thd, set_var *var)
151   {
152     my_bool fixed= FALSE;
153     longlong v;
154     ulonglong uv;
155 
156     v= var->value->val_int();
157     if (SIGNED) /* target variable has signed type */
158     {
159       if (var->value->unsigned_flag)
160       {
161         /*
162           Input value is such a large positive number that MySQL used an
163           unsigned item to hold it. When cast to a signed longlong, if the
164           result is negative there is "cycling" and this is incorrect (large
165           positive input value should not end up as a large negative value in
166           the session signed variable to be set); instead, we need to pick the
167           allowed number closest to the positive input value, i.e. pick the
168           biggest allowed positive integer.
169         */
170         if (v < 0)
171           uv= max_of_int_range(ARGT);
172         else /* no cycling, longlong can hold true value */
173           uv= (ulonglong) v;
174       }
175       else
176         uv= v;
177       /* This will further restrict with VALID_RANGE, BLOCK_SIZE */
178       var->save_result.ulonglong_value=
179         getopt_ll_limit_value(uv, &option, &fixed);
180     }
181     else
182     {
183       if (var->value->unsigned_flag)
184       {
185         /* Guaranteed positive input value, ulonglong can hold it */
186         uv= (ulonglong) v;
187       }
188       else
189       {
190         /*
191           Maybe negative input value; in this case, cast to ulonglong makes it
192           positive, which is wrong. Pick the closest allowed value i.e. 0.
193         */
194         uv= (ulonglong) (v < 0 ? 0 : v);
195       }
196       var->save_result.ulonglong_value=
197         getopt_ull_limit_value(uv, &option, &fixed);
198     }
199 
200     if (max_var_ptr())
201     {
202       /* check constraint set with --maximum-...=X */
203       if (SIGNED)
204       {
205         longlong max_val= *max_var_ptr();
206         if (((longlong)(var->save_result.ulonglong_value)) > max_val)
207           var->save_result.ulonglong_value= max_val;
208         /*
209           Signed variable probably has some kind of symmetry. Then it's good
210           to limit negative values just as we limit positive values.
211         */
212         max_val= -max_val;
213         if (((longlong)(var->save_result.ulonglong_value)) < max_val)
214           var->save_result.ulonglong_value= max_val;
215       }
216       else
217       {
218         ulonglong max_val= *max_var_ptr();
219         if (var->save_result.ulonglong_value > max_val)
220           var->save_result.ulonglong_value= max_val;
221       }
222     }
223 
224     return throw_bounds_warning(thd, name.str,
225                                 var->save_result.ulonglong_value !=
226                                 (ulonglong)v,
227                                 var->value->unsigned_flag, v);
228   }
229   bool session_update(THD *thd, set_var *var)
230   {
231     session_var(thd, T)= var->save_result.ulonglong_value;
232     return false;
233   }
234   bool global_update(THD *thd, set_var *var)
235   {
236     global_var(T)= var->save_result.ulonglong_value;
237     return false;
238   }
239   bool check_update_type(Item_result type)
240   { return type != INT_RESULT; }
241   void session_save_default(THD *thd, set_var *var)
242   { var->save_result.ulonglong_value= (ulonglong)*(T*)global_value_ptr(thd, 0); }
243   void global_save_default(THD *thd, set_var *var)
244   { var->save_result.ulonglong_value= option.def_value; }
245   private:
246   T *max_var_ptr()
247   {
248     return scope() == SESSION ? (T*)(((uchar*)&max_system_variables) + offset)
249                               : 0;
250   }
251 };
252 
253 typedef Sys_var_integer<int32, GET_UINT, SHOW_INT, FALSE> Sys_var_int32;
254 typedef Sys_var_integer<uint, GET_UINT, SHOW_INT, FALSE> Sys_var_uint;
255 typedef Sys_var_integer<ulong, GET_ULONG, SHOW_LONG, FALSE> Sys_var_ulong;
256 typedef Sys_var_integer<ha_rows, GET_HA_ROWS, SHOW_HA_ROWS, FALSE>
257   Sys_var_harows;
258 typedef Sys_var_integer<ulonglong, GET_ULL, SHOW_LONGLONG, FALSE>
259   Sys_var_ulonglong;
260 typedef Sys_var_integer<long, GET_LONG, SHOW_SIGNED_LONG, TRUE> Sys_var_long;
261 
262 /**
263   Helper class for variables that take values from a TYPELIB
264 */
265 class Sys_var_typelib: public sys_var
266 {
267 protected:
268   TYPELIB typelib;
269 public:
270   Sys_var_typelib(const char *name_arg,
271           const char *comment, int flag_args, ptrdiff_t off,
272           CMD_LINE getopt,
273           SHOW_TYPE show_val_type_arg, const char *values[],
274           ulonglong def_val, PolyLock *lock,
275           enum binlog_status_enum binlog_status_arg,
276           on_check_function on_check_func, on_update_function on_update_func,
277           const char *substitute, int parse_flag= PARSE_NORMAL)
278     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
279               getopt.arg_type, show_val_type_arg, def_val, lock,
280               binlog_status_arg, on_check_func,
281               on_update_func, substitute, parse_flag)
282   {
283     for (typelib.count= 0; values[typelib.count]; typelib.count++) /*no-op */;
284     typelib.name="";
285     typelib.type_names= values;
286     typelib.type_lengths= 0;    // only used by Fields_enum and Field_set
287     option.typelib= &typelib;
288   }
do_check(THD * thd,set_var * var)289   bool do_check(THD *thd, set_var *var) // works for enums and my_bool
290   {
291     char buff[STRING_BUFFER_USUAL_SIZE];
292     String str(buff, sizeof(buff), system_charset_info), *res;
293 
294     if (var->value->result_type() == STRING_RESULT)
295     {
296       if (!(res=var->value->val_str(&str)))
297         return true;
298       else
299       if (!(var->save_result.ulonglong_value=
300             find_type(&typelib, res->ptr(), res->length(), false)))
301         return true;
302       else
303         var->save_result.ulonglong_value--;
304     }
305     else
306     {
307       longlong tmp=var->value->val_int();
308       if (tmp < 0 || tmp >= typelib.count)
309         return true;
310       else
311         var->save_result.ulonglong_value= tmp;
312     }
313 
314     return false;
315   }
check_update_type(Item_result type)316   bool check_update_type(Item_result type)
317   { return type != INT_RESULT && type != STRING_RESULT; }
318 };
319 
320 /**
321   The class for ENUM variables - variables that take one value from a fixed
322   list of values.
323 
324   Class specific constructor arguments:
325     char* values[]    - 0-terminated list of strings of valid values
326 
327   Backing store: uint
328 
329   @note
330   Do *not* use "enum FOO" variables as a backing store, there is no
331   guarantee that sizeof(enum FOO) == sizeof(uint), there is no guarantee
332   even that sizeof(enum FOO) == sizeof(enum BAR)
333 */
334 class Sys_var_enum: public Sys_var_typelib
335 {
336 public:
337   Sys_var_enum(const char *name_arg,
338           const char *comment, int flag_args, ptrdiff_t off, size_t size,
339           CMD_LINE getopt,
340           const char *values[], uint def_val, PolyLock *lock=0,
341           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
342           on_check_function on_check_func=0,
343           on_update_function on_update_func=0,
344           const char *substitute=0)
Sys_var_typelib(name_arg,comment,flag_args,off,getopt,SHOW_CHAR,values,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)345     : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
346                       SHOW_CHAR, values, def_val, lock,
347                       binlog_status_arg, on_check_func, on_update_func,
348                       substitute)
349   {
350     option.var_type= GET_ENUM;
351     global_var(ulong)= def_val;
352     DBUG_ASSERT(def_val < typelib.count);
353     DBUG_ASSERT(size == sizeof(ulong));
354   }
session_update(THD * thd,set_var * var)355   bool session_update(THD *thd, set_var *var)
356   {
357     session_var(thd, ulong)= var->save_result.ulonglong_value;
358     return false;
359   }
global_update(THD * thd,set_var * var)360   bool global_update(THD *thd, set_var *var)
361   {
362     global_var(ulong)= var->save_result.ulonglong_value;
363     return false;
364   }
session_save_default(THD * thd,set_var * var)365   void session_save_default(THD *thd, set_var *var)
366   { var->save_result.ulonglong_value= global_var(ulong); }
global_save_default(THD * thd,set_var * var)367   void global_save_default(THD *thd, set_var *var)
368   { var->save_result.ulonglong_value= option.def_value; }
session_value_ptr(THD * thd,LEX_STRING * base)369   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
370   { return (uchar*)typelib.type_names[session_var(thd, ulong)]; }
global_value_ptr(THD * thd,LEX_STRING * base)371   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
372   { return (uchar*)typelib.type_names[global_var(ulong)]; }
373 };
374 
375 /**
376   The class for boolean variables - a variant of ENUM variables
377   with the fixed list of values of { OFF , ON }
378 
379   Backing store: my_bool
380 */
381 class Sys_var_mybool: public Sys_var_typelib
382 {
383 public:
384   Sys_var_mybool(const char *name_arg,
385           const char *comment, int flag_args, ptrdiff_t off, size_t size,
386           CMD_LINE getopt,
387           my_bool def_val, PolyLock *lock=0,
388           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
389           on_check_function on_check_func=0,
390           on_update_function on_update_func=0,
391           const char *substitute=0,
392           int parse_flag= PARSE_NORMAL)
Sys_var_typelib(name_arg,comment,flag_args,off,getopt,SHOW_MY_BOOL,bool_values,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute,parse_flag)393     : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
394                       SHOW_MY_BOOL, bool_values, def_val, lock,
395                       binlog_status_arg, on_check_func, on_update_func,
396                       substitute, parse_flag)
397   {
398     option.var_type= GET_BOOL;
399     global_var(my_bool)= def_val;
400     DBUG_ASSERT(def_val < 2);
401     DBUG_ASSERT(getopt.arg_type == OPT_ARG || getopt.id == -1);
402     DBUG_ASSERT(size == sizeof(my_bool));
403   }
session_update(THD * thd,set_var * var)404   bool session_update(THD *thd, set_var *var)
405   {
406     session_var(thd, my_bool)= var->save_result.ulonglong_value;
407     return false;
408   }
global_update(THD * thd,set_var * var)409   bool global_update(THD *thd, set_var *var)
410   {
411     global_var(my_bool)= var->save_result.ulonglong_value;
412     return false;
413   }
session_save_default(THD * thd,set_var * var)414   void session_save_default(THD *thd, set_var *var)
415   { var->save_result.ulonglong_value= (ulonglong)*(my_bool *)global_value_ptr(thd, 0); }
global_save_default(THD * thd,set_var * var)416   void global_save_default(THD *thd, set_var *var)
417   { var->save_result.ulonglong_value= option.def_value; }
418 };
419 
420 /**
421   The class for string variables. The string can be in character_set_filesystem
422   or in character_set_system. The string can be allocated with my_malloc()
423   or not. The state of the initial value is specified in the constructor,
424   after that it's managed automatically. The value of NULL is supported.
425 
426   Class specific constructor arguments:
427     enum charset_enum is_os_charset_arg
428 
429   Backing store: char*
430 
431   @note
432   This class supports only GLOBAL variables, because THD on destruction
433   does not destroy individual members of SV, there's no way to free
434   allocated string variables for every thread.
435 */
436 class Sys_var_charptr: public sys_var
437 {
438 public:
439   Sys_var_charptr(const char *name_arg,
440           const char *comment, int flag_args, ptrdiff_t off, size_t size,
441           CMD_LINE getopt,
442           enum charset_enum is_os_charset_arg,
443           const char *def_val, PolyLock *lock=0,
444           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
445           on_check_function on_check_func=0,
446           on_update_function on_update_func=0,
447           const char *substitute=0,
448           int parse_flag= PARSE_NORMAL)
449     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
450               getopt.arg_type, SHOW_CHAR_PTR, (intptr)def_val,
451               lock, binlog_status_arg, on_check_func, on_update_func,
452               substitute, parse_flag)
453   {
454     is_os_charset= is_os_charset_arg == IN_FS_CHARSET;
455     /*
456      use GET_STR_ALLOC - if ALLOCATED it must be *always* allocated,
457      otherwise (GET_STR) you'll never know whether to free it or not.
458      (think of an exit because of an error right after my_getopt)
459     */
460     option.var_type= (flags & ALLOCATED) ? GET_STR_ALLOC : GET_STR;
461     global_var(const char*)= def_val;
462     DBUG_ASSERT(scope() == GLOBAL);
463     DBUG_ASSERT(size == sizeof(char *));
464   }
cleanup()465   void cleanup()
466   {
467     if (flags & ALLOCATED)
468       my_free(global_var(char*));
469     flags&= ~ALLOCATED;
470   }
do_check(THD * thd,set_var * var)471   bool do_check(THD *thd, set_var *var)
472   {
473     char buff[STRING_BUFFER_USUAL_SIZE], buff2[STRING_BUFFER_USUAL_SIZE];
474     String str(buff, sizeof(buff), charset(thd));
475     String str2(buff2, sizeof(buff2), charset(thd)), *res;
476 
477     if (!(res=var->value->val_str(&str)))
478       var->save_result.string_value.str= 0;
479     else
480     {
481       uint32 unused;
482       if (String::needs_conversion(res->length(), res->charset(),
483                                    charset(thd), &unused))
484       {
485         uint errors;
486         str2.copy(res->ptr(), res->length(), res->charset(), charset(thd),
487                   &errors);
488         res=&str2;
489 
490       }
491       var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
492       var->save_result.string_value.length= res->length();
493     }
494 
495     return false;
496   }
session_update(THD * thd,set_var * var)497   bool session_update(THD *thd, set_var *var)
498   {
499     DBUG_ASSERT(FALSE);
500     return true;
501   }
global_update(THD * thd,set_var * var)502   bool global_update(THD *thd, set_var *var)
503   {
504     char *new_val, *ptr= var->save_result.string_value.str;
505     size_t len=var->save_result.string_value.length;
506     if (ptr)
507     {
508       new_val= (char*)my_memdup(ptr, len+1, MYF(MY_WME));
509       if (!new_val) return true;
510       new_val[len]=0;
511     }
512     else
513       new_val= 0;
514     if (flags & ALLOCATED)
515       my_free(global_var(char*));
516     flags|= ALLOCATED;
517     global_var(char*)= new_val;
518     return false;
519   }
session_save_default(THD * thd,set_var * var)520   void session_save_default(THD *thd, set_var *var)
521   { DBUG_ASSERT(FALSE); }
global_save_default(THD * thd,set_var * var)522   void global_save_default(THD *thd, set_var *var)
523   {
524     char *ptr= (char*)(intptr)option.def_value;
525     var->save_result.string_value.str= ptr;
526     var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
527   }
check_update_type(Item_result type)528   bool check_update_type(Item_result type)
529   { return type != STRING_RESULT; }
530 };
531 
532 
533 class Sys_var_proxy_user: public sys_var
534 {
535 public:
Sys_var_proxy_user(const char * name_arg,const char * comment,enum charset_enum is_os_charset_arg)536   Sys_var_proxy_user(const char *name_arg,
537           const char *comment, enum charset_enum is_os_charset_arg)
538     : sys_var(&all_sys_vars, name_arg, comment,
539               sys_var::READONLY+sys_var::ONLY_SESSION, 0, -1,
540               NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
541               NULL, NULL, NULL, PARSE_NORMAL)
542   {
543     is_os_charset= is_os_charset_arg == IN_FS_CHARSET;
544     option.var_type= GET_STR;
545   }
do_check(THD * thd,set_var * var)546   bool do_check(THD *thd, set_var *var)
547   {
548     DBUG_ASSERT(FALSE);
549     return true;
550   }
session_update(THD * thd,set_var * var)551   bool session_update(THD *thd, set_var *var)
552   {
553     DBUG_ASSERT(FALSE);
554     return true;
555   }
global_update(THD * thd,set_var * var)556   bool global_update(THD *thd, set_var *var)
557   {
558     DBUG_ASSERT(FALSE);
559     return false;
560   }
session_save_default(THD * thd,set_var * var)561   void session_save_default(THD *thd, set_var *var)
562   { DBUG_ASSERT(FALSE); }
global_save_default(THD * thd,set_var * var)563   void global_save_default(THD *thd, set_var *var)
564   { DBUG_ASSERT(FALSE); }
check_update_type(Item_result type)565   bool check_update_type(Item_result type)
566   { return true; }
567 protected:
session_value_ptr(THD * thd,LEX_STRING * base)568   virtual uchar *session_value_ptr(THD *thd, LEX_STRING *base)
569   {
570     return thd->security_ctx->proxy_user[0] ?
571       (uchar *) &(thd->security_ctx->proxy_user[0]) : NULL;
572   }
573 };
574 
575 class Sys_var_external_user : public Sys_var_proxy_user
576 {
577 public:
Sys_var_external_user(const char * name_arg,const char * comment_arg,enum charset_enum is_os_charset_arg)578   Sys_var_external_user(const char *name_arg, const char *comment_arg,
579           enum charset_enum is_os_charset_arg)
580     : Sys_var_proxy_user (name_arg, comment_arg, is_os_charset_arg)
581   {}
582 
583 protected:
session_value_ptr(THD * thd,LEX_STRING * base)584   virtual uchar *session_value_ptr(THD *thd, LEX_STRING *base)
585   {
586     return thd->security_ctx->proxy_user[0] ?
587       (uchar *) &(thd->security_ctx->proxy_user[0]) : NULL;
588   }
589 };
590 
591 /**
592   The class for string variables. Useful for strings that aren't necessarily
593   \0-terminated. Otherwise the same as Sys_var_charptr.
594 
595   Class specific constructor arguments:
596     enum charset_enum is_os_charset_arg
597 
598   Backing store: LEX_STRING
599 
600   @note
601   Behaves exactly as Sys_var_charptr, only the backing store is different.
602 */
603 class Sys_var_lexstring: public Sys_var_charptr
604 {
605 public:
606   Sys_var_lexstring(const char *name_arg,
607           const char *comment, int flag_args, ptrdiff_t off, size_t size,
608           CMD_LINE getopt,
609           enum charset_enum is_os_charset_arg,
610           const char *def_val, PolyLock *lock=0,
611           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
612           on_check_function on_check_func=0,
613           on_update_function on_update_func=0,
614           const char *substitute=0)
Sys_var_charptr(name_arg,comment,flag_args,off,sizeof (char *),getopt,is_os_charset_arg,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)615     : Sys_var_charptr(name_arg, comment, flag_args, off, sizeof(char*),
616               getopt, is_os_charset_arg, def_val, lock, binlog_status_arg,
617               on_check_func, on_update_func, substitute)
618   {
619     global_var(LEX_STRING).length= strlen(def_val);
620     DBUG_ASSERT(size == sizeof(LEX_STRING));
621     *const_cast<SHOW_TYPE*>(&show_val_type)= SHOW_LEX_STRING;
622   }
global_update(THD * thd,set_var * var)623   bool global_update(THD *thd, set_var *var)
624   {
625     if (Sys_var_charptr::global_update(thd, var))
626       return true;
627     global_var(LEX_STRING).length= var->save_result.string_value.length;
628     return false;
629   }
630 };
631 
632 #ifndef DBUG_OFF
633 /**
634   @@session.dbug and @@global.dbug variables.
635 
636   @@dbug variable differs from other variables in one aspect:
637   if its value is not assigned in the session, it "points" to the global
638   value, and so when the global value is changed, the change
639   immediately takes effect in the session.
640 
641   This semantics is intentional, to be able to debug one session from
642   another.
643 */
644 class Sys_var_dbug: public sys_var
645 {
646 public:
647   Sys_var_dbug(const char *name_arg,
648                const char *comment, int flag_args,
649                CMD_LINE getopt,
650                const char *def_val, PolyLock *lock=0,
651                enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
652                on_check_function on_check_func=0,
653                on_update_function on_update_func=0,
654                const char *substitute=0,
655                int parse_flag= PARSE_NORMAL)
656     : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id,
657               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
658               lock, binlog_status_arg, on_check_func, on_update_func,
659               substitute, parse_flag)
660   { option.var_type= GET_NO_ARG; }
do_check(THD * thd,set_var * var)661   bool do_check(THD *thd, set_var *var)
662   {
663     char buff[STRING_BUFFER_USUAL_SIZE];
664     String str(buff, sizeof(buff), system_charset_info), *res;
665 
666     if (!(res=var->value->val_str(&str)))
667       var->save_result.string_value.str= const_cast<char*>("");
668     else
669       var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
670     return false;
671   }
session_update(THD * thd,set_var * var)672   bool session_update(THD *thd, set_var *var)
673   {
674     const char *val= var->save_result.string_value.str;
675     if (!var->value)
676       DBUG_POP();
677     else
678       DBUG_SET(val);
679     return false;
680   }
global_update(THD * thd,set_var * var)681   bool global_update(THD *thd, set_var *var)
682   {
683     const char *val= var->save_result.string_value.str;
684     DBUG_SET_INITIAL(val);
685     return false;
686   }
session_save_default(THD * thd,set_var * var)687   void session_save_default(THD *thd, set_var *var)
688   { }
global_save_default(THD * thd,set_var * var)689   void global_save_default(THD *thd, set_var *var)
690   {
691     char *ptr= (char*)(intptr)option.def_value;
692     var->save_result.string_value.str= ptr;
693   }
session_value_ptr(THD * thd,LEX_STRING * base)694   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
695   {
696     char buf[256];
697     DBUG_EXPLAIN(buf, sizeof(buf));
698     return (uchar*) thd->strdup(buf);
699   }
global_value_ptr(THD * thd,LEX_STRING * base)700   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
701   {
702     char buf[256];
703     DBUG_EXPLAIN_INITIAL(buf, sizeof(buf));
704     return (uchar*) thd->strdup(buf);
705   }
check_update_type(Item_result type)706   bool check_update_type(Item_result type)
707   { return type != STRING_RESULT; }
708 };
709 #endif
710 
711 #define KEYCACHE_VAR(X) sys_var::GLOBAL,offsetof(KEY_CACHE, X), sizeof(((KEY_CACHE *)0)->X)
712 #define keycache_var_ptr(KC, OFF) (((uchar*)(KC))+(OFF))
713 #define keycache_var(KC, OFF) (*(ulonglong*)keycache_var_ptr(KC, OFF))
714 typedef bool (*keycache_update_function)(THD *, KEY_CACHE *, ptrdiff_t, ulonglong);
715 
716 /**
717   The class for keycache_* variables. Supports structured names,
718   keycache_name.variable_name.
719 
720   Class specific constructor arguments:
721     everything derived from Sys_var_ulonglong
722 
723   Backing store: ulonglong
724 
725   @note these variables can be only GLOBAL
726 */
727 class Sys_var_keycache: public Sys_var_ulonglong
728 {
729   keycache_update_function keycache_update;
730 public:
731   Sys_var_keycache(const char *name_arg,
732           const char *comment, int flag_args, ptrdiff_t off, size_t size,
733           CMD_LINE getopt,
734           ulonglong min_val, ulonglong max_val, ulonglong def_val,
735           ulonglong block_size, PolyLock *lock,
736           enum binlog_status_enum binlog_status_arg,
737           on_check_function on_check_func,
738           keycache_update_function on_update_func,
739           const char *substitute=0)
740     : Sys_var_ulonglong(name_arg, comment, flag_args,
741                         -1,     /* offset, see base class CTOR */
742                         size,
743                         getopt, min_val, max_val, def_val,
744                         block_size, lock, binlog_status_arg, on_check_func, 0,
745                         substitute),
746     keycache_update(on_update_func)
747   {
748     offset= off; /* Remember offset in KEY_CACHE */
749     option.var_type|= GET_ASK_ADDR;
750     option.value= (uchar**)1; // crash me, please
751     keycache_var(dflt_key_cache, off)= def_val;
752     DBUG_ASSERT(scope() == GLOBAL);
753   }
global_update(THD * thd,set_var * var)754   bool global_update(THD *thd, set_var *var)
755   {
756     ulonglong new_value= var->save_result.ulonglong_value;
757     LEX_STRING *base_name= &var->base;
758     KEY_CACHE *key_cache;
759 
760     /* If no basename, assume it's for the key cache named 'default' */
761     if (!base_name->length)
762       base_name= &default_key_cache_base;
763 
764     key_cache= get_key_cache(base_name);
765 
766     if (!key_cache)
767     {                                           // Key cache didn't exists */
768       if (!new_value)                           // Tried to delete cache
769         return false;                           // Ok, nothing to do
770       if (!(key_cache= create_key_cache(base_name->str, base_name->length)))
771         return true;
772     }
773 
774     /**
775       Abort if some other thread is changing the key cache
776       @todo This should be changed so that we wait until the previous
777       assignment is done and then do the new assign
778     */
779     if (key_cache->in_init)
780       return true;
781 
782     return keycache_update(thd, key_cache, offset, new_value);
783   }
global_value_ptr(THD * thd,LEX_STRING * base)784   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
785   {
786     KEY_CACHE *key_cache= get_key_cache(base);
787     if (!key_cache)
788       key_cache= &zero_key_cache;
789     return keycache_var_ptr(key_cache, offset);
790   }
791 };
792 
793 /**
794   The class for floating point variables
795 
796   Class specific constructor arguments: min, max
797 
798   Backing store: double
799 */
800 class Sys_var_double: public sys_var
801 {
802 public:
803   Sys_var_double(const char *name_arg,
804           const char *comment, int flag_args, ptrdiff_t off, size_t size,
805           CMD_LINE getopt,
806           double min_val, double max_val, double def_val, PolyLock *lock=0,
807           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
808           on_check_function on_check_func=0,
809           on_update_function on_update_func=0,
810           const char *substitute=0,
811           int parse_flag= PARSE_NORMAL)
812     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
813               getopt.arg_type, SHOW_DOUBLE,
814               (longlong) getopt_double2ulonglong(def_val),
815               lock, binlog_status_arg, on_check_func, on_update_func,
816               substitute, parse_flag)
817   {
818     option.var_type= GET_DOUBLE;
819     option.min_value= (longlong) getopt_double2ulonglong(min_val);
820     option.max_value= (longlong) getopt_double2ulonglong(max_val);
821     global_var(double)= (double)option.def_value;
822     DBUG_ASSERT(min_val <= max_val);
823     DBUG_ASSERT(min_val <= def_val);
824     DBUG_ASSERT(max_val >= def_val);
825     DBUG_ASSERT(size == sizeof(double));
826   }
do_check(THD * thd,set_var * var)827   bool do_check(THD *thd, set_var *var)
828   {
829     my_bool fixed;
830     double v= var->value->val_real();
831     var->save_result.double_value= getopt_double_limit_value(v, &option, &fixed);
832 
833     return throw_bounds_warning(thd, name.str, fixed, v);
834   }
session_update(THD * thd,set_var * var)835   bool session_update(THD *thd, set_var *var)
836   {
837     session_var(thd, double)= var->save_result.double_value;
838     return false;
839   }
global_update(THD * thd,set_var * var)840   bool global_update(THD *thd, set_var *var)
841   {
842     global_var(double)= var->save_result.double_value;
843     return false;
844   }
check_update_type(Item_result type)845   bool check_update_type(Item_result type)
846   {
847     return type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT;
848   }
session_save_default(THD * thd,set_var * var)849   void session_save_default(THD *thd, set_var *var)
850   { var->save_result.double_value= global_var(double); }
global_save_default(THD * thd,set_var * var)851   void global_save_default(THD *thd, set_var *var)
852   { var->save_result.double_value= getopt_ulonglong2double(option.def_value); }
853 };
854 
855 /**
856   The class for @test_flags (core_file for now).
857   It's derived from Sys_var_mybool.
858 
859   Class specific constructor arguments:
860     Caller need not pass in a variable as we make up the value on the
861     fly, that is, we derive it from the global test_flags bit vector.
862 
863   Backing store: my_bool
864 */
865 class Sys_var_test_flag: public Sys_var_mybool
866 {
867 private:
868   my_bool test_flag_value;
869   uint    test_flag_mask;
870 public:
Sys_var_test_flag(const char * name_arg,const char * comment,uint mask)871   Sys_var_test_flag(const char *name_arg, const char *comment, uint mask)
872   : Sys_var_mybool(name_arg, comment, READ_ONLY GLOBAL_VAR(test_flag_value),
873           NO_CMD_LINE, DEFAULT(FALSE))
874   {
875     test_flag_mask= mask;
876   }
global_value_ptr(THD * thd,LEX_STRING * base)877   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
878   {
879     test_flag_value= ((test_flags & test_flag_mask) > 0);
880     return (uchar*) &test_flag_value;
881   }
882 };
883 
884 /**
885   The class for the @max_user_connections.
886   It's derived from Sys_var_uint, but non-standard session value
887   requires a new class.
888 
889   Class specific constructor arguments:
890     everything derived from Sys_var_uint
891 
892   Backing store: uint
893 */
894 class Sys_var_max_user_conn: public Sys_var_uint
895 {
896 public:
897   Sys_var_max_user_conn(const char *name_arg,
898           const char *comment, int flag_args, ptrdiff_t off, size_t size,
899           CMD_LINE getopt,
900           uint min_val, uint max_val, uint def_val,
901           uint block_size, PolyLock *lock=0,
902           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
903           on_check_function on_check_func=0,
904           on_update_function on_update_func=0,
905           const char *substitute=0)
Sys_var_uint(name_arg,comment,SESSION,off,size,getopt,min_val,max_val,def_val,block_size,lock,binlog_status_arg,on_check_func,on_update_func,substitute)906     : Sys_var_uint(name_arg, comment, SESSION, off, size, getopt,
907               min_val, max_val, def_val, block_size,
908               lock, binlog_status_arg, on_check_func, on_update_func,
909               substitute)
910   { }
session_value_ptr(THD * thd,LEX_STRING * base)911   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
912   {
913     const USER_CONN *uc= thd->get_user_connect();
914     if (uc && uc->user_resources.user_conn)
915       return (uchar*) &(uc->user_resources.user_conn);
916     return global_value_ptr(thd, base);
917   }
918 };
919 
920 // overflow-safe (1 << X)-1
921 #define MAX_SET(X) ((((1UL << ((X)-1))-1) << 1) | 1)
922 
923 /**
924   The class for flagset variables - a variant of SET that allows in-place
925   editing (turning on/off individual bits). String representations looks like
926   a "flag=val,flag=val,...". Example: @@optimizer_switch
927 
928   Class specific constructor arguments:
929     char* values[]    - 0-terminated list of strings of valid values
930 
931   Backing store: ulonglong
932 
933   @note
934   the last value in the values[] array should
935   *always* be the string "default".
936 */
937 class Sys_var_flagset: public Sys_var_typelib
938 {
939 public:
940   Sys_var_flagset(const char *name_arg,
941           const char *comment, int flag_args, ptrdiff_t off, size_t size,
942           CMD_LINE getopt,
943           const char *values[], ulonglong def_val, PolyLock *lock=0,
944           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
945           on_check_function on_check_func=0,
946           on_update_function on_update_func=0,
947           const char *substitute=0)
Sys_var_typelib(name_arg,comment,flag_args,off,getopt,SHOW_CHAR,values,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)948     : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
949                       SHOW_CHAR, values, def_val, lock,
950                       binlog_status_arg, on_check_func, on_update_func,
951                       substitute)
952   {
953     option.var_type= GET_FLAGSET;
954     global_var(ulonglong)= def_val;
955     DBUG_ASSERT(typelib.count > 1);
956     DBUG_ASSERT(typelib.count <= 65);
957     DBUG_ASSERT(def_val < MAX_SET(typelib.count));
958     DBUG_ASSERT(strcmp(values[typelib.count-1], "default") == 0);
959     DBUG_ASSERT(size == sizeof(ulonglong));
960   }
do_check(THD * thd,set_var * var)961   bool do_check(THD *thd, set_var *var)
962   {
963     char buff[STRING_BUFFER_USUAL_SIZE];
964     String str(buff, sizeof(buff), system_charset_info), *res;
965     ulonglong default_value, current_value;
966     if (var->type == OPT_GLOBAL)
967     {
968       default_value= option.def_value;
969       current_value= global_var(ulonglong);
970     }
971     else
972     {
973       default_value= global_var(ulonglong);
974       current_value= session_var(thd, ulonglong);
975     }
976 
977     if (var->value->result_type() == STRING_RESULT)
978     {
979       if (!(res=var->value->val_str(&str)))
980         return true;
981       else
982       {
983         char *error;
984         uint error_len;
985 
986         var->save_result.ulonglong_value=
987               find_set_from_flags(&typelib,
988                                   typelib.count,
989                                   current_value,
990                                   default_value,
991                                   res->ptr(), res->length(),
992                                   &error, &error_len);
993         if (error)
994         {
995           ErrConvString err(error, error_len, res->charset());
996           my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
997           return true;
998         }
999       }
1000     }
1001     else
1002     {
1003       longlong tmp=var->value->val_int();
1004       if ((tmp < 0 && ! var->value->unsigned_flag)
1005           || (ulonglong)tmp > MAX_SET(typelib.count))
1006         return true;
1007       else
1008         var->save_result.ulonglong_value= tmp;
1009     }
1010 
1011     return false;
1012   }
session_update(THD * thd,set_var * var)1013   bool session_update(THD *thd, set_var *var)
1014   {
1015     session_var(thd, ulonglong)= var->save_result.ulonglong_value;
1016     return false;
1017   }
global_update(THD * thd,set_var * var)1018   bool global_update(THD *thd, set_var *var)
1019   {
1020     global_var(ulonglong)= var->save_result.ulonglong_value;
1021     return false;
1022   }
session_save_default(THD * thd,set_var * var)1023   void session_save_default(THD *thd, set_var *var)
1024   { var->save_result.ulonglong_value= global_var(ulonglong); }
global_save_default(THD * thd,set_var * var)1025   void global_save_default(THD *thd, set_var *var)
1026   { var->save_result.ulonglong_value= option.def_value; }
session_value_ptr(THD * thd,LEX_STRING * base)1027   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
1028   {
1029     return (uchar*)flagset_to_string(thd, 0, session_var(thd, ulonglong),
1030                                      typelib.type_names);
1031   }
global_value_ptr(THD * thd,LEX_STRING * base)1032   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1033   {
1034     return (uchar*)flagset_to_string(thd, 0, global_var(ulonglong),
1035                                      typelib.type_names);
1036   }
1037 };
1038 
1039 /**
1040   The class for SET variables - variables taking zero or more values
1041   from the given list. Example: @@sql_mode
1042 
1043   Class specific constructor arguments:
1044     char* values[]    - 0-terminated list of strings of valid values
1045 
1046   Backing store: ulonglong
1047 */
1048 class Sys_var_set: public Sys_var_typelib
1049 {
1050 public:
1051   Sys_var_set(const char *name_arg,
1052           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1053           CMD_LINE getopt,
1054           const char *values[], ulonglong def_val, PolyLock *lock=0,
1055           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1056           on_check_function on_check_func=0,
1057           on_update_function on_update_func=0,
1058           const char *substitute=0)
Sys_var_typelib(name_arg,comment,flag_args,off,getopt,SHOW_CHAR,values,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)1059     : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
1060                       SHOW_CHAR, values, def_val, lock,
1061                       binlog_status_arg, on_check_func, on_update_func,
1062                       substitute)
1063   {
1064     option.var_type= GET_SET;
1065     global_var(ulonglong)= def_val;
1066     DBUG_ASSERT(typelib.count > 0);
1067     DBUG_ASSERT(typelib.count <= 64);
1068     DBUG_ASSERT(def_val < MAX_SET(typelib.count));
1069     DBUG_ASSERT(size == sizeof(ulonglong));
1070   }
do_check(THD * thd,set_var * var)1071   bool do_check(THD *thd, set_var *var)
1072   {
1073     char buff[STRING_BUFFER_USUAL_SIZE];
1074     String str(buff, sizeof(buff), system_charset_info), *res;
1075 
1076     if (var->value->result_type() == STRING_RESULT)
1077     {
1078       if (!(res=var->value->val_str(&str)))
1079         return true;
1080       else
1081       {
1082         char *error;
1083         uint error_len;
1084         bool not_used;
1085 
1086         var->save_result.ulonglong_value=
1087               find_set(&typelib, res->ptr(), res->length(), NULL,
1088                       &error, &error_len, &not_used);
1089         /*
1090           note, we only issue an error if error_len > 0.
1091           That is even while empty (zero-length) values are considered
1092           errors by find_set(), these errors are ignored here
1093         */
1094         if (error_len)
1095         {
1096           ErrConvString err(error, error_len, res->charset());
1097           my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
1098           return true;
1099         }
1100       }
1101     }
1102     else
1103     {
1104       longlong tmp=var->value->val_int();
1105       if ((tmp < 0 && ! var->value->unsigned_flag)
1106           || (ulonglong)tmp > MAX_SET(typelib.count))
1107         return true;
1108       else
1109         var->save_result.ulonglong_value= tmp;
1110     }
1111 
1112     return false;
1113   }
session_update(THD * thd,set_var * var)1114   bool session_update(THD *thd, set_var *var)
1115   {
1116     session_var(thd, ulonglong)= var->save_result.ulonglong_value;
1117     return false;
1118   }
global_update(THD * thd,set_var * var)1119   bool global_update(THD *thd, set_var *var)
1120   {
1121     global_var(ulonglong)= var->save_result.ulonglong_value;
1122     return false;
1123   }
session_save_default(THD * thd,set_var * var)1124   void session_save_default(THD *thd, set_var *var)
1125   { var->save_result.ulonglong_value= global_var(ulonglong); }
global_save_default(THD * thd,set_var * var)1126   void global_save_default(THD *thd, set_var *var)
1127   { var->save_result.ulonglong_value= option.def_value; }
session_value_ptr(THD * thd,LEX_STRING * base)1128   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
1129   {
1130     return (uchar*)set_to_string(thd, 0, session_var(thd, ulonglong),
1131                                  typelib.type_names);
1132   }
global_value_ptr(THD * thd,LEX_STRING * base)1133   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1134   {
1135     return (uchar*)set_to_string(thd, 0, global_var(ulonglong),
1136                                  typelib.type_names);
1137   }
1138 };
1139 
1140 /**
1141   The class for variables which value is a plugin.
1142   Example: @@default_storage_engine
1143 
1144   Class specific constructor arguments:
1145     int plugin_type_arg (for example MYSQL_STORAGE_ENGINE_PLUGIN)
1146 
1147   Backing store: plugin_ref
1148 
1149   @note
1150   these variables don't support command-line equivalents, any such
1151   command-line options should be added manually to my_long_options in mysqld.cc
1152 */
1153 class Sys_var_plugin: public sys_var
1154 {
1155   int plugin_type;
1156 public:
1157   Sys_var_plugin(const char *name_arg,
1158           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1159           CMD_LINE getopt,
1160           int plugin_type_arg, char **def_val, PolyLock *lock=0,
1161           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1162           on_check_function on_check_func=0,
1163           on_update_function on_update_func=0,
1164           const char *substitute=0,
1165           int parse_flag= PARSE_NORMAL)
1166     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
1167               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
1168               lock, binlog_status_arg, on_check_func, on_update_func,
1169               substitute, parse_flag),
1170     plugin_type(plugin_type_arg)
1171   {
1172     option.var_type= GET_STR;
1173     DBUG_ASSERT(size == sizeof(plugin_ref));
1174     DBUG_ASSERT(getopt.id == -1); // force NO_CMD_LINE
1175   }
do_check(THD * thd,set_var * var)1176   bool do_check(THD *thd, set_var *var)
1177   {
1178     char buff[STRING_BUFFER_USUAL_SIZE];
1179     String str(buff,sizeof(buff), system_charset_info), *res;
1180     if (!(res=var->value->val_str(&str)))
1181       var->save_result.plugin= NULL;
1182     else
1183     {
1184       const LEX_STRING pname= { const_cast<char*>(res->ptr()), res->length() };
1185       plugin_ref plugin;
1186 
1187       // special code for storage engines (e.g. to handle historical aliases)
1188       if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
1189         plugin= ha_resolve_by_name(thd, &pname, FALSE);
1190       else
1191         plugin= my_plugin_lock_by_name(thd, &pname, plugin_type);
1192       if (!plugin)
1193       {
1194         // historically different error code
1195         if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
1196         {
1197           ErrConvString err(res);
1198           my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), err.ptr());
1199         }
1200         return true;
1201       }
1202       var->save_result.plugin= plugin;
1203     }
1204     return false;
1205   }
do_update(plugin_ref * valptr,plugin_ref newval)1206   void do_update(plugin_ref *valptr, plugin_ref newval)
1207   {
1208     plugin_ref oldval= *valptr;
1209     if (oldval != newval)
1210     {
1211       *valptr= my_plugin_lock(NULL, &newval);
1212       plugin_unlock(NULL, oldval);
1213     }
1214   }
session_update(THD * thd,set_var * var)1215   bool session_update(THD *thd, set_var *var)
1216   {
1217     do_update((plugin_ref*)session_var_ptr(thd),
1218               var->save_result.plugin);
1219     return false;
1220   }
global_update(THD * thd,set_var * var)1221   bool global_update(THD *thd, set_var *var)
1222   {
1223     do_update((plugin_ref*)global_var_ptr(),
1224               var->save_result.plugin);
1225     return false;
1226   }
session_save_default(THD * thd,set_var * var)1227   void session_save_default(THD *thd, set_var *var)
1228   {
1229     plugin_ref plugin= global_var(plugin_ref);
1230     var->save_result.plugin= my_plugin_lock(thd, &plugin);
1231   }
global_save_default(THD * thd,set_var * var)1232   void global_save_default(THD *thd, set_var *var)
1233   {
1234     LEX_STRING pname;
1235     char **default_value= reinterpret_cast<char**>(option.def_value);
1236     pname.str= *default_value;
1237     pname.length= strlen(pname.str);
1238 
1239     plugin_ref plugin;
1240     if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
1241       plugin= ha_resolve_by_name(thd, &pname, FALSE);
1242     else
1243       plugin= my_plugin_lock_by_name(thd, &pname, plugin_type);
1244     DBUG_ASSERT(plugin);
1245 
1246     var->save_result.plugin= my_plugin_lock(thd, &plugin);
1247   }
check_update_type(Item_result type)1248   bool check_update_type(Item_result type)
1249   { return type != STRING_RESULT; }
session_value_ptr(THD * thd,LEX_STRING * base)1250   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
1251   {
1252     plugin_ref plugin= session_var(thd, plugin_ref);
1253     return (uchar*)(plugin ? thd->strmake(plugin_name(plugin)->str,
1254                                           plugin_name(plugin)->length) : 0);
1255   }
global_value_ptr(THD * thd,LEX_STRING * base)1256   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1257   {
1258     plugin_ref plugin= global_var(plugin_ref);
1259     return (uchar*)(plugin ? thd->strmake(plugin_name(plugin)->str,
1260                                           plugin_name(plugin)->length) : 0);
1261   }
1262 };
1263 
1264 #if defined(ENABLED_DEBUG_SYNC)
1265 /**
1266   The class for @@debug_sync session-only variable
1267 */
1268 class Sys_var_debug_sync :public sys_var
1269 {
1270 public:
1271   Sys_var_debug_sync(const char *name_arg,
1272                const char *comment, int flag_args,
1273                CMD_LINE getopt,
1274                const char *def_val, PolyLock *lock=0,
1275                enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1276                on_check_function on_check_func=0,
1277                on_update_function on_update_func=0,
1278                const char *substitute=0,
1279                int parse_flag= PARSE_NORMAL)
1280     : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id,
1281               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
1282               lock, binlog_status_arg, on_check_func, on_update_func,
1283               substitute, parse_flag)
1284   {
1285     DBUG_ASSERT(scope() == ONLY_SESSION);
1286     option.var_type= GET_NO_ARG;
1287   }
do_check(THD * thd,set_var * var)1288   bool do_check(THD *thd, set_var *var)
1289   {
1290     char buff[STRING_BUFFER_USUAL_SIZE];
1291     String str(buff, sizeof(buff), system_charset_info), *res;
1292 
1293     if (!(res=var->value->val_str(&str)))
1294       var->save_result.string_value.str= const_cast<char*>("");
1295     else
1296       var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
1297     return false;
1298   }
session_update(THD * thd,set_var * var)1299   bool session_update(THD *thd, set_var *var)
1300   {
1301     extern bool debug_sync_update(THD *thd, char *val_str);
1302     return debug_sync_update(thd, var->save_result.string_value.str);
1303   }
global_update(THD * thd,set_var * var)1304   bool global_update(THD *thd, set_var *var)
1305   {
1306     DBUG_ASSERT(FALSE);
1307     return true;
1308   }
session_save_default(THD * thd,set_var * var)1309   void session_save_default(THD *thd, set_var *var)
1310   {
1311     var->save_result.string_value.str= const_cast<char*>("");
1312     var->save_result.string_value.length= 0;
1313   }
global_save_default(THD * thd,set_var * var)1314   void global_save_default(THD *thd, set_var *var)
1315   {
1316     DBUG_ASSERT(FALSE);
1317   }
session_value_ptr(THD * thd,LEX_STRING * base)1318   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
1319   {
1320     extern uchar *debug_sync_value_ptr(THD *thd);
1321     return debug_sync_value_ptr(thd);
1322   }
global_value_ptr(THD * thd,LEX_STRING * base)1323   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1324   {
1325     DBUG_ASSERT(FALSE);
1326     return 0;
1327   }
check_update_type(Item_result type)1328   bool check_update_type(Item_result type)
1329   { return type != STRING_RESULT; }
1330 };
1331 #endif /* defined(ENABLED_DEBUG_SYNC) */
1332 
1333 /**
1334   The class for bit variables - a variant of boolean that stores the value
1335   in a bit.
1336 
1337   Class specific constructor arguments:
1338     ulonglong bitmask_arg - the mask for the bit to set in the ulonglong
1339                             backing store
1340 
1341   Backing store: ulonglong
1342 
1343   @note
1344   This class supports the "reverse" semantics, when the value of the bit
1345   being 0 corresponds to the value of variable being set. To activate it
1346   use REVERSE(bitmask) instead of simply bitmask in the constructor.
1347 
1348   @note
1349   variables of this class cannot be set from the command line as
1350   my_getopt does not support bits.
1351 */
1352 class Sys_var_bit: public Sys_var_typelib
1353 {
1354   ulonglong bitmask;
1355   bool reverse_semantics;
set(uchar * ptr,ulonglong value)1356   void set(uchar *ptr, ulonglong value)
1357   {
1358     if ((value != 0) ^ reverse_semantics)
1359       (*(ulonglong *)ptr)|= bitmask;
1360     else
1361       (*(ulonglong *)ptr)&= ~bitmask;
1362   }
1363 public:
1364   Sys_var_bit(const char *name_arg,
1365           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1366           CMD_LINE getopt,
1367           ulonglong bitmask_arg, my_bool def_val, PolyLock *lock=0,
1368           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1369           on_check_function on_check_func=0,
1370           on_update_function on_update_func=0,
1371           const char *substitute=0)
Sys_var_typelib(name_arg,comment,flag_args,off,getopt,SHOW_MY_BOOL,bool_values,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)1372     : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
1373                       SHOW_MY_BOOL, bool_values, def_val, lock,
1374                       binlog_status_arg, on_check_func, on_update_func,
1375                       substitute)
1376   {
1377     option.var_type= GET_BOOL;
1378     reverse_semantics= my_count_bits(bitmask_arg) > 1;
1379     bitmask= reverse_semantics ? ~bitmask_arg : bitmask_arg;
1380     set(global_var_ptr(), def_val);
1381     DBUG_ASSERT(def_val < 2);
1382     DBUG_ASSERT(getopt.id == -1); // force NO_CMD_LINE
1383     DBUG_ASSERT(size == sizeof(ulonglong));
1384   }
session_update(THD * thd,set_var * var)1385   bool session_update(THD *thd, set_var *var)
1386   {
1387     set(session_var_ptr(thd), var->save_result.ulonglong_value);
1388     return false;
1389   }
global_update(THD * thd,set_var * var)1390   bool global_update(THD *thd, set_var *var)
1391   {
1392     set(global_var_ptr(), var->save_result.ulonglong_value);
1393     return false;
1394   }
session_save_default(THD * thd,set_var * var)1395   void session_save_default(THD *thd, set_var *var)
1396   { var->save_result.ulonglong_value= global_var(ulonglong) & bitmask; }
global_save_default(THD * thd,set_var * var)1397   void global_save_default(THD *thd, set_var *var)
1398   { var->save_result.ulonglong_value= option.def_value; }
session_value_ptr(THD * thd,LEX_STRING * base)1399   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
1400   {
1401     thd->sys_var_tmp.my_bool_value= reverse_semantics ^
1402       ((session_var(thd, ulonglong) & bitmask) != 0);
1403     return (uchar*) &thd->sys_var_tmp.my_bool_value;
1404   }
global_value_ptr(THD * thd,LEX_STRING * base)1405   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1406   {
1407     thd->sys_var_tmp.my_bool_value= reverse_semantics ^
1408       ((global_var(ulonglong) & bitmask) != 0);
1409     return (uchar*) &thd->sys_var_tmp.my_bool_value;
1410   }
1411 };
1412 
1413 /**
1414   The class for variables that have a special meaning for a session,
1415   such as @@timestamp or @@rnd_seed1, their values typically cannot be read
1416   from SV structure, and a special "read" callback is provided.
1417 
1418   Class specific constructor arguments:
1419     everything derived from Sys_var_ulonglong
1420     session_special_read_function read_func_arg
1421 
1422   Backing store: ulonglong
1423 
1424   @note
1425   These variables are session-only, global or command-line equivalents
1426   are not supported as they're generally meaningless.
1427 */
1428 class Sys_var_session_special: public Sys_var_ulonglong
1429 {
1430   typedef bool (*session_special_update_function)(THD *thd, set_var *var);
1431   typedef ulonglong (*session_special_read_function)(THD *thd);
1432 
1433   session_special_read_function read_func;
1434   session_special_update_function update_func;
1435 public:
1436   Sys_var_session_special(const char *name_arg,
1437                const char *comment, int flag_args,
1438                CMD_LINE getopt,
1439                ulonglong min_val, ulonglong max_val, ulonglong block_size,
1440                PolyLock *lock, enum binlog_status_enum binlog_status_arg,
1441                on_check_function on_check_func,
1442                session_special_update_function update_func_arg,
1443                session_special_read_function read_func_arg,
1444                const char *substitute=0)
1445     : Sys_var_ulonglong(name_arg, comment, flag_args, 0,
1446               sizeof(ulonglong), getopt, min_val,
1447               max_val, 0, block_size, lock, binlog_status_arg, on_check_func, 0,
1448               substitute),
1449       read_func(read_func_arg), update_func(update_func_arg)
1450   {
1451     DBUG_ASSERT(scope() == ONLY_SESSION);
1452     DBUG_ASSERT(getopt.id == -1); // NO_CMD_LINE, because the offset is fake
1453   }
session_update(THD * thd,set_var * var)1454   bool session_update(THD *thd, set_var *var)
1455   { return update_func(thd, var); }
global_update(THD * thd,set_var * var)1456   bool global_update(THD *thd, set_var *var)
1457   {
1458     DBUG_ASSERT(FALSE);
1459     return true;
1460   }
session_save_default(THD * thd,set_var * var)1461   void session_save_default(THD *thd, set_var *var)
1462   { var->value= 0; }
global_save_default(THD * thd,set_var * var)1463   void global_save_default(THD *thd, set_var *var)
1464   { DBUG_ASSERT(FALSE); }
session_value_ptr(THD * thd,LEX_STRING * base)1465   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
1466   {
1467     thd->sys_var_tmp.ulonglong_value= read_func(thd);
1468     return (uchar*) &thd->sys_var_tmp.ulonglong_value;
1469   }
global_value_ptr(THD * thd,LEX_STRING * base)1470   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1471   {
1472     DBUG_ASSERT(FALSE);
1473     return 0;
1474   }
1475 };
1476 
1477 
1478 /**
1479   Similar to Sys_var_session_special, but with double storage.
1480 */
1481 class Sys_var_session_special_double: public Sys_var_double
1482 {
1483   typedef bool (*session_special_update_function)(THD *thd, set_var *var);
1484   typedef double (*session_special_read_double_function)(THD *thd);
1485 
1486   session_special_read_double_function read_func;
1487   session_special_update_function update_func;
1488 public:
1489   Sys_var_session_special_double(const char *name_arg,
1490                const char *comment, int flag_args,
1491                CMD_LINE getopt,
1492                ulonglong min_val, ulonglong max_val, ulonglong block_size,
1493                PolyLock *lock, enum binlog_status_enum binlog_status_arg,
1494                on_check_function on_check_func,
1495                session_special_update_function update_func_arg,
1496                session_special_read_double_function read_func_arg,
1497                const char *substitute=0)
1498     : Sys_var_double(name_arg, comment, flag_args, 0,
1499               sizeof(double), getopt,
1500               min_val, max_val, 0,
1501               lock, binlog_status_arg, on_check_func, 0,
1502               substitute),
1503       read_func(read_func_arg), update_func(update_func_arg)
1504   {
1505     DBUG_ASSERT(scope() == ONLY_SESSION);
1506     DBUG_ASSERT(getopt.id == -1); // NO_CMD_LINE, because the offset is fake
1507   }
session_update(THD * thd,set_var * var)1508   bool session_update(THD *thd, set_var *var)
1509   { return update_func(thd, var); }
global_update(THD * thd,set_var * var)1510   bool global_update(THD *thd, set_var *var)
1511   {
1512     DBUG_ASSERT(FALSE);
1513     return true;
1514   }
session_save_default(THD * thd,set_var * var)1515   void session_save_default(THD *thd, set_var *var)
1516   { var->value= 0; }
global_save_default(THD * thd,set_var * var)1517   void global_save_default(THD *thd, set_var *var)
1518   { DBUG_ASSERT(FALSE); }
session_value_ptr(THD * thd,LEX_STRING * base)1519   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
1520   {
1521     thd->sys_var_tmp.double_value= read_func(thd);
1522     return (uchar *) &thd->sys_var_tmp.double_value;
1523   }
global_value_ptr(THD * thd,LEX_STRING * base)1524   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1525   {
1526     DBUG_ASSERT(FALSE);
1527     return 0;
1528   }
1529 };
1530 
1531 
1532 /**
1533   The class for read-only variables that show whether a particular
1534   feature is supported by the server. Example: have_compression
1535 
1536   Backing store: enum SHOW_COMP_OPTION
1537 
1538   @note
1539   These variables are necessarily read-only, only global, and have no
1540   command-line equivalent.
1541 */
1542 class Sys_var_have: public sys_var
1543 {
1544 public:
1545   Sys_var_have(const char *name_arg,
1546                const char *comment, int flag_args, ptrdiff_t off, size_t size,
1547                CMD_LINE getopt,
1548                PolyLock *lock=0,
1549                enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1550                on_check_function on_check_func=0,
1551                on_update_function on_update_func=0,
1552                const char *substitute=0,
1553                int parse_flag= PARSE_NORMAL)
1554     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
1555               getopt.arg_type, SHOW_CHAR, 0,
1556               lock, binlog_status_arg, on_check_func, on_update_func,
1557               substitute, parse_flag)
1558   {
1559     DBUG_ASSERT(scope() == GLOBAL);
1560     DBUG_ASSERT(getopt.id == -1);
1561     DBUG_ASSERT(lock == 0);
1562     DBUG_ASSERT(binlog_status_arg == VARIABLE_NOT_IN_BINLOG);
1563     DBUG_ASSERT(is_readonly());
1564     DBUG_ASSERT(on_update == 0);
1565     DBUG_ASSERT(size == sizeof(enum SHOW_COMP_OPTION));
1566   }
do_check(THD * thd,set_var * var)1567   bool do_check(THD *thd, set_var *var) {
1568     DBUG_ASSERT(FALSE);
1569     return true;
1570   }
session_update(THD * thd,set_var * var)1571   bool session_update(THD *thd, set_var *var)
1572   {
1573     DBUG_ASSERT(FALSE);
1574     return true;
1575   }
global_update(THD * thd,set_var * var)1576   bool global_update(THD *thd, set_var *var)
1577   {
1578     DBUG_ASSERT(FALSE);
1579     return true;
1580   }
session_save_default(THD * thd,set_var * var)1581   void session_save_default(THD *thd, set_var *var) { }
global_save_default(THD * thd,set_var * var)1582   void global_save_default(THD *thd, set_var *var) { }
session_value_ptr(THD * thd,LEX_STRING * base)1583   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
1584   {
1585     DBUG_ASSERT(FALSE);
1586     return 0;
1587   }
global_value_ptr(THD * thd,LEX_STRING * base)1588   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1589   {
1590     return (uchar*)show_comp_option_name[global_var(enum SHOW_COMP_OPTION)];
1591   }
check_update_type(Item_result type)1592   bool check_update_type(Item_result type) { return false; }
1593 };
1594 
1595 /**
1596   Generic class for variables for storing entities that are internally
1597   represented as structures, have names, and possibly can be referred to by
1598   numbers.  Examples: character sets, collations, locales,
1599 
1600   Class specific constructor arguments:
1601     ptrdiff_t name_offset  - offset of the 'name' field in the structure
1602 
1603   Backing store: void*
1604 
1605   @note
1606   As every such a structure requires special treatment from my_getopt,
1607   these variables don't support command-line equivalents, any such
1608   command-line options should be added manually to my_long_options in mysqld.cc
1609 */
1610 class Sys_var_struct: public sys_var
1611 {
1612   ptrdiff_t name_offset; // offset to the 'name' property in the structure
1613 public:
1614   Sys_var_struct(const char *name_arg,
1615           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1616           CMD_LINE getopt,
1617           ptrdiff_t name_off, void *def_val, PolyLock *lock=0,
1618           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1619           on_check_function on_check_func=0,
1620           on_update_function on_update_func=0,
1621           const char *substitute=0,
1622           int parse_flag= PARSE_NORMAL)
1623     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
1624               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
1625               lock, binlog_status_arg, on_check_func, on_update_func,
1626               substitute, parse_flag),
1627       name_offset(name_off)
1628   {
1629     option.var_type= GET_STR;
1630     /*
1631       struct variables are special on the command line - often (e.g. for
1632       charsets) the name cannot be immediately resolved, but only after all
1633       options (in particular, basedir) are parsed.
1634 
1635       thus all struct command-line options should be added manually
1636       to my_long_options in mysqld.cc
1637     */
1638     DBUG_ASSERT(getopt.id == -1);
1639     DBUG_ASSERT(size == sizeof(void *));
1640   }
do_check(THD * thd,set_var * var)1641   bool do_check(THD *thd, set_var *var)
1642   { return false; }
session_update(THD * thd,set_var * var)1643   bool session_update(THD *thd, set_var *var)
1644   {
1645     session_var(thd, const void*)= var->save_result.ptr;
1646     return false;
1647   }
global_update(THD * thd,set_var * var)1648   bool global_update(THD *thd, set_var *var)
1649   {
1650     global_var(const void*)= var->save_result.ptr;
1651     return false;
1652   }
session_save_default(THD * thd,set_var * var)1653   void session_save_default(THD *thd, set_var *var)
1654   { var->save_result.ptr= global_var(void*); }
global_save_default(THD * thd,set_var * var)1655   void global_save_default(THD *thd, set_var *var)
1656   {
1657     void **default_value= reinterpret_cast<void**>(option.def_value);
1658     var->save_result.ptr= *default_value;
1659   }
check_update_type(Item_result type)1660   bool check_update_type(Item_result type)
1661   { return type != INT_RESULT && type != STRING_RESULT; }
session_value_ptr(THD * thd,LEX_STRING * base)1662   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
1663   {
1664     uchar *ptr= session_var(thd, uchar*);
1665     return ptr ? *(uchar**)(ptr+name_offset) : 0;
1666   }
global_value_ptr(THD * thd,LEX_STRING * base)1667   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1668   {
1669     uchar *ptr= global_var(uchar*);
1670     return ptr ? *(uchar**)(ptr+name_offset) : 0;
1671   }
1672 };
1673 
1674 /**
1675   The class for variables that store time zones
1676 
1677   Backing store: Time_zone*
1678 
1679   @note
1680   Time zones cannot be supported directly by my_getopt, thus
1681   these variables don't support command-line equivalents, any such
1682   command-line options should be added manually to my_long_options in mysqld.cc
1683 */
1684 class Sys_var_tz: public sys_var
1685 {
1686 public:
1687   Sys_var_tz(const char *name_arg,
1688              const char *comment, int flag_args, ptrdiff_t off, size_t size,
1689              CMD_LINE getopt,
1690              Time_zone **def_val, PolyLock *lock=0,
1691              enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1692              on_check_function on_check_func=0,
1693              on_update_function on_update_func=0,
1694              const char *substitute=0,
1695              int parse_flag= PARSE_NORMAL)
1696     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
1697               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
1698               lock, binlog_status_arg, on_check_func, on_update_func,
1699               substitute, parse_flag)
1700   {
1701     DBUG_ASSERT(getopt.id == -1);
1702     DBUG_ASSERT(size == sizeof(Time_zone *));
1703   }
do_check(THD * thd,set_var * var)1704   bool do_check(THD *thd, set_var *var)
1705   {
1706     char buff[MAX_TIME_ZONE_NAME_LENGTH];
1707     String str(buff, sizeof(buff), &my_charset_latin1);
1708     String *res= var->value->val_str(&str);
1709 
1710     if (!res)
1711       return true;
1712 
1713     if (!(var->save_result.time_zone= my_tz_find(thd, res)))
1714     {
1715       ErrConvString err(res);
1716       my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), err.ptr());
1717       return true;
1718     }
1719     return false;
1720   }
session_update(THD * thd,set_var * var)1721   bool session_update(THD *thd, set_var *var)
1722   {
1723     session_var(thd, Time_zone*)= var->save_result.time_zone;
1724     return false;
1725   }
global_update(THD * thd,set_var * var)1726   bool global_update(THD *thd, set_var *var)
1727   {
1728     global_var(Time_zone*)= var->save_result.time_zone;
1729     return false;
1730   }
session_save_default(THD * thd,set_var * var)1731   void session_save_default(THD *thd, set_var *var)
1732   {
1733     var->save_result.time_zone= global_var(Time_zone*);
1734   }
global_save_default(THD * thd,set_var * var)1735   void global_save_default(THD *thd, set_var *var)
1736   {
1737     var->save_result.time_zone=
1738       *(Time_zone**)(intptr)option.def_value;
1739   }
session_value_ptr(THD * thd,LEX_STRING * base)1740   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
1741   {
1742     /*
1743       This is an ugly fix for replication: we don't replicate properly queries
1744       invoking system variables' values to update tables; but
1745       CONVERT_TZ(,,@@session.time_zone) is so popular that we make it
1746       replicable (i.e. we tell the binlog code to store the session
1747       timezone). If it's the global value which was used we can't replicate
1748       (binlog code stores session value only).
1749     */
1750     thd->time_zone_used= 1;
1751     return (uchar *)(session_var(thd, Time_zone*)->get_name()->ptr());
1752   }
global_value_ptr(THD * thd,LEX_STRING * base)1753   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1754   {
1755     return (uchar *)(global_var(Time_zone*)->get_name()->ptr());
1756   }
check_update_type(Item_result type)1757   bool check_update_type(Item_result type)
1758   { return type != STRING_RESULT; }
1759 };
1760 
1761 
1762 class Sys_var_tx_isolation: public Sys_var_enum
1763 {
1764 public:
Sys_var_tx_isolation(const char * name_arg,const char * comment,int flag_args,ptrdiff_t off,size_t size,CMD_LINE getopt,const char * values[],uint def_val,PolyLock * lock,enum binlog_status_enum binlog_status_arg,on_check_function on_check_func)1765   Sys_var_tx_isolation(const char *name_arg,
1766           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1767           CMD_LINE getopt,
1768           const char *values[], uint def_val, PolyLock *lock,
1769           enum binlog_status_enum binlog_status_arg,
1770           on_check_function on_check_func)
1771     :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt,
1772                   values, def_val, lock, binlog_status_arg, on_check_func)
1773   {}
1774   virtual bool session_update(THD *thd, set_var *var);
1775 };
1776 
1777 
1778 /**
1779   Class representing the tx_read_only system variable for setting
1780   default transaction access mode.
1781 
1782   Note that there is a special syntax - SET TRANSACTION READ ONLY
1783   (or READ WRITE) that sets the access mode for the next transaction
1784   only.
1785 */
1786 
1787 class Sys_var_tx_read_only: public Sys_var_mybool
1788 {
1789 public:
Sys_var_tx_read_only(const char * name_arg,const char * comment,int flag_args,ptrdiff_t off,size_t size,CMD_LINE getopt,my_bool def_val,PolyLock * lock,enum binlog_status_enum binlog_status_arg,on_check_function on_check_func)1790   Sys_var_tx_read_only(const char *name_arg, const char *comment, int flag_args,
1791                        ptrdiff_t off, size_t size, CMD_LINE getopt,
1792                        my_bool def_val, PolyLock *lock,
1793                        enum binlog_status_enum binlog_status_arg,
1794                        on_check_function on_check_func)
1795     :Sys_var_mybool(name_arg, comment, flag_args, off, size, getopt,
1796                     def_val, lock, binlog_status_arg, on_check_func)
1797   {}
1798   virtual bool session_update(THD *thd, set_var *var);
1799 };
1800 
1801 
1802 /**
1803    A class for @@global.binlog_checksum that has
1804    a specialized update method.
1805 */
1806 class Sys_var_enum_binlog_checksum: public Sys_var_enum
1807 {
1808 public:
Sys_var_enum_binlog_checksum(const char * name_arg,const char * comment,int flag_args,ptrdiff_t off,size_t size,CMD_LINE getopt,const char * values[],uint def_val,PolyLock * lock,enum binlog_status_enum binlog_status_arg)1809   Sys_var_enum_binlog_checksum(const char *name_arg,
1810           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1811           CMD_LINE getopt,
1812           const char *values[], uint def_val, PolyLock *lock,
1813           enum binlog_status_enum binlog_status_arg)
1814     :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt,
1815                   values, def_val, lock, binlog_status_arg, NULL)
1816   {}
1817   virtual bool global_update(THD *thd, set_var *var);
1818 };
1819 
1820 
1821 /**
1822   Class for variables that store values of type Gtid_specification.
1823 */
1824 class Sys_var_gtid_specification: public sys_var
1825 {
1826 public:
1827   Sys_var_gtid_specification(const char *name_arg,
1828           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1829           CMD_LINE getopt,
1830           const char *def_val,
1831           PolyLock *lock= 0,
1832           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1833           on_check_function on_check_func=0,
1834           on_update_function on_update_func=0,
1835           const char *substitute=0,
1836           int parse_flag= PARSE_NORMAL)
1837     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
1838               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
1839               lock, binlog_status_arg, on_check_func, on_update_func,
1840               substitute, parse_flag)
1841   {
1842     DBUG_ASSERT(size == sizeof(Gtid_specification));
1843   }
session_update(THD * thd,set_var * var)1844   bool session_update(THD *thd, set_var *var)
1845   {
1846     DBUG_ENTER("Sys_var_gtid::session_update");
1847     global_sid_lock->rdlock();
1848     bool ret= (((Gtid_specification *)session_var_ptr(thd))->
1849                parse(global_sid_map,
1850                      var->save_result.string_value.str) != 0);
1851     global_sid_lock->unlock();
1852     DBUG_RETURN(ret);
1853   }
global_update(THD * thd,set_var * var)1854   bool global_update(THD *thd, set_var *var)
1855   { DBUG_ASSERT(FALSE); return true; }
session_save_default(THD * thd,set_var * var)1856   void session_save_default(THD *thd, set_var *var)
1857   {
1858     DBUG_ENTER("Sys_var_gtid::session_save_default");
1859     char *ptr= (char*)(intptr)option.def_value;
1860     var->save_result.string_value.str= ptr;
1861     var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
1862     DBUG_VOID_RETURN;
1863   }
global_save_default(THD * thd,set_var * var)1864   void global_save_default(THD *thd, set_var *var)
1865   { DBUG_ASSERT(FALSE); }
do_check(THD * thd,set_var * var)1866   bool do_check(THD *thd, set_var *var)
1867   {
1868     DBUG_ENTER("Sys_var_gtid::do_check");
1869     char buf[Gtid_specification::MAX_TEXT_LENGTH + 1];
1870     String str(buf, sizeof(buf), &my_charset_latin1);
1871     String *res= var->value->val_str(&str);
1872     if (!res)
1873       DBUG_RETURN(true);
1874     var->save_result.string_value.str= thd->strmake(res->c_ptr_safe(), res->length());
1875     if (!var->save_result.string_value.str)
1876     {
1877       my_error(ER_OUT_OF_RESOURCES, MYF(0)); // thd->strmake failed
1878       DBUG_RETURN(true);
1879     }
1880     var->save_result.string_value.length= res->length();
1881     bool ret= Gtid_specification::is_valid(res->c_ptr_safe()) ? false : true;
1882     DBUG_PRINT("info", ("ret=%d", ret));
1883     DBUG_RETURN(ret);
1884   }
check_update_type(Item_result type)1885   bool check_update_type(Item_result type)
1886   { return type != STRING_RESULT; }
session_value_ptr(THD * thd,LEX_STRING * base)1887   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
1888   {
1889     DBUG_ENTER("Sys_var_gtid::session_value_ptr");
1890     char buf[Gtid_specification::MAX_TEXT_LENGTH + 1];
1891     global_sid_lock->rdlock();
1892     ((Gtid_specification *)session_var_ptr(thd))->
1893       to_string(global_sid_map, buf);
1894     global_sid_lock->unlock();
1895     char *ret= thd->strdup(buf);
1896     DBUG_RETURN((uchar *)ret);
1897   }
global_value_ptr(THD * thd,LEX_STRING * base)1898   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1899   { DBUG_ASSERT(FALSE); return NULL; }
1900 };
1901 
1902 #ifdef HAVE_GTID_NEXT_LIST
1903 /**
1904   Class for variables that store values of type Gtid_set.
1905 
1906   The back-end storage should be a Gtid_set_or_null, and it should be
1907   set to null by default.  When the variable is set for the first
1908   time, the Gtid_set* will be allocated.
1909 */
1910 class Sys_var_gtid_set: public sys_var
1911 {
1912 public:
1913   Sys_var_gtid_set(const char *name_arg,
1914           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1915           CMD_LINE getopt,
1916           const char *def_val,
1917           PolyLock *lock= 0,
1918           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1919           on_check_function on_check_func=0,
1920           on_update_function on_update_func=0,
1921           const char *substitute=0,
1922           int parse_flag= PARSE_NORMAL)
1923     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
1924               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
1925               lock, binlog_status_arg, on_check_func, on_update_func,
1926               substitute, parse_flag)
1927   {
1928     DBUG_ASSERT(size == sizeof(Gtid_set_or_null));
1929   }
session_update(THD * thd,set_var * var)1930   bool session_update(THD *thd, set_var *var)
1931   {
1932     DBUG_ENTER("Sys_var_gtid_set::session_update");
1933     Gtid_set_or_null *gsn=
1934       (Gtid_set_or_null *)session_var_ptr(thd);
1935     char *value= var->save_result.string_value.str;
1936     if (value == NULL)
1937       gsn->set_null();
1938     else
1939     {
1940       Gtid_set *gs= gsn->set_non_null(global_sid_map);
1941       if (gs == NULL)
1942       {
1943         my_error(ER_OUT_OF_RESOURCES, MYF(0)); // allocation failed
1944         DBUG_RETURN(true);
1945       }
1946       /*
1947         If string begins with '+', add to the existing set, otherwise
1948         replace existing set.
1949       */
1950       while (isspace(*value))
1951         value++;
1952       if (*value == '+')
1953         value++;
1954       else
1955         gs->clear();
1956       // Add specified set of groups to Gtid_set.
1957       global_sid_lock->rdlock();
1958       enum_return_status ret= gs->add_gtid_text(value);
1959       global_sid_lock->unlock();
1960       if (ret != RETURN_STATUS_OK)
1961       {
1962         gsn->set_null();
1963         DBUG_RETURN(true);
1964       }
1965     }
1966     DBUG_RETURN(false);
1967   }
global_update(THD * thd,set_var * var)1968   bool global_update(THD *thd, set_var *var)
1969   { DBUG_ASSERT(FALSE); return true; }
session_save_default(THD * thd,set_var * var)1970   void session_save_default(THD *thd, set_var *var)
1971   {
1972     DBUG_ENTER("Sys_var_gtid_set::session_save_default");
1973     char *ptr= (char*)(intptr)option.def_value;
1974     var->save_result.string_value.str= ptr;
1975     var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
1976     DBUG_VOID_RETURN;
1977   }
global_save_default(THD * thd,set_var * var)1978   void global_save_default(THD *thd, set_var *var)
1979   { DBUG_ASSERT(FALSE); }
do_check(THD * thd,set_var * var)1980   bool do_check(THD *thd, set_var *var)
1981   {
1982     DBUG_ENTER("Sys_var_gtid_set::do_check");
1983     String str;
1984     String *res= var->value->val_str(&str);
1985     if (res == NULL)
1986     {
1987       var->save_result.string_value.str= NULL;
1988       DBUG_RETURN(FALSE);
1989     }
1990     DBUG_ASSERT(res->ptr() != NULL);
1991     var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
1992     if (var->save_result.string_value.str == NULL)
1993     {
1994       my_error(ER_OUT_OF_RESOURCES, MYF(0)); // thd->strmake failed
1995       DBUG_RETURN(1);
1996     }
1997     var->save_result.string_value.length= res->length();
1998     bool ret= !Gtid_set::is_valid(res->ptr());
1999     DBUG_RETURN(ret);
2000   }
check_update_type(Item_result type)2001   bool check_update_type(Item_result type)
2002   { return type != STRING_RESULT; }
session_value_ptr(THD * thd,LEX_STRING * base)2003   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
2004   {
2005     DBUG_ENTER("Sys_var_gtid_set::session_value_ptr");
2006     Gtid_set_or_null *gsn= (Gtid_set_or_null *)session_var_ptr(thd);
2007     Gtid_set *gs= gsn->get_gtid_set();
2008     if (gs == NULL)
2009       DBUG_RETURN(NULL);
2010     char *buf;
2011     global_sid_lock->rdlock();
2012     buf= (char *)thd->alloc(gs->get_string_length() + 1);
2013     if (buf)
2014       gs->to_string(buf);
2015     else
2016       my_error(ER_OUT_OF_RESOURCES, MYF(0)); // thd->alloc faile
2017     global_sid_lock->unlock();
2018     DBUG_RETURN((uchar *)buf);
2019   }
global_value_ptr(THD * thd,LEX_STRING * base)2020   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
2021   { DBUG_ASSERT(FALSE); return NULL; }
2022 };
2023 #endif
2024 
2025 
2026 /**
2027   Abstract base class for read-only variables (global or session) of
2028   string type where the value is generated by some function.  This
2029   needs to be subclassed; the session_value_ptr or global_value_ptr
2030   function should be overridden.
2031 */
2032 class Sys_var_charptr_func: public sys_var
2033 {
2034 public:
Sys_var_charptr_func(const char * name_arg,const char * comment,flag_enum flag_arg)2035   Sys_var_charptr_func(const char *name_arg, const char *comment,
2036                        flag_enum flag_arg)
2037     : sys_var(&all_sys_vars, name_arg, comment, READ_ONLY flag_arg,
2038               0/*off*/, NO_CMD_LINE.id, NO_CMD_LINE.arg_type,
2039               SHOW_CHAR, (intptr)0/*def_val*/,
2040               NULL/*polylock*/, VARIABLE_NOT_IN_BINLOG,
2041               NULL/*on_check_func*/, NULL/*on_update_func*/,
2042               NULL/*substitute*/, PARSE_NORMAL/*parse_flag*/)
2043   {
2044     DBUG_ASSERT(flag_arg == sys_var::GLOBAL || flag_arg == sys_var::SESSION ||
2045                 flag_arg == sys_var::ONLY_SESSION);
2046   }
session_update(THD * thd,set_var * var)2047   bool session_update(THD *thd, set_var *var)
2048   { DBUG_ASSERT(FALSE); return true; }
global_update(THD * thd,set_var * var)2049   bool global_update(THD *thd, set_var *var)
2050   { DBUG_ASSERT(FALSE); return true; }
session_save_default(THD * thd,set_var * var)2051   void session_save_default(THD *thd, set_var *var) { DBUG_ASSERT(FALSE); }
global_save_default(THD * thd,set_var * var)2052   void global_save_default(THD *thd, set_var *var) { DBUG_ASSERT(FALSE); }
do_check(THD * thd,set_var * var)2053   bool do_check(THD *thd, set_var *var) { DBUG_ASSERT(FALSE); return true; }
check_update_type(Item_result type)2054   bool check_update_type(Item_result type) { DBUG_ASSERT(FALSE); return true; }
session_value_ptr(THD * thd,LEX_STRING * base)2055   virtual uchar *session_value_ptr(THD *thd, LEX_STRING *base)
2056   { DBUG_ASSERT(FALSE); return NULL; }
global_value_ptr(THD * thd,LEX_STRING * base)2057   virtual uchar *global_value_ptr(THD *thd, LEX_STRING *base)
2058   { DBUG_ASSERT(FALSE); return NULL; }
2059 };
2060 
2061 
2062 /**
2063   Abstract base class for read-only variables (global or session) of
2064   string type where the value is the string representation of a
2065   Gtid_set generated by some function.  This needs to be subclassed;
2066   the session_value_ptr or global_value_ptr should be overwritten.
2067 */
2068 class Sys_var_gtid_set_func: public Sys_var_charptr_func
2069 {
2070 public:
Sys_var_gtid_set_func(const char * name_arg,const char * comment,flag_enum flag_arg)2071   Sys_var_gtid_set_func(const char *name_arg, const char *comment,
2072                         flag_enum flag_arg)
2073     : Sys_var_charptr_func(name_arg, comment, flag_arg) {}
2074 
2075   typedef enum_return_status (*Gtid_set_getter)(THD *, Gtid_set *);
2076 
get_string_from_gtid_set(THD * thd,Gtid_set_getter get_gtid_set)2077   static uchar *get_string_from_gtid_set(THD *thd,
2078                                          Gtid_set_getter get_gtid_set)
2079   {
2080     DBUG_ENTER("Sys_var_gtid_ended_groups::session_value_ptr");
2081     Gtid_set gs(global_sid_map);
2082     char *buf;
2083     // As an optimization, add 10 Intervals that do not need to be
2084     // allocated.
2085     Gtid_set::Interval ivs[10];
2086     gs.add_interval_memory(10, ivs);
2087     global_sid_lock->wrlock();
2088     if (get_gtid_set(thd, &gs) != RETURN_STATUS_OK)
2089       goto error;
2090     // allocate string and print to it
2091     buf= (char *)thd->alloc(gs.get_string_length() + 1);
2092     if (buf == NULL)
2093     {
2094       my_error(ER_OUT_OF_RESOURCES, MYF(0));
2095       goto error;
2096     }
2097     gs.to_string(buf);
2098     global_sid_lock->unlock();
2099     DBUG_RETURN((uchar *)buf);
2100   error:
2101     global_sid_lock->unlock();
2102     DBUG_RETURN(NULL);
2103   }
2104 };
2105 
2106 
2107 /**
2108   Class for @@session.gtid_executed and @@global.gtid_executed.
2109 */
2110 class Sys_var_gtid_executed : Sys_var_gtid_set_func
2111 {
2112 public:
Sys_var_gtid_executed(const char * name_arg,const char * comment_arg)2113   Sys_var_gtid_executed(const char *name_arg, const char *comment_arg)
2114     : Sys_var_gtid_set_func(name_arg, comment_arg, SESSION) {}
2115 
global_value_ptr(THD * thd,LEX_STRING * base)2116   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
2117   {
2118     DBUG_ENTER("Sys_var_gtid_executed::global_value_ptr");
2119     global_sid_lock->wrlock();
2120     const Gtid_set *gs= gtid_state->get_logged_gtids();
2121     char *buf= (char *)thd->alloc(gs->get_string_length() + 1);
2122     if (buf == NULL)
2123       my_error(ER_OUT_OF_RESOURCES, MYF(0));
2124     else
2125       gs->to_string(buf);
2126     global_sid_lock->unlock();
2127     DBUG_RETURN((uchar *)buf);
2128   }
2129 
2130 private:
get_groups_from_trx_cache(THD * thd,Gtid_set * gs)2131   static enum_return_status get_groups_from_trx_cache(THD *thd, Gtid_set *gs)
2132   {
2133     DBUG_ENTER("Sys_var_gtid_executed::get_groups_from_trx_cache");
2134     if (opt_bin_log)
2135     {
2136       thd->binlog_setup_trx_data();
2137       PROPAGATE_REPORTED_ERROR(thd->get_group_cache(true)->get_gtids(gs));
2138     }
2139     RETURN_OK;
2140   }
2141 
2142 public:
session_value_ptr(THD * thd,LEX_STRING * base)2143   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
2144   {
2145     return get_string_from_gtid_set(thd, get_groups_from_trx_cache);
2146   }
2147 };
2148 
2149 
2150 /**
2151   Class for @@session.gtid_purged.
2152 */
2153 class Sys_var_gtid_purged : public sys_var
2154 {
2155 public:
2156   Sys_var_gtid_purged(const char *name_arg,
2157           const char *comment, int flag_args, ptrdiff_t off, size_t size,
2158           CMD_LINE getopt,
2159           const char *def_val,
2160           PolyLock *lock= 0,
2161           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
2162           on_check_function on_check_func=0,
2163           on_update_function on_update_func=0,
2164           const char *substitute=0,
2165           int parse_flag= PARSE_NORMAL)
2166     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
2167               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
2168               lock, binlog_status_arg, on_check_func, on_update_func,
2169               substitute, parse_flag)
2170   {}
2171 
session_update(THD * thd,set_var * var)2172   bool session_update(THD *thd, set_var *var)
2173   {
2174     DBUG_ASSERT(FALSE);
2175     return true;
2176   }
2177 
session_save_default(THD * thd,set_var * var)2178   void session_save_default(THD *thd, set_var *var)
2179   { DBUG_ASSERT(FALSE); }
2180 
global_update(THD * thd,set_var * var)2181   bool global_update(THD *thd, set_var *var)
2182   {
2183     DBUG_ENTER("Sys_var_gtid_purged::global_update");
2184 #ifdef HAVE_REPLICATION
2185     bool error= false;
2186     int rotate_res= 0;
2187 
2188     global_sid_lock->wrlock();
2189     char *previous_gtid_logged= gtid_state->get_logged_gtids()->to_string();
2190     char *previous_gtid_lost= gtid_state->get_lost_gtids()->to_string();
2191     enum_return_status ret= gtid_state->add_lost_gtids(var->save_result.string_value.str);
2192     char *current_gtid_logged= gtid_state->get_logged_gtids()->to_string();
2193     char *current_gtid_lost= gtid_state->get_lost_gtids()->to_string();
2194     global_sid_lock->unlock();
2195     if (RETURN_STATUS_OK != ret)
2196     {
2197       error= true;
2198       goto end;
2199     }
2200 
2201     // Log messages saying that GTID_PURGED and GTID_EXECUTED were changed.
2202     sql_print_information(ER(ER_GTID_PURGED_WAS_CHANGED),
2203                           previous_gtid_lost, current_gtid_lost);
2204     sql_print_information(ER(ER_GTID_EXECUTED_WAS_CHANGED),
2205                           previous_gtid_logged, current_gtid_logged);
2206 
2207     // Rotate logs to have Previous_gtid_event on last binlog.
2208     rotate_res= mysql_bin_log.rotate_and_purge(thd, true);
2209     if (rotate_res)
2210     {
2211       error= true;
2212       goto end;
2213     }
2214 
2215 end:
2216     my_free(previous_gtid_logged);
2217     my_free(previous_gtid_lost);
2218     my_free(current_gtid_logged);
2219     my_free(current_gtid_lost);
2220     DBUG_RETURN(error);
2221 #else
2222     DBUG_RETURN(true);
2223 #endif /* HAVE_REPLICATION */
2224   }
2225 
global_save_default(THD * thd,set_var * var)2226   void global_save_default(THD *thd, set_var *var)
2227   {
2228     /* gtid_purged does not have default value */
2229     my_error(ER_NO_DEFAULT, MYF(0), var->var->name.str);
2230   }
2231 
do_check(THD * thd,set_var * var)2232   bool do_check(THD *thd, set_var *var)
2233   {
2234     DBUG_ENTER("Sys_var_gtid_purged::do_check");
2235     char buf[1024];
2236     String str(buf, sizeof(buf), system_charset_info);
2237     String *res= var->value->val_str(&str);
2238     if (!res)
2239       DBUG_RETURN(true);
2240     var->save_result.string_value.str= thd->strmake(res->c_ptr_safe(),
2241                                                     res->length());
2242     if (!var->save_result.string_value.str)
2243     {
2244       my_error(ER_OUT_OF_RESOURCES, MYF(0)); // thd->strmake failed
2245       DBUG_RETURN(true);
2246     }
2247     var->save_result.string_value.length= res->length();
2248     bool ret= Gtid_set::is_valid(res->c_ptr_safe()) ? false : true;
2249     DBUG_PRINT("info", ("ret=%d", ret));
2250     DBUG_RETURN(ret);
2251   }
2252 
check_update_type(Item_result type)2253   bool check_update_type(Item_result type)
2254   { return type != STRING_RESULT; }
2255 
global_value_ptr(THD * thd,LEX_STRING * base)2256   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
2257   {
2258     DBUG_ENTER("Sys_var_gtid_purged::global_value_ptr");
2259     global_sid_lock->wrlock();
2260     const Gtid_set *gs= gtid_state->get_lost_gtids();
2261     char *buf= (char *)thd->alloc(gs->get_string_length() + 1);
2262     if (buf == NULL)
2263       my_error(ER_OUT_OF_RESOURCES, MYF(0));
2264     else
2265       gs->to_string(buf);
2266     global_sid_lock->unlock();
2267     DBUG_RETURN((uchar *)buf);
2268   }
2269 
session_value_ptr(THD * thd,LEX_STRING * base)2270   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
2271   { DBUG_ASSERT(0); return NULL; }
2272 };
2273 
2274 
2275 class Sys_var_gtid_owned : Sys_var_gtid_set_func
2276 {
2277 public:
Sys_var_gtid_owned(const char * name_arg,const char * comment_arg)2278   Sys_var_gtid_owned(const char *name_arg, const char *comment_arg)
2279     : Sys_var_gtid_set_func(name_arg, comment_arg, SESSION) {}
2280 
2281 public:
session_value_ptr(THD * thd,LEX_STRING * base)2282   uchar *session_value_ptr(THD *thd, LEX_STRING *base)
2283   {
2284     DBUG_ENTER("Sys_var_gtid_owned::session_value_ptr");
2285     char *buf= NULL;
2286     if (thd->owned_gtid.sidno == 0)
2287       DBUG_RETURN((uchar *)thd->strdup(""));
2288     if (thd->owned_gtid.sidno == -1)
2289     {
2290 #ifdef HAVE_GTID_NEXT_LIST
2291       buf= (char *)thd->alloc(thd->owned_gtid_set.get_string_length() + 1);
2292       if (buf)
2293       {
2294         global_sid_lock->rdlock();
2295         thd->owned_gtid_set.to_string(buf);
2296         global_sid_lock->unlock();
2297       }
2298       else
2299         my_error(ER_OUT_OF_RESOURCES, MYF(0));
2300 #else
2301      DBUG_ASSERT(0);
2302 #endif
2303     }
2304     else
2305     {
2306       buf= (char *)thd->alloc(Gtid::MAX_TEXT_LENGTH + 1);
2307       if (buf)
2308       {
2309         global_sid_lock->rdlock();
2310         thd->owned_gtid.to_string(global_sid_map, buf);
2311         global_sid_lock->unlock();
2312       }
2313       else
2314         my_error(ER_OUT_OF_RESOURCES, MYF(0));
2315     }
2316     DBUG_RETURN((uchar *)buf);
2317   }
2318 
global_value_ptr(THD * thd,LEX_STRING * base)2319   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
2320   {
2321     DBUG_ENTER("Sys_var_gtid_owned::global_value_ptr");
2322     const Owned_gtids *owned_gtids= gtid_state->get_owned_gtids();
2323     global_sid_lock->wrlock();
2324     char *buf= (char *)thd->alloc(owned_gtids->get_max_string_length());
2325     if (buf)
2326       owned_gtids->to_string(buf);
2327     else
2328       my_error(ER_OUT_OF_RESOURCES, MYF(0)); // thd->alloc faile
2329     global_sid_lock->unlock();
2330     DBUG_RETURN((uchar *)buf);
2331   }
2332 };
2333