Permalink
Browse files

The fractional part of the def, min and max values of system variables

is ignored.

Allow the default, minimum and maximum values of system variables of
type double to have a meaningful fractional part. Since the command-line
option parsing interface (my_getopt) uses fields of type unsigned long
long (ull) to store these values, the double values were being stored in
a lossy way that discards the fractional part.

This change introduces a couple of functions that can be used to store
the raw representation of a double value in the raw bits of unsigned
long long field in a way that the binary representation remains the
same. Using these function the real value can be converted back and
forth between the types.
  • Loading branch information...
1 parent 9cca1d8 commit 1b9de642d95963c24885a28751411f1c5be88aad Davi Arnaut committed Jan 2, 2013
Showing with 92 additions and 21 deletions.
  1. +3 −0 include/my_getopt.h
  2. +22 −6 mysql-test/r/plugin.result
  3. +9 −0 mysql-test/t/plugin.test
  4. +39 −5 mysys/my_getopt.c
  5. +10 −2 sql/sql_plugin.cc
  6. +6 −5 sql/sys_vars.h
  7. +3 −3 storage/example/ha_example.cc
View
@@ -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 */
@@ -16,10 +16,10 @@ 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, double_var is 8.000000, 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_var 8.000000
+example_double_var 8.500000
example_enum_var e1
example_ulong_var 500
UNINSTALL PLUGIN example;
@@ -69,11 +69,23 @@ Warnings:
Warning 1292 Truncated incorrect example_double_var value: '-0.1'
SELECT @@GLOBAL.example_double_var;
@@GLOBAL.example_double_var
-0.000000
+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.000001
+0.500000
+SET GLOBAL example_double_var = 0.5;
+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
@@ -87,9 +99,13 @@ SELECT @@GLOBAL.example_double_var;
@@GLOBAL.example_double_var
999.999999
SET GLOBAL example_double_var = 1000.1;
+SELECT @@GLOBAL.example_double_var;
+@@GLOBAL.example_double_var
+1000.100000
+SET GLOBAL example_double_var = 1000.51;
Warnings:
-Warning 1292 Truncated incorrect example_double_var value: '1000.1'
+Warning 1292 Truncated incorrect example_double_var value: '1000.51'
SELECT @@GLOBAL.example_double_var;
@@GLOBAL.example_double_var
-1000.000000
+1000.500000
UNINSTALL PLUGIN example;
@@ -91,6 +91,12 @@ 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 = 0.5;
+SELECT @@GLOBAL.example_double_var;
+
SET GLOBAL example_double_var = 123.456789;
SELECT @@GLOBAL.example_double_var;
@@ -103,4 +109,7 @@ SELECT @@GLOBAL.example_double_var;
SET GLOBAL example_double_var = 1000.1;
SELECT @@GLOBAL.example_double_var;
+SET GLOBAL example_double_var = 1000.51;
+SELECT @@GLOBAL.example_double_var;
+
UNINSTALL PLUGIN example;
View
@@ -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,19 @@ 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 max, min;
+
+ 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 +1168,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:
/*
View
@@ -3135,6 +3135,14 @@ bool sys_var_pluginvar::global_update(THD *thd, set_var *var)
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)
{
@@ -3162,7 +3170,7 @@ static void plugin_opt_set_limits(struct my_option *options,
OPTION_SET_LIMITS(GET_ULL, options, (sysvar_ulonglong_t*) opt);
break;
case PLUGIN_VAR_DOUBLE:
- OPTION_SET_LIMITS(GET_DOUBLE, options, (sysvar_double_t*) opt);
+ OPTION_SET_LIMITS_DOUBLE(options, (sysvar_double_t*) opt);
break;
case PLUGIN_VAR_ENUM:
options->var_type= GET_ENUM;
@@ -3207,7 +3215,7 @@ static void plugin_opt_set_limits(struct my_option *options,
OPTION_SET_LIMITS(GET_ULL, options, (thdvar_ulonglong_t*) opt);
break;
case PLUGIN_VAR_DOUBLE | PLUGIN_VAR_THDLOCAL:
- OPTION_SET_LIMITS(GET_DOUBLE, options, (thdvar_double_t*) opt);
+ OPTION_SET_LIMITS_DOUBLE(options, (thdvar_double_t*) opt);
break;
case PLUGIN_VAR_ENUM | PLUGIN_VAR_THDLOCAL:
options->var_type= GET_ENUM;
View
@@ -771,14 +771,15 @@ class Sys_var_double: public sys_var
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);
- global_var(double)= (double)option.def_value;
+ option.min_value= (longlong) getopt_double2ulonglong(min_val);
+ option.max_value= (longlong) getopt_double2ulonglong(max_val);
+ global_var(double)= def_val;
DBUG_ASSERT(min_val < max_val);
DBUG_ASSERT(min_val <= def_val);
DBUG_ASSERT(max_val >= def_val);
@@ -809,7 +810,7 @@ class Sys_var_double: public sys_var
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); }
};
/**
@@ -1046,9 +1046,9 @@ static MYSQL_SYSVAR_DOUBLE(
"0.0..1000.0",
NULL,
NULL,
- 8.0,
- 0.0,
- 1000.0,
+ 8.5,
+ 0.5,
+ 1000.5,
0);
static struct st_mysql_sys_var* example_system_variables[]= {

0 comments on commit 1b9de64

Please sign in to comment.