psycopg2 verhält sich nicht wie erwartet

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Benutzeravatar
Judge
User
Beiträge: 129
Registriert: Mittwoch 13. Juni 2012, 22:27
Wohnort: Ratingen
Kontaktdaten:

Hallo zusammen,

evtl. bin ich zu blöd Dokus zu lesen; ich versichere aber, dass ich das heute schon gefühlte 100x getan habe und trotzdem nicht dahinter komme :oops:

Im psycopg - Usage Guide steht:
Psycopg can automatically convert Python objects to and from SQL literals: using this feature your code will be more robust and reliable.

>>> SQL = "INSERT INTO authors (name) VALUES (%s);"
>>> data = ("O'Reilly", )
>>> cur.execute(SQL, data)
Ich habe mir jetzt ein stupid-as-f**k Beispiel gebaut:

Code: Alles auswählen

#!/usr/bin/python2
import psycopg2

# Create connection and cursor objects
con = psycopg2.connect(database="postgres", user="postgres", host="127.0.0.1", password="postgres")
con.set_isolation_level(0)
cur = con.cursor()

# http://initd.org/psycopg/docs/usage.htm ... ql-queries
SQL = "CREATE DATABASE %s;"
data = ("testdb", )
cur.execute(SQL, data)

con.close
Muss man nicht viel zu sagen: Soll auf die PostgreSQL DB auf localhost verbinden und die Datenbank "testdb" anlegen. Syntax eigentlich doch 1:1 wie im Beispiel.
So, jetzt führe ich das aus und erhalte:
judge@judge-nb:~$ ./test.py
Traceback (most recent call last):
File "./test.py", line 12, in <module>
cur.execute(SQL, data)
psycopg2.ProgrammingError: syntax error at or near "'testdb'"
LINE 1: CREATE DATABASE 'testdb';
Kopiere ich das und gebe das 1:1 in psql ein, sagt der auch:
postgres=# CREATE DATABASE 'testdb';
ERROR: syntax error at or near "'testdb'"
LINE 1: CREATE DATABASE 'testdb';
postgres=#
Gebe ich es ohne die Anführungsstriche in psql ein, klappt es:
postgres=# CREATE DATABASE testdb;
CREATE DATABASE
postgres=#
Wenig überraschend: Wenn ich das stumpf als unparameterisierte Operation ausführen lasse, klappt es auch mit psycopg2:

Code: Alles auswählen

SQL = "CREATE DATABASE testdb;"
cur.execute(SQL)
Aber das ist ja nicht Sinn der Sache.

Was macht psycopg2 da? Die zitierte Doku liest sich für mich so, als wenn er mit genau so einer Syntaxunterscheidung umgehen kann.
Oder mache ich was falsch?
BlackJack

@Judge: Ein Tabellenname ist kein Wert. Platzhalter in SQL sind nur für Werte. Denn die ändern sich bei den Abfragen, nicht so etwas wie Tabellennamen. Wenn man ”variable” Tabellennamen hat, dann stimmt in der Regel etwas mit dem Datenbankentwurf nicht.
Benutzeravatar
Judge
User
Beiträge: 129
Registriert: Mittwoch 13. Juni 2012, 22:27
Wohnort: Ratingen
Kontaktdaten:

Hi BlackJack,

leider verstehe ich Deine Antwort nicht.

Ich lege da ja keine Tabelle an, sondern eine Datenbank. "Diese sollten nicht variabel sein" - ich münze das mal noch diesem Missverständnis zu.
Denn denke ich z.B. an die Übergabe eines DB namens in einer durch den Anwender editierten Configdatei ergibt es sich hierbei ja durchaus das der CREATE code dazu sinnvoll mit solchen Variablen arbeitet.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Werte sind alles was du in eine Spalte packen kannst. Alles andere als Datenbank Namen, Tabellen Namen, Spalten Namen, usw. sind keine Werte und sollten nicht Variabel sein. Selbst wenn du diese Namen irgendwie generierst, sollte dies nicht vom User beeinflusst sein. Also sowas wie Usern über Konfigurationsdateien solche Namen festlegen lassen ist überhaupt keine gute Idee.
Benutzeravatar
Judge
User
Beiträge: 129
Registriert: Mittwoch 13. Juni 2012, 22:27
Wohnort: Ratingen
Kontaktdaten:

Bitte nicht in den falschen Hals kriegen, aber ich möchte nicht über (Un-/)Sinn von Scripten oder gutem und schlechtem Design/Stil philosophieren, sondern die technischen Gründe für ein fehlschlagen der gezeigten Anweisungen verstehen und wie ich technisch das Ziel erreiche.
Das etwas eine gute oder schlechte Idee ist, führt sicher nicht zu Fehlermeldungen eines Computerprogrammes.

Frage 1: Ich habe also einen variablen String und möchte eine PostgreSQL Datenbank anlegen, die so heißt: Wie mache ich das?

Frage 2: Ich verstehe, das das von mir gewählte Konstrukt davon ausgeht, das der resultierende Query in einem anderen (PostgreSQL-)Kontext verwendet wird, bei dem andere Regeln bezüglich der Quotation gelten als beim anlegen von Datenbanken. Da ich diese Einschränkung auf einen Anwendungsfall jedoch auch nach vielfachem lesen der Psycopg2 Doku nicht finden kann, stellt sich mir die Frage: Fehlt diese Info? Oder überlese ich das immer und immer wieder?
Ich würde mich freuen, wenn mich mal jemand mit der Nase drauf stubsen würde.

Vielen Dank für Eure Hilfe!
BlackJack

@Judge: Frage 1: Selbst eine Zeichenkette zusammenbauen und hoffen das dabei nichts böses passiert.

Frage 2 verstehe ich nicht‽
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Der technische Grund dafür dass das nicht geht, ist dass die Entwickler das für schlechtes Design halten und dementsprechend sowas nicht unterstützen. Wenn jemand über die Brücke springen will, hilft man üblicherweise nicht dabei. Du musst halt in diesem Fall String Formatting betreiben.

Zu 2:
Passing Parameters to SQL Queries hat geschrieben:Psycopg casts Python variables to SQL literals by type.
Ein Name ist kein Literal.
Benutzeravatar
Judge
User
Beiträge: 129
Registriert: Mittwoch 13. Juni 2012, 22:27
Wohnort: Ratingen
Kontaktdaten:

@BlackJack:

Zu Frage 2: Ich würde solche Dokus gerne in Zukunft auch alleine lesen können und wollte wissen, wo dieser Punkt beschrieben steht, den ich erst jetzt mit Hilfe von erfahrenen Programmierern verstehe.
So wie DasIch es mit seiner Antwort versucht hat: Pointing auf einen relevanten Doku-Teil, der mir gezeigt hätte das der Codeansatz Quark ist, ehe ich es durch Trial & Fail bemerkt habe.

@DasIch:

Ich bin kein gelernter Programmierer; "nur" Systemintegrator und Programmier-Autodidakt. Daher sieh es mir bitte nach, falls die folgende Frage allzu blöd sein sollte:
Was genau ist ein "Literal" in diesem Kontext? Ein "SQL Literal" / String literal scheint laut meiner Recherche einfach nur ein "Typ" von Daten zu sein, der nicht durch einen Identifier (/Variable?) repräsentiert wird. Also z.B.:

Ein String - Literal = 'Hallo Welt'
Numerischer Literal = 78

In diesem Zusammenhang verstehe ich die Aussage "Ein Name ist kein Literal" nicht.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@Judge: ungefähr das ist die Definition von Literal. Genauer steht das z.B. auf Wikipedia.
BlackJack

@Judge: Ich habe Frage 2 komplett nicht verstanden, also nicht verstanden was Du da überhaupt fragst.
Benutzeravatar
Judge
User
Beiträge: 129
Registriert: Mittwoch 13. Juni 2012, 22:27
Wohnort: Ratingen
Kontaktdaten:

Sirius3 hat geschrieben:@Judge: ungefähr das ist die Definition von Literal. Genauer steht das z.B. auf Wikipedia.
OK, also schonmal die Bezeichnung korrekt verstanden.
Jetzt bringe ich das aber dennoch nicht mit dem Satz "Ein Name ist kein Literal" übereinander. Wenn ein Schemaname z.B. "SchweineToast" ist, kann man doch gleichzeitig die korrekte Aussage treffen " 'SchweineToast' ist ein Zeichenkettenliteral" - richtig? Also was bedeutet "Ein Name ist kein Literal" nun - wie ist diese Aussage zu verstehen?
BlackJack hat geschrieben:@Judge: Ich habe Frage 2 komplett nicht verstanden, also nicht verstanden was Du da überhaupt fragst.
Dann formuliere ich die Frage mal anders:
Wo steht es in der psycopg Doku, das das "automatic Python object to SQL literals conversion" - Feature nicht bei Namen von Datenbanken verwendet werden darf?
BlackJack

@Judge: Wenn Du "Ein Name ist kein Literal" nicht mit Deinem Verständnis von Literal übereinander bringst, dann hast Du die Bezeichnung doch nicht verstanden. Ein Literal ist Syntax die direkt einen ganz konkreten Wert erzeugt. Ein Name steht indirekt für einen Wert. Der Name SchweineToast kann für alles mögliche stehen. Das Zeichenkettenliteral 'SchweineToast' steht direkt für den Wert der Zeichenkette die das Wort SchweineToast enthält und nichts anderes.

Edit: Das man das nicht für Namen verwenden kann ist in "automatic Python object to SQL literals conversion" implizit enthalten weil die Konverierung zu SQL-Literalen gemacht wird und Namen sind ja eben keine Literale. Per Definition was ein Literal ist.
Antworten