Fix for bugs #68114 (Build fails on OS X due to undefined symbols)

and #68657 (Reading 4 byte floats with Mysqli and libmysqlclient
has rounding errors).

The patch removes support for Decimal floating point numbers and
now defaults to using similar logic as what libmysqlclient does:
convert a 4 byte floating point number into a string, and then the
string into a double. The quirks of MySQL are maintained as seen in
Field_Float::val_str()
This commit is contained in:
Keyur Govande 2015-01-06 06:33:38 +00:00
parent 3f1d1892c9
commit f2eadb93b9
9 changed files with 140 additions and 90 deletions

View file

@ -24,6 +24,7 @@
#include "mysqlnd_wireprotocol.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_debug.h"
#include "ext/standard/float_to_double.h"
#define MYSQLND_SILENT
@ -181,55 +182,11 @@ ps_fetch_float(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_l
(*row)+= 4;
DBG_INF_FMT("value=%f", fval);
/*
* The following is needed to correctly support 4-byte floats.
* Otherwise, a value of 9.99 in a FLOAT column comes out of mysqli
* as 9.9998998641968.
*
* For GCC, we use the built-in decimal support to "up-convert" a
* 4-byte float to a 8-byte double.
* When that is not available, we fall back to converting the float
* to a string and then converting the string to a double. This mimics
* what MySQL does.
*/
#ifdef HAVE_DECIMAL_FP_SUPPORT
{
typedef float dec32 __attribute__((mode(SD)));
/* volatile so the compiler will not optimize away the conversion */
volatile dec32 d32val = fval;
/* The following cast is guaranteed to do the right thing */
dval = (double) d32val;
}
#elif defined(PHP_WIN32)
{
/* float datatype on Winows is already 4 byte but has a precision of 7 digits */
char num_buf[2048];
(void)_gcvt_s(num_buf, 2048, fval, field->decimals >= 31 ? 7 : field->decimals);
dval = zend_strtod(num_buf, NULL);
}
#else
{
char num_buf[2048]; /* Over allocated */
char *s;
#ifndef FLT_DIG
# define FLT_DIG 6
#ifndef NOT_FIXED_DEC
# define NOT_FIXED_DEC 31
#endif
/* Convert to string. Ignoring localization, etc.
* Following MySQL's rules. If precision is undefined (NOT_FIXED_DEC i.e. 31)
* or larger than 31, the value is limited to 6 (FLT_DIG).
*/
s = php_gcvt(fval,
field->decimals >= 31 ? FLT_DIG : field->decimals,
'.',
'e',
num_buf);
/* And now convert back to double */
dval = zend_strtod(s, NULL);
}
#endif
dval = float_to_double(fval, (field->decimals >= NOT_FIXED_DEC) ? -1 : field->decimals);
ZVAL_DOUBLE(zv, dval);
DBG_VOID_RETURN;