Bug #79375 [NEW]: mysqli_store_result does not report error from lock wait timout

From: Date: Thu, 12 Mar 2020 21:07:49 +0000
Subject: Bug #79375 [NEW]: mysqli_store_result does not report error from lock wait timout
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-226074@lists.php.net to get a copy of this message
From: brett dot cundal at iugome dot com Operating system: Ubuntu 18.04 PHP version: 7.2.28 Package: MySQLi related Bug Type: Bug Bug description:mysqli_store_result does not report error from lock wait timout Description: ------------ We've run across a case where mysqli_store_result() returns an empty result set when it should set the error code and message. In this case it's happening with a prepared and executed statement which is trying to read a row/gap locked by another connection. Checking the return code from store_result() does not indicate the error, and I'm not able to find any way to get the error to be indicated. Doing the same flow using mysqli_get_result() does result in the error being reported correctly. Note that I'm actually testing with PHP 7.2.24 which is not the latest at this time (it's the latest on ubuntu 18.04), but I've checked the change log for the few versions since this, and I don't see anything likely to fix this between 7.2.24 and 7.2.28. Possibly the issue is more broad, e.g. any time the error would be returned by store_result() rather than immediately by execute() - but we haven't found any other confirmed cases where this happens. This seems similar to https://bugs.php.net/bug.php?id=66370 but I ran that script on php 7.2 and was not able to reproduce that problem using query(), store_result() or get_result(). The test case is as follows. Set up a table with a composite key: CREATE TABLE lock_test ( first int(10) unsigned NOT NULL, second int(10) unsigned NOT NULL, third int(10) unsigned NOT NULL, status int(10) unsigned NOT NULL, PRIMARY KEY (first,second,third) ) ENGINE=InnoDB; Insert a record: INSERT INTO lock_test (first, second, third, status) VALUES (1, 1, 1, 1); On one connection, select the record using part of the key, with "FOR UPDATE": (we didn't see this problem when specifying the full key and therefore locking only the one record) $mysqli->query("START TRANSACTION"); $query = "SELECT status FROM lock_test WHERE first = 1 AND second = 1 FOR UPDATE"; $stmt = $mysqli->prepare($query); $stmt->execute(); if(!$stmt->store_result()) throw new Exception("Store failed: {$mysqli->error}"); echo "Got {$stmt->num_rows} for $name\n"; This will successfully return one record. Leave that open, and do the same on another connection. The second connection will block until 'innodb_lock_wait_timeout' elapses, and then will successfully return with 0 records in the result set. Instead, it should return an error, either on execute() or on store_result(), and should set the mysqli error code. The attached script assumes the table described above is set up on localhost in a schema named 'test'. Adjust as needed otherwise. Test script: --------------- $firstConnection = getConnection(); selectForUpdateStore($firstConnection, 'first connection'); $secondConnection = getConnection(); selectForUpdateStore($secondConnection, 'second connection'); function getConnection() { $mysqli = mysqli_init(); $mysqli->real_connect('localhost', 'root', '', 'test'); return $mysqli; } function selectForUpdateStore(mysqli $mysqli, string $name) { $mysqli->query("SET innodb_lock_wait_timeout = 2"); $mysqli->query("START TRANSACTION"); $query = "SELECT status FROM lock_test WHERE first = 1 AND second = 1 FOR UPDATE"; echo "Running query on $name\n"; $stmt = $mysqli->prepare($query); $stmt->execute(); if(!$stmt->store_result()) throw new Exception("Store failed for $name: {$mysqli->error}"); echo "Got {$stmt->num_rows} for $name\n"; } Expected result: ---------------- Running query on first connection Got 1 for first connection Running query on second connection PHP Fatal error: Uncaught Exception: Store failed for second connection: Lock wait timeout exceeded; try restarting transaction [...] Actual result: -------------- Running query on first connection Got 1 for first connection Running query on second connection Got 0 for second connection -- Edit bug report at https://bugs.php.net/bug.php?id=79375&edit=1 -- Fix committed: https://bugs.php.net/fix.php?id=79375&r=fixed Fixed in release: https://bugs.php.net/fix.php?id=79375&r=alreadyfixed Need backtrace: https://bugs.php.net/fix.php?id=79375&r=needtrace Need Reproduce Script: https://bugs.php.net/fix.php?id=79375&r=needscript Try newer version: https://bugs.php.net/fix.php?id=79375&r=oldversion Not developer issue: https://bugs.php.net/fix.php?id=79375&r=support Expected behavior: https://bugs.php.net/fix.php?id=79375&r=notwrong Not enough info: https://bugs.php.net/fix.php?id=79375&r=notenoughinfo Submitted twice: https://bugs.php.net/fix.php?id=79375&r=submittedtwice register_globals: https://bugs.php.net/fix.php?id=79375&r=globals PHP version support discontinued: https://bugs.php.net/fix.php?id=79375&r=phptooold Daylight Savings: https://bugs.php.net/fix.php?id=79375&r=dst IIS Stability: https://bugs.php.net/fix.php?id=79375&r=isapi Install GNU Sed: https://bugs.php.net/fix.php?id=79375&r=gnused Floating point limitations: https://bugs.php.net/fix.php?id=79375&r=float No Zend Extensions: https://bugs.php.net/fix.php?id=79375&r=nozend MySQL Configuration Error: https://bugs.php.net/fix.php?id=79375&r=mysqlcfg

« previous php.bugs (#226074) next »