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