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

Decimal field fix overflow

parent bac793e2
Loading
Loading
Loading
Loading
+16 −19
Original line number Diff line number Diff line
@@ -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 '-'
@@ -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 '-' */
  char expo_sign_char=0;
  uint exponent=0;                                // value of the exponent
  ulonglong exponent_ulonglong=0;
  /*
    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