1 #ifndef SYS_VARS_H_INCLUDED
2 #define SYS_VARS_H_INCLUDED
3 /* Copyright (c) 2002, 2021, Oracle and/or its affiliates.
4 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License, version 2.0,
7    as published by the Free Software Foundation.
8 
9    This program is also distributed with certain software (including
10    but not limited to OpenSSL) that is licensed under separate terms,
11    as designated in a particular file or component or in included license
12    documentation.  The authors of MySQL hereby grant you an additional
13    permission to link the program and your derivative works with the
14    separately licensed software that they have included with MySQL.
15 
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License, version 2.0, for more details.
20 
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
24 
25 /**
26   @file
27   "private" interface to sys_var - server configuration variables.
28 
29   This header is included only by the file that contains declarations
30   of sys_var variables (sys_vars.cc).
31 */
32 
33 #include "my_global.h"
34 #include "keycaches.h"            // dflt_key_cache
35 #include "my_bit.h"               // my_count_bits
36 #include "my_getopt.h"            // get_opt_arg_type
37 #include "mysql/plugin.h"         // enum_mysql_show_type
38 #include "item.h"                 // Item
39 #include "log.h"                  // sql_print_information
40 #include "set_var.h"              // sys_var
41 #include "sql_class.h"            // THD
42 #include "sql_plugin.h"           // my_plugin_lock_by_name
43 #include "strfunc.h"              // find_type
44 #include "sys_vars_shared.h"      // throw_bounds_warning
45 #include "tztime.h"               // Time_zone
46 #include "binlog.h"               // mysql_bin_log
47 #include "rpl_rli.h"              // sql_slave_skip_counter
48 #include "rpl_msr.h"              // channel_map
49 #include "rpl_group_replication.h"// is_group_replication_running
50 
51 
52 /*
53   a set of mostly trivial (as in f(X)=X) defines below to make system variable
54   declarations more readable
55 */
56 #define VALID_RANGE(X,Y) X,Y
57 #define DEFAULT(X) X
58 #define BLOCK_SIZE(X) X
59 #define GLOBAL_VAR(X) sys_var::GLOBAL, (((char*)&(X))-(char*)&global_system_variables), sizeof(X)
60 #define SESSION_VAR(X) sys_var::SESSION, offsetof(SV, X), sizeof(((SV *)0)->X)
61 #define SESSION_ONLY(X) sys_var::ONLY_SESSION, offsetof(SV, X), sizeof(((SV *)0)->X)
62 #define NO_CMD_LINE CMD_LINE(NO_ARG, -1)
63 /*
64   the define below means that there's no *second* mutex guard,
65   LOCK_global_system_variables always guards all system variables
66 */
67 #define NO_MUTEX_GUARD ((PolyLock*)0)
68 #define IN_BINLOG sys_var::SESSION_VARIABLE_IN_BINLOG
69 #define NOT_IN_BINLOG sys_var::VARIABLE_NOT_IN_BINLOG
70 #define ON_READ(X) X
71 #define ON_CHECK(X) X
72 #define PRE_UPDATE(X) X
73 #define ON_UPDATE(X) X
74 #define READ_ONLY sys_var::READONLY+
75 #define NOT_VISIBLE sys_var::INVISIBLE+
76 #define UNTRACKED_DEFAULT sys_var::TRI_LEVEL+
77 // this means that Sys_var_charptr initial value was malloc()ed
78 #define PREALLOCATED sys_var::ALLOCATED+
79 /*
80   Sys_var_bit meaning is reversed, like in
81   @@foreign_key_checks <-> OPTION_NO_FOREIGN_KEY_CHECKS
82 */
83 #define REVERSE(X) ~(X)
84 #define DEPRECATED_VAR(X) X
85 
86 #define session_var(THD, TYPE) (*(TYPE*)session_var_ptr(THD))
87 #define global_var(TYPE) (*(TYPE*)global_var_ptr())
88 
89 #if SIZEOF_OFF_T > 4
90 #define GET_HA_ROWS GET_ULL
91 #else
92 #define GET_HA_ROWS GET_ULONG
93 #endif
94 
95 extern sys_var_chain all_sys_vars;
96 
97 enum charset_enum {IN_SYSTEM_CHARSET, IN_FS_CHARSET};
98 
99 static const char *bool_values[3]= {"OFF", "ON", 0};
100 
101 /**
102   A small wrapper class to pass getopt arguments as a pair
103   to the Sys_var_* constructors. It improves type safety and helps
104   to catch errors in the argument order.
105 */
106 struct CMD_LINE
107 {
108   int id;
109   enum get_opt_arg_type arg_type;
110   CMD_LINE(enum get_opt_arg_type getopt_arg_type, int getopt_id=0)
idCMD_LINE111     : id(getopt_id), arg_type(getopt_arg_type) {}
112 };
113 
114 /**
115   Sys_var_integer template is used to generate Sys_var_* classes
116   for variables that represent the value as a signed or unsigned integer.
117   They are Sys_var_uint, Sys_var_ulong, Sys_var_harows, Sys_var_ulonglong,
118   and Sys_var_long.
119 
120   An integer variable has a minimal and maximal values, and a "block_size"
121   (any valid value of the variable must be divisible by the block_size).
122 
123   Class specific constructor arguments: min, max, block_size
124   Backing store: uint, ulong, ha_rows, ulonglong, long, depending on the
125   Sys_var_*
126 */
127 template
128   <typename T, ulong ARGT, enum enum_mysql_show_type SHOWT, bool SIGNED>
129 class Sys_var_integer: public sys_var
130 {
131 public:
132   Sys_var_integer(const char *name_arg,
133           const char *comment, int flag_args, ptrdiff_t off, size_t size,
134           CMD_LINE getopt,
135           T min_val, T max_val, T def_val, uint block_size, PolyLock *lock=0,
136           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
137           on_check_function on_check_func=0,
138           on_update_function on_update_func=0,
139           const char *substitute=0,
140           int parse_flag= PARSE_NORMAL)
141     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
142               getopt.arg_type, SHOWT, def_val, lock, binlog_status_arg,
143               on_check_func, on_update_func,
144               substitute, parse_flag)
145   {
146     option.var_type= ARGT;
147     option.min_value= min_val;
148     option.max_value= max_val;
149     option.block_size= block_size;
150     option.u_max_value= (uchar**)max_var_ptr();
151     if (max_var_ptr())
152       *max_var_ptr()= max_val;
153 
154     // Do not set global_var for Sys_var_keycache objects
155     if (offset >= 0)
156       global_var(T)= def_val;
157 
158     assert(size == sizeof(T));
159     assert(min_val < max_val);
160     assert(min_val <= def_val);
161     assert(max_val >= def_val);
162     assert(block_size > 0);
163     assert(def_val % block_size == 0);
164   }
165   bool do_check(THD *thd, set_var *var)
166   {
167     my_bool fixed= FALSE;
168     longlong v;
169     ulonglong uv;
170 
171     v= var->value->val_int();
172     if (SIGNED) /* target variable has signed type */
173     {
174       if (var->value->unsigned_flag)
175       {
176         /*
177           Input value is such a large positive number that MySQL used an
178           unsigned item to hold it. When cast to a signed longlong, if the
179           result is negative there is "cycling" and this is incorrect (large
180           positive input value should not end up as a large negative value in
181           the session signed variable to be set); instead, we need to pick the
182           allowed number closest to the positive input value, i.e. pick the
183           biggest allowed positive integer.
184         */
185         if (v < 0)
186           uv= max_of_int_range(ARGT);
187         else /* no cycling, longlong can hold true value */
188           uv= (ulonglong) v;
189       }
190       else
191         uv= v;
192       /* This will further restrict with VALID_RANGE, BLOCK_SIZE */
193       var->save_result.ulonglong_value=
194         getopt_ll_limit_value(uv, &option, &fixed);
195     }
196     else
197     {
198       if (var->value->unsigned_flag)
199       {
200         /* Guaranteed positive input value, ulonglong can hold it */
201         uv= (ulonglong) v;
202       }
203       else
204       {
205         /*
206           Maybe negative input value; in this case, cast to ulonglong makes it
207           positive, which is wrong. Pick the closest allowed value i.e. 0.
208         */
209         uv= (ulonglong) (v < 0 ? 0 : v);
210       }
211       var->save_result.ulonglong_value=
212         getopt_ull_limit_value(uv, &option, &fixed);
213     }
214 
215     if (max_var_ptr())
216     {
217       /* check constraint set with --maximum-...=X */
218       if (SIGNED)
219       {
220         longlong max_val= *max_var_ptr();
221         if (((longlong)(var->save_result.ulonglong_value)) > max_val)
222           var->save_result.ulonglong_value= max_val;
223         /*
224           Signed variable probably has some kind of symmetry. Then it's good
225           to limit negative values just as we limit positive values.
226         */
227         max_val= -max_val;
228         if (((longlong)(var->save_result.ulonglong_value)) < max_val)
229           var->save_result.ulonglong_value= max_val;
230       }
231       else
232       {
233         ulonglong max_val= *max_var_ptr();
234         if (var->save_result.ulonglong_value > max_val)
235           var->save_result.ulonglong_value= max_val;
236       }
237     }
238 
239     return throw_bounds_warning(thd, name.str,
240                                 var->save_result.ulonglong_value !=
241                                 (ulonglong)v,
242                                 var->value->unsigned_flag, v);
243   }
244   bool session_update(THD *thd, set_var *var)
245   {
246     session_var(thd, T)= static_cast<T>(var->save_result.ulonglong_value);
247     return false;
248   }
249   bool global_update(THD *thd, set_var *var)
250   {
251     global_var(T)= static_cast<T>(var->save_result.ulonglong_value);
252     return false;
253   }
254   bool check_update_type(Item_result type)
255   { return type != INT_RESULT; }
256   void session_save_default(THD *thd, set_var *var)
257   {
258     var->save_result.ulonglong_value=
259       static_cast<ulonglong>(*(T*)global_value_ptr(thd, 0));
260   }
261   void global_save_default(THD *thd, set_var *var)
262   { var->save_result.ulonglong_value= option.def_value; }
263   private:
264   T *max_var_ptr()
265   {
266     return scope() == SESSION ? (T*)(((uchar*)&max_system_variables) + offset)
267                               : 0;
268   }
269 };
270 
271 typedef Sys_var_integer<int32, GET_UINT, SHOW_INT, FALSE> Sys_var_int32;
272 typedef Sys_var_integer<uint, GET_UINT, SHOW_INT, FALSE> Sys_var_uint;
273 typedef Sys_var_integer<ulong, GET_ULONG, SHOW_LONG, FALSE> Sys_var_ulong;
274 typedef Sys_var_integer<ha_rows, GET_HA_ROWS, SHOW_HA_ROWS, FALSE>
275   Sys_var_harows;
276 typedef Sys_var_integer<ulonglong, GET_ULL, SHOW_LONGLONG, FALSE>
277   Sys_var_ulonglong;
278 typedef Sys_var_integer<long, GET_LONG, SHOW_SIGNED_LONG, TRUE> Sys_var_long;
279 
280 /**
281   Helper class for variables that take values from a TYPELIB
282 */
283 class Sys_var_typelib: public sys_var
284 {
285 protected:
286   TYPELIB typelib;
287 public:
288   Sys_var_typelib(const char *name_arg,
289           const char *comment, int flag_args, ptrdiff_t off,
290           CMD_LINE getopt,
291           SHOW_TYPE show_val_type_arg, const char *values[],
292           ulonglong def_val, PolyLock *lock,
293           enum binlog_status_enum binlog_status_arg,
294           on_check_function on_check_func, on_update_function on_update_func,
295           const char *substitute, int parse_flag= PARSE_NORMAL)
296     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
297               getopt.arg_type, show_val_type_arg, def_val, lock,
298               binlog_status_arg, on_check_func,
299               on_update_func, substitute, parse_flag)
300   {
301     for (typelib.count= 0; values[typelib.count]; typelib.count++) /*no-op */;
302     typelib.name="";
303     typelib.type_names= values;
304     typelib.type_lengths= 0;    // only used by Fields_enum and Field_set
305     option.typelib= &typelib;
306   }
do_check(THD * thd,set_var * var)307   bool do_check(THD *thd, set_var *var) // works for enums and my_bool
308   {
309     char buff[STRING_BUFFER_USUAL_SIZE];
310     String str(buff, sizeof(buff), system_charset_info), *res;
311 
312     if (var->value->result_type() == STRING_RESULT)
313     {
314       if (!(res=var->value->val_str(&str)))
315         return true;
316       else
317       if (!(var->save_result.ulonglong_value=
318             find_type(&typelib, res->ptr(), res->length(), false)))
319         return true;
320       else
321         var->save_result.ulonglong_value--;
322     }
323     else
324     {
325       longlong tmp=var->value->val_int();
326       if (tmp < 0 || tmp >= typelib.count)
327         return true;
328       else
329         var->save_result.ulonglong_value= tmp;
330     }
331 
332     return false;
333   }
check_update_type(Item_result type)334   bool check_update_type(Item_result type)
335   { return type != INT_RESULT && type != STRING_RESULT; }
336 };
337 
338 /**
339   The class for ENUM variables - variables that take one value from a fixed
340   list of values.
341 
342   Class specific constructor arguments:
343     char* values[]    - 0-terminated list of strings of valid values
344 
345   Backing store: uint
346 
347   @note
348   Do *not* use "enum FOO" variables as a backing store, there is no
349   guarantee that sizeof(enum FOO) == sizeof(uint), there is no guarantee
350   even that sizeof(enum FOO) == sizeof(enum BAR)
351 */
352 class Sys_var_enum: public Sys_var_typelib
353 {
354 public:
355   Sys_var_enum(const char *name_arg,
356           const char *comment, int flag_args, ptrdiff_t off, size_t size,
357           CMD_LINE getopt,
358           const char *values[], uint def_val, PolyLock *lock=0,
359           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
360           on_check_function on_check_func=0,
361           on_update_function on_update_func=0,
362           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)363     : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
364                       SHOW_CHAR, values, def_val, lock,
365                       binlog_status_arg, on_check_func, on_update_func,
366                       substitute)
367   {
368     option.var_type= GET_ENUM;
369     global_var(ulong)= def_val;
370     assert(def_val < typelib.count);
371     assert(size == sizeof(ulong));
372   }
session_update(THD * thd,set_var * var)373   bool session_update(THD *thd, set_var *var)
374   {
375     session_var(thd, ulong)=
376       static_cast<ulong>(var->save_result.ulonglong_value);
377     return false;
378   }
global_update(THD * thd,set_var * var)379   bool global_update(THD *thd, set_var *var)
380   {
381     global_var(ulong)=
382       static_cast<ulong>(var->save_result.ulonglong_value);
383     return false;
384   }
session_save_default(THD * thd,set_var * var)385   void session_save_default(THD *thd, set_var *var)
386   { var->save_result.ulonglong_value= global_var(ulong); }
global_save_default(THD * thd,set_var * var)387   void global_save_default(THD *thd, set_var *var)
388   { var->save_result.ulonglong_value= option.def_value; }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)389   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
390   { return (uchar*)typelib.type_names[session_var(target_thd, ulong)]; }
global_value_ptr(THD * thd,LEX_STRING * base)391   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
392   { return (uchar*)typelib.type_names[global_var(ulong)]; }
393 };
394 
395 /**
396   The class for boolean variables - a variant of ENUM variables
397   with the fixed list of values of { OFF , ON }
398 
399   Backing store: my_bool
400 */
401 class Sys_var_mybool: public Sys_var_typelib
402 {
403 public:
404   Sys_var_mybool(const char *name_arg,
405           const char *comment, int flag_args, ptrdiff_t off, size_t size,
406           CMD_LINE getopt,
407           my_bool def_val, PolyLock *lock=0,
408           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
409           on_check_function on_check_func=0,
410           on_update_function on_update_func=0,
411           const char *substitute=0,
412           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)413     : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
414                       SHOW_MY_BOOL, bool_values, def_val, lock,
415                       binlog_status_arg, on_check_func, on_update_func,
416                       substitute, parse_flag)
417   {
418     option.var_type= GET_BOOL;
419     global_var(my_bool)= def_val;
420     assert(def_val < 2);
421     assert(getopt.arg_type == OPT_ARG || getopt.id == -1);
422     assert(size == sizeof(my_bool));
423   }
session_update(THD * thd,set_var * var)424   bool session_update(THD *thd, set_var *var)
425   {
426     session_var(thd, my_bool)=
427       static_cast<my_bool>(var->save_result.ulonglong_value);
428     return false;
429   }
global_update(THD * thd,set_var * var)430   bool global_update(THD *thd, set_var *var)
431   {
432     global_var(my_bool)=
433       static_cast<my_bool>(var->save_result.ulonglong_value);
434     return false;
435   }
session_save_default(THD * thd,set_var * var)436   void session_save_default(THD *thd, set_var *var)
437   {
438     var->save_result.ulonglong_value=
439       static_cast<ulonglong>(*(my_bool *)global_value_ptr(thd, 0));
440   }
global_save_default(THD * thd,set_var * var)441   void global_save_default(THD *thd, set_var *var)
442   { var->save_result.ulonglong_value= option.def_value; }
443 };
444 
445 
446 /**
447   A variant of enum where:
448   - Each value may have multiple enum-like aliases.
449   - Instances of the class can specify different default values for
450     the cases:
451     - User specifies the command-line option without a value (i.e.,
452       --option, not --option=value).
453     - User does not specify a command-line option at all.
454 
455   This exists mainly to allow extending a variable that once was
456   boolean in a GA version, into an enumeration type.  Booleans accept
457   multiple aliases (0=off=false, 1=on=true), but Sys_var_enum does
458   not, so we could not use Sys_var_enum without breaking backward
459   compatibility.  Moreover, booleans default to false if option is not
460   given, and true if option is given without value.
461 
462   This is *incompatible* with boolean in the following sense:
463   'SELECT @@variable' returns 0 or 1 for a boolean, whereas this class
464   (similar to enum) returns the textual form. (Note that both boolean,
465   enum, and this class return the textual form in SHOW VARIABLES and
466   SELECT * FROM information_schema.variables).
467 
468   See enforce_gtid_consistency for an example of how this can be used.
469 */
470 class Sys_var_multi_enum : public sys_var
471 {
472 public:
473   struct ALIAS
474   {
475     const char *alias;
476     uint number;
477   };
478 
479   /**
480     Class specific parameters:
481 
482     @param aliases_arg Array of ALIASes, indicating which textual
483     values map to which number.  Should be terminated with an ALIAS
484     having member variable alias set to NULL.  The first
485     `value_count_arg' elements must map to 0, 1, etc; these will be
486     used when the value is displayed.  Remaining elements may appear
487     in arbitrary order.
488 
489     @param value_count_arg The number of allowed integer values.
490 
491     @param def_val The default value if no command line option is
492     given. This must be a valid index into the aliases_arg array, but
493     it does not have to be less than value_count.  The corresponding
494     alias will be used in mysqld --help to show the default value.
495 
496     @param command_line_no_value The default value if a command line
497     option is given without a value ('--command-line-option' without
498     '=VALUE').  This must be less than value_count_arg.
499   */
500   Sys_var_multi_enum(const char *name_arg,
501           const char *comment, int flag_args, ptrdiff_t off, size_t size,
502           CMD_LINE getopt,
503           const ALIAS aliases_arg[], uint value_count_arg,
504           uint def_val, uint command_line_no_value_arg, PolyLock *lock=0,
505           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
506           on_check_function on_check_func=0,
507           on_update_function on_update_func=0,
508           const char *substitute=0,
509           int parse_flag= PARSE_NORMAL)
510     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
511               getopt.arg_type, SHOW_CHAR, def_val, lock,
512               binlog_status_arg, on_check_func,
513               on_update_func, substitute, parse_flag),
514     value_count(value_count_arg),
515     aliases(aliases_arg),
516     command_line_no_value(command_line_no_value_arg)
517   {
518     for (alias_count= 0; aliases[alias_count].alias; alias_count++)
519       assert(aliases[alias_count].number < value_count);
520     assert(def_val < alias_count);
521 
522     option.var_type= GET_STR;
523     option.value= &command_line_value;
524     option.def_value= (intptr)aliases[def_val].alias;
525 
526     global_var(ulong)= aliases[def_val].number;
527 
528     assert(getopt.arg_type == OPT_ARG || getopt.id == -1);
529     assert(size == sizeof(ulong));
530   }
531 
532   /**
533     Return the numeric value for a given alias string, or -1 if the
534     string is not a valid alias.
535   */
find_value(const char * text)536   int find_value(const char *text)
537   {
538     for (uint i= 0; aliases[i].alias != NULL; i++)
539       if (my_strcasecmp(system_charset_info, aliases[i].alias, text) == 0)
540         return aliases[i].number;
541     return -1;
542   }
543 
544   /**
545     Because of limitations in the command-line parsing library, the
546     value given on the command-line cannot be automatically copied to
547     the global value.  Instead, inheritants of this class should call
548     this function from mysqld.cc:mysqld_get_one_option.
549 
550     @param value_str Pointer to the value specified on the command
551     line (as in --option=VALUE).
552 
553     @retval NULL Success.
554 
555     @retval non-NULL Pointer to the invalid string that was used as
556     argument.
557   */
fixup_command_line(const char * value_str)558   const char *fixup_command_line(const char *value_str)
559   {
560     DBUG_ENTER("Sys_var_multi_enum::fixup_command_line");
561     char *end= NULL;
562     long value;
563 
564     // User passed --option (not --option=value).
565     if (value_str == NULL)
566     {
567       value= command_line_no_value;
568       goto end;
569     }
570 
571     // Get textual value.
572     value= find_value(value_str);
573     if (value != -1)
574       goto end;
575 
576     // Get numeric value.
577     value= strtol(value_str, &end, 10);
578     // found a number and nothing else?
579     if (end > value_str && *end == '\0')
580       // value is in range?
581       if (value >= 0 && (longlong)value < (longlong)value_count)
582         goto end;
583 
584     // Not a valid value.
585     DBUG_RETURN(value_str);
586 
587 end:
588     global_var(ulong)= value;
589     DBUG_RETURN(NULL);
590   }
591 
do_check(THD * thd,set_var * var)592   bool do_check(THD *thd, set_var *var)
593   {
594     DBUG_ENTER("Sys_var_multi_enum::do_check");
595     char buff[STRING_BUFFER_USUAL_SIZE];
596     String str(buff, sizeof(buff), system_charset_info), *res;
597     if (var->value->result_type() == STRING_RESULT)
598     {
599       res= var->value->val_str(&str);
600       if (!res)
601         DBUG_RETURN(true);
602       int value= find_value(res->ptr());
603       if (value == -1)
604         DBUG_RETURN(true);
605       var->save_result.ulonglong_value= (uint)value;
606     }
607     else
608     {
609       longlong value= var->value->val_int();
610       if (value < 0 || value >= (longlong)value_count)
611         DBUG_RETURN(true);
612       else
613         var->save_result.ulonglong_value= value;
614     }
615 
616     DBUG_RETURN(false);
617   }
check_update_type(Item_result type)618   bool check_update_type(Item_result type)
619   { return type != INT_RESULT && type != STRING_RESULT; }
session_update(THD * thd,set_var * var)620   bool session_update(THD *thd, set_var *var)
621   {
622     DBUG_ENTER("Sys_var_multi_enum::session_update");
623     assert(0);
624     /*
625     Currently not used: uncomment if this class is used as a base for
626     a session variable.
627 
628     session_var(thd, ulong)=
629       static_cast<ulong>(var->save_result.ulonglong_value);
630     */
631     DBUG_RETURN(false);
632   }
global_update(THD * thd,set_var * var)633   bool global_update(THD *thd, set_var *var)
634   {
635     DBUG_ENTER("Sys_var_multi_enum::global_update");
636     assert(0);
637     /*
638     Currently not used: uncomment if this some inheriting class does
639     not override..
640 
641     ulong val=
642       static_cast<ulong>(var->save_result.ulonglong_value);
643     global_var(ulong)= val;
644     */
645     DBUG_RETURN(false);
646   }
session_save_default(THD * thd,set_var * var)647   void session_save_default(THD *thd, set_var *var)
648   {
649     DBUG_ENTER("Sys_var_multi_enum::session_save_default");
650     assert(0);
651     /*
652     Currently not used: uncomment if this class is used as a base for
653     a session variable.
654 
655     int value= find_value((char *)option.def_value);
656     assert(value != -1);
657     var->save_result.ulonglong_value= value;
658     */
659     DBUG_VOID_RETURN;
660   }
global_save_default(THD * thd,set_var * var)661   void global_save_default(THD *thd, set_var *var)
662   {
663     DBUG_ENTER("Sys_var_multi_enum::global_save_default");
664     int value= find_value((char *)option.def_value);
665     assert(value != -1);
666     var->save_result.ulonglong_value= value;
667     DBUG_VOID_RETURN;
668   }
669 
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)670   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
671   {
672     DBUG_ENTER("Sys_var_multi_enum::session_value_ptr");
673     assert(0);
674     /*
675     Currently not used: uncomment if this class is used as a base for
676     a session variable.
677 
678     DBUG_RETURN((uchar*)aliases[session_var(target_thd, ulong)].alias);
679     */
680     DBUG_RETURN(0);
681   }
global_value_ptr(THD * thd,LEX_STRING * base)682   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
683   {
684     DBUG_ENTER("Sys_var_multi_enum::global_value_ptr");
685     DBUG_RETURN((uchar*)aliases[global_var(ulong)].alias);
686   }
687 private:
688   /// The number of allowed numeric values.
689   const uint value_count;
690   /// Array of all textual aliases.
691   const ALIAS *aliases;
692   /// The number of elements of aliases (computed in the constructor).
693   uint alias_count;
694 
695   /**
696     Pointer to the value set by the command line (set by the command
697     line parser, copied to the global value in fixup_command_line()).
698   */
699   const char *command_line_value;
700   uint command_line_no_value;
701 };
702 
703 /**
704   The class for string variables. The string can be in character_set_filesystem
705   or in character_set_system. The string can be allocated with my_malloc()
706   or not. The state of the initial value is specified in the constructor,
707   after that it's managed automatically. The value of NULL is supported.
708 
709   Class specific constructor arguments:
710     enum charset_enum is_os_charset_arg
711 
712   Backing store: char*
713 
714 */
715 class Sys_var_charptr: public sys_var
716 {
717 public:
718   Sys_var_charptr(const char *name_arg,
719           const char *comment, int flag_args, ptrdiff_t off, size_t size,
720           CMD_LINE getopt,
721           enum charset_enum is_os_charset_arg,
722           const char *def_val, PolyLock *lock= 0,
723           enum binlog_status_enum binlog_status_arg= VARIABLE_NOT_IN_BINLOG,
724           on_check_function on_check_func= 0,
725           on_update_function on_update_func= 0,
726           const char *substitute= 0,
727           int parse_flag= PARSE_NORMAL)
728     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
729               getopt.arg_type, SHOW_CHAR_PTR, (intptr) def_val,
730               lock, binlog_status_arg, on_check_func, on_update_func,
731               substitute, parse_flag)
732   {
733     is_os_charset= is_os_charset_arg == IN_FS_CHARSET;
734     option.var_type= (flags & ALLOCATED) ? GET_STR_ALLOC : GET_STR;
735     global_var(const char*)= def_val;
736     assert(size == sizeof(char *));
737   }
738 
cleanup()739   void cleanup()
740   {
741     if (flags & ALLOCATED)
742       my_free(global_var(char*));
743     flags&= ~ALLOCATED;
744   }
745 
do_check(THD * thd,set_var * var)746   bool do_check(THD *thd, set_var *var)
747   {
748     char buff[STRING_BUFFER_USUAL_SIZE], buff2[STRING_BUFFER_USUAL_SIZE];
749     String str(buff, sizeof(buff), charset(thd));
750     String str2(buff2, sizeof(buff2), charset(thd)), *res;
751 
752     if (!(res=var->value->val_str(&str)))
753       var->save_result.string_value.str= 0;
754     else
755     {
756       size_t unused;
757       if (String::needs_conversion(res->length(), res->charset(),
758                                    charset(thd), &unused))
759       {
760         uint errors;
761         str2.copy(res->ptr(), res->length(), res->charset(), charset(thd),
762                   &errors);
763         res= &str2;
764 
765       }
766       var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
767       var->save_result.string_value.length= res->length();
768     }
769 
770     return false;
771   }
772 
session_update(THD * thd,set_var * var)773   bool session_update(THD *thd, set_var *var)
774   {
775     char *new_val=  var->save_result.string_value.str;
776     size_t new_val_len= var->save_result.string_value.length;
777     char *ptr= ((char *)&thd->variables + offset);
778 
779     return thd->session_sysvar_res_mgr.update((char **) ptr, new_val,
780                                               new_val_len);
781   }
782 
global_update(THD * thd,set_var * var)783   bool global_update(THD *thd, set_var *var)
784   {
785     char *new_val, *ptr= var->save_result.string_value.str;
786     size_t len=var->save_result.string_value.length;
787     if (ptr)
788     {
789       new_val= (char*) my_memdup(key_memory_Sys_var_charptr_value,
790                                  ptr, len+1, MYF(MY_WME));
791       if (!new_val) return true;
792       new_val[len]= 0;
793     }
794     else
795       new_val= 0;
796     if (flags & ALLOCATED)
797       my_free(global_var(char*));
798     flags |= ALLOCATED;
799     global_var(char*)= new_val;
800     return false;
801   }
802 
session_save_default(THD * thd,set_var * var)803   void session_save_default(THD *thd, set_var *var)
804   {
805     char *ptr= (char*)(intptr)option.def_value;
806     var->save_result.string_value.str= ptr;
807     var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
808   }
809 
global_save_default(THD * thd,set_var * var)810   void global_save_default(THD *thd, set_var *var)
811   {
812     char *ptr= (char*)(intptr)option.def_value;
813     var->save_result.string_value.str= ptr;
814     var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
815   }
816 
check_update_type(Item_result type)817   bool check_update_type(Item_result type)
818   { return type != STRING_RESULT; }
819 };
820 
821 class Sys_var_version : public Sys_var_charptr
822 {
823 public:
Sys_var_version(const char * name_arg,const char * comment,int flag_args,ptrdiff_t off,size_t size,CMD_LINE getopt,enum charset_enum is_os_charset_arg,const char * def_val)824   Sys_var_version(const char *name_arg,
825           const char *comment, int flag_args, ptrdiff_t off, size_t size,
826           CMD_LINE getopt,
827           enum charset_enum is_os_charset_arg,
828           const char *def_val)
829     : Sys_var_charptr(name_arg, comment, flag_args, off, size, getopt, is_os_charset_arg, def_val)
830   {}
831 
~Sys_var_version()832   ~Sys_var_version()
833   {}
834 
global_value_ptr(THD * thd,LEX_STRING * base)835   virtual uchar *global_value_ptr(THD *thd, LEX_STRING *base)
836   {
837     uchar *value= Sys_var_charptr::global_value_ptr(thd, base);
838 
839     DBUG_EXECUTE_IF("alter_server_version_str",
840                     {
841                       static const char *altered_value= "some-other-version";
842                       uchar *altered_value_ptr= reinterpret_cast<uchar*> (& altered_value);
843                       value= altered_value_ptr;
844                     });
845 
846     return value;
847   }
848 };
849 
850 
851 class Sys_var_proxy_user: public sys_var
852 {
853 public:
Sys_var_proxy_user(const char * name_arg,const char * comment,enum charset_enum is_os_charset_arg)854   Sys_var_proxy_user(const char *name_arg,
855           const char *comment, enum charset_enum is_os_charset_arg)
856     : sys_var(&all_sys_vars, name_arg, comment,
857               sys_var::READONLY+sys_var::ONLY_SESSION, 0, -1,
858               NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
859               NULL, NULL, NULL, PARSE_NORMAL)
860   {
861     is_os_charset= is_os_charset_arg == IN_FS_CHARSET;
862     option.var_type= GET_STR;
863   }
do_check(THD * thd,set_var * var)864   bool do_check(THD *thd, set_var *var)
865   {
866     assert(FALSE);
867     return true;
868   }
session_update(THD * thd,set_var * var)869   bool session_update(THD *thd, set_var *var)
870   {
871     assert(FALSE);
872     return true;
873   }
global_update(THD * thd,set_var * var)874   bool global_update(THD *thd, set_var *var)
875   {
876     assert(FALSE);
877     return false;
878   }
session_save_default(THD * thd,set_var * var)879   void session_save_default(THD *thd, set_var *var)
880   { assert(FALSE); }
global_save_default(THD * thd,set_var * var)881   void global_save_default(THD *thd, set_var *var)
882   { assert(FALSE); }
check_update_type(Item_result type)883   bool check_update_type(Item_result type)
884   { return true; }
885 protected:
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)886   virtual uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
887   {
888     const char* proxy_user= target_thd->security_context()->proxy_user().str;
889     return proxy_user[0] ? (uchar *)proxy_user : NULL;
890   }
891 };
892 
893 class Sys_var_external_user : public Sys_var_proxy_user
894 {
895 public:
Sys_var_external_user(const char * name_arg,const char * comment_arg,enum charset_enum is_os_charset_arg)896   Sys_var_external_user(const char *name_arg, const char *comment_arg,
897           enum charset_enum is_os_charset_arg)
898     : Sys_var_proxy_user (name_arg, comment_arg, is_os_charset_arg)
899   {}
900 
901 protected:
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)902   virtual uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
903   {
904     LEX_CSTRING external_user= target_thd->security_context()->external_user();
905     return external_user.length ? (uchar *) external_user.str : NULL;
906   }
907 };
908 
909 /**
910   The class for string variables. Useful for strings that aren't necessarily
911   \0-terminated. Otherwise the same as Sys_var_charptr.
912 
913   Class specific constructor arguments:
914     enum charset_enum is_os_charset_arg
915 
916   Backing store: LEX_STRING
917 
918   @note
919   Behaves exactly as Sys_var_charptr, only the backing store is different.
920 */
921 class Sys_var_lexstring: public Sys_var_charptr
922 {
923 public:
924   Sys_var_lexstring(const char *name_arg,
925           const char *comment, int flag_args, ptrdiff_t off, size_t size,
926           CMD_LINE getopt,
927           enum charset_enum is_os_charset_arg,
928           const char *def_val, PolyLock *lock=0,
929           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
930           on_check_function on_check_func=0,
931           on_update_function on_update_func=0,
932           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)933     : Sys_var_charptr(name_arg, comment, flag_args, off, sizeof(char*),
934               getopt, is_os_charset_arg, def_val, lock, binlog_status_arg,
935               on_check_func, on_update_func, substitute)
936   {
937     global_var(LEX_STRING).length= strlen(def_val);
938     assert(size == sizeof(LEX_STRING));
939     *const_cast<SHOW_TYPE*>(&show_val_type)= SHOW_LEX_STRING;
940   }
global_update(THD * thd,set_var * var)941   bool global_update(THD *thd, set_var *var)
942   {
943     if (Sys_var_charptr::global_update(thd, var))
944       return true;
945     global_var(LEX_STRING).length= var->save_result.string_value.length;
946     return false;
947   }
948 };
949 
950 #ifndef NDEBUG
951 /**
952   @@session.dbug and @@global.dbug variables.
953 
954   @@dbug variable differs from other variables in one aspect:
955   if its value is not assigned in the session, it "points" to the global
956   value, and so when the global value is changed, the change
957   immediately takes effect in the session.
958 
959   This semantics is intentional, to be able to debug one session from
960   another.
961 */
962 class Sys_var_dbug: public sys_var
963 {
964 public:
965   Sys_var_dbug(const char *name_arg,
966                const char *comment, int flag_args,
967                CMD_LINE getopt,
968                const char *def_val, PolyLock *lock=0,
969                enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
970                on_check_function on_check_func=0,
971                on_update_function on_update_func=0,
972                const char *substitute=0,
973                int parse_flag= PARSE_NORMAL)
974     : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id,
975               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
976               lock, binlog_status_arg, on_check_func, on_update_func,
977               substitute, parse_flag)
978   { option.var_type= GET_NO_ARG; }
do_check(THD * thd,set_var * var)979   bool do_check(THD *thd, set_var *var)
980   {
981     char buff[STRING_BUFFER_USUAL_SIZE];
982     String str(buff, sizeof(buff), system_charset_info), *res;
983 
984     if (!(res=var->value->val_str(&str)))
985       var->save_result.string_value.str= const_cast<char*>("");
986     else
987       var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
988     return false;
989   }
session_update(THD * thd,set_var * var)990   bool session_update(THD *thd, set_var *var)
991   {
992     const char *val= var->save_result.string_value.str;
993     if (!var->value)
994       DBUG_POP();
995     else
996       DBUG_SET(val);
997     return false;
998   }
global_update(THD * thd,set_var * var)999   bool global_update(THD *thd, set_var *var)
1000   {
1001     const char *val= var->save_result.string_value.str;
1002     DBUG_SET_INITIAL(val);
1003     return false;
1004   }
session_save_default(THD * thd,set_var * var)1005   void session_save_default(THD *thd, set_var *var)
1006   { }
global_save_default(THD * thd,set_var * var)1007   void global_save_default(THD *thd, set_var *var)
1008   {
1009     char *ptr= (char*)(intptr)option.def_value;
1010     var->save_result.string_value.str= ptr;
1011   }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1012   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
1013   {
1014     char buf[256];
1015     DBUG_EXPLAIN(buf, sizeof(buf));
1016     return (uchar*) running_thd->mem_strdup(buf);
1017   }
global_value_ptr(THD * thd,LEX_STRING * base)1018   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1019   {
1020     char buf[256];
1021     DBUG_EXPLAIN_INITIAL(buf, sizeof(buf));
1022     return (uchar*) thd->mem_strdup(buf);
1023   }
check_update_type(Item_result type)1024   bool check_update_type(Item_result type)
1025   { return type != STRING_RESULT; }
1026 };
1027 #endif
1028 
1029 #define KEYCACHE_VAR(X) sys_var::GLOBAL,offsetof(KEY_CACHE, X), sizeof(((KEY_CACHE *)0)->X)
1030 #define keycache_var_ptr(KC, OFF) (((uchar*)(KC))+(OFF))
1031 #define keycache_var(KC, OFF) (*(ulonglong*)keycache_var_ptr(KC, OFF))
1032 typedef bool (*keycache_update_function)(THD *, KEY_CACHE *, ptrdiff_t, ulonglong);
1033 
1034 /**
1035   The class for keycache_* variables. Supports structured names,
1036   keycache_name.variable_name.
1037 
1038   Class specific constructor arguments:
1039     everything derived from Sys_var_ulonglong
1040 
1041   Backing store: ulonglong
1042 
1043   @note these variables can be only GLOBAL
1044 */
1045 class Sys_var_keycache: public Sys_var_ulonglong
1046 {
1047   keycache_update_function keycache_update;
1048 public:
1049   Sys_var_keycache(const char *name_arg,
1050           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1051           CMD_LINE getopt,
1052           ulonglong min_val, ulonglong max_val, ulonglong def_val,
1053           uint block_size, PolyLock *lock,
1054           enum binlog_status_enum binlog_status_arg,
1055           on_check_function on_check_func,
1056           keycache_update_function on_update_func,
1057           const char *substitute=0)
1058     : Sys_var_ulonglong(name_arg, comment, flag_args,
1059                         -1,     /* offset, see base class CTOR */
1060                         size,
1061                         getopt, min_val, max_val, def_val,
1062                         block_size, lock, binlog_status_arg, on_check_func, 0,
1063                         substitute),
1064     keycache_update(on_update_func)
1065   {
1066     offset= off; /* Remember offset in KEY_CACHE */
1067     option.var_type|= GET_ASK_ADDR;
1068     option.value= (uchar**)1; // crash me, please
1069     keycache_var(dflt_key_cache, off)= def_val;
1070     assert(scope() == GLOBAL);
1071   }
global_update(THD * thd,set_var * var)1072   bool global_update(THD *thd, set_var *var)
1073   {
1074     ulonglong new_value= var->save_result.ulonglong_value;
1075     LEX_STRING *base_name= &var->base;
1076     KEY_CACHE *key_cache;
1077 
1078     /* If no basename, assume it's for the key cache named 'default' */
1079     if (!base_name->length)
1080       base_name= &default_key_cache_base;
1081 
1082     key_cache= get_key_cache(base_name);
1083 
1084     if (!key_cache)
1085     {                                           // Key cache didn't exists */
1086       if (!new_value)                           // Tried to delete cache
1087         return false;                           // Ok, nothing to do
1088       if (!(key_cache= create_key_cache(base_name->str, base_name->length)))
1089         return true;
1090     }
1091 
1092     /**
1093       Abort if some other thread is changing the key cache
1094       @todo This should be changed so that we wait until the previous
1095       assignment is done and then do the new assign
1096     */
1097     if (key_cache->in_init)
1098       return true;
1099 
1100     return keycache_update(thd, key_cache, offset, new_value);
1101   }
global_value_ptr(THD * thd,LEX_STRING * base)1102   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1103   {
1104     KEY_CACHE *key_cache= get_key_cache(base);
1105     if (!key_cache)
1106       key_cache= &zero_key_cache;
1107     return keycache_var_ptr(key_cache, offset);
1108   }
1109 };
1110 
1111 /**
1112   The class for floating point variables
1113 
1114   Class specific constructor arguments: min, max
1115 
1116   Backing store: double
1117 */
1118 class Sys_var_double: public sys_var
1119 {
1120 public:
1121   Sys_var_double(const char *name_arg,
1122           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1123           CMD_LINE getopt,
1124           double min_val, double max_val, double def_val, PolyLock *lock=0,
1125           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1126           on_check_function on_check_func=0,
1127           on_update_function on_update_func=0,
1128           const char *substitute=0,
1129           int parse_flag= PARSE_NORMAL)
1130     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
1131               getopt.arg_type, SHOW_DOUBLE,
1132               (longlong) getopt_double2ulonglong(def_val),
1133               lock, binlog_status_arg, on_check_func, on_update_func,
1134               substitute, parse_flag)
1135   {
1136     option.var_type= GET_DOUBLE;
1137     option.min_value= (longlong) getopt_double2ulonglong(min_val);
1138     option.max_value= (longlong) getopt_double2ulonglong(max_val);
1139     global_var(double)= (double)option.def_value;
1140     assert(min_val <= max_val);
1141     assert(min_val <= def_val);
1142     assert(max_val >= def_val);
1143     assert(size == sizeof(double));
1144   }
do_check(THD * thd,set_var * var)1145   bool do_check(THD *thd, set_var *var)
1146   {
1147     my_bool fixed;
1148     double v= var->value->val_real();
1149     var->save_result.double_value= getopt_double_limit_value(v, &option, &fixed);
1150 
1151     return throw_bounds_warning(thd, name.str, fixed, v);
1152   }
session_update(THD * thd,set_var * var)1153   bool session_update(THD *thd, set_var *var)
1154   {
1155     session_var(thd, double)= var->save_result.double_value;
1156     return false;
1157   }
global_update(THD * thd,set_var * var)1158   bool global_update(THD *thd, set_var *var)
1159   {
1160     global_var(double)= var->save_result.double_value;
1161     return false;
1162   }
check_update_type(Item_result type)1163   bool check_update_type(Item_result type)
1164   {
1165     return type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT;
1166   }
session_save_default(THD * thd,set_var * var)1167   void session_save_default(THD *thd, set_var *var)
1168   { var->save_result.double_value= global_var(double); }
global_save_default(THD * thd,set_var * var)1169   void global_save_default(THD *thd, set_var *var)
1170   { var->save_result.double_value= getopt_ulonglong2double(option.def_value); }
1171 };
1172 
1173 /**
1174   The class for @test_flags (core_file for now).
1175   It's derived from Sys_var_mybool.
1176 
1177   Class specific constructor arguments:
1178     Caller need not pass in a variable as we make up the value on the
1179     fly, that is, we derive it from the global test_flags bit vector.
1180 
1181   Backing store: my_bool
1182 */
1183 class Sys_var_test_flag: public Sys_var_mybool
1184 {
1185 private:
1186   my_bool test_flag_value;
1187   uint    test_flag_mask;
1188 public:
Sys_var_test_flag(const char * name_arg,const char * comment,uint mask)1189   Sys_var_test_flag(const char *name_arg, const char *comment, uint mask)
1190   : Sys_var_mybool(name_arg, comment, READ_ONLY GLOBAL_VAR(test_flag_value),
1191           NO_CMD_LINE, DEFAULT(FALSE))
1192   {
1193     test_flag_mask= mask;
1194   }
global_value_ptr(THD * thd,LEX_STRING * base)1195   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1196   {
1197     test_flag_value= ((test_flags & test_flag_mask) > 0);
1198     return (uchar*) &test_flag_value;
1199   }
1200 };
1201 
1202 /**
1203   The class for the @max_user_connections.
1204   It's derived from Sys_var_uint, but non-standard session value
1205   requires a new class.
1206 
1207   Class specific constructor arguments:
1208     everything derived from Sys_var_uint
1209 
1210   Backing store: uint
1211 */
1212 class Sys_var_max_user_conn: public Sys_var_uint
1213 {
1214 public:
1215   Sys_var_max_user_conn(const char *name_arg,
1216           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1217           CMD_LINE getopt,
1218           uint min_val, uint max_val, uint def_val,
1219           uint block_size, PolyLock *lock=0,
1220           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1221           on_check_function on_check_func=0,
1222           on_update_function on_update_func=0,
1223           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)1224     : Sys_var_uint(name_arg, comment, SESSION, off, size, getopt,
1225               min_val, max_val, def_val, block_size,
1226               lock, binlog_status_arg, on_check_func, on_update_func,
1227               substitute)
1228   { }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1229   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
1230   {
1231     const USER_CONN *uc= target_thd->get_user_connect();
1232     if (uc && uc->user_resources.user_conn)
1233       return (uchar*) &(uc->user_resources.user_conn);
1234     return global_value_ptr(running_thd, base);
1235   }
1236 };
1237 
1238 // overflow-safe (1 << X)-1
1239 #define MAX_SET(X) ((((1UL << ((X)-1))-1) << 1) | 1)
1240 
1241 /**
1242   The class for flagset variables - a variant of SET that allows in-place
1243   editing (turning on/off individual bits). String representations looks like
1244   a "flag=val,flag=val,...". Example: @@optimizer_switch
1245 
1246   Class specific constructor arguments:
1247     char* values[]    - 0-terminated list of strings of valid values
1248 
1249   Backing store: ulonglong
1250 
1251   @note
1252   the last value in the values[] array should
1253   *always* be the string "default".
1254 */
1255 class Sys_var_flagset: public Sys_var_typelib
1256 {
1257 public:
1258   Sys_var_flagset(const char *name_arg,
1259           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1260           CMD_LINE getopt,
1261           const char *values[], ulonglong def_val, PolyLock *lock=0,
1262           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1263           on_check_function on_check_func=0,
1264           on_update_function on_update_func=0,
1265           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)1266     : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
1267                       SHOW_CHAR, values, def_val, lock,
1268                       binlog_status_arg, on_check_func, on_update_func,
1269                       substitute)
1270   {
1271     option.var_type= GET_FLAGSET;
1272     global_var(ulonglong)= def_val;
1273     assert(typelib.count > 1);
1274     assert(typelib.count <= 65);
1275     assert(def_val < MAX_SET(typelib.count));
1276     assert(strcmp(values[typelib.count-1], "default") == 0);
1277     assert(size == sizeof(ulonglong));
1278   }
do_check(THD * thd,set_var * var)1279   bool do_check(THD *thd, set_var *var)
1280   {
1281     char buff[STRING_BUFFER_USUAL_SIZE];
1282     String str(buff, sizeof(buff), system_charset_info), *res;
1283     ulonglong default_value, current_value;
1284     if (var->type == OPT_GLOBAL)
1285     {
1286       default_value= option.def_value;
1287       current_value= global_var(ulonglong);
1288     }
1289     else
1290     {
1291       default_value= global_var(ulonglong);
1292       current_value= session_var(thd, ulonglong);
1293     }
1294 
1295     if (var->value->result_type() == STRING_RESULT)
1296     {
1297       if (!(res=var->value->val_str(&str)))
1298         return true;
1299       else
1300       {
1301         char *error;
1302         uint error_len;
1303 
1304         var->save_result.ulonglong_value=
1305               find_set_from_flags(&typelib,
1306                                   typelib.count,
1307                                   current_value,
1308                                   default_value,
1309                                   res->ptr(),
1310                                   static_cast<uint>(res->length()),
1311                                   &error, &error_len);
1312         if (error)
1313         {
1314           ErrConvString err(error, error_len, res->charset());
1315           my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
1316           return true;
1317         }
1318       }
1319     }
1320     else
1321     {
1322       longlong tmp=var->value->val_int();
1323       if ((tmp < 0 && ! var->value->unsigned_flag)
1324           || (ulonglong)tmp > MAX_SET(typelib.count))
1325         return true;
1326       else
1327         var->save_result.ulonglong_value= tmp;
1328     }
1329 
1330     return false;
1331   }
session_update(THD * thd,set_var * var)1332   bool session_update(THD *thd, set_var *var)
1333   {
1334     session_var(thd, ulonglong)= var->save_result.ulonglong_value;
1335     return false;
1336   }
global_update(THD * thd,set_var * var)1337   bool global_update(THD *thd, set_var *var)
1338   {
1339     global_var(ulonglong)= var->save_result.ulonglong_value;
1340     return false;
1341   }
session_save_default(THD * thd,set_var * var)1342   void session_save_default(THD *thd, set_var *var)
1343   { var->save_result.ulonglong_value= global_var(ulonglong); }
global_save_default(THD * thd,set_var * var)1344   void global_save_default(THD *thd, set_var *var)
1345   { var->save_result.ulonglong_value= option.def_value; }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1346   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
1347   {
1348     return (uchar*)flagset_to_string(running_thd, 0, session_var(target_thd, ulonglong),
1349                                      typelib.type_names);
1350   }
global_value_ptr(THD * thd,LEX_STRING * base)1351   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1352   {
1353     return (uchar*)flagset_to_string(thd, 0, global_var(ulonglong),
1354                                      typelib.type_names);
1355   }
1356 };
1357 
1358 /**
1359   The class for SET variables - variables taking zero or more values
1360   from the given list. Example: @@sql_mode
1361 
1362   Class specific constructor arguments:
1363     char* values[]    - 0-terminated list of strings of valid values
1364 
1365   Backing store: ulonglong
1366 */
1367 class Sys_var_set: public Sys_var_typelib
1368 {
1369 public:
1370   Sys_var_set(const char *name_arg,
1371           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1372           CMD_LINE getopt,
1373           const char *values[], ulonglong def_val, PolyLock *lock=0,
1374           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1375           on_check_function on_check_func=0,
1376           on_update_function on_update_func=0,
1377           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)1378     : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
1379                       SHOW_CHAR, values, def_val, lock,
1380                       binlog_status_arg, on_check_func, on_update_func,
1381                       substitute)
1382   {
1383     option.var_type= GET_SET;
1384     global_var(ulonglong)= def_val;
1385     assert(typelib.count > 0);
1386     assert(typelib.count <= 64);
1387     assert(def_val < MAX_SET(typelib.count));
1388     assert(size == sizeof(ulonglong));
1389   }
do_check(THD * thd,set_var * var)1390   bool do_check(THD *thd, set_var *var)
1391   {
1392     char buff[STRING_BUFFER_USUAL_SIZE];
1393     String str(buff, sizeof(buff), system_charset_info), *res;
1394 
1395     if (var->value->result_type() == STRING_RESULT)
1396     {
1397       if (!(res=var->value->val_str(&str)))
1398         return true;
1399       else
1400       {
1401         char *error;
1402         uint error_len;
1403         bool not_used;
1404 
1405         var->save_result.ulonglong_value=
1406               find_set(&typelib, res->ptr(),
1407                        static_cast<uint>(res->length()), NULL,
1408                        &error, &error_len, &not_used);
1409         /*
1410           note, we only issue an error if error_len > 0.
1411           That is even while empty (zero-length) values are considered
1412           errors by find_set(), these errors are ignored here
1413         */
1414         if (error_len)
1415         {
1416           ErrConvString err(error, error_len, res->charset());
1417           my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
1418           return true;
1419         }
1420       }
1421     }
1422     else
1423     {
1424       longlong tmp=var->value->val_int();
1425       if ((tmp < 0 && ! var->value->unsigned_flag)
1426           || (ulonglong)tmp > MAX_SET(typelib.count))
1427         return true;
1428       else
1429         var->save_result.ulonglong_value= tmp;
1430     }
1431 
1432     return false;
1433   }
session_update(THD * thd,set_var * var)1434   bool session_update(THD *thd, set_var *var)
1435   {
1436     session_var(thd, ulonglong)= var->save_result.ulonglong_value;
1437     return false;
1438   }
global_update(THD * thd,set_var * var)1439   bool global_update(THD *thd, set_var *var)
1440   {
1441     global_var(ulonglong)= var->save_result.ulonglong_value;
1442     return false;
1443   }
session_save_default(THD * thd,set_var * var)1444   void session_save_default(THD *thd, set_var *var)
1445   { var->save_result.ulonglong_value= global_var(ulonglong); }
global_save_default(THD * thd,set_var * var)1446   void global_save_default(THD *thd, set_var *var)
1447   { var->save_result.ulonglong_value= option.def_value; }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1448   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
1449   {
1450     return (uchar*)set_to_string(running_thd, 0, session_var(target_thd, ulonglong),
1451                                  typelib.type_names);
1452   }
global_value_ptr(THD * thd,LEX_STRING * base)1453   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1454   {
1455     return (uchar*)set_to_string(thd, 0, global_var(ulonglong),
1456                                  typelib.type_names);
1457   }
1458 };
1459 
1460 /**
1461   The class for variables which value is a plugin.
1462   Example: @@default_storage_engine
1463 
1464   Class specific constructor arguments:
1465     int plugin_type_arg (for example MYSQL_STORAGE_ENGINE_PLUGIN)
1466 
1467   Backing store: plugin_ref
1468 
1469   @note
1470   these variables don't support command-line equivalents, any such
1471   command-line options should be added manually to my_long_options in mysqld.cc
1472 */
1473 class Sys_var_plugin: public sys_var
1474 {
1475   int plugin_type;
1476 public:
1477   Sys_var_plugin(const char *name_arg,
1478           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1479           CMD_LINE getopt,
1480           int plugin_type_arg, char **def_val, PolyLock *lock=0,
1481           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1482           on_check_function on_check_func=0,
1483           on_update_function on_update_func=0,
1484           const char *substitute=0,
1485           int parse_flag= PARSE_NORMAL)
1486     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
1487               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
1488               lock, binlog_status_arg, on_check_func, on_update_func,
1489               substitute, parse_flag),
1490     plugin_type(plugin_type_arg)
1491   {
1492     option.var_type= GET_STR;
1493     assert(size == sizeof(plugin_ref));
1494     assert(getopt.id == -1); // force NO_CMD_LINE
1495   }
do_check(THD * thd,set_var * var)1496   bool do_check(THD *thd, set_var *var)
1497   {
1498     char buff[STRING_BUFFER_USUAL_SIZE];
1499     String str(buff,sizeof(buff), system_charset_info), *res;
1500 
1501     /* NULLs can't be used as a default storage engine */
1502     if (!(res=var->value->val_str(&str)))
1503       return true;
1504 
1505     const LEX_STRING pname= { const_cast<char*>(res->ptr()), res->length() };
1506     plugin_ref plugin;
1507 
1508     // special code for storage engines (e.g. to handle historical aliases)
1509     if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
1510       plugin= ha_resolve_by_name(thd, &pname, FALSE);
1511     else
1512     {
1513       LEX_CSTRING pname_cstr= { pname.str, pname.length };
1514       plugin= my_plugin_lock_by_name(thd, pname_cstr, plugin_type);
1515     }
1516 
1517     if (!plugin)
1518     {
1519       // historically different error code
1520       if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
1521       {
1522         ErrConvString err(res);
1523         my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), err.ptr());
1524       }
1525       return true;
1526     }
1527     var->save_result.plugin= plugin;
1528     return false;
1529   }
do_update(plugin_ref * valptr,plugin_ref newval)1530   void do_update(plugin_ref *valptr, plugin_ref newval)
1531   {
1532     plugin_ref oldval= *valptr;
1533     if (oldval != newval)
1534     {
1535       *valptr= my_plugin_lock(NULL, &newval);
1536       plugin_unlock(NULL, oldval);
1537     }
1538   }
session_update(THD * thd,set_var * var)1539   bool session_update(THD *thd, set_var *var)
1540   {
1541     do_update((plugin_ref*)session_var_ptr(thd),
1542               var->save_result.plugin);
1543     return false;
1544   }
global_update(THD * thd,set_var * var)1545   bool global_update(THD *thd, set_var *var)
1546   {
1547     do_update((plugin_ref*)global_var_ptr(),
1548               var->save_result.plugin);
1549     return false;
1550   }
session_save_default(THD * thd,set_var * var)1551   void session_save_default(THD *thd, set_var *var)
1552   {
1553     plugin_ref plugin= global_var(plugin_ref);
1554     var->save_result.plugin= my_plugin_lock(thd, &plugin);
1555   }
global_save_default(THD * thd,set_var * var)1556   void global_save_default(THD *thd, set_var *var)
1557   {
1558     LEX_STRING pname;
1559     char **default_value= reinterpret_cast<char**>(option.def_value);
1560     pname.str= *default_value;
1561     pname.length= strlen(pname.str);
1562 
1563     plugin_ref plugin;
1564     if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
1565       plugin= ha_resolve_by_name(thd, &pname, FALSE);
1566     else
1567     {
1568       LEX_CSTRING pname_cstr= {pname.str,pname.length};
1569       plugin= my_plugin_lock_by_name(thd, pname_cstr, plugin_type);
1570     }
1571     assert(plugin);
1572 
1573     var->save_result.plugin= my_plugin_lock(thd, &plugin);
1574   }
check_update_type(Item_result type)1575   bool check_update_type(Item_result type)
1576   { return type != STRING_RESULT; }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1577   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
1578   {
1579     plugin_ref plugin= session_var(target_thd, plugin_ref);
1580     return (uchar*)(plugin ? running_thd->strmake(plugin_name(plugin)->str,
1581                                           plugin_name(plugin)->length) : 0);
1582   }
global_value_ptr(THD * thd,LEX_STRING * base)1583   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1584   {
1585     plugin_ref plugin= global_var(plugin_ref);
1586     return (uchar*)(plugin ? thd->strmake(plugin_name(plugin)->str,
1587                                           plugin_name(plugin)->length) : 0);
1588   }
1589 };
1590 
1591 #if defined(ENABLED_DEBUG_SYNC)
1592 /**
1593   The class for @@debug_sync session-only variable
1594 */
1595 class Sys_var_debug_sync :public sys_var
1596 {
1597 public:
1598   Sys_var_debug_sync(const char *name_arg,
1599                const char *comment, int flag_args,
1600                CMD_LINE getopt,
1601                const char *def_val, PolyLock *lock=0,
1602                enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1603                on_check_function on_check_func=0,
1604                on_update_function on_update_func=0,
1605                const char *substitute=0,
1606                int parse_flag= PARSE_NORMAL)
1607     : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id,
1608               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
1609               lock, binlog_status_arg, on_check_func, on_update_func,
1610               substitute, parse_flag)
1611   {
1612     assert(scope() == ONLY_SESSION);
1613     option.var_type= GET_NO_ARG;
1614   }
do_check(THD * thd,set_var * var)1615   bool do_check(THD *thd, set_var *var)
1616   {
1617     char buff[STRING_BUFFER_USUAL_SIZE];
1618     String str(buff, sizeof(buff), system_charset_info), *res;
1619 
1620     if (!(res=var->value->val_str(&str)))
1621       var->save_result.string_value.str= const_cast<char*>("");
1622     else
1623       var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
1624     return false;
1625   }
session_update(THD * thd,set_var * var)1626   bool session_update(THD *thd, set_var *var)
1627   {
1628     extern bool debug_sync_update(THD *thd, char *val_str);
1629     return debug_sync_update(thd, var->save_result.string_value.str);
1630   }
global_update(THD * thd,set_var * var)1631   bool global_update(THD *thd, set_var *var)
1632   {
1633     assert(FALSE);
1634     return true;
1635   }
session_save_default(THD * thd,set_var * var)1636   void session_save_default(THD *thd, set_var *var)
1637   {
1638     var->save_result.string_value.str= const_cast<char*>("");
1639     var->save_result.string_value.length= 0;
1640   }
global_save_default(THD * thd,set_var * var)1641   void global_save_default(THD *thd, set_var *var)
1642   {
1643     assert(FALSE);
1644   }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1645   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
1646   {
1647     extern uchar *debug_sync_value_ptr(THD *thd);
1648     return debug_sync_value_ptr(running_thd);
1649   }
global_value_ptr(THD * thd,LEX_STRING * base)1650   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1651   {
1652     assert(FALSE);
1653     return 0;
1654   }
check_update_type(Item_result type)1655   bool check_update_type(Item_result type)
1656   { return type != STRING_RESULT; }
1657 };
1658 #endif /* defined(ENABLED_DEBUG_SYNC) */
1659 
1660 /**
1661   The class for bit variables - a variant of boolean that stores the value
1662   in a bit.
1663 
1664   Class specific constructor arguments:
1665     ulonglong bitmask_arg - the mask for the bit to set in the ulonglong
1666                             backing store
1667 
1668   Backing store: ulonglong
1669 
1670   @note
1671   This class supports the "reverse" semantics, when the value of the bit
1672   being 0 corresponds to the value of variable being set. To activate it
1673   use REVERSE(bitmask) instead of simply bitmask in the constructor.
1674 
1675   @note
1676   variables of this class cannot be set from the command line as
1677   my_getopt does not support bits.
1678 */
1679 class Sys_var_bit: public Sys_var_typelib
1680 {
1681   ulonglong bitmask;
1682   bool reverse_semantics;
set(uchar * ptr,ulonglong value)1683   void set(uchar *ptr, ulonglong value)
1684   {
1685     if ((value != 0) ^ reverse_semantics)
1686       (*(ulonglong *)ptr)|= bitmask;
1687     else
1688       (*(ulonglong *)ptr)&= ~bitmask;
1689   }
1690 public:
1691   Sys_var_bit(const char *name_arg,
1692           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1693           CMD_LINE getopt,
1694           ulonglong bitmask_arg, my_bool def_val, PolyLock *lock=0,
1695           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1696           on_check_function on_check_func=0,
1697           pre_update_function pre_update_func=0,
1698           on_update_function on_update_func=0,
1699           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)1700     : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
1701                       SHOW_MY_BOOL, bool_values, def_val, lock,
1702                       binlog_status_arg, on_check_func, on_update_func,
1703                       substitute)
1704   {
1705     option.var_type= GET_BOOL;
1706     pre_update= pre_update_func;
1707     reverse_semantics= my_count_bits(bitmask_arg) > 1;
1708     bitmask= reverse_semantics ? ~bitmask_arg : bitmask_arg;
1709     set(global_var_ptr(), def_val);
1710     assert(def_val < 2);
1711     assert(getopt.id == -1); // force NO_CMD_LINE
1712     assert(size == sizeof(ulonglong));
1713   }
session_update(THD * thd,set_var * var)1714   bool session_update(THD *thd, set_var *var)
1715   {
1716     set(session_var_ptr(thd), var->save_result.ulonglong_value);
1717     return false;
1718   }
global_update(THD * thd,set_var * var)1719   bool global_update(THD *thd, set_var *var)
1720   {
1721     set(global_var_ptr(), var->save_result.ulonglong_value);
1722     return false;
1723   }
session_save_default(THD * thd,set_var * var)1724   void session_save_default(THD *thd, set_var *var)
1725   { var->save_result.ulonglong_value= global_var(ulonglong) & bitmask; }
global_save_default(THD * thd,set_var * var)1726   void global_save_default(THD *thd, set_var *var)
1727   { var->save_result.ulonglong_value= option.def_value; }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1728   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
1729   {
1730     running_thd->sys_var_tmp.my_bool_value=
1731       static_cast<my_bool>(reverse_semantics ^
1732                            ((session_var(target_thd, ulonglong) & bitmask) != 0));
1733     return (uchar*) &running_thd->sys_var_tmp.my_bool_value;
1734   }
global_value_ptr(THD * thd,LEX_STRING * base)1735   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1736   {
1737     thd->sys_var_tmp.my_bool_value=
1738       static_cast<my_bool>(reverse_semantics ^
1739                            ((global_var(ulonglong) & bitmask) != 0));
1740     return (uchar*) &thd->sys_var_tmp.my_bool_value;
1741   }
1742 };
1743 
1744 /**
1745   The class for variables that have a special meaning for a session,
1746   such as @@timestamp or @@rnd_seed1, their values typically cannot be read
1747   from SV structure, and a special "read" callback is provided.
1748 
1749   Class specific constructor arguments:
1750     everything derived from Sys_var_ulonglong
1751     session_special_read_function read_func_arg
1752 
1753   Backing store: ulonglong
1754 
1755   @note
1756   These variables are session-only, global or command-line equivalents
1757   are not supported as they're generally meaningless.
1758 */
1759 class Sys_var_session_special: public Sys_var_ulonglong
1760 {
1761   typedef bool (*session_special_update_function)(THD *thd, set_var *var);
1762   typedef ulonglong (*session_special_read_function)(THD *thd);
1763 
1764   session_special_read_function read_func;
1765   session_special_update_function update_func;
1766 public:
1767   Sys_var_session_special(const char *name_arg,
1768                const char *comment, int flag_args,
1769                CMD_LINE getopt,
1770                ulonglong min_val, ulonglong max_val, uint block_size,
1771                PolyLock *lock, enum binlog_status_enum binlog_status_arg,
1772                on_check_function on_check_func,
1773                session_special_update_function update_func_arg,
1774                session_special_read_function read_func_arg,
1775                const char *substitute=0)
1776     : Sys_var_ulonglong(name_arg, comment, flag_args, 0,
1777               sizeof(ulonglong), getopt, min_val,
1778               max_val, 0, block_size, lock, binlog_status_arg, on_check_func, 0,
1779               substitute),
1780       read_func(read_func_arg), update_func(update_func_arg)
1781   {
1782     assert(scope() == ONLY_SESSION);
1783     assert(getopt.id == -1); // NO_CMD_LINE, because the offset is fake
1784   }
session_update(THD * thd,set_var * var)1785   bool session_update(THD *thd, set_var *var)
1786   { return update_func(thd, var); }
global_update(THD * thd,set_var * var)1787   bool global_update(THD *thd, set_var *var)
1788   {
1789     assert(FALSE);
1790     return true;
1791   }
session_save_default(THD * thd,set_var * var)1792   void session_save_default(THD *thd, set_var *var)
1793   { var->value= 0; }
global_save_default(THD * thd,set_var * var)1794   void global_save_default(THD *thd, set_var *var)
1795   { assert(FALSE); }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1796   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
1797   {
1798     running_thd->sys_var_tmp.ulonglong_value= read_func(target_thd);
1799     return (uchar*) &running_thd->sys_var_tmp.ulonglong_value;
1800   }
global_value_ptr(THD * thd,LEX_STRING * base)1801   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1802   {
1803     assert(FALSE);
1804     return 0;
1805   }
1806 };
1807 
1808 
1809 /**
1810   Similar to Sys_var_session_special, but with double storage.
1811 */
1812 class Sys_var_session_special_double: public Sys_var_double
1813 {
1814   typedef bool (*session_special_update_function)(THD *thd, set_var *var);
1815   typedef double (*session_special_read_double_function)(THD *thd);
1816 
1817   session_special_read_double_function read_func;
1818   session_special_update_function update_func;
1819 public:
1820   Sys_var_session_special_double(const char *name_arg,
1821                const char *comment, int flag_args,
1822                CMD_LINE getopt,
1823                double min_val, double max_val, uint block_size,
1824                PolyLock *lock, enum binlog_status_enum binlog_status_arg,
1825                on_check_function on_check_func,
1826                session_special_update_function update_func_arg,
1827                session_special_read_double_function read_func_arg,
1828                const char *substitute=0)
1829     : Sys_var_double(name_arg, comment, flag_args, 0,
1830               sizeof(double), getopt,
1831               min_val, max_val, 0.0,
1832               lock, binlog_status_arg, on_check_func, 0,
1833               substitute),
1834       read_func(read_func_arg), update_func(update_func_arg)
1835   {
1836     assert(scope() == ONLY_SESSION);
1837     assert(getopt.id == -1); // NO_CMD_LINE, because the offset is fake
1838   }
session_update(THD * thd,set_var * var)1839   bool session_update(THD *thd, set_var *var)
1840   { return update_func(thd, var); }
global_update(THD * thd,set_var * var)1841   bool global_update(THD *thd, set_var *var)
1842   {
1843     assert(FALSE);
1844     return true;
1845   }
session_save_default(THD * thd,set_var * var)1846   void session_save_default(THD *thd, set_var *var)
1847   { var->value= 0; }
global_save_default(THD * thd,set_var * var)1848   void global_save_default(THD *thd, set_var *var)
1849   { assert(FALSE); }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1850   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
1851   {
1852     running_thd->sys_var_tmp.double_value= read_func(target_thd);
1853     return (uchar *) &running_thd->sys_var_tmp.double_value;
1854   }
global_value_ptr(THD * thd,LEX_STRING * base)1855   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1856   {
1857     assert(FALSE);
1858     return 0;
1859   }
1860 };
1861 
1862 
1863 /**
1864   The class for read-only variables that show whether a particular
1865   feature is supported by the server. Example: have_compression
1866 
1867   Backing store: enum SHOW_COMP_OPTION
1868 
1869   @note
1870   These variables are necessarily read-only, only global, and have no
1871   command-line equivalent.
1872 */
1873 class Sys_var_have: public sys_var
1874 {
1875 public:
1876   Sys_var_have(const char *name_arg,
1877                const char *comment, int flag_args, ptrdiff_t off, size_t size,
1878                CMD_LINE getopt,
1879                PolyLock *lock=0,
1880                enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1881                on_check_function on_check_func=0,
1882                on_update_function on_update_func=0,
1883                const char *substitute=0,
1884                int parse_flag= PARSE_NORMAL)
1885     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
1886               getopt.arg_type, SHOW_CHAR, 0,
1887               lock, binlog_status_arg, on_check_func, on_update_func,
1888               substitute, parse_flag)
1889   {
1890     assert(scope() == GLOBAL);
1891     assert(getopt.id == -1);
1892     assert(lock == 0);
1893     assert(binlog_status_arg == VARIABLE_NOT_IN_BINLOG);
1894     assert(is_readonly());
1895     assert(on_update == 0);
1896     assert(size == sizeof(enum SHOW_COMP_OPTION));
1897   }
do_check(THD * thd,set_var * var)1898   bool do_check(THD *thd, set_var *var) {
1899     assert(FALSE);
1900     return true;
1901   }
session_update(THD * thd,set_var * var)1902   bool session_update(THD *thd, set_var *var)
1903   {
1904     assert(FALSE);
1905     return true;
1906   }
global_update(THD * thd,set_var * var)1907   bool global_update(THD *thd, set_var *var)
1908   {
1909     assert(FALSE);
1910     return true;
1911   }
session_save_default(THD * thd,set_var * var)1912   void session_save_default(THD *thd, set_var *var) { }
global_save_default(THD * thd,set_var * var)1913   void global_save_default(THD *thd, set_var *var) { }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1914   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
1915   {
1916     assert(FALSE);
1917     return 0;
1918   }
global_value_ptr(THD * thd,LEX_STRING * base)1919   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1920   {
1921     return (uchar*)show_comp_option_name[global_var(enum SHOW_COMP_OPTION)];
1922   }
check_update_type(Item_result type)1923   bool check_update_type(Item_result type) { return false; }
1924 };
1925 
1926 /**
1927   Generic class for variables for storing entities that are internally
1928   represented as structures, have names, and possibly can be referred to by
1929   numbers.  Examples: character sets, collations, locales,
1930 
1931   Class specific constructor arguments:
1932     ptrdiff_t name_offset  - offset of the 'name' field in the structure
1933 
1934   Backing store: void*
1935 
1936   @note
1937   As every such a structure requires special treatment from my_getopt,
1938   these variables don't support command-line equivalents, any such
1939   command-line options should be added manually to my_long_options in mysqld.cc
1940 */
1941 class Sys_var_struct: public sys_var
1942 {
1943   ptrdiff_t name_offset; // offset to the 'name' property in the structure
1944 public:
1945   Sys_var_struct(const char *name_arg,
1946           const char *comment, int flag_args, ptrdiff_t off, size_t size,
1947           CMD_LINE getopt,
1948           ptrdiff_t name_off, void *def_val, PolyLock *lock=0,
1949           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1950           on_check_function on_check_func=0,
1951           on_update_function on_update_func=0,
1952           const char *substitute=0,
1953           int parse_flag= PARSE_NORMAL)
1954     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
1955               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
1956               lock, binlog_status_arg, on_check_func, on_update_func,
1957               substitute, parse_flag),
1958       name_offset(name_off)
1959   {
1960     option.var_type= GET_STR;
1961     /*
1962       struct variables are special on the command line - often (e.g. for
1963       charsets) the name cannot be immediately resolved, but only after all
1964       options (in particular, basedir) are parsed.
1965 
1966       thus all struct command-line options should be added manually
1967       to my_long_options in mysqld.cc
1968     */
1969     assert(getopt.id == -1);
1970     assert(size == sizeof(void *));
1971   }
do_check(THD * thd,set_var * var)1972   bool do_check(THD *thd, set_var *var)
1973   { return false; }
session_update(THD * thd,set_var * var)1974   bool session_update(THD *thd, set_var *var)
1975   {
1976     session_var(thd, const void*)= var->save_result.ptr;
1977     return false;
1978   }
global_update(THD * thd,set_var * var)1979   bool global_update(THD *thd, set_var *var)
1980   {
1981     global_var(const void*)= var->save_result.ptr;
1982     return false;
1983   }
session_save_default(THD * thd,set_var * var)1984   void session_save_default(THD *thd, set_var *var)
1985   { var->save_result.ptr= global_var(void*); }
global_save_default(THD * thd,set_var * var)1986   void global_save_default(THD *thd, set_var *var)
1987   {
1988     void **default_value= reinterpret_cast<void**>(option.def_value);
1989     var->save_result.ptr= *default_value;
1990   }
check_update_type(Item_result type)1991   bool check_update_type(Item_result type)
1992   { return type != INT_RESULT && type != STRING_RESULT; }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)1993   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
1994   {
1995     uchar *ptr= session_var(target_thd, uchar*);
1996     return ptr ? *(uchar**)(ptr+name_offset) : 0;
1997   }
global_value_ptr(THD * thd,LEX_STRING * base)1998   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
1999   {
2000     uchar *ptr= global_var(uchar*);
2001     return ptr ? *(uchar**)(ptr+name_offset) : 0;
2002   }
2003 };
2004 
2005 /**
2006   The class for variables that store time zones
2007 
2008   Backing store: Time_zone*
2009 
2010   @note
2011   Time zones cannot be supported directly by my_getopt, thus
2012   these variables don't support command-line equivalents, any such
2013   command-line options should be added manually to my_long_options in mysqld.cc
2014 */
2015 class Sys_var_tz: public sys_var
2016 {
2017 public:
2018   Sys_var_tz(const char *name_arg,
2019              const char *comment, int flag_args, ptrdiff_t off, size_t size,
2020              CMD_LINE getopt,
2021              Time_zone **def_val, PolyLock *lock=0,
2022              enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
2023              on_check_function on_check_func=0,
2024              on_update_function on_update_func=0,
2025              const char *substitute=0,
2026              int parse_flag= PARSE_NORMAL)
2027     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
2028               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
2029               lock, binlog_status_arg, on_check_func, on_update_func,
2030               substitute, parse_flag)
2031   {
2032     assert(getopt.id == -1);
2033     assert(size == sizeof(Time_zone *));
2034   }
do_check(THD * thd,set_var * var)2035   bool do_check(THD *thd, set_var *var)
2036   {
2037     char buff[MAX_TIME_ZONE_NAME_LENGTH];
2038     String str(buff, sizeof(buff), &my_charset_latin1);
2039     String *res= var->value->val_str(&str);
2040 
2041     if (!res)
2042       return true;
2043 
2044     if (!(var->save_result.time_zone= my_tz_find(thd, res)))
2045     {
2046       ErrConvString err(res);
2047       my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), err.ptr());
2048       return true;
2049     }
2050     return false;
2051   }
session_update(THD * thd,set_var * var)2052   bool session_update(THD *thd, set_var *var)
2053   {
2054     session_var(thd, Time_zone*)= var->save_result.time_zone;
2055     return false;
2056   }
global_update(THD * thd,set_var * var)2057   bool global_update(THD *thd, set_var *var)
2058   {
2059     global_var(Time_zone*)= var->save_result.time_zone;
2060     return false;
2061   }
session_save_default(THD * thd,set_var * var)2062   void session_save_default(THD *thd, set_var *var)
2063   {
2064     var->save_result.time_zone= global_var(Time_zone*);
2065   }
global_save_default(THD * thd,set_var * var)2066   void global_save_default(THD *thd, set_var *var)
2067   {
2068     var->save_result.time_zone=
2069       *(Time_zone**)(intptr)option.def_value;
2070   }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2071   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
2072   {
2073     /*
2074       This is an ugly fix for replication: we don't replicate properly queries
2075       invoking system variables' values to update tables; but
2076       CONVERT_TZ(,,@@session.time_zone) is so popular that we make it
2077       replicable (i.e. we tell the binlog code to store the session
2078       timezone). If it's the global value which was used we can't replicate
2079       (binlog code stores session value only).
2080     */
2081     target_thd->time_zone_used= 1;
2082     return (uchar *)(session_var(target_thd, Time_zone*)->get_name()->ptr());
2083   }
global_value_ptr(THD * thd,LEX_STRING * base)2084   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
2085   {
2086     return (uchar *)(global_var(Time_zone*)->get_name()->ptr());
2087   }
check_update_type(Item_result type)2088   bool check_update_type(Item_result type)
2089   { return type != STRING_RESULT; }
2090 };
2091 
2092 
2093 /**
2094   Class representing the 'tx_isolation' system variable. This
2095   variable can also be indirectly set using 'SET TRANSACTION ISOLATION
2096   LEVEL'. This variable is deprecated and will be removed in a
2097   future release. 'transaction_isolation' is used an alternative
2098   instead.
2099 */
2100 class Sys_var_tx_isolation: public Sys_var_enum
2101 {
2102 public:
2103   Sys_var_tx_isolation(const char *name_arg,
2104           const char *comment, int flag_args, ptrdiff_t off, size_t size,
2105           CMD_LINE getopt,
2106           const char *values[], uint def_val, PolyLock *lock,
2107           enum binlog_status_enum binlog_status_arg,
2108           on_check_function on_check_func,
2109           on_update_function on_update_func=0,
2110           const char *substitute=0)
Sys_var_enum(name_arg,comment,flag_args,off,size,getopt,values,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)2111     :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt,
2112                   values, def_val, lock, binlog_status_arg, on_check_func,
2113                   on_update_func, substitute)
2114   {}
2115   virtual bool session_update(THD *thd, set_var *var);
2116 };
2117 
2118 
2119 /**
2120   Class representing the tx_read_only system variable for setting
2121   default transaction access mode. This variable is deprecated
2122   and will be removed in future release. 'transaction_read_only'
2123   is used as an alternative instead.
2124 
2125   Note that there is a special syntax - SET TRANSACTION READ ONLY
2126   (or READ WRITE) that sets the access mode for the next transaction
2127   only.
2128 */
2129 
2130 class Sys_var_tx_read_only: public Sys_var_mybool
2131 {
2132 public:
2133   Sys_var_tx_read_only(const char *name_arg, const char *comment, int flag_args,
2134                        ptrdiff_t off, size_t size, CMD_LINE getopt,
2135                        my_bool def_val, PolyLock *lock,
2136                        enum binlog_status_enum binlog_status_arg,
2137                        on_check_function on_check_func,
2138                        on_update_function on_update_func=0,
2139                        const char *substitute=0)
Sys_var_mybool(name_arg,comment,flag_args,off,size,getopt,def_val,lock,binlog_status_arg,on_check_func,on_update_func,substitute)2140     :Sys_var_mybool(name_arg, comment, flag_args, off, size, getopt,
2141                     def_val, lock, binlog_status_arg, on_check_func,
2142                     on_update_func, substitute)
2143   {}
2144   virtual bool session_update(THD *thd, set_var *var);
2145 };
2146 
2147 
2148 /**
2149   Class representing the sql_log_bin system variable for controlling
2150   whether logging to the binary log is done.
2151 */
2152 
2153 class Sys_var_sql_log_bin: public Sys_var_mybool
2154 {
2155 public:
Sys_var_sql_log_bin(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,on_update_function on_update_func)2156   Sys_var_sql_log_bin(const char *name_arg, const char *comment, int flag_args,
2157                       ptrdiff_t off, size_t size, CMD_LINE getopt,
2158                       my_bool def_val, PolyLock *lock,
2159                       enum binlog_status_enum binlog_status_arg,
2160                       on_check_function on_check_func,
2161                       on_update_function on_update_func)
2162     :Sys_var_mybool(name_arg, comment, flag_args, off, size, getopt,
2163                     def_val, lock, binlog_status_arg, on_check_func,
2164                     on_update_func)
2165   {}
2166 
global_value_ptr(THD * thd,LEX_STRING * base)2167   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
2168   {
2169     /* Reading GLOBAL SQL_LOG_BIN produces a deprecation warning. */
2170     if (base != NULL)
2171       push_warning_printf(thd, Sql_condition::SL_WARNING,
2172                           ER_WARN_DEPRECATED_SYNTAX,
2173                           ER(ER_WARN_DEPRECATED_SYNTAX),
2174                           "@@global.sql_log_bin", "the constant 1 "
2175                           "(since @@global.sql_log_bin is always equal to 1)");
2176 
2177     return Sys_var_mybool::global_value_ptr(thd, base);
2178   }
2179 };
2180 
2181 /**
2182    A class for @@global.binlog_checksum that has
2183    a specialized update method.
2184 */
2185 class Sys_var_enum_binlog_checksum: public Sys_var_enum
2186 {
2187 public:
2188   Sys_var_enum_binlog_checksum(const char *name_arg,
2189           const char *comment, int flag_args, ptrdiff_t off, size_t size,
2190           CMD_LINE getopt,
2191           const char *values[], uint def_val, PolyLock *lock,
2192           enum binlog_status_enum binlog_status_arg,
2193           on_check_function on_check_func=0
2194           )
Sys_var_enum(name_arg,comment,flag_args,off,size,getopt,values,def_val,lock,binlog_status_arg,on_check_func,NULL)2195     :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt,
2196                   values, def_val, lock, binlog_status_arg, on_check_func, NULL)
2197   {}
2198   virtual bool global_update(THD *thd, set_var *var);
2199 };
2200 
2201 
2202 /**
2203   Class for gtid_next.
2204 */
2205 class Sys_var_gtid_next: public sys_var
2206 {
2207 public:
2208   Sys_var_gtid_next(const char *name_arg,
2209           const char *comment, int flag_args, ptrdiff_t off, size_t size,
2210           CMD_LINE getopt,
2211           const char *def_val,
2212           PolyLock *lock= 0,
2213           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
2214           on_check_function on_check_func=0,
2215           on_update_function on_update_func=0,
2216           const char *substitute=0,
2217           int parse_flag= PARSE_NORMAL)
2218     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
2219               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
2220               lock, binlog_status_arg, on_check_func, on_update_func,
2221               substitute, parse_flag)
2222   {
2223     assert(size == sizeof(Gtid_specification));
2224   }
session_update(THD * thd,set_var * var)2225   bool session_update(THD *thd, set_var *var)
2226   {
2227     DBUG_ENTER("Sys_var_gtid_next::session_update");
2228     char buf[Gtid::MAX_TEXT_LENGTH + 1];
2229     // Get the value
2230     String str(buf, sizeof(buf), &my_charset_latin1);
2231     char* res= NULL;
2232     if (!var->value)
2233     {
2234       // set session gtid_next= default
2235       assert(var->save_result.string_value.str);
2236       assert(var->save_result.string_value.length);
2237       res= var->save_result.string_value.str;
2238     }
2239     else if (var->value->val_str(&str))
2240       res= var->value->val_str(&str)->c_ptr_safe();
2241     if (!res)
2242     {
2243       my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, "NULL");
2244       DBUG_RETURN(true);
2245     }
2246     global_sid_lock->rdlock();
2247     Gtid_specification spec;
2248     if (spec.parse(global_sid_map, res) != RETURN_STATUS_OK)
2249     {
2250       global_sid_lock->unlock();
2251       DBUG_RETURN(true);
2252     }
2253 
2254     bool ret= set_gtid_next(thd, spec);
2255     // set_gtid_next releases global_sid_lock
2256     DBUG_RETURN(ret);
2257   }
global_update(THD * thd,set_var * var)2258   bool global_update(THD *thd, set_var *var)
2259   { assert(FALSE); return true; }
session_save_default(THD * thd,set_var * var)2260   void session_save_default(THD *thd, set_var *var)
2261   {
2262     DBUG_ENTER("Sys_var_gtid_next::session_save_default");
2263     char* ptr= (char*)(intptr)option.def_value;
2264     var->save_result.string_value.str= ptr;
2265     var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
2266     DBUG_VOID_RETURN;
2267   }
global_save_default(THD * thd,set_var * var)2268   void global_save_default(THD *thd, set_var *var)
2269   { assert(FALSE); }
do_check(THD * thd,set_var * var)2270   bool do_check(THD *thd, set_var *var)
2271   { return false; }
check_update_type(Item_result type)2272   bool check_update_type(Item_result type)
2273   { return type != STRING_RESULT; }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2274   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
2275   {
2276     DBUG_ENTER("Sys_var_gtid_next::session_value_ptr");
2277     char buf[Gtid_specification::MAX_TEXT_LENGTH + 1];
2278     global_sid_lock->rdlock();
2279     ((Gtid_specification *)session_var_ptr(target_thd))->
2280       to_string(global_sid_map, buf);
2281     global_sid_lock->unlock();
2282     char *ret= running_thd->mem_strdup(buf);
2283     DBUG_RETURN((uchar *)ret);
2284   }
global_value_ptr(THD * thd,LEX_STRING * base)2285   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
2286   { assert(FALSE); return NULL; }
2287 };
2288 
2289 #ifdef HAVE_GTID_NEXT_LIST
2290 /**
2291   Class for variables that store values of type Gtid_set.
2292 
2293   The back-end storage should be a Gtid_set_or_null, and it should be
2294   set to null by default.  When the variable is set for the first
2295   time, the Gtid_set* will be allocated.
2296 */
2297 class Sys_var_gtid_set: public sys_var
2298 {
2299 public:
2300   Sys_var_gtid_set(const char *name_arg,
2301           const char *comment, int flag_args, ptrdiff_t off, size_t size,
2302           CMD_LINE getopt,
2303           const char *def_val,
2304           PolyLock *lock= 0,
2305           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
2306           on_check_function on_check_func=0,
2307           on_update_function on_update_func=0,
2308           const char *substitute=0,
2309           int parse_flag= PARSE_NORMAL)
2310     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
2311               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
2312               lock, binlog_status_arg, on_check_func, on_update_func,
2313               substitute, parse_flag)
2314   {
2315     assert(size == sizeof(Gtid_set_or_null));
2316   }
session_update(THD * thd,set_var * var)2317   bool session_update(THD *thd, set_var *var)
2318   {
2319     DBUG_ENTER("Sys_var_gtid_set::session_update");
2320     Gtid_set_or_null *gsn=
2321       (Gtid_set_or_null *)session_var_ptr(thd);
2322     char *value= var->save_result.string_value.str;
2323     if (value == NULL)
2324       gsn->set_null();
2325     else
2326     {
2327       Gtid_set *gs= gsn->set_non_null(global_sid_map);
2328       if (gs == NULL)
2329       {
2330         my_error(ER_OUT_OF_RESOURCES, MYF(0)); // allocation failed
2331         DBUG_RETURN(true);
2332       }
2333       /*
2334         If string begins with '+', add to the existing set, otherwise
2335         replace existing set.
2336       */
2337       while (isspace(*value))
2338         value++;
2339       if (*value == '+')
2340         value++;
2341       else
2342         gs->clear();
2343       // Add specified set of groups to Gtid_set.
2344       global_sid_lock->rdlock();
2345       enum_return_status ret= gs->add_gtid_text(value);
2346       global_sid_lock->unlock();
2347       if (ret != RETURN_STATUS_OK)
2348       {
2349         gsn->set_null();
2350         DBUG_RETURN(true);
2351       }
2352     }
2353     DBUG_RETURN(false);
2354   }
global_update(THD * thd,set_var * var)2355   bool global_update(THD *thd, set_var *var)
2356   { assert(FALSE); return true; }
session_save_default(THD * thd,set_var * var)2357   void session_save_default(THD *thd, set_var *var)
2358   {
2359     DBUG_ENTER("Sys_var_gtid_set::session_save_default");
2360     global_sid_lock->rdlock();
2361     char *ptr= (char*)(intptr)option.def_value;
2362     var->save_result.string_value.str= ptr;
2363     var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
2364     global_sid_lock->unlock();
2365     DBUG_VOID_RETURN;
2366   }
global_save_default(THD * thd,set_var * var)2367   void global_save_default(THD *thd, set_var *var)
2368   { assert(FALSE); }
do_check(THD * thd,set_var * var)2369   bool do_check(THD *thd, set_var *var)
2370   {
2371     DBUG_ENTER("Sys_var_gtid_set::do_check");
2372     String str;
2373     String *res= var->value->val_str(&str);
2374     if (res == NULL)
2375     {
2376       var->save_result.string_value.str= NULL;
2377       DBUG_RETURN(FALSE);
2378     }
2379     assert(res->ptr() != NULL);
2380     var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
2381     if (var->save_result.string_value.str == NULL)
2382     {
2383       my_error(ER_OUT_OF_RESOURCES, MYF(0)); // thd->strmake failed
2384       DBUG_RETURN(1);
2385     }
2386     var->save_result.string_value.length= res->length();
2387     bool ret= !Gtid_set::is_valid(res->ptr());
2388     DBUG_RETURN(ret);
2389   }
check_update_type(Item_result type)2390   bool check_update_type(Item_result type)
2391   { return type != STRING_RESULT; }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2392   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
2393   {
2394     DBUG_ENTER("Sys_var_gtid_set::session_value_ptr");
2395     Gtid_set_or_null *gsn= (Gtid_set_or_null *)session_var_ptr(target_thd);
2396     Gtid_set *gs= gsn->get_gtid_set();
2397     if (gs == NULL)
2398       DBUG_RETURN(NULL);
2399     char *buf;
2400     global_sid_lock->rdlock();
2401     buf= (char *)running_thd->alloc(gs->get_string_length() + 1);
2402     if (buf)
2403       gs->to_string(buf);
2404     else
2405       my_error(ER_OUT_OF_RESOURCES, MYF(0)); // thd->alloc failed
2406     global_sid_lock->unlock();
2407     DBUG_RETURN((uchar *)buf);
2408   }
global_value_ptr(THD * thd,LEX_STRING * base)2409   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
2410   { assert(FALSE); return NULL; }
2411 };
2412 #endif
2413 
2414 
2415 /**
2416   Abstract base class for read-only variables (global or session) of
2417   string type where the value is generated by some function.  This
2418   needs to be subclassed; the session_value_ptr or global_value_ptr
2419   function should be overridden.
2420 */
2421 class Sys_var_charptr_func: public sys_var
2422 {
2423 public:
Sys_var_charptr_func(const char * name_arg,const char * comment,flag_enum flag_arg)2424   Sys_var_charptr_func(const char *name_arg, const char *comment,
2425                        flag_enum flag_arg)
2426     : sys_var(&all_sys_vars, name_arg, comment, READ_ONLY flag_arg,
2427               0/*off*/, NO_CMD_LINE.id, NO_CMD_LINE.arg_type,
2428               SHOW_CHAR, (intptr)0/*def_val*/,
2429               NULL/*polylock*/, VARIABLE_NOT_IN_BINLOG,
2430               NULL/*on_check_func*/, NULL/*on_update_func*/,
2431               NULL/*substitute*/, PARSE_NORMAL/*parse_flag*/)
2432   {
2433     assert(flag_arg == sys_var::GLOBAL || flag_arg == sys_var::SESSION ||
2434            flag_arg == sys_var::ONLY_SESSION);
2435   }
session_update(THD * thd,set_var * var)2436   bool session_update(THD *thd, set_var *var)
2437   { assert(FALSE); return true; }
global_update(THD * thd,set_var * var)2438   bool global_update(THD *thd, set_var *var)
2439   { assert(FALSE); return true; }
session_save_default(THD * thd,set_var * var)2440   void session_save_default(THD *thd, set_var *var) { assert(FALSE); }
global_save_default(THD * thd,set_var * var)2441   void global_save_default(THD *thd, set_var *var) { assert(FALSE); }
do_check(THD * thd,set_var * var)2442   bool do_check(THD *thd, set_var *var) { assert(FALSE); return true; }
check_update_type(Item_result type)2443   bool check_update_type(Item_result type) { assert(FALSE); return true; }
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2444   virtual uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
2445   { assert(FALSE); return NULL; }
global_value_ptr(THD * thd,LEX_STRING * base)2446   virtual uchar *global_value_ptr(THD *thd, LEX_STRING *base)
2447   { assert(FALSE); return NULL; }
2448 };
2449 
2450 
2451 /**
2452   Class for @@session.gtid_executed and @@global.gtid_executed.
2453 */
2454 class Sys_var_gtid_executed : Sys_var_charptr_func
2455 {
2456 public:
Sys_var_gtid_executed(const char * name_arg,const char * comment_arg)2457   Sys_var_gtid_executed(const char *name_arg, const char *comment_arg)
2458     : Sys_var_charptr_func(name_arg, comment_arg, SESSION) {}
2459 
global_value_ptr(THD * thd,LEX_STRING * base)2460   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
2461   {
2462     DBUG_ENTER("Sys_var_gtid_executed::global_value_ptr");
2463     global_sid_lock->wrlock();
2464     const Gtid_set *gs= gtid_state->get_executed_gtids();
2465     char *buf= (char *)thd->alloc(gs->get_string_length() + 1);
2466     if (buf == NULL)
2467       my_error(ER_OUT_OF_RESOURCES, MYF(0));
2468     else
2469       gs->to_string(buf);
2470     global_sid_lock->unlock();
2471     DBUG_RETURN((uchar *)buf);
2472   }
2473 
2474 public:
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2475   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
2476   {
2477     DBUG_ENTER("Sys_var_gtid_executed::session_value_ptr");
2478 
2479     if (!running_thd->gtid_executed_warning_issued)
2480     {
2481       push_warning_printf(running_thd, Sql_condition::SL_WARNING,
2482           ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT,
2483           ER(ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT),
2484           "@@SESSION.GTID_EXECUTED");
2485       running_thd->gtid_executed_warning_issued= true;
2486     }
2487     if (opt_bin_log &&
2488        (target_thd == running_thd)) /* Supported for current thread only. */
2489     {
2490       target_thd->binlog_setup_trx_data();
2491       /*
2492         It is enough to check if the transaction cache is nonempty, we
2493         do not need to check the statement cache.  The statement cache
2494         can only be nonempty for single-statement transactions.  Since
2495         single-statement transactions are flushed to the binary log
2496         before the next statement gets to execute, there is no chance
2497         that the value of @@session.gtid_executed is read when the
2498         statement cache is nonempty.
2499       */
2500       if (!target_thd->is_binlog_cache_empty(true))
2501       {
2502         /*
2503           The case sidno == -1 cannot happen since it is not implemented.
2504           The cases sidno == 0 and sidno == -2 mean that we don't own any
2505           GTID, so we should return empty string.
2506         */
2507         if (target_thd->owned_gtid.sidno > 0)
2508         {
2509           uchar *buf= (uchar *)running_thd->alloc(Gtid::MAX_TEXT_LENGTH + 1);
2510           if (buf == NULL)
2511             my_error(ER_OUT_OF_RESOURCES, MYF(0));
2512           else
2513             target_thd->owned_gtid.to_string(target_thd->owned_sid, (char *)buf);
2514           DBUG_RETURN(buf);
2515         }
2516       }
2517     }
2518 
2519     uchar *buf= (uchar *)running_thd->alloc(1);
2520     if (buf == NULL)
2521       my_error(ER_OUT_OF_RESOURCES, MYF(0));
2522     else
2523       buf[0]= 0;
2524     DBUG_RETURN(buf);
2525   }
2526 };
2527 
2528 
2529 /**
2530   Class for @@session.gtid_purged.
2531 */
2532 class Sys_var_gtid_purged : public sys_var
2533 {
2534 public:
2535   Sys_var_gtid_purged(const char *name_arg,
2536           const char *comment, int flag_args, ptrdiff_t off, size_t size,
2537           CMD_LINE getopt,
2538           const char *def_val,
2539           PolyLock *lock= 0,
2540           enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
2541           on_check_function on_check_func=0,
2542           on_update_function on_update_func=0,
2543           const char *substitute=0,
2544           int parse_flag= PARSE_NORMAL)
2545     : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
2546               getopt.arg_type, SHOW_CHAR, (intptr)def_val,
2547               lock, binlog_status_arg, on_check_func, on_update_func,
2548               substitute, parse_flag)
2549   {}
2550 
session_update(THD * thd,set_var * var)2551   bool session_update(THD *thd, set_var *var)
2552   {
2553     assert(FALSE);
2554     return true;
2555   }
2556 
session_save_default(THD * thd,set_var * var)2557   void session_save_default(THD *thd, set_var *var)
2558   { assert(FALSE); }
2559 
2560   bool global_update(THD *thd, set_var *var);
2561 
global_save_default(THD * thd,set_var * var)2562   void global_save_default(THD *thd, set_var *var)
2563   {
2564     /* gtid_purged does not have default value */
2565     my_error(ER_NO_DEFAULT, MYF(0), var->var->name.str);
2566   }
2567 
do_check(THD * thd,set_var * var)2568   bool do_check(THD *thd, set_var *var)
2569   {
2570     DBUG_ENTER("Sys_var_gtid_purged::do_check");
2571     char buf[1024];
2572     String str(buf, sizeof(buf), system_charset_info);
2573     String *res= var->value->val_str(&str);
2574     if (!res)
2575       DBUG_RETURN(true);
2576     var->save_result.string_value.str= thd->strmake(res->c_ptr_safe(),
2577                                                     res->length());
2578     if (!var->save_result.string_value.str)
2579     {
2580       my_error(ER_OUT_OF_RESOURCES, MYF(0)); // thd->strmake failed
2581       DBUG_RETURN(true);
2582     }
2583     var->save_result.string_value.length= res->length();
2584     bool ret= Gtid_set::is_valid(res->c_ptr_safe()) ? false : true;
2585     DBUG_PRINT("info", ("ret=%d", ret));
2586     DBUG_RETURN(ret);
2587   }
2588 
check_update_type(Item_result type)2589   bool check_update_type(Item_result type)
2590   { return type != STRING_RESULT; }
2591 
global_value_ptr(THD * thd,LEX_STRING * base)2592   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
2593   {
2594     DBUG_ENTER("Sys_var_gtid_purged::global_value_ptr");
2595     const Gtid_set *gs;
2596     global_sid_lock->wrlock();
2597     if (opt_bin_log)
2598       gs= gtid_state->get_lost_gtids();
2599     else
2600       /*
2601         When binlog is off, report @@GLOBAL.GTID_PURGED from
2602         executed_gtids, since @@GLOBAL.GTID_PURGED and
2603         @@GLOBAL.GTID_EXECUTED are always same, so we did not
2604         save gtid into lost_gtids for every transaction for
2605         improving performance.
2606       */
2607       gs= gtid_state->get_executed_gtids();
2608     char *buf= (char *)thd->alloc(gs->get_string_length() + 1);
2609     if (buf == NULL)
2610       my_error(ER_OUT_OF_RESOURCES, MYF(0));
2611     else
2612       gs->to_string(buf);
2613     global_sid_lock->unlock();
2614     DBUG_RETURN((uchar *)buf);
2615   }
2616 
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2617   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
2618   { assert(0); return NULL; }
2619 };
2620 
2621 
2622 class Sys_var_gtid_owned : Sys_var_charptr_func
2623 {
2624 public:
Sys_var_gtid_owned(const char * name_arg,const char * comment_arg)2625   Sys_var_gtid_owned(const char *name_arg, const char *comment_arg)
2626     : Sys_var_charptr_func(name_arg, comment_arg, SESSION) {}
2627 
2628 public:
session_value_ptr(THD * running_thd,THD * target_thd,LEX_STRING * base)2629   uchar *session_value_ptr(THD *running_thd, THD *target_thd, LEX_STRING *base)
2630   {
2631     DBUG_ENTER("Sys_var_gtid_owned::session_value_ptr");
2632     char *buf= NULL;
2633     bool remote= (target_thd != running_thd);
2634 
2635     if (target_thd->owned_gtid.sidno == 0)
2636       DBUG_RETURN((uchar *)running_thd->mem_strdup(""));
2637     else if (target_thd->owned_gtid.sidno == THD::OWNED_SIDNO_ANONYMOUS)
2638     {
2639       assert(gtid_state->get_anonymous_ownership_count() > 0);
2640       DBUG_RETURN((uchar *)running_thd->mem_strdup("ANONYMOUS"));
2641     }
2642     else if (target_thd->owned_gtid.sidno == THD::OWNED_SIDNO_GTID_SET)
2643     {
2644 #ifdef HAVE_GTID_NEXT_LIST
2645       buf= (char *)running_thd->alloc(target_thd->owned_gtid_set.get_string_length() + 1);
2646       if (buf)
2647       {
2648         global_sid_lock->rdlock();
2649         target_thd->owned_gtid_set.to_string(buf);
2650         global_sid_lock->unlock();
2651       }
2652       else
2653         my_error(ER_OUT_OF_RESOURCES, MYF(0));
2654 #else
2655       assert(0);
2656 #endif
2657     }
2658     else
2659     {
2660       buf= (char *)running_thd->alloc(Gtid::MAX_TEXT_LENGTH + 1);
2661       if (buf)
2662       {
2663         /* Take the lock if accessing another session. */
2664         if (remote)
2665           global_sid_lock->rdlock();
2666         running_thd->owned_gtid.to_string(target_thd->owned_sid, buf);
2667         if (remote)
2668           global_sid_lock->unlock();
2669       }
2670       else
2671         my_error(ER_OUT_OF_RESOURCES, MYF(0));
2672     }
2673     DBUG_RETURN((uchar *)buf);
2674   }
2675 
global_value_ptr(THD * thd,LEX_STRING * base)2676   uchar *global_value_ptr(THD *thd, LEX_STRING *base)
2677   {
2678     DBUG_ENTER("Sys_var_gtid_owned::global_value_ptr");
2679     const Owned_gtids *owned_gtids= gtid_state->get_owned_gtids();
2680     global_sid_lock->wrlock();
2681     char *buf= (char *)thd->alloc(owned_gtids->get_max_string_length());
2682     if (buf)
2683       owned_gtids->to_string(buf);
2684     else
2685       my_error(ER_OUT_OF_RESOURCES, MYF(0)); // thd->alloc failed
2686     global_sid_lock->unlock();
2687     DBUG_RETURN((uchar *)buf);
2688   }
2689 };
2690 
2691 #ifdef HAVE_REPLICATION
2692 class Sys_var_gtid_mode : public Sys_var_enum
2693 {
2694 public:
2695   Sys_var_gtid_mode(const char *name_arg,
2696                     const char *comment,
2697                     int flag_args,
2698                     ptrdiff_t off,
2699                     size_t size,
2700                     CMD_LINE getopt,
2701                     const char *values[],
2702                     uint def_val,
2703                     PolyLock *lock=0,
2704                     enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
2705                     on_check_function on_check_func=0) :
Sys_var_enum(name_arg,comment,flag_args,off,size,getopt,values,def_val,lock,binlog_status_arg,on_check_func)2706                       Sys_var_enum(name_arg, comment, flag_args, off, size,
2707                                    getopt, values, def_val, lock, binlog_status_arg,
2708                                    on_check_func)
2709   { }
2710 
global_update(THD * thd,set_var * var)2711   bool global_update(THD *thd, set_var *var)
2712   {
2713     DBUG_ENTER("Sys_var_gtid_mode::global_update");
2714     bool ret= true;
2715 
2716      /*
2717       SET GITD_MODE command should ignore 'read-only' and 'super_read_only'
2718       options so that it can update 'mysql.gtid_executed' replication repository
2719       table.
2720      */
2721     thd->set_skip_readonly_check();
2722 
2723     /*
2724       Hold lock_log so that:
2725       - other transactions are not flushed while gtid_mode is changed;
2726       - gtid_mode is not changed while some other thread is rotating
2727         the binlog.
2728 
2729       Hold channel_map lock so that:
2730       - gtid_mode is not changed during the execution of some
2731         replication command; particularly CHANGE MASTER. CHANGE MASTER
2732         checks if GTID_MODE is compatible with AUTO_POSITION, and
2733         later it actually updates the in-memory structure for
2734         AUTO_POSITION.  If gtid_mode was changed between these calls,
2735         auto_position could be set incompatible with gtid_mode.
2736 
2737       Hold global_sid_lock.wrlock so that:
2738       - other transactions cannot acquire ownership of any gtid.
2739 
2740       Hold gtid_mode_lock so that all places that don't want to hold
2741       any of the other locks, but want to read gtid_mode, don't need
2742       to take the other locks.
2743     */
2744     gtid_mode_lock->wrlock();
2745     channel_map.wrlock();
2746     mysql_mutex_lock(mysql_bin_log.get_log_lock());
2747     global_sid_lock->wrlock();
2748     int lock_count= 4;
2749 
2750     enum_gtid_mode new_gtid_mode=
2751       (enum_gtid_mode)var->save_result.ulonglong_value;
2752     enum_gtid_mode old_gtid_mode= get_gtid_mode(GTID_MODE_LOCK_SID);
2753     assert(new_gtid_mode <= GTID_MODE_ON);
2754 
2755     DBUG_PRINT("info", ("old_gtid_mode=%d new_gtid_mode=%d",
2756                         old_gtid_mode, new_gtid_mode));
2757 
2758     if (new_gtid_mode == old_gtid_mode)
2759       goto end;
2760 
2761     // Can only change one step at a time.
2762     if (abs((int)new_gtid_mode - (int)old_gtid_mode) > 1)
2763     {
2764       my_error(ER_GTID_MODE_CAN_ONLY_CHANGE_ONE_STEP_AT_A_TIME, MYF(0));
2765       goto err;
2766     }
2767 
2768     // Not allowed with slave_sql_skip_counter
2769     DBUG_PRINT("info", ("sql_slave_skip_counter=%d", sql_slave_skip_counter));
2770     if (new_gtid_mode == GTID_MODE_ON && sql_slave_skip_counter > 0)
2771     {
2772       my_error(ER_CANT_SET_GTID_MODE, MYF(0), "ON",
2773                "@@GLOBAL.SQL_SLAVE_SKIP_COUNTER is greater than zero");
2774       goto err;
2775     }
2776 
2777     // Cannot set OFF when some channel uses AUTO_POSITION.
2778     if (new_gtid_mode == GTID_MODE_OFF)
2779     {
2780       for (mi_map::iterator it= channel_map.begin(); it!= channel_map.end(); it++)
2781       {
2782         Master_info *mi= it->second;
2783         DBUG_PRINT("info", ("auto_position for channel '%s' is %d",
2784                             mi->get_channel(), mi->is_auto_position()));
2785         if (mi != NULL && mi->is_auto_position())
2786         {
2787           char buf[1024];
2788           sprintf(buf, "replication channel '%.192s' is configured "
2789                   "in AUTO_POSITION mode. Execute "
2790                   "CHANGE MASTER TO MASTER_AUTO_POSITION = 0 "
2791                   "FOR CHANNEL '%.192s' before you set "
2792                   "@@GLOBAL.GTID_MODE = OFF.",
2793                   mi->get_channel(), mi->get_channel());
2794           my_error(ER_CANT_SET_GTID_MODE, MYF(0), "OFF", buf);
2795           goto err;
2796         }
2797       }
2798     }
2799 
2800     // Can't set GTID_MODE != ON when group replication is enabled.
2801     if (is_group_replication_running())
2802     {
2803       assert(old_gtid_mode == GTID_MODE_ON);
2804       assert(new_gtid_mode == GTID_MODE_ON_PERMISSIVE);
2805       my_error(ER_CANT_SET_GTID_MODE, MYF(0),
2806                get_gtid_mode_string(new_gtid_mode),
2807                "group replication requires @@GLOBAL.GTID_MODE=ON");
2808       goto err;
2809     }
2810 
2811     // Compatible with ongoing transactions.
2812     DBUG_PRINT("info", ("anonymous_ownership_count=%d owned_gtids->is_empty=%d",
2813                         gtid_state->get_anonymous_ownership_count(),
2814                         gtid_state->get_owned_gtids()->is_empty()));
2815     gtid_state->get_owned_gtids()->dbug_print("global owned_gtids");
2816     if (new_gtid_mode == GTID_MODE_ON &&
2817         gtid_state->get_anonymous_ownership_count() > 0)
2818     {
2819       my_error(ER_CANT_SET_GTID_MODE, MYF(0), "ON",
2820                "there are ongoing, anonymous transactions. Before "
2821                "setting @@GLOBAL.GTID_MODE = ON, wait until "
2822                "SHOW STATUS LIKE 'ANONYMOUS_TRANSACTION_COUNT' "
2823                "shows zero on all servers. Then wait for all "
2824                "existing, anonymous transactions to replicate to "
2825                "all slaves, and then execute "
2826                "SET @@GLOBAL.GTID_MODE = ON on all servers. "
2827                "See the Manual for details");
2828       goto err;
2829     }
2830 
2831     if (new_gtid_mode == GTID_MODE_OFF &&
2832         !gtid_state->get_owned_gtids()->is_empty())
2833     {
2834       my_error(ER_CANT_SET_GTID_MODE, MYF(0), "OFF",
2835                "there are ongoing transactions that have a GTID. "
2836                "Before you set @@GLOBAL.GTID_MODE = OFF, wait "
2837                "until SELECT @@GLOBAL.GTID_OWNED is empty on all "
2838                "servers. Then wait for all GTID-transactions to "
2839                "replicate to all servers, and then execute "
2840                "SET @@GLOBAL.GTID_MODE = OFF on all servers. "
2841                "See the Manual for details");
2842       goto err;
2843     }
2844 
2845     // Compatible with ongoing GTID-violating transactions
2846     DBUG_PRINT("info", ("automatic_gtid_violating_transaction_count=%d",
2847                         gtid_state->get_automatic_gtid_violating_transaction_count()));
2848     if (new_gtid_mode >= GTID_MODE_ON_PERMISSIVE &&
2849         gtid_state->get_automatic_gtid_violating_transaction_count() > 0)
2850     {
2851       my_error(ER_CANT_SET_GTID_MODE, MYF(0), "ON_PERMISSIVE",
2852                "there are ongoing transactions that use "
2853                "GTID_NEXT = 'AUTOMATIC', which violate GTID "
2854                "consistency. Adjust your workload to be "
2855                "GTID-consistent before setting "
2856                "@@GLOBAL.GTID_MODE = ON_PERMISSIVE. "
2857                "See the Manual for "
2858                "@@GLOBAL.ENFORCE_GTID_CONSISTENCY for details");
2859       goto err;
2860     }
2861 
2862     // Compatible with ENFORCE_GTID_CONSISTENCY.
2863     if (new_gtid_mode == GTID_MODE_ON &&
2864         get_gtid_consistency_mode() != GTID_CONSISTENCY_MODE_ON)
2865     {
2866       my_error(ER_CANT_SET_GTID_MODE, MYF(0), "ON",
2867                "ENFORCE_GTID_CONSISTENCY is not ON");
2868       goto err;
2869     }
2870 
2871     // Can't set GTID_MODE=OFF with ongoing calls to
2872     // WAIT_FOR_EXECUTED_GTID_SET or
2873     // WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS.
2874     DBUG_PRINT("info", ("gtid_wait_count=%d", gtid_state->get_gtid_wait_count() > 0));
2875     if (new_gtid_mode == GTID_MODE_OFF &&
2876         gtid_state->get_gtid_wait_count() > 0)
2877     {
2878       my_error(ER_CANT_SET_GTID_MODE, MYF(0), "OFF",
2879                "there are ongoing calls to "
2880                "WAIT_FOR_EXECUTED_GTID_SET or "
2881                "WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS. Before you set "
2882                "@@GLOBAL.GTID_MODE = OFF, ensure that no other "
2883                "client is waiting for GTID-transactions to be "
2884                "committed");
2885       goto err;
2886     }
2887 
2888     // Update the mode
2889     global_var(ulong)= new_gtid_mode;
2890     global_sid_lock->unlock();
2891     lock_count= 3;
2892 
2893     // Generate note in log
2894     sql_print_information("Changed GTID_MODE from %s to %s.",
2895                           gtid_mode_names[old_gtid_mode],
2896                           gtid_mode_names[new_gtid_mode]);
2897 
2898     // Rotate
2899     {
2900       bool dont_care= false;
2901       if (mysql_bin_log.rotate(true, &dont_care))
2902         goto err;
2903     }
2904 
2905 end:
2906     ret= false;
2907 err:
2908     assert(lock_count >= 0);
2909     assert(lock_count <= 4);
2910     if (lock_count == 4)
2911       global_sid_lock->unlock();
2912     mysql_mutex_unlock(mysql_bin_log.get_log_lock());
2913     channel_map.unlock();
2914     gtid_mode_lock->unlock();
2915     DBUG_RETURN(ret);
2916   }
2917 };
2918 
2919 #endif /* HAVE_REPLICATION */
2920 
2921 
2922 class Sys_var_enforce_gtid_consistency : public Sys_var_multi_enum
2923 {
2924 public:
2925   Sys_var_enforce_gtid_consistency(
2926     const char *name_arg,
2927     const char *comment,
2928     int flag_args,
2929     ptrdiff_t off,
2930     size_t size,
2931     CMD_LINE getopt,
2932     const ALIAS aliases[],
2933     const uint value_count,
2934     uint def_val,
2935     uint command_line_no_value,
2936     PolyLock *lock=0,
2937     enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
2938     on_check_function on_check_func=0) :
Sys_var_multi_enum(name_arg,comment,flag_args,off,size,getopt,aliases,value_count,def_val,command_line_no_value,lock,binlog_status_arg,on_check_func)2939   Sys_var_multi_enum(name_arg, comment, flag_args, off, size, getopt,
2940                aliases, value_count, def_val, command_line_no_value,
2941                lock, binlog_status_arg, on_check_func)
2942   { }
2943 
global_update(THD * thd,set_var * var)2944   bool global_update(THD *thd, set_var *var)
2945   {
2946     DBUG_ENTER("Sys_var_enforce_gtid_consistency::global_update");
2947     bool ret= true;
2948 
2949     /*
2950       Hold global_sid_lock.wrlock so that other transactions cannot
2951       acquire ownership of any gtid.
2952     */
2953     global_sid_lock->wrlock();
2954 
2955     DBUG_PRINT("info", ("var->save_result.ulonglong_value=%llu",
2956                         var->save_result.ulonglong_value));
2957     enum_gtid_consistency_mode new_mode=
2958       (enum_gtid_consistency_mode)var->save_result.ulonglong_value;
2959     enum_gtid_consistency_mode old_mode= get_gtid_consistency_mode();
2960     enum_gtid_mode gtid_mode= get_gtid_mode(GTID_MODE_LOCK_SID);
2961 
2962     assert(new_mode <= GTID_CONSISTENCY_MODE_WARN);
2963 
2964     DBUG_PRINT("info", ("old enforce_gtid_consistency=%d "
2965                         "new enforce_gtid_consistency=%d "
2966                         "gtid_mode=%d ",
2967                         old_mode, new_mode, gtid_mode));
2968 
2969     if (new_mode == old_mode)
2970       goto end;
2971 
2972     // Can't turn off GTID-consistency when GTID_MODE=ON.
2973     if (new_mode != GTID_CONSISTENCY_MODE_ON && gtid_mode == GTID_MODE_ON)
2974     {
2975       my_error(ER_GTID_MODE_ON_REQUIRES_ENFORCE_GTID_CONSISTENCY_ON, MYF(0));
2976       goto err;
2977     }
2978     // If there are ongoing GTID-violating transactions, and we are
2979     // moving from OFF->ON, WARN->ON, or OFF->WARN, generate warning
2980     // or error accordingly.
2981     if (new_mode == GTID_CONSISTENCY_MODE_ON ||
2982         (old_mode == GTID_CONSISTENCY_MODE_OFF &&
2983          new_mode == GTID_CONSISTENCY_MODE_WARN))
2984     {
2985       DBUG_PRINT("info",
2986                  ("automatic_gtid_violating_transaction_count=%d "
2987                   "anonymous_gtid_violating_transaction_count=%d",
2988                   gtid_state->get_automatic_gtid_violating_transaction_count(),
2989                   gtid_state->get_anonymous_gtid_violating_transaction_count()));
2990       if (gtid_state->get_automatic_gtid_violating_transaction_count() > 0 ||
2991           gtid_state->get_anonymous_gtid_violating_transaction_count() > 0)
2992       {
2993         if (new_mode == GTID_CONSISTENCY_MODE_ON)
2994         {
2995           my_error(ER_CANT_SET_ENFORCE_GTID_CONSISTENCY_ON_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS, MYF(0));
2996           goto err;
2997         }
2998         else
2999         {
3000           push_warning_printf(thd, Sql_condition::SL_WARNING,
3001                               ER_SET_ENFORCE_GTID_CONSISTENCY_WARN_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS,
3002                               "%s", ER(ER_SET_ENFORCE_GTID_CONSISTENCY_WARN_WITH_ONGOING_GTID_VIOLATING_TRANSACTIONS));
3003         }
3004       }
3005     }
3006 
3007     // Update the mode
3008     global_var(ulong)= new_mode;
3009 
3010     // Generate note in log
3011     sql_print_information("Changed ENFORCE_GTID_CONSISTENCY from %s to %s.",
3012                           get_gtid_consistency_mode_string(old_mode),
3013                           get_gtid_consistency_mode_string(new_mode));
3014 
3015 end:
3016     ret= false;
3017 err:
3018     global_sid_lock->unlock();
3019     DBUG_RETURN(ret);
3020   }
3021 };
3022 
3023 #endif /* SYS_VARS_H_INCLUDED */
3024 
3025