Binäre Werte in eine MySql-Datenbank schreiben / daraus lese
Binäre Werte in eine MySql-Datenbank schreiben / daraus lese
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?
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?
-
Christian81
- Beiträge: 7319
- Registriert: 26. August 2004 14:11
- Wohnort: Bremen
- Kontaktdaten:
Daran soll es nicht scheitern: So wird geschrieben. Die Methode acnrListe() gibt das zu schreibende Bytearray zurück.
st 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 */
/* */
/* 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 */
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).
Aber stimmt natürlich, dann weiß man wenigstens woran es wirklich klemmt (schreiben oder lesen).
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
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
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.
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.
-
Christian81
- Beiträge: 7319
- Registriert: 26. August 2004 14:11
- Wohnort: Bremen
- Kontaktdaten:
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.
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.
-
Christian81
- Beiträge: 7319
- Registriert: 26. August 2004 14:11
- Wohnort: Bremen
- Kontaktdaten:
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.
Ein minimales Beispiel mit de Fehler und wir würden sehen dass es nicht am QByteArray liegt.
MfG Christian
'Funktioniert nicht' ist keine Fehlerbeschreibung
'Funktioniert nicht' ist keine Fehlerbeschreibung