Skip to content

Commit 961da40

Browse files
committed
Merge branch 'PHP-5.6'
* PHP-5.6: Add NEWS Add NEWS Patch commit d9f8537 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: ext/mysqli/mysqli_api.c
2 parents 3e826c9 + 39f8960 commit 961da40

File tree

6 files changed

+107
-89
lines changed

6 files changed

+107
-89
lines changed

ext/mysqli/mysqli_api.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "zend_smart_str.h"
3434
#include "php_mysqli_structs.h"
3535
#include "mysqli_priv.h"
36+
#include "ext/mysqlnd/mysql_float_to_double.h"
3637

3738

3839
#if !defined(MYSQLI_USE_MYSQLND)
@@ -413,8 +414,17 @@ mysqli_stmt_bind_result_do_bind(MY_STMT *stmt, zval *args, unsigned int argc, un
413414
col_type = (stmt->stmt->fields) ? stmt->stmt->fields[ofs].type : MYSQL_TYPE_STRING;
414415

415416
switch (col_type) {
416-
case MYSQL_TYPE_DOUBLE:
417417
case MYSQL_TYPE_FLOAT:
418+
stmt->result.buf[ofs].type = IS_DOUBLE;
419+
stmt->result.buf[ofs].buflen = sizeof(float);
420+
421+
stmt->result.buf[ofs].val = (char *)emalloc(sizeof(float));
422+
bind[ofs].buffer_type = MYSQL_TYPE_FLOAT;
423+
bind[ofs].buffer = stmt->result.buf[ofs].val;
424+
bind[ofs].is_null = &stmt->result.is_null[ofs];
425+
break;
426+
427+
case MYSQL_TYPE_DOUBLE:
418428
stmt->result.buf[ofs].type = IS_DOUBLE;
419429
stmt->result.buf[ofs].buflen = sizeof(double);
420430

@@ -1021,8 +1031,22 @@ void mysqli_stmt_fetch_libmysql(INTERNAL_FUNCTION_PARAMETERS)
10211031
}
10221032
break;
10231033
case IS_DOUBLE:
1024-
ZVAL_DOUBLE(result, *(double *)stmt->result.buf[i].val);
1034+
{
1035+
double dval;
1036+
if (stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_FLOAT) {
1037+
#ifndef NOT_FIXED_DEC
1038+
# define NOT_FIXED_DEC 31
1039+
#endif
1040+
dval = mysql_float_to_double(*(float *)stmt->result.buf[i].val,
1041+
(stmt->stmt->fields[i].decimals >= NOT_FIXED_DEC) ? -1 :
1042+
stmt->stmt->fields[i].decimals);
1043+
} else {
1044+
dval = *((double *)stmt->result.buf[i].val);
1045+
}
1046+
1047+
ZVAL_DOUBLE(result, dval);
10251048
break;
1049+
}
10261050
case IS_STRING:
10271051
if (stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_LONGLONG
10281052
#if MYSQL_VERSION_ID > 50002

ext/mysqli/tests/010.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,18 @@ mysqli_close($link);
6262
--EXPECT--
6363
array(7) {
6464
[0]=>
65-
float(3.141593)
65+
float(3.14159)
6666
[1]=>
6767
float(-1.0E-6)
6868
[2]=>
6969
float(0)
7070
[3]=>
7171
float(1.0E+12)
7272
[4]=>
73-
float(0.5646425)
73+
float(0.564642)
7474
[5]=>
7575
float(1)
7676
[6]=>
77-
float(8.888889E+14)
77+
float(8.88889E+14)
7878
}
7979
done!

ext/mysqli/tests/bug67839.phpt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,27 @@ precision=5
3838
die();
3939
}
4040

41-
if (!mysqli_stmt_execute($stmt)) {
41+
$id = null;
42+
$fp4 = null;
43+
$fp8 = null;
44+
45+
if (!mysqli_stmt_bind_result($stmt, $id, $fp4, $fp8)) {
4246
printf("[006] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
4347
die();
4448
}
4549

46-
47-
if (!($result = mysqli_stmt_get_result($stmt))) {
50+
if (!mysqli_stmt_execute($stmt)) {
4851
printf("[007] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
4952
die();
5053
}
5154

52-
$data = mysqli_fetch_assoc($result);
53-
print $data['id'] . ": " . $data['fp4'] . ": " . $data['fp8'] . "\n";
55+
56+
if (!(mysqli_stmt_fetch($stmt))) {
57+
printf("[008] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
58+
die();
59+
}
60+
61+
print $id . ": " . $fp4 . ": " . $fp8 . "\n";
5462
?>
5563
--CLEAN--
5664
<?php

ext/mysqlnd/config9.m4

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -49,34 +49,3 @@ fi
4949
if test "$PHP_MYSQLND" != "no" || test "$PHP_MYSQLND_ENABLED" = "yes" || test "$PHP_MYSQLI" != "no"; then
5050
PHP_ADD_BUILD_DIR([ext/mysqlnd], 1)
5151
fi
52-
53-
dnl
54-
dnl Check if the compiler supports Decimal32/64/128 types from the IEEE-754 2008 version
55-
dnl References: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1657.pdf
56-
dnl http://speleotrove.com/decimal/
57-
dnl
58-
AC_CACHE_CHECK([whether whether compiler supports Decimal32/64/128 types], ac_cv_decimal_fp_supported,[
59-
AC_TRY_RUN( [
60-
#include <stdio.h>
61-
#include <string.h>
62-
63-
int main(int argc, char **argv) {
64-
typedef float dec32 __attribute__((mode(SD)));
65-
dec32 k = 99.49f;
66-
double d2 = (double)k;
67-
const char *check_str = "99.49";
68-
char print_str[32];
69-
70-
snprintf(print_str, 32, "%f", d2);
71-
return memcmp(print_str, check_str, 5);
72-
}
73-
],[
74-
ac_cv_decimal_fp_supported=yes
75-
],[
76-
ac_cv_decimal_fp_supported=no
77-
],[
78-
ac_cv_decimal_fp_supported=no
79-
])])
80-
if test "$ac_cv_decimal_fp_supported" = "yes"; then
81-
AC_DEFINE(HAVE_DECIMAL_FP_SUPPORT, 1, [Define if the compiler supports Decimal32/64/128 types.])
82-
fi

ext/mysqlnd/mysql_float_to_double.h

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
+----------------------------------------------------------------------+
3+
| PHP Version 5 |
4+
+----------------------------------------------------------------------+
5+
| Copyright (c) 2006-2014 The PHP Group |
6+
+----------------------------------------------------------------------+
7+
| This source file is subject to version 3.01 of the PHP license, |
8+
| that is bundled with this package in the file LICENSE, and is |
9+
| available through the world-wide-web at the following url: |
10+
| http://www.php.net/license/3_01.txt |
11+
| If you did not receive a copy of the PHP license and are unable to |
12+
| obtain it through the world-wide-web, please send a note to |
13+
| [email protected] so we can mail you a copy immediately. |
14+
+----------------------------------------------------------------------+
15+
| Authors: Keyur Govande <[email protected]> |
16+
+----------------------------------------------------------------------+
17+
*/
18+
19+
#ifndef MYSQL_FLOAT_TO_DOUBLE_H
20+
#define MYSQL_FLOAT_TO_DOUBLE_H
21+
22+
#include "main/php.h"
23+
#include <float.h>
24+
#include "main/snprintf.h"
25+
26+
#define MAX_CHAR_BUF_LEN 255
27+
28+
#ifndef FLT_DIG
29+
# define FLT_DIG 6
30+
#endif
31+
32+
/*
33+
* Convert from a 4-byte float to a 8-byte decimal by first converting
34+
* the float to a string, and then the string to a double.
35+
* The decimals argument specifies the precision of the output. If decimals
36+
* is less than zero, then a gcvt(3) like logic is used with the significant
37+
* digits set to FLT_DIG i.e. 6.
38+
*/
39+
static inline double mysql_float_to_double(float fp4, int decimals) {
40+
char num_buf[MAX_CHAR_BUF_LEN]; /* Over allocated */
41+
42+
if (decimals < 0) {
43+
php_gcvt(fp4, FLT_DIG, '.', 'e', num_buf);
44+
} else {
45+
php_sprintf(num_buf, "%.*f", decimals, fp4);
46+
}
47+
48+
return zend_strtod(num_buf, NULL);
49+
}
50+
51+
/*
52+
* Local variables:
53+
* tab-width: 4
54+
* c-basic-offset: 4
55+
* End:
56+
* vim600: noet sw=4 ts=4 fdm=marker
57+
* vim<600: noet sw=4 ts=4
58+
*/
59+
60+
#endif /* MYSQL_FLOAT_TO_DOUBLE_H */

ext/mysqlnd/mysqlnd_ps_codec.c

Lines changed: 5 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "mysqlnd_wireprotocol.h"
2525
#include "mysqlnd_priv.h"
2626
#include "mysqlnd_debug.h"
27+
#include "ext/mysqlnd/mysql_float_to_double.h"
2728

2829
#define MYSQLND_SILENT
2930

@@ -181,56 +182,12 @@ ps_fetch_float(zval * zv, const MYSQLND_FIELD * const field, unsigned int pack_l
181182
(*row)+= 4;
182183
DBG_INF_FMT("value=%f", fval);
183184

184-
/*
185-
* The following is needed to correctly support 4-byte floats.
186-
* Otherwise, a value of 9.99 in a FLOAT column comes out of mysqli
187-
* as 9.9998998641968.
188-
*
189-
* For GCC, we use the built-in decimal support to "up-convert" a
190-
* 4-byte float to a 8-byte double.
191-
* When that is not available, we fall back to converting the float
192-
* to a string and then converting the string to a double. This mimics
193-
* what MySQL does.
194-
*/
195-
#ifdef HAVE_DECIMAL_FP_SUPPORT
196-
{
197-
typedef float dec32 __attribute__((mode(SD)));
198-
/* volatile so the compiler will not optimize away the conversion */
199-
volatile dec32 d32val = fval;
200-
201-
/* The following cast is guaranteed to do the right thing */
202-
dval = (double) d32val;
203-
}
204-
#elif defined(PHP_WIN32)
205-
{
206-
/* float datatype on Winows is already 4 byte but has a precision of 7 digits */
207-
char num_buf[2048];
208-
(void)_gcvt_s(num_buf, 2048, fval, field->decimals >= 31 ? 7 : field->decimals);
209-
dval = zend_strtod(num_buf, NULL);
210-
}
211-
#else
212-
{
213-
char num_buf[2048]; /* Over allocated */
214-
char *s;
215-
216-
#ifndef FLT_DIG
217-
# define FLT_DIG 6
218-
#endif
219-
/* Convert to string. Ignoring localization, etc.
220-
* Following MySQL's rules. If precision is undefined (NOT_FIXED_DEC i.e. 31)
221-
* or larger than 31, the value is limited to 6 (FLT_DIG).
222-
*/
223-
s = php_gcvt(fval,
224-
field->decimals >= 31 ? FLT_DIG : field->decimals,
225-
'.',
226-
'e',
227-
num_buf);
228-
229-
/* And now convert back to double */
230-
dval = zend_strtod(s, NULL);
231-
}
185+
#ifndef NOT_FIXED_DEC
186+
# define NOT_FIXED_DEC 31
232187
#endif
233188

189+
dval = mysql_float_to_double(fval, (field->decimals >= NOT_FIXED_DEC) ? -1 : field->decimals);
190+
234191
ZVAL_DOUBLE(zv, dval);
235192
DBG_VOID_RETURN;
236193
}

0 commit comments

Comments
 (0)