Why is mysqli giving a "Commands out of sync" error?
I am trying to run the following.
<?php
$db = mysqli_connect("localhost","user","pw") or die("Database error");
mysqli_select_db($db, "database");
$agtid = $_POST['level'];
$sql = sprintf("call agent_hier(%d)", $agtid);
$result = mysqli_query($db, $sql) or exit(mysqli_error($db));
if ($result) {
echo "<table border='1'>
<tr><th>id</th>
<th>name</th>
<th>parent_id</th>
<th>parent_name</th>
<th>level</th>
<th>email</th></tr>";
while ($row = mysqli_fetch_assoc($result))
{
$aid = $row["id"];
$sql2 = "SELECT * FROM members WHERE MEMNO = '$aid'";
$result2 = mysqli_query($db,$sql2) or exit(mysqli_error($db));
while ($newArray = mysqli_fetch_array($result2)) {
$fname = $newArray['FNAME'];
$lname = $newArray['LNAME'];
$mi = $newArray['MI'];
$address = $newArray['ADDRESS'];
$city = $newArray['CITY'];
$state = $newArray['STATE'];
$zip = $newArray['ZIP'];
$kdate = $newArray['KDATE'];
$date = abs(strtotime(date('m/d/Y')) - strtotime(date($kdate))) / (60 * 60 * 24);
}
echo sprintf("<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>",
开发者_开发问答 $row["id"],$row["name"],
$row["parent_id"],$row["parent_name"],
$row["level"],$row["email"]);
}
echo "</table>";
}
mysqli_free_result($result);
mysqli_close($db);
?>
If I remove lines from:
$aid = $row["agent_id"];
to....
$date = abs(strtotime(date('m/d/Y')) - strtotime(date($kdate))) / (60 * 60 * 24);
}
everything will work fine. If not, I get the following error:
Commands out of sync; you can't run this command now
In researching, I think it could be due to multiple MySQLi queries run at the same time, in which using mysqli_multi_query
but for all the samples and general data in the guide does not seem to be applicable.
Any ideas?
The MySQL client does not allow you to execute a new query where there are still rows to be fetched from an in-progress query. See Commands out of sync in the MySQL doc on common errors.
You can use mysqli_store_result()
to pre-fetch all the rows from the outer query. That will buffer them in the MySQL client, so from the server's point of view your app has fetched the full result set. Then you can execute more queries even in a loop of fetching rows from the now-buffered outer result set.
Or you mysqli_result::fetch_all()
which returns the full result set as a PHP array, and then you can loop over that array.
Calling stored procedures is a special case, because a stored procedure has the potential for returning multiple result sets, each of which may have its own set of rows. That's why the answer from @a1ex07 mentions using mysqli_multi_query()
and looping until mysqli_next_result()
has no more result sets. This is necessary to satisfy the MySQL protocol, even if in your case your stored procedure has a single result set.
PS: By the way, I see you are doing the nested queries because you have data representing a hierarchy. You might want to consider storing the data differently, so you can query it more easily. I did a presentation about this titled Models for Hierarchical Data with SQL and PHP. I also cover this topic in a chapter of my book SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming.
Here is how to implement mysqli_next_result()
in CodeIgnitor 3.0.3:
On line 262 of system/database/drivers/mysqli/mysqli_driver.php
change
protected function _execute($sql)
{
return $this->conn_id->query($this->_prep_query($sql));
}
to this
protected function _execute($sql)
{
$results = $this->conn_id->query($this->_prep_query($sql));
@mysqli_next_result($this->conn_id); // Fix 'command out of sync' error
return $results;
}
This has been an issue since 2.x. I just updated to 3.x and had to copy this hack over to the new version.
Simply, You have to call mysqli_next_result($db) , after mysqli_free_result is called.
mysqli_free_result($result); mysqli_next_result($db) mysqli_close($db);
simply call this function :
$this->free_result();
function free_result() {
while (mysqli_more_results($this->conn) && mysqli_next_result($this->conn)) {
$dummyResult = mysqli_use_result($this->conn);
if ($dummyResult instanceof mysqli_result) {
mysqli_free_result($this->conn);
}
}
}
You have to close previous connection hold by Stored Procedure. Instead of closing connection each time, you can simply use :
mysqli_next_result($conn);
For new mariaDb check in_predicate_conversion_threshold param. By default you can use up to 1000 attributes for "In" queries
If you are also making a few calls to stored procedures, and facing the aforementioned error, I have a solution for you, Mr. Wayne.
IMHO, Somewhere down the line, the CALL
to Stored Procedure
actually messes up the connection. So all you have to do is reset the database connection handle.
You could even have a function sitting in your config file doing just that for you, and all you do is call that function once before making any query
or CALL
to the Stored Procedure
My implementation is (just ignore the $app
since I am working on silex
framework it is there, YMMV)
function flushhandle() {
global $app;
global $db_host;
global $db_user;
global $db_pass;
global $db_name;
$app['mysqlio']->close();
$app['mysqlio'] = new mysqli($db_host, $db_user, $db_pass, $db_name);
return $app['mysqlio'];
}
精彩评论