Bin in folgendes Szenario gerauscht:
DB = SQLite
Ich hab ein TSQLQuery-Objekt, welches ich "wiederverwende" (wie wahrscheinlich wir alle).
Was ich jedes Mal mache:
Code: Alles auswählen
MyQuery.Close;
MyQuery.SQL.Clear;
MyQuery.SQL.Text:=EinSQLStatement;
//Optional setze Parameter mit MyQuery.ParamByName(':pEinParam').AsString:='Irgendwas'; //oder auch Integer oder was auch immer
MyQuery.Open; //Oder ExecSQL;
//Optional: Commit/CommitRetaining;
Ich nutze das Objekt um ein SQL-Statement auszuführen, hole das Ergebnis ab, speicher das irgendwo oder es löst eine Aktion aus.
Ich verwende dasselbe Objekt, um ein weiteres SQL-Statement auszuführen, welches Parameter hat, setze die Parameter und Feuer frei.
Ich verwende WIEDER dasselbe Objekt, setzt aber diesmal als erstes "ParamCheck:=False", da ich im SQL-String zwei Parameter als Literals an die Datenbank senden muss.
(Ist ein CREATE TABLE-Statement)
Beispielhaft:
Code: Alles auswählen
MyQuery.Close;
MyQuery.SQL.Clear;
MyQuery.SQL.Text:=EinSQLStatement;
MyQuery.Open;
//Mache etwas mit dem Ergebnis
MyQuery.Close;
MyQuery.SQL.Clear;
MyQuery.SQL.Text:=EinSQLStatementMitEinemParametern;
MyQuery.ParamByName(':pEinParam').AsString:='Irgendwas';
MyQuery.Open;
//Mache etwas mit dem Ergebnis
MyQuery.Close;
MyQuery.ParamCheck:=False; //<-----!!!!!
MyQuery.SQL.Clear;
MyQuery.SQL.Text:=EinSQLStatementMitZweiParameternAlsLiterals;
MyQuery.ExecSQL; //--> KABUMM!
und genau beim letzten Schritt hats geknallt --> Index out of Bounds
Was ist es gewesen?
Die Params-Auflistung bleibt gecached!
Heisst: Obwohl ich ParamCheck:=False habe, will der Code dennoch Param-Bindings durchführen, weil eben Params.Count>0 ist.
Und in dem Fall hatte ich sogar "Glück" dass es eine unterschiedliche Zahl an Params war im Vergleich zu den Literals im SQL-String.
Ich denke nicht dass ich eine Exception bekommen hätte, wenn die Zahl der gecachten Params gleich gewesen wäre mit der Zahl der Literal-Parameter
Die Lösung war ein explizites
Code: Alles auswählen
MyQuery.Close;
MyQuery.ParamCheck:=False;
MyQuery.Params.Clear; //<-----!!!!!
MyQuery.SQL.Clear;
MyQuery.SQL.Text:=EinSQLStatementMitZweiParameternAlsLiterals;
MyQuery.ExecSQL; //--> Kein KABUMM!Und jetzt die philosophische Frage: Ist das ein Bug?
Ich hätte erwartet, dass wenn ich explizit ein ParamCheck setze, und dabei egal, ob auf False oder True, da ich das True z.B. bei nachfolgenden Aufrufen wieder brauchen würde, die Params gelöscht werden.
Meinungen?
Und ja, ist wirklich so, dass ich "Parameter" als Literals an die DB schicken muss (Pivot-Tabellen-Erstellung)