]> granicus.if.org Git - php/commitdiff
Fixe bug #76386
authorVictor Csiky <strongholdmedia@users.noreply.github.com>
Wed, 30 May 2018 05:49:56 +0000 (07:49 +0200)
committerAnatol Belski <ab@php.net>
Fri, 15 Jun 2018 05:23:31 +0000 (07:23 +0200)
..that is also a duplicate of #67122

UPGRADING
ext/mysqli/tests/bug76386.phpt [new file with mode: 0644]
ext/mysqlnd/mysqlnd_ps_codec.c

index 9903e8662118c5ae7d3cdb4518f4d6ea1fc94f4e..6f1657dbf34b4fcf2f69047c2df982e88ba41d5c 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -20,8 +20,8 @@ PHP 7.3 UPGRADE NOTES
 ========================================
 
 Core:
-  . The ext_skel utility has been completely redesigned with new options and 
-    some old options removed. This is now written in PHP and has no external 
+  . The ext_skel utility has been completely redesigned with new options and
+    some old options removed. This is now written in PHP and has no external
        dependencies.
   . Support for BeOS has been dropped.
   . Exceptions thrown due to automatic conversion of warnings into exceptions
@@ -51,6 +51,23 @@ BCMath:
   . bcmul() and bcpow() now return numbers with the requested scale. Formerly,
     the returned numbers may have omitted trailing decimal zeroes.
 
+mysqli:
+  . Prepared statements now properly report the fractional seconds for DATETIME/
+    TIME/TIMESTAMP columns with decimals specifier (e.g. TIMESTAMP(6) when using
+    microseconds). Formerly, the fractional seconds part was simply omitted from
+    the returned values.
+
+PDO/MySQL:
+  . Prepared statements now properly report the fractional seconds for DATETIME/
+    TIME/TIMESTAMP columns with decimals specifier (e.g. TIMESTAMP(6) when using
+    microseconds). Formerly, the fractional seconds part was simply omitted from
+    the returned values.
+    Please note that this only affects the usage of PDO_MYSQL with emulated
+    prepares turned off (e.g. using the native preparation functionality).
+    Statements using connections having PDO::ATTR_EMULATE_PREPARES=true (which
+    is the default) were not affected by the bug fixed and have already been
+    getting the proper fractional seconds values from the engine.
+
 Reflection:
   . Reflection export to string now uses `int` and `bool` instead of `integer`
     and `boolean`.
@@ -260,7 +277,7 @@ JSON:
  MBString:
   . The configuration option --with-libmbfl is no longer available.
 
- ODBC: 
+ ODBC:
   . Support for ODBCRouter has been removed.
   . Support for Birdstep has been removed.
 
diff --git a/ext/mysqli/tests/bug76386.phpt b/ext/mysqli/tests/bug76386.phpt
new file mode 100644 (file)
index 0000000..4b51842
--- /dev/null
@@ -0,0 +1,94 @@
+--TEST--
+Prepared Statement formatter truncates fractional seconds from date/time column (bug #76386)
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifemb.inc');
+require_once('skipifconnectfailure.inc');
+?>
+--FILE--
+<?php
+require_once('connect.inc');
+// test part 1 - TIMESTAMP(n)
+$link = new mysqli($host, $user, $passwd, $db, $port, $socket);
+$link->query('DROP TABLE IF EXISTS ts_test;');
+$link->query(
+    'CREATE TABLE ts_test (id bigint unsigned auto_increment primary key, ' .
+    'ts timestamp default current_timestamp(), ts2 timestamp(2) default ' .
+    'current_timestamp(2), ts2b timestamp(2) default "2018-01-01 03:04:05.06", ' .
+    'ts4 timestamp(4) default current_timestamp(4), ts4b timestamp(4) default ' .
+    '"2018-01-01 03:04:05.0070", ts6 timestamp(6) default current_timestamp(6), ts6b ' .
+    'timestamp(6) default "2018-01-01 03:04:05.008000") character set utf8 collate ' .
+    'utf8_general_ci;'
+);
+$link->query(
+    'INSERT INTO ts_test (ts, ts2, ts4, ts6) VALUES ("2018-01-01 11:22:33", ' .
+    '"2018-02-02 11:22:33.77", "2018-03-03 11:22:33.8888", ' .
+    '"2018-04-04 11:22:33.999999");'
+);
+$stmt = $link->prepare('SELECT * FROM ts_test;'); // must be statement
+if ($stmt) {
+    $stmt->execute();
+    $tsid = $ts = $ts2 = $ts2b = $ts4 = $ts4b = $ts6 = $ts6b = null;
+    $stmt->bind_result($tsid, $ts, $ts2, $ts2b, $ts4, $ts4b, $ts6, $ts6b);
+    $stmt->fetch();
+    var_dump($ts, $ts2, $ts2b, $ts4, $ts4b, $ts6, $ts6b);
+    $stmt->free_result();
+} else {
+    echo('[FIRST][FAIL] mysqli::prepare returned false: ' . $link->error . PHP_EOL);
+}
+$link->close();
+
+// test part 2 - TIME(n)
+$link = new mysqli($host, $user, $passwd, $db, $port, $socket);
+$link->query('DROP TABLE IF EXISTS t_test;');
+$link->query(
+    'CREATE TABLE t_test (id bigint unsigned auto_increment primary key, ' .
+    't time default "11:00:00", t2 time(2) default "11:00:00.22", t4 ' .
+    'time(4) default "11:00:00.4444", t6 time(6) default "11:00:00.006054") ' .
+    'character set utf8 collate utf8_general_ci;'
+);
+$link->query(
+    'INSERT INTO t_test (t, t2, t4, t6) VALUES ("21:22:33", "21:22:33.44", ' .
+    '"21:22:33.5555", "21:22:33.676767");'
+);
+$link->query('INSERT INTO t_test VALUES ();');
+
+$stmt = $link->prepare('SELECT * FROM t_test;');
+if ($stmt) {
+    $stmt->execute();
+    $tid = $t = $t2 = $t3 = $t4 = null;
+    $stmt->bind_result($tid, $t, $t2, $t4, $t6);
+    while ($stmt->fetch()) {
+        var_dump($t, $t2, $t4, $t6);
+    }
+    $stmt->free_result();
+} else {
+    echo('[SECOND][FAIL] mysqli::prepare returned false: ' . $link->error . PHP_EOL);
+}
+$link->close();
+?>
+--EXPECTF--
+string(19) "2018-01-01 11:22:33"
+string(22) "2018-02-02 11:22:33.77"
+string(22) "2018-01-01 03:04:05.06"
+string(24) "2018-03-03 11:22:33.8888"
+string(24) "2018-01-01 03:04:05.0070"
+string(26) "2018-04-04 11:22:33.999999"
+string(26) "2018-01-01 03:04:05.008000"
+string(8) "21:22:33"
+string(11) "21:22:33.44"
+string(13) "21:22:33.5555"
+string(15) "21:22:33.676767"
+string(8) "11:00:00"
+string(11) "11:00:00.22"
+string(13) "11:00:00.4444"
+string(15) "11:00:00.006054"
+--CLEAN--
+<?php
+require_once('connect.inc');
+$link = new mysqli($host, $user, $passwd, $db, $port, $socket);
+$link->query('DROP TABLE ts_test;');
+$link->query('DROP TABLE t_test;');
+$link->close();
+?>
index 0d647088519d26b403cef891bbb87a484bab1917..e5e1e624120e491165aa31a2ffc484039be74598 100644 (file)
@@ -17,6 +17,7 @@
   +----------------------------------------------------------------------+
 */
 
+#include <math.h>
 #include "php.h"
 #include "mysqlnd.h"
 #include "mysqlnd_wireprotocol.h"
@@ -241,7 +242,21 @@ ps_fetch_time(zval * zv, const MYSQLND_FIELD * const field, const unsigned int p
                t.time_type = MYSQLND_TIMESTAMP_TIME;
        }
 
-       length = mnd_sprintf(&value, 0, "%s%02u:%02u:%02u", (t.neg ? "-" : ""), t.hour, t.minute, t.second);
+    if (field->decimals > 0 && field->decimals < 7) {
+        length = mnd_sprintf(
+            &value,
+            0,
+            "%s%02u:%02u:%02u.%0*u",
+            (t.neg ? "-" : ""),
+            t.hour,
+            t.minute,
+            t.second,
+            field->decimals,
+           (uint32_t) (t.second_part / pow(10, 6 - field->decimals))
+        );
+    } else {
+        length = mnd_sprintf(&value, 0, "%s%02u:%02u:%02u", (t.neg ? "-" : ""), t.hour, t.minute, t.second);
+    }
 
        DBG_INF_FMT("%s", value);
        ZVAL_STRINGL(zv, value, length);
@@ -322,7 +337,23 @@ ps_fetch_datetime(zval * zv, const MYSQLND_FIELD * const field, const unsigned i
                t.time_type = MYSQLND_TIMESTAMP_DATETIME;
        }
 
-       length = mnd_sprintf(&value, 0, "%04u-%02u-%02u %02u:%02u:%02u", t.year, t.month, t.day, t.hour, t.minute, t.second);
+    if (field->decimals > 0 && field->decimals < 7) {
+       length = mnd_sprintf(
+            &value,
+            0,
+            "%04u-%02u-%02u %02u:%02u:%02u.%0*u",
+            t.year,
+            t.month,
+            t.day,
+            t.hour,
+            t.minute,
+            t.second,
+            field->decimals,
+            (uint32_t) (t.second_part / pow(10, 6 - field->decimals))
+        );
+    } else {
+       length = mnd_sprintf(&value, 0, "%04u-%02u-%02u %02u:%02u:%02u", t.year, t.month, t.day, t.hour, t.minute, t.second);
+    }
 
        DBG_INF_FMT("%s", value);
        ZVAL_STRINGL(zv, value, length);