Bug #80653 [Opn]: MySQL BIGINT UNSIGNED value in prepared statement treated incorrectly

From: Date: Thu, 21 Jan 2021 22:54:35 +0000
Subject: Bug #80653 [Opn]: MySQL BIGINT UNSIGNED value in prepared statement treated incorrectly
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-231687@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=80653&edit=1 ID: 80653 User updated by: gman dot n at xrbr dot com Reported by: gman dot n at xrbr dot com Summary: MySQL BIGINT UNSIGNED value in prepared statement treated incorrectly Status: Open Type: Bug Package: MySQLi related Operating System: Ubuntu 20.04.1 LTS PHP Version: 7.4.14 Block user comment: N Private report: N New Comment: Done: https://bugs.mysql.com/bug.php?id=102338 Previous Comments: ------------------------------------------------------------------------ [2021-01-21 21:43:13] dharman@php.net Thanks, I can see that there is a problem. I have been looking into the issue for the past hour and I still haven't narrowed it down, but I have some more findings I would like to keep a record of here. It looks like the only affected version is MySQL 8.0.22. I am 90% sure that the bug is on MySQL side... What I have found out so far is: - It affects all PHP versions - Engine is irrelevant - As you have noticed the type (both column and binding) of the second column impacts the result - Only certain numbers are affected. There is a pattern, but it's unclear to me what that pattern is. The bigger the numbers get the more irregular the pattern becomes. e.g. numbers between 13326067295508630 and 13326067295508660 (00 fail, 11-success): 11 13326067295508630 00 13326067295508631 11 13326067295508632 11 13326067295508633 11 13326067295508634 00 13326067295508635 11 13326067295508636 11 13326067295508637 11 13326067295508638 00 13326067295508639 11 13326067295508640 11 13326067295508641 11 13326067295508642 00 13326067295508643 11 13326067295508644 11 13326067295508645 11 13326067295508646 00 13326067295508647 11 13326067295508648 11 13326067295508649 11 13326067295508650 00 13326067295508651 11 13326067295508652 11 13326067295508653 11 13326067295508654 00 13326067295508655 11 13326067295508656 11 13326067295508657 11 13326067295508658 00 13326067295508659 ----------------------------- - The type used in binding makes huge difference, regardless of what it is or which parameter it is. For example, this works fine: $type3 = 30; $statement1->bind_param('ss', $hash3, $type3); $statement1->execute(); echo $statement1->get_result()->num_rows; $type4 = 30; $statement1->bind_param('ss', $hash3, $type4); $statement1->execute(); echo $statement1->get_result()->num_rows; but this does not $type3 = 30; $statement1->bind_param('si', $hash3, $type3); $statement1->execute(); echo $statement1->get_result()->num_rows; $type4 = 30; $statement1->bind_param('ss', $hash3, $type4); $statement1->execute(); echo $statement1->get_result()->num_rows; This leads me to believe that the problem is on MySQL side with the way the optimizer handles type casting in prepared statements. MySQL 8.0.22 has changed the way that prepared statements are parsed and optimized. This looks like an unintentional bug. The only explanation I have for this erratic behaviour is that there is a bug in the new way that MySQL handles PS and type casting. I see no way that mysqli or mysqlnd could produce such bug. Therefore, I would kindly ask you to report it to Oracle (https://bugs.mysql.com/) as soon as possible. ------------------------------------------------------------------------ [2021-01-21 21:24:28] kieran at supportpal dot com This issue looks very similar to one that I'm experiencing. Here's a reproducer: https://phpize.online/?phpses=10da649bcd37236fa6f1498f6adcdba0&sqlses=aa6be73c673b7971675e7fc46729579d&php_version=php8&sql_version=mysql80 Change int unsigned to int and the query works: https://phpize.online/?phpses=eab1ced5f425974278c22777c0e79f58&sqlses=aa6be73c673b7971675e7fc46729579d&php_version=php8&sql_version=mysql80 The issue only occurs on MySQL 8 (not 5.x versions), and affects all PHP versions. Emulating prepared statements seems to be a workaround to the problem. ------------------------------------------------------------------------ [2021-01-21 19:33:46] gman dot n at xrbr dot com Thanks for checking this out! Using your phpize.online link, when I change to MySQL 8.0 it does no longer work. I immediately checked and I'm using MySQL 8.0.22-0ubuntu0.20.04.3 (should have added that in the beginning, sorry!). So is it an issue with PHP or MySQL? Updated link: https://phpize.online/?phpses=ff46fef22cb57979f1280d43f0ad2729&sqlses=null&php_version=php7&sql_version=mysql80 ------------------------------------------------------------------------ [2021-01-21 19:16:03] dharman@php.net I can't reproduce it. I tried with PHP 7.3, 7.4.14 and 8.0. I tried on Windows and Linux. I tried it with MySQL and MariaDB. I even tried it online, but I always get the same output: https://phpize.online/?phpses=ff46fef22cb57979f1280d43f0ad2729&sqlses=null&php_version=php7&sql_version=mysql57 1111 11 11 Are you sure there isn't something else in your environment that causes the wrong output? ------------------------------------------------------------------------ [2021-01-21 18:47:06] gman dot n at xrbr dot com Description: ------------ When using MySQLi prepared statement, everything works as expected when using only a single BIGINT UNSIGNED column by itself: Using one column only: "... WHERE val_hash=?" test value A: 8969302881072144 => result: works. test value B: 13326067295508650029 => result: works. The query returns the expected result in both cases. However, when adding a second column, which in my scenario is a TINYINT column, the SELECT query will work for test value A, but not yield any results for test value B. This occurs probabaly because the test value B ist a BIGINT UNSIGNED value is higher than PHP_INT_MAX. Using two columns: "... WHERE val_type=? AND val_hash=?" test value A: 8969302881072144 => result: works. test value B: 13326067295508650029 => result: DOES NOT WORK. Therefore, there must be a bug that messes up the BIGINT UNSIGNED value when higher than PHP_INT_MAX. Test script: --------------- Full script: https://pastebin.com/g4ZCG3sB Shorted version: <?php $connection = new \mysqli(...); $statement1 = $connection->prepare('SELECT val_id, val_type FROM copy_pw_values WHERE val_type=? AND val_hash=?'); $type3 = 3; $hash3 = '13326067295508650029'; $statement1->bind_param('is', $type3, $hash3); $statement1->execute(); echo $statement1->get_result()->num_rows; // Returns 0, should return 1. $type4 = '3'; $hash4 = '13326067295508650029'; $statement1->bind_param('ss', $type4, $hash4); $statement1->execute(); echo $statement1->get_result()->num_rows; // Returns 0, should return 1. Expected result: ---------------- 1111 11 11 Actual result: -------------- 1100 11 11 ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=80653&edit=1

« previous php.bugs (#231687) next »