Teile einer Abfrage über raw_Input()
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Man müsste eben selbst quoten (ich habe jetzt auch nichts gefunden, das das erledigt - warscheinlich hat aber das DB-API 2.0 konforme Modul da schon etwas fertiges).
Wenn du es aber selbst implementierst kannst du dich ja orientieren was PgQuoteString macht.
Wenn du es aber selbst implementierst kannst du dich ja orientieren was PgQuoteString macht.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Leonidas hat geschrieben:Man müsste eben selbst quoten (ich habe jetzt auch nichts gefunden, das das erledigt - warscheinlich hat aber das DB-API 2.0 konforme Modul da schon etwas fertiges).
Wenn du es aber selbst implementierst kannst du dich ja orientieren was PgQuoteString macht.

*verwirrt guck* ... damit kann ich jetzt gerade irgendwie gar nix anfangen

Ich glaub dann geht es doch einfacher und schneller ich beschränke die Eingabemöglichkeiten noch mehr ... so wie Gerold das macht, also Auswahlmöglicheiten stellen ...

(will/muss bis Ende Dezember mit Programmieren fertig sein für das Projekt und das mit dem selber quoten dauert dann wohl doch etwas länger, bis verstanden und umgesetzt, kommt aber auf jeden Fall mit auf die ToDO Liste zum angucken für danach

Danke euch allen.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Ich habe doch gesagt, dass selbst quoten in aller Regel nicht so einfach ist.
An sich ist es aber auch nicht so schwer, man muss nur unter Umständen "gefährliche" Zeichen, die nicht erlaubt sind escapen. Also etwa einen Backslash durch zwei, ein Quote durch ein escapetes-Quote, Tab als \t, etc.
An sich ist es aber auch nicht so schwer, man muss nur unter Umständen "gefährliche" Zeichen, die nicht erlaubt sind escapen. Also etwa einen Backslash durch zwei, ein Quote durch ein escapetes-Quote, Tab als \t, etc.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Ja, das ist mir klar. Aber warum sollte ich tabellen- oder feldnamen escapen wollen? Wie sieht eine software aus, wo solche namen aus nicht vertrauenswürdigen Quellen kommen?gerold hat geschrieben:Damit kannst du nur Werte ersetzen lassen. Tabellennamen oder Feldnamen kannst du damit nicht ergänzend in die SQL-Anweisung einfügen, da ein Text immer in Anführungszeichen gesetzt wird.keppla hat geschrieben:Indem du es nicht selber machst, sondern die API machen lässt
<loriot>ach?</loriot>Na da wo sie ein Anwender eingeben kann.
Ernsthaft: warum sollte man soetwas tun? Wenn ein Anwender bestimmen kann, auf welche Tabellen oder Felder queries losgelassen werden können, hilft escaping auch nicht mehr.
Um es mal plakativ darzustellen:
Code: Alles auswählen
delete from %s where %s = %s
Und selbst _wenn_ es denn nötig sein sollte, braucht man da kein escaping, sondern nur eine positivliste:
Code: Alles auswählen
cursor = conn.cursor()
conn.execute('show tables')
tables = set(row[0] for row in conn.fetchall)
table = raw_input("auf welche tabelle soll der query losgelassen werden?")
if not table in tables:
raise Exception("es sollte schon eine Tabelle sein")
cursor.execute("select * from %s" % table)
for row in cursor.fetchall():
print row
So etwas sollte man natürlich nicht tun wollen. Was aber nicht jeden davon abhält. 

keppla hat geschrieben: Ernsthaft: warum sollte man soetwas tun? Wenn ein Anwender bestimmen kann, auf welche Tabellen oder Felder queries losgelassen werden können, hilft escaping auch nicht mehr.
oh je oh je .... das will ich doch gar nicht

Alles was gehen soll, ist, das Teile des Where-Teiles formuliert werden sollen. Und das versuche ich so mininal wie möglich zu halten. Hab ich bei dem 2. Teil halt auch geschafft.
Ich will nur Indikatoren berechnen*, aus einer passenden Tabelle, wo die alle drin stehen, aber halt nicht alle auf einmal, sondern ich möchte das beschränken auf Kategorien - und da gibt es nicht nur eine, sondern 2 pro Indikator. Das kann am Ende recht viel werden. Also nicht nur KAT1 ="a" sondern vielleicht Kat 1 ="a" and (Kat2 ="A" OR Kat2 ="C"). Könnte aber auch sein, dass ich nru einen einzigen Indikator direkt selektiere über seine ID ... und das macht es irgenwie gerade etwas kompliziert ...
Funktioniert ja nun auch mit den Templates ganz gut

* das eigentliche Berechnen sind im Prinzip das eigentlich zu lösende Problem... das Selektieren aus der Datenbank brauch ich nur um an die Argumente zu kommen, die der Funktion dann übergeben werden
*etwas hilflos guck* ... oh je oh je ... Ich versteh das mit dem escapen und quoten grade überhaupt nicht.... also so überhaupt nicht, dass ich gar nicht weiß was Ihr eigentlich meint und wie mir das jetzt weiterhelfen soll ...

Minimal scheint mir das nicht.meneliel hat geschrieben:Alles was gehen soll, ist, das Teile des Where-Teiles formuliert werden sollen. Und das versuche ich so mininal wie möglich zu halten. Hab ich bei dem 2. Teil halt auch geschafft.
nicht unbedingt.Ich will nur Indikatoren berechnen*, aus einer passenden Tabelle, wo die alle drin stehen, aber halt nicht alle auf einmal, sondern ich möchte das beschränken auf Kategorien - und da gibt es nicht nur eine, sondern 2 pro Indikator. Das kann am Ende recht viel werden. Also nicht nur KAT1 ="a" sondern vielleicht Kat 1 ="a" and (Kat2 ="A" OR Kat2 ="C"). Könnte aber auch sein, dass ich nru einen einzigen Indikator direkt selektiere über seine ID ... und das macht es irgenwie gerade etwas kompliziert ...
in mysql kann man statt
Code: Alles auswählen
(kat = "1" or kat="2" ... or kat="n")
Code: Alles auswählen
kat in (1, 2, ... n)
Code: Alles auswählen
query = "select * from tabelle where kat1 in %s and kat2 in %s"
values = (["A"], ["A", "C"])
cursor.execute(query, values)
also funktioniert es NICHT. Es bricht lediglich nicht sofort zusammen.Funktioniert ja nun auch mit den Templates ganz gut Smile ... eigentlich ... wenn man brav ist und/oder weiß was man tut
Bitte nicht falsch verstehen, das geht nicht gegen dich persönlich. Nur ist es einfach dumm, den komplizierten unsicheren weg, anstatt den einfachen, sicheren Weg zu gehen.
Escaping ist (ohne sql drumrum, plain python) z.B. sowas:*etwas hilflos guck* ... oh je oh je ... Ich versteh das mit dem escapen und quoten grade überhaupt nicht.... also so überhaupt nicht, dass ich gar nicht weiß was Ihr eigentlich meint und wie mir das jetzt weiterhelfen soll ... Embarassed *schäm*
Code: Alles auswählen
text = 'hallo \'welt\''
Bei sql hast du bei der "manuellen" ersetzung eben das Problmen, dass der user ' eingeben kann, und sql dann einen Teil seiner eingabe als befehl sieht.
Denke dir einen sql-string, der so aussieht:
Code: Alles auswählen
query = "select id from users where name='%s' and password='%s'"
Code: Alles auswählen
query %= ("egal' or 1=1 --", "völlig egal")
print query # select id from users where name = 'egal' or 1=1 --'and password='völlig egal'
Auch, wenn man davon ausgehen könnte, dass alle user gutartig wären, müsste man sich drum kümmern, denn sonst kommt früher oder später ein user namens O'Hara daher, und macht völlig gutartigerweise eine Eingabe, die das Programm abschmieren lässt.
Aber, weil das Problem so häufig ist, hat unsere db-api da schon was vorbereitet, nämlich den zweiten Parameter der execute-Methode.
Wenn du
Code: Alles auswählen
c.execute("insert into users set name = %s", ["O'Hara"])
Zuletzt geändert von keppla am Dienstag 11. Dezember 2007, 22:30, insgesamt 1-mal geändert.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
So wie ich das sehe ist beim Escapen von SQL mehr nötig als nur die Apostrophe zu escapen, zumindest macht das von mir verlinkte Modul einige Sachen mehr.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Ich wollte es eigentlich auch nicht darauf reduzieren, ich hätte häufiger z.B. sagen sollen. Ich wollte nur anhand der Apostrophe die Problematik erklärenLeonidas hat geschrieben:So wie ich das sehe ist beim Escapen von SQL mehr nötig als nur die Apostrophe zu escapen
Reicht das standardquoting von execute und co nicht aus?zumindest macht das von mir verlinkte Modul einige Sachen mehr.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Was ist das "Standardquoting"? Ich denke, was `execute()` quotet ist ihm selbst überlassen, das heißt jedem Modul das es implementiert. Ich könnte mir vorstellen, dass die Module ganz unterschiedlich quoten - wollte zwar im Quellcode von psycopg2 nachschauen, aber dann hat sich herausgestellt dass das im C-Part implementiert zu sein scheint und dann hatte ich keine Lust mehr weiterzugucken.keppla hat geschrieben:Reicht das standardquoting von execute und co nicht aus?zumindest macht das von mir verlinkte Modul einige Sachen mehr.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Ja, aber wir waren hier bei MySQL, und ich würde doch hoffen, dass das und die sonstigen gängigen apis da "vernünftig" handeln.Leonidas hat geschrieben:Was ist das "Standardquoting"? Ich denke, was `execute()` quotet ist ihm selbst überlassen, das heißt jedem Modul das es implementiert.keppla hat geschrieben:Reicht das standardquoting von execute und co nicht aus?zumindest macht das von mir verlinkte Modul einige Sachen mehr.
Hättest du da ein Gegenbeispiel?
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Ja, sicherlich. Ich wollte nur betonen dass es womöglich nicht reicht einfach nur ' zu quoten. Daher sollte man sich umso mehr auf das Quoting des Moduls stützen.keppla hat geschrieben:Ja, aber wir waren hier bei MySQL, und ich würde doch hoffen, dass das und die sonstigen gängigen apis da "vernünftig" handeln.
Hättest du da ein Gegenbeispiel?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
ALSO
... nach noch einem Tipp von Keppla, und weiterer verbaler Prügel von Kollegen, ich könne dem USer bitte GAR nichts überlassen, egal ob da außer mir nur noch 1-2 andere jemals das Programm benutzen, hab ich mich jetzt doch hingesetzt und
1. eine Oberfläche zusammengebastelt, wo wirklich NICHTS weiter, außer NUR die Werte selber eingegeben werden.
und
2. die querys gestückelt zusammengebastelt, und das sieht nun so aus:
(also nur der kleine Ausschnitt:)
geht bestimmt wieder viel toller und kompakter.
Mich stört das i+=1 noch. Das krieg ich bestimtm gleich mit in die for schleife rein, aber irgendwie steh ich auch gerade auf dem Schlauch und ganzen tag Oberfläche zusammenbasteln schlaucht ...
Ist das so nun besser? und sicherer?

1. eine Oberfläche zusammengebastelt, wo wirklich NICHTS weiter, außer NUR die Werte selber eingegeben werden.
und
2. die querys gestückelt zusammengebastelt, und das sieht nun so aus:
(also nur der kleine Ausschnitt:)
Code: Alles auswählen
elif indikator.get() == "category":
where_i = 'select * from indizes where 1=1'
# calc_cat
c_list = calc_cat_entry.get().split(",")
if len(c_list) > 0:
i_values=[]
where_i +=" and ("
i = 0
for c in c_list:
where_i +="calc_cat = %s"
i_values.append(c.lower())
i +=1
if len(c_list)-i > 0:
where_i +=" or "
where_i +=")"
# kategorie
k_list = kat.get().split(",")
# ... hier dann genau so, wie oben ....
cursor.execute(where_i, i_values)
Mich stört das i+=1 noch. Das krieg ich bestimtm gleich mit in die for schleife rein, aber irgendwie steh ich auch gerade auf dem Schlauch und ganzen tag Oberfläche zusammenbasteln schlaucht ...
Ist das so nun besser? und sicherer?
ich könnte das mit dem i noch so lösen:
und dann weiter unten statt len(c_list) -i einfach (len(c_list) -(i+1))
Code: Alles auswählen
for i in xrange(len(c_list)):
... i_values.append(c_list[i].lower())
Das sieht in der Tat etwas umständlich aus. Wie wär's damit (ungetestet):
Wenn Du irgend etwas zwischen Elemente formatieren möchtest, ist `str.join()` wesentlich einfacher als selbst herausfinden zu müssen an welchem Index man sich gerade befindet.
Code: Alles auswählen
where_i = 'select * from indizes where 1=1'
i_values = [v.strip().lower() for v in calc_cat_entry.get().split(',')]
if i_values:
where_i += 'and calc_cat in (%s)' % (','.join(['%s'] * len(i_values)))
das wird so nicht funktionieren, auch wenn es viel schöner aussieht.
Das rausfinden an welcher Stelle ich mich befinde ist auch nur, um herauszubekommen, ob aus der selben Tabellenspalte noch weitere Werte mit in die Abfrage sollen, weil die mit OR verknüpft werden müssen, wohin gegen der Rest (also evetuelle andere Spalten) und das 1=1 ein AND dazwischen muss....
wenn in der Liste noch ein weiterer WErt kommt, häng ich einfach vor dem nächsten Schleifen durchlauf das OR an den Query, wenn nicht, dann nicht ....
EDIT:
Wobei ... ahso , das funktioniert ja doch ....
das ist ja mal clever.......
Das rausfinden an welcher Stelle ich mich befinde ist auch nur, um herauszubekommen, ob aus der selben Tabellenspalte noch weitere Werte mit in die Abfrage sollen, weil die mit OR verknüpft werden müssen, wohin gegen der Rest (also evetuelle andere Spalten) und das 1=1 ein AND dazwischen muss....
wenn in der Liste noch ein weiterer WErt kommt, häng ich einfach vor dem nächsten Schleifen durchlauf das OR an den Query, wenn nicht, dann nicht ....
EDIT:
Wobei ... ahso , das funktioniert ja doch ....
das ist ja mal clever.......
soooo, noch bisschen erweitert, für den Fall, dass
1. bei einer Eingabe z.B zum Abschluss noch ein "," gesetzt wurde (weil ist mir beim Testen zufällig passiert, wäre also gut möglich, dass passiert jedem), oder das ausversehen zwei "," hintereinander gesetzt werden.
2. für den Fall dass für eine der beiden Kategorien keine Einschränkung erfolgen soll, dann wäre eine Liste ja leer, würde aber beim addiresen der Listen ja einen leeren Listeneintrag der addierten Liste erzeugen:
1. bei einer Eingabe z.B zum Abschluss noch ein "," gesetzt wurde (weil ist mir beim Testen zufällig passiert, wäre also gut möglich, dass passiert jedem), oder das ausversehen zwei "," hintereinander gesetzt werden.
2. für den Fall dass für eine der beiden Kategorien keine Einschränkung erfolgen soll, dann wäre eine Liste ja leer, würde aber beim addiresen der Listen ja einen leeren Listeneintrag der addierten Liste erzeugen:
Code: Alles auswählen
elif indikator == "category":
where_i = 'select * from indizes where 1=1 '
# calc_cat
i_values = [v.strip().lower() for v in ifilter(lambda n: len(n)> 0, calc_cat.split(','))]
if i_values:
where_i += 'and calc_cat in (%s)' % (','.join(['%s'] * len(i_values)))
# kategegorie
k_values = [k.strip().upper() for k in ifilter(lambda n: len(n)> 0, kat.split(','))]
if k_values:
where_i += 'and kat in (%s)' % (','.join(['%s'] * len(k_values)))
values = []
for element in ifilter(lambda n: len(n)>0, i_values + k_values):
values.append(element)
where_indikator_list = [where_i, values]
return where_indikator_list