diff --git a/NEWS b/NEWS index 48afd654b2ef..b1252555b41f 100644 --- a/NEWS +++ b/NEWS @@ -58,6 +58,8 @@ PHP NEWS - MySQLnd: . Fixed bug GH-24293 (Segfault on connect with an empty password to a MariaDB PAM account). (lazerg) + . Fixed bug GH-16910 (Fractional seconds truncated in prepared statements + if decimals is AUTO_SEC_PART_DIGITS). (Ojus Chugh) - Opcache: . Fixed bug GH-20890 (Segfault in zval_undefined_cv with non-simple property diff --git a/ext/mysqli/tests/gh16910.phpt b/ext/mysqli/tests/gh16910.phpt new file mode 100644 index 000000000000..910f586d2f39 --- /dev/null +++ b/ext/mysqli/tests/gh16910.phpt @@ -0,0 +1,42 @@ +--TEST-- +GH-16910 (Fractional seconds truncated in prepared statements if decimals is AUTO_SEC_PART_DIGITS) +--EXTENSIONS-- +mysqli +--SKIPIF-- +prepare("SELECT FROM_UNIXTIME('1992.1')"); +if (!$stmt || $stmt->result_metadata()->fetch_field_direct(0)->decimals !== 39) + die("SKIP Server does not report AUTO_SEC_PART_DIGITS for FROM_UNIXTIME()"); +?> +--FILE-- +query("SET time_zone = '+00:00'"); + +$sql = "SELECT FROM_UNIXTIME('1992.1'), FROM_UNIXTIME('1992.0')"; +var_dump($link->query($sql)->fetch_row()); + +$stmt = $link->prepare($sql); +$stmt->execute(); +var_dump($stmt->get_result()->fetch_row()); +?> +--EXPECT-- +array(2) { + [0]=> + string(26) "1970-01-01 00:33:12.100000" + [1]=> + string(19) "1970-01-01 00:33:12" +} +array(2) { + [0]=> + string(26) "1970-01-01 00:33:12.100000" + [1]=> + string(19) "1970-01-01 00:33:12" +} diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c index 787fe3b245cd..53ff394ebeb8 100644 --- a/ext/mysqlnd/mysqlnd_ps_codec.c +++ b/ext/mysqlnd/mysqlnd_ps_codec.c @@ -305,10 +305,11 @@ ps_fetch_time(zval * zv, const MYSQLND_FIELD * const field, const unsigned int p t.time_type = MYSQLND_TIMESTAMP_TIME; } - if (field->decimals > 0 && field->decimals < 7) { + unsigned int decimals = field->decimals > 6 ? (t.second_part ? 6 : 0) : field->decimals; + if (decimals > 0) { ZVAL_STR(zv, zend_strpprintf(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)))); + (t.neg ? "-" : ""), t.hour, t.minute, t.second, decimals, + (uint32_t) (t.second_part / pow(10, 6 - decimals)))); } else { ZVAL_STR(zv, zend_strpprintf(0, "%s%02u:%02u:%02u", (t.neg ? "-" : ""), t.hour, t.minute, t.second)); @@ -401,10 +402,11 @@ ps_fetch_datetime(zval * zv, const MYSQLND_FIELD * const field, const unsigned i t.time_type = MYSQLND_TIMESTAMP_DATETIME; } - if (field->decimals > 0 && field->decimals < 7) { + unsigned int decimals = field->decimals > 6 ? (t.second_part ? 6 : 0) : field->decimals; + if (decimals > 0) { ZVAL_STR(zv, zend_strpprintf(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)))); + t.year, t.month, t.day, t.hour, t.minute, t.second, decimals, + (uint32_t) (t.second_part / pow(10, 6 - decimals)))); } else { ZVAL_STR(zv, zend_strpprintf(0, "%04u-%02u-%02u %02u:%02u:%02u", t.year, t.month, t.day, t.hour, t.minute, t.second));