From: Tatjana A Nuernberg Date: February 24 2008 12:45pm Subject: bk commit into 5.1 tree (tnurnberg:1.2669) BUG#32757 List-Archive: http://lists.mysql.com/commits/42917 X-Bug: 32757 Message-Id: <200802241245.m1OCj7bN004155@white.intern.koehntopp.de> Below is the list of changes that have just been committed into a local 5.1 repository of tnurnberg. When tnurnberg does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository. For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html ChangeSet@stripped, 2008-02-24 13:45:01+01:00, tnurnberg@stripped +6 -0 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@stripped, 2008-02-24 13:45:00+01:00, tnurnberg@stripped +27 -0 show that on out-of-range values, plugin interface throws errors in STRICT mode and warnings otherwise. mysql-test/t/plugin.test@stripped, 2008-02-24 13:45:00+01:00, tnurnberg@stripped +35 -0 show that on out-of-range values, plugin interface throws errors in STRICT mode and warnings otherwise. sql/set_var.cc@stripped, 2008-02-24 13:45:00+01:00, tnurnberg@stripped +29 -12 - handle signedness of values used in warnings - in STRICT mode, throw errors rather than warnings sql/sql_parse.cc@stripped, 2008-02-24 13:45:00+01:00, tnurnberg@stripped +12 -0 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@stripped, 2008-02-24 13:45:00+01:00, tnurnberg@stripped +8 -30 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@stripped, 2008-02-24 13:45:00+01:00, tnurnberg@stripped +14 -0 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. diff -Nrup a/mysql-test/r/plugin.result b/mysql-test/r/plugin.result --- a/mysql-test/r/plugin.result 2007-11-14 10:48:18 +01:00 +++ b/mysql-test/r/plugin.result 2008-02-24 13:45:00 +01:00 @@ -27,3 +27,30 @@ SET GLOBAL example_enum_var= e2; SET GLOBAL example_enum_var= impossible; ERROR 42000: Variable 'enum_var' can't be set to the value of 'impossible' 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; diff -Nrup a/mysql-test/t/plugin.test b/mysql-test/t/plugin.test --- a/mysql-test/t/plugin.test 2007-11-14 10:48:17 +01:00 +++ b/mysql-test/t/plugin.test 2008-02-24 13:45:00 +01:00 @@ -39,3 +39,38 @@ SET GLOBAL example_enum_var= e2; SET GLOBAL example_enum_var= impossible; 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; diff -Nrup a/sql/set_var.cc b/sql/set_var.cc --- a/sql/set_var.cc 2008-01-10 18:44:20 +01:00 +++ b/sql/set_var.cc 2008-02-24 13:45:00 +01:00 @@ -123,7 +123,8 @@ static void fix_server_id(THD *thd, enum 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 } -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, 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 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, /* 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, 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 diff -Nrup a/sql/sql_parse.cc b/sql/sql_parse.cc --- a/sql/sql_parse.cc 2007-12-14 14:01:11 +01:00 +++ b/sql/sql_parse.cc 2008-02-24 13:45:00 +01:00 @@ -3185,6 +3185,18 @@ end_with_restore_list: thd->one_shot_set|= lex->one_shot_set; 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; } diff -Nrup a/sql/sql_plugin.cc b/sql/sql_plugin.cc --- a/sql/sql_plugin.cc 2007-12-13 12:49:55 +01:00 +++ b/sql/sql_plugin.cc 2008-02-24 13:45:00 +01:00 @@ -210,6 +210,8 @@ static void reap_plugins(void); /* declared in set_var.cc */ 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 /* declared in sql_base.cc */ @@ -1888,16 +1890,8 @@ static int check_func_int(THD *thd, stru else *(int *)save= (int) getopt_ll_limit_value(tmp, &options, &fixed); - if (fixed) - { - 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); + return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED, + var->name, (longlong) tmp); } @@ -1916,16 +1910,8 @@ static int check_func_long(THD *thd, str else *(long *)save= (long) getopt_ll_limit_value(tmp, &options, &fixed); - if (fixed) - { - 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); + return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED, + var->name, (longlong) tmp); } @@ -1945,16 +1931,8 @@ static int check_func_longlong(THD *thd, else *(longlong *)save= getopt_ll_limit_value(tmp, &options, &fixed); - if (fixed) - { - 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); + return throw_bounds_warning(thd, fixed, var->flags & PLUGIN_VAR_UNSIGNED, + var->name, (longlong) tmp); } static int check_func_str(THD *thd, struct st_mysql_sys_var *var, diff -Nrup a/storage/example/ha_example.cc b/storage/example/ha_example.cc --- a/storage/example/ha_example.cc 2007-11-14 10:48:15 +01:00 +++ b/storage/example/ha_example.cc 2008-02-24 13:45:00 +01:00 @@ -849,6 +849,7 @@ struct st_mysql_storage_engine example_s { MYSQL_HANDLERTON_INTERFACE_VERSION }; static ulong srv_enum_var= 0; +static ulong srv_ulong_var= 0; const char *enum_var_names[]= { @@ -871,8 +872,21 @@ static MYSQL_SYSVAR_ENUM( 0, // def &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[]= { MYSQL_SYSVAR(enum_var), + MYSQL_SYSVAR(ulong_var), NULL };