Printanweisung mit variabler Länge erzeugen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Hallo,

ich möchte eine print-Anweisung erzeugen, die eine variable Anzahl von Argumenten hat.

Ich habe einen Print-String mit "%s"-Symbolen erzeugt, die mit der Anzahl der Elemente in values übereinstimmt.

Code: Alles auswählen

#!/usr/bin/env python

#value_list = []
#value_list.append (["1", "2", "3", "4"])
#value_list.append (["5", "6", "7", "8"])
#value_list.append (["9", "10", "11", "12"])

values = ["1", "2", "3", "4"]

print_string = ""
for i in range (0, values.__len__(), 1):
    Wert_str = ("   Wert %s: " % (i+1) )
    print_string = print_string + Wert_str + " %s"

print ("Wert 1: %s    Wert 2: %s    Wert 3: %s     Wert 4: %s" % (values[0], values[1], values[2], values[3]))

print (print_string % (values[0], values[1], values[2], values[3]))

print (print_string % values)

#for value_entry in value_list:
#   print (print_string % value_entry)
Diese Print-Anweisung funktioniert:

Code: Alles auswählen

print (print_string % (values[0], values[1], values[2], values[3]))
Diese Printanweisung muss ich aber manuell an die Anzahl der Elemente in values anpassen. Das gefällt mir nicht.

Ich habe daher versucht, die komplette Liste zu übergeben:

Code: Alles auswählen

print (print_string % values)
Leider funktioniert das nicht, dass Programm bricht an dieser Stelle ab. Leider habe ich noch keine Idee, wie ich das so mit varaibler Länge hinbekommen kann.

Wozu brauche ich das überhaupt - ich möchte in eine MySQL-Datenbank Werte hineinschreiben. Die Anzahl der Spalten ist aber veränderlich. Ich habe versucht, mein Problem so wie in diesem Beispiel zu vereinfachen. Wenn ich es hinbekomme, dass die print-Anweisung funktioniert, dann müsste ich dies auf die cursor.execute-Anweisung übertragen können

Falls mir jemand von Euch helfen könnte, würde ich mich sehr darüber freuen.
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Alternatives Programm:

Code: Alles auswählen

#!/usr/bin/env python

value_list = []
value_list.append (["1", "2", "3"])
value_list.append (["5", "6", "7"])
value_list.append (["9", "10", "11"])

table_name = "Hexentabelle"
table_column_names = ["Name", "Alter", "Besenflugberechtigung"]

values = ["1", "2", "3"]

column_name_str = ""
percent_str     = ""

i = 1
for column_name in table_column_names:
    if i == table_column_names.__len__():
        percent_str = percent_str + "%s"
        column_name_str = column_name_str + column_name
    else:
        percent_str = percent_str + "%s, "
        column_name_str = column_name_str + column_name + ", "
    i = i+1

execute_string = ("INSERT INTO %s (%s) VALUES (%s)" %(table_name, column_name_str, percent_str) )
print execute_string

# Hier das, was ich erreichen moechte:

cursor.execute (execute_string %values )

# oder in einer laengeren Liste:

for value in value_list:
    cursor.execute (execute_string %value)
    
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Weil values ein Tuple sein müsste. Und nochwas, __len__ hat nicht umsonst zwei Unterstriche und warum nutzt du kein len()?
Und ich hasse es wenn zwischen Bezeichnern und Klammer unnötigerweise Leerzeichen stehen.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
BlackJack

@Papp Nase: Ein paar Anmerkungen:

Auch wenn es nur ein Beispielquelltext ist: Konkrete Typen sollte man nicht in Namen schreiben. Wenn man den Typ mal ändert, zum Beispiel aus einer Liste ein Tupel oder ein `set` macht, muss man entweder auch überall den Namen ändern, oder man hat einen irreführenden Namen im Programm stehen.

Das erstellen der ersten Liste mit den wiederholten `append()`-Aufrufen ist unnötig umständlich. Man kann Listenliterale auch verschachteln.

Die Zeilen 13 bis 24 sind neben der `__len__()`-Geschichte ebenfalls viel zu umständlich und „unpythonisch”. Zeichenketten sollte man nicht durch wiederholtes ``+`` oder ``+=`` in einer Schleife aufbauen, weil das ineffizient ist. Zeichenketten sind in Python unveränderbar, dass bedeutet in jedem Schleifendurchlauf wird die bisherige Zeichenkette und das was angehängt werden soll in einen neuen Speicherbereich kopiert und die bisherige Zeichenkette wird freigegeben. Dabei wird die Datenmenge in jedem Durchlauf grösser. Idiomatisches Python sammelt deshalb die Teilzeichenketten in einer Liste und setzt die dann mit Hilfe der `str.join()`-Methode zusammen. Dann muss man auch nicht selber den Fall des letzten Durchlaufs berücksichtigen. Anstelle einer Liste kann man auch einen Generatorausdruck direkt als Argument für `join()` verwenden, wo sich das anbietet.

Beim ``%``-Operator hast Du bei der Schreibweise immer eine Asymmetrie‽ Das ist ein binärer Operator wie ``+``, ``-``, oder ``*``, da sieht es komisch aus wenn nicht auf beiden Seiten ein Leerzeichen zu den Operanden steht. Man schreibt ja auch nicht ``c = a +b``.

Bei neuem Quelltext würde ich auch die `format()`-Methode dem ``%``-Operator vorziehen wo das geht.

Bei `execute()` sollte man weder den ``%`` noch die `format()`-Methode verwenden um Werte für eine Anfrage zu übergeben für die es Platzhalter gibt. Das ist eine Sicherheitslücke, Stichwort „SQL injection”. Ausserdem können DBMS die intern in einen Ablaufplan kompilierte SQL-Anweisung nicht für mehrere Anfragen cachen wenn das SQL sich bei jeder dieser Anfragen ändert. Die `execute()`-Methode kennt für Werte eine zweites, optionales Argument.

Und wenn man eine Anweisung mit Platzhaltern auf mehrere Sätze von Werten anwenden möchte, gibt es die `execute_many()`-Methode, bei der die SQL-Anweisung vom DBMS nur einmal verarbeitet werden muss statt für jeden Wertesatz erneut.

Ich bin dann bei so etwas (ungetestet):

Code: Alles auswählen

    records = [['1', '2', '3'], ['5', '6', '7'], ['9', '10', '11']]

    table_name = 'Hexentabelle'
    table_column_names = ['Name', 'Alter', 'Besenflugberechtigung']

    sql_value_placeholder = '%s'
    sql = 'INSERT INTO {0} ({1}) VALUES ({2})'.format(
        table_name,
        ', '.join(table_column_names),
        ', '.join([sql_value_placeholder] * len(table_column_names)),
    )
    print sql

    cursor.execute(sql, records[0])
    cursor.executemany(sql, records)
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@Papp Nase: Das hier ist wirklich wichtig:
BlackJack hat geschrieben:Bei `execute()` sollte man weder den ``%`` noch die `format()`-Methode verwenden um Werte für eine Anfrage zu übergeben für die es Platzhalter gibt. Das ist eine Sicherheitslücke, Stichwort „SQL injection”.
Siehe auch http://xkcd.com/327.
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Wenn man nicht nur Werte sondern auch Bezeichner beliebig haben will, ist das Zusammenbauen des Strings die einzige Möglichkeit. Zeigt ja auch das Beispiel.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
BlackJack

@darktrym: Ja, aber die Werte sollte man halt in jedem Fall *nicht* mit Zeichenkettenoperationen selbst einfügen. Bei den Tabellen- und Spaltennamen gilt natürlich, dass man die vorher entsprechend absichert.
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Also dann im ersten Schritt den String samt Platzhalter um anschließend prepared statement drüberlaufen zu lassen.
Ich glaub ich muss da schnell noch was fixen.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Guten Abend!

Vielen Dank für die Tipps, die ich von Euch bekommen habe.

Ich komme mit dem Begriff SQL-Injection in dem von mir gefragten Beispiel nicht klar. Ich habe mir dazu ein youtube-Lernvideo angeschaut. In diesem Video hat ein Mensch in eine Suchanfrage heimlich in den Suchstring weitere SQL-Befehle eingebaut, die dann vom SQL-Server nicht als Suchanfrage gewertet wurden, sondern als Befehl interpretiert würde.

Auf das Beispiel von mir bezogen würde ich mir da vorstellen, dass z.B. in diese Zeile:

Code: Alles auswählen

records = [['1', '2', '3'], ['5', '6', '7'], ['9', '10', '11']]
heimlich etwas eingebaut wird, z.B.

Code: Alles auswählen

records = [['1', '2', '3'], ['5', '6', '7'], ['9', '10', '11 and where ID = 1']]
Viele Beispiele - die man auch im Netz findet, arbeiten dann aber auch mit dem %s in der execute-Anweisung für den SQL-Zugriff

Das ist jetzt einfach nur ein Beispiel, vielleicht funktioniert das mit "and whrere ID = 1" nicht, aber vom Prinzip her wird so einfach an irgendeiner Stelle der eigentliche SQL-Befehl abgeändert - so verstehe ich jetzt die SQL-Injection.

In dem youtube-Video konnte der Hacker über solche heimlichen Zusatzabfragen z.B. auf User-Tabellen drauf zugreifen und auch Passwörter ausspähen.

Aber ich kann doch Rechte definieren beim Erstellen der Benutzer. Wenn ich doch jetzt Benutzer erstelle, so kann ich doch genau definieren, welche SQL-Befehle ausgeführt werden dürfen und in welche Tabellen/Datenbanken der jeweilige User drauf zugreifen kann. Jetzt konnte z.B. der Gastuser auf die User-Tabelle mittels der Zusatzabfragen auch Werte aus dieser anderen Tabelle auslesen. Was ist aber denn, wenn ich diese Tabellen sperre?

Ich möchte ja in meinem Beispiel "nur" Werte in eine Datenbank schreiben. Also benötige ich den Befehl "INSERT INTO". Ich kann doch andere Befehle dem Benutzer entziehen, z.B. den drop-Befehl. Wenn also dann über den User heimlich ein drop-Befehl eingebaut wird, dann kann der doch garnicht ausgeführt werden. Genauso kann ich doch wichtige Tabellen, in der z.B. Passwörter gespeichert sind, sperren, die dann nur als root eingesehen werden können.

Aber die ganze SQL-Injection basiert doch darauf, dass jemand von Außen auf eine Datenbank drauf zugreift und z.B. über die Suchenfunktion heimlich seine Kommandos einbaut.

Das SQL-Kommando muss aber doch als String vorliegen, dementsprechend muss ich mir doch meine execute_command mit den Stringfeldern zusammenbauen.

Ihr schreibt mir jetzt in Euren Beiträgen, dass man keine Stringoperationen zum Zusammenbauen des SQL-Kommandos verwenden soll, und dass keine Platzhalter verwendet werden sollen:
Bei `execute()` sollte man weder den ``%`` noch die `format()`-Methode verwenden um Werte für eine Anfrage zu übergeben für die es Platzhalter gibt
In einem Eurer Beispielcodes steht doch auch der Befehl:

Code: Alles auswählen

sql_value_placeholder = '%s'
Wie soll ich denn ohne das "%s" einen Wert an das execute-Kommando senden, wenn der von einer Variablen kommt?

Ich bekomme von irgendwoher z.B. Messwerte. Diese Messwerte sollen z.B. die Werte sein, die hier stehen:

Code: Alles auswählen

    records = [['1', '2', '3'], ['5', '6', '7'], ['9', '10', '11']]
Wie soll ich denn nun ohne ein &s oder das .format() die Werte in den Befehl einbauen? Ich stehe da grade echt vor einem Rätsel.

So wie ich Euch jetzt auch verstanden habe, besteht wo eine Gefahr darin, dass die Bezeichner beliebig sein sollen. Aber ich weis einfach nicht, wie ich das anders lösen soll. Ich benötige jetzt in meiner Tabelle vier Spalten. Es waren vorher erst drei Spalten, aber es ist ein Messwert hinzugekommen.

Ich kann natürlich den SQL-Befehl im Programm nicht variabel halten. Ändere ich nun die Anzahl der Parameter, dann kann ich im Quelltext etwas ändern. Ich wollte aber dazu übergehen, beim Programmstart die Informationen aus einer Initialisierungsdatei auszulesen. Genaus verhält es sich mit den Tabellen-Namen, die ich auf dem SQL-Server erstellt habe. Ich kann natürlich die Tabellennamen bei "INSERT INTO XXX (A, B, C)" einfach per Hand abändern "INSERT INTO XXX (Y, Z, V)". Aber von der späteren Administrierung des Programms ist es einfacher, wenn der SQL-Befehl variabel beim Programmstart angepasst werden kann.

Oder was ist, wenn ich in meinem Modul zum Senden an die Datenbank etwas einbaue und dieses Modul einmal für eine Tabelle mit 3 Messwerten verwende und an einer anderen Stelle von einem anderen Gerät mit zwei Messwerten? Ich könnte natürlich auch zweimal separate Funktionen für die eine Messerfassung haben und für die andere. Aber wenn ich dann später eine Anpassung vornehmen will/muss, die wäre dann an beiden Modulen vorzunehmen - was auch immer das sein könnte.

Im Summe fasse ich für mich jetzt zu der SQL-Injection-Problematik für mich zusammen - ich habe einen PC, an dem mehrere Geräte dranhängen, die Messwerte produzieren und in die Datenbank - die auf einem anderen Rechner liegt - abgespeichert werden. Es wird für den User, der dort schreiben darf, nur der "INSERT INTO" Befehl zugelassen. Andere Befehle dürfen dann doch garnicht ausgeführt werden können. Die Admin-Rechte auf dem MySQL-Server sind auf localhost beschränkt, jemand von einem anderen Rechner sollte also schon mal nicht ohne weiteres Admin-Rechte haben dürfen.

Eine andere Baustelle ist dann, was später mit den Messwerten weiter passiert. Dort könnte z.B. eine Webseite eine Datenbankabfrage durchführen - schicke mir alle Messwerte in Tabelle XYZ vom Datum X bis Datum Y. Dort könnte später z.B. ein Feld stehen, wo man die Werte eingeben kann. Aber um Werte abzufragen, benötige ich doch nur den Befehl "select". Und wenn das dann ein anderer User ist, als der von dem Rechner, welcher die Messwerte erfasst, und nur Werte auch nur aus dieser einen Tabelle lesen darf und keine anderen Abfragen möglich sind - spielt denn dann die SQL-Injection eine Rolle?

Für mich würde ich sagen, dass ich auf der Datenerfassungsseite, auf der ich mich gerade befinde, die Injection-Problematik nicht so stark beachten brauche. Vielleicht ist es auch ein Abwägen zw. einfacher Administrierung - wenn ich mir Spaltennamen etc. erst aus einer INI-Datei auslesen tue, dann aber den execute-Befehl mittels Stringoperationen erstellt werden muss - zu lasten der Sicherheit.
BlackJack

@Papp Nase: Das man auch auf Seite des DBMS noch einiges über Rechtevergabe regeln kann ist schön und gut, aber das ist kein Grund sich nicht auch gegen SQL-Injection zu schützen. Und letztendlich wird man in der Praxis kaum für jeden Endbenutzer auch einen Datenbankbenutzer anlegen, sondern üblicherweise einen Benutzer pro Anwendung und dann kann eine SQL-Injection alles nutzen was die Anwendung insgesamt darf.

Wenn also die Anwendung Benutzer über Passwörter authentifiziert die in der Datenbank gespeichert sind, dann muss die Anwendung die Rechte haben diese zu lesen und damit kann man da auch per SQL-Injection dran kommen. Das kann man restriktiver handhaben, wird aber selten gemacht.

Schau Dir in meinem Beispiel noch mal genau die `execute()`-Aufrufe an. Da sind zwar Platzhalter im SQL, und bei `MySQLdb` und einigen anderen Datenbankmodulen sind das leider auch '%s' wie für den ``%``-Operator, darum ist das vielleicht ein bisschen verwirrend, aber ich benutze nicht ``%`` um da Werte zu ersetzen. Diese Platzhalter werden vom Datenbankmodul ersetzt und zwar *sicher*, das heisst die Werte werden vorher „escaped” um eventuell vorhandenes SQL unschädlich zu machen. Im zweiten Fall, dem `executemany()` kann man die Werte ja auch gar nicht selbst einsetzen, denn da ist ja gerade der Witz das man *eine* SQL-Anweisung mit Platzhaltern angibt und mehrere Datensätze.
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Hier auf dieser Homepage
ist folgendes Beispiel zu finden:

Code: Alles auswählen

# Never do this -- insecure!
symbol = 'RHAT'
c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)

# Do this instead
t = ('RHAT',)
c.execute('SELECT * FROM stocks WHERE symbol=?', t)
print c.fetchone()

# Larger example that inserts many records at a time
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
             ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
             ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
            ]
c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)
Also - dass hier ist verboten:

Code: Alles auswählen

symbol = 'RHAT'
c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)
Das ist erlaubt:

Code: Alles auswählen

# Do this instead
t = ('RHAT',)
c.execute('SELECT * FROM stocks WHERE symbol=?', t)
print c.fetchone()
Ok, ich ersetze jetzt "%s" durch "?".

Da steht symbol = `RHAT' und ich könnte es jetzt erweitern symbol = 'RHAT + Schadbefehl'

Und warum kann ich jetzt hier nicht auch einen Schadbefehl anfügen?

t = ('RHAT + Schadbefehl',)?

Was macht die zweite Variante sicherer gegenüber der ersten?
BlackJack

@Papp Nase: Ob Du das '%s' durch '?' ersetzen kannst hängt vom Datenbankmodul ab! `sqlite3` verwendet '?' als Platzhalter (was übrigens auch SQL-Standard ist), aber `MySQLdb` verwendet '%s' als Platzhalter.

Bei der zweiten Variante wird der Platzhalter nicht einfach durch den Inhalt von `t` ersetzt sondern dort werden vorher gefährliche Zeichen „escaped” um sicherzustellen, dass das alles ein Wert ist und kein ausführbares SQL.

Aus ``42'; drop table passwords; --`` würde zum Beispiel ``42\'; drop table passwords; --`` damit das ``'`` den Wert nicht beendet und man wieder im „SQL-Modus” ist.

Edit: Sofern bei der zweiten Variante überhaupt eine Zeichenkette mit der SQL-Anweisung und den eingesetzten Werten erstellt wird. Bei DB-Modulen die SQL-Standard-Platzhalter verwenden kann man auch hoffen das die SQL-Anweisung und Werte separat an die DB schicken. Dann sieht die SQL-Anweisung unabhängig von den Daten nämlich immer gleich aus, und das DBMS braucht das SQL nicht jedes mal neu parsen und in einen Ablaufplan überführen, sondern kann den cachen.
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Hallo BlackJack, vielen Dank für Deine Hilfe.
BlackJack hat geschrieben:Schau Dir in meinem Beispiel noch mal genau die `execute()`-Aufrufe an. Da sind zwar Platzhalter im SQL, und bei `MySQLdb` und einigen anderen Datenbankmodulen sind das leider auch '%s' wie für den ``%``-Operator, darum ist das vielleicht ein bisschen verwirrend, aber ich benutze nicht ``%`` um da Werte zu ersetzen. Diese Platzhalter werden vom Datenbankmodul ersetzt und zwar *sicher*, das heisst die Werte werden vorher „escaped” um eventuell vorhandenes SQL unschädlich zu machen. Im zweiten Fall, dem `executemany()` kann man die Werte ja auch gar nicht selbst einsetzen, denn da ist ja gerade der Witz das man *eine* SQL-Anweisung mit Platzhaltern angibt und mehrere Datensätze.
Ok, ich hab es mir ein paar mal angeschaut. Du hast ja in Deinem Beispiel das {1} verwendet.
@Papp Nase: Ob Du das '%s' durch '?' ersetzen kannst hängt vom Datenbankmodul ab! `sqlite3` verwendet '?' als Platzhalter (was übrigens auch SQL-Standard ist), aber `MySQLdb` verwendet '%s' als Platzhalter.

Bei der zweiten Variante wird der Platzhalter nicht einfach durch den Inhalt von `t` ersetzt sondern dort werden vorher gefährliche Zeichen „escaped” um sicherzustellen, dass das alles ein Wert ist und kein ausführbares SQL.

Aus ``42'; drop table passwords; --`` würde zum Beispiel ``42\'; drop table passwords; --`` damit das ``'`` den Wert nicht beendet und man wieder im „SQL-Modus” ist.
Ach so, dieser feine Unterschied - 42' und 42\' ist schon weltbewegend, alle achtung. Also kapier ich das jetzt glaub ich endlich - bei der zweiten Variante wird also dafür gesorgt, dass ein Klammerausdruck nicht unterbrochen wird und wenn ich ein ' als Zeichen darstellen will, dann muss ich das Dingen \ davorsetzen, damit er es nicht als Steuerzeichen interpretiert, sondern als darzustellendes Zeichen und die Funktion interpretiert das als darzustellendes Zeichen, also wird der Klammerausdruck nicht böswillig unterbrochen, sondern ich krieg dann einfach einen langen Befehl.

Aber wenn ich jetzt als Tabelleneigenschaft ein int habe und will die 42 eintragen, es kommt dann aber nach der 42 noch der andere Rest hinten dran mit \' drop table passwords; --, dann müsste ja eine Fehlermeldung kommen, dass die Operation wegen inkompatibler Datentypen nicht in die Tabelle reingeschrieben werden kann.
BlackJack

Man kann sich das ja mal mit farbiger Syntaxhervorhebung anschauen was das für einen Unterschied macht:

Code: Alles auswählen

SELECT * FROM stocks WHERE symbol = 'RHAT'; DROP TABLE passwords; --'

SELECT * FROM stocks WHERE symbol = 'RHAT\'; DROP TABLE passwords; --'
Wenn die entsprechende Spalte in meinem Beispiel mit der 42 einen Zahltyp hat, dann gibt es natürlich eine Fehlermeldung, aber immerhin wird nicht versucht eine Tabelle zu löschen. :-)

Und wie gesagt: Wenn das DBMS „prepared statements” kennt, dann werden die Werte gar nicht erst in die SQL-Anweisung hinein formatiert. Das kann also auch effizienter sein.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Aber was ist schon Effizenz in Anbetracht von Effektivität? :K
BlackJack

@jerch: Naja beim `execute()` ist Effizienz ein netter Bonus zur effektiven Verhinderung von SQL-Injection, und bei `executemany()` wäre es alleine für sich schon ein Grund da für `n` Datensätze nicht `n` verschiedene SQL-Anweisungen an das DBMS zu füttern. Oder habe ich die Frage missverstanden?
Sirius3
User
Beiträge: 17746
Registriert: Sonntag 21. Oktober 2012, 17:20

@Papp Nase: es gibt 101 Gründe, warum das Übergeben von Werten in SQL-Statements mit Stringformatierung schlecht und mit Platzhaltern gut ist. Warum ist es gut, einen Sicherheitsgurt im Auto anzulegen oder statt aus dem 5. Stock zu springen, die Treppe zu nehmen?

1. Lesbarer: Befehl und Werte sind getrennt
2. Schneller: Werte werden direkt übergeben und müssen nicht erst geparst werden
3. Einfacher: man muß sich nicht selbst um das Escapen von Sonderzeichen bemühen
4. weniger Fehleranfälliger, weil weniger Komplex
5. Sicherer: es können nicht absichtlich oder unabsichtlich andere SQL-Befehle ausgeführt werden.

Punkt 5 ist nur ein netter Nebeneffekt, der in den meisten Fällen gar keine Rolle spielt. Die Punkt davor sollten Grund genug sein, sich zu merken, wie man Parameter übergibt, zumal es absolut keine Nachteile gibt.
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Vielen Dank für die vielen Tipps und Beispiele, die ich von Euch bekommen habe - ihr habt mir sehr weitergeholfen.
Antworten