php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #81494 Stopped unbuffered query does not throw error
Submitted: 2021-10-01 14:22 UTC Modified: 2021-10-08 12:36 UTC
From: madri2 at gmail dot com Assigned:
Status: Closed Package: MySQLi related
PHP Version: Irrelevant OS:
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: madri2 at gmail dot com
New email:
PHP Version: OS:

 

 [2021-10-01 14:22 UTC] madri2 at gmail dot com
Description:
------------
Do an unbuffered mysqli query and do a while to read all results,
kill the mysql request in mysql, then php will only trigger a warning when doing fetch_assoc
Warning: mysqli_result::fetch_assoc(): Error while reading a row

while ($found = $req->fetch_assoc()) {

}

will only stop the loop when the mysql query is killed, instead of throwing an error

I've tried to set mysqli_report(MYSQLI_REPORT_ALL & ~MYSQLI_REPORT_INDEX);
but this doesn't change anything

Expected result:
----------------
An exception thrown

Actual result:
--------------
Warning: mysqli_result::fetch_assoc(): Error while reading a row

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-10-01 14:24 UTC] nikic@php.net
-Status: Open +Status: Feedback
 [2021-10-01 14:24 UTC] nikic@php.net
Please provide a full reproducer.
 [2021-10-04 12:17 UTC] madri2 at gmail dot com
-Status: Feedback +Status: Open
 [2021-10-04 12:17 UTC] madri2 at gmail dot com
<?php
error_reporting(E_ALL);
set_time_limit(0);

ini_set('memory_limit','2000M'); 
ini_set('display_errors', true); 

$dbo = mysqli_connect('localhost', 'xxx', 'yyy', '');
$dbo2 = mysqli_connect('localhost', 'xxx', 'yyy', '');

mysqli_report(MYSQLI_REPORT_ALL & ~MYSQLI_REPORT_INDEX);


$req = $dbo->query("SELECT * FROM mustBeATableBigEnough", MYSQLI_USE_RESULT);
$numFound = 0;

while ($found = $req->fetch_assoc()) {
    $numFound++;

    $req2 = $dbo2->query("SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID = '".$dbo->thread_id."'");
    if ($found2 = $req2->fetch_assoc()) {
        print_r($found2);
        $dbo2->query("KILL ".$found2['ID']);
    }
    $req2->free();
}
$req->free();

echo 'numFound : '.$numFound."\n";



it outputs :
Array
(
    [ID] => 2348965
    [USER] => yyyyy
    [HOST] => localhost
    [DB] => zzzzzz
    [COMMAND] => Query
    [TIME] => 0
    [STATE] => Sending data
    [INFO] => SELECT * FROM xxxx
    [TIME_MS] => 1.708
    [STAGE] => 0
    [MAX_STAGE] => 0
    [PROGRESS] => 0.000
    [MEMORY_USED] => 212672
    [MAX_MEMORY_USED] => 212672
    [EXAMINED_ROWS] => 0
    [QUERY_ID] => 554751313
    [INFO_BINARY] => SELECT * FROM xxxx
    [TID] => 3625133
)

Warning: mysqli_result::fetch_assoc(): Error while reading a row in ....testBug.php on line 54
numFound : 52


the table contains millions of entries
 [2021-10-04 12:34 UTC] nikic@php.net
-Summary: Stopped unbuffered query does not throw error +Summary: Variables become null in if statements -Status: Open +Status: Verified -Operating System: debian +Operating System: Linux -PHP Version: 7.4.24 +PHP Version: 7.4.16
 [2021-10-04 12:35 UTC] nikic@php.net
-Summary: Variables become null in if statements +Summary: Stopped unbuffered query does not throw error -Operating System: Linux +Operating System: -PHP Version: 7.4.16 +PHP Version: Irrelevant
 [2021-10-04 12:35 UTC] nikic@php.net
Oops, some autocomplete messed things up. I only wanted to change the status to Verified...
 [2021-10-08 12:36 UTC] nikic@php.net
After looking a bit closer, I believe the key problem here is that this is calling a method on mysqli_result, while the error is reported on the connection (or stmt) and the result doesn't have access to the connection.

So either we need to store the connection object in the mysqli result object, or we need to recover it from the underlying driver -- mysqlnd has a conn field, which stores a reference to the connection data, so we could use the low level API to access the error information.
 [2021-10-08 13:03 UTC] git@php.net
Automatic comment on behalf of nikic
Revision: https://github.com/php/php-src/commit/fcabe693ba19ff60fc735aebe42f8ccc5f139bec
Log: Fixed bug #81494
 [2021-10-08 13:03 UTC] git@php.net
-Status: Verified +Status: Closed
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Mar 28 13:01:28 2024 UTC