Alexander (HH): DBI und Platzhalter

Beitrag lesen

Moin Moin!

$anz = 'otto'; # provoziere Fehler, $anz muss integer sein

my $st = qq(
INSERT INTO warenkorb VALUES(?,?,?, NOW())
ON DUPLICATE KEY UPDATE anz = $anz, datime = NOW()
);

füg hier mal print $st; ein.

my $sth = $self->{DBH}->prepare($st);
eval { $sth->execute($self->{SID}, $self->{URL}, $anz) };

if($self->{EVE} = $@){
$self->{ERR} = $DBI::errstr;
return;
}
else { return 1 }
}
[/code]

Allerdings ist die Fehlermeldung unverständlich:

DBD::mysql::st execute failed: Unknown column 'otto' in 'field list'

Nein, sie ist komplett richtig.

Was zum Teufel passiert hier?

Genau das, was Du der Datenbank-Karrikatur befiehlst: Sollte das Insert scheitern, weise der Spalte anz den Wert der Spalte otto zu.

Setze ich direkt
eval { $sth->execute($self->{SID}, $self->{URL}, 'otto') };

erhalte ich wie erwartet ein
DBD::mysql::st execute failed: Incorrect integer value: 'otto' for column 'anz'

Was hast Du zwischen den tests noch am Code geändert? Laß mich raten: Du hast $anz='otto'; wieder rausgeschmissen, wodurch $anz wieder numerisch wurde.

Es gibt gute Gründe, Werte nicht direkt in SQL-Statements zu frickeln. Das Hauptargument heißt SQL Injection, und genau daran leidest Du gerade. Ein anderer Grund ist, dass Du damit das Caching von prepared Statements massiv sabotierst.

Schreib SQL in Single Quotes bzw. q() bzw. <<'__marker__', damit kommst Du gar nicht erst in Versuchung, Variablen in den String zu interpolieren.

Oh, und noch was: In welche Spalten schreibt Dein INSERT-Statement? Du hoffst auf die Default-Reihenfolge der Tabelle, und genau darauf würde ich mich niemals verlassen. Schon allein, weil diese Information an einer völlig anderen Stelle im Programm steht, wenn überhaupt. So ist das nicht wartbar. Benutze die Langform des INSERT-Statements, mit den Spaltennamen in Klammern und mit Kommas getrennt zwischen dem Tabellennamen und dem VALUES-Keyword. So funktioniert Dein Code auch noch, wenn irgendwann (z.B. Dein zukünftiges Ich) mal jemand die Tabellenstruktur ändert. Ich finde es ziemlich übel bis kaputt, dass SQL die Angabe der Spalten als optional definiert.

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".