Unicode Problem in MySQL

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Ich kämpfe mal wieder mit Unicode. Genau genommen bin ich mir nicht sicher, ob in der Datenbank wirklich richtig mit Unicode umgegangen wird.

Hintergrund ist ein PHP Programm, das Daten in MySQL speichert. Die Felder sind mit utf8_general_ci erstellt. Ich habe eine SQL Datei im UTF8 Format, die ich via phpmyadmin importiert habe. phpmyadmin zeigt Umlaute auch als Umlaute an. Ein Qt Programm, das QString verwendet, kommt (angeblich, ich hab es nicht getestet) damit zurecht. Auch der MySQL Query Browser zeigt die Umlaute an.

Wenn ich jetzt allerdings mit Elixir und SQLAlchemy (Camelot) auf so eine Datenbank zugreifen will bekomme ich eine Fehlermeldung
UnicodeDecodeError: 'utf8' codec can't decode byte 0xfc in position 14: invalid start byte
Mir ist klar, dass es 0xfc in UTF8 nicht gibt. Wenn ich mit meinem Programm Umlaute in die Datenbank speichere zeigen sowohl phpmyadmin als auch MySQL Query Browser die bekannten Zeichen an.
öäü
Wer macht also den Fehler? 0xfc ist doch kein echter Unicode, oder?
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ja dann schau doch mal in die Datenbank, wie die Daten dort genau gespiechert werden. Also welche Bytes und so.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
microkernel
User
Beiträge: 271
Registriert: Mittwoch 10. Juni 2009, 17:27
Wohnort: Frankfurt
Kontaktdaten:

Ich hatte mal so ein ähnliches Problem. Letztendlich lag der Fehler darin, dass ich in der Datenbank die Länge einer Spalte beschränkt hatte. Allerdings war der Datensatz, welcher in die Spalte sollte, größer als das Limit. So wurde schließlich nur ein Teil des original Datensatzes in die Datenbank geschrieben wodurch bei mir die Datensätze eine ähnlich komische Endung hatten.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Leonidas hat geschrieben:Ja dann schau doch mal in die Datenbank, wie die Daten dort genau gespiechert werden. Also welche Bytes und so.
Hm, und wie kann ich das? Mit einem Hex Editor das Datenbankfile öffnen?
microkernel hat geschrieben:Letztendlich lag der Fehler darin, dass ich in der Datenbank die Länge einer Spalte beschränkt hatte. Allerdings war der Datensatz, welcher in die Spalte sollte, größer als das Limit.
Ne, das ist hier definitiv nicht der Fall. Es geht darum, wie die Programme, die Schnittstelle und/oder die Datenbank mit Unicode umgehen. Ich kann nicht nachvollziehen, ob in der Datenbank jetzt tatsächlich Umlaute usw als Unicode abgelegt werden oder ob die Schnittstellen anhand der Informationen da irgendwelche Konvertierungen vornimmt.

Tatsache ist, dass ich mit SQLAlchemy mit 0xfc den ISO8859-1 Wert für das kleine "ü" zurück bekomme. Und ich vermute stark, dass hier auch überall damit gearbeitet wird, ausgenommen in Camelot.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Hm, ich habe mir jetzt mal die Datenbank im Hex Editor angeschaut. In der Datenbank steht tatsächlich

Code: Alles auswählen

0xC3 0xBC
für ein ü, wenn ich es mit phpmyadmin speichere. Wenn ich mit SQLAlchemy ein ü speichere bekomme ich dagegen

Code: Alles auswählen

0xC3 0x83 0xC2 0xBC
Also insgesamt 4 Byte. Kann es sein, dass SQLAlchemy tatsächlich UTF-16 oder sowas verwendet statt UTF-8?
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Ich hab einen indirekten Hinweis gefunden.
unicode – Defaults to False: short-hand for the ucs2 character set, generates UNICODE in schema.
Und ucs2 ist so ziemlich das gleiche wie UTF-16. SQLAlchemy scheint bei MySQL also mit ucs2 zu arbeiten. Die Lösung ist wohl unter Character Sets zu finden

Code: Alles auswählen

create_engine('mysql+mysqldb:///mydb?charset=utf8&use_unicode=0')
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
BlackJack

@burli: Was heisst "ein ü speichern"? Hast Du da tatsächlich eine `unicode`-Objekt mit einem 'ü'?
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

BlackJack hat geschrieben:@burli: Was heisst "ein ü speichern"? Hast Du da tatsächlich eine `unicode`-Objekt mit einem 'ü'?
Das "Objekt" nennt sich auch String ;)
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
BlackJack

@burli: Also verwendest Du Python 3 und dort `str`-Objekte (und nicht "String") oder Python 2 und `unicode`-Objekte? Python 2 und `str` sind keine Zeichen sondern Bytewerte und damit kann da kein 'ü' drin sein, sondern höchstens Bytewerte die in einer bestimmten Kodierung ein 'ü' darstellen können.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

BlackJack hat geschrieben:@burli: Also verwendest Du Python 3 und dort `str`-Objekte (und nicht "String") oder Python 2 und `unicode`-Objekte? Python 2 und `str` sind keine Zeichen sondern Bytewerte und damit kann da kein 'ü' drin sein, sondern höchstens Bytewerte die in einer bestimmten Kodierung ein 'ü' darstellen können.
Ich weiß. Es geht ja auch um die Umwandlung der Zeichen in die entsprechende Codierung. Also ASCII, ISO8859, UTF-8, UTF-16 usw. SQLAlchemy scheint zumindest bei MySQL UTF-16 zu verwenden.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
BlackJack

@burli: Wie kommst Du denn darauf? Wenn die vier Bytes da ein 'ü' darstellen sollen, dann sieht das eher so aus als wenn UTF-8 irgendwo fälschlich als ISO-8859-1 oder ähnliches dekodiert und dann für die Datenbank diese zwei falschen Zeichen als UTF-8 kodiert wurden. Wenn das tatsächlich für ein 'ü' in der Datenbank steht, dann steht da Müll in der DB.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Ich hab doch geschrieben, welche Bytes im Datenbank File stehen. In der Datenbank steht kein ü. IMHO entweder die UTF-8 oder UTF-16 Representation des ü, je nach dem, mit welcher Software die Daten geschrieben wurden.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
BlackJack

@burli: Die vier Bytes sind kein 'ü' sondern Müll. Wie kommst Du bitte darauf das könnte UTF-16 sein? Schau Dir das doch einfach mal an:

Code: Alles auswählen

In [10]: print '\xc3\x83\xc2\xbc'.decode('utf-16')
菃볂
In [11]: print '\xc3\x83\xc2\xbc'.decode('utf-8')
ü
Sieht nicht wirklich nach einem 'ü' aus.

Und wenn verschiedene Software da verschiedene Repräsentationen zur Folge haben, dann ist da irgendwo etwas falsch. Dann kann man die ja nicht mehr eindeutig dekodieren.
burli
User
Beiträge: 1156
Registriert: Dienstag 9. März 2004, 18:22

Ich kenne die technischen Details nicht. Ich kann nur weitergeben, was ich beobachtet habe. Wenn ich mit phpmyadmin ein "ü" speichere und mir dann das Datenbank File mit einem Hex Editor anschaue sehe ich die genannten 2 Bytes. Wenn ich mit Camelot ein ü in der selben Datenbank speichere und mir das Datenbank File anschaue finde ich dort 4 Bytes. Camelot verarbeitet diese Daten aber korrekt.

Wenn ich den create_engine String um ?charset=utf8&use_unicode=0 ergänze speichert Camelot ein ü auch in 2 Bytes und kann bestehende UTF-8 Daten auch korrekt anzeigen.

Ich habe noch keinen konkreten Hinweis gefunden, was Camelot bzw SQLAlchemy standardmäßig zur Zeichencodierung verwendet. Ich weiß auch nicht, was auf dem Weg von Camelot über SQLAlchemy und MySQLdb in die Datenbank und zurück genau passiert. Ich kann nur sagen, dass es kein Müll ist, sonst würde es nicht funktionieren.
Das schwierigste beim Programmieren ist, sinnvolle Variablen- und Funktionsnamen zu finden :lol:
BlackJack

@burli: Es ist Müll. Das Camelot dann mit dem eigenen Müll klar kommt, bedeutet ja nicht das es korrekt ist was dort in die Datenbank geschrieben wird. Es wird halt nur in beide Richtungen falsch gemacht, wodurch es wieder richtig aussieht. Aber wenn Du da mit anderen Programmen dran gehst, die es richtig machen, werden die dort kein 'ü' raus lesen. Daten in einer Datenbank sollten unabhängig vom verwendeten Zugriffsweg lesbar sein.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Btw betrachtet man Datenbanken nicht mit dem Hexeditor. Sondern mit einem Query das man nicht sofort in Unicode dekodieren lässt sondern als ``str`` (Python 2) oder ``bytes`` (Python 3) belässt und darauf ``repr`` ausführt. Wie die Daten dann tatsächlich auf der Festplatte gespeichert werden ist Implementationsdetail der DB:
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten