mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Decimal field fix overflow
This commit is contained in:
33
sql/field.cc
33
sql/field.cc
@ -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)
|
|||||||
/* 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 '-'
|
||||||
@ -382,7 +386,6 @@ void Field_decimal::store(const char *from,uint len)
|
|||||||
/* 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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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
|
||||||
|
Reference in New Issue
Block a user