summaryrefslogtreecommitdiffstats
path: root/sql/sys_vars.inl
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sys_vars.inl')
-rw-r--r--sql/sys_vars.inl2820
1 files changed, 2820 insertions, 0 deletions
diff --git a/sql/sys_vars.inl b/sql/sys_vars.inl
new file mode 100644
index 00000000..385ad897
--- /dev/null
+++ b/sql/sys_vars.inl
@@ -0,0 +1,2820 @@
+/* Copyright (c) 2002, 2011, Oracle and/or its affiliates.
+ Copyright (c) 2010, 2020, MariaDB Corporation.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
+
+/**
+ @file
+ "private" interface to sys_var - server configuration variables.
+
+ This header is included only by the file that contains declarations
+ of sys_var variables (sys_vars.cc).
+*/
+
+#include "sys_vars_shared.h"
+#include <my_getopt.h>
+#include <my_bit.h>
+#include <my_dir.h>
+#include "keycaches.h"
+#include "strfunc.h"
+#include "tztime.h" // my_tz_find, my_tz_SYSTEM, struct Time_zone
+#include "rpl_mi.h" // For Multi-Source Replication
+#include "debug_sync.h"
+#include "sql_acl.h" // check_global_access()
+
+/*
+ a set of mostly trivial (as in f(X)=X) defines below to make system variable
+ declarations more readable
+*/
+#define VALID_RANGE(X,Y) X,Y
+#define DEFAULT(X) X
+#define BLOCK_SIZE(X) X
+#define GLOBAL_VAR(X) sys_var::GLOBAL, (((char*)&(X))-(char*)&global_system_variables), sizeof(X)
+#define SESSION_VAR(X) sys_var::SESSION, offsetof(SV, X), sizeof(((SV *)0)->X)
+#define SESSION_ONLY(X) sys_var::ONLY_SESSION, offsetof(SV, X), sizeof(((SV *)0)->X)
+#define NO_CMD_LINE CMD_LINE(NO_ARG, sys_var::NO_GETOPT)
+#define CMD_LINE_HELP_ONLY CMD_LINE(NO_ARG, sys_var::GETOPT_ONLY_HELP)
+/*
+ the define below means that there's no *second* mutex guard,
+ LOCK_global_system_variables always guards all system variables
+*/
+#define NO_MUTEX_GUARD ((PolyLock*)0)
+#define IN_BINLOG sys_var::SESSION_VARIABLE_IN_BINLOG
+#define NOT_IN_BINLOG sys_var::VARIABLE_NOT_IN_BINLOG
+#define ON_READ(X) X
+#define ON_CHECK(X) X
+#define ON_UPDATE(X) X
+#define READ_ONLY sys_var::READONLY+
+#define AUTO_SET sys_var::AUTO_SET+
+// this means that Sys_var_charptr initial value was malloc()ed
+#define PREALLOCATED sys_var::ALLOCATED+
+#define PARSED_EARLY sys_var::PARSE_EARLY+
+#define NO_SET_STMT sys_var::NO_SET_STATEMENT+
+
+/*
+ Sys_var_bit meaning is reversed, like in
+ @@foreign_key_checks <-> OPTION_NO_FOREIGN_KEY_CHECKS
+*/
+#define REVERSE(X) ~(X)
+#define DEPRECATED(X) X
+
+#define session_var(THD, TYPE) (*(TYPE*)session_var_ptr(THD))
+#define global_var(TYPE) (*(TYPE*)global_var_ptr())
+
+#if SIZEOF_OFF_T > 4 && defined(BIG_TABLES)
+#define GET_HA_ROWS GET_ULL
+#else
+#define GET_HA_ROWS GET_ULONG
+#endif
+
+// Disable warning caused by SESSION_VAR() macro
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Winvalid-offsetof"
+#endif
+
+/*
+ special assert for sysvars. Tells the name of the variable,
+ and fails even in non-debug builds.
+
+ It is supposed to be used *only* in Sys_var* constructors,
+ and has name_arg hard-coded to prevent incorrect usage.
+*/
+#define SYSVAR_ASSERT(X) \
+ while(!(X)) \
+ { \
+ fprintf(stderr, "Sysvar '%s' failed '%s'\n", name_arg, #X); \
+ DBUG_ASSERT(0); \
+ exit(255); \
+ }
+
+
+static const char *bool_values[3]= {"OFF", "ON", 0};
+TYPELIB bool_typelib={ array_elements(bool_values)-1, "", bool_values, 0 };
+
+
+template<class BASE, privilege_t GLOBAL_PRIV, privilege_t SESSION_PRIV>
+class Sys_var_on_access: public BASE
+{
+ using BASE::BASE;
+ bool on_check_access_global(THD *thd) const override
+ {
+ return check_global_access(thd, GLOBAL_PRIV);
+ }
+ bool on_check_access_session(THD *thd) const override
+ {
+ return check_global_access(thd, SESSION_PRIV);
+ }
+};
+
+
+template<class BASE, privilege_t GLOBAL_PRIV>
+class Sys_var_on_access_global: public BASE
+{
+ using BASE::BASE;
+ bool on_check_access_global(THD *thd) const override
+ {
+ return check_global_access(thd, GLOBAL_PRIV);
+ }
+};
+
+
+template<class BASE, privilege_t SESSION_PRIV>
+class Sys_var_on_access_session: public BASE
+{
+ using BASE::BASE;
+ bool on_check_access_session(THD *thd) const override
+ {
+ return check_global_access(thd, SESSION_PRIV);
+ }
+};
+
+
+/**
+ A small wrapper class to pass getopt arguments as a pair
+ to the Sys_var_* constructors. It improves type safety and helps
+ to catch errors in the argument order.
+*/
+struct CMD_LINE
+{
+ int id;
+ enum get_opt_arg_type arg_type;
+ CMD_LINE(enum get_opt_arg_type getopt_arg_type, int getopt_id=0)
+ : id(getopt_id), arg_type(getopt_arg_type) {}
+};
+
+/**
+ Sys_var_integer template is used to generate Sys_var_* classes
+ for variables that represent the value as an integer number.
+ They are Sys_var_uint, Sys_var_ulong, Sys_var_harows, Sys_var_ulonglong,
+ Sys_var_int.
+
+ An integer variable has a minimal and maximal values, and a "block_size"
+ (any valid value of the variable must be divisible by the block_size).
+
+ Class specific constructor arguments: min, max, block_size
+ Backing store: int, uint, ulong, ha_rows, ulonglong, depending on the class
+*/
+template <typename T, ulong ARGT, enum enum_mysql_show_type SHOWT>
+class Sys_var_integer: public sys_var
+{
+public:
+ Sys_var_integer(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ T min_val, T max_val, T def_val, uint block_size, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOWT, def_val, lock, binlog_status_arg,
+ on_check_func, on_update_func, substitute)
+ {
+ option.var_type|= ARGT;
+ option.min_value= min_val;
+ option.max_value= max_val;
+ option.block_size= block_size;
+ if ((option.u_max_value= (uchar**) max_var_ptr()))
+ {
+ *((T*) option.u_max_value)= max_val;
+ }
+
+ global_var(T)= def_val;
+ SYSVAR_ASSERT(size == sizeof(T));
+ SYSVAR_ASSERT(min_val < max_val);
+ SYSVAR_ASSERT(min_val <= def_val);
+ SYSVAR_ASSERT(max_val >= def_val);
+ SYSVAR_ASSERT(block_size > 0);
+ SYSVAR_ASSERT(def_val % block_size == 0);
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ my_bool fixed= FALSE, unused;
+ longlong v= var->value->val_int();
+
+ if ((ARGT == GET_HA_ROWS) || (ARGT == GET_UINT) ||
+ (ARGT == GET_ULONG) || (ARGT == GET_ULL))
+ {
+ ulonglong uv;
+
+ /*
+ if the value is signed and negative,
+ and a variable is unsigned, it is set to zero
+ */
+ if ((fixed= (!var->value->unsigned_flag && v < 0)))
+ uv= 0;
+ else
+ uv= v;
+
+ var->save_result.ulonglong_value=
+ getopt_ull_limit_value(uv, &option, &unused);
+
+ if (max_var_ptr() && (T)var->save_result.ulonglong_value > get_max_var())
+ var->save_result.ulonglong_value= get_max_var();
+
+ fixed= fixed || var->save_result.ulonglong_value != uv;
+ }
+ else
+ {
+ /*
+ if the value is unsigned and has the highest bit set
+ and a variable is signed, it is set to max signed value
+ */
+ if ((fixed= (var->value->unsigned_flag && v < 0)))
+ v= LONGLONG_MAX;
+
+ var->save_result.longlong_value=
+ getopt_ll_limit_value(v, &option, &unused);
+
+ if (max_var_ptr() && (T)var->save_result.longlong_value > get_max_var())
+ var->save_result.longlong_value= get_max_var();
+
+ fixed= fixed || var->save_result.longlong_value != v;
+ }
+ return throw_bounds_warning(thd, name.str, fixed,
+ var->value->unsigned_flag, v);
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, T)= static_cast<T>(var->save_result.ulonglong_value);
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(T)= static_cast<T>(var->save_result.ulonglong_value);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= (ulonglong)*(T*)global_value_ptr(thd, 0); }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= option.def_value; }
+ private:
+ T get_max_var() { return *((T*) max_var_ptr()); }
+ const uchar *default_value_ptr(THD *thd) const { return (uchar*) &option.def_value; }
+};
+
+typedef Sys_var_integer<int, GET_INT, SHOW_SINT> Sys_var_int;
+typedef Sys_var_integer<uint, GET_UINT, SHOW_UINT> Sys_var_uint;
+typedef Sys_var_integer<ulong, GET_ULONG, SHOW_ULONG> Sys_var_ulong;
+typedef Sys_var_integer<ha_rows, GET_HA_ROWS, SHOW_HA_ROWS> Sys_var_harows;
+typedef Sys_var_integer<ulonglong, GET_ULL, SHOW_ULONGLONG> Sys_var_ulonglong;
+typedef Sys_var_integer<long, GET_LONG, SHOW_SLONG> Sys_var_long;
+
+
+template<> const uchar *Sys_var_int::default_value_ptr(THD *thd) const
+{
+ thd->sys_var_tmp.int_value= (int)option.def_value;
+ return (uchar*) &thd->sys_var_tmp.int_value;
+}
+
+template<> const uchar *Sys_var_uint::default_value_ptr(THD *thd) const
+{
+ thd->sys_var_tmp.uint_value= (uint)option.def_value;
+ return (uchar*) &thd->sys_var_tmp.uint_value;
+}
+
+template<> const uchar *Sys_var_long::default_value_ptr(THD *thd) const
+{
+ thd->sys_var_tmp.long_value= (long)option.def_value;
+ return (uchar*) &thd->sys_var_tmp.long_value;
+}
+
+template<> const uchar *Sys_var_ulong::default_value_ptr(THD *thd) const
+{
+ thd->sys_var_tmp.ulong_value= (ulong)option.def_value;
+ return (uchar*) &thd->sys_var_tmp.ulong_value;
+}
+
+
+/**
+ Helper class for variables that take values from a TYPELIB
+*/
+class Sys_var_typelib: public sys_var
+{
+protected:
+ TYPELIB typelib;
+ virtual bool check_maximum(THD *thd, set_var *var,
+ const char *c_val, longlong i_val)
+ { return FALSE; }
+public:
+ Sys_var_typelib(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off,
+ CMD_LINE getopt,
+ SHOW_TYPE show_val_type_arg, const char *values[],
+ ulonglong def_val, PolyLock *lock,
+ enum binlog_status_enum binlog_status_arg,
+ on_check_function on_check_func, on_update_function on_update_func,
+ const char *substitute)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, show_val_type_arg, def_val, lock,
+ binlog_status_arg, on_check_func,
+ on_update_func, substitute)
+ {
+ for (typelib.count= 0; values[typelib.count]; typelib.count++) /*no-op */;
+ typelib.name="";
+ typelib.type_names= values;
+ typelib.type_lengths= 0; // only used by Fields_enum and Field_set
+ option.typelib= &typelib;
+ }
+ bool do_check(THD *thd, set_var *var) // works for enums and my_bool
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), system_charset_info), *res;
+
+ if (var->value->result_type() == STRING_RESULT)
+ {
+ if (!(res=var->value->val_str(&str)))
+ return true;
+ else
+ if (!(var->save_result.ulonglong_value=
+ find_type(&typelib, res->ptr(), res->length(), false)))
+ return true;
+ else
+ var->save_result.ulonglong_value--;
+ return check_maximum(thd, var, res->ptr(), 0);
+ }
+
+ longlong tmp=var->value->val_int();
+ if (tmp < 0 || tmp >= typelib.count)
+ return true;
+ var->save_result.ulonglong_value= tmp;
+ return check_maximum(thd, var, 0, tmp);
+ }
+};
+
+/**
+ The class for ENUM variables - variables that take one value from a fixed
+ list of values.
+
+ Class specific constructor arguments:
+ char* values[] - 0-terminated list of strings of valid values
+
+ Backing store: ulong
+
+ @note
+ Do *not* use "enum FOO" variables as a backing store, there is no
+ guarantee that sizeof(enum FOO) == sizeof(uint), there is no guarantee
+ even that sizeof(enum FOO) == sizeof(enum BAR)
+*/
+class Sys_var_enum: public Sys_var_typelib
+{
+public:
+ Sys_var_enum(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ const char *values[], uint def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
+ SHOW_CHAR, values, def_val, lock,
+ binlog_status_arg, on_check_func, on_update_func,
+ substitute)
+ {
+ option.var_type|= GET_ENUM;
+ option.min_value= 0;
+ option.max_value= ULONG_MAX;
+ global_var(ulong)= def_val;
+ if ((option.u_max_value= (uchar**)max_var_ptr()))
+ {
+ *((ulong *) option.u_max_value)= ULONG_MAX;
+ }
+ SYSVAR_ASSERT(def_val < typelib.count);
+ SYSVAR_ASSERT(size == sizeof(ulong));
+ }
+ bool check_maximum(THD *thd, set_var *var,
+ const char *c_val, longlong i_val)
+ {
+ if (!max_var_ptr() ||
+ var->save_result.ulonglong_value <= get_max_var())
+ return FALSE;
+ var->save_result.ulonglong_value= get_max_var();
+
+ return c_val ? throw_bounds_warning(thd, name.str, c_val) :
+ throw_bounds_warning(thd, name.str, TRUE,
+ var->value->unsigned_flag, i_val);
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, ulong)= static_cast<ulong>(var->save_result.ulonglong_value);
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(ulong)= static_cast<ulong>(var->save_result.ulonglong_value);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= global_var(ulong); }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= option.def_value; }
+ const uchar *valptr(THD *thd, ulong val) const
+ { return reinterpret_cast<const uchar*>(typelib.type_names[val]); }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, session_var(thd, ulong)); }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, global_var(ulong)); }
+ const uchar *default_value_ptr(THD *thd) const
+ { return valptr(thd, (ulong)option.def_value); }
+
+ ulong get_max_var() { return *((ulong *) max_var_ptr()); }
+};
+
+/**
+ The class for boolean variables - a variant of ENUM variables
+ with the fixed list of values of { OFF , ON }
+
+ Backing store: my_bool
+*/
+class Sys_var_mybool: public Sys_var_typelib
+{
+public:
+ Sys_var_mybool(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ my_bool def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
+ SHOW_MY_BOOL, bool_values, def_val, lock,
+ binlog_status_arg, on_check_func, on_update_func,
+ substitute)
+ {
+ option.var_type|= GET_BOOL;
+ global_var(my_bool)= def_val;
+ SYSVAR_ASSERT(def_val < 2);
+ SYSVAR_ASSERT(getopt.arg_type == OPT_ARG || getopt.id < 0);
+ SYSVAR_ASSERT(size == sizeof(my_bool));
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, my_bool)= var->save_result.ulonglong_value != 0;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(my_bool)= var->save_result.ulonglong_value != 0;
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= (ulonglong)*(my_bool *)global_value_ptr(thd, 0); }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= option.def_value; }
+ const uchar *default_value_ptr(THD *thd) const
+ {
+ thd->sys_var_tmp.my_bool_value=(my_bool) option.def_value;
+ return (uchar*) &thd->sys_var_tmp.my_bool_value;
+ }
+};
+
+/**
+ The class for string variables. The string can be in character_set_filesystem
+ or in character_set_system. The string can be allocated with my_malloc()
+ or not. The state of the initial value is specified in the constructor,
+ after that it's managed automatically. The value of NULL is supported.
+
+ Backing store: char*
+
+ @note
+ This class supports only GLOBAL variables, because THD on destruction
+ does not destroy individual members of SV, there's no way to free
+ allocated string variables for every thread.
+*/
+class Sys_var_charptr_base: public sys_var
+{
+public:
+ Sys_var_charptr_base(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ const char *def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR_PTR, (intptr)def_val,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ substitute)
+ {
+ /*
+ use GET_STR_ALLOC - if ALLOCATED it must be *always* allocated,
+ otherwise (GET_STR) you'll never know whether to free it or not.
+ (think of an exit because of an error right after my_getopt)
+ */
+ option.var_type|= (flags & ALLOCATED) ? GET_STR_ALLOC : GET_STR;
+ global_var(const char*)= def_val;
+ }
+ void cleanup()
+ {
+ if (flags & ALLOCATED)
+ {
+ my_free(global_var(char*));
+ global_var(char *)= NULL;
+ }
+ flags&= ~ALLOCATED;
+ }
+ static bool do_string_check(THD *thd, set_var *var, CHARSET_INFO *charset)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE], buff2[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), charset);
+ String str2(buff2, sizeof(buff2), charset), *res;
+
+ if (!(res=var->value->val_str(&str)))
+ {
+ var->save_result.string_value.str= 0;
+ var->save_result.string_value.length= 0; // safety
+ }
+ else
+ {
+ uint32 unused;
+ if (String::needs_conversion(res->length(), res->charset(),
+ charset, &unused))
+ {
+ uint errors;
+ str2.copy(res->ptr(), res->length(), res->charset(), charset,
+ &errors);
+ res=&str2;
+
+ }
+ var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
+ var->save_result.string_value.length= res->length();
+ }
+
+ return false;
+ }
+ bool do_check(THD *thd, set_var *var)
+ { return do_string_check(thd, var, charset(thd)); }
+ bool session_update(THD *thd, set_var *var)= 0;
+ char *global_update_prepare(THD *thd, set_var *var)
+ {
+ char *new_val, *ptr= var->save_result.string_value.str;
+ size_t len=var->save_result.string_value.length;
+ if (ptr)
+ {
+ new_val= (char*)my_memdup(key_memory_Sys_var_charptr_value,
+ ptr, len+1, MYF(MY_WME));
+ if (!new_val) return 0;
+ new_val[len]=0;
+ }
+ else
+ new_val= 0;
+ return new_val;
+ }
+ void global_update_finish(char *new_val)
+ {
+ if (flags & ALLOCATED)
+ my_free(global_var(char*));
+ flags|= ALLOCATED;
+ global_var(char*)= new_val;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ char *new_val= global_update_prepare(thd, var);
+ global_update_finish(new_val);
+ return (new_val == 0 && var->save_result.string_value.str != 0);
+ }
+ void session_save_default(THD *thd, set_var *var)= 0;
+ void global_save_default(THD *thd, set_var *var)
+ {
+ char *ptr= (char*)(intptr)option.def_value;
+ var->save_result.string_value.str= ptr;
+ var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
+ }
+};
+
+class Sys_var_charptr: public Sys_var_charptr_base
+{
+public:
+ Sys_var_charptr(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ const char *def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0) :
+ Sys_var_charptr_base(name_arg, comment, flag_args, off, size, getopt,
+ def_val, lock, binlog_status_arg,
+ on_check_func, on_update_func, substitute)
+ {
+ SYSVAR_ASSERT(scope() == GLOBAL);
+ SYSVAR_ASSERT(size == sizeof(char *));
+ }
+
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { DBUG_ASSERT(FALSE); }
+};
+
+
+class Sys_var_charptr_fscs: public Sys_var_charptr
+{
+ using Sys_var_charptr::Sys_var_charptr;
+public:
+ CHARSET_INFO *charset(THD *thd) const override
+ {
+ return thd->variables.character_set_filesystem;
+ }
+};
+
+
+#ifndef EMBEDDED_LIBRARY
+class Sys_var_sesvartrack: public Sys_var_charptr_base
+{
+public:
+ Sys_var_sesvartrack(const char *name_arg,
+ const char *comment,
+ CMD_LINE getopt,
+ const char *def_val, PolyLock *lock= 0) :
+ Sys_var_charptr_base(name_arg, comment,
+ SESSION_VAR(session_track_system_variables),
+ getopt, def_val, lock,
+ VARIABLE_NOT_IN_BINLOG, 0, 0, 0)
+ {}
+ bool do_check(THD *thd, set_var *var)
+ {
+ if (Sys_var_charptr_base::do_check(thd, var) ||
+ sysvartrack_validate_value(thd, var->save_result.string_value.str,
+ var->save_result.string_value.length))
+ return TRUE;
+ return FALSE;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ char *new_val= global_update_prepare(thd, var);
+ if (new_val)
+ {
+ if (sysvartrack_global_update(thd, new_val,
+ var->save_result.string_value.length))
+ {
+ if (new_val)
+ my_free(new_val);
+ new_val= 0;
+ }
+ }
+ global_update_finish(new_val);
+ return (new_val == 0 && var->save_result.string_value.str != 0);
+ }
+ bool session_update(THD *thd, set_var *var)
+ { return thd->session_tracker.sysvars.update(thd, var); }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ var->save_result.string_value.str= global_var(char*);
+ var->save_result.string_value.length=
+ strlen(var->save_result.string_value.str);
+ /* parse and feel list with default values */
+ if (thd)
+ {
+#ifdef DBUG_ASSERT_EXISTS
+ bool res=
+#endif
+ sysvartrack_validate_value(thd,
+ var->save_result.string_value.str,
+ var->save_result.string_value.length);
+ DBUG_ASSERT(res == 0);
+ }
+ }
+};
+#endif //EMBEDDED_LIBRARY
+
+
+class Sys_var_proxy_user: public sys_var
+{
+public:
+ Sys_var_proxy_user(const char *name_arg, const char *comment)
+ : sys_var(&all_sys_vars, name_arg, comment,
+ sys_var::READONLY+sys_var::ONLY_SESSION, 0, NO_GETOPT,
+ NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
+ NULL, NULL, NULL)
+ {
+ option.var_type|= GET_STR;
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { DBUG_ASSERT(FALSE); }
+ void global_save_default(THD *thd, set_var *var)
+ { DBUG_ASSERT(FALSE); }
+protected:
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ return thd->security_ctx->proxy_user[0] ?
+ (uchar *) &(thd->security_ctx->proxy_user[0]) : NULL;
+ }
+};
+
+class Sys_var_external_user : public Sys_var_proxy_user
+{
+public:
+ Sys_var_external_user(const char *name_arg, const char *comment_arg)
+ : Sys_var_proxy_user (name_arg, comment_arg)
+ {}
+
+protected:
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ return (uchar*)thd->security_ctx->external_user;
+ }
+};
+
+class Master_info;
+class Sys_var_rpl_filter: public sys_var
+{
+private:
+ int opt_id;
+ privilege_t m_access_global;
+
+public:
+ Sys_var_rpl_filter(const char *name, int getopt_id, const char *comment,
+ privilege_t access_global)
+ : sys_var(&all_sys_vars, name, comment, sys_var::GLOBAL, 0, NO_GETOPT,
+ NO_ARG, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
+ NULL, NULL, NULL), opt_id(getopt_id),
+ m_access_global(access_global)
+ {
+ option.var_type|= GET_STR | GET_ASK_ADDR;
+ }
+
+ bool do_check(THD *thd, set_var *var) override
+ {
+ return Sys_var_charptr::do_string_check(thd, var, charset(thd));
+ }
+ void session_save_default(THD *, set_var *) override
+ { DBUG_ASSERT(FALSE); }
+
+ void global_save_default(THD *thd, set_var *var) override
+ {
+ char *ptr= (char*)(intptr)option.def_value;
+ var->save_result.string_value.str= ptr;
+ var->save_result.string_value.length= ptr ? strlen(ptr) : 0;
+ }
+
+ bool session_update(THD *, set_var *) override
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+
+ bool global_update(THD *thd, set_var *var) override;
+
+ bool on_check_access_global(THD *thd) const override
+ {
+ return check_global_access(thd, m_access_global);
+ }
+
+protected:
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base)
+ const override;
+ bool set_filter_value(const char *value, Master_info *mi);
+};
+
+/**
+ The class for string variables. Useful for strings that aren't necessarily
+ \0-terminated. Otherwise the same as Sys_var_charptr.
+
+ Backing store: LEX_CSTRING
+
+ @note
+ Behaves exactly as Sys_var_charptr, only the backing store is different.
+*/
+class Sys_var_lexstring: public Sys_var_charptr
+{
+public:
+ Sys_var_lexstring(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ const char *def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : Sys_var_charptr(name_arg, comment, flag_args, off, sizeof(char*),
+ getopt, def_val, lock, binlog_status_arg,
+ on_check_func, on_update_func, substitute)
+ {
+ global_var(LEX_CSTRING).length= strlen(def_val);
+ SYSVAR_ASSERT(size == sizeof(LEX_CSTRING));
+ *const_cast<SHOW_TYPE*>(&show_val_type)= SHOW_LEX_STRING;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ if (Sys_var_charptr::global_update(thd, var))
+ return true;
+ global_var(LEX_CSTRING).length= var->save_result.string_value.length;
+ return false;
+ }
+};
+
+
+/*
+ A LEX_CSTRING stored only in thd->variables
+ Only to be used for small buffers
+*/
+
+class Sys_var_session_lexstring: public sys_var
+{
+ size_t max_length;
+public:
+ Sys_var_session_lexstring(const char *name_arg,
+ const char *comment, int flag_args,
+ ptrdiff_t off, size_t size, CMD_LINE getopt,
+ const char *def_val, size_t max_length_arg,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, (intptr)def_val,
+ 0, VARIABLE_NOT_IN_BINLOG, on_check_func, on_update_func,
+ 0),max_length(max_length_arg)
+ {
+ option.var_type|= GET_STR;
+ SYSVAR_ASSERT(scope() == ONLY_SESSION)
+ *const_cast<SHOW_TYPE*>(&show_val_type)= SHOW_LEX_STRING;
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), system_charset_info), *res;
+
+ if (!(res=var->value->val_str(&str)))
+ {
+ var->save_result.string_value.str= 0; /* NULL */
+ var->save_result.string_value.length= 0;
+ }
+ else
+ {
+ if (res->length() > max_length)
+ {
+ my_error(ER_WRONG_STRING_LENGTH, MYF(0),
+ res->ptr(), name.str, (int) max_length);
+ return true;
+ }
+ var->save_result.string_value.str= thd->strmake(res->ptr(),
+ res->length());
+ var->save_result.string_value.length= res->length();
+ }
+ return false;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ LEX_CSTRING *tmp= &session_var(thd, LEX_CSTRING);
+ tmp->length= var->save_result.string_value.length;
+ /* Store as \0 terminated string (just to be safe) */
+ strmake((char*) tmp->str, var->save_result.string_value.str, tmp->length);
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ char *ptr= (char*)(intptr)option.def_value;
+ var->save_result.string_value.str= ptr;
+ var->save_result.string_value.length= strlen(ptr);
+ }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ DBUG_ASSERT(FALSE);
+ return NULL;
+ }
+};
+
+
+#ifndef DBUG_OFF
+/**
+ @@session.debug_dbug and @@global.debug_dbug variables.
+
+ @@dbug variable differs from other variables in one aspect:
+ if its value is not assigned in the session, it "points" to the global
+ value, and so when the global value is changed, the change
+ immediately takes effect in the session.
+
+ This semantics is intentional, to be able to debug one session from
+ another.
+*/
+class Sys_var_dbug: public sys_var
+{
+public:
+ Sys_var_dbug(const char *name_arg,
+ const char *comment, int flag_args,
+ CMD_LINE getopt,
+ const char *def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args,
+ (char*)&current_dbug_option-(char*)&global_system_variables, getopt.id,
+ getopt.arg_type, SHOW_CHAR, (intptr)def_val,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ substitute)
+ { option.var_type|= GET_STR; }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), system_charset_info), *res;
+
+ if (!(res=var->value->val_str(&str)))
+ {
+ var->save_result.string_value.str= const_cast<char*>("");
+ var->save_result.string_value.length= 0;
+ }
+ else
+ {
+ size_t len= res->length();
+ var->save_result.string_value.str= thd->strmake(res->ptr(), len);
+ var->save_result.string_value.length= len;
+ }
+ return false;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ const char *val= var->save_result.string_value.str;
+ if (!var->value)
+ DBUG_POP();
+ else
+ DBUG_SET(val);
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ const char *val= var->save_result.string_value.str;
+ DBUG_SET_INITIAL(val);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ char *ptr= (char*)(intptr)option.def_value;
+ var->save_result.string_value.str= ptr;
+ var->save_result.string_value.length= safe_strlen(ptr);
+ }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ char buf[256];
+ DBUG_EXPLAIN(buf, sizeof(buf));
+ return (uchar*) thd->strdup(buf);
+ }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ char buf[256];
+ DBUG_EXPLAIN_INITIAL(buf, sizeof(buf));
+ return (uchar*) thd->strdup(buf);
+ }
+ const uchar *default_value_ptr(THD *thd) const
+ { return (uchar*)""; }
+};
+#endif
+
+#define KEYCACHE_VAR(X) GLOBAL_VAR(dflt_key_cache_var.X)
+#define keycache_var_ptr(KC, OFF) (((uchar*)(KC))+(OFF))
+#define keycache_var(KC, OFF) (*(ulonglong*)keycache_var_ptr(KC, OFF))
+typedef bool (*keycache_update_function)(THD *, KEY_CACHE *, ptrdiff_t, ulonglong);
+
+/**
+ The class for keycache_* variables. Supports structured names,
+ keycache_name.variable_name.
+
+ Class specific constructor arguments:
+ everything derived from Sys_var_ulonglong
+
+ Backing store: ulonglong
+
+ @note these variables can be only GLOBAL
+*/
+class Sys_var_keycache: public Sys_var_ulonglong
+{
+ keycache_update_function keycache_update;
+public:
+ Sys_var_keycache(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ ulonglong min_val, ulonglong max_val, ulonglong def_val,
+ uint block_size, PolyLock *lock,
+ enum binlog_status_enum binlog_status_arg,
+ on_check_function on_check_func,
+ keycache_update_function on_update_func,
+ const char *substitute=0)
+ : Sys_var_ulonglong(name_arg, comment, flag_args, off, size,
+ getopt, min_val, max_val, def_val,
+ block_size, lock, binlog_status_arg, on_check_func, 0,
+ substitute),
+ keycache_update(on_update_func)
+ {
+ option.var_type|= GET_ASK_ADDR;
+ option.value= (uchar**)1; // crash me, please
+ // fix an offset from global_system_variables to be an offset in KEY_CACHE
+ offset= global_var_ptr() - (uchar*)dflt_key_cache;
+ SYSVAR_ASSERT(scope() == GLOBAL);
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ ulonglong new_value= var->save_result.ulonglong_value;
+ LEX_CSTRING *base_name= &var->base;
+ KEY_CACHE *key_cache;
+
+ /* If no basename, assume it's for the key cache named 'default' */
+ if (!base_name->length)
+ base_name= &default_key_cache_base;
+
+ key_cache= get_key_cache(base_name);
+
+ if (!key_cache)
+ { // Key cache didn't exists */
+ if (!new_value) // Tried to delete cache
+ return false; // Ok, nothing to do
+ if (!(key_cache= create_key_cache(base_name->str, base_name->length)))
+ return true;
+ }
+
+ /**
+ Abort if some other thread is changing the key cache
+ @todo This should be changed so that we wait until the previous
+ assignment is done and then do the new assign
+ */
+ if (key_cache->in_init)
+ return true;
+
+ return keycache_update(thd, key_cache, offset, new_value);
+ }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ KEY_CACHE *key_cache= get_key_cache(base);
+ if (!key_cache)
+ key_cache= &zero_key_cache;
+ return keycache_var_ptr(key_cache, offset);
+ }
+};
+
+static bool update_buffer_size(THD *thd, KEY_CACHE *key_cache,
+ ptrdiff_t offset, ulonglong new_value)
+{
+ bool error= false;
+ DBUG_ASSERT(offset == offsetof(KEY_CACHE, param_buff_size));
+
+ if (new_value == 0)
+ {
+ if (key_cache == dflt_key_cache)
+ {
+ my_error(ER_WARN_CANT_DROP_DEFAULT_KEYCACHE, MYF(0));
+ return true;
+ }
+
+ if (key_cache->key_cache_inited) // If initied
+ {
+ /*
+ Move tables using this key cache to the default key cache
+ and clear the old key cache.
+ */
+ key_cache->in_init= 1;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ key_cache->param_buff_size= 0;
+ ha_resize_key_cache(key_cache);
+ ha_change_key_cache(key_cache, dflt_key_cache);
+ /*
+ We don't delete the key cache as some running threads my still be in
+ the key cache code with a pointer to the deleted (empty) key cache
+ */
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ key_cache->in_init= 0;
+ }
+ return error;
+ }
+
+ key_cache->param_buff_size= new_value;
+
+ /* If key cache didn't exist initialize it, else resize it */
+ key_cache->in_init= 1;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+
+ if (!key_cache->key_cache_inited)
+ error= ha_init_key_cache(0, key_cache, 0);
+ else
+ error= ha_resize_key_cache(key_cache);
+
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ key_cache->in_init= 0;
+
+ return error;
+}
+
+static bool update_keycache(THD *thd, KEY_CACHE *key_cache,
+ ptrdiff_t offset, ulonglong new_value,
+ int (*func)(KEY_CACHE *))
+{
+ bool error= false;
+ DBUG_ASSERT(offset != offsetof(KEY_CACHE, param_buff_size));
+
+ keycache_var(key_cache, offset)= new_value;
+
+ key_cache->in_init= 1;
+ mysql_mutex_unlock(&LOCK_global_system_variables);
+ error= func(key_cache);
+ mysql_mutex_lock(&LOCK_global_system_variables);
+ key_cache->in_init= 0;
+
+ return error;
+}
+
+static bool resize_keycache(THD *thd, KEY_CACHE *key_cache,
+ ptrdiff_t offset, ulonglong new_value)
+{
+ return update_keycache(thd, key_cache, offset, new_value,
+ ha_resize_key_cache);
+}
+
+static bool change_keycache_param(THD *thd, KEY_CACHE *key_cache,
+ ptrdiff_t offset, ulonglong new_value)
+{
+ return update_keycache(thd, key_cache, offset, new_value,
+ ha_change_key_cache_param);
+}
+
+static bool repartition_keycache(THD *thd, KEY_CACHE *key_cache,
+ ptrdiff_t offset, ulonglong new_value)
+{
+ return update_keycache(thd, key_cache, offset, new_value,
+ ha_repartition_key_cache);
+}
+
+
+/**
+ The class for floating point variables
+
+ Class specific constructor arguments: min, max
+
+ Backing store: double
+*/
+class Sys_var_double: public sys_var
+{
+public:
+ Sys_var_double(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ double min_val, double max_val, double def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_DOUBLE,
+ (longlong) getopt_double2ulonglong(def_val),
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ substitute)
+ {
+ option.var_type|= GET_DOUBLE;
+ option.min_value= (longlong) getopt_double2ulonglong(min_val);
+ option.max_value= (longlong) getopt_double2ulonglong(max_val);
+ global_var(double)= (double)option.def_value;
+ SYSVAR_ASSERT(min_val < max_val);
+ SYSVAR_ASSERT(min_val <= def_val);
+ SYSVAR_ASSERT(max_val >= def_val);
+ SYSVAR_ASSERT(size == sizeof(double));
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ my_bool fixed;
+ double v= var->value->val_real();
+ var->save_result.double_value= getopt_double_limit_value(v, &option, &fixed);
+
+ return throw_bounds_warning(thd, name.str, fixed, v);
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, double)= var->save_result.double_value;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(double)= var->save_result.double_value;
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.double_value= global_var(double); }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.double_value= getopt_ulonglong2double(option.def_value); }
+};
+
+/**
+ The class for the @max_user_connections.
+ It's derived from Sys_var_uint, but non-standard session value
+ requires a new class.
+
+ Class specific constructor arguments:
+ everything derived from Sys_var_uint
+
+ Backing store: uint
+*/
+class Sys_var_max_user_conn: public Sys_var_int
+{
+public:
+ Sys_var_max_user_conn(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ int min_val, int max_val, int def_val,
+ uint block_size, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : Sys_var_int(name_arg, comment, SESSION, off, size, getopt,
+ min_val, max_val, def_val, block_size,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ substitute)
+ { }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ if (thd->user_connect && thd->user_connect->user_resources.user_conn)
+ return (uchar*) &(thd->user_connect->user_resources.user_conn);
+ return global_value_ptr(thd, base);
+ }
+};
+
+/**
+ The class for flagset variables - a variant of SET that allows in-place
+ editing (turning on/off individual bits). String representations looks like
+ a "flag=val,flag=val,...". Example: @@optimizer_switch
+
+ Class specific constructor arguments:
+ char* values[] - 0-terminated list of strings of valid values
+
+ Backing store: ulonglong
+
+ @note
+ the last value in the values[] array should
+ *always* be the string "default".
+*/
+class Sys_var_flagset: public Sys_var_typelib
+{
+public:
+ Sys_var_flagset(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ const char *values[], ulonglong def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
+ SHOW_CHAR, values, def_val, lock,
+ binlog_status_arg, on_check_func, on_update_func,
+ substitute)
+ {
+ option.var_type|= GET_FLAGSET;
+ global_var(ulonglong)= def_val;
+ SYSVAR_ASSERT(typelib.count > 1);
+ SYSVAR_ASSERT(typelib.count <= 65);
+ SYSVAR_ASSERT(def_val <= my_set_bits(typelib.count-1));
+ SYSVAR_ASSERT(strcmp(values[typelib.count-1], "default") == 0);
+ SYSVAR_ASSERT(size == sizeof(ulonglong));
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), system_charset_info), *res;
+ ulonglong default_value, current_value;
+ if (var->type == OPT_GLOBAL)
+ {
+ default_value= option.def_value;
+ current_value= global_var(ulonglong);
+ }
+ else
+ {
+ default_value= global_var(ulonglong);
+ current_value= session_var(thd, ulonglong);
+ }
+
+ if (var->value->result_type() == STRING_RESULT)
+ {
+ if (!(res=var->value->val_str(&str)))
+ return true;
+ else
+ {
+ char *error;
+ uint error_len;
+
+ var->save_result.ulonglong_value=
+ find_set_from_flags(&typelib,
+ typelib.count,
+ current_value,
+ default_value,
+ res->ptr(), res->length(),
+ &error, &error_len);
+ if (unlikely(error))
+ {
+ ErrConvString err(error, error_len, res->charset());
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
+ return true;
+ }
+ }
+ }
+ else
+ {
+ longlong tmp=var->value->val_int();
+ if ((tmp < 0 && ! var->value->unsigned_flag)
+ || (ulonglong)tmp > my_set_bits(typelib.count))
+ return true;
+ else
+ var->save_result.ulonglong_value= tmp;
+ }
+
+ return false;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, ulonglong)= var->save_result.ulonglong_value;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(ulonglong)= var->save_result.ulonglong_value;
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= global_var(ulonglong); }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= option.def_value; }
+ const uchar *valptr(THD *thd, ulonglong val) const
+ { return (uchar*)flagset_to_string(thd, 0, val, typelib.type_names); }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, session_var(thd, ulonglong)); }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, global_var(ulonglong)); }
+ const uchar *default_value_ptr(THD *thd) const
+ { return valptr(thd, option.def_value); }
+};
+
+/**
+ The class for SET variables - variables taking zero or more values
+ from the given list. Example: @@sql_mode
+
+ Class specific constructor arguments:
+ char* values[] - 0-terminated list of strings of valid values
+
+ Backing store: ulonglong
+*/
+
+static const LEX_CSTRING all_clex_str= {STRING_WITH_LEN("all")};
+
+
+class Sys_var_set: public Sys_var_typelib
+{
+public:
+ Sys_var_set(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ const char *values[], ulonglong def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
+ SHOW_CHAR, values, def_val, lock,
+ binlog_status_arg, on_check_func, on_update_func,
+ substitute)
+ {
+ option.var_type|= GET_SET;
+ option.min_value= 0;
+ option.max_value= ~0ULL;
+ global_var(ulonglong)= def_val;
+ if ((option.u_max_value= (uchar**)max_var_ptr()))
+ {
+ *((ulonglong*) option.u_max_value)= ~0ULL;
+ }
+ SYSVAR_ASSERT(typelib.count > 0);
+ SYSVAR_ASSERT(typelib.count <= 64);
+ SYSVAR_ASSERT(def_val <= my_set_bits(typelib.count));
+ SYSVAR_ASSERT(size == sizeof(ulonglong));
+ }
+ bool check_maximum(THD *thd, set_var *var,
+ const char *c_val, longlong i_val)
+ {
+ if (!max_var_ptr() ||
+ (var->save_result.ulonglong_value & ~(get_max_var())) == 0)
+ return FALSE;
+ var->save_result.ulonglong_value&= get_max_var();
+
+ return c_val ? throw_bounds_warning(thd, name.str, c_val) :
+ throw_bounds_warning(thd, name.str, TRUE,
+ var->value->unsigned_flag, i_val);
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), system_charset_info), *res;
+
+ if (var->value->result_type() == STRING_RESULT)
+ {
+ char *error;
+ uint error_len;
+ bool not_used;
+
+ if (!(res= var->value->val_str_ascii_revert_empty_string_is_null(thd,
+ &str)))
+ return true;
+
+ var->save_result.ulonglong_value=
+ find_set(&typelib, res->ptr(), res->length(), NULL,
+ &error, &error_len, &not_used);
+ if (error_len &&
+ !my_charset_latin1.strnncollsp(res->to_lex_cstring(), all_clex_str))
+ {
+ var->save_result.ulonglong_value= ((1ULL << (typelib.count)) -1);
+ error_len= 0;
+ }
+ /*
+ note, we only issue an error if error_len > 0.
+ That is even while empty (zero-length) values are considered
+ errors by find_set(), these errors are ignored here
+ */
+ if (error_len)
+ {
+ ErrConvString err(error, error_len, res->charset());
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, err.ptr());
+ return true;
+ }
+ return check_maximum(thd, var, res->ptr(), 0);
+ }
+
+ longlong tmp=var->value->val_int();
+ if ((tmp < 0 && ! var->value->unsigned_flag)
+ || (ulonglong)tmp > my_set_bits(typelib.count))
+ return true;
+
+ var->save_result.ulonglong_value= tmp;
+ return check_maximum(thd, var, 0, tmp);
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, ulonglong)= var->save_result.ulonglong_value;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(ulonglong)= var->save_result.ulonglong_value;
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= global_var(ulonglong); }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= option.def_value; }
+ const uchar *valptr(THD *thd, ulonglong val) const
+ { return reinterpret_cast<const uchar*>(set_to_string(thd, 0, val, typelib.type_names)); }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, session_var(thd, ulonglong)); }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, global_var(ulonglong)); }
+ const uchar *default_value_ptr(THD *thd) const
+ { return valptr(thd, option.def_value); }
+
+ ulonglong get_max_var() { return *((ulonglong*) max_var_ptr()); }
+};
+
+/**
+ The class for variables which value is a plugin.
+ Example: @@default_storage_engine
+
+ Class specific constructor arguments:
+ int plugin_type_arg (for example MYSQL_STORAGE_ENGINE_PLUGIN)
+
+ Backing store: plugin_ref
+
+ @note
+ these variables don't support command-line equivalents, any such
+ command-line options should be added manually to my_long_options in mysqld.cc
+*/
+class Sys_var_plugin: public sys_var
+{
+ int plugin_type;
+public:
+ Sys_var_plugin(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ int plugin_type_arg, char **def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, (intptr)def_val,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ substitute),
+ plugin_type(plugin_type_arg)
+ {
+ option.var_type|= GET_STR;
+ SYSVAR_ASSERT(size == sizeof(plugin_ref));
+ SYSVAR_ASSERT(getopt.id < 0); // force NO_CMD_LINE
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff,sizeof(buff), system_charset_info), *res;
+ if (!(res=var->value->val_str(&str)))
+ var->save_result.plugin= NULL;
+ else
+ {
+ const LEX_CSTRING pname= { const_cast<char*>(res->ptr()), res->length() };
+ plugin_ref plugin;
+
+ // special code for storage engines (e.g. to handle historical aliases)
+ if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
+ plugin= ha_resolve_by_name(thd, &pname, false);
+ else
+ plugin= my_plugin_lock_by_name(thd, &pname, plugin_type);
+ if (unlikely(!plugin))
+ {
+ // historically different error code
+ if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
+ {
+ ErrConvString err(res);
+ my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), err.ptr());
+ }
+ return true;
+ }
+ var->save_result.plugin= plugin;
+ }
+ return false;
+ }
+ void do_update(plugin_ref *valptr, plugin_ref newval)
+ {
+ plugin_ref oldval= *valptr;
+ if (oldval != newval)
+ {
+ *valptr= newval ? my_plugin_lock(NULL, newval) : 0;
+ plugin_unlock(NULL, oldval);
+ }
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ do_update((plugin_ref*)session_var_ptr(thd),
+ var->save_result.plugin);
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ do_update((plugin_ref*)global_var_ptr(),
+ var->save_result.plugin);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ plugin_ref plugin= global_var(plugin_ref);
+ var->save_result.plugin= plugin ? my_plugin_lock(thd, plugin) : 0;
+ }
+ plugin_ref get_default(THD *thd) const
+ {
+ char *default_value= *reinterpret_cast<char**>(option.def_value);
+ if (!default_value)
+ return 0;
+
+ LEX_CSTRING pname= { default_value, strlen(default_value) };
+ plugin_ref plugin;
+
+ if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN)
+ plugin= ha_resolve_by_name(thd, &pname, false);
+ else
+ plugin= my_plugin_lock_by_name(thd, &pname, plugin_type);
+ DBUG_ASSERT(plugin);
+ return my_plugin_lock(thd, plugin);
+ }
+
+ void global_save_default(THD *thd, set_var *var)
+ {
+ var->save_result.plugin= get_default(thd);
+ }
+
+ uchar *valptr(THD *thd, plugin_ref plugin) const
+ {
+ return (uchar*)(plugin ? thd->strmake(plugin_name(plugin)->str,
+ plugin_name(plugin)->length) : 0);
+ }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, session_var(thd, plugin_ref)); }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, global_var(plugin_ref)); }
+ const uchar *default_value_ptr(THD *thd) const
+ { return valptr(thd, get_default(thd)); }
+};
+
+/**
+ Class for variables that containg a list of plugins.
+ Currently this is used only for @@gtid_pos_auto_create_engines
+
+ Backing store: plugin_ref
+
+ @note
+ Currently this is only used for storage engine type plugins, and thus only
+ storage engine type plugin is implemented. It could be extended to other
+ plugin types later if needed, similar to Sys_var_plugin.
+
+ These variables don't support command-line equivalents, any such
+ command-line options should be added manually to my_long_options in mysqld.cc
+
+ Note on lifetimes of resources allocated: We allocate a zero-terminated array
+ of plugin_ref*, and lock the contained plugins. The list in the global
+ variable must be freed (with free_engine_list()). However, the way Sys_var
+ works, there is no place to explicitly free other lists, like the one
+ returned from get_default().
+
+ Therefore, the code needs to work with temporary lists, which are
+ registered in the THD to be automatically freed (and plugins similarly
+ automatically unlocked). This is why do_check() allocates a temporary
+ list, from which do_update() then makes a permanent copy.
+*/
+class Sys_var_pluginlist: public sys_var
+{
+public:
+ Sys_var_pluginlist(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ char **def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, (intptr)def_val,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ substitute)
+ {
+ option.var_type|= GET_STR;
+ SYSVAR_ASSERT(size == sizeof(plugin_ref));
+ SYSVAR_ASSERT(getopt.id < 0); // force NO_CMD_LINE
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff,sizeof(buff), system_charset_info), *res;
+ plugin_ref *plugins;
+
+ if (!(res=var->value->val_str(&str)))
+ plugins= resolve_engine_list(thd, "", 0, true, true);
+ else
+ plugins= resolve_engine_list(thd, res->ptr(), res->length(), true, true);
+ if (!plugins)
+ return true;
+ var->save_result.plugins= plugins;
+ return false;
+ }
+ void do_update(plugin_ref **valptr, plugin_ref* newval)
+ {
+ plugin_ref *oldval= *valptr;
+ *valptr= copy_engine_list(newval);
+ free_engine_list(oldval);
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ do_update((plugin_ref**)session_var_ptr(thd),
+ var->save_result.plugins);
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ do_update((plugin_ref**)global_var_ptr(),
+ var->save_result.plugins);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ plugin_ref* plugins= global_var(plugin_ref *);
+ var->save_result.plugins= plugins ? temp_copy_engine_list(thd, plugins) : 0;
+ }
+ plugin_ref *get_default(THD *thd) const
+ {
+ char *default_value= *reinterpret_cast<char**>(option.def_value);
+ if (!default_value)
+ return 0;
+ return resolve_engine_list(thd, default_value, strlen(default_value),
+ false, true);
+ }
+
+ void global_save_default(THD *thd, set_var *var)
+ {
+ var->save_result.plugins= get_default(thd);
+ }
+
+ uchar *valptr(THD *thd, plugin_ref *plugins) const
+ {
+ return reinterpret_cast<uchar*>(pretty_print_engine_list(thd, plugins));
+ }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, session_var(thd, plugin_ref*)); }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, global_var(plugin_ref*)); }
+ const uchar *default_value_ptr(THD *thd) const
+ { return valptr(thd, get_default(thd)); }
+};
+
+#if defined(ENABLED_DEBUG_SYNC)
+
+#include "debug_sync.h"
+
+/**
+ The class for @@debug_sync session-only variable
+*/
+class Sys_var_debug_sync :public sys_var
+{
+public:
+ Sys_var_debug_sync(const char *name_arg,
+ const char *comment, int flag_args,
+ CMD_LINE getopt,
+ const char *def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id,
+ getopt.arg_type, SHOW_CHAR, (intptr)def_val,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ substitute)
+ {
+ SYSVAR_ASSERT(scope() == ONLY_SESSION);
+ option.var_type|= GET_STR;
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[STRING_BUFFER_USUAL_SIZE];
+ String str(buff, sizeof(buff), system_charset_info), *res;
+
+ if (!(res=var->value->val_str(&str)))
+ var->save_result.string_value= empty_lex_str;
+ else
+ {
+ if (!thd->make_lex_string(&var->save_result.string_value,
+ res->ptr(), res->length()))
+ return true;
+ }
+ return false;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ return debug_sync_update(thd, var->save_result.string_value.str,
+ var->save_result.string_value.length);
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ var->save_result.string_value.str= const_cast<char*>("");
+ var->save_result.string_value.length= 0;
+ }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ return debug_sync_value_ptr(thd);
+ }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ DBUG_ASSERT(FALSE);
+ return 0;
+ }
+ const uchar *default_value_ptr(THD *thd) const
+ { return (uchar*)""; }
+};
+#endif /* defined(ENABLED_DEBUG_SYNC) */
+
+
+/**
+ The class for bit variables - a variant of boolean that stores the value
+ in a bit.
+
+ Class specific constructor arguments:
+ ulonglong bitmask_arg - the mask for the bit to set in the ulonglong
+ backing store
+
+ Backing store: ulonglong
+
+ @note
+ This class supports the "reverse" semantics, when the value of the bit
+ being 0 corresponds to the value of variable being set. To activate it
+ use REVERSE(bitmask) instead of simply bitmask in the constructor.
+
+ @note
+ variables of this class cannot be set from the command line as
+ my_getopt does not support bits.
+*/
+class Sys_var_bit: public Sys_var_typelib
+{
+ ulonglong bitmask;
+ bool reverse_semantics;
+ void set(uchar *ptr, ulonglong value)
+ {
+ if ((value != 0) ^ reverse_semantics)
+ (*(ulonglong *)ptr)|= bitmask;
+ else
+ (*(ulonglong *)ptr)&= ~bitmask;
+ }
+public:
+ Sys_var_bit(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ ulonglong bitmask_arg, my_bool def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : Sys_var_typelib(name_arg, comment, flag_args, off, getopt,
+ SHOW_MY_BOOL, bool_values, def_val, lock,
+ binlog_status_arg, on_check_func, on_update_func,
+ substitute)
+ {
+ option.var_type|= GET_BIT;
+ reverse_semantics= my_count_bits(bitmask_arg) > 1;
+ bitmask= reverse_semantics ? ~bitmask_arg : bitmask_arg;
+ option.block_size= reverse_semantics ? -(long) bitmask : (long)bitmask;
+ set(global_var_ptr(), def_val);
+ SYSVAR_ASSERT(def_val < 2);
+ SYSVAR_ASSERT(size == sizeof(ulonglong));
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ set(session_var_ptr(thd), var->save_result.ulonglong_value);
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ set(global_var_ptr(), var->save_result.ulonglong_value);
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ var->save_result.ulonglong_value=
+ (reverse_semantics == !(global_var(ulonglong) & bitmask));
+ }
+ void global_save_default(THD *thd, set_var *var)
+ { var->save_result.ulonglong_value= option.def_value; }
+
+ uchar *valptr(THD *thd, ulonglong val) const
+ {
+ thd->sys_var_tmp.my_bool_value= (reverse_semantics == !(val & bitmask));
+ return (uchar*) &thd->sys_var_tmp.my_bool_value;
+ }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, session_var(thd, ulonglong)); }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, global_var(ulonglong)); }
+ const uchar *default_value_ptr(THD *thd) const
+ {
+ thd->sys_var_tmp.my_bool_value= option.def_value != 0;
+ return (uchar*) &thd->sys_var_tmp.my_bool_value;
+ }
+};
+
+/**
+ The class for variables that have a special meaning for a session,
+ such as @@timestamp or @@rnd_seed1, their values typically cannot be read
+ from SV structure, and a special "read" callback is provided.
+
+ Class specific constructor arguments:
+ everything derived from Sys_var_ulonglong
+ session_special_read_function read_func_arg
+
+ Backing store: ulonglong
+
+ @note
+ These variables are session-only, global or command-line equivalents
+ are not supported as they're generally meaningless.
+*/
+class Sys_var_session_special: public Sys_var_ulonglong
+{
+ typedef bool (*session_special_update_function)(THD *thd, set_var *var);
+ typedef ulonglong (*session_special_read_function)(THD *thd);
+
+ session_special_read_function read_func;
+ session_special_update_function update_func;
+public:
+ Sys_var_session_special(const char *name_arg,
+ const char *comment, int flag_args,
+ CMD_LINE getopt,
+ ulonglong min_val, ulonglong max_val, uint block_size,
+ PolyLock *lock, enum binlog_status_enum binlog_status_arg,
+ on_check_function on_check_func,
+ session_special_update_function update_func_arg,
+ session_special_read_function read_func_arg,
+ const char *substitute=0)
+ : Sys_var_ulonglong(name_arg, comment, flag_args, 0,
+ sizeof(ulonglong), getopt, min_val,
+ max_val, 0, block_size, lock, binlog_status_arg, on_check_func, 0,
+ substitute),
+ read_func(read_func_arg), update_func(update_func_arg)
+ {
+ SYSVAR_ASSERT(scope() == ONLY_SESSION);
+ SYSVAR_ASSERT(getopt.id < 0); // NO_CMD_LINE, because the offset is fake
+ }
+ bool session_update(THD *thd, set_var *var)
+ { return update_func(thd, var); }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->value= 0; }
+ void global_save_default(THD *thd, set_var *var)
+ { DBUG_ASSERT(FALSE); }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ thd->sys_var_tmp.ulonglong_value= read_func(thd);
+ return (uchar*) &thd->sys_var_tmp.ulonglong_value;
+ }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ DBUG_ASSERT(FALSE);
+ return 0;
+ }
+ const uchar *default_value_ptr(THD *thd) const
+ {
+ thd->sys_var_tmp.ulonglong_value= 0;
+ return (uchar*) &thd->sys_var_tmp.ulonglong_value;
+ }
+};
+
+
+/*
+ Dedicated class because of a weird behavior of a default value.
+ Assigning timestamp to itself
+
+ SET @@timestamp = @@timestamp
+
+ make it non-default and stops the time flow.
+*/
+class Sys_var_timestamp: public Sys_var_double
+{
+public:
+ Sys_var_timestamp(const char *name_arg,
+ const char *comment, int flag_args,
+ CMD_LINE getopt,
+ double min_val, double max_val,
+ PolyLock *lock, enum binlog_status_enum binlog_status_arg,
+ on_check_function on_check_func=0)
+ : Sys_var_double(name_arg, comment, flag_args, 0,
+ sizeof(double), getopt, min_val,
+ max_val, 0, lock, binlog_status_arg, on_check_func)
+ {
+ SYSVAR_ASSERT(scope() == ONLY_SESSION);
+ SYSVAR_ASSERT(getopt.id < 0); // NO_CMD_LINE, because the offset is fake
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ if (var->value)
+ {
+ my_hrtime_t hrtime = { hrtime_from_time(var->save_result.double_value) };
+ thd->set_time(hrtime);
+ }
+ else // SET timestamp=DEFAULT
+ thd->user_time.val= 0;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ bool session_is_default(THD *thd)
+ {
+ return thd->user_time.val == 0;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->value= 0; }
+ void global_save_default(THD *thd, set_var *var)
+ { DBUG_ASSERT(FALSE); }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ thd->sys_var_tmp.double_value= thd->start_time +
+ thd->start_time_sec_part/(double)TIME_SECOND_PART_FACTOR;
+ return (uchar*) &thd->sys_var_tmp.double_value;
+ }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ DBUG_ASSERT(FALSE);
+ return 0;
+ }
+ const uchar *default_value_ptr(THD *thd) const
+ {
+ thd->sys_var_tmp.double_value= 0;
+ return (uchar*) &thd->sys_var_tmp.double_value;
+ }
+ bool on_check_access_session(THD *thd) const;
+};
+
+
+/**
+ The class for read-only variables that show whether a particular
+ feature is supported by the server. Example: have_compression
+
+ Backing store: enum SHOW_COMP_OPTION
+
+ @note
+ These variables are necessarily read-only, only global, and have no
+ command-line equivalent.
+*/
+class Sys_var_have: public sys_var
+{
+public:
+ Sys_var_have(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, 0,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ substitute)
+ {
+ SYSVAR_ASSERT(scope() == GLOBAL);
+ SYSVAR_ASSERT(getopt.id < 0);
+ SYSVAR_ASSERT(lock == 0);
+ SYSVAR_ASSERT(binlog_status_arg == VARIABLE_NOT_IN_BINLOG);
+ SYSVAR_ASSERT(is_readonly());
+ SYSVAR_ASSERT(on_update == 0);
+ SYSVAR_ASSERT(size == sizeof(enum SHOW_COMP_OPTION));
+ option.var_type|= GET_STR;
+ }
+ bool do_check(THD *thd, set_var *var) {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(FALSE);
+ return true;
+ }
+ void session_save_default(THD *thd, set_var *var) { }
+ void global_save_default(THD *thd, set_var *var) { }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ DBUG_ASSERT(FALSE);
+ return 0;
+ }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ return (uchar*)show_comp_option_name[global_var(enum SHOW_COMP_OPTION)];
+ }
+};
+
+/**
+ Generic class for variables for storing entities that are internally
+ represented as structures, have names, and possibly can be referred to by
+ numbers. Examples: character sets, collations, locales,
+
+ Class specific constructor arguments:
+ ptrdiff_t name_offset - offset of the 'name' field in the structure
+
+ Backing store: void*
+
+ @note
+ As every such a structure requires special treatment from my_getopt,
+ these variables don't support command-line equivalents, any such
+ command-line options should be added manually to my_long_options in mysqld.cc
+*/
+class Sys_var_struct: public sys_var
+{
+ ptrdiff_t name_offset; // offset to the 'name' property in the structure
+public:
+ Sys_var_struct(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ ptrdiff_t name_off, void *def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, (intptr)def_val,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ substitute),
+ name_offset(name_off)
+ {
+ option.var_type|= GET_ENUM; // because we accept INT and STRING here
+ /*
+ struct variables are special on the command line - often (e.g. for
+ charsets) the name cannot be immediately resolved, but only after all
+ options (in particular, basedir) are parsed.
+
+ thus all struct command-line options should be added manually
+ to my_long_options in mysqld.cc
+ */
+ SYSVAR_ASSERT(getopt.id < 0);
+ SYSVAR_ASSERT(size == sizeof(void *));
+ }
+ bool do_check(THD *thd, set_var *var)
+ { return false; }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, const void*)= var->save_result.ptr;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(const void*)= var->save_result.ptr;
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ { var->save_result.ptr= global_var(void*); }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ void **default_value= reinterpret_cast<void**>(option.def_value);
+ var->save_result.ptr= *default_value;
+ }
+ uchar *valptr(THD *thd, uchar *val) const
+ { return val ? *(uchar**)(val+name_offset) : 0; }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, session_var(thd, uchar*)); }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, global_var(uchar*)); }
+ const uchar *default_value_ptr(THD *thd) const
+ { return valptr(thd, *(uchar**)option.def_value); }
+};
+
+/**
+ The class for variables that store time zones
+
+ Backing store: Time_zone*
+
+ @note
+ Time zones cannot be supported directly by my_getopt, thus
+ these variables don't support command-line equivalents, any such
+ command-line options should be added manually to my_long_options in mysqld.cc
+*/
+class Sys_var_tz: public sys_var
+{
+public:
+ Sys_var_tz(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ Time_zone **def_val, PolyLock *lock=0,
+ enum binlog_status_enum binlog_status_arg=VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func=0,
+ on_update_function on_update_func=0,
+ const char *substitute=0)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, (intptr)def_val,
+ lock, binlog_status_arg, on_check_func, on_update_func,
+ substitute)
+ {
+ SYSVAR_ASSERT(getopt.id < 0);
+ SYSVAR_ASSERT(size == sizeof(Time_zone *));
+ option.var_type|= GET_STR;
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ char buff[MAX_TIME_ZONE_NAME_LENGTH];
+ String str(buff, sizeof(buff), &my_charset_latin1);
+ String *res= var->value->val_str(&str);
+
+ if (!res)
+ return true;
+
+ if (!(var->save_result.time_zone= my_tz_find(thd, res)))
+ {
+ ErrConvString err(res);
+ my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), err.ptr());
+ return true;
+ }
+ return false;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ session_var(thd, Time_zone*)= var->save_result.time_zone;
+ return false;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ global_var(Time_zone*)= var->save_result.time_zone;
+ return false;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ var->save_result.time_zone= global_var(Time_zone*);
+ }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ var->save_result.time_zone=
+ *(Time_zone**)(intptr)option.def_value;
+ }
+ const uchar *valptr(THD *thd, Time_zone *val) const
+ { return reinterpret_cast<const uchar*>(val->get_name()->ptr()); }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ /*
+ This is an ugly fix for replication: we don't replicate properly queries
+ invoking system variables' values to update tables; but
+ CONVERT_TZ(,,@@session.time_zone) is so popular that we make it
+ replicable (i.e. we tell the binlog code to store the session
+ timezone). If it's the global value which was used we can't replicate
+ (binlog code stores session value only).
+ */
+ thd->used|= THD::TIME_ZONE_USED;
+ return valptr(thd, session_var(thd, Time_zone *));
+ }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return valptr(thd, global_var(Time_zone*)); }
+ const uchar *default_value_ptr(THD *thd) const
+ { return valptr(thd, *(Time_zone**)option.def_value); }
+};
+
+/**
+ Special implementation for transaction isolation, that
+ distingushes between
+
+ SET GLOBAL TRANSACTION ISOLATION (stored in global_system_variables)
+ SET SESSION TRANSACTION ISOLATION (stored in thd->variables)
+ SET TRANSACTION ISOLATION (stored in thd->tx_isolation)
+
+ where the last statement sets isolation level for the next transaction only
+*/
+class Sys_var_tx_isolation: public Sys_var_enum
+{
+public:
+ Sys_var_tx_isolation(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ const char *values[], uint def_val, PolyLock *lock,
+ enum binlog_status_enum binlog_status_arg,
+ on_check_function on_check_func)
+ :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt,
+ values, def_val, lock, binlog_status_arg, on_check_func)
+ {}
+ bool session_update(THD *thd, set_var *var)
+ {
+ if (var->type == OPT_SESSION && Sys_var_enum::session_update(thd, var))
+ return TRUE;
+ if (var->type == OPT_DEFAULT || !thd->in_active_multi_stmt_transaction())
+ {
+ thd->tx_isolation= (enum_tx_isolation) var->save_result.ulonglong_value;
+
+#ifndef EMBEDDED_LIBRARY
+ if (var->type == OPT_DEFAULT)
+ {
+ enum enum_tx_isol_level l;
+ switch (thd->tx_isolation) {
+ case ISO_READ_UNCOMMITTED:
+ l= TX_ISOL_UNCOMMITTED;
+ break;
+ case ISO_READ_COMMITTED:
+ l= TX_ISOL_COMMITTED;
+ break;
+ case ISO_REPEATABLE_READ:
+ l= TX_ISOL_REPEATABLE;
+ break;
+ case ISO_SERIALIZABLE:
+ l= TX_ISOL_SERIALIZABLE;
+ break;
+ default:
+ DBUG_ASSERT(0);
+ return TRUE;
+ }
+ if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
+ thd->session_tracker.transaction_info.set_isol_level(thd, l);
+ }
+ else if (thd->variables.session_track_transaction_info > TX_TRACK_NONE)
+ thd->session_tracker.transaction_info.set_isol_level(thd, TX_ISOL_INHERIT);
+#endif //EMBEDDED_LIBRARY
+ }
+ return FALSE;
+ }
+};
+
+
+/**
+ Class representing the tx_read_only system variable for setting
+ default transaction access mode.
+
+ Note that there is a special syntax - SET TRANSACTION READ ONLY
+ (or READ WRITE) that sets the access mode for the next transaction
+ only.
+*/
+
+class Sys_var_tx_read_only: public Sys_var_mybool
+{
+public:
+ Sys_var_tx_read_only(const char *name_arg, const char *comment, int flag_args,
+ ptrdiff_t off, size_t size, CMD_LINE getopt,
+ my_bool def_val, PolyLock *lock,
+ enum binlog_status_enum binlog_status_arg,
+ on_check_function on_check_func)
+ :Sys_var_mybool(name_arg, comment, flag_args, off, size, getopt,
+ def_val, lock, binlog_status_arg, on_check_func)
+ {}
+ virtual bool session_update(THD *thd, set_var *var);
+};
+
+/*
+ Class for replicate_events_marked_for_skip.
+ We need a custom update function that ensures the slave is stopped when
+ the update is happening.
+*/
+class Sys_var_replicate_events_marked_for_skip: public Sys_var_enum
+{
+public:
+ Sys_var_replicate_events_marked_for_skip(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ const char *values[], uint def_val, PolyLock *lock= 0,
+ enum binlog_status_enum binlog_status_arg= VARIABLE_NOT_IN_BINLOG)
+ :Sys_var_enum(name_arg, comment, flag_args, off, size, getopt,
+ values, def_val, lock, binlog_status_arg)
+ {}
+ bool global_update(THD *thd, set_var *var);
+};
+
+/*
+ Class for handing multi-source replication variables
+ Variable values are store in Master_info, but to make it possible to
+ access variable without locks we also store it thd->variables.
+ These can be used as GLOBAL or SESSION, but both points to the same
+ variable. This is to make things compatible with MySQL 5.5 where variables
+ like sql_slave_skip_counter are GLOBAL.
+*/
+
+#define MASTER_INFO_VAR(X) my_offsetof(Master_info, X), sizeof(((Master_info *)0x10)->X)
+class Sys_var_multi_source_ulonglong;
+class Master_info;
+
+typedef bool (*on_multi_source_update_function)(sys_var *self, THD *thd,
+ Master_info *mi);
+bool update_multi_source_variable(sys_var *self,
+ THD *thd, enum_var_type type);
+
+
+class Sys_var_multi_source_ulonglong :public Sys_var_ulonglong
+{
+ ptrdiff_t master_info_offset;
+ on_multi_source_update_function update_multi_source_variable_func;
+public:
+ Sys_var_multi_source_ulonglong(const char *name_arg,
+ const char *comment, int flag_args,
+ ptrdiff_t off, size_t size,
+ CMD_LINE getopt,
+ ptrdiff_t master_info_offset_arg,
+ size_t master_info_arg_size,
+ ulonglong min_val, ulonglong max_val,
+ ulonglong def_val, uint block_size,
+ on_multi_source_update_function on_update_func)
+ :Sys_var_ulonglong(name_arg, comment, flag_args, off, size,
+ getopt, min_val, max_val, def_val, block_size,
+ 0, VARIABLE_NOT_IN_BINLOG, 0, update_multi_source_variable),
+ master_info_offset(master_info_offset_arg),
+ update_multi_source_variable_func(on_update_func)
+ {
+ SYSVAR_ASSERT(master_info_arg_size == size);
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ return session_update(thd, var);
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ /* Use value given in variable declaration */
+ global_save_default(thd, var);
+ }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ ulonglong *tmp, res;
+ tmp= (ulonglong*) (((uchar*)&(thd->variables)) + offset);
+ res= get_master_info_ulonglong_value(thd, master_info_offset);
+ *tmp= res;
+ return (uchar*) tmp;
+ }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ return session_value_ptr(thd, base);
+ }
+ ulonglong get_master_info_ulonglong_value(THD *thd, ptrdiff_t offset) const;
+ bool update_variable(THD *thd, Master_info *mi)
+ {
+ return update_multi_source_variable_func(this, thd, mi);
+ }
+};
+
+
+/**
+ Class for @@global.gtid_current_pos.
+*/
+class Sys_var_gtid_current_pos: public sys_var
+{
+public:
+ Sys_var_gtid_current_pos(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
+ NULL, NULL, NULL)
+ {
+ SYSVAR_ASSERT(getopt.id < 0);
+ SYSVAR_ASSERT(is_readonly());
+ option.var_type|= GET_STR;
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ DBUG_ASSERT(false);
+ return NULL;
+ }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const;
+};
+
+
+/**
+ Class for @@global.gtid_binlog_pos.
+*/
+class Sys_var_gtid_binlog_pos: public sys_var
+{
+public:
+ Sys_var_gtid_binlog_pos(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
+ NULL, NULL, NULL)
+ {
+ SYSVAR_ASSERT(getopt.id < 0);
+ SYSVAR_ASSERT(is_readonly());
+ option.var_type|= GET_STR;
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ DBUG_ASSERT(false);
+ return NULL;
+ }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const;
+};
+
+
+/**
+ Class for @@global.gtid_slave_pos.
+*/
+class Sys_var_gtid_slave_pos: public sys_var
+{
+public:
+ Sys_var_gtid_slave_pos(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
+ NULL, NULL, NULL)
+ {
+ option.var_type|= GET_STR;
+ }
+ bool do_check(THD *thd, set_var *var);
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool global_update(THD *thd, set_var *var);
+ void session_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ /* Record the attempt to use default so we can error. */
+ var->value= 0;
+ }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ DBUG_ASSERT(false);
+ return NULL;
+ }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const;
+ const uchar *default_value_ptr(THD *thd) const
+ { return 0; }
+ bool on_check_access_global(THD *thd) const
+ {
+ return check_global_access(thd, PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_SLAVE_POS);
+ }
+};
+
+
+/**
+ Class for @@global.gtid_binlog_state.
+*/
+class Sys_var_gtid_binlog_state: public sys_var
+{
+public:
+ Sys_var_gtid_binlog_state(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id,
+ getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
+ NULL, NULL, NULL)
+ {
+ option.var_type|= GET_STR;
+ }
+ bool do_check(THD *thd, set_var *var);
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool global_update(THD *thd, set_var *var);
+ void session_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ /* Record the attempt to use default so we can error. */
+ var->value= 0;
+ }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ DBUG_ASSERT(false);
+ return NULL;
+ }
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const;
+ const uchar *default_value_ptr(THD *thd) const
+ { return 0; }
+ bool on_check_access_global(THD *thd) const
+ {
+ return
+ check_global_access(thd, PRIV_SET_SYSTEM_GLOBAL_VAR_GTID_BINLOG_STATE);
+ }
+};
+
+
+/**
+ Class for @@session.last_gtid.
+*/
+class Sys_var_last_gtid: public sys_var
+{
+public:
+ Sys_var_last_gtid(const char *name_arg,
+ const char *comment, int flag_args, CMD_LINE getopt)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, 0, getopt.id,
+ getopt.arg_type, SHOW_CHAR, 0, NULL, VARIABLE_NOT_IN_BINLOG,
+ NULL, NULL, NULL)
+ {
+ SYSVAR_ASSERT(getopt.id < 0);
+ SYSVAR_ASSERT(is_readonly());
+ option.var_type|= GET_STR;
+ }
+ bool do_check(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool session_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ bool global_update(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ return true;
+ }
+ void session_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ }
+ void global_save_default(THD *thd, set_var *var)
+ {
+ DBUG_ASSERT(false);
+ }
+ const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const;
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ {
+ DBUG_ASSERT(false);
+ return NULL;
+ }
+};
+
+
+/**
+ Class for connection_name.slave_parallel_mode.
+*/
+class Sys_var_slave_parallel_mode: public Sys_var_enum
+{
+public:
+ Sys_var_slave_parallel_mode(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt, const char *values[],
+ enum_slave_parallel_mode def_val)
+ : Sys_var_enum(name_arg, comment, flag_args, off, size,
+ getopt, values, def_val)
+ {
+ option.var_type|= GET_ASK_ADDR;
+ option.value= (uchar**)1; // crash me, please
+ SYSVAR_ASSERT(scope() == GLOBAL);
+ }
+ bool global_update(THD *thd, set_var *var);
+ const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const;
+};
+
+
+class Sys_var_vers_asof: public sys_var
+{
+public:
+ Sys_var_vers_asof(const char *name_arg,
+ const char *comment, int flag_args, ptrdiff_t off, size_t size,
+ CMD_LINE getopt, uint def_val,
+ PolyLock *lock= NO_MUTEX_GUARD,
+ binlog_status_enum binlog_status_arg= VARIABLE_NOT_IN_BINLOG,
+ on_check_function on_check_func= NULL,
+ on_update_function on_update_func= NULL,
+ const char *substitute= NULL)
+ : sys_var(&all_sys_vars, name_arg, comment, flag_args, off,
+ getopt.id, getopt.arg_type, SHOW_CHAR, def_val, lock,
+ binlog_status_arg, on_check_func, on_update_func, substitute)
+ {
+ option.var_type= GET_STR;
+ }
+ virtual bool do_check(THD *thd, set_var *var)
+ {
+ if (!var->value)
+ return false;
+
+ MYSQL_TIME ltime;
+ Datetime::Options opt(TIME_CONV_NONE |
+ TIME_NO_ZERO_IN_DATE |
+ TIME_NO_ZERO_DATE, thd);
+ bool res= var->value->get_date(thd, &ltime, opt);
+ if (!res)
+ {
+ uint error;
+ var->save_result.timestamp.unix_time=
+ thd->variables.time_zone->TIME_to_gmt_sec(&ltime, &error);
+ var->save_result.timestamp.second_part= ltime.second_part;
+ res= error != 0;
+ }
+ return res;
+ }
+
+private:
+ static bool update(THD *thd, set_var *var, vers_asof_timestamp_t *out)
+ {
+ if (var->value)
+ {
+ out->type = SYSTEM_TIME_AS_OF;
+ out->unix_time = var->save_result.timestamp.unix_time;
+ out->second_part= var->save_result.timestamp.second_part;
+ }
+ return 0;
+ }
+
+ static void save_default(set_var *var, vers_asof_timestamp_t *out)
+ {
+ out->type= SYSTEM_TIME_UNSPECIFIED;
+ }
+
+public:
+ virtual bool global_update(THD *thd, set_var *var)
+ {
+ return update(thd, var, &global_var(vers_asof_timestamp_t));
+ }
+ virtual bool session_update(THD *thd, set_var *var)
+ {
+ return update(thd, var, &session_var(thd, vers_asof_timestamp_t));
+ }
+
+ virtual bool session_is_default(THD *thd)
+ {
+ const vers_asof_timestamp_t &var= session_var(thd, vers_asof_timestamp_t);
+ return var.type == SYSTEM_TIME_UNSPECIFIED;
+ }
+
+ virtual void session_save_default(THD *thd, set_var *var)
+ {
+ save_default(var, &session_var(thd, vers_asof_timestamp_t));
+ }
+ virtual void global_save_default(THD *thd, set_var *var)
+ {
+ save_default(var, &global_var(vers_asof_timestamp_t));
+ }
+
+private:
+ const uchar *value_ptr(THD *thd, vers_asof_timestamp_t &val) const
+ {
+ const char *value;
+ switch (val.type)
+ {
+ case SYSTEM_TIME_UNSPECIFIED:
+ return (uchar*)"DEFAULT";
+ break;
+ case SYSTEM_TIME_AS_OF:
+ {
+ char *buf= (char*) thd->alloc(MAX_DATE_STRING_REP_LENGTH);
+ MYSQL_TIME ltime;
+
+ thd->variables.time_zone->gmt_sec_to_TIME(&ltime, val.unix_time);
+ ltime.second_part= val.second_part;
+
+ value= buf;
+ if (buf && !my_datetime_to_str(&ltime, buf, 6))
+ {
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, "NULL (wrong datetime)");
+ value= thd->strdup("Error: wrong datetime");
+ }
+ break;
+ }
+ default:
+ my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name.str, "NULL (wrong range type)");
+ value= thd->strdup("Error: wrong range type");
+ }
+ return reinterpret_cast<const uchar *>(value);
+ }
+
+public:
+ virtual const uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return value_ptr(thd, session_var(thd, vers_asof_timestamp_t)); }
+ virtual const uchar *global_value_ptr(THD *thd, const LEX_CSTRING *base) const
+ { return value_ptr(thd, global_var(vers_asof_timestamp_t)); }
+};