diff options
author | Alexey Kopytov <Alexey.Kopytov@Sun.com> | 2009-12-22 19:23:13 +0300 |
---|---|---|
committer | Alexey Kopytov <Alexey.Kopytov@Sun.com> | 2009-12-22 19:23:13 +0300 |
commit | f02525be8346b7426f1640fb168a7451d38b1641 (patch) | |
tree | 40437c602d2a9ddaa03a54742cec4884f0974253 /sql | |
parent | 5bce1e06429c3d58457051f0c439f130609df375 (diff) | |
download | mariadb-git-f02525be8346b7426f1640fb168a7451d38b1641.tar.gz |
Backport of WL #2934: Make/find library for doing float/double
to string conversions and vice versa"
Initial import of the dtoa.c code and custom wrappers around it
to allow its usage from the server code.
Conversion of FLOAT/DOUBLE values to DECIMAL ones or strings
and vice versa has been significantly reworked. As the new
algoritms are more precise than the older ones, results of such
conversions may not always match those obtained from older
server versions. This in turn may break compatibility for some
applications.
This patch also fixes the following bugs:
- bug #12860 "Difference in zero padding of exponent between
Unix and Windows"
- bug #21497 "DOUBLE truncated to unusable value"
- bug #26788 "mysqld (debug) aborts when inserting specific
numbers into char fields"
- bug #24541 "Data truncated..." on decimal type columns
without any good reason"
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 243 | ||||
-rw-r--r-- | sql/item.cc | 13 | ||||
-rw-r--r-- | sql/log_event.cc | 6 | ||||
-rw-r--r-- | sql/mysql_priv.h | 1 | ||||
-rw-r--r-- | sql/mysqld.cc | 65 | ||||
-rw-r--r-- | sql/spatial.cc | 23 | ||||
-rw-r--r-- | sql/sql_show.cc | 3 | ||||
-rw-r--r-- | sql/sql_string.cc | 80 | ||||
-rw-r--r-- | sql/unireg.h | 1 |
9 files changed, 118 insertions, 317 deletions
diff --git a/sql/field.cc b/sql/field.cc index 0934bb04ccd..56da32959f9 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) \ @@ -2304,13 +2301,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) { @@ -2723,17 +2714,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)) @@ -4231,67 +4211,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; @@ -4479,8 +4412,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) @@ -4590,68 +4527,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; @@ -6448,84 +6331,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()); } @@ -7601,7 +7418,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); } diff --git a/sql/item.cc b/sql/item.cc index f4b2e549667..8416f53d77f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -5259,9 +5259,7 @@ int Item_null::save_safe_in_field(Field *field) int Item::save_in_field(Field *field, bool no_conversions) { int error; - if (result_type() == STRING_RESULT || - (result_type() == REAL_RESULT && - field->result_type() == STRING_RESULT)) + if (result_type() == STRING_RESULT) { String *result; CHARSET_INFO *cs= collation.collation; @@ -5280,6 +5278,15 @@ int Item::save_in_field(Field *field, bool no_conversions) error=field->store(result->ptr(),result->length(),cs); str_value.set_quick(0, 0, cs); } + else if (result_type() == REAL_RESULT && + field->result_type() == STRING_RESULT) + { + double nr= val_real(); + if (null_value) + return set_field_to_null_with_conversions(field, no_conversions); + field->set_notnull(); + error= field->store(nr); + } else if (result_type() == REAL_RESULT) { double nr= val_real(); diff --git a/sql/log_event.cc b/sql/log_event.cc index 9cfa6cf1540..8985d396b3a 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -5355,11 +5355,11 @@ void User_var_log_event::pack_info(Protocol* protocol) case REAL_RESULT: double real_val; float8get(real_val, val); - if (!(buf= (char*) my_malloc(val_offset + FLOATING_POINT_BUFFER, + if (!(buf= (char*) my_malloc(val_offset + MY_GCVT_MAX_FIELD_WIDTH + 1, MYF(MY_WME)))) return; - event_len+= my_sprintf(buf + val_offset, - (buf + val_offset, "%.14g", real_val)); + event_len+= my_gcvt(real_val, MY_GCVT_ARG_DOUBLE, MY_GCVT_MAX_FIELD_WIDTH, + buf + val_offset, NULL); break; case INT_RESULT: if (!(buf= (char*) my_malloc(val_offset + 22, MYF(MY_WME)))) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3ddaf114673..d4cf1bd2c63 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1939,6 +1939,7 @@ extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN]; extern char pidfile_name[FN_REFLEN], system_time_zone[30], *opt_init_file; extern char default_logfile_name[FN_REFLEN]; extern char log_error_file[FN_REFLEN], *opt_tc_log_file; +extern const double log_10[309]; extern ulonglong log_10_int[20]; extern ulonglong keybuff_size; extern ulonglong thd_startup_options; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 826e8a6c980..fe7f85f82d2 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -212,7 +212,36 @@ inline void setup_fpu() /* Set FPU rounding mode to "round-to-nearest" */ fesetround(FE_TONEAREST); #endif /* HAVE_FESETROUND */ - + + /* + x86 (32-bit) requires FPU precision to be explicitly set to 64 bit for + portable results of floating point operations + */ +#if defined(__i386__) +#if defined(_WIN32) +#if !defined(_WIN64) + _control87(_PC_53, MCW_PC); +#endif /* !_WIN64 */ +#else /* !_WIN32 */ +#if !defined(HAVE_FPU_CONTROL_H) +#define fpu_control_t unsigned int +#define _FPU_EXTENDED 0x300 +#define _FPU_DOUBLE 0x200 +#if defined(__GNUC__) +#define _FPU_GETCW(cw) __asm__ __volatile__("fnstcw %0" : "=m" (*&cw)) +#define _FPU_SETCW(cw) __asm__ __volatile__("fldcw %0" : : "m" (*&cw)) +#else /* !__GNUC__ */ +#define _FPU_GETCW(cw) (cw= 0) +#define _FPU_SETCW(cw) +#endif /* __GNUC__ */ +#endif /* !HAVE_FPU_CONTROL_H */ + fpu_control_t cw; + _FPU_GETCW(cw); + cw= (cw & ~_FPU_EXTENDED) | _FPU_DOUBLE; + _FPU_SETCW(cw); +#endif /* _WIN32 && */ +#endif /* __i386__ */ + #if defined(__sgi) && defined(HAVE_SYS_FPU_H) /* Enable denormalized DOUBLE values support for IRIX */ union fpc_csr n; @@ -575,6 +604,40 @@ ulong expire_logs_days = 0; ulong rpl_recovery_rank=0; const char *log_output_str= "FILE"; +const double log_10[] = { + 1e000, 1e001, 1e002, 1e003, 1e004, 1e005, 1e006, 1e007, 1e008, 1e009, + 1e010, 1e011, 1e012, 1e013, 1e014, 1e015, 1e016, 1e017, 1e018, 1e019, + 1e020, 1e021, 1e022, 1e023, 1e024, 1e025, 1e026, 1e027, 1e028, 1e029, + 1e030, 1e031, 1e032, 1e033, 1e034, 1e035, 1e036, 1e037, 1e038, 1e039, + 1e040, 1e041, 1e042, 1e043, 1e044, 1e045, 1e046, 1e047, 1e048, 1e049, + 1e050, 1e051, 1e052, 1e053, 1e054, 1e055, 1e056, 1e057, 1e058, 1e059, + 1e060, 1e061, 1e062, 1e063, 1e064, 1e065, 1e066, 1e067, 1e068, 1e069, + 1e070, 1e071, 1e072, 1e073, 1e074, 1e075, 1e076, 1e077, 1e078, 1e079, + 1e080, 1e081, 1e082, 1e083, 1e084, 1e085, 1e086, 1e087, 1e088, 1e089, + 1e090, 1e091, 1e092, 1e093, 1e094, 1e095, 1e096, 1e097, 1e098, 1e099, + 1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109, + 1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119, + 1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129, + 1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139, + 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, + 1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159, + 1e160, 1e161, 1e162, 1e163, 1e164, 1e165, 1e166, 1e167, 1e168, 1e169, + 1e170, 1e171, 1e172, 1e173, 1e174, 1e175, 1e176, 1e177, 1e178, 1e179, + 1e180, 1e181, 1e182, 1e183, 1e184, 1e185, 1e186, 1e187, 1e188, 1e189, + 1e190, 1e191, 1e192, 1e193, 1e194, 1e195, 1e196, 1e197, 1e198, 1e199, + 1e200, 1e201, 1e202, 1e203, 1e204, 1e205, 1e206, 1e207, 1e208, 1e209, + 1e210, 1e211, 1e212, 1e213, 1e214, 1e215, 1e216, 1e217, 1e218, 1e219, + 1e220, 1e221, 1e222, 1e223, 1e224, 1e225, 1e226, 1e227, 1e228, 1e229, + 1e230, 1e231, 1e232, 1e233, 1e234, 1e235, 1e236, 1e237, 1e238, 1e239, + 1e240, 1e241, 1e242, 1e243, 1e244, 1e245, 1e246, 1e247, 1e248, 1e249, + 1e250, 1e251, 1e252, 1e253, 1e254, 1e255, 1e256, 1e257, 1e258, 1e259, + 1e260, 1e261, 1e262, 1e263, 1e264, 1e265, 1e266, 1e267, 1e268, 1e269, + 1e270, 1e271, 1e272, 1e273, 1e274, 1e275, 1e276, 1e277, 1e278, 1e279, + 1e280, 1e281, 1e282, 1e283, 1e284, 1e285, 1e286, 1e287, 1e288, 1e289, + 1e290, 1e291, 1e292, 1e293, 1e294, 1e295, 1e296, 1e297, 1e298, 1e299, + 1e300, 1e301, 1e302, 1e303, 1e304, 1e305, 1e306, 1e307, 1e308 +}; + time_t server_start_time, flush_status_time; char mysql_home[FN_REFLEN], pidfile_name[FN_REFLEN], system_time_zone[30]; diff --git a/sql/spatial.cc b/sql/spatial.cc index 9114c81514d..671b8544b8a 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -17,28 +17,7 @@ #ifdef HAVE_SPATIAL -/* - exponential notation : - 1 sign - 1 number before the decimal point - 1 decimal point - 14 number of significant digits (see String::qs_append(double)) - 1 'e' sign - 1 exponent sign - 3 exponent digits - == - 22 - - "f" notation : - 1 optional 0 - 1 sign - 14 number significant digits (see String::qs_append(double) ) - 1 decimal point - == - 17 -*/ - -#define MAX_DIGITS_IN_DOUBLE 22 +#define MAX_DIGITS_IN_DOUBLE MY_GCVT_MAX_FIELD_WIDTH /***************************** Gis_class_info *******************************/ diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bf92717e79d..4774a91a9bf 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2166,7 +2166,8 @@ static bool show_status_array(THD *thd, const char *wild, value= ((char *) status_var + (ulong) value); /* fall through */ case SHOW_DOUBLE: - end= buff + my_sprintf(buff, (buff, "%f", *(double*) value)); + /* 6 is the default precision for '%f' in sprintf() */ + end= buff + my_fcvt(*(double *) value, 6, buff, NULL); break; case SHOW_LONG_STATUS: value= ((char *) status_var + (ulong) value); diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 40040ab0934..e4e51aba622 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -24,10 +24,6 @@ #include <m_string.h> #include <m_ctype.h> #include <mysql_com.h> -#ifdef HAVE_FCONVERT -#include <floatingpoint.h> -#endif - /* The following extern declarations are ok as these are interface functions required by the string function @@ -107,82 +103,19 @@ bool String::set_int(longlong num, bool unsigned_flag, CHARSET_INFO *cs) bool String::set_real(double num,uint decimals, CHARSET_INFO *cs) { - char buff[331]; + char buff[FLOATING_POINT_BUFFER]; uint dummy_errors; + size_t len; str_charset=cs; if (decimals >= NOT_FIXED_DEC) { - uint32 len= my_sprintf(buff,(buff, "%.15g",num));// Enough for a DATETIME + len= my_gcvt(num, MY_GCVT_ARG_DOUBLE, sizeof(buff) - 1, buff, NULL); return copy(buff, len, &my_charset_latin1, cs, &dummy_errors); } -#ifdef HAVE_FCONVERT - int decpt,sign; - char *pos,*to; - - (void) fconvert(num,(int) decimals,&decpt,&sign,buff+1); - if (!my_isdigit(&my_charset_latin1, buff[1])) - { // Nan or Inf - pos=buff+1; - if (sign) - { - buff[0]='-'; - pos=buff; - } - uint dummy_errors; - return copy(pos,(uint32) strlen(pos), &my_charset_latin1, cs, &dummy_errors); - } - if (alloc((uint32) ((uint32) decpt+3+decimals))) - return TRUE; - to=Ptr; - if (sign) - *to++='-'; - - pos=buff+1; - if (decpt < 0) - { /* value is < 0 */ - *to++='0'; - if (!decimals) - goto end; - *to++='.'; - if ((uint32) -decpt > decimals) - decpt= - (int) decimals; - decimals=(uint32) ((int) decimals+decpt); - while (decpt++ < 0) - *to++='0'; - } - else if (decpt == 0) - { - *to++= '0'; - if (!decimals) - goto end; - *to++='.'; - } - else - { - while (decpt-- > 0) - *to++= *pos++; - if (!decimals) - goto end; - *to++='.'; - } - while (decimals--) - *to++= *pos++; - -end: - *to=0; - str_length=(uint32) (to-Ptr); - return FALSE; -#else -#ifdef HAVE_SNPRINTF - buff[sizeof(buff)-1]=0; // Safety - snprintf(buff,sizeof(buff)-1, "%.*f",(int) decimals,num); -#else - sprintf(buff,"%.*f",(int) decimals,num); -#endif - return copy(buff,(uint32) strlen(buff), &my_charset_latin1, cs, + len= my_fcvt(num, decimals, buff, NULL); + return copy(buff, (uint32) len, &my_charset_latin1, cs, &dummy_errors); -#endif } @@ -661,7 +594,8 @@ void String::qs_append(const char *str, uint32 len) void String::qs_append(double d) { char *buff = Ptr + str_length; - str_length+= my_sprintf(buff, (buff, "%.15g", d)); + str_length+= my_gcvt(d, MY_GCVT_ARG_DOUBLE, FLOATING_POINT_BUFFER - 1, buff, + NULL); } void String::qs_append(double *d) diff --git a/sql/unireg.h b/sql/unireg.h index 80c6ad23907..b6f81f48987 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -213,7 +213,6 @@ */ #define BIN_LOG_HEADER_SIZE 4 -#define FLOATING_POINT_BUFFER 331 #define DEFAULT_KEY_CACHE_NAME "default" |