-
-
Save keyurdg/9c99da11848ac7589e66 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/ext/mysqli/tests/mysqli_float_handling.phpt b/ext/mysqli/tests/mysqli_float_handling.phpt | |
new file mode 100644 | |
index 0000000..b2821a2 | |
--- /dev/null | |
+++ b/ext/mysqli/tests/mysqli_float_handling.phpt | |
@@ -0,0 +1,58 @@ | |
+--TEST-- | |
+mysqli_float_handling - ensure 4 byte float is handled correctly | |
+--SKIPIF-- | |
+<?php | |
+ require_once('skipif.inc'); | |
+ require_once('skipifemb.inc'); | |
+ require_once('skipifconnectfailure.inc'); | |
+?> | |
+--FILE-- | |
+<?php | |
+ require('connect.inc'); | |
+ if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) { | |
+ printf("[001] [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()); | |
+ die(); | |
+ } | |
+ | |
+ | |
+ if (!mysqli_query($link, "DROP TABLE IF EXISTS test")) { | |
+ printf("[002] [%d] %s\n", mysqli_errno($link), mysqli_error($link)); | |
+ die(); | |
+ } | |
+ | |
+ if (!mysqli_query($link, "CREATE TABLE test(id INT PRIMARY KEY, fp4 FLOAT, fp8 DOUBLE) ENGINE = InnoDB")) { | |
+ printf("[003] [%d] %s\n", mysqli_errno($link), mysqli_error($link)); | |
+ die(); | |
+ } | |
+ | |
+ // Insert via string to make sure the real floating number gets to the DB | |
+ if (!mysqli_query($link, "INSERT INTO test(id, fp4, fp8) VALUES (1, 9.9999, 9.9999)")) { | |
+ printf("[004] [%d] %s\n", mysqli_errno($link), mysqli_error($link)); | |
+ die(); | |
+ } | |
+ | |
+ if (!($stmt = mysqli_prepare($link, "SELECT id, fp4, fp8 FROM test"))) { | |
+ printf("[005] [%d] %s\n", mysqli_errno($link), mysqli_error($link)); | |
+ die(); | |
+ } | |
+ | |
+ if (!mysqli_stmt_execute($stmt)) { | |
+ printf("[006] [%d] %s\n", mysqli_errno($link), mysqli_error($link)); | |
+ die(); | |
+ } | |
+ | |
+ | |
+ if (!($result = mysqli_stmt_get_result($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"; | |
+?> | |
+--CLEAN-- | |
+<?php | |
+ require_once("clean_table.inc"); | |
+?> | |
+--EXPECTF-- | |
+1: 9.9999: 9.9999 | |
diff --git a/ext/mysqlnd/config9.m4 b/ext/mysqlnd/config9.m4 | |
index 2c15c34..d730ba7 100644 | |
--- a/ext/mysqlnd/config9.m4 | |
+++ b/ext/mysqlnd/config9.m4 | |
@@ -51,3 +51,29 @@ if test "$PHP_MYSQLND" != "no" || test "$PHP_MYSQLND_ENABLED" = "yes" || test "$ | |
#endif | |
]) | |
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> | |
+ | |
+int main(int argc, char **argv) { | |
+ typedef float dec32 __attribute__((mode(SD))); | |
+ dec32 k = 99.49f; | |
+ double d2 = (double)k; | |
+ return 0; | |
+} | |
+],[ | |
+ 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 | |
diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c | |
index e2640c7..3f7d310 100644 | |
--- a/ext/mysqlnd/mysqlnd_ps_codec.c | |
+++ b/ext/mysqlnd/mysqlnd_ps_codec.c | |
@@ -195,12 +195,53 @@ void ps_fetch_float(zval *zv, const MYSQLND_FIELD * const field, | |
unsigned int pack_len, zend_uchar **row, | |
zend_bool as_unicode TSRMLS_DC) | |
{ | |
- float value; | |
+ float fval; | |
+ double dval; | |
DBG_ENTER("ps_fetch_float"); | |
- float4get(value, *row); | |
- ZVAL_DOUBLE(zv, value); | |
+ float4get(fval, *row); | |
(*row)+= 4; | |
- DBG_INF_FMT("value=%f", value); | |
+ 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))); | |
+ dec32 d32val = fval; | |
+ | |
+ /* The following cast is guaranteed to do the right thing */ | |
+ dval = (double) d32val; | |
+ } | |
+#else | |
+ { | |
+ char num_buf[2048]; /* Over allocated */ | |
+ char *s; | |
+ | |
+ /* 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 ? 6 : field->decimals, | |
+ '.', | |
+ 'e', | |
+ num_buf); | |
+ | |
+ /* And now convert back to double */ | |
+ dval = zend_strtod(s, NULL); | |
+ } | |
+#endif | |
+ | |
+ ZVAL_DOUBLE(zv, dval); | |
DBG_VOID_RETURN; | |
} | |
/* }}} */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment