Binärdaten in MySql Datenbank mit Utf8-Kodierung schreiben
Verfasst: 10. Februar 2012 20:06
Hallo,
ich habe ein Problem mit einer Datenbankanwendung. Das Problem besteht darin, dass beim Schreiben von Binärdaten (in meinem Fall JPG-Bilder) die Daten falsch übetragen werden. Hier die Details:
Bei der Datenbank handelt es sich um eine MySQL-Datenbank, die mit UTF-8 Kodierung aufgesetzt ist, da Texte in verschiendenen Sprachen gespeichert werden müssen. Mit dem Speichern von Textfeldern klappt auch alles wunderbar. Nun möchte ich aber auch Bilder in einer BLOB-Spalte der MySQL Datenbank speichern. Hierzu verwende ich den folgenden Code:
QSqlRecord rec = m_driver->record("tbdocdata");
rec.setValue("docid", docId);
rec.setValue("docdata", data);
QSqlQuery iquery(m_driver->sqlStatement(QSqlDriver::InsertStatement, "tbdocdata", rec, false));
Bei 'data' handelt es sich um einen QVariant, welches mit einem QByteArray mit den Bilddaten gefüllt ist. Der Member m_driver enthält den von der QSqlDatabase gelieferten Treiber.
In der Tabelle steht anschliessend allerdings Müll. Ich habe den Weg der Daten mit einem Debugger verfolgt und weiss jetzt, dass es bei der Hin- und Herwandlung der Daten zwischen QByteArray und QString zu Problemen kommt. Es passiert nämlich folgendes:
Beim Zusammenbau des Insert-Statements durch den Treiber wird das QByteArray zunächst mittels der Funktion
mysql_real_escape_string aufbereitet. Danach werden die Daten in einen QString gewandelt. Dies geschieht mit dem vom Treiber bei der Datenbank ermittelten UTF8-Codec (tc->toUnicode(buffer)). Dabei wird davon ausgegangen, dass es sich um UTF-8 kodierte Daten handelt. Dies ist aber nicht der Fall!
Also dachte ich, ich kann das Problem umgehen indem ich den INSERT-String selber zusammenbaue (allerdings muss ich dann selber auf die Funktion mysql_real_escape_string zugreifen, was meinen Code natürlich von MySQL abhängig macht). Doch auch das geht schief, weil nämlich beim Absetzen des Statements die umgekehrte Wandlung von QString in QByteArray stattfindet. Hier der entscheidende Code im MySQL-Treiber:
const QByteArray encQuery(fromUnicode(d->driver->d->tc, query));
Beim Codec handet es sich wie gesagt um den UTF8-Codec. Dieser soll hier aber gar nicht verwendet werden. Ich habe keine Ahnung, wie ich dieses Problem umschiffen soll. Der letzte Ausweg wäre dann höchstens die MySQL-C-API direkt aufzurufen. Doch das hebt dann die Datenbankunabhängigkeit endgültig auf.
Kann mir jemand einen Tipp geben, wie ich weiter vorgehen kann?
Vielen Dank im Voraus,
Rainer
PS: Das Laden von in der Datenbank abgelegten Bildern klappt übrigens einwandfrei. Hier findet aber auch keine Wandlung nach QString statt.
ich habe ein Problem mit einer Datenbankanwendung. Das Problem besteht darin, dass beim Schreiben von Binärdaten (in meinem Fall JPG-Bilder) die Daten falsch übetragen werden. Hier die Details:
Bei der Datenbank handelt es sich um eine MySQL-Datenbank, die mit UTF-8 Kodierung aufgesetzt ist, da Texte in verschiendenen Sprachen gespeichert werden müssen. Mit dem Speichern von Textfeldern klappt auch alles wunderbar. Nun möchte ich aber auch Bilder in einer BLOB-Spalte der MySQL Datenbank speichern. Hierzu verwende ich den folgenden Code:
QSqlRecord rec = m_driver->record("tbdocdata");
rec.setValue("docid", docId);
rec.setValue("docdata", data);
QSqlQuery iquery(m_driver->sqlStatement(QSqlDriver::InsertStatement, "tbdocdata", rec, false));
Bei 'data' handelt es sich um einen QVariant, welches mit einem QByteArray mit den Bilddaten gefüllt ist. Der Member m_driver enthält den von der QSqlDatabase gelieferten Treiber.
In der Tabelle steht anschliessend allerdings Müll. Ich habe den Weg der Daten mit einem Debugger verfolgt und weiss jetzt, dass es bei der Hin- und Herwandlung der Daten zwischen QByteArray und QString zu Problemen kommt. Es passiert nämlich folgendes:
Beim Zusammenbau des Insert-Statements durch den Treiber wird das QByteArray zunächst mittels der Funktion
mysql_real_escape_string aufbereitet. Danach werden die Daten in einen QString gewandelt. Dies geschieht mit dem vom Treiber bei der Datenbank ermittelten UTF8-Codec (tc->toUnicode(buffer)). Dabei wird davon ausgegangen, dass es sich um UTF-8 kodierte Daten handelt. Dies ist aber nicht der Fall!
Also dachte ich, ich kann das Problem umgehen indem ich den INSERT-String selber zusammenbaue (allerdings muss ich dann selber auf die Funktion mysql_real_escape_string zugreifen, was meinen Code natürlich von MySQL abhängig macht). Doch auch das geht schief, weil nämlich beim Absetzen des Statements die umgekehrte Wandlung von QString in QByteArray stattfindet. Hier der entscheidende Code im MySQL-Treiber:
const QByteArray encQuery(fromUnicode(d->driver->d->tc, query));
Beim Codec handet es sich wie gesagt um den UTF8-Codec. Dieser soll hier aber gar nicht verwendet werden. Ich habe keine Ahnung, wie ich dieses Problem umschiffen soll. Der letzte Ausweg wäre dann höchstens die MySQL-C-API direkt aufzurufen. Doch das hebt dann die Datenbankunabhängigkeit endgültig auf.
Kann mir jemand einen Tipp geben, wie ich weiter vorgehen kann?
Vielen Dank im Voraus,
Rainer
PS: Das Laden von in der Datenbank abgelegten Bildern klappt übrigens einwandfrei. Hier findet aber auch keine Wandlung nach QString statt.