1/* Copyright (c) 2002, 2011, Oracle and/or its affiliates.
2   Copyright (c) 2010, 2019, MariaDB Corporation.
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; version 2 of the License.
7
8   This program is distributed in the hope that it will be useful,
9   but WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   GNU General Public License for more details.
12
13   You should have received a copy of the GNU General Public License
14   along with this program; if not, write to the Free Software
15   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335  USA */
16
17/**
18  @file
19  "private" interface to sys_var - server configuration variables.
20
21  This header is included only by the file that contains declarations
22  of sys_var variables (sys_vars.cc).
23*/
24
25#include "sys_vars_shared.h"
26#include <my_getopt.h>
27#include <my_bit.h>
28#include <my_dir.h>
29#include "keycaches.h"
30#include "strfunc.h"
31#include "tztime.h"     // my_tz_find, my_tz_SYSTEM, struct Time_zone
32#include "rpl_mi.h" // For Multi-Source Replication
33#include "debug_sync.h"
34
35/*
36  a set of mostly trivial (as in f(X)=X) defines below to make system variable
37  declarations more readable
38*/
39#define VALID_RANGE(X,Y) X,Y
40#define DEFAULT(X) X
41#define BLOCK_SIZE(X) X
42#define GLOBAL_VAR(X) sys_var::GLOBAL, (((char*)&(X))-(char*)&global_system_variables), sizeof(X)
43#define SESSION_VAR(X) sys_var::SESSION, offsetof(SV, X), sizeof(((SV *)0)->X)
44#define SESSION_ONLY(X) sys_var::ONLY_SESSION, offsetof(SV, X), sizeof(((SV *)0)->X)
45#define NO_CMD_LINE CMD_LINE(NO_ARG, sys_var::NO_GETOPT)
46#define CMD_LINE_HELP_ONLY CMD_LINE(NO_ARG, sys_var::GETOPT_ONLY_HELP)
47/*
48  the define below means that there's no *second* mutex guard,
49  LOCK_global_system_variables always guards all system variables
50*/
51#define NO_MUTEX_GUARD ((PolyLock*)0)
52#define IN_BINLOG sys_var::SESSION_VARIABLE_IN_BINLOG
53#define NOT_IN_BINLOG sys_var::VARIABLE_NOT_IN_BINLOG
54#define ON_READ(X) X
55#define ON_CHECK(X) X
56#define ON_UPDATE(X) X
57#define READ_ONLY sys_var::READONLY+
58#define AUTO_SET sys_var::AUTO_SET+
59// this means that Sys_var_charptr initial value was malloc()ed
60#define PREALLOCATED sys_var::ALLOCATED+
61#define PARSED_EARLY sys_var::PARSE_EARLY+
62#define NO_SET_STMT sys_var::NO_SET_STATEMENT+
63
64/*
65  Sys_var_bit meaning is reversed, like in
66  @@foreign_key_checks <-> OPTION_NO_FOREIGN_KEY_CHECKS
67*/
68#define REVERSE(X) ~(X)
69#define DEPRECATED(X) X
70
71#define session_var(THD, TYPE) (*(TYPE*)session_var_ptr(THD))
72#define global_var(TYPE) (*(TYPE*)global_var_ptr())
73
74#if SIZEOF_OFF_T > 4 && defined(BIG_TABLES)
75#define GET_HA_ROWS GET_ULL
76#else
77#define GET_HA_ROWS GET_ULONG
78#endif
79
80// Disable warning caused by SESSION_VAR() macro
81#ifdef __clang__
82#pragma clang diagnostic ignored "-Winvalid-offsetof"
83#endif
84
85/*
86  special assert for sysvars. Tells the name of the variable,
87  and fails even in non-debug builds.
88
89  It is supposed to be used *only* in Sys_var* constructors,
90  and has name_arg hard-coded to prevent incorrect usage.
91*/
92#define SYSVAR_ASSERT(X)                                                \
93    while(!(X))                                                         \
94    {                                                                   \
95      fprintf(stderr, "Sysvar '%s' failed '%s'\n", name_arg, #X);       \
96      DBUG_ASSERT(0);                                                   \
97      exit(255);                                                        \
98    }
99
100enum charset_enum {IN_SYSTEM_CHARSET, IN_FS_CHARSET};
101
102static const char *bool_values[3]= {"OFF", "ON", 0};
103TYPELIB bool_typelib={ array_elements(bool_values)-1, "", bool_values, 0 };
104
105/**
106  A small wrapper class to pass getopt arguments as a pair
107  to the Sys_var_* constructors. It improves type safety and helps
108  to catch errors in the argument order.
109*/
110struct CMD_LINE
111{
112  int id;
113  enum get_opt_arg_type arg_type;
114  CMD_LINE(enum get_opt_arg_type getopt_arg_type, int getopt_id=0)
115    : id(getopt_id), arg_type(getopt_arg_type) {}
116};
117
118/**
119  Sys_var_integer template is used to generate Sys_var_* classes
120  for variables that represent the value as an integer number.
121  They are Sys_var_uint, Sys_var_ulong, Sys_var_harows, Sys_var_ulonglong,
122  Sys_var_int.
123
124  An integer variable has a minimal and maximal values, and a "block_size"
125  (any valid value of the variable must be divisible by the block_size).
126
127  Class specific constructor arguments: min, max, block_size
128  Backing store: int, uint, ulong, ha_rows, ulonglong, depending on the class
129*/
130template <typename T, ulong ARGT, enum enum_mysql_show_type SHOWT>
131class Sys_var_integer: public sys_var
132{
133public:
134  Sys_var_integer(const char *name_arg,
135          const char *comment, int flag_args, ptrdiff_t off, size_t size,
136          CMD_LINE getopt,
137          T min_val, T max_val, T def_val, uint block_size, PolyLock *lock=0,
138          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
139          on_check_function on_check_func=0,
140          on_update_function on_update_func=0,
141          const char *substitute=0)
142    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
143              getopt.arg_type, SHOWT, def_val, lock, binlog_status_arg,
144              on_check_func, on_update_func, substitute)
145  {
146    option.var_type|= ARGT;
147    option.min_value= min_val;
148    option.max_value= max_val;
149    option.block_size= block_size;
150    if ((option.u_max_value= (uchar**) max_var_ptr()))
151    {
152      *((T*) option.u_max_value)= max_val;
153    }
154
155    global_var(T)= def_val;
156    SYSVAR_ASSERT(size == sizeof(T));
157    SYSVAR_ASSERT(min_val < max_val);
158    SYSVAR_ASSERT(min_val <= def_val);
159    SYSVAR_ASSERT(max_val >= def_val);
160    SYSVAR_ASSERT(block_size > 0);
161    SYSVAR_ASSERT(def_val % block_size == 0);
162  }
163  bool do_check(THD *thd, set_var *var)
164  {
165    my_bool fixed= FALSE, unused;
166    longlong v= var->value->val_int();
167
168    if ((ARGT == GET_HA_ROWS) || (ARGT == GET_UINT) ||
169        (ARGT == GET_ULONG)   || (ARGT == GET_ULL))
170    {
171      ulonglong uv;
172
173      /*
174        if the value is signed and negative,
175        and a variable is unsigned, it is set to zero
176      */
177      if ((fixed= (!var->value->unsigned_flag && v < 0)))
178        uv= 0;
179      else
180        uv= v;
181
182      var->save_result.ulonglong_value=
183        getopt_ull_limit_value(uv, &option, &unused);
184
185      if (max_var_ptr() && (T)var->save_result.ulonglong_value > get_max_var())
186        var->save_result.ulonglong_value= get_max_var();
187
188      fixed= fixed || var->save_result.ulonglong_value != uv;
189    }
190    else
191    {
192      /*
193        if the value is unsigned and has the highest bit set
194        and a variable is signed, it is set to max signed value
195      */
196      if ((fixed= (var->value->unsigned_flag && v < 0)))
197        v= LONGLONG_MAX;
198
199      var->save_result.longlong_value=
200        getopt_ll_limit_value(v, &option, &unused);
201
202      if (max_var_ptr() && (T)var->save_result.longlong_value > get_max_var())
203        var->save_result.longlong_value= get_max_var();
204
205      fixed= fixed || var->save_result.longlong_value != v;
206    }
207    return throw_bounds_warning(thd, name.str, fixed,
208                                var->value->unsigned_flag, v);
209  }
210  bool session_update(THD *thd, set_var *var)
211  {
212    session_var(thd, T)= static_cast<T>(var->save_result.ulonglong_value);
213    return false;
214  }
215  bool global_update(THD *thd, set_var *var)
216  {
217    global_var(T)= static_cast<T>(var->save_result.ulonglong_value);
218    return false;
219  }
220  void session_save_default(THD *thd, set_var *var)
221  { var->save_result.ulonglong_value= (ulonglong)*(T*)global_value_ptr(thd, 0); }
222  void global_save_default(THD *thd, set_var *var)
223  { var->save_result.ulonglong_value= option.def_value; }
224  private:
225  T get_max_var() { return *((T*) max_var_ptr()); }
226  const uchar *default_value_ptr(THD *thd) const { return (uchar*) &option.def_value; }
227};
228
229typedef Sys_var_integer<int, GET_INT, SHOW_SINT> Sys_var_int;
230typedef Sys_var_integer<uint, GET_UINT, SHOW_UINT> Sys_var_uint;
231typedef Sys_var_integer<ulong, GET_ULONG, SHOW_ULONG> Sys_var_ulong;
232typedef Sys_var_integer<ha_rows, GET_HA_ROWS, SHOW_HA_ROWS> Sys_var_harows;
233typedef Sys_var_integer<ulonglong, GET_ULL, SHOW_ULONGLONG> Sys_var_ulonglong;
234typedef Sys_var_integer<long, GET_LONG, SHOW_SLONG> Sys_var_long;
235
236
237template<> const uchar *Sys_var_int::default_value_ptr(THD *thd) const
238{
239  thd->sys_var_tmp.int_value= (int)option.def_value;
240  return (uchar*) &thd->sys_var_tmp.int_value;
241}
242
243template<> const uchar *Sys_var_uint::default_value_ptr(THD *thd) const
244{
245  thd->sys_var_tmp.uint_value= (uint)option.def_value;
246  return (uchar*) &thd->sys_var_tmp.uint_value;
247}
248
249template<> const uchar *Sys_var_long::default_value_ptr(THD *thd) const
250{
251  thd->sys_var_tmp.long_value= (long)option.def_value;
252  return (uchar*) &thd->sys_var_tmp.long_value;
253}
254
255template<> const uchar *Sys_var_ulong::default_value_ptr(THD *thd) const
256{
257  thd->sys_var_tmp.ulong_value= (ulong)option.def_value;
258  return (uchar*) &thd->sys_var_tmp.ulong_value;
259}
260
261
262/**
263  Helper class for variables that take values from a TYPELIB
264*/
265class Sys_var_typelib: public sys_var
266{
267protected:
268  TYPELIB typelib;
269  virtual bool check_maximum(THD *thd, set_var *var,
270                             const char *c_val, longlong i_val)
271    { return FALSE; }
272public:
273  Sys_var_typelib(const char *name_arg,
274          const char *comment, int flag_args, ptrdiff_t off,
275          CMD_LINE getopt,
276          SHOW_TYPE show_val_type_arg, const char *values[],
277          ulonglong def_val, PolyLock *lock,
278          enum binlog_status_enum binlog_status_arg,
279          on_check_function on_check_func, on_update_function on_update_func,
280          const char *substitute)
281    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
282              getopt.arg_type, show_val_type_arg, def_val, lock,
283              binlog_status_arg, on_check_func,
284              on_update_func, substitute)
285  {
286    for (typelib.count= 0; values[typelib.count]; typelib.count++) /*no-op */;
287    typelib.name="";
288    typelib.type_names= values;
289    typelib.type_lengths= 0;    // only used by Fields_enum and Field_set
290    option.typelib= &typelib;
291  }
292  bool do_check(THD *thd, set_var *var) // works for enums and my_bool
293  {
294    char buff[STRING_BUFFER_USUAL_SIZE];
295    String str(buff, sizeof(buff), system_charset_info), *res;
296
297    if (var->value->result_type() == STRING_RESULT)
298    {
299      if (!(res=var->value->val_str(&str)))
300        return true;
301      else
302      if (!(var->save_result.ulonglong_value=
303            find_type(&typelib, res->ptr(), res->length(), false)))
304        return true;
305      else
306        var->save_result.ulonglong_value--;
307      return check_maximum(thd, var, res->ptr(), 0);
308    }
309
310    longlong tmp=var->value->val_int();
311    if (tmp < 0 || tmp >= typelib.count)
312      return true;
313    var->save_result.ulonglong_value= tmp;
314    return check_maximum(thd, var, 0, tmp);
315  }
316};
317
318/**
319  The class for ENUM variables - variables that take one value from a fixed
320  list of values.
321
322  Class specific constructor arguments:
323    char* values[]    - 0-terminated list of strings of valid values
324
325  Backing store: ulong
326
327  @note
328  Do *not* use "enum FOO" variables as a backing store, there is no
329  guarantee that sizeof(enum FOO) == sizeof(uint), there is no guarantee
330  even that sizeof(enum FOO) == sizeof(enum BAR)
331*/
332class Sys_var_enum: public Sys_var_typelib
333{
334public:
335  Sys_var_enum(const char *name_arg,
336          const char *comment, int flag_args, ptrdiff_t off, size_t size,
337          CMD_LINE getopt,
338          const char *values[], uint def_val, PolyLock *lock=0,
339          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
340          on_check_function on_check_func=0,
341          on_update_function on_update_func=0,
342          const char *substitute=0)
343    : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
344                      SHOW_CHAR, values, def_val, lock,
345                      binlog_status_arg, on_check_func, on_update_func,
346                      substitute)
347  {
348    option.var_type|= GET_ENUM;
349    option.min_value= 0;
350    option.max_value= ULONG_MAX;
351    global_var(ulong)= def_val;
352    if ((option.u_max_value= (uchar**)max_var_ptr()))
353    {
354      *((ulong *) option.u_max_value)= ULONG_MAX;
355    }
356    SYSVAR_ASSERT(def_val < typelib.count);
357    SYSVAR_ASSERT(size == sizeof(ulong));
358  }
359  bool check_maximum(THD *thd, set_var *var,
360                     const char *c_val, longlong i_val)
361  {
362    if (!max_var_ptr() ||
363        var->save_result.ulonglong_value <= get_max_var())
364      return FALSE;
365    var->save_result.ulonglong_value= get_max_var();
366
367    return c_val ? throw_bounds_warning(thd, name.str, c_val) :
368                   throw_bounds_warning(thd, name.str, TRUE,
369                                        var->value->unsigned_flag, i_val);
370  }
371  bool session_update(THD *thd, set_var *var)
372  {
373    session_var(thd, ulong)= static_cast<ulong>(var->save_result.ulonglong_value);
374    return false;
375  }
376  bool global_update(THD *thd, set_var *var)
377  {
378    global_var(ulong)= static_cast<ulong>(var->save_result.ulonglong_value);
379    return false;
380  }
381  void session_save_default(THD *thd, set_var *var)
382  { var->save_result.ulonglong_value= global_var(ulong); }
383  void global_save_default(THD *thd, set_var *var)
384  { var->save_result.ulonglong_value= option.def_value; }
385  const uchar *valptr(THD *thd, ulong val) const
386  { return reinterpret_cast<const uchar*>(typelib.type_names[val]); }
387  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
388  { return valptr(thd, session_var(thd, ulong)); }
389  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
390  { return valptr(thd, global_var(ulong)); }
391  const uchar *default_value_ptr(THD *thd) const
392  { return valptr(thd, (ulong)option.def_value); }
393
394  ulong get_max_var() { return *((ulong *) max_var_ptr()); }
395};
396
397/**
398  The class for boolean variables - a variant of ENUM variables
399  with the fixed list of values of { OFF , ON }
400
401  Backing store: my_bool
402*/
403class Sys_var_mybool: public Sys_var_typelib
404{
405public:
406  Sys_var_mybool(const char *name_arg,
407          const char *comment, int flag_args, ptrdiff_t off, size_t size,
408          CMD_LINE getopt,
409          my_bool def_val, PolyLock *lock=0,
410          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
411          on_check_function on_check_func=0,
412          on_update_function on_update_func=0,
413          const char *substitute=0)
414    : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
415                      SHOW_MY_BOOL, bool_values, def_val, lock,
416                      binlog_status_arg, on_check_func, on_update_func,
417                      substitute)
418  {
419    option.var_type|= GET_BOOL;
420    global_var(my_bool)= def_val;
421    SYSVAR_ASSERT(def_val < 2);
422    SYSVAR_ASSERT(getopt.arg_type == OPT_ARG || getopt.id < 0);
423    SYSVAR_ASSERT(size == sizeof(my_bool));
424  }
425  bool session_update(THD *thd, set_var *var)
426  {
427    session_var(thd, my_bool)= var->save_result.ulonglong_value != 0;
428    return false;
429  }
430  bool global_update(THD *thd, set_var *var)
431  {
432    global_var(my_bool)= var->save_result.ulonglong_value != 0;
433    return false;
434  }
435  void session_save_default(THD *thd, set_var *var)
436  { var->save_result.ulonglong_value= (ulonglong)*(my_bool *)global_value_ptr(thd, 0); }
437  void global_save_default(THD *thd, set_var *var)
438  { var->save_result.ulonglong_value= option.def_value; }
439  const uchar *default_value_ptr(THD *thd) const
440  {
441    thd->sys_var_tmp.my_bool_value=(my_bool) option.def_value;
442    return (uchar*) &thd->sys_var_tmp.my_bool_value;
443  }
444};
445
446/**
447  The class for string variables. The string can be in character_set_filesystem
448  or in character_set_system. The string can be allocated with my_malloc()
449  or not. The state of the initial value is specified in the constructor,
450  after that it's managed automatically. The value of NULL is supported.
451
452  Class specific constructor arguments:
453    enum charset_enum is_os_charset_arg
454
455  Backing store: char*
456
457  @note
458  This class supports only GLOBAL variables, because THD on destruction
459  does not destroy individual members of SV, there's no way to free
460  allocated string variables for every thread.
461*/
462class Sys_var_charptr_base: public sys_var
463{
464public:
465  Sys_var_charptr_base(const char *name_arg,
466          const char *comment, int flag_args, ptrdiff_t off, size_t size,
467          CMD_LINE getopt,
468          enum charset_enum is_os_charset_arg,
469          const char *def_val, PolyLock *lock=0,
470          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
471          on_check_function on_check_func=0,
472          on_update_function on_update_func=0,
473          const char *substitute=0)
474    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
475              getopt.arg_type, SHOW_CHAR_PTR, (intptr)def_val,
476              lock, binlog_status_arg, on_check_func, on_update_func,
477              substitute)
478  {
479    is_os_charset= is_os_charset_arg == IN_FS_CHARSET;
480    /*
481     use GET_STR_ALLOC - if ALLOCATED it must be *always* allocated,
482     otherwise (GET_STR) you'll never know whether to free it or not.
483     (think of an exit because of an error right after my_getopt)
484    */
485    option.var_type|= (flags & ALLOCATED) ? GET_STR_ALLOC : GET_STR;
486    global_var(const char*)= def_val;
487  }
488  void cleanup()
489  {
490    if (flags & ALLOCATED)
491    {
492      my_free(global_var(char*));
493      global_var(char *)= NULL;
494    }
495    flags&= ~ALLOCATED;
496  }
497  static bool do_string_check(THD *thd, set_var *var, CHARSET_INFO *charset)
498  {
499    char buff[STRING_BUFFER_USUAL_SIZE], buff2[STRING_BUFFER_USUAL_SIZE];
500    String str(buff, sizeof(buff), charset);
501    String str2(buff2, sizeof(buff2), charset), *res;
502
503    if (!(res=var->value->val_str(&str)))
504    {
505      var->save_result.string_value.str= 0;
506      var->save_result.string_value.length= 0; // safety
507    }
508    else
509    {
510      uint32 unused;
511      if (String::needs_conversion(res->length(), res->charset(),
512                                   charset, &unused))
513      {
514        uint errors;
515        str2.copy(res->ptr(), res->length(), res->charset(), charset,
516                  &errors);
517        res=&str2;
518
519      }
520      var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
521      var->save_result.string_value.length= res->length();
522    }
523
524    return false;
525  }
526  bool do_check(THD *thd, set_var *var)
527  { return do_string_check(thd, var, charset(thd)); }
528  bool session_update(THD *thd, set_var *var)= 0;
529  char *global_update_prepare(THD *thd, set_var *var)
530  {
531    char *new_val, *ptr= var->save_result.string_value.str;
532    size_t len=var->save_result.string_value.length;
533    if (ptr)
534    {
535      new_val= (char*)my_memdup(ptr, len+1, MYF(MY_WME));
536      if (!new_val) return 0;
537      new_val[len]=0;
538    }
539    else
540      new_val= 0;
541    return new_val;
542  }
543  void global_update_finish(char *new_val)
544  {
545    if (flags & ALLOCATED)
546      my_free(global_var(char*));
547    flags|= ALLOCATED;
548    global_var(char*)= new_val;
549  }
550  bool global_update(THD *thd, set_var *var)
551  {
552    char *new_val= global_update_prepare(thd, var);
553    global_update_finish(new_val);
554    return (new_val == 0 && var->save_result.string_value.str != 0);
555  }
556  void session_save_default(THD *thd, set_var *var)= 0;
557  void global_save_default(THD *thd, set_var *var)
558  {
559    char *ptr= (char*)(intptr)option.def_value;
560    var->save_result.string_value.str= ptr;
561    var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
562  }
563};
564
565class Sys_var_charptr: public Sys_var_charptr_base
566{
567public:
568  Sys_var_charptr(const char *name_arg,
569          const char *comment, int flag_args, ptrdiff_t off, size_t size,
570          CMD_LINE getopt,
571          enum charset_enum is_os_charset_arg,
572          const char *def_val, PolyLock *lock=0,
573          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
574          on_check_function on_check_func=0,
575          on_update_function on_update_func=0,
576          const char *substitute=0) :
577    Sys_var_charptr_base(name_arg, comment, flag_args, off, size, getopt,
578                         is_os_charset_arg, def_val, lock, binlog_status_arg,
579                         on_check_func, on_update_func, substitute)
580  {
581    SYSVAR_ASSERT(scope() == GLOBAL);
582    SYSVAR_ASSERT(size == sizeof(char *));
583  }
584
585  bool session_update(THD *thd, set_var *var)
586  {
587    DBUG_ASSERT(FALSE);
588    return true;
589  }
590  void session_save_default(THD *thd, set_var *var)
591  { DBUG_ASSERT(FALSE); }
592};
593
594#ifndef EMBEDDED_LIBRARY
595class Sys_var_sesvartrack: public Sys_var_charptr_base
596{
597public:
598  Sys_var_sesvartrack(const char *name_arg,
599                      const char *comment,
600                      CMD_LINE getopt,
601                      enum charset_enum is_os_charset_arg,
602                      const char *def_val, PolyLock *lock) :
603    Sys_var_charptr_base(name_arg, comment,
604                         SESSION_VAR(session_track_system_variables),
605                         getopt, is_os_charset_arg, def_val, lock,
606                         VARIABLE_NOT_IN_BINLOG, 0, 0, 0)
607    {}
608  bool do_check(THD *thd, set_var *var)
609  {
610     if (Sys_var_charptr_base::do_check(thd, var) ||
611         sysvartrack_validate_value(thd, var->save_result.string_value.str,
612                                    var->save_result.string_value.length))
613       return TRUE;
614     return FALSE;
615  }
616  bool global_update(THD *thd, set_var *var)
617  {
618    char *new_val= global_update_prepare(thd, var);
619    if (new_val)
620    {
621      if (sysvartrack_global_update(thd, new_val,
622                                    var->save_result.string_value.length))
623        new_val= 0;
624    }
625    global_update_finish(new_val);
626    return (new_val == 0 && var->save_result.string_value.str != 0);
627  }
628  bool session_update(THD *thd, set_var *var)
629  { return thd->session_tracker.sysvars.update(thd, var); }
630  void session_save_default(THD *thd, set_var *var)
631  {
632     var->save_result.string_value.str= global_var(char*);
633     var->save_result.string_value.length=
634       strlen(var->save_result.string_value.str);
635     /* parse and feel list with default values */
636     if (thd)
637     {
638#ifdef DBUG_ASSERT_EXISTS
639       bool res=
640#endif
641         sysvartrack_validate_value(thd,
642                                    var->save_result.string_value.str,
643                                    var->save_result.string_value.length);
644       DBUG_ASSERT(res == 0);
645     }
646  }
647};
648#endif //EMBEDDED_LIBRARY
649
650
651class Sys_var_proxy_user: public sys_var
652{
653public:
654  Sys_var_proxy_user(const char *name_arg,
655          const char *comment, enum charset_enum is_os_charset_arg)
656    : sys_var(&all_sys_vars, name_arg, comment,
657              sys_var::READONLY+sys_var::ONLY_SESSION, 0, NO_GETOPT,
658              NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
659              NULL, NULL, NULL)
660  {
661    is_os_charset= is_os_charset_arg == IN_FS_CHARSET;
662    option.var_type|= GET_STR;
663  }
664  bool do_check(THD *thd, set_var *var)
665  {
666    DBUG_ASSERT(FALSE);
667    return true;
668  }
669  bool session_update(THD *thd, set_var *var)
670  {
671    DBUG_ASSERT(FALSE);
672    return true;
673  }
674  bool global_update(THD *thd, set_var *var)
675  {
676    DBUG_ASSERT(FALSE);
677    return false;
678  }
679  void session_save_default(THD *thd, set_var *var)
680  { DBUG_ASSERT(FALSE); }
681  void global_save_default(THD *thd, set_var *var)
682  { DBUG_ASSERT(FALSE); }
683protected:
684  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
685  {
686    return thd->security_ctx->proxy_user[0] ?
687      (uchar *) &(thd->security_ctx->proxy_user[0]) : NULL;
688  }
689};
690
691class Sys_var_external_user : public Sys_var_proxy_user
692{
693public:
694  Sys_var_external_user(const char *name_arg, const char *comment_arg,
695          enum charset_enum is_os_charset_arg)
696    : Sys_var_proxy_user (name_arg, comment_arg, is_os_charset_arg)
697  {}
698
699protected:
700  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
701  {
702    return (uchar*)thd->security_ctx->external_user;
703  }
704};
705
706class Master_info;
707class Sys_var_rpl_filter: public sys_var
708{
709private:
710  int opt_id;
711
712public:
713  Sys_var_rpl_filter(const char *name, int getopt_id, const char *comment)
714    : sys_var(&all_sys_vars, name, comment, sys_var::GLOBAL, 0, NO_GETOPT,
715              NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
716              NULL, NULL, NULL), opt_id(getopt_id)
717  {
718    option.var_type|= GET_STR | GET_ASK_ADDR;
719  }
720
721  bool do_check(THD *thd, set_var *var)
722  {
723    return Sys_var_charptr::do_string_check(thd, var, charset(thd));
724  }
725  void session_save_default(THD *thd, set_var *var)
726  { DBUG_ASSERT(FALSE); }
727
728  void global_save_default(THD *thd, set_var *var)
729  {
730    char *ptr= (char*)(intptr)option.def_value;
731    var->save_result.string_value.str= ptr;
732    var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
733  }
734
735  bool session_update(THD *thd, set_var *var)
736  {
737    DBUG_ASSERT(FALSE);
738    return true;
739  }
740
741  bool global_update(THD *thd, set_var *var);
742
743protected:
744  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const;
745  bool set_filter_value(const char *value, Master_info *mi);
746};
747
748/**
749  The class for string variables. Useful for strings that aren't necessarily
750  \0-terminated. Otherwise the same as Sys_var_charptr.
751
752  Class specific constructor arguments:
753    enum charset_enum is_os_charset_arg
754
755  Backing store: LEX_CSTRING
756
757  @note
758  Behaves exactly as Sys_var_charptr, only the backing store is different.
759*/
760class Sys_var_lexstring: public Sys_var_charptr
761{
762public:
763  Sys_var_lexstring(const char *name_arg,
764          const char *comment, int flag_args, ptrdiff_t off, size_t size,
765          CMD_LINE getopt,
766          enum charset_enum is_os_charset_arg,
767          const char *def_val, PolyLock *lock=0,
768          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
769          on_check_function on_check_func=0,
770          on_update_function on_update_func=0,
771          const char *substitute=0)
772    : Sys_var_charptr(name_arg, comment, flag_args, off, sizeof(char*),
773              getopt, is_os_charset_arg, def_val, lock, binlog_status_arg,
774              on_check_func, on_update_func, substitute)
775  {
776    global_var(LEX_CSTRING).length= strlen(def_val);
777    SYSVAR_ASSERT(size == sizeof(LEX_CSTRING));
778    *const_cast<SHOW_TYPE*>(&show_val_type)= SHOW_LEX_STRING;
779  }
780  bool global_update(THD *thd, set_var *var)
781  {
782    if (Sys_var_charptr::global_update(thd, var))
783      return true;
784    global_var(LEX_CSTRING).length= var->save_result.string_value.length;
785    return false;
786  }
787};
788
789
790/*
791  A LEX_CSTRING stored only in thd->variables
792  Only to be used for small buffers
793*/
794
795class Sys_var_session_lexstring: public sys_var
796{
797  size_t max_length;
798public:
799  Sys_var_session_lexstring(const char *name_arg,
800                            const char *comment, int flag_args,
801                            ptrdiff_t off, size_t size, CMD_LINE getopt,
802                            enum charset_enum is_os_charset_arg,
803                            const char *def_val, size_t max_length_arg,
804                            on_check_function on_check_func=0,
805                            on_update_function on_update_func=0)
806    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
807              getopt.arg_type, SHOW_CHAR, (intptr)def_val,
808              0, VARIABLE_NOT_IN_BINLOG, on_check_func, on_update_func,
809              0),max_length(max_length_arg)
810  {
811    option.var_type|= GET_STR;
812    SYSVAR_ASSERT(scope() == ONLY_SESSION)
813    *const_cast<SHOW_TYPE*>(&show_val_type)= SHOW_LEX_STRING;
814  }
815  bool do_check(THD *thd, set_var *var)
816  {
817    char buff[STRING_BUFFER_USUAL_SIZE];
818    String str(buff, sizeof(buff), system_charset_info), *res;
819
820    if (!(res=var->value->val_str(&str)))
821    {
822      var->save_result.string_value.str= 0;     /* NULL */
823      var->save_result.string_value.length= 0;
824    }
825    else
826    {
827      if (res->length() > max_length)
828      {
829        my_error(ER_WRONG_STRING_LENGTH, MYF(0),
830                 res->ptr(), name.str, (int) max_length);
831        return true;
832      }
833      var->save_result.string_value.str= thd->strmake(res->ptr(),
834                                                      res->length());
835      var->save_result.string_value.length= res->length();
836    }
837    return false;
838  }
839  bool session_update(THD *thd, set_var *var)
840  {
841    LEX_CSTRING *tmp= &session_var(thd, LEX_CSTRING);
842    tmp->length= var->save_result.string_value.length;
843    /* Store as \0 terminated string (just to be safe) */
844    strmake((char*) tmp->str, var->save_result.string_value.str, tmp->length);
845    return false;
846  }
847  bool global_update(THD *thd, set_var *var)
848  {
849    DBUG_ASSERT(FALSE);
850    return false;
851  }
852  void session_save_default(THD *thd, set_var *var)
853  {
854    char *ptr= (char*)(intptr)option.def_value;
855    var->save_result.string_value.str= ptr;
856    var->save_result.string_value.length= strlen(ptr);
857  }
858  void global_save_default(THD *thd, set_var *var)
859  {
860    DBUG_ASSERT(FALSE);
861  }
862  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
863  {
864    DBUG_ASSERT(FALSE);
865    return NULL;
866  }
867};
868
869
870#ifndef DBUG_OFF
871/**
872  @@session.debug_dbug and @@global.debug_dbug variables.
873
874  @@dbug variable differs from other variables in one aspect:
875  if its value is not assigned in the session, it "points" to the global
876  value, and so when the global value is changed, the change
877  immediately takes effect in the session.
878
879  This semantics is intentional, to be able to debug one session from
880  another.
881*/
882class Sys_var_dbug: public sys_var
883{
884public:
885  Sys_var_dbug(const char *name_arg,
886               const char *comment, int flag_args,
887               CMD_LINE getopt,
888               const char *def_val, PolyLock *lock=0,
889               enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
890               on_check_function on_check_func=0,
891               on_update_function on_update_func=0,
892               const char *substitute=0)
893    : sys_var(&all_sys_vars, name_arg, comment, flag_args,
894              (char*)&current_dbug_option-(char*)&global_system_variables, getopt.id,
895              getopt.arg_type, SHOW_CHAR, (intptr)def_val,
896              lock, binlog_status_arg, on_check_func, on_update_func,
897              substitute)
898  { option.var_type|= GET_STR; }
899  bool do_check(THD *thd, set_var *var)
900  {
901    char buff[STRING_BUFFER_USUAL_SIZE];
902    String str(buff, sizeof(buff), system_charset_info), *res;
903
904    if (!(res=var->value->val_str(&str)))
905    {
906      var->save_result.string_value.str= const_cast<char*>("");
907      var->save_result.string_value.length= 0;
908    }
909    else
910    {
911      size_t len= res->length();
912      var->save_result.string_value.str= thd->strmake(res->ptr(), len);
913      var->save_result.string_value.length= len;
914    }
915    return false;
916  }
917  bool session_update(THD *thd, set_var *var)
918  {
919    const char *val= var->save_result.string_value.str;
920    if (!var->value)
921      DBUG_POP();
922    else
923      DBUG_SET(val);
924    return false;
925  }
926  bool global_update(THD *thd, set_var *var)
927  {
928    const char *val= var->save_result.string_value.str;
929    DBUG_SET_INITIAL(val);
930    return false;
931  }
932  void session_save_default(THD *thd, set_var *var)
933  { }
934  void global_save_default(THD *thd, set_var *var)
935  {
936    char *ptr= (char*)(intptr)option.def_value;
937    var->save_result.string_value.str= ptr;
938    var->save_result.string_value.length= safe_strlen(ptr);
939  }
940  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
941  {
942    char buf[256];
943    DBUG_EXPLAIN(buf, sizeof(buf));
944    return (uchar*) thd->strdup(buf);
945  }
946  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
947  {
948    char buf[256];
949    DBUG_EXPLAIN_INITIAL(buf, sizeof(buf));
950    return (uchar*) thd->strdup(buf);
951  }
952  const uchar *default_value_ptr(THD *thd) const
953  { return (uchar*)""; }
954};
955#endif
956
957#define KEYCACHE_VAR(X) GLOBAL_VAR(dflt_key_cache_var.X)
958#define keycache_var_ptr(KC, OFF) (((uchar*)(KC))+(OFF))
959#define keycache_var(KC, OFF) (*(ulonglong*)keycache_var_ptr(KC, OFF))
960typedef bool (*keycache_update_function)(THD *, KEY_CACHE *, ptrdiff_t, ulonglong);
961
962/**
963  The class for keycache_* variables. Supports structured names,
964  keycache_name.variable_name.
965
966  Class specific constructor arguments:
967    everything derived from Sys_var_ulonglong
968
969  Backing store: ulonglong
970
971  @note these variables can be only GLOBAL
972*/
973class Sys_var_keycache: public Sys_var_ulonglong
974{
975  keycache_update_function keycache_update;
976public:
977  Sys_var_keycache(const char *name_arg,
978          const char *comment, int flag_args, ptrdiff_t off, size_t size,
979          CMD_LINE getopt,
980          ulonglong min_val, ulonglong max_val, ulonglong def_val,
981          uint block_size, PolyLock *lock,
982          enum binlog_status_enum binlog_status_arg,
983          on_check_function on_check_func,
984          keycache_update_function on_update_func,
985          const char *substitute=0)
986    : Sys_var_ulonglong(name_arg, comment, flag_args, off, size,
987              getopt, min_val, max_val, def_val,
988              block_size, lock, binlog_status_arg, on_check_func, 0,
989              substitute),
990    keycache_update(on_update_func)
991  {
992    option.var_type|= GET_ASK_ADDR;
993    option.value= (uchar**)1; // crash me, please
994    // fix an offset from global_system_variables to be an offset in KEY_CACHE
995    offset= global_var_ptr() - (uchar*)dflt_key_cache;
996    SYSVAR_ASSERT(scope() == GLOBAL);
997  }
998  bool global_update(THD *thd, set_var *var)
999  {
1000    ulonglong new_value= var->save_result.ulonglong_value;
1001    LEX_CSTRING *base_name= &var->base;
1002    KEY_CACHE *key_cache;
1003
1004    /* If no basename, assume it's for the key cache named 'default' */
1005    if (!base_name->length)
1006      base_name= &default_key_cache_base;
1007
1008    key_cache= get_key_cache(base_name);
1009
1010    if (!key_cache)
1011    {                                           // Key cache didn't exists */
1012      if (!new_value)                           // Tried to delete cache
1013        return false;                           // Ok, nothing to do
1014      if (!(key_cache= create_key_cache(base_name->str, base_name->length)))
1015        return true;
1016    }
1017
1018    /**
1019      Abort if some other thread is changing the key cache
1020      @todo This should be changed so that we wait until the previous
1021      assignment is done and then do the new assign
1022    */
1023    if (key_cache->in_init)
1024      return true;
1025
1026    return keycache_update(thd, key_cache, offset, new_value);
1027  }
1028  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
1029  {
1030    KEY_CACHE *key_cache= get_key_cache(base);
1031    if (!key_cache)
1032      key_cache= &zero_key_cache;
1033    return keycache_var_ptr(key_cache, offset);
1034  }
1035};
1036
1037static bool update_buffer_size(THD *thd, KEY_CACHE *key_cache,
1038                               ptrdiff_t offset, ulonglong new_value)
1039{
1040  bool error= false;
1041  DBUG_ASSERT(offset == offsetof(KEY_CACHE, param_buff_size));
1042
1043  if (new_value == 0)
1044  {
1045    if (key_cache == dflt_key_cache)
1046    {
1047      my_error(ER_WARN_CANT_DROP_DEFAULT_KEYCACHE, MYF(0));
1048      return true;
1049    }
1050
1051    if (key_cache->key_cache_inited)            // If initied
1052    {
1053      /*
1054        Move tables using this key cache to the default key cache
1055        and clear the old key cache.
1056      */
1057      key_cache->in_init= 1;
1058      mysql_mutex_unlock(&LOCK_global_system_variables);
1059      key_cache->param_buff_size= 0;
1060      ha_resize_key_cache(key_cache);
1061      ha_change_key_cache(key_cache, dflt_key_cache);
1062      /*
1063        We don't delete the key cache as some running threads my still be in
1064        the key cache code with a pointer to the deleted (empty) key cache
1065      */
1066      mysql_mutex_lock(&LOCK_global_system_variables);
1067      key_cache->in_init= 0;
1068    }
1069    return error;
1070  }
1071
1072  key_cache->param_buff_size= new_value;
1073
1074  /* If key cache didn't exist initialize it, else resize it */
1075  key_cache->in_init= 1;
1076  mysql_mutex_unlock(&LOCK_global_system_variables);
1077
1078  if (!key_cache->key_cache_inited)
1079    error= ha_init_key_cache(0, key_cache, 0);
1080  else
1081    error= ha_resize_key_cache(key_cache);
1082
1083  mysql_mutex_lock(&LOCK_global_system_variables);
1084  key_cache->in_init= 0;
1085
1086  return error;
1087}
1088
1089static bool update_keycache(THD *thd, KEY_CACHE *key_cache,
1090                            ptrdiff_t offset, ulonglong new_value,
1091                            int (*func)(KEY_CACHE *))
1092{
1093  bool error= false;
1094  DBUG_ASSERT(offset != offsetof(KEY_CACHE, param_buff_size));
1095
1096  keycache_var(key_cache, offset)= new_value;
1097
1098  key_cache->in_init= 1;
1099  mysql_mutex_unlock(&LOCK_global_system_variables);
1100  error= func(key_cache);
1101  mysql_mutex_lock(&LOCK_global_system_variables);
1102  key_cache->in_init= 0;
1103
1104  return error;
1105}
1106
1107static bool resize_keycache(THD *thd, KEY_CACHE *key_cache,
1108                            ptrdiff_t offset, ulonglong new_value)
1109{
1110  return update_keycache(thd, key_cache, offset, new_value,
1111                         ha_resize_key_cache);
1112}
1113
1114static bool change_keycache_param(THD *thd, KEY_CACHE *key_cache,
1115                                  ptrdiff_t offset, ulonglong new_value)
1116{
1117  return update_keycache(thd, key_cache, offset, new_value,
1118                         ha_change_key_cache_param);
1119}
1120
1121static bool repartition_keycache(THD *thd, KEY_CACHE *key_cache,
1122                                 ptrdiff_t offset, ulonglong new_value)
1123{
1124  return update_keycache(thd, key_cache, offset, new_value,
1125                         ha_repartition_key_cache);
1126}
1127
1128
1129/**
1130  The class for floating point variables
1131
1132  Class specific constructor arguments: min, max
1133
1134  Backing store: double
1135*/
1136class Sys_var_double: public sys_var
1137{
1138public:
1139  Sys_var_double(const char *name_arg,
1140          const char *comment, int flag_args, ptrdiff_t off, size_t size,
1141          CMD_LINE getopt,
1142          double min_val, double max_val, double def_val, PolyLock *lock=0,
1143          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1144          on_check_function on_check_func=0,
1145          on_update_function on_update_func=0,
1146          const char *substitute=0)
1147    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
1148              getopt.arg_type, SHOW_DOUBLE,
1149              (longlong) getopt_double2ulonglong(def_val),
1150              lock, binlog_status_arg, on_check_func, on_update_func,
1151              substitute)
1152  {
1153    option.var_type|= GET_DOUBLE;
1154    option.min_value= (longlong) getopt_double2ulonglong(min_val);
1155    option.max_value= (longlong) getopt_double2ulonglong(max_val);
1156    global_var(double)= (double)option.def_value;
1157    SYSVAR_ASSERT(min_val < max_val);
1158    SYSVAR_ASSERT(min_val <= def_val);
1159    SYSVAR_ASSERT(max_val >= def_val);
1160    SYSVAR_ASSERT(size == sizeof(double));
1161  }
1162  bool do_check(THD *thd, set_var *var)
1163  {
1164    my_bool fixed;
1165    double v= var->value->val_real();
1166    var->save_result.double_value= getopt_double_limit_value(v, &option, &fixed);
1167
1168    return throw_bounds_warning(thd, name.str, fixed, v);
1169  }
1170  bool session_update(THD *thd, set_var *var)
1171  {
1172    session_var(thd, double)= var->save_result.double_value;
1173    return false;
1174  }
1175  bool global_update(THD *thd, set_var *var)
1176  {
1177    global_var(double)= var->save_result.double_value;
1178    return false;
1179  }
1180  void session_save_default(THD *thd, set_var *var)
1181  { var->save_result.double_value= global_var(double); }
1182  void global_save_default(THD *thd, set_var *var)
1183  { var->save_result.double_value= getopt_ulonglong2double(option.def_value); }
1184};
1185
1186/**
1187  The class for the @max_user_connections.
1188  It's derived from Sys_var_uint, but non-standard session value
1189  requires a new class.
1190
1191  Class specific constructor arguments:
1192    everything derived from Sys_var_uint
1193
1194  Backing store: uint
1195*/
1196class Sys_var_max_user_conn: public Sys_var_int
1197{
1198public:
1199  Sys_var_max_user_conn(const char *name_arg,
1200          const char *comment, int flag_args, ptrdiff_t off, size_t size,
1201          CMD_LINE getopt,
1202          int min_val, int max_val, int def_val,
1203          uint block_size, PolyLock *lock=0,
1204          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1205          on_check_function on_check_func=0,
1206          on_update_function on_update_func=0,
1207          const char *substitute=0)
1208    : Sys_var_int(name_arg, comment, SESSION, off, size, getopt,
1209              min_val, max_val, def_val, block_size,
1210              lock, binlog_status_arg, on_check_func, on_update_func,
1211              substitute)
1212  { }
1213  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
1214  {
1215    if (thd->user_connect && thd->user_connect->user_resources.user_conn)
1216      return (uchar*) &(thd->user_connect->user_resources.user_conn);
1217    return global_value_ptr(thd, base);
1218  }
1219};
1220
1221/**
1222  The class for flagset variables - a variant of SET that allows in-place
1223  editing (turning on/off individual bits). String representations looks like
1224  a "flag=val,flag=val,...". Example: @@optimizer_switch
1225
1226  Class specific constructor arguments:
1227    char* values[]    - 0-terminated list of strings of valid values
1228
1229  Backing store: ulonglong
1230
1231  @note
1232  the last value in the values[] array should
1233  *always* be the string "default".
1234*/
1235class Sys_var_flagset: public Sys_var_typelib
1236{
1237public:
1238  Sys_var_flagset(const char *name_arg,
1239          const char *comment, int flag_args, ptrdiff_t off, size_t size,
1240          CMD_LINE getopt,
1241          const char *values[], ulonglong def_val, PolyLock *lock=0,
1242          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1243          on_check_function on_check_func=0,
1244          on_update_function on_update_func=0,
1245          const char *substitute=0)
1246    : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
1247                      SHOW_CHAR, values, def_val, lock,
1248                      binlog_status_arg, on_check_func, on_update_func,
1249                      substitute)
1250  {
1251    option.var_type|= GET_FLAGSET;
1252    global_var(ulonglong)= def_val;
1253    SYSVAR_ASSERT(typelib.count > 1);
1254    SYSVAR_ASSERT(typelib.count <= 65);
1255    SYSVAR_ASSERT(def_val <= my_set_bits(typelib.count-1));
1256    SYSVAR_ASSERT(strcmp(values[typelib.count-1], "default") == 0);
1257    SYSVAR_ASSERT(size == sizeof(ulonglong));
1258  }
1259  bool do_check(THD *thd, set_var *var)
1260  {
1261    char buff[STRING_BUFFER_USUAL_SIZE];
1262    String str(buff, sizeof(buff), system_charset_info), *res;
1263    ulonglong default_value, current_value;
1264    if (var->type == OPT_GLOBAL)
1265    {
1266      default_value= option.def_value;
1267      current_value= global_var(ulonglong);
1268    }
1269    else
1270    {
1271      default_value= global_var(ulonglong);
1272      current_value= session_var(thd, ulonglong);
1273    }
1274
1275    if (var->value->result_type() == STRING_RESULT)
1276    {
1277      if (!(res=var->value->val_str(&str)))
1278        return true;
1279      else
1280      {
1281        char *error;
1282        uint error_len;
1283
1284        var->save_result.ulonglong_value=
1285              find_set_from_flags(&typelib,
1286                                  typelib.count,
1287                                  current_value,
1288                                  default_value,
1289                                  res->ptr(), res->length(),
1290                                  &error, &error_len);
1291        if (unlikely(error))
1292        {
1293          ErrConvString err(error, error_len, res->charset());
1294          my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
1295          return true;
1296        }
1297      }
1298    }
1299    else
1300    {
1301      longlong tmp=var->value->val_int();
1302      if ((tmp < 0 && ! var->value->unsigned_flag)
1303          || (ulonglong)tmp > my_set_bits(typelib.count))
1304        return true;
1305      else
1306        var->save_result.ulonglong_value= tmp;
1307    }
1308
1309    return false;
1310  }
1311  bool session_update(THD *thd, set_var *var)
1312  {
1313    session_var(thd, ulonglong)= var->save_result.ulonglong_value;
1314    return false;
1315  }
1316  bool global_update(THD *thd, set_var *var)
1317  {
1318    global_var(ulonglong)= var->save_result.ulonglong_value;
1319    return false;
1320  }
1321  void session_save_default(THD *thd, set_var *var)
1322  { var->save_result.ulonglong_value= global_var(ulonglong); }
1323  void global_save_default(THD *thd, set_var *var)
1324  { var->save_result.ulonglong_value= option.def_value; }
1325  const uchar *valptr(THD *thd, ulonglong val) const
1326  { return (uchar*)flagset_to_string(thd, 0, val, typelib.type_names); }
1327  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
1328  { return valptr(thd, session_var(thd, ulonglong)); }
1329  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
1330  { return valptr(thd, global_var(ulonglong)); }
1331  const uchar *default_value_ptr(THD *thd) const
1332  { return valptr(thd, option.def_value); }
1333};
1334
1335/**
1336  The class for SET variables - variables taking zero or more values
1337  from the given list. Example: @@sql_mode
1338
1339  Class specific constructor arguments:
1340    char* values[]    - 0-terminated list of strings of valid values
1341
1342  Backing store: ulonglong
1343*/
1344class Sys_var_set: public Sys_var_typelib
1345{
1346public:
1347  Sys_var_set(const char *name_arg,
1348          const char *comment, int flag_args, ptrdiff_t off, size_t size,
1349          CMD_LINE getopt,
1350          const char *values[], ulonglong def_val, PolyLock *lock=0,
1351          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1352          on_check_function on_check_func=0,
1353          on_update_function on_update_func=0,
1354          const char *substitute=0)
1355    : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
1356                      SHOW_CHAR, values, def_val, lock,
1357                      binlog_status_arg, on_check_func, on_update_func,
1358                      substitute)
1359  {
1360    option.var_type|= GET_SET;
1361    option.min_value= 0;
1362    option.max_value= ~0ULL;
1363    global_var(ulonglong)= def_val;
1364    if ((option.u_max_value= (uchar**)max_var_ptr()))
1365    {
1366      *((ulonglong*) option.u_max_value)= ~0ULL;
1367    }
1368    SYSVAR_ASSERT(typelib.count > 0);
1369    SYSVAR_ASSERT(typelib.count <= 64);
1370    SYSVAR_ASSERT(def_val <= my_set_bits(typelib.count));
1371    SYSVAR_ASSERT(size == sizeof(ulonglong));
1372  }
1373  bool check_maximum(THD *thd, set_var *var,
1374                     const char *c_val, longlong i_val)
1375  {
1376    if (!max_var_ptr() ||
1377        (var->save_result.ulonglong_value & ~(get_max_var())) == 0)
1378      return FALSE;
1379    var->save_result.ulonglong_value&= get_max_var();
1380
1381    return c_val ? throw_bounds_warning(thd, name.str, c_val) :
1382                   throw_bounds_warning(thd, name.str, TRUE,
1383                                        var->value->unsigned_flag, i_val);
1384  }
1385  bool do_check(THD *thd, set_var *var)
1386  {
1387    char buff[STRING_BUFFER_USUAL_SIZE];
1388    String str(buff, sizeof(buff), system_charset_info), *res;
1389
1390    if (var->value->result_type() == STRING_RESULT)
1391    {
1392      char *error;
1393      uint error_len;
1394      bool not_used;
1395
1396      if (!(res= var->value->val_str_ascii_revert_empty_string_is_null(thd,
1397                                                                       &str)))
1398        return true;
1399
1400      var->save_result.ulonglong_value=
1401            find_set(&typelib, res->ptr(), res->length(), NULL,
1402                    &error, &error_len, &not_used);
1403      /*
1404        note, we only issue an error if error_len > 0.
1405        That is even while empty (zero-length) values are considered
1406        errors by find_set(), these errors are ignored here
1407      */
1408      if (error_len)
1409      {
1410        ErrConvString err(error, error_len, res->charset());
1411        my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
1412        return true;
1413      }
1414      return check_maximum(thd, var, res->ptr(), 0);
1415    }
1416
1417    longlong tmp=var->value->val_int();
1418    if ((tmp < 0 && ! var->value->unsigned_flag)
1419        || (ulonglong)tmp > my_set_bits(typelib.count))
1420      return true;
1421
1422    var->save_result.ulonglong_value= tmp;
1423    return check_maximum(thd, var, 0, tmp);
1424  }
1425  bool session_update(THD *thd, set_var *var)
1426  {
1427    session_var(thd, ulonglong)= var->save_result.ulonglong_value;
1428    return false;
1429  }
1430  bool global_update(THD *thd, set_var *var)
1431  {
1432    global_var(ulonglong)= var->save_result.ulonglong_value;
1433    return false;
1434  }
1435  void session_save_default(THD *thd, set_var *var)
1436  { var->save_result.ulonglong_value= global_var(ulonglong); }
1437  void global_save_default(THD *thd, set_var *var)
1438  { var->save_result.ulonglong_value= option.def_value; }
1439  const uchar *valptr(THD *thd, ulonglong val) const
1440  { return reinterpret_cast<const uchar*>(set_to_string(thd, 0, val, typelib.type_names)); }
1441  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
1442  { return valptr(thd, session_var(thd, ulonglong)); }
1443  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
1444  { return valptr(thd, global_var(ulonglong)); }
1445  const uchar *default_value_ptr(THD *thd) const
1446  { return valptr(thd, option.def_value); }
1447
1448  ulonglong get_max_var() { return *((ulonglong*) max_var_ptr()); }
1449};
1450
1451/**
1452  The class for variables which value is a plugin.
1453  Example: @@default_storage_engine
1454
1455  Class specific constructor arguments:
1456    int plugin_type_arg (for example MYSQL_STORAGE_ENGINE_PLUGIN)
1457
1458  Backing store: plugin_ref
1459
1460  @note
1461  these variables don't support command-line equivalents, any such
1462  command-line options should be added manually to my_long_options in mysqld.cc
1463*/
1464class Sys_var_plugin: public sys_var
1465{
1466  int plugin_type;
1467public:
1468  Sys_var_plugin(const char *name_arg,
1469          const char *comment, int flag_args, ptrdiff_t off, size_t size,
1470          CMD_LINE getopt,
1471          int plugin_type_arg, char **def_val, PolyLock *lock=0,
1472          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1473          on_check_function on_check_func=0,
1474          on_update_function on_update_func=0,
1475          const char *substitute=0)
1476    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
1477              getopt.arg_type, SHOW_CHAR, (intptr)def_val,
1478              lock, binlog_status_arg, on_check_func, on_update_func,
1479              substitute),
1480    plugin_type(plugin_type_arg)
1481  {
1482    option.var_type|= GET_STR;
1483    SYSVAR_ASSERT(size == sizeof(plugin_ref));
1484    SYSVAR_ASSERT(getopt.id < 0); // force NO_CMD_LINE
1485  }
1486  bool do_check(THD *thd, set_var *var)
1487  {
1488    char buff[STRING_BUFFER_USUAL_SIZE];
1489    String str(buff,sizeof(buff), system_charset_info), *res;
1490    if (!(res=var->value->val_str(&str)))
1491      var->save_result.plugin= NULL;
1492    else
1493    {
1494      const LEX_CSTRING pname= { const_cast<char*>(res->ptr()), res->length() };
1495      plugin_ref plugin;
1496
1497      // special code for storage engines (e.g. to handle historical aliases)
1498      if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
1499        plugin= ha_resolve_by_name(thd, &pname, false);
1500      else
1501        plugin= my_plugin_lock_by_name(thd, &pname, plugin_type);
1502      if (unlikely(!plugin))
1503      {
1504        // historically different error code
1505        if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
1506        {
1507          ErrConvString err(res);
1508          my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), err.ptr());
1509        }
1510        return true;
1511      }
1512      var->save_result.plugin= plugin;
1513    }
1514    return false;
1515  }
1516  void do_update(plugin_ref *valptr, plugin_ref newval)
1517  {
1518    plugin_ref oldval= *valptr;
1519    if (oldval != newval)
1520    {
1521      *valptr= newval ? my_plugin_lock(NULL, newval) : 0;
1522      plugin_unlock(NULL, oldval);
1523    }
1524  }
1525  bool session_update(THD *thd, set_var *var)
1526  {
1527    do_update((plugin_ref*)session_var_ptr(thd),
1528              var->save_result.plugin);
1529    return false;
1530  }
1531  bool global_update(THD *thd, set_var *var)
1532  {
1533    do_update((plugin_ref*)global_var_ptr(),
1534              var->save_result.plugin);
1535    return false;
1536  }
1537  void session_save_default(THD *thd, set_var *var)
1538  {
1539    plugin_ref plugin= global_var(plugin_ref);
1540    var->save_result.plugin= plugin ? my_plugin_lock(thd, plugin) : 0;
1541  }
1542  plugin_ref get_default(THD *thd) const
1543  {
1544    char *default_value= *reinterpret_cast<char**>(option.def_value);
1545    if (!default_value)
1546      return 0;
1547
1548    LEX_CSTRING pname= { default_value, strlen(default_value) };
1549    plugin_ref plugin;
1550
1551    if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
1552      plugin= ha_resolve_by_name(thd, &pname, false);
1553    else
1554      plugin= my_plugin_lock_by_name(thd, &pname, plugin_type);
1555    DBUG_ASSERT(plugin);
1556    return my_plugin_lock(thd, plugin);
1557  }
1558
1559  void global_save_default(THD *thd, set_var *var)
1560  {
1561    var->save_result.plugin= get_default(thd);
1562  }
1563
1564  uchar *valptr(THD *thd, plugin_ref plugin) const
1565  {
1566    return (uchar*)(plugin ? thd->strmake(plugin_name(plugin)->str,
1567                                          plugin_name(plugin)->length) : 0);
1568  }
1569  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
1570  { return valptr(thd, session_var(thd, plugin_ref)); }
1571  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
1572  { return valptr(thd, global_var(plugin_ref)); }
1573  const uchar *default_value_ptr(THD *thd) const
1574  { return valptr(thd, get_default(thd)); }
1575};
1576
1577/**
1578  Class for variables that containg a list of plugins.
1579  Currently this is used only for @@gtid_pos_auto_create_engines
1580
1581  Backing store: plugin_ref
1582
1583  @note
1584  Currently this is only used for storage engine type plugins, and thus only
1585  storage engine type plugin is implemented. It could be extended to other
1586  plugin types later if needed, similar to Sys_var_plugin.
1587
1588  These variables don't support command-line equivalents, any such
1589  command-line options should be added manually to my_long_options in mysqld.cc
1590
1591  Note on lifetimes of resources allocated: We allocate a zero-terminated array
1592  of plugin_ref*, and lock the contained plugins. The list in the global
1593  variable must be freed (with free_engine_list()). However, the way Sys_var
1594  works, there is no place to explicitly free other lists, like the one
1595  returned from get_default().
1596
1597  Therefore, the code needs to work with temporary lists, which are
1598  registered in the THD to be automatically freed (and plugins similarly
1599  automatically unlocked). This is why do_check() allocates a temporary
1600  list, from which do_update() then makes a permanent copy.
1601*/
1602class Sys_var_pluginlist: public sys_var
1603{
1604public:
1605  Sys_var_pluginlist(const char *name_arg,
1606          const char *comment, int flag_args, ptrdiff_t off, size_t size,
1607          CMD_LINE getopt,
1608          char **def_val, PolyLock *lock=0,
1609          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1610          on_check_function on_check_func=0,
1611          on_update_function on_update_func=0,
1612          const char *substitute=0)
1613    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
1614              getopt.arg_type, SHOW_CHAR, (intptr)def_val,
1615              lock, binlog_status_arg, on_check_func, on_update_func,
1616              substitute)
1617  {
1618    option.var_type|= GET_STR;
1619    SYSVAR_ASSERT(size == sizeof(plugin_ref));
1620    SYSVAR_ASSERT(getopt.id < 0); // force NO_CMD_LINE
1621  }
1622  bool do_check(THD *thd, set_var *var)
1623  {
1624    char buff[STRING_BUFFER_USUAL_SIZE];
1625    String str(buff,sizeof(buff), system_charset_info), *res;
1626    plugin_ref *plugins;
1627
1628    if (!(res=var->value->val_str(&str)))
1629      plugins= resolve_engine_list(thd, "", 0, true, true);
1630    else
1631      plugins= resolve_engine_list(thd, res->ptr(), res->length(), true, true);
1632    if (!plugins)
1633      return true;
1634    var->save_result.plugins= plugins;
1635    return false;
1636  }
1637  void do_update(plugin_ref **valptr, plugin_ref* newval)
1638  {
1639    plugin_ref *oldval= *valptr;
1640    *valptr= copy_engine_list(newval);
1641    free_engine_list(oldval);
1642  }
1643  bool session_update(THD *thd, set_var *var)
1644  {
1645    do_update((plugin_ref**)session_var_ptr(thd),
1646              var->save_result.plugins);
1647    return false;
1648  }
1649  bool global_update(THD *thd, set_var *var)
1650  {
1651    do_update((plugin_ref**)global_var_ptr(),
1652              var->save_result.plugins);
1653    return false;
1654  }
1655  void session_save_default(THD *thd, set_var *var)
1656  {
1657    plugin_ref* plugins= global_var(plugin_ref *);
1658    var->save_result.plugins= plugins ? temp_copy_engine_list(thd, plugins) : 0;
1659  }
1660  plugin_ref *get_default(THD *thd) const
1661  {
1662    char *default_value= *reinterpret_cast<char**>(option.def_value);
1663    if (!default_value)
1664      return 0;
1665    return resolve_engine_list(thd, default_value, strlen(default_value),
1666                               false, true);
1667  }
1668
1669  void global_save_default(THD *thd, set_var *var)
1670  {
1671    var->save_result.plugins= get_default(thd);
1672  }
1673
1674  uchar *valptr(THD *thd, plugin_ref *plugins) const
1675  {
1676    return reinterpret_cast<uchar*>(pretty_print_engine_list(thd, plugins));
1677  }
1678  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
1679  { return valptr(thd, session_var(thd, plugin_ref*)); }
1680  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
1681  { return valptr(thd, global_var(plugin_ref*)); }
1682  const uchar *default_value_ptr(THD *thd) const
1683  { return valptr(thd, get_default(thd)); }
1684};
1685
1686#if defined(ENABLED_DEBUG_SYNC)
1687
1688#include "debug_sync.h"
1689
1690/**
1691  The class for @@debug_sync session-only variable
1692*/
1693class Sys_var_debug_sync :public sys_var
1694{
1695public:
1696  Sys_var_debug_sync(const char *name_arg,
1697               const char *comment, int flag_args,
1698               CMD_LINE getopt,
1699               const char *def_val, PolyLock *lock=0,
1700               enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1701               on_check_function on_check_func=0,
1702               on_update_function on_update_func=0,
1703               const char *substitute=0)
1704    : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id,
1705              getopt.arg_type, SHOW_CHAR, (intptr)def_val,
1706              lock, binlog_status_arg, on_check_func, on_update_func,
1707              substitute)
1708  {
1709    SYSVAR_ASSERT(scope() == ONLY_SESSION);
1710    option.var_type|= GET_STR;
1711  }
1712  bool do_check(THD *thd, set_var *var)
1713  {
1714    char buff[STRING_BUFFER_USUAL_SIZE];
1715    String str(buff, sizeof(buff), system_charset_info), *res;
1716
1717    if (!(res=var->value->val_str(&str)))
1718      var->save_result.string_value= empty_lex_str;
1719    else
1720    {
1721      if (!thd->make_lex_string(&var->save_result.string_value,
1722                                res->ptr(), res->length()))
1723        return true;
1724    }
1725    return false;
1726  }
1727  bool session_update(THD *thd, set_var *var)
1728  {
1729    return debug_sync_update(thd, var->save_result.string_value.str,
1730                                  var->save_result.string_value.length);
1731  }
1732  bool global_update(THD *thd, set_var *var)
1733  {
1734    DBUG_ASSERT(FALSE);
1735    return true;
1736  }
1737  void session_save_default(THD *thd, set_var *var)
1738  {
1739    var->save_result.string_value.str= const_cast<char*>("");
1740    var->save_result.string_value.length= 0;
1741  }
1742  void global_save_default(THD *thd, set_var *var)
1743  {
1744    DBUG_ASSERT(FALSE);
1745  }
1746  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
1747  {
1748    return debug_sync_value_ptr(thd);
1749  }
1750  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
1751  {
1752    DBUG_ASSERT(FALSE);
1753    return 0;
1754  }
1755  const uchar *default_value_ptr(THD *thd) const
1756  { return (uchar*)""; }
1757};
1758#endif /* defined(ENABLED_DEBUG_SYNC) */
1759
1760
1761/**
1762  The class for bit variables - a variant of boolean that stores the value
1763  in a bit.
1764
1765  Class specific constructor arguments:
1766    ulonglong bitmask_arg - the mask for the bit to set in the ulonglong
1767                            backing store
1768
1769  Backing store: ulonglong
1770
1771  @note
1772  This class supports the "reverse" semantics, when the value of the bit
1773  being 0 corresponds to the value of variable being set. To activate it
1774  use REVERSE(bitmask) instead of simply bitmask in the constructor.
1775
1776  @note
1777  variables of this class cannot be set from the command line as
1778  my_getopt does not support bits.
1779*/
1780class Sys_var_bit: public Sys_var_typelib
1781{
1782  ulonglong bitmask;
1783  bool reverse_semantics;
1784  void set(uchar *ptr, ulonglong value)
1785  {
1786    if ((value != 0) ^ reverse_semantics)
1787      (*(ulonglong *)ptr)|= bitmask;
1788    else
1789      (*(ulonglong *)ptr)&= ~bitmask;
1790  }
1791public:
1792  Sys_var_bit(const char *name_arg,
1793          const char *comment, int flag_args, ptrdiff_t off, size_t size,
1794          CMD_LINE getopt,
1795          ulonglong bitmask_arg, my_bool def_val, PolyLock *lock=0,
1796          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
1797          on_check_function on_check_func=0,
1798          on_update_function on_update_func=0,
1799          const char *substitute=0)
1800    : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
1801                      SHOW_MY_BOOL, bool_values, def_val, lock,
1802                      binlog_status_arg, on_check_func, on_update_func,
1803                      substitute)
1804  {
1805    option.var_type|= GET_BIT;
1806    reverse_semantics= my_count_bits(bitmask_arg) > 1;
1807    bitmask= reverse_semantics ? ~bitmask_arg : bitmask_arg;
1808    option.block_size= reverse_semantics ? -(long) bitmask : (long)bitmask;
1809    set(global_var_ptr(), def_val);
1810    SYSVAR_ASSERT(def_val < 2);
1811    SYSVAR_ASSERT(size == sizeof(ulonglong));
1812  }
1813  bool session_update(THD *thd, set_var *var)
1814  {
1815    set(session_var_ptr(thd), var->save_result.ulonglong_value);
1816    return false;
1817  }
1818  bool global_update(THD *thd, set_var *var)
1819  {
1820    set(global_var_ptr(), var->save_result.ulonglong_value);
1821    return false;
1822  }
1823  void session_save_default(THD *thd, set_var *var)
1824  {
1825    var->save_result.ulonglong_value=
1826      (reverse_semantics == !(global_var(ulonglong) & bitmask));
1827  }
1828  void global_save_default(THD *thd, set_var *var)
1829  { var->save_result.ulonglong_value= option.def_value; }
1830
1831  uchar *valptr(THD *thd, ulonglong val) const
1832  {
1833    thd->sys_var_tmp.my_bool_value= (reverse_semantics == !(val & bitmask));
1834    return (uchar*) &thd->sys_var_tmp.my_bool_value;
1835  }
1836  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
1837  { return valptr(thd, session_var(thd, ulonglong)); }
1838  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
1839  { return valptr(thd, global_var(ulonglong)); }
1840  const uchar *default_value_ptr(THD *thd) const
1841  {
1842    thd->sys_var_tmp.my_bool_value= option.def_value != 0;
1843    return (uchar*) &thd->sys_var_tmp.my_bool_value;
1844  }
1845};
1846
1847/**
1848  The class for variables that have a special meaning for a session,
1849  such as @@timestamp or @@rnd_seed1, their values typically cannot be read
1850  from SV structure, and a special "read" callback is provided.
1851
1852  Class specific constructor arguments:
1853    everything derived from Sys_var_ulonglong
1854    session_special_read_function read_func_arg
1855
1856  Backing store: ulonglong
1857
1858  @note
1859  These variables are session-only, global or command-line equivalents
1860  are not supported as they're generally meaningless.
1861*/
1862class Sys_var_session_special: public Sys_var_ulonglong
1863{
1864  typedef bool (*session_special_update_function)(THD *thd, set_var *var);
1865  typedef ulonglong (*session_special_read_function)(THD *thd);
1866
1867  session_special_read_function read_func;
1868  session_special_update_function update_func;
1869public:
1870  Sys_var_session_special(const char *name_arg,
1871               const char *comment, int flag_args,
1872               CMD_LINE getopt,
1873               ulonglong min_val, ulonglong max_val, uint block_size,
1874               PolyLock *lock, enum binlog_status_enum binlog_status_arg,
1875               on_check_function on_check_func,
1876               session_special_update_function update_func_arg,
1877               session_special_read_function read_func_arg,
1878               const char *substitute=0)
1879    : Sys_var_ulonglong(name_arg, comment, flag_args, 0,
1880              sizeof(ulonglong), getopt, min_val,
1881              max_val, 0, block_size, lock, binlog_status_arg, on_check_func, 0,
1882              substitute),
1883      read_func(read_func_arg), update_func(update_func_arg)
1884  {
1885    SYSVAR_ASSERT(scope() == ONLY_SESSION);
1886    SYSVAR_ASSERT(getopt.id < 0); // NO_CMD_LINE, because the offset is fake
1887  }
1888  bool session_update(THD *thd, set_var *var)
1889  { return update_func(thd, var); }
1890  bool global_update(THD *thd, set_var *var)
1891  {
1892    DBUG_ASSERT(FALSE);
1893    return true;
1894  }
1895  void session_save_default(THD *thd, set_var *var)
1896  { var->value= 0; }
1897  void global_save_default(THD *thd, set_var *var)
1898  { DBUG_ASSERT(FALSE); }
1899  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
1900  {
1901    thd->sys_var_tmp.ulonglong_value= read_func(thd);
1902    return (uchar*) &thd->sys_var_tmp.ulonglong_value;
1903  }
1904  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
1905  {
1906    DBUG_ASSERT(FALSE);
1907    return 0;
1908  }
1909  const uchar *default_value_ptr(THD *thd) const
1910  {
1911    thd->sys_var_tmp.ulonglong_value= 0;
1912    return (uchar*) &thd->sys_var_tmp.ulonglong_value;
1913  }
1914};
1915
1916
1917/*
1918  Dedicated class because of a weird behavior of a default value.
1919  Assigning timestamp to itself
1920
1921    SET @@timestamp = @@timestamp
1922
1923  make it non-default and stops the time flow.
1924*/
1925class Sys_var_timestamp: public Sys_var_double
1926{
1927public:
1928  Sys_var_timestamp(const char *name_arg,
1929               const char *comment, int flag_args,
1930               CMD_LINE getopt,
1931               double min_val, double max_val,
1932               PolyLock *lock, enum binlog_status_enum binlog_status_arg,
1933               on_check_function on_check_func=0)
1934    : Sys_var_double(name_arg, comment, flag_args, 0,
1935              sizeof(double), getopt, min_val,
1936              max_val, 0, lock, binlog_status_arg, on_check_func)
1937  {
1938    SYSVAR_ASSERT(scope() == ONLY_SESSION);
1939    SYSVAR_ASSERT(getopt.id < 0); // NO_CMD_LINE, because the offset is fake
1940  }
1941  bool session_update(THD *thd, set_var *var)
1942  {
1943    if (var->value)
1944    {
1945      my_hrtime_t hrtime = { hrtime_from_time(var->save_result.double_value) };
1946      thd->set_time(hrtime);
1947    }
1948    else // SET timestamp=DEFAULT
1949      thd->user_time.val= 0;
1950    return false;
1951  }
1952  bool global_update(THD *thd, set_var *var)
1953  {
1954    DBUG_ASSERT(FALSE);
1955    return true;
1956  }
1957  bool session_is_default(THD *thd)
1958  {
1959    return thd->user_time.val == 0;
1960  }
1961  void session_save_default(THD *thd, set_var *var)
1962  { var->value= 0; }
1963  void global_save_default(THD *thd, set_var *var)
1964  { DBUG_ASSERT(FALSE); }
1965  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
1966  {
1967    thd->sys_var_tmp.double_value= thd->start_time +
1968          thd->start_time_sec_part/(double)TIME_SECOND_PART_FACTOR;
1969    return (uchar*) &thd->sys_var_tmp.double_value;
1970  }
1971  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
1972  {
1973    DBUG_ASSERT(FALSE);
1974    return 0;
1975  }
1976  const uchar *default_value_ptr(THD *thd) const
1977  {
1978    thd->sys_var_tmp.double_value= 0;
1979    return (uchar*) &thd->sys_var_tmp.double_value;
1980  }
1981};
1982
1983
1984/**
1985  The class for read-only variables that show whether a particular
1986  feature is supported by the server. Example: have_compression
1987
1988  Backing store: enum SHOW_COMP_OPTION
1989
1990  @note
1991  These variables are necessarily read-only, only global, and have no
1992  command-line equivalent.
1993*/
1994class Sys_var_have: public sys_var
1995{
1996public:
1997  Sys_var_have(const char *name_arg,
1998               const char *comment, int flag_args, ptrdiff_t off, size_t size,
1999               CMD_LINE getopt,
2000               PolyLock *lock=0,
2001               enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
2002               on_check_function on_check_func=0,
2003               on_update_function on_update_func=0,
2004               const char *substitute=0)
2005    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
2006              getopt.arg_type, SHOW_CHAR, 0,
2007              lock, binlog_status_arg, on_check_func, on_update_func,
2008              substitute)
2009  {
2010    SYSVAR_ASSERT(scope() == GLOBAL);
2011    SYSVAR_ASSERT(getopt.id < 0);
2012    SYSVAR_ASSERT(lock == 0);
2013    SYSVAR_ASSERT(binlog_status_arg == VARIABLE_NOT_IN_BINLOG);
2014    SYSVAR_ASSERT(is_readonly());
2015    SYSVAR_ASSERT(on_update == 0);
2016    SYSVAR_ASSERT(size == sizeof(enum SHOW_COMP_OPTION));
2017    option.var_type|= GET_STR;
2018  }
2019  bool do_check(THD *thd, set_var *var) {
2020    DBUG_ASSERT(FALSE);
2021    return true;
2022  }
2023  bool session_update(THD *thd, set_var *var)
2024  {
2025    DBUG_ASSERT(FALSE);
2026    return true;
2027  }
2028  bool global_update(THD *thd, set_var *var)
2029  {
2030    DBUG_ASSERT(FALSE);
2031    return true;
2032  }
2033  void session_save_default(THD *thd, set_var *var) { }
2034  void global_save_default(THD *thd, set_var *var) { }
2035  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
2036  {
2037    DBUG_ASSERT(FALSE);
2038    return 0;
2039  }
2040  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
2041  {
2042    return (uchar*)show_comp_option_name[global_var(enum SHOW_COMP_OPTION)];
2043  }
2044};
2045
2046/**
2047  Generic class for variables for storing entities that are internally
2048  represented as structures, have names, and possibly can be referred to by
2049  numbers.  Examples: character sets, collations, locales,
2050
2051  Class specific constructor arguments:
2052    ptrdiff_t name_offset  - offset of the 'name' field in the structure
2053
2054  Backing store: void*
2055
2056  @note
2057  As every such a structure requires special treatment from my_getopt,
2058  these variables don't support command-line equivalents, any such
2059  command-line options should be added manually to my_long_options in mysqld.cc
2060*/
2061class Sys_var_struct: public sys_var
2062{
2063  ptrdiff_t name_offset; // offset to the 'name' property in the structure
2064public:
2065  Sys_var_struct(const char *name_arg,
2066          const char *comment, int flag_args, ptrdiff_t off, size_t size,
2067          CMD_LINE getopt,
2068          ptrdiff_t name_off, void *def_val, PolyLock *lock=0,
2069          enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
2070          on_check_function on_check_func=0,
2071          on_update_function on_update_func=0,
2072          const char *substitute=0)
2073    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
2074              getopt.arg_type, SHOW_CHAR, (intptr)def_val,
2075              lock, binlog_status_arg, on_check_func, on_update_func,
2076              substitute),
2077      name_offset(name_off)
2078  {
2079    option.var_type|= GET_ENUM; // because we accept INT and STRING here
2080    /*
2081      struct variables are special on the command line - often (e.g. for
2082      charsets) the name cannot be immediately resolved, but only after all
2083      options (in particular, basedir) are parsed.
2084
2085      thus all struct command-line options should be added manually
2086      to my_long_options in mysqld.cc
2087    */
2088    SYSVAR_ASSERT(getopt.id < 0);
2089    SYSVAR_ASSERT(size == sizeof(void *));
2090  }
2091  bool do_check(THD *thd, set_var *var)
2092  { return false; }
2093  bool session_update(THD *thd, set_var *var)
2094  {
2095    session_var(thd, const void*)= var->save_result.ptr;
2096    return false;
2097  }
2098  bool global_update(THD *thd, set_var *var)
2099  {
2100    global_var(const void*)= var->save_result.ptr;
2101    return false;
2102  }
2103  void session_save_default(THD *thd, set_var *var)
2104  { var->save_result.ptr= global_var(void*); }
2105  void global_save_default(THD *thd, set_var *var)
2106  {
2107    void **default_value= reinterpret_cast<void**>(option.def_value);
2108    var->save_result.ptr= *default_value;
2109  }
2110  uchar *valptr(THD *thd, uchar *val) const
2111  { return val ? *(uchar**)(val+name_offset) : 0; }
2112  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
2113  { return valptr(thd, session_var(thd, uchar*)); }
2114  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
2115  { return valptr(thd, global_var(uchar*)); }
2116  const uchar *default_value_ptr(THD *thd) const
2117  { return valptr(thd, *(uchar**)option.def_value); }
2118};
2119
2120/**
2121  The class for variables that store time zones
2122
2123  Backing store: Time_zone*
2124
2125  @note
2126  Time zones cannot be supported directly by my_getopt, thus
2127  these variables don't support command-line equivalents, any such
2128  command-line options should be added manually to my_long_options in mysqld.cc
2129*/
2130class Sys_var_tz: public sys_var
2131{
2132public:
2133  Sys_var_tz(const char *name_arg,
2134             const char *comment, int flag_args, ptrdiff_t off, size_t size,
2135             CMD_LINE getopt,
2136             Time_zone **def_val, PolyLock *lock=0,
2137             enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
2138             on_check_function on_check_func=0,
2139             on_update_function on_update_func=0,
2140             const char *substitute=0)
2141    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
2142              getopt.arg_type, SHOW_CHAR, (intptr)def_val,
2143              lock, binlog_status_arg, on_check_func, on_update_func,
2144              substitute)
2145  {
2146    SYSVAR_ASSERT(getopt.id < 0);
2147    SYSVAR_ASSERT(size == sizeof(Time_zone *));
2148    option.var_type|= GET_STR;
2149  }
2150  bool do_check(THD *thd, set_var *var)
2151  {
2152    char buff[MAX_TIME_ZONE_NAME_LENGTH];
2153    String str(buff, sizeof(buff), &my_charset_latin1);
2154    String *res= var->value->val_str(&str);
2155
2156    if (!res)
2157      return true;
2158
2159    if (!(var->save_result.time_zone= my_tz_find(thd, res)))
2160    {
2161      ErrConvString err(res);
2162      my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), err.ptr());
2163      return true;
2164    }
2165    return false;
2166  }
2167  bool session_update(THD *thd, set_var *var)
2168  {
2169    session_var(thd, Time_zone*)= var->save_result.time_zone;
2170    return false;
2171  }
2172  bool global_update(THD *thd, set_var *var)
2173  {
2174    global_var(Time_zone*)= var->save_result.time_zone;
2175    return false;
2176  }
2177  void session_save_default(THD *thd, set_var *var)
2178  {
2179    var->save_result.time_zone= global_var(Time_zone*);
2180  }
2181  void global_save_default(THD *thd, set_var *var)
2182  {
2183    var->save_result.time_zone=
2184      *(Time_zone**)(intptr)option.def_value;
2185  }
2186  const uchar *valptr(THD *thd, Time_zone *val) const
2187  { return reinterpret_cast<const uchar*>(val->get_name()->ptr()); }
2188  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
2189  {
2190    /*
2191      This is an ugly fix for replication: we don't replicate properly queries
2192      invoking system variables' values to update tables; but
2193      CONVERT_TZ(,,@@session.time_zone) is so popular that we make it
2194      replicable (i.e. we tell the binlog code to store the session
2195      timezone). If it's the global value which was used we can't replicate
2196      (binlog code stores session value only).
2197    */
2198    thd->time_zone_used= 1;
2199    return valptr(thd, session_var(thd, Time_zone *));
2200  }
2201  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
2202  { return valptr(thd, global_var(Time_zone*)); }
2203  const uchar *default_value_ptr(THD *thd) const
2204  { return valptr(thd, *(Time_zone**)option.def_value); }
2205};
2206
2207/**
2208  Special implementation for transaction isolation, that
2209  distingushes between
2210
2211  SET GLOBAL TRANSACTION ISOLATION (stored in global_system_variables)
2212  SET SESSION TRANSACTION ISOLATION (stored in thd->variables)
2213  SET TRANSACTION ISOLATION (stored in thd->tx_isolation)
2214
2215  where the last statement sets isolation level for the next transaction only
2216*/
2217class Sys_var_tx_isolation: public Sys_var_enum
2218{
2219public:
2220  Sys_var_tx_isolation(const char *name_arg,
2221          const char *comment, int flag_args, ptrdiff_t off, size_t size,
2222          CMD_LINE getopt,
2223          const char *values[], uint def_val, PolyLock *lock,
2224          enum binlog_status_enum binlog_status_arg,
2225          on_check_function on_check_func)
2226    :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt,
2227                  values, def_val, lock, binlog_status_arg, on_check_func)
2228  {}
2229  bool session_update(THD *thd, set_var *var)
2230  {
2231    if (var->type == OPT_SESSION && Sys_var_enum::session_update(thd, var))
2232      return TRUE;
2233    if (var->type == OPT_DEFAULT || !thd->in_active_multi_stmt_transaction())
2234    {
2235      thd->tx_isolation= (enum_tx_isolation) var->save_result.ulonglong_value;
2236
2237#ifndef EMBEDDED_LIBRARY
2238      if (var->type == OPT_DEFAULT)
2239      {
2240        enum enum_tx_isol_level l;
2241        switch (thd->tx_isolation) {
2242        case ISO_READ_UNCOMMITTED:
2243          l=  TX_ISOL_UNCOMMITTED;
2244          break;
2245        case ISO_READ_COMMITTED:
2246          l=  TX_ISOL_COMMITTED;
2247          break;
2248        case ISO_REPEATABLE_READ:
2249          l= TX_ISOL_REPEATABLE;
2250          break;
2251        case ISO_SERIALIZABLE:
2252          l= TX_ISOL_SERIALIZABLE;
2253          break;
2254        default:
2255          DBUG_ASSERT(0);
2256          return TRUE;
2257        }
2258        if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
2259          thd->session_tracker.transaction_info.set_isol_level(thd, l);
2260      }
2261      else if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
2262        thd->session_tracker.transaction_info.set_isol_level(thd, TX_ISOL_INHERIT);
2263#endif //EMBEDDED_LIBRARY
2264    }
2265    return FALSE;
2266  }
2267};
2268
2269
2270/**
2271  Class representing the tx_read_only system variable for setting
2272  default transaction access mode.
2273
2274  Note that there is a special syntax - SET TRANSACTION READ ONLY
2275  (or READ WRITE) that sets the access mode for the next transaction
2276  only.
2277*/
2278
2279class Sys_var_tx_read_only: public Sys_var_mybool
2280{
2281public:
2282  Sys_var_tx_read_only(const char *name_arg, const char *comment, int flag_args,
2283                       ptrdiff_t off, size_t size, CMD_LINE getopt,
2284                       my_bool def_val, PolyLock *lock,
2285                       enum binlog_status_enum binlog_status_arg,
2286                       on_check_function on_check_func)
2287    :Sys_var_mybool(name_arg, comment, flag_args, off, size, getopt,
2288                    def_val, lock, binlog_status_arg, on_check_func)
2289  {}
2290  virtual bool session_update(THD *thd, set_var *var);
2291};
2292
2293/*
2294  Class for replicate_events_marked_for_skip.
2295  We need a custom update function that ensures the slave is stopped when
2296  the update is happening.
2297*/
2298class Sys_var_replicate_events_marked_for_skip: public Sys_var_enum
2299{
2300public:
2301  Sys_var_replicate_events_marked_for_skip(const char *name_arg,
2302          const char *comment, int flag_args, ptrdiff_t off, size_t size,
2303          CMD_LINE getopt,
2304          const char *values[], uint def_val, PolyLock *lock= 0,
2305          enum binlog_status_enum binlog_status_arg= VARIABLE_NOT_IN_BINLOG)
2306    :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt,
2307                  values, def_val, lock, binlog_status_arg)
2308  {}
2309  bool global_update(THD *thd, set_var *var);
2310};
2311
2312/*
2313  Class for handing multi-source replication variables
2314  Variable values are store in Master_info, but to make it possible to
2315  access variable without locks we also store it thd->variables.
2316  These can be used as GLOBAL or SESSION, but both points to the same
2317  variable.  This is to make things compatible with MySQL 5.5 where variables
2318  like sql_slave_skip_counter are GLOBAL.
2319*/
2320
2321#define MASTER_INFO_VAR(X) my_offsetof(Master_info, X), sizeof(((Master_info *)0x10)->X)
2322class Sys_var_multi_source_ulonglong;
2323class Master_info;
2324
2325typedef bool (*on_multi_source_update_function)(sys_var *self, THD *thd,
2326                                                Master_info *mi);
2327bool update_multi_source_variable(sys_var *self,
2328                                  THD *thd, enum_var_type type);
2329
2330
2331class Sys_var_multi_source_ulonglong :public Sys_var_ulonglong
2332{
2333  ptrdiff_t master_info_offset;
2334  on_multi_source_update_function update_multi_source_variable_func;
2335public:
2336  Sys_var_multi_source_ulonglong(const char *name_arg,
2337                             const char *comment, int flag_args,
2338                             ptrdiff_t off, size_t size,
2339                             CMD_LINE getopt,
2340                             ptrdiff_t master_info_offset_arg,
2341                             size_t master_info_arg_size,
2342                             ulonglong min_val, ulonglong max_val,
2343                             ulonglong def_val, uint block_size,
2344                             on_multi_source_update_function on_update_func)
2345    :Sys_var_ulonglong(name_arg, comment, flag_args, off, size,
2346                       getopt, min_val, max_val, def_val, block_size,
2347                       0, VARIABLE_NOT_IN_BINLOG, 0, update_multi_source_variable),
2348    master_info_offset(master_info_offset_arg),
2349    update_multi_source_variable_func(on_update_func)
2350  {
2351    SYSVAR_ASSERT(master_info_arg_size == size);
2352  }
2353  bool global_update(THD *thd, set_var *var)
2354  {
2355    return session_update(thd, var);
2356  }
2357  void session_save_default(THD *thd, set_var *var)
2358  {
2359    /* Use value given in variable declaration */
2360    global_save_default(thd, var);
2361  }
2362  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
2363  {
2364    ulonglong *tmp, res;
2365    tmp= (ulonglong*) (((uchar*)&(thd->variables)) + offset);
2366    res= get_master_info_ulonglong_value(thd, master_info_offset);
2367    *tmp= res;
2368    return (uchar*) tmp;
2369  }
2370  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
2371  {
2372    return session_value_ptr(thd, base);
2373  }
2374  ulonglong get_master_info_ulonglong_value(THD *thd, ptrdiff_t offset) const;
2375  bool update_variable(THD *thd, Master_info *mi)
2376  {
2377    return update_multi_source_variable_func(this, thd, mi);
2378  }
2379};
2380
2381
2382/**
2383  Class for @@global.gtid_current_pos.
2384*/
2385class Sys_var_gtid_current_pos: public sys_var
2386{
2387public:
2388  Sys_var_gtid_current_pos(const char *name_arg,
2389          const char *comment, int flag_args, ptrdiff_t off, size_t size,
2390          CMD_LINE getopt)
2391    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
2392              getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
2393              NULL, NULL, NULL)
2394  {
2395    SYSVAR_ASSERT(getopt.id < 0);
2396    SYSVAR_ASSERT(is_readonly());
2397    option.var_type|= GET_STR;
2398  }
2399  bool do_check(THD *thd, set_var *var)
2400  {
2401    DBUG_ASSERT(false);
2402    return true;
2403  }
2404  bool session_update(THD *thd, set_var *var)
2405  {
2406    DBUG_ASSERT(false);
2407    return true;
2408  }
2409  bool global_update(THD *thd, set_var *var)
2410  {
2411    DBUG_ASSERT(false);
2412    return true;
2413  }
2414  void session_save_default(THD *thd, set_var *var)
2415  {
2416    DBUG_ASSERT(false);
2417  }
2418  void global_save_default(THD *thd, set_var *var)
2419  {
2420    DBUG_ASSERT(false);
2421  }
2422  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
2423  {
2424    DBUG_ASSERT(false);
2425    return NULL;
2426  }
2427  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const;
2428};
2429
2430
2431/**
2432  Class for @@global.gtid_binlog_pos.
2433*/
2434class Sys_var_gtid_binlog_pos: public sys_var
2435{
2436public:
2437  Sys_var_gtid_binlog_pos(const char *name_arg,
2438          const char *comment, int flag_args, ptrdiff_t off, size_t size,
2439          CMD_LINE getopt)
2440    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
2441              getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
2442              NULL, NULL, NULL)
2443  {
2444    SYSVAR_ASSERT(getopt.id < 0);
2445    SYSVAR_ASSERT(is_readonly());
2446    option.var_type|= GET_STR;
2447  }
2448  bool do_check(THD *thd, set_var *var)
2449  {
2450    DBUG_ASSERT(false);
2451    return true;
2452  }
2453  bool session_update(THD *thd, set_var *var)
2454  {
2455    DBUG_ASSERT(false);
2456    return true;
2457  }
2458  bool global_update(THD *thd, set_var *var)
2459  {
2460    DBUG_ASSERT(false);
2461    return true;
2462  }
2463  void session_save_default(THD *thd, set_var *var)
2464  {
2465    DBUG_ASSERT(false);
2466  }
2467  void global_save_default(THD *thd, set_var *var)
2468  {
2469    DBUG_ASSERT(false);
2470  }
2471  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
2472  {
2473    DBUG_ASSERT(false);
2474    return NULL;
2475  }
2476  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const;
2477};
2478
2479
2480/**
2481  Class for @@global.gtid_slave_pos.
2482*/
2483class Sys_var_gtid_slave_pos: public sys_var
2484{
2485public:
2486  Sys_var_gtid_slave_pos(const char *name_arg,
2487          const char *comment, int flag_args, ptrdiff_t off, size_t size,
2488          CMD_LINE getopt)
2489    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
2490              getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
2491              NULL, NULL, NULL)
2492  {
2493    option.var_type|= GET_STR;
2494  }
2495  bool do_check(THD *thd, set_var *var);
2496  bool session_update(THD *thd, set_var *var)
2497  {
2498    DBUG_ASSERT(false);
2499    return true;
2500  }
2501  bool global_update(THD *thd, set_var *var);
2502  void session_save_default(THD *thd, set_var *var)
2503  {
2504    DBUG_ASSERT(false);
2505  }
2506  void global_save_default(THD *thd, set_var *var)
2507  {
2508    /* Record the attempt to use default so we can error. */
2509    var->value= 0;
2510  }
2511  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
2512  {
2513    DBUG_ASSERT(false);
2514    return NULL;
2515  }
2516  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const;
2517  const uchar *default_value_ptr(THD *thd) const
2518  { return 0; }
2519};
2520
2521
2522/**
2523  Class for @@global.gtid_binlog_state.
2524*/
2525class Sys_var_gtid_binlog_state: public sys_var
2526{
2527public:
2528  Sys_var_gtid_binlog_state(const char *name_arg,
2529          const char *comment, int flag_args, ptrdiff_t off, size_t size,
2530          CMD_LINE getopt)
2531    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
2532              getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
2533              NULL, NULL, NULL)
2534  {
2535    option.var_type|= GET_STR;
2536  }
2537  bool do_check(THD *thd, set_var *var);
2538  bool session_update(THD *thd, set_var *var)
2539  {
2540    DBUG_ASSERT(false);
2541    return true;
2542  }
2543  bool global_update(THD *thd, set_var *var);
2544  void session_save_default(THD *thd, set_var *var)
2545  {
2546    DBUG_ASSERT(false);
2547  }
2548  void global_save_default(THD *thd, set_var *var)
2549  {
2550    /* Record the attempt to use default so we can error. */
2551    var->value= 0;
2552  }
2553  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
2554  {
2555    DBUG_ASSERT(false);
2556    return NULL;
2557  }
2558  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const;
2559  const uchar *default_value_ptr(THD *thd) const
2560  { return 0; }
2561};
2562
2563
2564/**
2565  Class for @@session.last_gtid.
2566*/
2567class Sys_var_last_gtid: public sys_var
2568{
2569public:
2570  Sys_var_last_gtid(const char *name_arg,
2571          const char *comment, int flag_args, CMD_LINE getopt)
2572    : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id,
2573              getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
2574              NULL, NULL, NULL)
2575  {
2576    SYSVAR_ASSERT(getopt.id < 0);
2577    SYSVAR_ASSERT(is_readonly());
2578    option.var_type|= GET_STR;
2579  }
2580  bool do_check(THD *thd, set_var *var)
2581  {
2582    DBUG_ASSERT(false);
2583    return true;
2584  }
2585  bool session_update(THD *thd, set_var *var)
2586  {
2587    DBUG_ASSERT(false);
2588    return true;
2589  }
2590  bool global_update(THD *thd, set_var *var)
2591  {
2592    DBUG_ASSERT(false);
2593    return true;
2594  }
2595  void session_save_default(THD *thd, set_var *var)
2596  {
2597    DBUG_ASSERT(false);
2598  }
2599  void global_save_default(THD *thd, set_var *var)
2600  {
2601    DBUG_ASSERT(false);
2602  }
2603  const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const;
2604  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
2605  {
2606    DBUG_ASSERT(false);
2607    return NULL;
2608  }
2609};
2610
2611
2612/**
2613   Class for connection_name.slave_parallel_mode.
2614*/
2615class Sys_var_slave_parallel_mode: public Sys_var_enum
2616{
2617public:
2618  Sys_var_slave_parallel_mode(const char *name_arg,
2619          const char *comment, int flag_args, ptrdiff_t off, size_t size,
2620          CMD_LINE getopt, const char *values[],
2621          enum_slave_parallel_mode def_val)
2622    : Sys_var_enum(name_arg, comment, flag_args, off, size,
2623                   getopt, values, def_val)
2624  {
2625    option.var_type|= GET_ASK_ADDR;
2626    option.value= (uchar**)1; // crash me, please
2627    SYSVAR_ASSERT(scope() == GLOBAL);
2628  }
2629  bool global_update(THD *thd, set_var *var);
2630  const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const;
2631};
2632
2633
2634class Sys_var_vers_asof: public sys_var
2635{
2636public:
2637  Sys_var_vers_asof(const char *name_arg,
2638          const char *comment, int flag_args, ptrdiff_t off, size_t size,
2639          CMD_LINE getopt, uint def_val,
2640          PolyLock *lock= NO_MUTEX_GUARD,
2641          binlog_status_enum binlog_status_arg= VARIABLE_NOT_IN_BINLOG,
2642          on_check_function on_check_func= NULL,
2643          on_update_function on_update_func= NULL,
2644          const char *substitute= NULL)
2645    : sys_var(&all_sys_vars, name_arg, comment, flag_args, off,
2646              getopt.id, getopt.arg_type, SHOW_CHAR, def_val, lock,
2647              binlog_status_arg, on_check_func, on_update_func, substitute)
2648  {
2649    option.var_type= GET_STR;
2650  }
2651  virtual bool do_check(THD *thd, set_var *var)
2652  {
2653    if (!var->value)
2654      return false;
2655
2656    MYSQL_TIME ltime;
2657    bool res= var->value->get_date(&ltime,
2658                                   TIME_NO_ZERO_IN_DATE | TIME_NO_ZERO_DATE);
2659    if (!res)
2660    {
2661      uint error;
2662      var->save_result.timestamp.unix_time=
2663              thd->variables.time_zone->TIME_to_gmt_sec(&ltime, &error);
2664      var->save_result.timestamp.second_part= ltime.second_part;
2665      res= error != 0;
2666    }
2667    return res;
2668  }
2669
2670private:
2671  static bool update(THD *thd, set_var *var, vers_asof_timestamp_t *out)
2672  {
2673    if (var->value)
2674    {
2675      out->type       = SYSTEM_TIME_AS_OF;
2676      out->unix_time  = var->save_result.timestamp.unix_time;
2677      out->second_part= var->save_result.timestamp.second_part;
2678    }
2679    return 0;
2680  }
2681
2682  static void save_default(set_var *var, vers_asof_timestamp_t *out)
2683  {
2684    out->type= SYSTEM_TIME_UNSPECIFIED;
2685  }
2686
2687public:
2688  virtual bool global_update(THD *thd, set_var *var)
2689  {
2690    return update(thd, var, &global_var(vers_asof_timestamp_t));
2691  }
2692  virtual bool session_update(THD *thd, set_var *var)
2693  {
2694    return update(thd, var, &session_var(thd, vers_asof_timestamp_t));
2695  }
2696
2697  virtual bool session_is_default(THD *thd)
2698  {
2699    const vers_asof_timestamp_t &var= session_var(thd, vers_asof_timestamp_t);
2700    return var.type == SYSTEM_TIME_UNSPECIFIED;
2701  }
2702
2703  virtual void session_save_default(THD *thd, set_var *var)
2704  {
2705    save_default(var, &session_var(thd, vers_asof_timestamp_t));
2706  }
2707  virtual void global_save_default(THD *thd, set_var *var)
2708  {
2709    save_default(var, &global_var(vers_asof_timestamp_t));
2710  }
2711
2712private:
2713  const uchar *value_ptr(THD *thd, vers_asof_timestamp_t &val) const
2714  {
2715    const char *value;
2716    switch (val.type)
2717    {
2718    case SYSTEM_TIME_UNSPECIFIED:
2719      return (uchar*)"DEFAULT";
2720      break;
2721    case SYSTEM_TIME_AS_OF:
2722    {
2723      char *buf= (char*) thd->alloc(MAX_DATE_STRING_REP_LENGTH);
2724      MYSQL_TIME ltime;
2725
2726      thd->variables.time_zone->gmt_sec_to_TIME(&ltime, val.unix_time);
2727      ltime.second_part= val.second_part;
2728
2729      value= buf;
2730      if (buf && !my_datetime_to_str(&ltime, buf, 6))
2731      {
2732        my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, "NULL (wrong datetime)");
2733        value= thd->strdup("Error: wrong datetime");
2734      }
2735      break;
2736    }
2737    default:
2738      my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, "NULL (wrong range type)");
2739      value= thd->strdup("Error: wrong range type");
2740    }
2741    return reinterpret_cast<const uchar *>(value);
2742  }
2743
2744public:
2745  virtual const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
2746  { return value_ptr(thd, session_var(thd, vers_asof_timestamp_t)); }
2747  virtual const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
2748  { return value_ptr(thd, global_var(vers_asof_timestamp_t)); }
2749};
2750