Skip to content

Fix GH-16910: Fractional seconds truncated in prepared statements - #24467

Open
ojuschugh1 wants to merge 2 commits into
php:PHP-8.4from
ojuschugh1:mysqlnd-auto-sec-part
Open

ojuschugh1 wants to merge 2 commits into
php:PHP-8.4from
ojuschugh1:mysqlnd-auto-sec-part

Conversation

@ojuschugh1

@ojuschugh1 ojuschugh1 commented Oct 20, 2026 •

Copy link
Copy Markdown

Fixes #16910

The problem was that ps_fetch_time() and ps_fetch_datetime() only print second_part when decimals is 1 to 6, the check added for bug #76386. MariaDB reports AUTO_SEC_PART_DIGITS (39) when the precision isn't known up front, for example for FROM_UNIXTIME('1992.1'), so prepared statements dropped the fraction that the text protocol returns.

I made any decimals above 6, the not-fixed sentinel (39 in MariaDB, 31 in MySQL), print six digits when second_part is non-zero and none otherwise, as MariaDB Connector/C does for 39, which gives the same strings as the text protocol. ps_fetch_time() gets the same change, though on MariaDB 13.0.2 I only got 39 for FROM_UNIXTIME() (TIMESTAMP) results.

The test compares the text and binary protocol results and skips unless the server reports 39 for FROM_UNIXTIME(). It fails without the fix on MariaDB 13.0.2 and skips on MySQL 8.4.13, and the other ext/mysqli, ext/pdo_mysql and ext/mysqlnd tests give the same results with and without the fix on both servers.

@ojuschugh1

Copy link
Copy Markdown
Author

Changed to treat every decimals value above 6 as unknown precision, after @9EOR9's note in #16910 that 39 is a sentinel (31 in MySQL). It still prints no fraction when second_part is 0, since that's what the text protocol returns for FROM_UNIXTIME('1992.0').

@anun333

anun333 commented Oct 25, 2026

Copy link
Copy Markdown

Quoted below: written with Claude, an LLM, as CONTRIBUTING.md asks us to mark. The builds and test runs behind it are on my machine; the commands to repeat them are under the fold.

Tested against MariaDB 12.3.3 with debug builds of PHP-8.4 (51808ac5478) without and with this branch (be41b58628e):

Without the patch With it
gh16910.phpt FAIL PASS
ext/mysqli/tests 440 passed, 12 failed, 34 skipped 441 passed, 12 failed, 34 skipped

So the server reports the 39 sentinel for FROM_UNIXTIME() on 12.3 as well as on the 13.0.2 you tested. The same 12 tests fail on both builds against MariaDB; the one extra pass is the new test.

How this was tested

Builds (Linux x86_64, gcc 13.3), the same for both trees:

./buildconf --force
./configure --enable-debug --with-mysqli --disable-cgi --disable-phpdbg --disable-fileinfo
make -j6

Server and tests:

docker run -d --name mariadb-test -e MARIADB_ROOT_PASSWORD=test -e MARIADB_DATABASE=test -p 127.0.0.1:33306:3306 mariadb:12.3.3
export MYSQL_TEST_HOST=127.0.0.1 MYSQL_TEST_PORT=33306 MYSQL_TEST_USER=root MYSQL_TEST_PASSWD=test MYSQL_TEST_DB=test
TEST_PHP_EXECUTABLE=sapi/cli/php sapi/cli/php run-tests.php -q -n ext/mysqli/tests

On that server, SELECT FROM_UNIXTIME('1992.1') over the text protocol gives 1970-01-01 00:33:12.100000.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants