Skip to content

mysqlnd: Fractional seconds truncated in prepared statements, if value of decimals is AUTO_SEC_PART_DIGITS (=39). #16910

Open

Description

@9EOR9

Description

This issue was initially reported for MariaDB Connector/C (which uses part of mysqlnd):

In some cases both MySQL and MariaDB server will send the value 39 (=AUTO_SEC_PART_DIGITS) for datetime and time decimals. The binary protocol implementation however will only set fractional seconds if decimals is <= 6.

The following code:

<?php

$link= mysqli_connect("localhost", "georg", null, "test", 0, "/tmp/mysql.sock");

$stmt = $link->prepare("select FROM_UNIXTIME('1992.1'), FROM_UNIXTIME('1992.0')");
$stmt->execute();
$stmt->bind_result($binval[0],$binval[1]);
$stmt->fetch();
$stmt->close();

$result = $link->query("select FROM_UNIXTIME('1992.1'), FROM_UNIXTIME('1992.0')");
$txtval = $result->fetch_row();
$result->close();
$err_cnt= 0;

for ($i=0; $i < 2; $i++)
    if ($txtval[$i] != $binval[$i])
        printf("[%03d] Expected '%s' (text protocol), got '%s' (binary protocol)\n",
               $err_cnt++, $txtval[$i], $binval[$i]);

printf("Done!\n");
?>

Resulted in this output:

[000] Expected '1970-01-01 01:33:12.100000' (text protocol), got '1970-01-01 01:33:12' (binary protocol)
Done!

But I expected this output instead:

Done!

Metadata sent by server:

$> mariadb --column-type-info -e"select from_unixtime('1922.1')"
Field   1:  `from_unixtime('1922.1')`
Org_field:  ``
Catalog:    `def`
Database:   ``
Table:      ``
Org_table:  ``
Type:       DATETIME
Collation:  binary (63)
Length:     26
Max_length: 26
Decimals:   39
Flags:      BINARY 

PHP Version

PHP 8.4.0-dev

Operating System

No response

Activity

  1. added theissue type on Feb 5, 2025
  2. ojuschugh1 commented on Oct 20, 2026

    @ojuschugh1

    Still happens on 8.5.11 and on master (2f7b01b) with MariaDB 13.0.2, for mysqli prepared statements and for PDO with PDO::ATTR_EMULATE_PREPARES => false:

    $link->query("SET time_zone = '+00:00'");
    $sql = "SELECT FROM_UNIXTIME('1992.1'), FROM_UNIXTIME('1992.0')";
    $link->query($sql)->fetch_row();   // "1970-01-01 00:33:12.100000", "1970-01-01 00:33:12"
    $stmt = $link->prepare($sql);      // decimals is 39 for both columns
    $stmt->execute();
    $stmt->get_result()->fetch_row();  // "1970-01-01 00:33:12", "1970-01-01 00:33:12"

    ps_fetch_time() and ps_fetch_datetime() only print second_part when decimals is 1 to 6 (the check from bug #76386), so 39 falls through to the format without a fraction.

    I'd handle 39 the way MariaDB Connector/C does, six digits when second_part is non-zero and none otherwise, which gives the same strings as the text protocol. The alternative is to treat every value above 6 that way. @9EOR9 @bukka does the first sound right? If so I can take over from #16911 and do it against PHP-8.4, with a fake-server test so CI covers it without MariaDB.

  3. kamil-tekiela commented on Oct 20, 2026

    @kamil-tekiela
    Member

    @ojuschugh1 Feel free to open a PR and we will review it. If it's a real life behaviour, you should not use fake-server; that's only for testing behaviour that doesn't happen with real servers.

  4. 9EOR9 commented on Oct 21, 2026

    @9EOR9
    Author
  5. ojuschugh1 commented on Oct 21, 2026

    @ojuschugh1

    Thanks @9EOR9 for the clarification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions