Probleme mit MySQLdb - Warnung

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
geraldf
User
Beiträge: 5
Registriert: Montag 20. November 2006, 19:43

Hallo allerseits,

das Python-Modul MySQLdb vermittelt zwischen Python und MySQL. Derzeit haben viele Entwickler damit Probleme.

Das Projekt ist auf Sourceforge gehostet.
http://sourceforge.net/projects/mysql-python/

Ich habe im Forum "Open Discussion" einen offenen Brief an den Entwickler gepostet.
http://sourceforge.net/forum/forum.php? ... m_id=70460

Das Folgende ist eine auszugsweise Übersetzung aus diesem Posting:

---

Es gab eine - stille? - Interface-Änderung zwischen den Versionen 1.2.1c3 und and 1.2.1_p2.

Alte Version: cursor.execute() erhält einen String als Parameter.
Neue Version: cursor.execute() erwartet ein Unicode-Objekt.

Aus diesem Grund kämpfen derzeit viele Entwickler mit nicht mehr funktionierenden Anwendungen. Oder sie haben dieses Erlebnis noch vor sich.
z. B. wenn sie von Ubuntu 6.06 auf Version 6.10 wechseln.

Derzeit scheint es keine "Produktivversion" von MySQLdb zu geben, die unter Linux UND Windows funktioniert.

Niemand ist für das Testen unter Windows verantwortlich, obwohl in der Projektzusammenfassung "32-bit MS Windows (NT/2000/XP)" als Plattformen angeführt sind.

--- Auszug Ende

Da bei vielen Leuten schon recht viel Arbeitszeit den Bach hinuntergegangen ist, rate ich aus derzeitiger Sicht zu großer Vorsicht beim Einsatz von MySQLdb.
Lest auf Sourceforge, python-forum.de, im Usenet etc. alle relevanten Postings und Bugreports und zieht Eure Schlüsse.
Testet rechtzeitig auf allen Ziel-Plattformen.
Beste Grüße
Gerald
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Ich bin nicht sicher, wie direkt da Zusammenhänge bestehen, aber ich hatte ein größeres Problem mit Encodings mit der noch aktuellen stabilen Version von MySQLdb. Auf http://homework.nwsnet.de/releases/2d1e ... e-imminent habe ich dazu ein paar Worte geschrieben und einen Weg aufgezeigt, dies mit einem einfachen Patch zu umgehen. Leider lässt 1.2.2 schon viel zu lange auf sich warten :(
Zuletzt geändert von Y0Gi am Sonntag 10. Februar 2013, 00:47, insgesamt 2-mal geändert.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

geraldf hat geschrieben:Interface-Änderung zwischen den Versionen 1.2.1c3 und and 1.2.1_p2.

Alte Version: cursor.execute() erhält einen String als Parameter.
Neue Version: cursor.execute() erwartet ein Unicode-Objekt.
Aha! Das ist aber interessant!
Ich hab in PyLucid mit relativ viel Aufwand selber das de-/encoding eingebaut...

Gibt es denn wirklich einen Traceback, wenn man bei der neuen Version einen String und kein Unicode Objekt benutzt???

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Wie sieht es nun aus mit unicode und MySQLdb... Gibt es da neue Erkenntnisse???

Ich bastel mir jetzt mal ein Skript zum testen.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

So, ich hab mal ein test Skript geschrieben: http://paste.pocoo.org/show/298/

Ich hab es getestet mit MySQLdb Version: 1.2.1g2 und 1.2.1_p2 mehr habe ich z.Z. nicht zur Verfügung...

Ich muß da aber irgendwie einen Fehler drin haben... Hier mal die Ausgaben, die eigentlich bei beiden Versionen gleich sind:
-==[MySQLdb unicode test]==-

MySQLdb Version: 1.2.1_p2
MySQLdb version_info: (1, 2, 1, 'final', 2)
MySQL server encoding: latin1
-------------------------------------------------------------------------------
CREATE TABLE temp_test... OK

-------------------------------------------------------------------------------
inser the teststring in unicode!
INSERT & SELECT... OK
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß

-------------------------------------------------------------------------------
insert the teststring encoded in 'utf-8'
INSERT & SELECT... OK
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß

-------------------------------------------------------------------------------
insert the teststring encoded in 'latin-1'
INSERT & SELECT... OK
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß

-------------------------------------------------------------------------------
insert the teststring encoded in 'iso-8859-15'
INSERT & SELECT... OK
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß

DROP TABLE... OK

Close Connection... OK
Zur Funktionsweise:
Das Skript erzeugt eine Tabelle mit einem varchar Feld.
Es wird der Test-String in den Varianten "unicode", "utf-8", "latin-1", "iso-8859-15" eingefügt und danach wieder ausgelesen.
Der ausgelesene String wird versucht mit "unicode", "utf-8", "latin-1", "iso-8859-15" zu decodieren.

Wie sich zeigt, ist es 1. egal in welchem Encoding man Daten einfügt (Was irgendwie sehr merkwürdig ist) und 2. erhält man die Daten immer mit dem Codec zurück, der beim Server eingestellt ist.
Es ist der Codec der in der Variable "character_set_server" angegeben ist. Bei MySQL in der neueren Version ist es per default "latin-1"...

Irgendwie kann ich aber nicht glauben, das man die Daten in egal welchem Code in die DB packen kann.... Da muß irgendwo ein Fehler im Skript sein.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

jens hat geschrieben:Irgendwie kann ich aber nicht glauben, das man die Daten in egal welchem Code in die DB packen kann.... Da muß irgendwo ein Fehler im Skript sein.
Warum versuchst Du zu raten was Du zurückbekommst? Viel interessanter wäre es doch direkt den Vergleich zu zeigen: was Du reinsteckst und was Du zurückbekommst. Beides als `repr()` damit man wirklich Byte für Byte sieht wie die Daten aussehen.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Sehr gute Idee! Ich sollte mir endlich mal repr() merken :oops:

Aktualisiert: http://paste.pocoo.org/show/299/
Diff: http://paste.pocoo.org/compare/299/

Code: Alles auswählen

-==[MySQLdb unicode test]==-

MySQLdb Version: 1.2.1_p2
MySQLdb version_info: (1, 2, 1, 'final', 2)

MySQL server encoding:
	MySQL variable 'character_set_server': latin1
	connection.character_set_name: latin1

-------------------------------------------------------------------------------
CREATE TABLE temp_test... OK

-------------------------------------------------------------------------------
inser the teststring in unicode!
INSERT & SELECT... OK
db_input...: u'Test \xe4\xf6\xfc\xdf'
db_output..: 'Test \xe4\xf6\xfc\xdf'
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß

-------------------------------------------------------------------------------
insert the teststring encoded in 'utf-8':
INSERT & SELECT... OK
db_input...: 'Test \xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f'
db_output..: 'Test \xe4\xf6\xfc\xdf'
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß

-------------------------------------------------------------------------------
insert the teststring encoded in 'latin-1':
INSERT & SELECT... OK
db_input...: 'Test \xe4\xf6\xfc\xdf'
db_output..: 'Test \xe4\xf6\xfc\xdf'
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß

-------------------------------------------------------------------------------
insert the teststring encoded in 'iso-8859-15':
INSERT & SELECT... OK
db_input...: 'Test \xe4\xf6\xfc\xdf'
db_output..: 'Test \xe4\xf6\xfc\xdf'
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß

-------------------------------------------------------------------------------
insert the teststring encoded in 'utf_16_be':
INSERT & SELECT... OK
db_input...: '\x00T\x00e\x00s\x00t\x00 \x00\xe4\x00\xf6\x00\xfc\x00\xdf'
db_output..: 'Test \xe4\xf6\xfc\xdf'
The String can be encoded with 'latin-1'
Test output with 'utf-8': Test äöüß

DROP TABLE... OK

Close Connection... OK
Wie man sieht, stecke ich schon den String richtig encodiert in die DB... Und es kommt immer in "latin-1" raus und ist der selbe Test-String...

Ich werde mit mal eine Uralte MySQLdb installieren und damit mal testen...

EDIT: Gesagt, getan... Das Ergebnis ist das selbe mit MySQLdb version_info: (1, 2, 0, 'final', 1)
EDIT 2: Das gleiche bei MySQLdb version_info: (1, 0, 0, 'final', 1) ... Ist die älteste für Python 2.4... Mal sehen, wie es mit Python 2.3 aussieht!
EDIT 3: Mit Python 2.3 und MySQLdb version_info: (1, 2, 0, 'final', 1) aus das selbe...
EDIT4: Und noch Python 2.3 mit MySQLdb version_info: (0, 9, 2, 'final', 1) das selbe...
Zuletzt geändert von jens am Donnerstag 7. Dezember 2006, 14:29, insgesamt 1-mal geändert.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Ich werfe zzzeeks sqlalchemy in den Raum.
TUFKAB – the user formerly known as blackbird
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

blackbird hat geschrieben:Ich werfe zzzeeks sqlalchemy in den Raum.
Ich schmeiß auch noch PostgreSQL ein - ein DMBS das sehr gut funktioniert und viele verschiedene teilweise auch sehr gute Python-Interfaces hat. Wird auch von SQLAlchemy unterstützt.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

SQLAlchemy und PostgreSQL hilft mir jetzt unheimlich toll weiter... :?

Also: Was kann ich jetzt aus meinem Test folgern?

Das man egal in welchem Encoding Daten in die DB schmeißen kann und sie kommen immer sauber im Server Encoding (also latin-1) zurück?

Das kann doch irgendwie nicht sein, oder?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

jens hat geschrieben:[...]
Das man egal in welchem Encoding Daten in die DB schmeißen kann und sie kommen immer sauber im Server Encoding (also latin-1) zurück?

Das kann doch irgendwie nicht sein, oder?
Ne das kann auch nicht sein ;) Spätesten wenn du ein encoding für Chinesisch oder ähnliches benutzt und es dann in ein "Coding rausholst" das den Zeichensatz nicht unterstützt, wird es nicht gehen.

lg
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hm... Nagut... Wenn der Server latin-1 als encoding eingestellt hat, kann er auch IMHO nur alle Zeichen die latin-1 abbilden kann speichern... Latin-1 müßte somit alle Zeichen von 0x0000 bis 0x00FF abbilden, oder ?

Ich mache mal ein Test damit...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Jep, so ist es...

Als Testdaten hab ich mal das genommen:

Code: Alles auswählen

TEST_STRING = u"".join([unichr(i) for i in xrange(0, 256)])
Das kann ich als "unicode" oder encodiert in "utf-8", "latin-1" oder "utf_16_be" in die DB schmeißen... Raus kommt latin-1 der decodiert genau dem Test-String entspricht...

Also ist ja schön, das MySQLdb es so macht, aber wie macht es das???

Wenn ich einen String im exotischen "utf_16_be" Encoding in die DB schreibe, wie kann das Modul wissen, das es dieser Codec ist?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Hier mal der latin-1 Test: http://paste.pocoo.org/show/301/

Wirft das raus:

Code: Alles auswählen

-==[MySQLdb unicode test]==-

MySQLdb Version: 1.2.0
MySQLdb version_info: (1, 2, 0, 'final', 1)

MySQL server encoding:
	MySQL variable 'character_set_server': latin1
	connection.character_set_name: latin1

-------------------------------------------------------------------------------
CREATE TABLE temp_test... OK

-------------------------------------------------------------------------------
inser the teststring in unicode!
INSERT & SELECT... OK
db_input...: u'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: True

-------------------------------------------------------------------------------
insert the teststring encoded in 'utf-8':
INSERT & SELECT... OK
db_input...: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: True

-------------------------------------------------------------------------------
insert the teststring encoded in 'latin-1':
INSERT & SELECT... OK
db_input...: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: True

-------------------------------------------------------------------------------
insert the teststring encoded in 'utf_16_be':
INSERT & SELECT... OK
db_input...: '\x00\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: True

DROP TABLE... OK

Close Connection... OK

Ach, und noch was...

Man kann ab MySQL v4.1 das verwendete character set ändern. So:

Code: Alles auswählen

cursor.execute('set character set %s;', ("utf8",))
Das scheint aber keine Gute Idee zu sein... In dem Fall sind alle Werte "defekt". Egal ob ich versuche die Ausgaben mit "latin-1" oder "utf-8" zu encodieren:

Code: Alles auswählen

inser the teststring in unicode!
INSERT & SELECT... OK
db_input...: u'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: False

-------------------------------------------------------------------------------
insert the teststring encoded in 'utf-8':
INSERT & SELECT... OK
db_input...: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: False

-------------------------------------------------------------------------------
insert the teststring encoded in 'latin-1':
INSERT & SELECT... OK
db_input...: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: False

-------------------------------------------------------------------------------
insert the teststring encoded in 'utf_16_be':
INSERT & SELECT... OK
db_input...: '\x00\x00\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\...
db_output..: '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1...
Encode db output with server encoding 'latin1'... OK
Is test-String == db output: False

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

So, nach den tests habe ich jetzt auch anpassungen in PyLucid unternommen.

Mit https://pylucid.net/trac/changeset/643 wird nun folgendes gemacht bzw. nicht mehr gemacht:
  • 1. Das DB encoding wird nicht mehr mit 'set character set %s;' geändert. Es wird immer das default encoding des Servers genommen.
    2. Die Daten, zur DB gehen, werden nicht mehr von in ein anderes encoding gebracht.
Und, ja, ich werde auf SQLAlchemy umsteigen ;) btw. wie bekommt man da die Daten zurück? Direkt als unicode oder in dem encoding der DB???

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

jens hat geschrieben:Und, ja, ich werde auf SQLAlchemy umsteigen ;) btw. wie bekommt man da die Daten zurück? Direkt als unicode oder in dem encoding der DB???
Wenn du eine Column als "String" im table definierst bekommst du das encoding zurück, oder bullshit. Letzteres besonders gerne beim MySQL adapter. Das würde ich gar nicht verwenden. Wenn deine Column als "Unicode" definiert ist bekommst du, tadadada: unicode :)
TUFKAB – the user formerly known as blackbird
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:


GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

geraldf hat geschrieben:Interface-Änderung zwischen den Versionen 1.2.1c3 und and 1.2.1_p2.

Alte Version: cursor.execute() erhält einen String als Parameter.
Neue Version: cursor.execute() erwartet ein Unicode-Objekt.
Da hat sich wohl noch mehr geändert...

Beim connecten kann man einmal ein kwarg "charset" angeben, in einer älteren v1.2.1 nicht, dafür aber "use_unicode"...

Irgendwie blicke ich in den Versionnummern nicht durch. Von daher kann man auch schlecht testen, welches kwargs nun geht, wie hier:

Code: Alles auswählen

        from MySQLdb import version_info
        if version_info < (1, 2, 1):
            # Für alte Versionen
            kwargs["use_unicode"] = True
        else:
            # ab python-mysqldb v1.2.1
            kwargs["charset"] = self.encoding
Ich hab es jetzt so gemacht: Ich probiere es mit dem neuen "charset"="utf8", wenn das nicht geht, setzte ich "use_unicode"=true :?

Ich frage mich dann, ob der trac-Patch auch richtig arbeitet.

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten