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

Decimal field fix overflow

parent bac793e2
...@@ -41,6 +41,11 @@ ...@@ -41,6 +41,11 @@
#include <floatingpoint.h> #include <floatingpoint.h>
#endif #endif
// Maximum allowed exponent value for converting string to decimal
#define MAX_EXPONENT 1024
/***************************************************************************** /*****************************************************************************
Instansiate templates and static variables Instansiate templates and static variables
*****************************************************************************/ *****************************************************************************/
...@@ -367,7 +372,6 @@ void Field_decimal::store(const char *from,uint len) ...@@ -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") */ /* The pointer where the field value starts (i.e., "where to write") */
char *to=ptr; char *to=ptr;
uint tmp_dec, tmp_uint; uint tmp_dec, tmp_uint;
ulonglong tmp_ulonglong;
/* /*
The sign of the number : will be 0 (means positive but sign not The sign of the number : will be 0 (means positive but sign not
specified), '+' or '-' specified), '+' or '-'
...@@ -381,8 +385,7 @@ void Field_decimal::store(const char *from,uint len) ...@@ -381,8 +385,7 @@ void Field_decimal::store(const char *from,uint len)
const char *frac_digits_from, *frac_digits_end; const char *frac_digits_from, *frac_digits_end;
/* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */ /* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */
char expo_sign_char=0; char expo_sign_char=0;
uint exponent=0; // value of the exponent uint exponent=0; // value of the exponent
ulonglong exponent_ulonglong=0;
/* /*
Pointers used when digits move from the left of the '.' to the Pointers used when digits move from the left of the '.' to the
right of the '.' (explained below) right of the '.' (explained below)
...@@ -485,14 +488,13 @@ void Field_decimal::store(const char *from,uint len) ...@@ -485,14 +488,13 @@ void Field_decimal::store(const char *from,uint len)
*/ */
for (;from!=end && isdigit(*from); from++) for (;from!=end && isdigit(*from); from++)
{ {
exponent_ulonglong=10*exponent_ulonglong+(ulonglong)(*from-'0'); exponent=10*exponent+(*from-'0');
if (exponent_ulonglong>(ulonglong)UINT_MAX) if (exponent>MAX_EXPONENT)
{ {
exponent_ulonglong=(ulonglong)UINT_MAX; exponent=MAX_EXPONENT;
break; break;
} }
} }
exponent=(uint)(exponent_ulonglong);
} }
/* /*
...@@ -534,21 +536,21 @@ void Field_decimal::store(const char *from,uint len) ...@@ -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 as int_digits_added_zeros<=exponent<4G and
(ulonglong)(int_digits_end-int_digits_from)<=max_allowed_packet<=2G 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 (ulonglong)(frac_digits_from-int_digits_tail_from)<=max_allowed_packet<=2G
*/ */
if (!expo_sign_char) 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 == '-') else if (expo_sign_char == '-')
{ {
tmp_uint=min(exponent,(uint)(int_digits_end-int_digits_from)); tmp_uint=min(exponent,(uint)(int_digits_end-int_digits_from));
frac_digits_added_zeros=exponent-tmp_uint; frac_digits_added_zeros=exponent-tmp_uint;
int_digits_end -= tmp_uint; int_digits_end -= tmp_uint;
frac_digits_head_end=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=='+') else // (expo_sign_char=='+')
{ {
...@@ -575,9 +577,9 @@ void Field_decimal::store(const char *from,uint len) ...@@ -575,9 +577,9 @@ void Field_decimal::store(const char *from,uint len)
int_digits_added_zeros=0; int_digits_added_zeros=0;
} }
} }
tmp_ulonglong=(ulonglong)tmp_dec+(ulonglong)(int_digits_end-int_digits_from) tmp_uint=tmp_dec+(int_digits_end-int_digits_from)
+(ulonglong)(frac_digits_from-int_digits_tail_from)+ +(uint)(frac_digits_from-int_digits_tail_from)+
(ulonglong)int_digits_added_zeros; int_digits_added_zeros;
} }
/* /*
...@@ -588,7 +590,7 @@ void Field_decimal::store(const char *from,uint len) ...@@ -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 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 //the rightmost sum above cannot overflow
{ {
// too big number, change to max or min number // too big number, change to max or min number
...@@ -596,11 +598,6 @@ void Field_decimal::store(const char *from,uint len) ...@@ -596,11 +598,6 @@ void Field_decimal::store(const char *from,uint len)
return; 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 Tmp_left_pos is the position where the leftmost digit of
the int_% parts will be written 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