Merge branch 'PHP-5.5' into PHP-5.6

* PHP-5.5:
  Add NEWS
  Patch commit d9f85373e3 by moving the float_to_double function to a header file.
  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).
  5.5.22 now

Conflicts:
	configure.in
	main/php_version.h
This commit is contained in:
Keyur Govande 2015-01-07 22:50:55 +00:00
commit 90144c0d08
6 changed files with 107 additions and 88 deletions

View File

@ -33,6 +33,7 @@
#include "ext/standard/php_smart_str.h"
#include "php_mysqli_structs.h"
#include "mysqli_priv.h"
#include "ext/mysqlnd/mysql_float_to_double.h"
#if !defined(MYSQLI_USE_MYSQLND)
@ -413,8 +414,18 @@ mysqli_stmt_bind_result_do_bind(MY_STMT *stmt, zval ***args, unsigned int argc,
col_type = (stmt->stmt->fields) ? stmt->stmt->fields[ofs].type : MYSQL_TYPE_STRING;
switch (col_type) {
case MYSQL_TYPE_DOUBLE:
case MYSQL_TYPE_FLOAT:
convert_to_double_ex(args[i]);
stmt->result.buf[ofs].type = IS_DOUBLE;
stmt->result.buf[ofs].buflen = sizeof(float);
stmt->result.buf[ofs].val = (char *)emalloc(sizeof(float));
bind[ofs].buffer_type = MYSQL_TYPE_FLOAT;
bind[ofs].buffer = stmt->result.buf[ofs].val;
bind[ofs].is_null = &stmt->result.is_null[ofs];
break;
case MYSQL_TYPE_DOUBLE:
convert_to_double_ex(args[i]);
stmt->result.buf[ofs].type = IS_DOUBLE;
stmt->result.buf[ofs].buflen = sizeof(double);
@ -1053,8 +1064,22 @@ void mysqli_stmt_fetch_libmysql(INTERNAL_FUNCTION_PARAMETERS)
}
break;
case IS_DOUBLE:
ZVAL_DOUBLE(stmt->result.vars[i], *(double *)stmt->result.buf[i].val);
{
double dval;
if (stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_FLOAT) {
#ifndef NOT_FIXED_DEC
# define NOT_FIXED_DEC 31
#endif
dval = mysql_float_to_double(*(float *)stmt->result.buf[i].val,
(stmt->stmt->fields[i].decimals >= NOT_FIXED_DEC) ? -1 :
stmt->stmt->fields[i].decimals);
} else {
dval = *((double *)stmt->result.buf[i].val);
}
ZVAL_DOUBLE(stmt->result.vars[i], dval);
break;
}
case IS_STRING:
if (stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_LONGLONG
#if MYSQL_VERSION_ID > 50002

View File

@ -62,7 +62,7 @@ mysqli_close($link);
--EXPECT--
array(7) {
[0]=>
float(3.141593)
float(3.14159)
[1]=>
float(-1.0E-6)
[2]=>
@ -70,10 +70,10 @@ array(7) {
[3]=>
float(1.0E+12)
[4]=>
float(0.5646425)
float(0.564642)
[5]=>
float(1)
[6]=>
float(8.888889E+14)
float(8.88889E+14)
}
done!

View File

@ -36,19 +36,27 @@ mysqli_float_handling - ensure 4 byte float is handled correctly
die();
}
if (!mysqli_stmt_execute($stmt)) {
$id = null;
$fp4 = null;
$fp8 = null;
if (!mysqli_stmt_bind_result($stmt, $id, $fp4, $fp8)) {
printf("[006] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
die();
}
if (!($result = mysqli_stmt_get_result($stmt))) {
if (!mysqli_stmt_execute($stmt)) {
printf("[007] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
die();
}
$data = mysqli_fetch_assoc($result);
print $data['id'] . ": " . $data['fp4'] . ": " . $data['fp8'] . "\n";
if (!(mysqli_stmt_fetch($stmt))) {
printf("[008] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
die();
}
print $id . ": " . $fp4 . ": " . $fp8 . "\n";
?>
--CLEAN--
<?php

View File

@ -49,34 +49,3 @@ fi
if test "$PHP_MYSQLND" != "no" || test "$PHP_MYSQLND_ENABLED" = "yes" || test "$PHP_MYSQLI" != "no"; then
PHP_ADD_BUILD_DIR([ext/mysqlnd], 1)
fi
dnl
dnl Check if the compiler supports Decimal32/64/128 types from the IEEE-754 2008 version
dnl References: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1657.pdf
dnl http://speleotrove.com/decimal/
dnl
AC_CACHE_CHECK([whether whether compiler supports Decimal32/64/128 types], ac_cv_decimal_fp_supported,[
AC_TRY_RUN( [
#include <stdio.h>
#include <string.h>
int main(int argc, char **argv) {
typedef float dec32 __attribute__((mode(SD)));
dec32 k = 99.49f;
double d2 = (double)k;
const char *check_str = "99.49";
char print_str[32];
snprintf(print_str, 32, "%f", d2);
return memcmp(print_str, check_str, 5);
}
],[
ac_cv_decimal_fp_supported=yes
],[
ac_cv_decimal_fp_supported=no
],[
ac_cv_decimal_fp_supported=no
])])
if test "$ac_cv_decimal_fp_supported" = "yes"; then
AC_DEFINE(HAVE_DECIMAL_FP_SUPPORT, 1, [Define if the compiler supports Decimal32/64/128 types.])
fi

View File

@ -0,0 +1,60 @@
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2014 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Keyur Govande <kgovande@gmail.com> |
+----------------------------------------------------------------------+
*/
#ifndef MYSQL_FLOAT_TO_DOUBLE_H
#define MYSQL_FLOAT_TO_DOUBLE_H
#include "main/php.h"
#include <float.h>
#include "main/snprintf.h"
#define MAX_CHAR_BUF_LEN 255
#ifndef FLT_DIG
# define FLT_DIG 6
#endif
/*
* Convert from a 4-byte float to a 8-byte decimal by first converting
* the float to a string, and then the string to a double.
* The decimals argument specifies the precision of the output. If decimals
* is less than zero, then a gcvt(3) like logic is used with the significant
* digits set to FLT_DIG i.e. 6.
*/
static inline double mysql_float_to_double(float fp4, int decimals) {
char num_buf[MAX_CHAR_BUF_LEN]; /* Over allocated */
if (decimals < 0) {
php_gcvt(fp4, FLT_DIG, '.', 'e', num_buf);
} else {
php_sprintf(num_buf, "%.*f", decimals, fp4);
}
return zend_strtod(num_buf, NULL);
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
#endif /* MYSQL_FLOAT_TO_DOUBLE_H */

View File

@ -24,6 +24,7 @@
#include "mysqlnd_wireprotocol.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_debug.h"
#include "ext/mysqlnd/mysql_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 = mysql_float_to_double(fval, (field->decimals >= NOT_FIXED_DEC) ? -1 : field->decimals);
ZVAL_DOUBLE(zv, dval);
DBG_VOID_RETURN;