Seite 1 von 1

Binäre Werte in eine MySql-Datenbank schreiben / daraus lese

Verfasst: 22. März 2011 19:57
von Nukleus
Ich habe ein Problem, bei dem ich momentan nicht weiterkomme:

Ich will in eine MYSql-Datenbank binäre Werte schreiben und daraus lesen.

Mit lesbaren Zeichen geht das vollkommen problemlos. Im konkreten Fall möchte ich jetzt ein Char-Feld von 128 bytes (die auch binär 0 enthalten können) per QSqlQuery in die Datenbank schreiben.

Die Daten schreibe ich in ein QByteArray. Reinschreiben und wieder Lesen funktioniert auch. Aber: wenn ich in dem ByteArray ein einziges Bit sitzen habe, dann sitzen beim Wieder lesen desselben Satzes (ggf) mehrere Bits. (Allerdings ist das Orginalbit jedesmal dabei). Warum ist mir völlig unklar.

Die Doku sagt zwar, daß man beim Zuweisen (per bindValue) sagen kann, daß die Daten binär sind und das sage ich auch (QSql Parameter Type: QSql::In | QSql::Binary). Beim Lesen kann ich aber nirgendwo sagen, daß ich Binärdaten erwarte (oder zumindest habe ich das noch nirgends gefunden), dies obwohl es auch den Parameter Typ QSql::Out gibt.

Ich habe es auch mit QBitArray probiert (wäre für mich einfacher). Dabei schreibe ich in die Datenbank dann den Typ QVariant::BitArray (=13). Wenn ich es wieder lese, dann erhalte ich QVariant::ByteArray (=12).

Ich habe jetzt schon eine ganze Menge Zeugs erfolglos ausprobiert und so langsam gehen mir die Ideen aus.

Kann mir jemand einen Tip geben?

Verfasst: 22. März 2011 20:15
von Christian81
Code wäre nicht schlecht, vor allem wie die Daten ausgelesen werden.

Verfasst: 22. März 2011 20:53
von upsala
Was hat das Datenbank-Feld für einen Datentyp?

Verfasst: 22. März 2011 20:55
von Nukleus
Daran soll es nicht scheitern: So wird geschrieben. Die Methode acnrListe() gibt das zu schreibende Bytearray zurück. (Ist ein wenig schwer zu lesen, weil ich jedes Statement kommentiere und die Eingabe hier mit meinen Tabs nicht so richtig klarkommt),

/* */
/* update der Auswertung */
/* */
if(ok) /* Frage: noch alles ok? */
{ /* wenn ja... */
query->prepare("UPDATE AUSWERTUNGEN SET " /* dann update durchfuehren */
"auswname = :AWN, " /* Name aufsetzen */
"acnrliste = :ANL " /* Liste der ACNummern aufsetzen */
"WHERE " /* mit diesen Bedingungen */
"auswnr = :ANR ");/* aber unterschiedlicher Nummer */
query->bindValue(":AWN",auswTitel->text()); /* werte Zuweisen */
query->bindValue(":ANR",auswnr); /* dito */
query->bindValue(":ANL",QVariant(acnrListe()),QSql::In | QSql::Binary);/* dito */
if(!query->exec()) /* Frage: geht das gut? */
{ /* wenn nein... */
QMessageBox::warning( this,"Warnung",textCodec->toUnicode( /* parent und caption der MB + Text */
tr("Datenbankfehler bei Update der erfassten Daten\n" /* oder Benutzer Ignoriert es */
"Prüfen Sie bitte Ihre Eingaben")), /* */
QMessageBox::Ok,QMessageBox::NoButton); /* */
ok = FALSE; /* Merken, es ging was schief */
}; /* Ende Frage: geht das gut, nein */
}; /* Ende Frage: alles noch ok, ja */


und so wird gelesen:


/* */
/* Fall: Modifizieren einer Auswertung */
/* */
case AuswerteDialog::modAusw: /* Frage: Aenderung */
this->setCaption(textCodec->toUnicode(tr("Auswertung ändern")));/* ueberschrift */
query->prepare("SELECT " /* Aufbau des SQL-Statements */
"auswname, " /* der Name */
"auswdescription, " /* Beschreibung der Auswertung */
"DATE_FORMAT(begin_period,'%d.%m.%Y'), " /* Beginn datum */
"DATE_FORMAT(end_period,'%d.%m.%Y'), " /* Ende datum */
"acnrliste " /* Liste der Account-Nummern */
"FROM AUSWERTUNGEN WHERE auswnr = :ANR "); /* */
query->bindValue("ANR",itemNr); /* hole den richtigen Datensatz */
query->exec(); /* fuehre Query aus */
query->next(); /* hole Satz */
auswTitel->setText(query->value(0).toString()); /* Name der Auswertung */
auswDescription->setText(query->value(1).toString()); /* Beschreibung der Auswertung */
auswZeitVon->setDate( /* Datum uebernehmen */
QDateTime::fromString( /* */
query->value(2).toString(),dateFormat).date()); /* */
auswZeitBis->setDate( /* Datum uebernehmen */
QDateTime::fromString( /* */
query->value(3).toString(),dateFormat).date()); /* */
ba = query->value(4).toByteArray(); /* Hole das Bytearray */

Verfasst: 22. März 2011 20:58
von Nukleus
Der Typ des Feldes acnrliste ist char(128) binary;

Verfasst: 22. März 2011 21:05
von upsala
Zum einen kann man kein QBitArray aus der Datenbank lesen, da MySQL keine Bit-Felder kennt.

Hast du schon mal überprüft, was wirklich in der Datenbank steht?

Verfasst: 22. März 2011 21:10
von Nukleus
Nein, das habe ich noch nicht geprüft. Muß mich dazu ein wenig tiefer in Mysql reinwursteln, aber das bekomme ich hin. Mit einem händischen Select in der Terminalbox sieht man mit binären Daten natürlich nix.

Aber stimmt natürlich, dann weiß man wenigstens woran es wirklich klemmt (schreiben oder lesen).

Verfasst: 23. März 2011 08:31
von padreigh
Da SQL keine bits kennt, wird der wohl jedes bit in einem Char speichern,
QVariant::BitArray (=13). ==> QVariant::ByteArray (=12).

Hypothese:
speichern 0 1000 0000 0000, führende 0 eleminiert SQL -> 12 Werte, die lieste auch wieder aus.

Vorschlag: wenn du fixe Größen hast, speicher dein Bitmuster doch einfach in einen 16 bit int, dann passt du speichern und laden so an, das das dir ein QByteArray aus dem integer bastelt. - dann brauchst du auch weniger Speicher in der Datenbank . ansonsten wäre auch ein kleiner string möglich und da einfach 010101101 reinschreiben - das ist immer noch sparsamer als ein fixes chararray, kostet aber mehr Speicher als ein integer - wenn du an die Datenbank nicht selbst rankommst - vergiss beides da du dafür den Typ ändern müsstest :)

Verfasst: 23. März 2011 16:13
von Nukleus
Also vielen Dank zusammen an alle, die auf meine Meldung gepostet haben.

Soweit ich es bisher weiter ermitteln konnte, hat mein Problem nichts mit QSqlQuery oder der Datenbank zu tun, sondern damit, daß ich genau dann Probleme bekomme, wenn ich ein Zeichen errechne, bei dem das höchste Bit gesetzt ist gepaart mit ein paar Eigenschaften von Bytearray. Alles andere tut einwandfrei.

Alleine mit dieser Erkenntnis komme ich weiter.

Verfasst: 23. März 2011 17:24
von Christian81
Ein Byte-Array in ein char-Feld zu schreiben ist ja auch nicht wirklich sinnig. In einem char-Feld stehen nunmal Zeichen (und werden auch als solches interpretiert) und keine binären Daten. Für binäre Daten gibts blobs ...

Verfasst: 23. März 2011 23:23
von Nukleus
Im Nachgang (und nach Lösung) eine kurze Zusammenfassung:

Das Problem war tatsächlich das führende Bit im char. Probleme hat nicht die Datenbank gemacht, sondern das Bytearray beim Einlesen aus der Datenbank (also der Befehl query->value(4).toByteArray()). Dabei erweitert Bytearray automatisch sein Array um mehrere Bytes, sobald es ein Byte bearbeitet, bei dem das high order Bit gesetzt ist. Damit ging die ganze beabsichtigte Zuordnung natürlich flöten.

Der Feldtyp Blob in der Datenbank hätte genau dasselbe Problem verursacht. Das wäre also keine Lösung gewesen.

Ich habe statt dessen auf Verwendung des High-Order bits verzichtet (verwende nur 7 bits der eigentlich möglichen 8, meine Methoden lassen das zu) und damit tut alles, wie es soll.

Der Preis: Das Datenfeld ist jetzt 20 Bytes länger. Insgesamt sind es dann maximal 500 bytes mehr. Bei einer TB Platte zu verschmerzen.

Verfasst: 24. März 2011 06:30
von Christian81
Sorry aber dass es ein Problem mit de QByteArray geben soll glaube ich nicht. Wir verwenden es genauso ohne irgendwelche Probleme. Ein lob ist genau für sowas da und da muss es funktionieren...
Ein minimales Beispiel mit de Fehler und wir würden sehen dass es nicht am QByteArray liegt.