diff options
Diffstat (limited to 'sql/set_var.cc')
-rw-r--r-- | sql/set_var.cc | 236 |
1 files changed, 159 insertions, 77 deletions
diff --git a/sql/set_var.cc b/sql/set_var.cc index f14068fcfcb..84e628fbddf 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -110,6 +110,7 @@ static void sys_default_init_connect(THD*, enum_var_type type); static bool sys_update_init_slave(THD*, set_var*); static void sys_default_init_slave(THD*, enum_var_type type); static bool set_option_bit(THD *thd, set_var *var); +static bool set_option_log_bin_bit(THD *thd, set_var *var); static bool set_option_autocommit(THD *thd, set_var *var); static int check_log_update(THD *thd, set_var *var); static bool set_log_update(THD *thd, set_var *var); @@ -134,8 +135,6 @@ static int check_max_delayed_threads(THD *thd, set_var *var); static void fix_thd_mem_root(THD *thd, enum_var_type type); static void fix_trans_mem_root(THD *thd, enum_var_type type); static void fix_server_id(THD *thd, enum_var_type type); -static ulonglong fix_unsigned(THD *, ulonglong, const struct my_option *); -static bool get_unsigned(THD *thd, set_var *var); bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd, const char *name, longlong val); static KEY_CACHE *create_key_cache(const char *name, uint length); @@ -731,7 +730,7 @@ static sys_var_thd_bit sys_log_update(&vars, "sql_log_update", OPTION_BIN_LOG); static sys_var_thd_bit sys_log_binlog(&vars, "sql_log_bin", check_log_update, - set_option_bit, + set_option_log_bin_bit, OPTION_BIN_LOG); static sys_var_thd_bit sys_sql_warnings(&vars, "sql_warnings", 0, set_option_bit, @@ -1370,6 +1369,19 @@ static void fix_server_id(THD *thd, enum_var_type type) } +/** + Throw warning (error in STRICT mode) if value for variable needed bounding. + Only call from check(), not update(), because an error in update() would be + bad mojo. Plug-in interface also uses this. + + @param thd thread handle + @param fixed did we have to correct the value? (throw warn/err if so) + @param unsignd is value's type unsigned? + @param name variable's name + @param val variable's value + + @retval TRUE on error, FALSE otherwise (warning or OK) + */ bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd, const char *name, longlong val) { @@ -1395,26 +1407,128 @@ bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd, return FALSE; } -static ulonglong fix_unsigned(THD *thd, ulonglong num, + +/** + check an unsigned user-supplied value for a systemvariable against bounds. + + TODO: This is a wrapper function to call clipping from within an update() + function. Calling bounds from within update() is fair game in theory, + but we can only send warnings from in there, not errors, and besides, + it violates our model of separating check from update phase. + To avoid breaking out of the server with an ASSERT() in strict mode, + we pretend we're not in strict mode when we go through here. Bug#43233 + was opened to remind us to replace this kludge with The Right Thing, + which of course is to do the check in the actual check phase, and then + throw an error or warning accordingly. + + @param thd thread handle + @param num the value to limit + @param option_limits the bounds-record, or NULL if none + */ +static void bound_unsigned(THD *thd, ulonglong *num, const struct my_option *option_limits) { - my_bool fixed= FALSE; - ulonglong out= getopt_ull_limit_value(num, option_limits, &fixed); + if (option_limits) + { + my_bool fixed = FALSE; + ulonglong unadjusted= *num; + + *num= getopt_ull_limit_value(unadjusted, option_limits, &fixed); - throw_bounds_warning(thd, fixed, TRUE, option_limits->name, (longlong) num); - return out; + if (fixed) + { + ulong ssm= thd->variables.sql_mode; + thd->variables.sql_mode&= ~MODE_STRICT_ALL_TABLES; + throw_bounds_warning(thd, fixed, TRUE, option_limits->name, unadjusted); + thd->variables.sql_mode= ssm; + } + } } -static bool get_unsigned(THD *thd, set_var *var) -{ + +/** + Get unsigned system-variable. + Negative value does not wrap around, but becomes zero. + Check user-supplied value for a systemvariable against bounds. + If we needed to adjust the value, throw a warning or error depending + on SQL-mode. + + @param thd thread handle + @param var the system-variable to get + @param user_max a limit given with --maximum-variable-name=... or 0 + @param var_type function will bound on systems where necessary. + + @retval TRUE on error, FALSE otherwise (warning or OK) + */ +static bool get_unsigned(THD *thd, set_var *var, ulonglong user_max, + ulong var_type) +{ + int warnings= 0; + ulonglong unadjusted; + const struct my_option *limits= var->var->option_limits; + struct my_option fallback; + + /* get_unsigned() */ if (var->value->unsigned_flag) var->save_result.ulonglong_value= (ulonglong) var->value->val_int(); else { longlong v= var->value->val_int(); var->save_result.ulonglong_value= (ulonglong) ((v < 0) ? 0 : v); + if (v < 0) + { + warnings++; + if (throw_bounds_warning(thd, TRUE, FALSE, var->var->name, v)) + return TRUE; /* warning was promoted to error, give up */ + } } - return 0; + + unadjusted= var->save_result.ulonglong_value; + + /* max, if any */ + + if ((user_max > 0) && (unadjusted > user_max)) + { + var->save_result.ulonglong_value= user_max; + + if ((warnings == 0) && throw_bounds_warning(thd, TRUE, TRUE, + var->var->name, + (longlong) unadjusted)) + return TRUE; + + warnings++; + } + + /* + if the sysvar doesn't have a proper bounds record but the check + function would like bounding to ULONG where its size differs from + that of ULONGLONG, we make up a bogus limits record here and let + the usual suspects handle the actual limiting. + */ + + if (!limits && var_type != GET_ULL) + { + bzero(&fallback, sizeof(fallback)); + fallback.var_type= var_type; + limits= &fallback; + } + + /* fix_unsigned() */ + if (limits) + { + my_bool fixed; + + var->save_result.ulonglong_value= getopt_ull_limit_value(var->save_result. + ulonglong_value, + limits, &fixed); + + if ((warnings == 0) && throw_bounds_warning(thd, fixed, TRUE, + var->var->name, + (longlong) unadjusted)) + return TRUE; + } + + return FALSE; } @@ -1428,29 +1542,13 @@ sys_var_long_ptr(sys_var_chain *chain, const char *name_arg, ulong *value_ptr_ar bool sys_var_long_ptr_global::check(THD *thd, set_var *var) { - return get_unsigned(thd, var); + return get_unsigned(thd, var, 0, GET_ULONG); } bool sys_var_long_ptr_global::update(THD *thd, set_var *var) { - ulonglong tmp= var->save_result.ulonglong_value; pthread_mutex_lock(guard); - if (option_limits) - *value= (ulong) fix_unsigned(thd, tmp, option_limits); - else - { -#if SIZEOF_LONG < SIZEOF_LONG_LONG - /* Avoid overflows on 32 bit systems */ - if (tmp > ULONG_MAX) - { - tmp= ULONG_MAX; - throw_bounds_warning(thd, TRUE, TRUE, name, - (longlong) var->save_result.ulonglong_value); - } -#endif - *value= (ulong) tmp; - } - + *value= (ulong) var->save_result.ulonglong_value; pthread_mutex_unlock(guard); return 0; } @@ -1470,10 +1568,8 @@ bool sys_var_ulonglong_ptr::update(THD *thd, set_var *var) { ulonglong tmp= var->save_result.ulonglong_value; pthread_mutex_lock(&LOCK_global_system_variables); - if (option_limits) - *value= (ulonglong) fix_unsigned(thd, tmp, option_limits); - else - *value= (ulonglong) tmp; + bound_unsigned(thd, &tmp, option_limits); + *value= (ulonglong) tmp; pthread_mutex_unlock(&LOCK_global_system_variables); return 0; } @@ -1523,36 +1619,18 @@ uchar *sys_var_enum_const::value_ptr(THD *thd, enum_var_type type, bool sys_var_thd_ulong::check(THD *thd, set_var *var) { - return (get_unsigned(thd, var) || - (check_func && (*check_func)(thd, var))); + if (get_unsigned(thd, var, max_system_variables.*offset, GET_ULONG)) + return TRUE; + DBUG_ASSERT(var->save_result.ulonglong_value <= ULONG_MAX); + return ((check_func && (*check_func)(thd, var))); } bool sys_var_thd_ulong::update(THD *thd, set_var *var) { - ulonglong tmp= var->save_result.ulonglong_value; - - /* Don't use bigger value than given with --maximum-variable-name=.. */ - if (tmp > max_system_variables.*offset) - { - throw_bounds_warning(thd, TRUE, TRUE, name, (longlong) tmp); - tmp= max_system_variables.*offset; - } - - if (option_limits) - tmp= fix_unsigned(thd, tmp, option_limits); -#if SIZEOF_LONG < SIZEOF_LONG_LONG - else if (tmp > ULONG_MAX) - { - tmp= ULONG_MAX; - throw_bounds_warning(thd, TRUE, TRUE, name, (longlong) var->save_result.ulonglong_value); - } -#endif - - DBUG_ASSERT(tmp <= ULONG_MAX); if (var->type == OPT_GLOBAL) - global_system_variables.*offset= (ulong) tmp; + global_system_variables.*offset= (ulong) var->save_result.ulonglong_value; else - thd->variables.*offset= (ulong) tmp; + thd->variables.*offset= (ulong) var->save_result.ulonglong_value; return 0; } @@ -1590,8 +1668,8 @@ bool sys_var_thd_ha_rows::update(THD *thd, set_var *var) if ((ha_rows) tmp > max_system_variables.*offset) tmp= max_system_variables.*offset; - if (option_limits) - tmp= (ha_rows) fix_unsigned(thd, tmp, option_limits); + bound_unsigned(thd, &tmp, option_limits); + if (var->type == OPT_GLOBAL) { /* Lock is needed to make things safe on 32 bit systems */ @@ -1632,27 +1710,21 @@ uchar *sys_var_thd_ha_rows::value_ptr(THD *thd, enum_var_type type, bool sys_var_thd_ulonglong::check(THD *thd, set_var *var) { - return get_unsigned(thd, var); + return get_unsigned(thd, var, max_system_variables.*offset, GET_ULL); } bool sys_var_thd_ulonglong::update(THD *thd, set_var *var) { - ulonglong tmp= var->save_result.ulonglong_value; - - if (tmp > max_system_variables.*offset) - tmp= max_system_variables.*offset; - - if (option_limits) - tmp= fix_unsigned(thd, tmp, option_limits); if (var->type == OPT_GLOBAL) { /* Lock is needed to make things safe on 32 bit systems */ pthread_mutex_lock(&LOCK_global_system_variables); - global_system_variables.*offset= (ulonglong) tmp; + global_system_variables.*offset= (ulonglong) + var->save_result.ulonglong_value; pthread_mutex_unlock(&LOCK_global_system_variables); } else - thd->variables.*offset= (ulonglong) tmp; + thd->variables.*offset= (ulonglong) var->save_result.ulonglong_value; return 0; } @@ -2284,10 +2356,10 @@ bool sys_var_key_buffer_size::update(THD *thd, set_var *var) goto end; } - key_cache->param_buff_size= - (ulonglong) fix_unsigned(thd, tmp, option_limits); + bound_unsigned(thd, &tmp, option_limits); + key_cache->param_buff_size= (ulonglong) tmp; - /* If key cache didn't existed initialize it, else resize it */ + /* If key cache didn't exist initialize it, else resize it */ key_cache->in_init= 1; pthread_mutex_unlock(&LOCK_global_system_variables); @@ -2313,7 +2385,7 @@ end: */ bool sys_var_key_cache_long::update(THD *thd, set_var *var) { - ulong tmp= (ulong) var->value->val_int(); + ulonglong tmp= var->value->val_int(); LEX_STRING *base_name= &var->base; bool error= 0; @@ -2338,8 +2410,8 @@ bool sys_var_key_cache_long::update(THD *thd, set_var *var) if (key_cache->in_init) goto end; - *((ulong*) (((char*) key_cache) + offset))= - (ulong) fix_unsigned(thd, tmp, option_limits); + bound_unsigned(thd, &tmp, option_limits); + *((ulong*) (((char*) key_cache) + offset))= (ulong) tmp; /* Don't create a new key cache if it didn't exist @@ -2963,6 +3035,16 @@ static bool set_option_bit(THD *thd, set_var *var) return 0; } +/* + Functions to be only used to update thd->options OPTION_BIN_LOG bit +*/ +static bool set_option_log_bin_bit(THD *thd, set_var *var) +{ + set_option_bit(thd, var); + if (!thd->in_sub_stmt) + thd->sql_log_bin_toplevel= thd->options & OPTION_BIN_LOG; + return 0; +} static bool set_option_autocommit(THD *thd, set_var *var) { @@ -3682,7 +3764,7 @@ bool sys_var_thd_storage_engine::update(THD *thd, set_var *var) void sys_var_thd_table_type::warn_deprecated(THD *thd) { - WARN_DEPRECATED(thd, "5.2", "@@table_type", "'@@storage_engine'"); + WARN_DEPRECATED(thd, "6.0", "@@table_type", "'@@storage_engine'"); } void sys_var_thd_table_type::set_default(THD *thd, enum_var_type type) @@ -3944,7 +4026,7 @@ bool process_key_caches(process_key_cache_t func) void sys_var_trust_routine_creators::warn_deprecated(THD *thd) { - WARN_DEPRECATED(thd, "5.2", "@@log_bin_trust_routine_creators", + WARN_DEPRECATED(thd, "6.0", "@@log_bin_trust_routine_creators", "'@@log_bin_trust_function_creators'"); } |