使用 Sqlite3 C++ 和 VisualStudio2010 插入期间的编码问题

Encoding problems during INSERT with Sqlite3 C++ and VisualStudio2010

我正在为使用 sqlite3 和 C++ API 和 VisualStudio 2010 的项目开发一个小型包装器。就目前而言,使用 SQLiteDataBaseBrowser 等工具进行检查,主要问题是我尝试在 table 中插入的信息似乎已损坏/根本没有出现。 table 似乎是使用 UTF8 编码正确创建的。

我尝试将 VS 中的字符集配置值用作 "Use Multy-Byte Character set",也尝试使用 "Use Unicode Character set",但结果没有任何变化。两者都给了我同样的数据损坏问题。我使用典型的 std::strings 转换为遗留 c char* 并且正如我在几个示例中看到的那样,它应该与 API 提供的 sqlite3_bind_text(...) 函数一起正常工作。

    sqlite3_bind_int(stmt, 1, newShop.GetId());
    sqlite3_bind_text(stmt, 2, newShop.GetName().c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 3, newShop.GetLocation().c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 4, newShop.GetPicturePath().c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 5, newShop.GetRegisters().c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 6, newShop.GetMixes().c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 7, newShop.GetAllowedUsers().c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_int(stmt, 8, newShop.IsAvailable() == true?1:0);

newShop 是 class 的实例,它包含 std::strings 和 int 中的信息。我不得不说与 int 类型的绑定工作完美且没有问题,但其他人看起来完全搞砸了。当字符串被硬编码时,它们看起来也不错,直到我尝试插入特殊字符,如“áàä”等。

table 是使用以下语句创建的:

char *szSQL = "CREATE TABLE IF NOT EXISTS SHOPS (ID INTEGER PRIMARY KEY NOT NULL, NAME TEXT NOT NULL, LOCATION TEXT, PICTUREPATH TEXT, REGISTERS TEXT, MIXES TEXT, USERS TEXT, AVAILABLE INTEGER NOT NULL);";
int rc = sqlite3_exec(db, szSQL, NULL, 0, NULL);

这是我使用上面的代码片段插入数据时的样子:

从看起来像这样的 WINUNIT 测试发送它:

Shop shOne = Shop(1234, "Its about nothing", "Manhattan", "seinfeld.jpg", "1111,2222,3333", "1000x1,2000x7", "10,11,12", true); 
Shop shTwo = Shop(4321, "Louie", "Manhattan", "", "1111,5555", "50000x1,10000x5", "60,70", true);

WIN_ASSERT_EQUAL(0, auxsql.InsertShop(shOne));
WIN_ASSERT_EQUAL(0, auxsql.InsertShop(shTwo));

插入、提交、创建 sql 语句或对 sqlite3 API return 的任何其他函数调用都不是错误代码。

我觉得sqlite reference已经很清楚API的用法了。

In those routines that have a fourth argument, its value is the number of bytes in the parameter. To be clear: the value is the number of bytes in the value, not the number of characters.

根据您的使用情况,

sqlite3_bind_text(stmt, 2, newShop.GetName().c_str(), -1, SQLITE_STATIC); 第 4 个参数是 -1。但是它应该是 newShop.GetName().length 或 strlen(newShop.GetName().c_str())`

Note : be careful when you deal with string with multi-wide chars. Where strlen(chinese string) ! = chinese string.len . Refer here for more details.

我找到了解决方案。这与编码无关,正如我所想的那样,因为字符在数据库浏览器中被奇怪地表示,而且与长度无关。

问题出在绑定的最后一个参数中。在我传递 SQLITE_STATIC 的地方,我应该传递 SQLITE_TRANSIENT,因为我想绑定的调用返回的对象可能在执行查询之前被破坏。正如另一个问题中所解释的那样:

sqlite3_bind_text SQLITE_STATIC vs SQLITE_TRANSIENT for c++ string