diff options
author | <Dao-Gang.Qu@sun.com> | 2010-01-12 20:07:09 +0800 |
---|---|---|
committer | <Dao-Gang.Qu@sun.com> | 2010-01-12 20:07:09 +0800 |
commit | b805e3d4d6ae5835ec5d6dcafc7ba4e65103f0b2 (patch) | |
tree | 81fd0ce6bdc321649671cd1240deb0d5b1248e49 /sql/field.cc | |
parent | d866afe56f670d5739112fee01c122584ff60145 (diff) | |
parent | e698ae01128fde4f82d4595e67a72cfac09ca125 (diff) | |
download | mariadb-git-b805e3d4d6ae5835ec5d6dcafc7ba4e65103f0b2.tar.gz |
Manual merge from next-mr.
Diffstat (limited to 'sql/field.cc')
-rw-r--r-- | sql/field.cc | 243 |
1 files changed, 30 insertions, 213 deletions
diff --git a/sql/field.cc b/sql/field.cc index 8e5fa682e9e..a07493a6964 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -31,9 +31,6 @@ #include "slave.h" // Pull in rpl_master_has_bug() #include <m_ctype.h> #include <errno.h> -#ifdef HAVE_FCONVERT -#include <floatingpoint.h> -#endif // Maximum allowed exponent value for converting string to decimal #define MAX_EXPONENT 1024 @@ -50,7 +47,7 @@ template class List_iterator<Create_field>; uchar Field_null::null[1]={1}; const char field_separator=','; -#define DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE 320 +#define DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE FLOATING_POINT_BUFFER #define LONGLONG_TO_STRING_CONVERSION_BUFFER_SIZE 128 #define DECIMAL_TO_STRING_CONVERSION_BUFFER_SIZE 128 #define BLOB_PACK_LENGTH_TO_MAX_LENGH(arg) \ @@ -2348,13 +2345,7 @@ int Field_decimal::store(double nr) char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; fyllchar = zerofill ? (char) '0' : (char) ' '; -#ifdef HAVE_SNPRINTF - buff[sizeof(buff)-1]=0; // Safety - snprintf(buff,sizeof(buff)-1, "%.*f",(int) dec,nr); - length= strlen(buff); -#else - length= my_sprintf(buff,(buff,"%.*f",dec,nr)); -#endif + length= my_fcvt(nr, dec, buff, NULL); if (length > field_length) { @@ -2767,17 +2758,6 @@ int Field_new_decimal::store(double nr) err= double2my_decimal(E_DEC_FATAL_ERROR & ~E_DEC_OVERFLOW, nr, &decimal_value); - /* - TODO: fix following when double2my_decimal when double2decimal - will return E_DEC_TRUNCATED always correctly - */ - if (!err) - { - double nr2; - my_decimal2double(E_DEC_FATAL_ERROR, &decimal_value, &nr2); - if (nr2 != nr) - err= E_DEC_TRUNCATED; - } if (err) { if (check_overflow(err)) @@ -4258,67 +4238,20 @@ String *Field_float::val_str(String *val_buffer, uint to_length=max(field_length,70); val_buffer->alloc(to_length); char *to=(char*) val_buffer->ptr(); + size_t len; if (dec >= NOT_FIXED_DEC) - { - sprintf(to,"%-*.*g",(int) field_length,FLT_DIG,nr); - to=strcend(to,' '); - *to=0; - } + len= my_gcvt(nr, MY_GCVT_ARG_FLOAT, to_length - 1, to, NULL); else { -#ifdef HAVE_FCONVERT - char buff[70],*pos=buff; - int decpt,sign,tmp_dec=dec; - - (void) sfconvert(&nr,tmp_dec,&decpt,&sign,buff); - if (sign) - { - *to++='-'; - } - if (decpt < 0) - { /* val_buffer is < 0 */ - *to++='0'; - if (!tmp_dec) - goto end; - *to++='.'; - if (-decpt > tmp_dec) - decpt= - (int) tmp_dec; - tmp_dec=(uint) ((int) tmp_dec+decpt); - while (decpt++ < 0) - *to++='0'; - } - else if (decpt == 0) - { - *to++= '0'; - if (!tmp_dec) - goto end; - *to++='.'; - } - else - { - while (decpt-- > 0) - *to++= *pos++; - if (!tmp_dec) - goto end; - *to++='.'; - } - while (tmp_dec--) - *to++= *pos++; -#else -#ifdef HAVE_SNPRINTF - to[to_length-1]=0; // Safety - snprintf(to,to_length-1,"%.*f",dec,nr); - to=strend(to); -#else - to+= my_sprintf(to,(to,"%.*f",dec,nr)); -#endif -#endif + /* + We are safe here because the buffer length is >= 70, and + fabs(float) < 10^39, dec < NOT_FIXED_DEC. So the resulting string + will be not longer than 69 chars + terminating '\0'. + */ + len= my_fcvt(nr, dec, to, NULL); } -#ifdef HAVE_FCONVERT - end: -#endif - val_buffer->length((uint) (to-val_buffer->ptr())); + val_buffer->length((uint) len); if (zerofill) prepend_zeros(val_buffer); return val_buffer; @@ -4506,8 +4439,12 @@ int Field_real::truncate(double *nr, double max_value) max_value*= log_10[order]; max_value-= 1.0 / log_10[dec]; - double tmp= rint((res - floor(res)) * log_10[dec]) / log_10[dec]; - res= floor(res) + tmp; + /* Check for infinity so we don't get NaN in calculations */ + if (!my_isinf(res)) + { + double tmp= rint((res - floor(res)) * log_10[dec]) / log_10[dec]; + res= floor(res) + tmp; + } } if (res < -max_value) @@ -4617,68 +4554,14 @@ String *Field_double::val_str(String *val_buffer, uint to_length=max(field_length, DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE); val_buffer->alloc(to_length); char *to=(char*) val_buffer->ptr(); + size_t len; if (dec >= NOT_FIXED_DEC) - { - sprintf(to,"%-*.*g",(int) field_length,DBL_DIG,nr); - to=strcend(to,' '); - } + len= my_gcvt(nr, MY_GCVT_ARG_DOUBLE, to_length - 1, to, NULL); else - { -#ifdef HAVE_FCONVERT - char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; - char *pos= buff; - int decpt,sign,tmp_dec=dec; - - (void) fconvert(nr,tmp_dec,&decpt,&sign,buff); - if (sign) - { - *to++='-'; - } - if (decpt < 0) - { /* val_buffer is < 0 */ - *to++='0'; - if (!tmp_dec) - goto end; - *to++='.'; - if (-decpt > tmp_dec) - decpt= - (int) tmp_dec; - tmp_dec=(uint) ((int) tmp_dec+decpt); - while (decpt++ < 0) - *to++='0'; - } - else if (decpt == 0) - { - *to++= '0'; - if (!tmp_dec) - goto end; - *to++='.'; - } - else - { - while (decpt-- > 0) - *to++= *pos++; - if (!tmp_dec) - goto end; - *to++='.'; - } - while (tmp_dec--) - *to++= *pos++; -#else -#ifdef HAVE_SNPRINTF - to[to_length-1]=0; // Safety - snprintf(to,to_length-1,"%.*f",dec,nr); - to=strend(to); -#else - to+= my_sprintf(to,(to,"%.*f",dec,nr)); -#endif -#endif - } -#ifdef HAVE_FCONVERT - end: -#endif + len= my_fcvt(nr, dec, to, NULL); - val_buffer->length((uint) (to-val_buffer->ptr())); + val_buffer->length((uint) len); if (zerofill) prepend_zeros(val_buffer); return val_buffer; @@ -6475,84 +6358,18 @@ int Field_str::store(double nr) { ASSERT_COLUMN_MARKED_FOR_WRITE; char buff[DOUBLE_TO_STRING_CONVERSION_BUFFER_SIZE]; - uint length; uint local_char_length= field_length / charset()->mbmaxlen; - double anr= fabs(nr); - bool fractional= (anr != floor(anr)); - int neg= (nr < 0.0) ? 1 : 0; - uint max_length; - int exp; - uint digits; - uint i; - - /* Calculate the exponent from the 'e'-format conversion */ - if (anr < 1.0 && anr > 0) - { - for (exp= 0; anr < 1e-100; exp-= 100, anr*= 1e100) ; - for (; anr < 1e-10; exp-= 10, anr*= 1e10) ; - for (i= 1; anr < 1 / log_10[i]; exp--, i++) ; - exp--; - } - else - { - for (exp= 0; anr > 1e100; exp+= 100, anr/= 1e100) ; - for (; anr > 1e10; exp+= 10, anr/= 1e10) ; - for (i= 1; anr > log_10[i]; exp++, i++) ; - } - - max_length= local_char_length - neg; - - /* - Since in sprintf("%g") precision means the number of significant digits, - calculate the maximum number of significant digits if the 'f'-format - would be used (+1 for decimal point if the number has a fractional part). - */ - digits= max(1, (int) max_length - fractional); - /* - If the exponent is negative, decrease digits by the number of leading zeros - after the decimal point that do not count as significant digits. - */ - if (exp < 0) - digits= max(1, (int) digits + exp); - /* - 'e'-format is used only if the exponent is less than -4 or greater than or - equal to the precision. In this case we need to adjust the number of - significant digits to take "e+NN" + decimal point into account (hence -5). - We also have to reserve one additional character if abs(exp) >= 100. - */ - if (exp >= (int) digits || exp < -4) - digits= max(1, (int) (max_length - 5 - (exp >= 100 || exp <= -100))); - - /* Limit precision to DBL_DIG to avoid garbage past significant digits */ - set_if_smaller(digits, DBL_DIG); - - length= (uint) my_sprintf(buff, (buff, "%-.*g", digits, nr)); + size_t length; + my_bool error; -#ifdef __WIN__ - /* - Windows always zero-pads the exponent to 3 digits, we want to remove the - leading 0 to match the sprintf() output on other platforms. - */ - if ((exp >= (int) digits || exp < -4) && exp > -100 && exp < 100) + length= my_gcvt(nr, MY_GCVT_ARG_DOUBLE, local_char_length, buff, &error); + if (error) { - DBUG_ASSERT(length >= 6); /* 1e+NNN */ - uint tmp= length - 3; - buff[tmp]= buff[tmp + 1]; - tmp++; - buff[tmp]= buff[tmp + 1]; - length--; + if (table->in_use->abort_on_warning) + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_DATA_TOO_LONG, 1); + else + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, WARN_DATA_TRUNCATED, 1); } -#endif - - /* - +1 below is because "precision" in %g above means the - max. number of significant digits, not the output width. - Thus the width can be larger than number of significant digits by 1 - (for decimal point) - the test for local_char_length < 5 is for extreme cases, - like inserting 500.0 in char(1) - */ - DBUG_ASSERT(local_char_length < 5 || length <= local_char_length+1); return store(buff, length, charset()); } @@ -7634,7 +7451,7 @@ oom_error: int Field_blob::store(double nr) { CHARSET_INFO *cs=charset(); - value.set_real(nr, 2, cs); + value.set_real(nr, NOT_FIXED_DEC, cs); return Field_blob::store(value.ptr(),(uint) value.length(), cs); } |