I'm not sure if this is a bug in PHP, MySQL or me being stupid but very occasionally (and it is very rare) we call mysqli::query
and don't get FALSE
or a mysqli_result
object back.
We are running:
- PHP 5.5.9-1ubuntu4.3
- MySQL Ver 15.1 Distrib 5.5.38-MariaDB, for debian-linux-gnu (x86_64) using readline 5.1 (using Galera)
The query run was SHOW STATUS LIKE "Questions"
.
According to the manual for a SHOW
query we should ALWAYS get back either FALSE
or a mysqli_result
object, but we don't get either. This line of code runs over 100,000 times each day and fails about once a week.
Here is a snippet of code from our database wrapper (the function is only ever used for read queries):
public function read($query, $cache = 0) {
$total_time_start = microtime(1);
$deadlock_retries_done = 0;
$deadlock_retries_max = 10;
$other_error_retries_done = 0;
$other_error_retries_max = 10;
$return = array(); // Keeps IDEs happy!
while (true) {
$start = microtime(1);
$return = array();
$q = $this->connection->query($query, MYSQLI_STORE_RESULT);
$this->debug_last_query = $query;
// Was there an error?
if ($q === false) {
$error = $this->connection->error;
switch ($error) {
case 'Deadlock found when trying to get lock; try restarting transaction':
case 'Lock wait timeout exceeded; try restarting transaction':
$deadlock_retries_done++;
if ($deadlock_retries_done == $deadlock_retries_max) {
throw new SQLException($error . '. Re-tried with deadlock ' . $deadlock_retries_done . ' times. Query: ' . $query);
} else {
continue; // Try again
}
break;
case 'WSREP has not yet prepared node for application use':
$other_error_retries_done++;
if ($other_error_retries_done == $other_error_retries_max) {
throw new SQLException($error . '. Re-tried with error ' . $other_error_retries_done . ' times. Query: ' . $query);
} else {
if ($this->in_transaction) {
throw new SQLException($error . '. Re-tried with error ' . $other_error_retries_done . ' times. Cannot reconnect as in transaction. Query: ' . $query);
} else {
$this->close_and_establish_new_database_connection();
continue; // Try again
}
}
break;
default:
throw new SQLException($error . '. Query: ' . $query);
break;
}
}
// Check we have got a result
if (!$q instanceof mysqli_result) {
throw new SQLException('Seemed to have a result but it is not a mysqli_result object. Query: ' . $query);
}
// All worked ok, deal with the result
while (($row = $q->fetch_assoc())) {
$return[] = $row;
}
$end = microtime(1);
$this->debugData($start, $end, $query, 'DB', '', $total_time_start, $cache);
$this->last_affected_rows = $q->num_rows;
$q->free_result();
break;
}
return $return;
}
Obviously it calls some functions that are not included in the snippet, but you should get the idea.
The exception thrown is:
SQLException: Seemed to have a result but it is not a mysqli_result object. Query: SHOW STATUS LIKE "Questions"
I will add to our exception message something to output what $q
actually is and wait for it to happen again.
Has anyone else every experienced something like this and do you have anything to suggest? I really appreciate your help. Thanks
EDIT:
We have just had it happen on a really simple SELECT cols FROM table WHERE key = x LIMIT 1;
type query (real query not shown for security reasons, but it was about the most simple query you could have). This happened before my extra logging had gone live. I'll update here again when I get another with hopefully more details.