#include "ext/standard/php_smart_str.h"
#include "php_mysqli_structs.h"
#include "mysqli_priv.h"
+#include "ext/standard/float_to_double.h"
#if !defined(MYSQLI_USE_MYSQLND)
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);
}
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 = 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
--EXPECT--
array(7) {
[0]=>
- float(3.141593)
+ float(3.14159)
[1]=>
float(-1.0E-6)
[2]=>
[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!
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
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
#include "mysqlnd_wireprotocol.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_debug.h"
+#include "ext/standard/float_to_double.h"
#define MYSQLND_SILENT
(*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
-#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);
- }
+#ifndef NOT_FIXED_DEC
+# define NOT_FIXED_DEC 31
#endif
+ dval = float_to_double(fval, (field->decimals >= NOT_FIXED_DEC) ? -1 : field->decimals);
+
ZVAL_DOUBLE(zv, dval);
DBG_VOID_RETURN;
}
incomplete_class.c url_scanner_ex.c ftp_fopen_wrapper.c \
http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \
var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c \
- filters.c proc_open.c streamsfuncs.c http.c password.c)
+ filters.c proc_open.c streamsfuncs.c http.c password.c \
+ float_to_double.c)
PHP_ADD_MAKEFILE_FRAGMENT
PHP_INSTALL_HEADERS([ext/standard/])
url_scanner_ex.c ftp_fopen_wrapper.c http_fopen_wrapper.c \
php_fopen_wrapper.c credits.c css.c var_unserializer.c ftok.c sha1.c \
user_filters.c uuencode.c filters.c proc_open.c password.c \
- streamsfuncs.c http.c flock_compat.c", false /* never shared */);
+ streamsfuncs.c http.c flock_compat.c float_to_double.c", false /* never shared */);
PHP_INSTALL_HEADERS("", "ext/standard");
if (PHP_MBREGEX != "no") {
CHECK_HEADER_ADD_INCLUDE("oniguruma.h", "CFLAGS_STANDARD", PHP_MBREGEX + ";ext\\mbstring\\oniguruma")
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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> |
+ +----------------------------------------------------------------------+
+*/
+
+#include <float.h>
+#include "float_to_double.h"
+#include "main/snprintf.h"
+
+#define MAX_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.
+ */
+double float_to_double(float fp4, int decimals) {
+ char num_buf[MAX_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
+ */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | 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 FLOAT_TO_DOUBLE_H
+#define FLOAT_TO_DOUBLE_H
+
+#include "main/php.h"
+
+PHPAPI double float_to_double(float fp4, int decimals);
+
+#endif /* FLOAT_TO_DOUBLE_H */
+
+/*
+ * 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
+ */