--- /dev/null
+--TEST--
+Bug #79375: mysqli_store_result does not report error from lock wait timeout
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifconnectfailure.inc');
+if (!defined('MYSQLI_STORE_RESULT_COPY_DATA')) die('skip requires mysqlnd');
+?>
+--FILE--
+<?php
+
+require_once("connect.inc");
+mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
+$mysqli = new my_mysqli($host, $user, $passwd, $db, $port, $socket);
+$mysqli2 = new my_mysqli($host, $user, $passwd, $db, $port, $socket);
+
+$mysqli->query('DROP TABLE IF EXISTS test');
+$mysqli->query('CREATE TABLE test (first int) ENGINE = InnoDB');
+$mysqli->query('INSERT INTO test VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9)');
+
+function testStmtStoreResult(mysqli $mysqli, string $name) {
+ $mysqli->query("SET innodb_lock_wait_timeout = 1");
+ $mysqli->query("START TRANSACTION");
+ $query = "SELECT first FROM test WHERE first = 1 FOR UPDATE";
+ echo "Running query on $name\n";
+ $stmt = $mysqli->prepare($query);
+ $stmt->execute();
+ try {
+ $stmt->store_result();
+ echo "Got {$stmt->num_rows} for $name\n";
+ } catch(mysqli_sql_exception $e) {
+ echo $e->getMessage()."\n";
+ }
+}
+function testStmtGetResult(mysqli $mysqli, string $name) {
+ $mysqli->query("SET innodb_lock_wait_timeout = 1");
+ $mysqli->query("START TRANSACTION");
+ $query = "SELECT first FROM test WHERE first = 1 FOR UPDATE";
+ echo "Running query on $name\n";
+ $stmt = $mysqli->prepare($query);
+ $stmt->execute();
+ try {
+ $res = $stmt->get_result();
+ echo "Got {$res->num_rows} for $name\n";
+ } catch(mysqli_sql_exception $e) {
+ echo $e->getMessage()."\n";
+ }
+}
+function testNormalQuery(mysqli $mysqli, string $name) {
+ $mysqli->query("SET innodb_lock_wait_timeout = 1");
+ $mysqli->query("START TRANSACTION");
+ $query = "SELECT first FROM test WHERE first = 1 FOR UPDATE";
+ echo "Running query on $name\n";
+ try {
+ $res = $mysqli->query($query);
+ echo "Got {$res->num_rows} for $name\n";
+ } catch(mysqli_sql_exception $e) {
+ echo $e->getMessage()."\n";
+ }
+}
+function testStmtUseResult(mysqli $mysqli, string $name) {
+ $mysqli->query("SET innodb_lock_wait_timeout = 1");
+ $mysqli->query("START TRANSACTION");
+ $query = "SELECT first FROM test WHERE first = 1 FOR UPDATE";
+ echo "Running query on $name\n";
+ $stmt = $mysqli->prepare($query);
+ $stmt->execute();
+ try {
+ $stmt->fetch(); // should throw an error
+ $stmt->fetch();
+ echo "Got {$stmt->num_rows} for $name\n";
+ } catch (mysqli_sql_exception $e) {
+ echo $e->getMessage()."\n";
+ }
+}
+function testResultFetchRow(mysqli $mysqli, string $name) {
+ $mysqli->query("SET innodb_lock_wait_timeout = 1");
+ $mysqli->query("START TRANSACTION");
+ $query = "SELECT first FROM test WHERE first = 1 FOR UPDATE";
+ echo "Running query on $name\n";
+ $res = $mysqli->query($query, MYSQLI_USE_RESULT);
+ try {
+ $res->fetch_row();
+ $res->fetch_row();
+ echo "Got {$res->num_rows} for $name\n";
+ } catch(mysqli_sql_exception $e) {
+ echo $e->getMessage()."\n";
+ }
+}
+
+testStmtStoreResult($mysqli, 'first connection');
+testStmtStoreResult($mysqli2, 'second connection');
+
+$mysqli->close();
+$mysqli2->close();
+
+echo "\n";
+// try it again for get_result
+$mysqli = new my_mysqli($host, $user, $passwd, $db, $port, $socket);
+$mysqli2 = new my_mysqli($host, $user, $passwd, $db, $port, $socket);
+
+testStmtGetResult($mysqli, 'first connection');
+testStmtGetResult($mysqli2, 'second connection');
+
+$mysqli->close();
+$mysqli2->close();
+
+echo "\n";
+// try it again with unprepared query
+$mysqli = new my_mysqli($host, $user, $passwd, $db, $port, $socket);
+$mysqli2 = new my_mysqli($host, $user, $passwd, $db, $port, $socket);
+
+testNormalQuery($mysqli, 'first connection');
+testNormalQuery($mysqli2, 'second connection');
+
+$mysqli->close();
+$mysqli2->close();
+
+echo "\n";
+// try it again with unprepared query
+$mysqli = new my_mysqli($host, $user, $passwd, $db, $port, $socket);
+$mysqli2 = new my_mysqli($host, $user, $passwd, $db, $port, $socket);
+
+testStmtUseResult($mysqli, 'first connection');
+testStmtUseResult($mysqli2, 'second connection');
+
+$mysqli->close();
+$mysqli2->close();
+
+echo "\n";
+// try it again using fetch_row on a result object
+$mysqli = new my_mysqli($host, $user, $passwd, $db, $port, $socket);
+$mysqli2 = new my_mysqli($host, $user, $passwd, $db, $port, $socket);
+
+testResultFetchRow($mysqli, 'first connection');
+testResultFetchRow($mysqli2, 'second connection');
+
+$mysqli->close();
+$mysqli2->close();
+
+?>
+--CLEAN--
+<?php
+ require_once("clean_table.inc");
+?>
+--EXPECTF--
+Running query on first connection
+Got %d for first connection
+Running query on second connection
+Lock wait timeout exceeded; try restarting transaction
+
+Running query on first connection
+Got %d for first connection
+Running query on second connection
+Lock wait timeout exceeded; try restarting transaction
+
+Running query on first connection
+Got %d for first connection
+Running query on second connection
+Lock wait timeout exceeded; try restarting transaction
+
+Running query on first connection
+Got %d for first connection
+Running query on second connection
+Lock wait timeout exceeded; try restarting transaction
+
+Running query on first connection
+Got 1 for first connection
+Running query on second connection
+
+Warning: mysqli_result::fetch_row(): Error while reading a row in %s on line %d
+Got 0 for second connection
--- /dev/null
+--TEST--
+Bug #79375: mysqli_store_result does not report error from lock wait timeout
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo') || !extension_loaded('pdo_mysql')) die('skip not loaded');
+require_once(__DIR__ . DIRECTORY_SEPARATOR . 'skipif.inc');
+require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
+MySQLPDOTest::skip();
+?>
+--FILE--
+<?php
+require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
+
+function createDB(): PDO {
+ $db = MySQLPDOTest::factory();
+ $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+ $db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
+ return $db;
+}
+
+$db = createDB();
+$db2 = createDB();
+$db->query('DROP TABLE IF EXISTS test');
+$db->query('CREATE TABLE test (first int) ENGINE = InnoDB');
+$db->query('INSERT INTO test VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9)');
+
+function testNormalQuery(PDO $db, string $name) {
+ $db->exec("SET innodb_lock_wait_timeout = 1");
+ $db->exec("START TRANSACTION");
+ $query = "SELECT first FROM test WHERE first = 1 FOR UPDATE";
+ echo "Running query on $name\n";
+ try {
+ $stmt = $db->query($query);
+ echo "Got {$stmt->rowCount()} for $name\n";
+ } catch (PDOException $e) {
+ echo $e->getMessage()."\n";
+ }
+}
+
+function testPrepareExecute(PDO $db, string $name) {
+ $db->exec("SET innodb_lock_wait_timeout = 1");
+ $db->exec("START TRANSACTION");
+ $query = "SELECT first FROM test WHERE first = 1 FOR UPDATE";
+ echo "Running query on $name\n";
+ $stmt = $db->prepare($query);
+ try {
+ $stmt->execute();
+ echo "Got {$stmt->rowCount()} for $name\n";
+ } catch (PDOException $e) {
+ echo $e->getMessage()."\n";
+ }
+}
+
+function testUnbuffered(PDO $db, string $name) {
+ $db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);
+ $db->exec("SET innodb_lock_wait_timeout = 1");
+ $db->exec("START TRANSACTION");
+ $query = "SELECT first FROM test WHERE first = 1 FOR UPDATE";
+ echo "Running query on $name\n";
+ $stmt = $db->prepare($query);
+ $stmt->execute();
+ try {
+ $rows = $stmt->fetchAll();
+ $count = count($rows);
+ echo "Got $count for $name\n";
+ } catch (PDOException $e) {
+ echo $e->getMessage()."\n";
+ }
+}
+
+testNormalQuery($db, 'first connection');
+testNormalQuery($db2, 'second connection');
+unset($db);
+unset($db2);
+echo "\n";
+
+$db = createDB();
+$db2 = createDB();
+testPrepareExecute($db, 'first connection');
+testPrepareExecute($db2, 'second connection');
+unset($db);
+unset($db2);
+echo "\n";
+
+$db = createDB();
+$db2 = createDB();
+testUnbuffered($db, 'first connection');
+testUnbuffered($db2, 'second connection');
+unset($db);
+unset($db2);
+echo "\n";
+
+?>
+--CLEAN--
+<?php
+require __DIR__ . '/mysql_pdo_test.inc';
+MySQLPDOTest::dropTestTable();
+?>
+--EXPECT--
+Running query on first connection
+Got 1 for first connection
+Running query on second connection
+SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction
+
+Running query on first connection
+Got 1 for first connection
+Running query on second connection
+SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction
+
+Running query on first connection
+Got 1 for first connection
+Running query on second connection
+SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction