
Immer wenn es schnell gehen muß – für ein Projekt hatte ich eine stored procedure angelegt, und auf der Konsole getestet. Alles wunderbar, aber – eingebunden in ein PHP Script bricht das Ganze mit der Meldung ab: “You can’t run this command now” – ich will aber, also wo war der Fehler?
In einer gespeicherten Prozedur können ganze Abläufe von Anweisungen unter einem Namen gespeichert werden, die dann auf dem Datenbankserver zur Verfügung stehen und ausgeführt werden können. Sie ist somit ein eigenständiger Befehl, der eine Abfolge von gespeicherten Befehlen ausführt. Solche Routinen können viel Logik in die Datenbank auslagern und sind gerade bei sich ständig wiederholenden Aufgaben äußerst hilfreich.
Zurück zum Problem – die Prozedur lief auf der Konsole einwandfrei, aber über das PHP Script war nichts zu machen. Die folgenden Zeilen dienen lediglich der Veranschaulichung des Problems, mit dem eigentlichen Skript hat dieser Code-Schnipsel nichts zu tun:
$mysqli = new MySQLI('host','user','pass','db');
$result = $mysqli->query("CALL myprocedure()");
$data = $result->fetch_assoc();
$result2 = $mysqli->query("SELECT something DIFFERENT");Ein solcher Aufruf schlägt fehl. Wahlweise man erhält den Fehler: “Lost connection to MySQL server during query“. Oder – für den Fall, dass man kein free auf das Ergebnis ($result) anwendet – eben “Commands out of sync; you can’t run this command now“. Der Grund: Eine stored procedure liefert nicht ein Ergebnis, sondern zwei – das Resultset zum einen und zum anderen eine Statusmeldung. Auch wenn es mich in dem Moment geärgert hat, der Fehler macht Sinn – sobald man sich das nächste Ergbnis abholen will, geht es nicht weiter, es hängt einfach noch ein Ergebnis in der Warteschleife (die Statusmeldung), jeder weitere REQUEST muß scheitern. Die Lösung: Anstatt $mysqli->query die Funktion $mysqli->multi_query verwenden:
$mysqli = new MySQLI('host','user','pass','db');
if($query = $mysqli->multi_query("CALL myprocedure()") {
$result = $mysqli->use_result();
$data = $result->fetch_assoc();
$result->free();
while ($mysqli->next_result()) {
$result = $mysqli->use_result();
if ($result instanceof mysqli_result) {
$result->free();
}
}
}
$result2 = $mysqli->query("SELECT something DIFFERENT");Diese Variante tat es für mich, und das Script lief wie gewünscht. Nachträglich bin ich dann noch auf einen Artikel gestoßen, der eben dieses “Phänomen” ausführlich beschreibt und neben der hier beschriebenen Lösung auch noch eine zweite Alternative anbietet – die Verwendung des statischen Aufrufes von MySQLI::query(). Manchmal bräuchte man halt nur die notwendige Ruhe und die richtigen Suchbegriffe.
