Skip to content

Commit d6e66b6

Browse files
author
kaa@polly.local
committed
Merge polly.local:/home/kaa/src/maint/bug28121/my50-bug28121
into polly.local:/home/kaa/src/maint/bug28121/my51-bug28121
2 parents b4b44b0 + 8ac1ffd commit d6e66b6

File tree

10 files changed

+200
-134
lines changed

10 files changed

+200
-134
lines changed

include/m_string.h

+4
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ extern char *stpcpy(char *, const char *); /* For AIX with gcc 2.95.3 */
9292
extern char NEAR _dig_vec_upper[];
9393
extern char NEAR _dig_vec_lower[];
9494

95+
/* Defined in strtod.c */
96+
extern const double log_10[310];
97+
extern const double log_01[310];
98+
9599
#ifdef BAD_STRING_COMPILER
96100
#define strmov(A,B) (memccpy(A,B,0,INT_MAX)-1)
97101
#else

mysql-test/r/type_float.result

+33
Original file line numberDiff line numberDiff line change
@@ -344,3 +344,36 @@ create table t1 (s1 float(0,2));
344344
ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 's1').
345345
create table t1 (s1 float(1,2));
346346
ERROR 42000: For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column 's1').
347+
create table t1 (f1 double(200, 0));
348+
insert into t1 values (1e199), (-1e199);
349+
insert into t1 values (1e200), (-1e200);
350+
insert into t1 values (2e200), (-2e200);
351+
Warnings:
352+
Warning 1264 Out of range value adjusted for column 'f1' at row 1
353+
Warning 1264 Out of range value adjusted for column 'f1' at row 2
354+
select f1 + 0e0 from t1;
355+
f1 + 0e0
356+
1e+199
357+
-1e+199
358+
1e+200
359+
-1e+200
360+
1e+200
361+
-1e+200
362+
drop table t1;
363+
create table t1 (f1 float(30, 0));
364+
insert into t1 values (1e29), (-1e29);
365+
insert into t1 values (1e30), (-1e30);
366+
insert into t1 values (2e30), (-2e30);
367+
Warnings:
368+
Warning 1264 Out of range value adjusted for column 'f1' at row 1
369+
Warning 1264 Out of range value adjusted for column 'f1' at row 2
370+
select f1 + 0e0 from t1;
371+
f1 + 0e0
372+
1.0000000150475e+29
373+
-1.0000000150475e+29
374+
1.0000000150475e+30
375+
-1.0000000150475e+30
376+
1.0000000150475e+30
377+
-1.0000000150475e+30
378+
drop table t1;
379+
End of 5.0 tests

mysql-test/t/type_float.test

+20
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,23 @@ drop table t1;
222222
create table t1 (s1 float(0,2));
223223
--error 1427
224224
create table t1 (s1 float(1,2));
225+
226+
#
227+
# Bug #28121 "INSERT or UPDATE into DOUBLE(200,0) field being truncated to 31 digits"
228+
#
229+
230+
create table t1 (f1 double(200, 0));
231+
insert into t1 values (1e199), (-1e199);
232+
insert into t1 values (1e200), (-1e200);
233+
insert into t1 values (2e200), (-2e200);
234+
select f1 + 0e0 from t1;
235+
drop table t1;
236+
237+
create table t1 (f1 float(30, 0));
238+
insert into t1 values (1e29), (-1e29);
239+
insert into t1 values (1e30), (-1e30);
240+
insert into t1 values (2e30), (-2e30);
241+
select f1 + 0e0 from t1;
242+
drop table t1;
243+
244+
--echo End of 5.0 tests

sql/field.cc

+60-91
Original file line numberDiff line numberDiff line change
@@ -3769,56 +3769,9 @@ int Field_float::store(const char *from,uint len,CHARSET_INFO *cs)
37693769
int Field_float::store(double nr)
37703770
{
37713771
ASSERT_COLUMN_MARKED_FOR_WRITE;
3772-
float j;
3773-
int error= 0;
3772+
int error= truncate(&nr, FLT_MAX);
3773+
float j= nr;
37743774

3775-
if (isnan(nr))
3776-
{
3777-
j= 0;
3778-
set_null();
3779-
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
3780-
error= 1;
3781-
}
3782-
else if (unsigned_flag && nr < 0)
3783-
{
3784-
j= 0;
3785-
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
3786-
error= 1;
3787-
}
3788-
else
3789-
{
3790-
double max_value;
3791-
if (dec >= NOT_FIXED_DEC)
3792-
{
3793-
max_value= FLT_MAX;
3794-
}
3795-
else
3796-
{
3797-
uint tmp=min(field_length,array_elements(log_10)-1);
3798-
max_value= (log_10[tmp]-1)/log_10[dec];
3799-
/*
3800-
The following comparison is needed to not get an overflow if nr
3801-
is close to FLT_MAX
3802-
*/
3803-
if (fabs(nr) < FLT_MAX/10.0e+32)
3804-
nr= floor(nr*log_10[dec]+0.5)/log_10[dec];
3805-
}
3806-
if (nr < -max_value)
3807-
{
3808-
j= (float)-max_value;
3809-
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
3810-
error= 1;
3811-
}
3812-
else if (nr > max_value)
3813-
{
3814-
j= (float)max_value;
3815-
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
3816-
error= 1;
3817-
}
3818-
else
3819-
j= (float) nr;
3820-
}
3821-
38223775
#ifdef WORDS_BIGENDIAN
38233776
if (table->s->db_low_byte_first)
38243777
{
@@ -4062,48 +4015,7 @@ int Field_double::store(const char *from,uint len,CHARSET_INFO *cs)
40624015
int Field_double::store(double nr)
40634016
{
40644017
ASSERT_COLUMN_MARKED_FOR_WRITE;
4065-
int error= 0;
4066-
4067-
if (isnan(nr))
4068-
{
4069-
nr= 0;
4070-
set_null();
4071-
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
4072-
error= 1;
4073-
}
4074-
else if (unsigned_flag && nr < 0)
4075-
{
4076-
nr= 0;
4077-
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
4078-
error= 1;
4079-
}
4080-
else
4081-
{
4082-
double max_value;
4083-
if (not_fixed)
4084-
{
4085-
max_value= DBL_MAX;
4086-
}
4087-
else
4088-
{
4089-
uint tmp=min(field_length,array_elements(log_10)-1);
4090-
max_value= (log_10[tmp]-1)/log_10[dec];
4091-
if (fabs(nr) < DBL_MAX/10.0e+32)
4092-
nr= floor(nr*log_10[dec]+0.5)/log_10[dec];
4093-
}
4094-
if (nr < -max_value)
4095-
{
4096-
nr= -max_value;
4097-
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
4098-
error= 1;
4099-
}
4100-
else if (nr > max_value)
4101-
{
4102-
nr= max_value;
4103-
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
4104-
error= 1;
4105-
}
4106-
}
4018+
int error= truncate(&nr, DBL_MAX);
41074019

41084020
#ifdef WORDS_BIGENDIAN
41094021
if (table->s->db_low_byte_first)
@@ -4123,6 +4035,63 @@ int Field_double::store(longlong nr, bool unsigned_val)
41234035
(double) nr);
41244036
}
41254037

4038+
/*
4039+
If a field has fixed length, truncate the double argument pointed to by 'nr'
4040+
appropriately.
4041+
Also ensure that the argument is within [-max_value; max_value] range.
4042+
*/
4043+
4044+
int Field_real::truncate(double *nr, double max_value)
4045+
{
4046+
int error= 1;
4047+
double res= *nr;
4048+
4049+
if (isnan(res))
4050+
{
4051+
res= 0;
4052+
set_null();
4053+
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
4054+
goto end;
4055+
}
4056+
else if (unsigned_flag && res < 0)
4057+
{
4058+
res= 0;
4059+
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
4060+
goto end;
4061+
}
4062+
4063+
if (!not_fixed)
4064+
{
4065+
uint order= field_length - dec;
4066+
uint step= array_elements(log_10) - 1;
4067+
max_value= 1.0;
4068+
for (; order > step; order-= step)
4069+
max_value*= log_10[step];
4070+
max_value*= log_10[order];
4071+
max_value-= 1.0 / log_10[dec];
4072+
4073+
double tmp= rint((res - floor(res)) * log_10[dec]) / log_10[dec];
4074+
res= floor(res) + tmp;
4075+
}
4076+
4077+
if (res < -max_value)
4078+
{
4079+
res= -max_value;
4080+
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
4081+
}
4082+
else if (res > max_value)
4083+
{
4084+
res= max_value;
4085+
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_OUT_OF_RANGE, 1);
4086+
}
4087+
else
4088+
error= 0;
4089+
4090+
end:
4091+
*nr= res;
4092+
return error;
4093+
}
4094+
41264095

41274096
int Field_real::store_decimal(const my_decimal *dm)
41284097
{

sql/field.h

+10-10
Original file line numberDiff line numberDiff line change
@@ -530,15 +530,19 @@ class Field_longstr :public Field_str
530530
/* base class for float and double and decimal (old one) */
531531
class Field_real :public Field_num {
532532
public:
533+
my_bool not_fixed;
534+
533535
Field_real(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
534536
uchar null_bit_arg, utype unireg_check_arg,
535537
const char *field_name_arg,
536538
uint8 dec_arg, bool zero_arg, bool unsigned_arg)
537539
:Field_num(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
538-
field_name_arg, dec_arg, zero_arg, unsigned_arg)
540+
field_name_arg, dec_arg, zero_arg, unsigned_arg),
541+
not_fixed(dec_arg >= NOT_FIXED_DEC)
539542
{}
540543
int store_decimal(const my_decimal *);
541544
my_decimal *val_decimal(my_decimal *);
545+
int truncate(double *nr, double max_length);
542546
uint32 max_display_length() { return field_length; }
543547
};
544548

@@ -823,28 +827,24 @@ class Field_float :public Field_real {
823827

824828
class Field_double :public Field_real {
825829
public:
826-
my_bool not_fixed;
827830
Field_double(char *ptr_arg, uint32 len_arg, uchar *null_ptr_arg,
828831
uchar null_bit_arg,
829832
enum utype unireg_check_arg, const char *field_name_arg,
830833
uint8 dec_arg,bool zero_arg,bool unsigned_arg)
831834
:Field_real(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
832835
unireg_check_arg, field_name_arg,
833-
dec_arg, zero_arg, unsigned_arg),
834-
not_fixed(dec_arg >= NOT_FIXED_DEC)
836+
dec_arg, zero_arg, unsigned_arg)
835837
{}
836838
Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
837839
uint8 dec_arg)
838840
:Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0,
839-
NONE, field_name_arg, dec_arg, 0, 0),
840-
not_fixed(dec_arg >= NOT_FIXED_DEC)
841+
NONE, field_name_arg, dec_arg, 0, 0)
841842
{}
842843
Field_double(uint32 len_arg, bool maybe_null_arg, const char *field_name_arg,
843-
uint8 dec_arg, my_bool not_fixed_srg)
844+
uint8 dec_arg, my_bool not_fixed_arg)
844845
:Field_real((char*) 0, len_arg, maybe_null_arg ? (uchar*) "" : 0, (uint) 0,
845-
NONE, field_name_arg, dec_arg, 0, 0),
846-
not_fixed(not_fixed_srg)
847-
{}
846+
NONE, field_name_arg, dec_arg, 0, 0)
847+
{not_fixed= not_fixed_arg; }
848848
enum_field_types type() const { return MYSQL_TYPE_DOUBLE;}
849849
enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; }
850850
int store(const char *to,uint length,CHARSET_INFO *charset);

sql/init.cc

-13
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121

2222
void unireg_init(ulong options)
2323
{
24-
uint i;
25-
double nr;
2624
DBUG_ENTER("unireg_init");
2725

2826
MYSYS_PROGRAM_DONT_USE_CURSES();
@@ -40,16 +38,5 @@ void unireg_init(ulong options)
4038
VOID(strmov(reg_ext,".frm"));
4139
reg_ext_length= 4;
4240
specialflag=SPECIAL_SAME_DB_NAME | options; /* Set options from argv */
43-
/* Make a tab of powers of 10 */
44-
for (i=0,nr=1.0; i < array_elements(log_10) ; i++)
45-
{ /* It's used by filesort... */
46-
log_10[i]= nr ; nr*= 10.0;
47-
}
48-
/* Make a tab of powers of 0.1 */
49-
for (i= 0, nr= 0.1; i < array_elements(log_01); i++)
50-
{
51-
log_01[i]= nr;
52-
nr*= 0.1;
53-
}
5441
DBUG_VOID_RETURN;
5542
}

sql/item_cmpfunc.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
560560
{
561561
if ((*a)->decimals < NOT_FIXED_DEC && (*b)->decimals < NOT_FIXED_DEC)
562562
{
563-
precision= 5 * log_01[max((*a)->decimals, (*b)->decimals)];
563+
precision= 5 * log_01[max((*a)->decimals, (*b)->decimals) + 1];
564564
if (func == &Arg_comparator::compare_real)
565565
func= &Arg_comparator::compare_real_fixed;
566566
else if (func == &Arg_comparator::compare_e_real)

sql/mysql_priv.h

-2
Original file line numberDiff line numberDiff line change
@@ -1621,8 +1621,6 @@ extern uint reg_ext_length;
16211621
extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
16221622
extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file;
16231623
extern char log_error_file[FN_REFLEN], *opt_tc_log_file;
1624-
extern double log_10[32];
1625-
extern double log_01[32];
16261624
extern ulonglong log_10_int[20];
16271625
extern ulonglong keybuff_size;
16281626
extern ulonglong thd_startup_options;

sql/mysqld.cc

-2
Original file line numberDiff line numberDiff line change
@@ -512,8 +512,6 @@ ulong expire_logs_days = 0;
512512
ulong rpl_recovery_rank=0;
513513
const char *log_output_str= "TABLE";
514514

515-
double log_10[32]; /* 10 potences */
516-
double log_01[32];
517515
time_t server_start_time;
518516

519517
char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], system_time_zone[30];

0 commit comments

Comments
 (0)