Erfolgreich eingefügt blob-Daten in SQLite-Datenbank, kann aber nicht die Daten eingefügt
Ich BLOB zum einfügen eines Objekts zu einer SQLite-Datenbank. Nach dem einsetzen, kann ich die Daten mit "SELECT" - Satz und die Daten korrekt sind, obwohl die Zeile von "TASK_HEAD" ist "Leer", wenn das durchsuchen der Datenbank mit "SQLite Database Browser".
Allerdings, wenn ich Sie zerstören das Objekt, das gerade eingefügt wurde, kann ich nicht die richtigen Daten mehr, mit dem Zeiger "pHead" verweist auf eine Adresse, wo die Inhalte von dessen "id" - Mitglied ist "铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪铪UG?" beim Lesen in VS2008 im debug-Modus.
Hier ist ein Beispiel:
//user-defined data type
typedef std::string TASK_ID;
struct TASK_HEAD
{
TASK_ID id;
std::string userData;
int Size()
{
return (id.size() + userData.size()) * sizeof(TCHAR);
}
};
//when TEST_INSIDE is defined, pHead is invalid; but if undef it, I can get the "head" I just inserted
//and if the blob data is a string (when USING_STRING is defined), I can get the string inserted into the db even though the "test" string has been destroyed
void CDBWriter::WriteTestData()
{
//open db
sqlite3* db = NULL;
int nRet = sqlite3_open(DATABASE_NAME.c_str(), &db);
if (nRet != SQLITE_OK)
{
return;
}
if (db != NULL)
{
//create a table
std::string cmdCreate("CREATE TABLE IF NOT EXISTS testTable (id TEXT NOT NULL, TASK_HEAD BLOB, PRIMARY KEY(id));");
char* errMsg = NULL;
nRet = sqlite3_exec( db , cmdCreate.c_str() , 0 , 0 , &errMsg );
if( errMsg != NULL )
{
sqlite3_free( errMsg );
errMsg = NULL;
return;
}
//#define USING_STRING
#define TEST_INSIDE
#ifndef TEST_INSIDE
TASK_HEAD head;
#endif //TEST_INSIDE
//insert blob data
const TASK_ID newID(NewGUID()); //NewGUID returns string like this: "5811307F-7AA7-4C44-831F-774FC5832627"
string query = "INSERT OR REPLACE INTO testTable (id, TASK_HEAD) VALUES ('";
query += newID;
query += "', ?1);";
sqlite3_stmt* res = NULL;
nRet = sqlite3_prepare_v2(db, query.c_str(), query.length(), &res, 0);
{
#ifdef TEST_INSIDE
TASK_HEAD head;
#endif //TEST_INSIDE
head.id = newID;
#ifdef USING_STRING
std::string test("ewsjoafijdoaijeofsafsd");
nRet = sqlite3_bind_blob (res, 1, test.c_str(), test.size(), SQLITE_TRANSIENT);
#else
int nsizeHead = sizeof(head);
int nSizeHeadSt = sizeof(TASK_HEAD);
int sizeString = sizeof(std::string);
size_t nLen = newID.size();
//nRet = sqlite3_bind_blob (res, 1, &head, sizeof(head), SQLITE_TRANSIENT);
nRet = sqlite3_bind_blob (res, 1, &head, head.Size(), SQLITE_TRANSIENT);
#endif //USING_STRING
if (SQLITE_OK == nRet)
{
nRet = sqlite3_step(res);
}
if (nRet != SQLITE_OK && nRet != SQLITE_DONE)
{
return;
}
}
//get all columns in the database
query = "SELECT * FROM testTable;";
nRet = sqlite3_prepare_v2 (db, query.c_str(), query.length(), &res, 0);
if (SQLITE_OK == nRet)
{
while (SQLITE_ROW == sqlite3_step(res))
{
#ifdef USING_STRING
const char* pHead = (const char*)sqlite3_column_blob(res, 1);
#else
const TASK_HEAD *pHead = (const TASK_HEAD*)sqlite3_column_blob(res, 1);
#endif //USING_STRING
continue;
}
}
sqlite3_finalize(res);
sqlite3_close(db);
}
}
Zuerst dachte ich, es könnte das problem von bytes übergeben sqlite3_bind_blob, so bekomme ich die bytes des Objektes eine dumme Methode, wie Sie hier sehen können (die size () - Funktion von TASK_HEAD), aber das hilft nicht.
Dann habe ich versucht zu verwenden SQLITE_STATIC statt SQLITE_TRANSIENT, immer noch nicht funktioniert.
Was ist falsch?
Ps: ich weiß, es ist eine schlechte Lösung zum einfügen eines Objekts in die db, und ich möchte nur wissen, warum ich kann nicht Lesen, wieder meine eingefügten Daten in die db.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich denke, das problem ist:
Kommen Sie nicht an die Adresse des TASK_HEAD Struktur und übergeben es an sqlite wie diese. Zum erstellen einer blob-Sie müssen flach Daten, die nichts mit Pointern und dynamische Puffer wie std::string-Objekte.
Müssen Sie serialisiert die TASK_HEAD Struktur in einem Puffer, noch bevor die Bindung Betrieb.
Zum Beispiel:
und:
Bitte beachten Sie das hinzufügen der Felder zu serialisieren, wie oben gezeigt, ist sehr schlecht (da dieses format nicht unserialized). Umgang mit blobs, die Sie brauchen, um eine gute Serialisierungs-Bibliothek oder-format (protocol buffer message pack, JSON, etc ...) oder Rollen Sie Ihre eigenen.
Es gibt ein zweites Problem in Ihrem code, an:
Wird dies nicht funktionieren, aus einem ähnlichen Grund.
Den Inhalt
userData
ist wahrscheinlich gespeichert werden auf dem heap. Auch wenn es im inneren aufbewahrt diestd::string
(für SSO), so kann Sie noch verwenden, die einen Zeiger auf sich selbst intern, und so wird es nicht funktionieren, wenn Sie bitweise kopieren an einen anderen Ort im Speicher (was du machst, ist äquivalent zu einemmemcpy
).Jedoch ist es egal, warum genau es nicht funktioniert, da es nur Undefiniertes Verhalten. Nur nicht "legen Sie ein Objekt in die db" wie diese. Entweder serialisieren Sie es mit einigen Serialisierung Bibliothek und dann einfügen, oder Sie verwenden zwei Spalten in der Tabelle, eine für
id
und eine füruserData
.