Problem
How to call two MySQL stored procedures in the same mysqli connection using prepared statements (or another query method equally safe against SQL injections) without getting the following errors:
Warning: Packets out of order. Expected 1 received 61. Packet size=7 in /...
Warning: mysqli::prepare(): MySQL server has gone away in /...
Got the code hooked up online at tutorialspoint
Story
I'm making a PHP backend with a MySQL database. I have two results that I want to get from one query: a list of weekly summaries, and a summary of all the weeks.
┌───────┬────────────┬────────────┬─────
| Week | Sales | Commission | ...
├───────┼────────────┼────────────┼─────
| week1 | $7,912.12 | $923.41 | ...
| week2 | $6,423.48 | $824.87 | ...
| week3 | $8,180.67 | $634.04 | ...
| ... | ... | ... | ...
├───────┼────────────┼────────────┼─────
| total | $67,012.23 | $7,532.58 | ...
| avg | $7,012.54 | $787.38 | ...
└───────┴────────────┴────────────┴─────
I used to just store the weekly summaries in a database table, and used a stored procedure to get the summary of all the weekly summaries. In my PHP code, I just selected all the rows in the week
table and then called the getWeeksSummary
stored procedure.
Now I have to be able to filter the data in the weekly summaries. I replaced a simple SELECT ... FROM week
with a stored procedure getWeeks()
to calculate all the weekly summaries.
Code
$weeksSummary = new stdClass();
if ($stmt = $mysqli->prepare('CALL getWeeks(?,?,?);')) {
$stmt->bind_param('sss', $a, $b, $c);
$stmt->execute();
$stmt->bind_result($week, $sales, $commission, ...);
$weeksSummary->weeks = [];
while($stmt->fetch())
{
$week = new stdClass();
$week->week = $week;
$week->sales = $sales;
$week->commission = $commission;
...
$weeksSummary->weeks[] = $week;
}
$stmt->free_result();
$stmt->close();
}
if ($stmt = $mysqli->prepare('CALL getWeeksSummary(?,?,?);')) {
$stmt->bind_param('sss', $a, $b, $c);
$stmt->execute();
$stmt->bind_result($avgSales, $totSales, $avgCommission, $totCommission ...);
$stmt->fetch();
$weeksSummary->summary = new stdClass();
$weeksSummary->summary->avgSales = $avgSales;
$weeksSummary->summary->totSales = $totSales;
$weeksSummary->summary->avgCommission = $avgCommission;
$weeksSummary->summary->totCommission = $totCommission;
...
$stmt->free_result();
$stmt->close();
}
echo json_encode($weeksSummary);
This code worked fine when the first prepared statement was SELECT week, sales, commission, ... FROM week WHERE a=?, b=?, c=?;
instead of CALL getWeeks(?,?,?);
. Now I get these errors:
Warning: Packets out of order. Expected 1 received 61. Packet size=7 in /...
Warning: mysqli::prepare(): MySQL server has gone away in /...
Attempts
1) Failed: I used a new statement object $stmt2
for the second query. Same errors.
2) Success: I closed the mysqli
connection and opened a new one before the second statement. A second mysqli
connection with its own prepared statement does run fine, but the code to connect to the database is kept completely separate, so that doesn't really help.
3) Failed: Just out of curiosity, I went back to my original working code and reordered the statements, putting the stored procedure statement before the SELECT
statement. Same errors. So the mysqli
connection is fine with queries before the stored procedure, but doesn't like anything after the stored procedure.
4) Failed: I tried putting $mysqli->next_result();
after the first statement. Same errors. However, if I use query()
instead of prepare()
to call the stored procedures, the next_result()
does indeed allow both stored procedures to run. I'd like to use prepared statement though, as they help against SQL injections.
Undesirable Potential Solutions
A): I could separate it into two calls to the back-end, but the summaries would be out of sync on the front-end when data refreshes.
B): I could join them into one MySQL stored procedure and then separate them in PHP, but I need them separate as well, so the same code would be there twice.
C): I could stop using prepared statements, but I don't know any other ways to avoid SQL injections.
Help
Any suggestions?