diff options
-rw-r--r-- | include/my_getopt.h | 3 | ||||
-rw-r--r-- | include/mysql/plugin.h | 11 | ||||
-rw-r--r-- | mysql-test/r/plugin.result | 82 | ||||
-rw-r--r-- | mysql-test/t/plugin.test | 52 | ||||
-rw-r--r-- | mysys/my_getopt.c | 43 | ||||
-rw-r--r-- | sql/sql_plugin.cc | 61 | ||||
-rw-r--r-- | sql/sys_vars.h | 9 | ||||
-rw-r--r-- | storage/example/ha_example.cc | 31 |
8 files changed, 280 insertions, 12 deletions
diff --git a/include/my_getopt.h b/include/my_getopt.h index 04278c061a5..2b84267a237 100644 --- a/include/my_getopt.h +++ b/include/my_getopt.h @@ -120,6 +120,9 @@ double getopt_double_limit_value(double num, const struct my_option *optp, my_bool *fix); my_bool getopt_compare_strings(const char *s, const char *t, uint length); +ulonglong getopt_double2ulonglong(double); +double getopt_ulonglong2double(ulonglong); + C_MODE_END #endif /* _my_getopt_h */ diff --git a/include/mysql/plugin.h b/include/mysql/plugin.h index c8cdfe2a0b8..0dced1b5a53 100644 --- a/include/mysql/plugin.h +++ b/include/mysql/plugin.h @@ -163,6 +163,7 @@ typedef int (*mysql_show_var_func)(MYSQL_THD, struct st_mysql_show_var*, char *) #define PLUGIN_VAR_STR 0x0005 #define PLUGIN_VAR_ENUM 0x0006 #define PLUGIN_VAR_SET 0x0007 +#define PLUGIN_VAR_DOUBLE 0x0008 #define PLUGIN_VAR_UNSIGNED 0x0080 #define PLUGIN_VAR_THDLOCAL 0x0100 /* Variable is per-connection */ #define PLUGIN_VAR_READONLY 0x0200 /* Server variable is read only */ @@ -345,6 +346,11 @@ DECLARE_MYSQL_SYSVAR_TYPELIB(name, unsigned long long) = { \ PLUGIN_VAR_SET | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, &varname, def, typelib } +#define MYSQL_SYSVAR_DOUBLE(name, varname, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_SYSVAR_SIMPLE(name, double) = { \ + PLUGIN_VAR_DOUBLE | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, &varname, def, min, max, blk } + #define MYSQL_THDVAR_BOOL(name, opt, comment, check, update, def) \ DECLARE_MYSQL_THDVAR_BASIC(name, char) = { \ PLUGIN_VAR_BOOL | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ @@ -395,6 +401,11 @@ DECLARE_MYSQL_THDVAR_TYPELIB(name, unsigned long long) = { \ PLUGIN_VAR_SET | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ #name, comment, check, update, -1, def, NULL, typelib } +#define MYSQL_THDVAR_DOUBLE(name, opt, comment, check, update, def, min, max, blk) \ +DECLARE_MYSQL_THDVAR_SIMPLE(name, double) = { \ + PLUGIN_VAR_DOUBLE | PLUGIN_VAR_THDLOCAL | ((opt) & PLUGIN_VAR_MASK), \ + #name, comment, check, update, -1, def, min, max, blk, NULL } + /* accessor macros */ #define SYSVAR(name) \ diff --git a/mysql-test/r/plugin.result b/mysql-test/r/plugin.result index 0d5bc29fc8c..2b96dc4f3ac 100644 --- a/mysql-test/r/plugin.result +++ b/mysql-test/r/plugin.result @@ -16,9 +16,11 @@ set global example_ulong_var=500; set global example_enum_var= e1; show status like 'example%'; Variable_name Value -example_func_example enum_var is 0, ulong_var is 500, really +example_func_example enum_var is 0, ulong_var is 500, double_var is 8.500000, really show variables like 'example%'; Variable_name Value +example_double_thdvar 8.500000 +example_double_var 8.500000 example_enum_var e1 example_ulong_var 500 UNINSTALL PLUGIN example; @@ -63,3 +65,81 @@ set session sql_mode=@old_sql_mode; set session old=bla; ERROR HY000: Variable 'old' is a read only variable UNINSTALL PLUGIN example; +# +# Bug #16194302 SUPPORT FOR FLOATING-POINT SYSTEM +# VARIABLES USING THE PLUGIN INTERFACE. +# +INSTALL PLUGIN example SONAME 'ha_example.so'; +SET GLOBAL example_double_var = -0.1; +Warnings: +Warning 1292 Truncated incorrect example_double_var value: '-0.1' +SELECT @@GLOBAL.example_double_var; +@@GLOBAL.example_double_var +0.500000 +SET GLOBAL example_double_var = 0.000001; +Warnings: +Warning 1292 Truncated incorrect example_double_var value: '0.000001' +SELECT @@GLOBAL.example_double_var; +@@GLOBAL.example_double_var +0.500000 +SET GLOBAL example_double_var = 0.4; +Warnings: +Warning 1292 Truncated incorrect example_double_var value: '0.4' +SELECT @@GLOBAL.example_double_var; +@@GLOBAL.example_double_var +0.500000 +SET GLOBAL example_double_var = 123.456789; +SELECT @@GLOBAL.example_double_var; +@@GLOBAL.example_double_var +123.456789 +SET GLOBAL example_double_var = 500; +SELECT @@GLOBAL.example_double_var; +@@GLOBAL.example_double_var +500.000000 +SET GLOBAL example_double_var = 999.999999; +SELECT @@GLOBAL.example_double_var; +@@GLOBAL.example_double_var +999.999999 +SET GLOBAL example_double_var = 1000.51; +Warnings: +Warning 1292 Truncated incorrect example_double_var value: '1000.51' +SELECT @@GLOBAL.example_double_var; +@@GLOBAL.example_double_var +1000.500000 +SET SESSION example_double_thdvar = -0.1; +Warnings: +Warning 1292 Truncated incorrect example_double_thdvar value: '-0.1' +SELECT @@SESSION.example_double_thdvar; +@@SESSION.example_double_thdvar +0.500000 +SET SESSION example_double_thdvar = 0.000001; +Warnings: +Warning 1292 Truncated incorrect example_double_thdvar value: '0.000001' +SELECT @@SESSION.example_double_thdvar; +@@SESSION.example_double_thdvar +0.500000 +SET SESSION example_double_thdvar = 0.4; +Warnings: +Warning 1292 Truncated incorrect example_double_thdvar value: '0.4' +SELECT @@SESSION.example_double_thdvar; +@@SESSION.example_double_thdvar +0.500000 +SET SESSION example_double_thdvar = 123.456789; +SELECT @@SESSION.example_double_thdvar; +@@SESSION.example_double_thdvar +123.456789 +SET SESSION example_double_thdvar = 500; +SELECT @@SESSION.example_double_thdvar; +@@SESSION.example_double_thdvar +500.000000 +SET SESSION example_double_thdvar = 999.999999; +SELECT @@SESSION.example_double_thdvar; +@@SESSION.example_double_thdvar +999.999999 +SET SESSION example_double_thdvar = 1000.51; +Warnings: +Warning 1292 Truncated incorrect example_double_thdvar value: '1000.51' +SELECT @@SESSION.example_double_thdvar; +@@SESSION.example_double_thdvar +1000.500000 +UNINSTALL PLUGIN example; diff --git a/mysql-test/t/plugin.test b/mysql-test/t/plugin.test index 117eaf1e19b..f3a3b0cc068 100644 --- a/mysql-test/t/plugin.test +++ b/mysql-test/t/plugin.test @@ -85,3 +85,55 @@ set session sql_mode=@old_sql_mode; set session old=bla; UNINSTALL PLUGIN example; + +--echo # +--echo # Bug #16194302 SUPPORT FOR FLOATING-POINT SYSTEM +--echo # VARIABLES USING THE PLUGIN INTERFACE. +--echo # + +--replace_regex /\.dll/.so/ +eval INSTALL PLUGIN example SONAME '$EXAMPLE_PLUGIN'; + +SET GLOBAL example_double_var = -0.1; +SELECT @@GLOBAL.example_double_var; + +SET GLOBAL example_double_var = 0.000001; +SELECT @@GLOBAL.example_double_var; + +SET GLOBAL example_double_var = 0.4; +SELECT @@GLOBAL.example_double_var; + +SET GLOBAL example_double_var = 123.456789; +SELECT @@GLOBAL.example_double_var; + +SET GLOBAL example_double_var = 500; +SELECT @@GLOBAL.example_double_var; + +SET GLOBAL example_double_var = 999.999999; +SELECT @@GLOBAL.example_double_var; + +SET GLOBAL example_double_var = 1000.51; +SELECT @@GLOBAL.example_double_var; + +SET SESSION example_double_thdvar = -0.1; +SELECT @@SESSION.example_double_thdvar; + +SET SESSION example_double_thdvar = 0.000001; +SELECT @@SESSION.example_double_thdvar; + +SET SESSION example_double_thdvar = 0.4; +SELECT @@SESSION.example_double_thdvar; + +SET SESSION example_double_thdvar = 123.456789; +SELECT @@SESSION.example_double_thdvar; + +SET SESSION example_double_thdvar = 500; +SELECT @@SESSION.example_double_thdvar; + +SET SESSION example_double_thdvar = 999.999999; +SELECT @@SESSION.example_double_thdvar; + +SET SESSION example_double_thdvar = 1000.51; +SELECT @@SESSION.example_double_thdvar; + +UNINSTALL PLUGIN example; diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c index adee17ba3d1..8575fde0ca9 100644 --- a/mysys/my_getopt.c +++ b/mysys/my_getopt.c @@ -90,6 +90,35 @@ void my_getopt_register_get_addr(my_getopt_value func_addr) getopt_get_addr= func_addr; } +union ull_dbl +{ + ulonglong ull; + double dbl; +}; + +/** + Returns an ulonglong value containing a raw + representation of the given double value. +*/ +ulonglong getopt_double2ulonglong(double v) +{ + union ull_dbl u; + u.dbl= v; + compile_time_assert(sizeof(ulonglong) >= sizeof(double)); + return u.ull; +} + +/** + Returns the double value which corresponds to + the given raw representation. +*/ +double getopt_ulonglong2double(ulonglong v) +{ + union ull_dbl u; + u.ull= v; + return u.dbl; +} + /** Handle command line options. Sort options. @@ -1044,14 +1073,18 @@ double getopt_double_limit_value(double num, const struct my_option *optp, { my_bool adjusted= FALSE; double old= num; - if (optp->max_value && num > (double) optp->max_value) + double min, max; + + max= getopt_ulonglong2double(optp->max_value); + min= getopt_ulonglong2double(optp->min_value); + if (max && num > max) { - num= (double) optp->max_value; + num= max; adjusted= TRUE; } - if (num < (double) optp->min_value) + if (num < min) { - num= (double) optp->min_value; + num= min; adjusted= TRUE; } if (fix) @@ -1134,7 +1167,7 @@ static void init_one_value(const struct my_option *option, void *variable, *((ulonglong*) variable)= (ulonglong) value; break; case GET_DOUBLE: - *((double*) variable)= ulonglong2double(value); + *((double*) variable)= getopt_ulonglong2double(value); break; case GET_STR: /* diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 13623078265..25dbf6a61f3 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -2059,6 +2059,7 @@ typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_longlong_t, longlong); typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_uint_t, uint); typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_ulong_t, ulong); typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_ulonglong_t, ulonglong); +typedef DECLARE_MYSQL_SYSVAR_SIMPLE(sysvar_double_t, double); typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_int_t, int); typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_long_t, long); @@ -2066,6 +2067,7 @@ typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_longlong_t, longlong); typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_uint_t, uint); typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_ulong_t, ulong); typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_ulonglong_t, ulonglong); +typedef DECLARE_MYSQL_THDVAR_SIMPLE(thdvar_double_t, double); /**************************************************************************** @@ -2281,6 +2283,20 @@ err: return 1; } +static int check_func_double(THD *thd, struct st_mysql_sys_var *var, + void *save, st_mysql_value *value) +{ + double v; + my_bool fixed; + struct my_option option; + + value->val_real(value, &v); + plugin_opt_set_limits(&option, var); + *(double *) save= getopt_double_limit_value(v, &option, &fixed); + + return throw_bounds_warning(thd, var->name, fixed, v); +} + static void update_func_bool(THD *thd, struct st_mysql_sys_var *var, void *tgt, const void *save) @@ -2316,6 +2332,11 @@ static void update_func_str(THD *thd, struct st_mysql_sys_var *var, *(char **) tgt= *(char **) save; } +static void update_func_double(THD *thd, struct st_mysql_sys_var *var, + void *tgt, const void *save) +{ + *(double *) tgt= *(double *) save; +} /**************************************************************************** System Variables support @@ -2430,6 +2451,9 @@ static st_bookmark *register_var(const char *plugin, const char *name, case PLUGIN_VAR_STR: size= sizeof(char*); break; + case PLUGIN_VAR_DOUBLE: + size= sizeof(double); + break; default: DBUG_ASSERT(0); return NULL; @@ -2641,6 +2665,11 @@ static char **mysql_sys_var_str(THD* thd, int offset) return (char **) intern_sys_var_ptr(thd, offset, true); } +static double *mysql_sys_var_double(THD* thd, int offset) +{ + return (double *) intern_sys_var_ptr(thd, offset, true); +} + void plugin_thdvar_init(THD *thd) { plugin_ref old_table_plugin= thd->variables.table_plugin; @@ -2773,6 +2802,8 @@ static SHOW_TYPE pluginvar_show_type(st_mysql_sys_var *plugin_var) case PLUGIN_VAR_ENUM: case PLUGIN_VAR_SET: return SHOW_CHAR; + case PLUGIN_VAR_DOUBLE: + return SHOW_DOUBLE; default: DBUG_ASSERT(0); return SHOW_UNDEF; @@ -2923,6 +2954,8 @@ bool sys_var_pluginvar::check_update_type(Item_result type) case PLUGIN_VAR_BOOL: case PLUGIN_VAR_SET: return type != STRING_RESULT && type != INT_RESULT; + case PLUGIN_VAR_DOUBLE: + return type != INT_RESULT && type != REAL_RESULT && type != DECIMAL_RESULT; default: return true; } @@ -3048,6 +3081,9 @@ bool sys_var_pluginvar::global_update(THD *thd, set_var *var) case PLUGIN_VAR_STR: src= &((sysvar_str_t*) plugin_var)->def_val; break; + case PLUGIN_VAR_DOUBLE: + src= &((sysvar_double_t*) plugin_var)->def_val; + break; case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL: src= &((thdvar_uint_t*) plugin_var)->def_val; break; @@ -3069,6 +3105,9 @@ bool sys_var_pluginvar::global_update(THD *thd, set_var *var) case PLUGIN_VAR_STR | PLUGIN_VAR_THDLOCAL: src= &((thdvar_str_t*) plugin_var)->def_val; break; + case PLUGIN_VAR_DOUBLE | PLUGIN_VAR_THDLOCAL: + src= &((thdvar_double_t*) plugin_var)->def_val; + break; default: DBUG_ASSERT(0); } @@ -3092,6 +3131,13 @@ bool sys_var_pluginvar::global_update(THD *thd, set_var *var) options->max_value= (opt)->max_val; \ options->block_size= (long) (opt)->blk_sz +#define OPTION_SET_LIMITS_DOUBLE(options, opt) \ + options->var_type= GET_DOUBLE; \ + options->def_value= (longlong) getopt_double2ulonglong((opt)->def_val); \ + options->min_value= (longlong) getopt_double2ulonglong((opt)->min_val); \ + options->max_value= getopt_double2ulonglong((opt)->max_val); \ + options->block_size= (long) (opt)->blk_sz; + static void plugin_opt_set_limits(struct my_option *options, const struct st_mysql_sys_var *opt) @@ -3142,6 +3188,9 @@ static void plugin_opt_set_limits(struct my_option *options, GET_STR_ALLOC : GET_STR); options->def_value= (intptr) ((sysvar_str_t*) opt)->def_val; break; + case PLUGIN_VAR_DOUBLE: + OPTION_SET_LIMITS_DOUBLE(options, (sysvar_double_t*) opt); + break; /* threadlocal variables */ case PLUGIN_VAR_INT | PLUGIN_VAR_THDLOCAL: OPTION_SET_LIMITS(GET_INT, options, (thdvar_int_t*) opt); @@ -3161,6 +3210,9 @@ static void plugin_opt_set_limits(struct my_option *options, case PLUGIN_VAR_LONGLONG | PLUGIN_VAR_UNSIGNED | PLUGIN_VAR_THDLOCAL: OPTION_SET_LIMITS(GET_ULL, options, (thdvar_ulonglong_t*) opt); break; + case PLUGIN_VAR_DOUBLE | PLUGIN_VAR_THDLOCAL: + OPTION_SET_LIMITS_DOUBLE(options, (thdvar_double_t*) opt); + break; case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL: options->var_type= GET_ENUM; options->typelib= ((thdvar_enum_t*) opt)->typelib; @@ -3323,6 +3375,9 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, case PLUGIN_VAR_SET: ((thdvar_set_t *) opt)->resolve= mysql_sys_var_ulonglong; break; + case PLUGIN_VAR_DOUBLE: + ((thdvar_double_t *) opt)->resolve= mysql_sys_var_double; + break; default: sql_print_error("Unknown variable type code 0x%x in plugin '%s'.", opt->flags, plugin_name); @@ -3386,6 +3441,12 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, if (!opt->update) opt->update= update_func_longlong; break; + case PLUGIN_VAR_DOUBLE: + if (!opt->check) + opt->check= check_func_double; + if (!opt->update) + opt->update= update_func_double; + break; default: sql_print_error("Unknown variable type code 0x%x in plugin '%s'.", opt->flags, plugin_name); diff --git a/sql/sys_vars.h b/sql/sys_vars.h index ca6e7d40b0e..443e843bdde 100644 --- a/sql/sys_vars.h +++ b/sql/sys_vars.h @@ -729,13 +729,14 @@ public: const char *substitute=0, int parse_flag= PARSE_NORMAL) : sys_var(&all_sys_vars, name_arg, comment, flag_args, off, getopt.id, - getopt.arg_type, SHOW_DOUBLE, (longlong) double2ulonglong(def_val), + getopt.arg_type, SHOW_DOUBLE, + (longlong) getopt_double2ulonglong(def_val), lock, binlog_status_arg, on_check_func, on_update_func, substitute, parse_flag) { option.var_type= GET_DOUBLE; - option.min_value= (longlong) double2ulonglong(min_val); - option.max_value= (longlong) double2ulonglong(max_val); + option.min_value= (longlong) getopt_double2ulonglong(min_val); + option.max_value= (longlong) getopt_double2ulonglong(max_val); global_var(double)= (double)option.def_value; DBUG_ASSERT(min_val < max_val); DBUG_ASSERT(min_val <= def_val); @@ -767,7 +768,7 @@ public: 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; } + { var->save_result.double_value= getopt_ulonglong2double(option.def_value); } }; /** diff --git a/storage/example/ha_example.cc b/storage/example/ha_example.cc index c4ed4d5d2c2..68cd3fa2138 100644 --- a/storage/example/ha_example.cc +++ b/storage/example/ha_example.cc @@ -1004,6 +1004,7 @@ struct st_mysql_storage_engine example_storage_engine= static ulong srv_enum_var= 0; static ulong srv_ulong_var= 0; +static double srv_double_var= 0; const char *enum_var_names[]= { @@ -1038,9 +1039,34 @@ static MYSQL_SYSVAR_ULONG( 1000, 0); +static MYSQL_SYSVAR_DOUBLE( + double_var, + srv_double_var, + PLUGIN_VAR_RQCMDARG, + "0.500000..1000.500000", + NULL, + NULL, + 8.5, + 0.5, + 1000.5, + 0); // reserved always 0 + +static MYSQL_THDVAR_DOUBLE( + double_thdvar, + PLUGIN_VAR_RQCMDARG, + "0.500000..1000.500000", + NULL, + NULL, + 8.5, + 0.5, + 1000.5, + 0); + static struct st_mysql_sys_var* example_system_variables[]= { MYSQL_SYSVAR(enum_var), MYSQL_SYSVAR(ulong_var), + MYSQL_SYSVAR(double_var), + MYSQL_SYSVAR(double_thdvar), NULL }; @@ -1051,8 +1077,9 @@ static int show_func_example(MYSQL_THD thd, struct st_mysql_show_var *var, var->type= SHOW_CHAR; var->value= buf; // it's of SHOW_VAR_FUNC_BUFF_SIZE bytes my_snprintf(buf, SHOW_VAR_FUNC_BUFF_SIZE, - "enum_var is %lu, ulong_var is %lu, %.6b", // %b is MySQL extension - srv_enum_var, srv_ulong_var, "really"); + "enum_var is %lu, ulong_var is %lu, " + "double_var is %f, %.6b", // %b is a MySQL extension + srv_enum_var, srv_ulong_var, srv_double_var, "really"); return 0; } |