mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-30 04:26:45 +03:00 
			
		
		
		
	fix sys_var->is_default() method (that was using default_val property in a global sys_var object to track per-session state): * move timestamp to a dedicated Sys_var_timestamp class (in fact, rename Sys_var_session_special_double to Sys_var_timestamp) * make session_is_default a virtual method with a special implementation for timestamps * other variables don't have a special behavior for default values and can have session_is_default() to be always false.
		
			
				
	
	
		
			2344 lines
		
	
	
		
			74 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			2344 lines
		
	
	
		
			74 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* Copyright (c) 2002, 2011, Oracle and/or its affiliates.
 | |
|    Copyright (c) 2010, 2013, Monty Program Ab.
 | |
| 
 | |
|    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-1301  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
 | |
| 
 | |
| /*
 | |
|   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+
 | |
| // 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
 | |
| 
 | |
| /*
 | |
|   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_ABORT();                                                     \
 | |
|       exit(255);                                                        \
 | |
|     }
 | |
| 
 | |
| enum charset_enum {IN_SYSTEM_CHARSET, IN_FS_CHARSET};
 | |
| 
 | |
| static const char *bool_values[3]= {"OFF", "ON", 0};
 | |
| TYPELIB bool_typelib={ array_elements(bool_values)-1, "", bool_values, 0 };
 | |
| extern const char *encrypt_algorithm_names[];
 | |
| 
 | |
| /**
 | |
|   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;
 | |
|     option.u_max_value= (uchar**)max_var_ptr();
 | |
|     if (max_var_ptr())
 | |
|       *max_var_ptr()= 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 > *max_var_ptr())
 | |
|         var->save_result.ulonglong_value= *max_var_ptr();
 | |
| 
 | |
|       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 > *max_var_ptr())
 | |
|         var->save_result.longlong_value= *max_var_ptr();
 | |
| 
 | |
|       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 *max_var_ptr()
 | |
|   {
 | |
|     return scope() == SESSION ? (T*)(((uchar*)&max_system_variables) + offset)
 | |
|                               : 0;
 | |
|   }
 | |
|   uchar *default_value_ptr(THD *thd) { 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<> uchar *Sys_var_int::default_value_ptr(THD *thd)
 | |
| {
 | |
|   thd->sys_var_tmp.int_value= option.def_value;
 | |
|   return (uchar*) &thd->sys_var_tmp.int_value;
 | |
| }
 | |
| 
 | |
| template<> uchar *Sys_var_uint::default_value_ptr(THD *thd)
 | |
| {
 | |
|   thd->sys_var_tmp.uint_value= option.def_value;
 | |
|   return (uchar*) &thd->sys_var_tmp.uint_value;
 | |
| }
 | |
| 
 | |
| template<> uchar *Sys_var_long::default_value_ptr(THD *thd)
 | |
| {
 | |
|   thd->sys_var_tmp.long_value= option.def_value;
 | |
|   return (uchar*) &thd->sys_var_tmp.long_value;
 | |
| }
 | |
| 
 | |
| template<> uchar *Sys_var_ulong::default_value_ptr(THD *thd)
 | |
| {
 | |
|   thd->sys_var_tmp.ulong_value= 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;
 | |
| 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--;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       longlong tmp=var->value->val_int();
 | |
|       if (tmp < 0 || tmp >= typelib.count)
 | |
|         return true;
 | |
|       else
 | |
|         var->save_result.ulonglong_value= tmp;
 | |
|     }
 | |
| 
 | |
|     return false;
 | |
|   }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   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: uint
 | |
| 
 | |
|   @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;
 | |
|     global_var(ulong)= def_val;
 | |
|     SYSVAR_ASSERT(def_val < typelib.count);
 | |
|     SYSVAR_ASSERT(size == sizeof(ulong));
 | |
|   }
 | |
|   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; }
 | |
|   uchar *valptr(THD *thd, ulong val)
 | |
|   { return (uchar*)typelib.type_names[val]; }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   { return valptr(thd, session_var(thd, ulong)); }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   { return valptr(thd, global_var(ulong)); }
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   { return valptr(thd, option.def_value); }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   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; }
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   {
 | |
|     thd->sys_var_tmp.my_bool_value= 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.
 | |
| 
 | |
|   Class specific constructor arguments:
 | |
|     enum charset_enum is_os_charset_arg
 | |
| 
 | |
|   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: public sys_var
 | |
| {
 | |
| public:
 | |
|   Sys_var_charptr(const char *name_arg,
 | |
|           const char *comment, int flag_args, ptrdiff_t off, size_t size,
 | |
|           CMD_LINE getopt,
 | |
|           enum charset_enum is_os_charset_arg,
 | |
|           const char *def_val, 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)
 | |
|   {
 | |
|     is_os_charset= is_os_charset_arg == IN_FS_CHARSET;
 | |
|     /*
 | |
|      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;
 | |
|     SYSVAR_ASSERT(scope() == GLOBAL);
 | |
|     SYSVAR_ASSERT(size == sizeof(char *));
 | |
|   }
 | |
|   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;
 | |
|     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)
 | |
|   {
 | |
|     DBUG_ASSERT(FALSE);
 | |
|     return true;
 | |
|   }
 | |
|   bool global_update(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(ptr, len+1, MYF(MY_WME));
 | |
|       if (!new_val) return true;
 | |
|       new_val[len]=0;
 | |
|     }
 | |
|     else
 | |
|       new_val= 0;
 | |
|     if (flags & ALLOCATED)
 | |
|       my_free(global_var(char*));
 | |
|     flags|= ALLOCATED;
 | |
|     global_var(char*)= new_val;
 | |
|     return false;
 | |
|   }
 | |
|   void session_save_default(THD *thd, set_var *var)
 | |
|   { DBUG_ASSERT(FALSE); }
 | |
|   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_proxy_user: public sys_var
 | |
| {
 | |
| public:
 | |
|   Sys_var_proxy_user(const char *name_arg,
 | |
|           const char *comment, enum charset_enum is_os_charset_arg)
 | |
|     : 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)
 | |
|   {
 | |
|     is_os_charset= is_os_charset_arg == IN_FS_CHARSET;
 | |
|     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:
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     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, 
 | |
|           enum charset_enum is_os_charset_arg) 
 | |
|     : Sys_var_proxy_user (name_arg, comment_arg, is_os_charset_arg)
 | |
|   {}
 | |
| 
 | |
| protected:
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     return (uchar*)thd->security_ctx->external_user;
 | |
|   }
 | |
| };
 | |
| 
 | |
| class Master_info;
 | |
| class Sys_var_rpl_filter: public sys_var
 | |
| {
 | |
| private:
 | |
|   int opt_id;
 | |
| 
 | |
| public:
 | |
|   Sys_var_rpl_filter(const char *name, int getopt_id, const char *comment)
 | |
|     : 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)
 | |
|   {
 | |
|     option.var_type= GET_STR | GET_ASK_ADDR;
 | |
|   }
 | |
| 
 | |
|   bool do_check(THD *thd, set_var *var)
 | |
|   {
 | |
|     return Sys_var_charptr::do_string_check(thd, var, charset(thd));
 | |
|   }
 | |
|   void session_save_default(THD *thd, set_var *var)
 | |
|   { DBUG_ASSERT(FALSE); }
 | |
| 
 | |
|   void global_save_default(THD *thd, set_var *var)
 | |
|   { DBUG_ASSERT(FALSE); }
 | |
| 
 | |
|   bool session_update(THD *thd, set_var *var)
 | |
|   {
 | |
|     DBUG_ASSERT(FALSE);
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool global_update(THD *thd, set_var *var);
 | |
| 
 | |
| protected:
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base);
 | |
|   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.
 | |
| 
 | |
|   Class specific constructor arguments:
 | |
|     enum charset_enum is_os_charset_arg
 | |
| 
 | |
|   Backing store: LEX_STRING
 | |
| 
 | |
|   @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,
 | |
|           enum charset_enum is_os_charset_arg,
 | |
|           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, is_os_charset_arg, def_val, lock, binlog_status_arg,
 | |
|               on_check_func, on_update_func, substitute)
 | |
|   {
 | |
|     global_var(LEX_STRING).length= strlen(def_val);
 | |
|     SYSVAR_ASSERT(size == sizeof(LEX_STRING));
 | |
|     *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_STRING).length= var->save_result.string_value.length;
 | |
|     return false;
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| /*
 | |
|   A LEX_STRING 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,
 | |
|                             enum charset_enum is_os_charset_arg,
 | |
|                             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_STRING *tmp= &session_var(thd, LEX_STRING);
 | |
|     tmp->length= var->save_result.string_value.length;
 | |
|     /* Store as \0 terminated string (just to be safe) */
 | |
|     strmake(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);
 | |
|   }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     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*)¤t_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*>("");
 | |
|     else
 | |
|       var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
 | |
|     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;
 | |
|   }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     char buf[256];
 | |
|     DBUG_EXPLAIN(buf, sizeof(buf));
 | |
|     return (uchar*) thd->strdup(buf);
 | |
|   }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     char buf[256];
 | |
|     DBUG_EXPLAIN_INITIAL(buf, sizeof(buf));
 | |
|     return (uchar*) thd->strdup(buf);
 | |
|   }
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   { 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_STRING *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);
 | |
|   }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     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)
 | |
|   { }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     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);
 | |
|   }
 | |
| };
 | |
| 
 | |
| // overflow-safe (1 << X)-1
 | |
| #define MAX_SET(X) ((((1UL << ((X)-1))-1) << 1) | 1)
 | |
| 
 | |
| /**
 | |
|   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 < MAX_SET(typelib.count));
 | |
|     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 (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 > MAX_SET(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; }
 | |
|   uchar *valptr(THD *thd, ulonglong val)
 | |
|   { return (uchar*)flagset_to_string(thd, 0, val, typelib.type_names); }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   { return valptr(thd, session_var(thd, ulonglong)); }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   { return valptr(thd, global_var(ulonglong)); }
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   { 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
 | |
| */
 | |
| 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;
 | |
|     global_var(ulonglong)= def_val;
 | |
|     SYSVAR_ASSERT(typelib.count > 0);
 | |
|     SYSVAR_ASSERT(typelib.count <= 64);
 | |
|     SYSVAR_ASSERT(def_val <= MAX_SET(typelib.count));
 | |
|     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;
 | |
| 
 | |
|     if (var->value->result_type() == STRING_RESULT)
 | |
|     {
 | |
|       if (!(res=var->value->val_str(&str)))
 | |
|         return true;
 | |
|       else
 | |
|       {
 | |
|         char *error;
 | |
|         uint error_len;
 | |
|         bool not_used;
 | |
| 
 | |
|         var->save_result.ulonglong_value=
 | |
|               find_set(&typelib, res->ptr(), res->length(), NULL,
 | |
|                       &error, &error_len, ¬_used);
 | |
|         /*
 | |
|           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;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       longlong tmp=var->value->val_int();
 | |
|       if ((tmp < 0 && ! var->value->unsigned_flag)
 | |
|           || (ulonglong)tmp > MAX_SET(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; }
 | |
|   uchar *valptr(THD *thd, ulonglong val)
 | |
|   { return (uchar*)set_to_string(thd, 0, val, typelib.type_names); }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   { return valptr(thd, session_var(thd, ulonglong)); }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   { return valptr(thd, global_var(ulonglong)); }
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   { return valptr(thd, option.def_value); }
 | |
| };
 | |
| 
 | |
| /**
 | |
|   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_STRING 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 (!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)
 | |
|   {
 | |
|     char *default_value= *reinterpret_cast<char**>(option.def_value);
 | |
|     if (!default_value)
 | |
|       return 0;
 | |
| 
 | |
|     LEX_STRING pname= { default_value, strlen(pname.str) };
 | |
|     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)
 | |
|   {
 | |
|     return (uchar*)(plugin ? thd->strmake(plugin_name(plugin)->str,
 | |
|                                           plugin_name(plugin)->length) : 0);
 | |
|   }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   { return valptr(thd, session_var(thd, plugin_ref)); }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   { return valptr(thd, global_var(plugin_ref)); }
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   { return valptr(thd, get_default(thd)); }
 | |
| };
 | |
| 
 | |
| #if defined(ENABLED_DEBUG_SYNC)
 | |
| /**
 | |
|   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.str= const_cast<char*>("");
 | |
|     else
 | |
|       var->save_result.string_value.str= thd->strmake(res->ptr(), res->length());
 | |
|     return false;
 | |
|   }
 | |
|   bool session_update(THD *thd, set_var *var)
 | |
|   {
 | |
|     extern bool debug_sync_update(THD *thd, char *val_str);
 | |
|     return debug_sync_update(thd, var->save_result.string_value.str);
 | |
|   }
 | |
|   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);
 | |
|   }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     extern uchar *debug_sync_value_ptr(THD *thd);
 | |
|     return debug_sync_value_ptr(thd);
 | |
|   }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     DBUG_ASSERT(FALSE);
 | |
|     return 0;
 | |
|   }
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   { 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_BOOL;
 | |
|     reverse_semantics= my_count_bits(bitmask_arg) > 1;
 | |
|     bitmask= reverse_semantics ? ~bitmask_arg : bitmask_arg;
 | |
|     set(global_var_ptr(), def_val);
 | |
|     SYSVAR_ASSERT(def_val < 2);
 | |
|     SYSVAR_ASSERT(getopt.id < 0); // force NO_CMD_LINE
 | |
|     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= 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)
 | |
|   {
 | |
|     thd->sys_var_tmp.my_bool_value= reverse_semantics ^ ((val & bitmask) != 0);
 | |
|     return (uchar*) &thd->sys_var_tmp.my_bool_value;
 | |
|   }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   { return valptr(thd, session_var(thd, ulonglong)); }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   { return valptr(thd, global_var(ulonglong)); }
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   {
 | |
|     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); }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     thd->sys_var_tmp.ulonglong_value= read_func(thd);
 | |
|     return (uchar*) &thd->sys_var_tmp.ulonglong_value;
 | |
|   }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     DBUG_ASSERT(FALSE);
 | |
|     return 0;
 | |
|   }
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   {
 | |
|     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)
 | |
|     : Sys_var_double(name_arg, comment, flag_args, 0,
 | |
|               sizeof(double), getopt, min_val,
 | |
|               max_val, 0, lock, binlog_status_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)
 | |
|   {
 | |
|     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); }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     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;
 | |
|   }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     DBUG_ASSERT(FALSE);
 | |
|     return 0;
 | |
|   }
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   {
 | |
|     thd->sys_var_tmp.double_value= 0;
 | |
|     return (uchar*) &thd->sys_var_tmp.double_value;
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   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) { }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     DBUG_ASSERT(FALSE);
 | |
|     return 0;
 | |
|   }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     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)
 | |
|   { return val ? *(uchar**)(val+name_offset) : 0; }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   { return valptr(thd, session_var(thd, uchar*)); }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   { return valptr(thd, global_var(uchar*)); }
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   { 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;
 | |
|   }
 | |
|   uchar *valptr(THD *thd, Time_zone *val)
 | |
|   { return (uchar *)(val->get_name()->ptr()); }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     /*
 | |
|       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->time_zone_used= 1;
 | |
|     return valptr(thd, session_var(thd, Time_zone *));
 | |
|   }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   { return valptr(thd, global_var(Time_zone*)); }
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   { 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;
 | |
|     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);
 | |
|   }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     ulonglong *tmp, res;
 | |
|     tmp= (ulonglong*) (((uchar*)&(thd->variables)) + offset);
 | |
|     res= get_master_info_ulonglong_value(thd, master_info_offset);
 | |
|     *tmp= res;
 | |
|     return (uchar*) tmp;
 | |
|   }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     return session_value_ptr(thd, base);
 | |
|   }
 | |
|   ulonglong get_master_info_ulonglong_value(THD *thd, ptrdiff_t offset);
 | |
|   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);
 | |
|   }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     DBUG_ASSERT(false);
 | |
|     return NULL;
 | |
|   }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base);
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   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);
 | |
|   }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     DBUG_ASSERT(false);
 | |
|     return NULL;
 | |
|   }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base);
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   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;
 | |
|   }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     DBUG_ASSERT(false);
 | |
|     return NULL;
 | |
|   }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base);
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   { return 0; }
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   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;
 | |
|   }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     DBUG_ASSERT(false);
 | |
|     return NULL;
 | |
|   }
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base);
 | |
|   uchar *default_value_ptr(THD *thd)
 | |
|   { return 0; }
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   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);
 | |
|   }
 | |
|   uchar *session_value_ptr(THD *thd, const LEX_STRING *base);
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base)
 | |
|   {
 | |
|     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);
 | |
|   uchar *global_value_ptr(THD *thd, const LEX_STRING *base);
 | |
| };
 |