diff options
Diffstat (limited to 'sql/sys_vars.h')
-rw-r--r-- | sql/sys_vars.h | 1600 |
1 files changed, 1600 insertions, 0 deletions
diff --git a/sql/sys_vars.h b/sql/sys_vars.h new file mode 100644 index 00000000000..bdbbcbbbd59 --- /dev/null +++ b/sql/sys_vars.h @@ -0,0 +1,1600 @@ +/* Copyright (C) 2002-2006 MySQL AB, 2009 Sun Microsystems, Inc. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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" + +/* + 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, -1) +/* + 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+ +/* + Sys_var_bit meaning is reversed, like in + @@foreign_key_checks <-> OPTION_NO_FOREIGN_KEY_CHECKS +*/ +#define REVERSE(X) ~(X) +#define DEPRECATED(X, Y) X, Y + +#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 + +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 }; + +/** + 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_unsigned template is used to generate Sys_var_* classes + for variables that represent the value as an unsigned integer. + They are Sys_var_uint, Sys_var_ulong, Sys_var_harows, Sys_var_ulonglong. + + 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: uint, ulong, ha_rows, ulonglong, depending on the Sys_var_* +*/ +template <typename T, ulong ARGT, enum enum_mysql_show_type SHOWT> +class Sys_var_unsigned: public sys_var +{ +public: + Sys_var_unsigned(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, + uint deprecated_version=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, deprecated_version, + 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; + DBUG_ASSERT(size == sizeof(T)); + DBUG_ASSERT(min_val < max_val); + DBUG_ASSERT(min_val <= def_val); + DBUG_ASSERT(max_val >= def_val); + DBUG_ASSERT(block_size > 0); + DBUG_ASSERT(def_val % block_size == 0); + } + bool do_check(THD *thd, set_var *var) + { + my_bool fixed= FALSE; + ulonglong uv; + longlong v; + + v= var->value->val_int(); + if (var->value->unsigned_flag) + uv= (ulonglong) v; + else + uv= (ulonglong) (v < 0 ? 0 : v); + + var->save_result.ulonglong_value= + getopt_ull_limit_value(uv, &option, &fixed); + + if (max_var_ptr() && var->save_result.ulonglong_value > *max_var_ptr()) + var->save_result.ulonglong_value= *max_var_ptr(); + + return throw_bounds_warning(thd, name.str, + var->save_result.ulonglong_value != uv, + var->value->unsigned_flag, v); + } + bool session_update(THD *thd, set_var *var) + { + session_var(thd, T)= var->save_result.ulonglong_value; + return false; + } + bool global_update(THD *thd, set_var *var) + { + global_var(T)= var->save_result.ulonglong_value; + return false; + } + bool check_update_type(Item_result type) + { return type != INT_RESULT; } + 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; + } +}; + +typedef Sys_var_unsigned<uint, GET_UINT, SHOW_INT> Sys_var_uint; +typedef Sys_var_unsigned<ulong, GET_ULONG, SHOW_LONG> Sys_var_ulong; +typedef Sys_var_unsigned<ha_rows, GET_HA_ROWS, SHOW_HA_ROWS> Sys_var_harows; +typedef Sys_var_unsigned<ulonglong, GET_ULL, SHOW_LONGLONG> Sys_var_ulonglong; + +/** + 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, + uint deprecated_version, 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, deprecated_version, 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; + } + bool check_update_type(Item_result type) + { return type != INT_RESULT && type != STRING_RESULT; } +}; + +/** + 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, + uint deprecated_version=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, + deprecated_version, substitute) + { + option.var_type= GET_ENUM; + global_var(uint)= def_val; + DBUG_ASSERT(def_val < typelib.count); + DBUG_ASSERT(size == sizeof(uint)); + } + bool session_update(THD *thd, set_var *var) + { + session_var(thd, uint)= var->save_result.ulonglong_value; + return false; + } + bool global_update(THD *thd, set_var *var) + { + global_var(uint)= var->save_result.ulonglong_value; + return false; + } + void session_save_default(THD *thd, set_var *var) + { var->save_result.ulonglong_value= global_var(uint); } + void global_save_default(THD *thd, set_var *var) + { var->save_result.ulonglong_value= option.def_value; } + uchar *session_value_ptr(THD *thd, LEX_STRING *base) + { return (uchar*)typelib.type_names[session_var(thd, uint)]; } + uchar *global_value_ptr(THD *thd, LEX_STRING *base) + { return (uchar*)typelib.type_names[global_var(uint)]; } +}; + +/** + 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, + uint deprecated_version=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, + deprecated_version, substitute) + { + option.var_type= GET_BOOL; + global_var(my_bool)= def_val; + DBUG_ASSERT(def_val < 2); + DBUG_ASSERT(getopt.arg_type == OPT_ARG || getopt.id == -1); + DBUG_ASSERT(size == sizeof(my_bool)); + } + bool session_update(THD *thd, set_var *var) + { + session_var(thd, my_bool)= var->save_result.ulonglong_value; + return false; + } + bool global_update(THD *thd, set_var *var) + { + global_var(my_bool)= var->save_result.ulonglong_value; + 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; } +}; + +/** + 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, + uint deprecated_version=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, + deprecated_version, 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; + DBUG_ASSERT(scope() == GLOBAL); + DBUG_ASSERT(size == sizeof(char *)); + } + ~Sys_var_charptr() + { + if (flags & ALLOCATED) + my_free(global_var(char*), MYF(MY_ALLOW_ZERO_PTR)); + flags&= ~ALLOCATED; + } + bool do_check(THD *thd, set_var *var) + { + char buff[STRING_BUFFER_USUAL_SIZE], buff2[STRING_BUFFER_USUAL_SIZE]; + String str(buff, sizeof(buff), charset(thd)); + String str2(buff2, sizeof(buff2), charset(thd)), *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(thd), &unused)) + { + uint errors; + str2.copy(res->ptr(), res->length(), res->charset(), charset(thd), + &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 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*), MYF(MY_ALLOW_ZERO_PTR)); + 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; + } + bool check_update_type(Item_result type) + { return type != STRING_RESULT; } +}; + +/** + 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, + uint deprecated_version=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, deprecated_version, substitute) + { + global_var(LEX_STRING).length= strlen(def_val); + DBUG_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; + } +}; + +#ifndef DBUG_OFF +/** + @@session.dbug and @@global.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, + uint deprecated_version=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, + deprecated_version, substitute) + { option.var_type= GET_NO_ARG; } + 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, LEX_STRING *base) + { + char buf[256]; + DBUG_EXPLAIN(buf, sizeof(buf)); + return (uchar*) thd->strdup(buf); + } + uchar *global_value_ptr(THD *thd, LEX_STRING *base) + { + char buf[256]; + DBUG_EXPLAIN_INITIAL(buf, sizeof(buf)); + return (uchar*) thd->strdup(buf); + } + bool check_update_type(Item_result type) + { return type != STRING_RESULT; } +}; +#endif + +#define KEYCACHE_VAR(X) sys_var::GLOBAL,offsetof(KEY_CACHE, X), sizeof(((KEY_CACHE *)0)->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, + ulonglong block_size, PolyLock *lock, + enum binlog_status_enum binlog_status_arg, + on_check_function on_check_func, + keycache_update_function on_update_func, + uint deprecated_version=0, 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, + deprecated_version, substitute), + keycache_update(on_update_func) + { + option.var_type|= GET_ASK_ADDR; + option.value= (uchar**)1; // crash me, please + keycache_var(dflt_key_cache, off)= def_val; + DBUG_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, 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; + pthread_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 + */ + pthread_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; + pthread_mutex_unlock(&LOCK_global_system_variables); + + if (!key_cache->key_cache_inited) + error= ha_init_key_cache(0, key_cache); + else + error= ha_resize_key_cache(key_cache); + + pthread_mutex_lock(&LOCK_global_system_variables); + key_cache->in_init= 0; + + return error; +} + +static bool update_keycache_param(THD *thd, KEY_CACHE *key_cache, + ptrdiff_t offset, ulonglong new_value) +{ + bool error= false; + DBUG_ASSERT(offset != offsetof(KEY_CACHE, param_buff_size)); + + keycache_var(key_cache, offset)= new_value; + + key_cache->in_init= 1; + pthread_mutex_unlock(&LOCK_global_system_variables); + error= ha_resize_key_cache(key_cache); + + pthread_mutex_lock(&LOCK_global_system_variables); + key_cache->in_init= 0; + + return error; +} + +/** + 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, + uint deprecated_version=0, const char *substitute=0) + : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, + getopt.arg_type, SHOW_DOUBLE, def_val, lock, binlog_status_arg, + on_check_func, on_update_func, deprecated_version, substitute) + { + option.var_type= GET_DOUBLE; + option.min_value= min_val; + option.max_value= max_val; + global_var(double)= (double)option.def_value; + DBUG_ASSERT(min_val < max_val); + DBUG_ASSERT(min_val <= def_val); + DBUG_ASSERT(max_val >= def_val); + DBUG_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; + } + bool check_update_type(Item_result type) + { + return type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT; + } + 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= (double)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_uint +{ +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, + uint min_val, uint max_val, uint 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, + uint deprecated_version=0, const char *substitute=0) + : Sys_var_uint(name_arg, comment, SESSION, off, size, getopt, + min_val, max_val, def_val, block_size, + lock, binlog_status_arg, on_check_func, on_update_func, + deprecated_version, substitute) + { } + uchar *session_value_ptr(THD *thd, 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, + uint deprecated_version=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, + deprecated_version, substitute) + { + option.var_type= GET_FLAGSET; + global_var(ulonglong)= def_val; + DBUG_ASSERT(typelib.count > 1); + DBUG_ASSERT(typelib.count <= 65); + DBUG_ASSERT(def_val < MAX_SET(typelib.count)); + DBUG_ASSERT(strcmp(values[typelib.count-1], "default") == 0); + DBUG_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 *session_value_ptr(THD *thd, LEX_STRING *base) + { + return (uchar*)flagset_to_string(thd, 0, session_var(thd, ulonglong), + typelib.type_names); + } + uchar *global_value_ptr(THD *thd, LEX_STRING *base) + { + return (uchar*)flagset_to_string(thd, 0, global_var(ulonglong), + typelib.type_names); + } +}; + +/** + 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, + uint deprecated_version=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, + deprecated_version, substitute) + { + option.var_type= GET_SET; + global_var(ulonglong)= def_val; + DBUG_ASSERT(typelib.count > 0); + DBUG_ASSERT(typelib.count <= 64); + DBUG_ASSERT(def_val < MAX_SET(typelib.count)); + DBUG_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 *session_value_ptr(THD *thd, LEX_STRING *base) + { + return (uchar*)set_to_string(thd, 0, session_var(thd, ulonglong), + typelib.type_names); + } + uchar *global_value_ptr(THD *thd, LEX_STRING *base) + { + return (uchar*)set_to_string(thd, 0, global_var(ulonglong), + typelib.type_names); + } +}; + +/** + 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, + uint deprecated_version=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, + deprecated_version, substitute), + plugin_type(plugin_type_arg) + { + option.var_type= GET_STR; + DBUG_ASSERT(size == sizeof(plugin_ref)); + DBUG_ASSERT(getopt.id == -1); // 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); + 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= my_plugin_lock(NULL, &newval); + 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= my_plugin_lock(thd, &plugin); + } + void global_save_default(THD *thd, set_var *var) + { + LEX_STRING pname; + pname.str= *(char**)option.def_value; + pname.length= strlen(pname.str); + + plugin_ref plugin; + if (plugin_type == MYSQL_STORAGE_ENGINE_PLUGIN) + plugin= ha_resolve_by_name(thd, &pname); + else + plugin= my_plugin_lock_by_name(thd, &pname, plugin_type); + DBUG_ASSERT(plugin); + + var->save_result.plugin= my_plugin_lock(thd, &plugin); + } + bool check_update_type(Item_result type) + { return type != STRING_RESULT; } + uchar *session_value_ptr(THD *thd, LEX_STRING *base) + { + plugin_ref plugin= session_var(thd, plugin_ref); + return (uchar*)(plugin ? thd->strmake(plugin_name(plugin)->str, + plugin_name(plugin)->length) : 0); + } + uchar *global_value_ptr(THD *thd, LEX_STRING *base) + { + plugin_ref plugin= global_var(plugin_ref); + return (uchar*)(plugin ? thd->strmake(plugin_name(plugin)->str, + plugin_name(plugin)->length) : 0); + } +}; + +#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, + uint deprecated_version=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, + deprecated_version, substitute) + { + DBUG_ASSERT(scope() == ONLY_SESSION); + option.var_type= GET_NO_ARG; + } + 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, LEX_STRING *base) + { + extern uchar *debug_sync_value_ptr(THD *thd); + return debug_sync_value_ptr(thd); + } + uchar *global_value_ptr(THD *thd, LEX_STRING *base) + { + DBUG_ASSERT(FALSE); + return 0; + } + bool check_update_type(Item_result type) + { return type != STRING_RESULT; } +}; +#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, + uint deprecated_version=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, + deprecated_version, 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); + DBUG_ASSERT(def_val < 2); + DBUG_ASSERT(getopt.id == -1); // force NO_CMD_LINE + DBUG_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 *session_value_ptr(THD *thd, LEX_STRING *base) + { + thd->sys_var_tmp.my_bool_value= reverse_semantics ^ + ((session_var(thd, ulonglong) & bitmask) != 0); + return (uchar*) &thd->sys_var_tmp.my_bool_value; + } + uchar *global_value_ptr(THD *thd, LEX_STRING *base) + { + thd->sys_var_tmp.my_bool_value= reverse_semantics ^ + ((global_var(ulonglong) & bitmask) != 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, ulonglong 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, + uint deprecated_version=0, 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, + deprecated_version, substitute), + read_func(read_func_arg), update_func(update_func_arg) + { + DBUG_ASSERT(scope() == ONLY_SESSION); + DBUG_ASSERT(getopt.id == -1); // 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, 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, LEX_STRING *base) + { + DBUG_ASSERT(FALSE); + return 0; + } +}; + +/** + 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, + uint deprecated_version=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, + deprecated_version, substitute) + { + DBUG_ASSERT(scope() == GLOBAL); + DBUG_ASSERT(getopt.id == -1); + DBUG_ASSERT(lock == 0); + DBUG_ASSERT(binlog_status_arg == VARIABLE_NOT_IN_BINLOG); + DBUG_ASSERT(is_readonly()); + DBUG_ASSERT(on_update == 0); + DBUG_ASSERT(size == sizeof(enum SHOW_COMP_OPTION)); + } + 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, LEX_STRING *base) + { + DBUG_ASSERT(FALSE); + return 0; + } + uchar *global_value_ptr(THD *thd, LEX_STRING *base) + { + return (uchar*)show_comp_option_name[global_var(enum SHOW_COMP_OPTION)]; + } + bool check_update_type(Item_result type) { return false; } +}; + +/** + 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, + uint deprecated_version=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, + deprecated_version, substitute), name_offset(name_off) + { + option.var_type= GET_STR; + /* + 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 + */ + DBUG_ASSERT(getopt.id == -1); + DBUG_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, void*)= var->save_result.ptr; + return false; + } + bool global_update(THD *thd, set_var *var) + { + global_var(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) + { var->save_result.ptr= *(void**)option.def_value; } + bool check_update_type(Item_result type) + { return type != INT_RESULT && type != STRING_RESULT; } + uchar *session_value_ptr(THD *thd, LEX_STRING *base) + { + uchar *ptr= session_var(thd, uchar*); + return ptr ? *(uchar**)(ptr+name_offset) : 0; + } + uchar *global_value_ptr(THD *thd, LEX_STRING *base) + { + uchar *ptr= global_var(uchar*); + return ptr ? *(uchar**)(ptr+name_offset) : 0; + } +}; + +/** + 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, + uint deprecated_version=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, + deprecated_version, substitute) + { + DBUG_ASSERT(getopt.id == -1); + DBUG_ASSERT(size == sizeof(Time_zone *)); + } + 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 *session_value_ptr(THD *thd, 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 (uchar *)(session_var(thd, Time_zone*)->get_name()->ptr()); + } + uchar *global_value_ptr(THD *thd, LEX_STRING *base) + { + return (uchar *)(global_var(Time_zone*)->get_name()->ptr()); + } + bool check_update_type(Item_result type) + { return type != STRING_RESULT; } +}; + +/**************************************************************************** + Used templates +****************************************************************************/ + +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION +template class List<set_var_base>; +template class List_iterator_fast<set_var_base>; +template class Sys_var_unsigned<uint, GET_UINT, SHOW_INT>; +template class Sys_var_unsigned<ulong, GET_ULONG, SHOW_LONG>; +template class Sys_var_unsigned<ha_rows, GET_HA_ROWS, SHOW_HA_ROWS>; +template class Sys_var_unsigned<ulonglong, GET_ULL, SHOW_LONGLONG>; +#endif + |