mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 04:53:01 +01:00
Bug#32757: hang with sql_mode set when setting some global variables
If setting a system-variable provided by a plug-in failed, no OK or error was sent in some cases, hanging the client. We now send an error in the case from the ticket (integer-argument out of range in STRICT mode). We also provide a semi-generic fallback message for possible future cases like this where an error is signalled, but no message is sent to the client. The error/warning handling is unified so it's the same again for variables provided by plugins and those in the server proper.
This commit is contained in:
parent
60fc91570b
commit
79491f93c8
6 changed files with 125 additions and 43 deletions
|
@ -27,3 +27,30 @@ SET GLOBAL example_enum_var= e2;
|
||||||
SET GLOBAL example_enum_var= impossible;
|
SET GLOBAL example_enum_var= impossible;
|
||||||
ERROR 42000: Variable 'enum_var' can't be set to the value of 'impossible'
|
ERROR 42000: Variable 'enum_var' can't be set to the value of 'impossible'
|
||||||
UNINSTALL PLUGIN example;
|
UNINSTALL PLUGIN example;
|
||||||
|
INSTALL PLUGIN example SONAME 'ha_example.so';
|
||||||
|
select @@session.sql_mode into @old_sql_mode;
|
||||||
|
set session sql_mode='';
|
||||||
|
set global example_ulong_var=500;
|
||||||
|
select @@global.example_ulong_var;
|
||||||
|
@@global.example_ulong_var
|
||||||
|
500
|
||||||
|
set global example_ulong_var=1111;
|
||||||
|
Warnings:
|
||||||
|
Warning 1292 Truncated incorrect ulong_var value: '1111'
|
||||||
|
select @@global.example_ulong_var;
|
||||||
|
@@global.example_ulong_var
|
||||||
|
1000
|
||||||
|
set session sql_mode='STRICT_ALL_TABLES';
|
||||||
|
set global example_ulong_var=500;
|
||||||
|
select @@global.example_ulong_var;
|
||||||
|
@@global.example_ulong_var
|
||||||
|
500
|
||||||
|
set global example_ulong_var=1111;
|
||||||
|
ERROR 42000: Variable 'ulong_var' can't be set to the value of '1111'
|
||||||
|
select @@global.example_ulong_var;
|
||||||
|
@@global.example_ulong_var
|
||||||
|
500
|
||||||
|
set session sql_mode=@old_sql_mode;
|
||||||
|
set session old=bla;
|
||||||
|
ERROR HY000: Variable 'old' is a read only variable
|
||||||
|
UNINSTALL PLUGIN example;
|
||||||
|
|
|
@ -39,3 +39,38 @@ SET GLOBAL example_enum_var= e2;
|
||||||
SET GLOBAL example_enum_var= impossible;
|
SET GLOBAL example_enum_var= impossible;
|
||||||
|
|
||||||
UNINSTALL PLUGIN example;
|
UNINSTALL PLUGIN example;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug #32757 hang with sql_mode set when setting some global variables
|
||||||
|
#
|
||||||
|
INSTALL PLUGIN example SONAME 'ha_example.so';
|
||||||
|
|
||||||
|
select @@session.sql_mode into @old_sql_mode;
|
||||||
|
|
||||||
|
# first, try normal sql_mode (no error, send OK)
|
||||||
|
set session sql_mode='';
|
||||||
|
set global example_ulong_var=500;
|
||||||
|
select @@global.example_ulong_var;
|
||||||
|
# overflow -- correct value, but throw warning
|
||||||
|
set global example_ulong_var=1111;
|
||||||
|
select @@global.example_ulong_var;
|
||||||
|
|
||||||
|
# now, try STRICT (error occurrs, no message is sent, so send default)
|
||||||
|
set session sql_mode='STRICT_ALL_TABLES';
|
||||||
|
set global example_ulong_var=500;
|
||||||
|
select @@global.example_ulong_var;
|
||||||
|
# overflow -- throw warning, do NOT change value
|
||||||
|
--error ER_WRONG_VALUE_FOR_VAR
|
||||||
|
set global example_ulong_var=1111;
|
||||||
|
select @@global.example_ulong_var;
|
||||||
|
|
||||||
|
set session sql_mode=@old_sql_mode;
|
||||||
|
|
||||||
|
# finally, show that conditions that already raised an error are not
|
||||||
|
# adversely affected (error was already sent, do nothing)
|
||||||
|
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
|
||||||
|
set session old=bla;
|
||||||
|
|
||||||
|
UNINSTALL PLUGIN example;
|
||||||
|
|
|
@ -123,7 +123,8 @@ static void fix_server_id(THD *thd, enum_var_type type);
|
||||||
static ulonglong fix_unsigned(THD *thd, ulonglong num,
|
static ulonglong fix_unsigned(THD *thd, ulonglong num,
|
||||||
const struct my_option *option_limits);
|
const struct my_option *option_limits);
|
||||||
static bool get_unsigned(THD *thd, set_var *var);
|
static bool get_unsigned(THD *thd, set_var *var);
|
||||||
static void throw_bounds_warning(THD *thd, const char *name, ulonglong num);
|
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);
|
static KEY_CACHE *create_key_cache(const char *name, uint length);
|
||||||
void fix_sql_mode_var(THD *thd, enum_var_type type);
|
void fix_sql_mode_var(THD *thd, enum_var_type type);
|
||||||
static uchar *get_error_count(THD *thd);
|
static uchar *get_error_count(THD *thd);
|
||||||
|
@ -1106,13 +1107,29 @@ static void fix_server_id(THD *thd, enum_var_type type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void throw_bounds_warning(THD *thd, const char *name, ulonglong num)
|
bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd,
|
||||||
|
const char *name, longlong val)
|
||||||
{
|
{
|
||||||
char buf[22];
|
if (fixed)
|
||||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
{
|
||||||
ER_TRUNCATED_WRONG_VALUE,
|
char buf[22];
|
||||||
ER(ER_TRUNCATED_WRONG_VALUE), name,
|
|
||||||
ullstr(num, buf));
|
if (unsignd)
|
||||||
|
ullstr((ulonglong) val, buf);
|
||||||
|
else
|
||||||
|
llstr(val, buf);
|
||||||
|
|
||||||
|
if (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES)
|
||||||
|
{
|
||||||
|
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buf);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
||||||
|
ER_TRUNCATED_WRONG_VALUE,
|
||||||
|
ER(ER_TRUNCATED_WRONG_VALUE), name, buf);
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ulonglong fix_unsigned(THD *thd, ulonglong num,
|
static ulonglong fix_unsigned(THD *thd, ulonglong num,
|
||||||
|
@ -1121,8 +1138,7 @@ static ulonglong fix_unsigned(THD *thd, ulonglong num,
|
||||||
bool fixed= FALSE;
|
bool fixed= FALSE;
|
||||||
ulonglong out= getopt_ull_limit_value(num, option_limits, &fixed);
|
ulonglong out= getopt_ull_limit_value(num, option_limits, &fixed);
|
||||||
|
|
||||||
if (fixed)
|
throw_bounds_warning(thd, fixed, TRUE, option_limits->name, (longlong) num);
|
||||||
throw_bounds_warning(thd, option_limits->name, num);
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1165,7 +1181,8 @@ bool sys_var_long_ptr_global::update(THD *thd, set_var *var)
|
||||||
if (tmp > ULONG_MAX)
|
if (tmp > ULONG_MAX)
|
||||||
{
|
{
|
||||||
tmp= ULONG_MAX;
|
tmp= ULONG_MAX;
|
||||||
throw_bounds_warning(thd, name, var->save_result.ulonglong_value);
|
throw_bounds_warning(thd, TRUE, TRUE, name,
|
||||||
|
(longlong) var->save_result.ulonglong_value);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
*value= (ulong) tmp;
|
*value= (ulong) tmp;
|
||||||
|
@ -1250,7 +1267,7 @@ bool sys_var_thd_ulong::update(THD *thd, set_var *var)
|
||||||
/* Don't use bigger value than given with --maximum-variable-name=.. */
|
/* Don't use bigger value than given with --maximum-variable-name=.. */
|
||||||
if ((ulong) tmp > max_system_variables.*offset)
|
if ((ulong) tmp > max_system_variables.*offset)
|
||||||
{
|
{
|
||||||
throw_bounds_warning(thd, name, tmp);
|
throw_bounds_warning(thd, TRUE, TRUE, name, (longlong) tmp);
|
||||||
tmp= max_system_variables.*offset;
|
tmp= max_system_variables.*offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1260,7 +1277,7 @@ bool sys_var_thd_ulong::update(THD *thd, set_var *var)
|
||||||
else if (tmp > ULONG_MAX)
|
else if (tmp > ULONG_MAX)
|
||||||
{
|
{
|
||||||
tmp= ULONG_MAX;
|
tmp= ULONG_MAX;
|
||||||
throw_bounds_warning(thd, name, var->save_result.ulonglong_value);
|
throw_bounds_warning(thd, TRUE, TRUE, name, (longlong) var->save_result.ulonglong_value);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -3185,6 +3185,18 @@ end_with_restore_list:
|
||||||
thd->one_shot_set|= lex->one_shot_set;
|
thd->one_shot_set|= lex->one_shot_set;
|
||||||
send_ok(thd);
|
send_ok(thd);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We encountered some sort of error, but no message was sent.
|
||||||
|
Send something semi-generic here since we don't know which
|
||||||
|
assignment in the list caused the error.
|
||||||
|
*/
|
||||||
|
if (!thd->is_error())
|
||||||
|
my_error(ER_WRONG_ARGUMENTS,MYF(0),"SET");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -210,6 +210,8 @@ static void reap_plugins(void);
|
||||||
|
|
||||||
/* declared in set_var.cc */
|
/* declared in set_var.cc */
|
||||||
extern sys_var *intern_find_sys_var(const char *str, uint length, bool no_error);
|
extern sys_var *intern_find_sys_var(const char *str, uint length, bool no_error);
|
||||||
|
extern bool throw_bounds_warning(THD *thd, bool fixed, bool unsignd,
|
||||||
|
const char *name, longlong val);
|
||||||
|
|
||||||
#ifdef EMBEDDED_LIBRARY
|
#ifdef EMBEDDED_LIBRARY
|
||||||
/* declared in sql_base.cc */
|
/* declared in sql_base.cc */
|
||||||
|
@ -1888,16 +1890,8 @@ static int check_func_int(THD *thd, struct st_mysql_sys_var *var,
|
||||||
else
|
else
|
||||||
*(int *)save= (int) getopt_ll_limit_value(tmp, &options, &fixed);
|
*(int *)save= (int) getopt_ll_limit_value(tmp, &options, &fixed);
|
||||||
|
|
||||||
if (fixed)
|
return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
|
||||||
{
|
var->name, (longlong) tmp);
|
||||||
char buf[22];
|
|
||||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
||||||
ER_TRUNCATED_WRONG_VALUE,
|
|
||||||
ER(ER_TRUNCATED_WRONG_VALUE), var->name,
|
|
||||||
ullstr(tmp, buf));
|
|
||||||
}
|
|
||||||
return (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) &&
|
|
||||||
(*(int *)save != (int) tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1916,16 +1910,8 @@ static int check_func_long(THD *thd, struct st_mysql_sys_var *var,
|
||||||
else
|
else
|
||||||
*(long *)save= (long) getopt_ll_limit_value(tmp, &options, &fixed);
|
*(long *)save= (long) getopt_ll_limit_value(tmp, &options, &fixed);
|
||||||
|
|
||||||
if (fixed)
|
return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
|
||||||
{
|
var->name, (longlong) tmp);
|
||||||
char buf[22];
|
|
||||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
||||||
ER_TRUNCATED_WRONG_VALUE,
|
|
||||||
ER(ER_TRUNCATED_WRONG_VALUE), var->name,
|
|
||||||
ullstr(tmp, buf));
|
|
||||||
}
|
|
||||||
return (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) &&
|
|
||||||
(*(long *)save != (long) tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1937,7 +1923,6 @@ static int check_func_longlong(THD *thd, struct st_mysql_sys_var *var,
|
||||||
struct my_option options;
|
struct my_option options;
|
||||||
value->val_int(value, &tmp);
|
value->val_int(value, &tmp);
|
||||||
plugin_opt_set_limits(&options, var);
|
plugin_opt_set_limits(&options, var);
|
||||||
*(ulonglong *)save= getopt_ull_limit_value(tmp, &options, &fixed);
|
|
||||||
|
|
||||||
if (var->flags & PLUGIN_VAR_UNSIGNED)
|
if (var->flags & PLUGIN_VAR_UNSIGNED)
|
||||||
*(ulonglong *)save= getopt_ull_limit_value((ulonglong) tmp, &options,
|
*(ulonglong *)save= getopt_ull_limit_value((ulonglong) tmp, &options,
|
||||||
|
@ -1945,16 +1930,8 @@ static int check_func_longlong(THD *thd, struct st_mysql_sys_var *var,
|
||||||
else
|
else
|
||||||
*(longlong *)save= getopt_ll_limit_value(tmp, &options, &fixed);
|
*(longlong *)save= getopt_ll_limit_value(tmp, &options, &fixed);
|
||||||
|
|
||||||
if (fixed)
|
return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED,
|
||||||
{
|
var->name, (longlong) tmp);
|
||||||
char buf[22];
|
|
||||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
|
|
||||||
ER_TRUNCATED_WRONG_VALUE,
|
|
||||||
ER(ER_TRUNCATED_WRONG_VALUE), var->name,
|
|
||||||
ullstr(tmp, buf));
|
|
||||||
}
|
|
||||||
return (thd->variables.sql_mode & MODE_STRICT_ALL_TABLES) &&
|
|
||||||
(*(long long *)save != tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_func_str(THD *thd, struct st_mysql_sys_var *var,
|
static int check_func_str(THD *thd, struct st_mysql_sys_var *var,
|
||||||
|
|
|
@ -849,6 +849,7 @@ struct st_mysql_storage_engine example_storage_engine=
|
||||||
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
|
{ MYSQL_HANDLERTON_INTERFACE_VERSION };
|
||||||
|
|
||||||
static ulong srv_enum_var= 0;
|
static ulong srv_enum_var= 0;
|
||||||
|
static ulong srv_ulong_var= 0;
|
||||||
|
|
||||||
const char *enum_var_names[]=
|
const char *enum_var_names[]=
|
||||||
{
|
{
|
||||||
|
@ -871,8 +872,21 @@ static MYSQL_SYSVAR_ENUM(
|
||||||
0, // def
|
0, // def
|
||||||
&enum_var_typelib); // typelib
|
&enum_var_typelib); // typelib
|
||||||
|
|
||||||
|
static MYSQL_SYSVAR_ULONG(
|
||||||
|
ulong_var,
|
||||||
|
srv_ulong_var,
|
||||||
|
PLUGIN_VAR_RQCMDARG,
|
||||||
|
"0..1000",
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
8,
|
||||||
|
0,
|
||||||
|
1000,
|
||||||
|
0);
|
||||||
|
|
||||||
static struct st_mysql_sys_var* example_system_variables[]= {
|
static struct st_mysql_sys_var* example_system_variables[]= {
|
||||||
MYSQL_SYSVAR(enum_var),
|
MYSQL_SYSVAR(enum_var),
|
||||||
|
MYSQL_SYSVAR(ulong_var),
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue