php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71803 MySQLi doesn't properly update connection error with persistent connections
Submitted: 2016-03-11 18:23 UTC Modified: 2017-10-23 15:46 UTC
Votes:6
Avg. Score:4.7 ± 0.5
Reproduced:6 of 6 (100.0%)
Same Version:5 (83.3%)
Same OS:5 (83.3%)
From: jeff dot minard at creditkarma dot com Assigned: bjori (profile)
Status: Assigned Package: MySQLi related
PHP Version: 5.6.19 OS: CentOS
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2016-03-11 18:23 UTC] jeff dot minard at creditkarma dot com
Description:
------------
Essentially, it would appear that when creating a mysql connection, without persistence, each time you call the mysqli_connect() method it will clear the "last error" state value so calls to mysqli_connect_error() work correctly.

However, when you user presistent connections this doesn't work correctly. I suspect that the mysqli_connect() method is, when doing persistence, shortcutting the method and not clearing the state for what mysqli_connect_error() reads from. IE:

function mysqli_connect(...params) {
  if (host is persistent) {
    setup persistentHost
    return true
  }
  clearErrorState()
  doNormalConnectStuff()
}

As terrible psuedo code, I suspect that something like that is happening which causes the state to not reset until the next real connection happens (instead of pulling an existing connection from the pool).

Test script:
---------------
<?php

$mysql1 = '172.17.0.67';
$mysql2 = '172.17.0.69';

$conn = @mysqli_connect($mysql1, 'root', 'root', 'mysql', '3306');
echo "Err?: " . ( $conn ? 'connected' : 'conn fail' ) . ' -- ' . mysqli_connect_errno() . ': ' . mysqli_connect_error() . "\n";

$conn = @mysqli_connect($mysql2, 'root', 'root', 'mysql', '3307'); // note: WRONG PORT
echo "Err?: " . ( $conn ? 'connected' : 'conn fail' ) . ' -- ' . mysqli_connect_errno() . ': ' . mysqli_connect_error() . "\n";

$conn = @mysqli_connect($mysql1, 'root', 'root', 'mysql', '3306');
echo "Err?: " . ( $conn ? 'connected' : 'conn fail' ) . ' -- ' . mysqli_connect_errno() . ': ' . mysqli_connect_error() . "\n";

$conn = @mysqli_connect($mysql2, 'root', 'root', 'mysql', '3306');
echo "Err?: " . ( $conn ? 'connected' : 'conn fail' ) . ' -- ' . mysqli_connect_errno() . ': ' . mysqli_connect_error() . "\n";

$mysql1 = 'p:' . $mysql1;
$mysql2 = 'p:' . $mysql2;

$conn = @mysqli_connect($mysql1, 'root', 'root', 'mysql', '3306');
echo "Err?: " . ( $conn ? 'connected' : 'conn fail' ) . ' -- ' . mysqli_connect_errno() . ': ' . mysqli_connect_error() . "\n";

$conn = @mysqli_connect($mysql2, 'root', 'root', 'mysql', '3307'); // note: WRONG PORT
echo "Err?: " . ( $conn ? 'connected' : 'conn fail' ) . ' -- ' . mysqli_connect_errno() . ': ' . mysqli_connect_error() . "\n";

$conn = @mysqli_connect($mysql1, 'root', 'root', 'mysql', '3306');
echo "Err?: " . ( $conn ? 'connected' : 'conn fail' ) . ' -- ' . mysqli_connect_errno() . ': ' . mysqli_connect_error() . "\n";

$conn = @mysqli_connect($mysql2, 'root', 'root', 'mysql', '3306');
echo "Err?: " . ( $conn ? 'connected' : 'conn fail' ) . ' -- ' . mysqli_connect_errno() . ': ' . mysqli_connect_error() . "\n";

Expected result:
----------------
Err?: connected -- 0:
Err?: conn fail -- 2003: Can't connect to MySQL server on '172.17.0.69' (111)
Err?: connected -- 0:
Err?: connected -- 0:
Err?: connected -- 0:
Err?: conn fail -- 2003: Can't connect to MySQL server on '172.17.0.69' (111)
Err?: connected -- 0:
Err?: connected -- 0:

Actual result:
--------------
Err?: connected -- 0:
Err?: conn fail -- 2003: Can't connect to MySQL server on '172.17.0.69' (111)
Err?: connected -- 0:
Err?: connected -- 0:
Err?: connected -- 0:
Err?: conn fail -- 2003: Can't connect to MySQL server on '172.17.0.69' (111)
Err?: connected -- 2003: Can't connect to MySQL server on '172.17.0.69' (111)
Err?: connected -- 0:

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-03-11 18:42 UTC] jeff dot minard at creditkarma dot com
Looks like the mysqli c code from here:

https://github.com/php/php-src/blob/71c19800258ee3a9548af9a5e64ab0a62d1b1d8e/ext/mysqli/mysqli_nonapi.c#L186

Will jump over this

https://github.com/php/php-src/blob/71c19800258ee3a9548af9a5e64ab0a62d1b1d8e/ext/mysqli/mysqli_nonapi.c#L259

Which means the errors don't get reset even though the "connect" call was successful.
 [2017-03-21 00:24 UTC] domainadmin at digitalaxcess dot com
This happens also when script wants to create two separate mysqli connections.

Example:

$db_host1 = 'localhostinvalid';
$db_host2 = 'localhost';
$db_user = 'username';
$db_pass = 'password';
$db_name = 'dbname';

$db1 = @new mysqli($db_host1, $db_user, $db_pass, $db_name);
if ($db1->connect_errno) { echo $db1->connect_error.'<br/>'; } else { echo 'Ok<br/>';}

$db2 = @new mysqli($db_host2, $db_user, $db_pass, $db_name);
if ($db1->connect_errno) { echo $db1->connect_error.'<br/>'; } else { echo 'Ok<br/>';}

Result:
php_network_getaddresses: getaddrinfo failed: Name or service not known
Access denied for user 'username'@'localhost' (using password: YES)

$db1 will fail as it tries to connect to an invalid host, and the error message will indicate so. Note that second "if" operates again on $db1, and the error message of $db1->connect_error will be overwritten by whatever happened to $db2 (second connection), or if $db2 connection was successful, $db1 will indicate the same even though $db1 wasn't successful and "Ok" will be printed. Tested on 5.5 and 7.0.
 [2017-04-02 14:50 UTC] tpunt@php.net
-Package: mysql +Package: MySQLi related
 [2017-10-23 15:46 UTC] bjori@php.net
-Assigned To: +Assigned To: bjori
 
PHP Copyright © 2001-2018 The PHP Group
All rights reserved.
Last updated: Wed Dec 12 07:01:25 2018 UTC