【问题标题】:Encoding problems during INSERT with Sqlite3 C++ and VisualStudio2010使用 Sqlite3 C++ 和 VisualStudio2010 插入期间的编码问题
【发布时间】:2015-04-26 11:12:25
【问题描述】:

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

我尝试将 VS 中的字符集配置值用作“使用多字节字符集”,也尝试使用“使用 Unicode 字符集”,但结果没有任何变化。两者都给我与损坏的数据相同的问题。我使用转换为传统 c char* 的典型 std::strings,正如我在几个示例中看到的那样,它应该与 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 是一个类的实例,它包含 std::strings 和 int 中的信息。我不得不说 int 类型的绑定可以完美地工作并且没有问题,但是其他的看起来完全一团糟。当字符串被硬编码时,它们看起来也不错,直到我尝试插入特殊字符,例如“áàä”等。

表是用以下语句创建的:

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);

这是我使用上面的代码 sn-p 插入数据时的样子:

从 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 的任何其他函数调用都不会返回错误代码。

【问题讨论】:

  • std::strings 的编码是什么?
  • 你是如何创建表格的?您使用哪种类型的文本?
  • 字符串是基本的 std::strings。该表是这样创建的: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);
  • 尝试切换到 sqlite3_bind_text16

标签: c++ visual-studio-2010 encoding utf-8 sqlite


【解决方案1】:

我找到了解决方案。这与编码无关,因为我认为字符在 DB 浏览器中被奇怪地表示,并且与长度无关。

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

sqlite3_bind_text SQLITE_STATIC vs SQLITE_TRANSIENT for c++ string

【讨论】:

    【解决方案2】:

    我认为sqlite reference 对 API 的使用非常清楚。

    在那些有第四个参数的例程中,它的值是数字 参数中的字节数。需要明确的是:该值是 值中的字节数,而不是字符数。

    根据您的使用情况,

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

    注意:处理多字符的字符串时要小心。 在哪里 strlen(chinese string) ! = chinese string.len 。详情请参考here

    【讨论】:

    • 据我所知,我已经能够在网络上的一些示例中看到,指定字符串的大小是提高速度的好习惯。当一个人只是将 -1 作为参数时,sqlite 会自己猜测大小,所以这不应该是问题(根据我的测试,它不是问题)。
    • @Ed 你是否遇到同样的错误,即使在明确指定了长度之后?
    • 是的,我也试过像sqlite3_bind_text(stmt, 2, "hardcoded", -1, SQLITE_STATIC);这样的绑定文本,大小没有问题。所以我会说这个论点没有问题。
    • 所以你的意思是,字符串文字没有任何问题?并且只有 std::string 有一些问题?
    猜你喜欢
    • 2018-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-02
    • 1970-01-01
    • 2011-08-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多