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.


mysql-test/r/plugin.result:
  show that on out-of-range values, plugin interface throws errors
  in STRICT mode and warnings otherwise.
mysql-test/t/plugin.test:
  show that on out-of-range values, plugin interface throws errors
  in STRICT mode and warnings otherwise.
sql/set_var.cc:
  - handle signedness of values used in warnings
  - in STRICT mode, throw errors rather than warnings
sql/sql_parse.cc:
  If sql_set_variables() returns with an error but no message
  was sent to the client, send a semi-generic one so the session
  won't hang and we won't fail silently.
sql/sql_plugin.cc:
  throw a warning if more than just block-size was corrected
  (or an error in STRICT mode). use functions from set_var
  for uniform behaviour of server- and plug-in variables.
storage/example/ha_example.cc:
  Add a ULONG system variable to example plugin so
  we can test integers in the plugin-interface without
  having to depend on the presence of innobase.
This commit is contained in:
unknown 2008-02-24 14:12:17 +01:00
commit 9bd3b8545a
6 changed files with 125 additions and 43 deletions

View file

@ -123,7 +123,8 @@ static void fix_server_id(THD *thd, enum_var_type type);
static ulonglong fix_unsigned(THD *thd, ulonglong num,
const struct my_option *option_limits);
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);
void fix_sql_mode_var(THD *thd, enum_var_type type);
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];
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE,
ER(ER_TRUNCATED_WRONG_VALUE), name,
ullstr(num, buf));
if (fixed)
{
char buf[22];
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,
@ -1121,8 +1138,7 @@ static ulonglong fix_unsigned(THD *thd, ulonglong num,
bool fixed= FALSE;
ulonglong out= getopt_ull_limit_value(num, option_limits, &fixed);
if (fixed)
throw_bounds_warning(thd, option_limits->name, num);
throw_bounds_warning(thd, fixed, TRUE, option_limits->name, (longlong) num);
return out;
}
@ -1165,7 +1181,8 @@ bool sys_var_long_ptr_global::update(THD *thd, set_var *var)
if (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
*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=.. */
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;
}
@ -1260,7 +1277,7 @@ bool sys_var_thd_ulong::update(THD *thd, set_var *var)
else if (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