Bug #78932 [Ver->Csd]: Cannot fetch mysqli_prepare error if $statement variable reused
| From: | craig at craigfrancis dot co dot uk | Date: | Tue, 08 Dec 2020 18:51:13 +0000 |
| Subject: | Bug #78932 [Ver->Csd]: Cannot fetch mysqli_prepare error if $statement variable reused | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-230944@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=78932&edit=1
ID: 78932
User updated by: craig at craigfrancis dot co dot uk
Reported by: craig at craigfrancis dot co dot uk
Summary: Cannot fetch mysqli_prepare error if $statement
variable reused
-Status: Verified
+Status: Closed
Type: Bug
Package: MySQLi related
PHP Version: 7.3.12
Block user comment: N
Private report: N
New Comment:
Thanks for the update.
I think I follow, even though it's still a bit weird/unexpected.
Previous Comments:
------------------------------------------------------------------------
[2020-12-08 01:02:50] dharman@php.net
Although unexpected, this is the correct behaviour. As nikic explained the destructor of mysqli_stmt
is called once a new value is assigned to the same variable. The destructor performs a close
operation on the MySQL server. Each time a command is sent, the error message is reset. You would
need to check the error message before the mysqli_stmt is closed.
Your code example would be equivalent to the following:
if (false === ($statement1 = mysqli_prepare($link, 'SELECT 1'))) {
exit(mysqli_errno($link) . ': ' . mysqli_error($link));
}
if (false === ($statement2 = mysqli_prepare($link, 'SELECT 1 FROM
this_table_does_not_exist'))) {
exit(mysqli_errno($link) . ': ' . mysqli_error($link));
}
if (false === mysqli_stmt_close($statement1)) {
exit(mysqli_errno($link) . ': ' . mysqli_error($link));
}
if (false === mysqli_stmt_close($statement2)) {
exit(mysqli_errno($link) . ': ' . mysqli_error($link));
}
However, the recommended practice would be to enable automatic error reporting and stop worrying
about manual error checking. With automatic error reporting an exception is triggered as soon as the
error happens. To enable automatic error reporting just add the following line before making a
connection.
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
------------------------------------------------------------------------
[2019-12-09 08:36:55] nikic@php.net
The problem here is that the original $statement gets destroyed when the next assignment to the
variable happens (that is, after the second prepare has finished). When the old $statement is
destroyed a close_on_server operation on the statement is issued. This is going to reset the error
state, because it performs a number of operations that may in themselves fail (like exhausting the
result and closing the statement), and the error result from those operations will be used. As they
don't fail, the error ends up being zero.
I don't really know what we should be doing about this. I guess one possibility is to back up
the error information before we do an *implicit* close, as opposed to an explicit close with
mysqli_stmt_close() (in which case we *do* want to report errors from that operation).
------------------------------------------------------------------------
[2019-12-09 08:26:16] nikic@php.net
Also reproduces on older PHP versions.
------------------------------------------------------------------------
[2019-12-08 21:27:49] craig at craigfrancis dot co dot uk
Description:
------------
When running the following test script, the error is not correctly shown.
But if you un-commented the
$statement = false line, then it works.
It's as though the $statement variable is not being properly replaced.
Test script:
---------------
<?php
$link = mysqli_connect('localhost', 'username', 'password',
'database');
$statement = mysqli_prepare($link, 'SELECT 1');
// $statement = false;
$statement = mysqli_prepare($link, 'SELECT 1 FROM this_table_does_not_exist');
if (!$statement) {
exit(mysqli_errno($link) . ': ' . mysqli_error($link));
}
?>
Expected result:
----------------
1146: Table 'database.this_table_does_not_exist' doesn't exist
Actual result:
--------------
0:
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=78932&edit=1