Commit 043ea441 authored by peter@mysql.com's avatar peter@mysql.com

Decimal field fix overflow

parent bac793e2
......@@ -41,6 +41,11 @@
#include <floatingpoint.h>
#endif
// Maximum allowed exponent value for converting string to decimal
#define MAX_EXPONENT 1024
/*****************************************************************************
Instansiate templates and static variables
*****************************************************************************/
......@@ -367,7 +372,6 @@ void Field_decimal::store(const char *from,uint len)
/* The pointer where the field value starts (i.e., "where to write") */
char *to=ptr;
uint tmp_dec, tmp_uint;
ulonglong tmp_ulonglong;
/*
The sign of the number : will be 0 (means positive but sign not
specified), '+' or '-'
......@@ -381,8 +385,7 @@ void Field_decimal::store(const char *from,uint len)
const char *frac_digits_from, *frac_digits_end;
/* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */
char expo_sign_char=0;
uint exponent=0; // value of the exponent
ulonglong exponent_ulonglong=0;
uint exponent=0; // value of the exponent
/*
Pointers used when digits move from the left of the '.' to the
right of the '.' (explained below)
......@@ -485,14 +488,13 @@ void Field_decimal::store(const char *from,uint len)
*/
for (;from!=end && isdigit(*from); from++)
{
exponent_ulonglong=10*exponent_ulonglong+(ulonglong)(*from-'0');
if (exponent_ulonglong>(ulonglong)UINT_MAX)
exponent=10*exponent+(*from-'0');
if (exponent>MAX_EXPONENT)
{
exponent_ulonglong=(ulonglong)UINT_MAX;
exponent=MAX_EXPONENT;
break;
}
}
exponent=(uint)(exponent_ulonglong);
}
/*
......@@ -534,21 +536,21 @@ void Field_decimal::store(const char *from,uint len)
*/
/*
Below tmp_ulongulong cannot overflow,
Below tmp_uint cannot overflow with small enough MAX_EXPONENT setting,
as int_digits_added_zeros<=exponent<4G and
(ulonglong)(int_digits_end-int_digits_from)<=max_allowed_packet<=2G and
(ulonglong)(frac_digits_from-int_digits_tail_from)<=max_allowed_packet<=2G
*/
if (!expo_sign_char)
tmp_ulonglong=(ulonglong)tmp_dec+(ulonglong)(int_digits_end-int_digits_from);
tmp_uint=tmp_dec+(uint)(int_digits_end-int_digits_from);
else if (expo_sign_char == '-')
{
tmp_uint=min(exponent,(uint)(int_digits_end-int_digits_from));
frac_digits_added_zeros=exponent-tmp_uint;
int_digits_end -= tmp_uint;
frac_digits_head_end=int_digits_end+tmp_uint;
tmp_ulonglong=(ulonglong)tmp_dec+(ulonglong)(int_digits_end-int_digits_from);
tmp_uint=tmp_dec+(uint)(int_digits_end-int_digits_from);
}
else // (expo_sign_char=='+')
{
......@@ -575,9 +577,9 @@ void Field_decimal::store(const char *from,uint len)
int_digits_added_zeros=0;
}
}
tmp_ulonglong=(ulonglong)tmp_dec+(ulonglong)(int_digits_end-int_digits_from)
+(ulonglong)(frac_digits_from-int_digits_tail_from)+
(ulonglong)int_digits_added_zeros;
tmp_uint=tmp_dec+(int_digits_end-int_digits_from)
+(uint)(frac_digits_from-int_digits_tail_from)+
int_digits_added_zeros;
}
/*
......@@ -588,7 +590,7 @@ void Field_decimal::store(const char *from,uint len)
If the sign is defined and '-', we need one position for it
*/
if ((ulonglong)field_length < tmp_ulonglong + (ulonglong) (sign_char == '-'))
if (field_length < tmp_uint + (sign_char == '-'))
//the rightmost sum above cannot overflow
{
// too big number, change to max or min number
......@@ -596,11 +598,6 @@ void Field_decimal::store(const char *from,uint len)
return;
}
/*
If the above test was ok, then tmp_ulonglong<4G and the following cast is valid
*/
tmp_uint=(uint)tmp_ulonglong;
/*
Tmp_left_pos is the position where the leftmost digit of
the int_% parts will be written
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment