如何使用本机 sqlite 库而不是 QSql 从 sqlite 插入和检索 QString
Posted
技术标签:
【中文标题】如何使用本机 sqlite 库而不是 QSql 从 sqlite 插入和检索 QString【英文标题】:How to insert and retrieve QString from sqlite using native sqlite library instead of QSql 【发布时间】:2015-02-06 13:39:21 【问题描述】:我在一个使用 Qt 的 C++ 项目中使用本机 sqlite 库(合并 1file),我围绕它创建了一个简单的包装器,但我在插入和选择长 UTF-8 文本时遇到了麻烦。
我用这段代码插入数据:
SqlResult *result = new SqlResult();
sqlite3_stmt *statement;
int current_parameter = 1;
this->LastStatement = sql;
int x = sqlite3_prepare_v2(this->db, sql.toUtf8().constData(), sql.length() + 1, &statement, NULL);
foreach (QString text, parameter)
////////////// here is problem ///////////////
x = sqlite3_bind_text(statement, current_parameter++, text.toUtf8().constData(), -1, SQLITE_STATIC);
if (!this->Evaluate(x))
...
如您所见,我正在使用 SQL 变量 ?
,其文本绑定到使用函数 sqlite3_bind_text(statement, current_parameter++, text.toUtf8().constData(), -1, SQLITE_STATIC)
,该函数应获取 QString 文本的值并将其转换为 utf8 const char *
。然而,我在数据库中获得的文本部分是垃圾(当我使用一些 sqlite 浏览器应用程序时,我可以看到一些奇怪的符号)。
这是我用来转换 const char *
的代码,我从 sqlite3_column_text
获得
static QString StringFromUnsignedChar( const unsigned char *str )
std::string temp = std::string(reinterpret_cast<const char*>(str));
return QString::fromUtf8(temp.c_str());
我得到的文本与我在 sqlite 管理器中看到的“垃圾”相同。所以我想问题出在插入过程中,并且选择可能有效。怎么了?如何正确使用 sqlite3_bind_text
函数和 QString
?
附:我宁愿不使用 Qt 自己的 sqlite 实现,主要是出于兼容性目的(在 linux 上我使用 Qt4,在 windows Qt5 上,我希望在任何地方都有相同的 sqlite 库以实现可移植性)
【问题讨论】:
会不会是double UTF-8 encoding的问题? 看来我已经找到了这个bug,问题是我需要使用SQL_TRANSIENT
,以便sqlite创建一个const char *数组的副本,因为它是在堆栈上分配的,所以很快就会被删除随着函数调用结束。 sqlite 将删除的字符串存储到数据库中,这是大多数字符变成垃圾的原因。
太棒了。发布为答案。
【参考方案1】:
问题在于我自己的代码,用法正确但实现不正确。这一行:
sqlite3_bind_text(statement, current_parameter++, text.toUtf8().constData(), -1, SQLITE_STATIC);
需要
sqlite3_bind_text(statement, current_parameter++, text.toUtf8().constData(), -1, SQLITE_TRANSIENT);
如文档所述:
BLOB 和字符串绑定接口的第五个参数是 析构函数用于在 SQLite 处理后处理 BLOB 或字符串 完成它。调用析构函数来处理 BLOB 或 即使对绑定 API 的调用失败,也是字符串。如果第五个参数是 特殊值 SQLITE_STATIC,则 SQLite 假定 信息位于静态、非托管空间中,不需要 释放。如果第五个参数的值为 SQLITE_TRANSIENT,则 SQLite 立即创建自己的私有数据副本,在 sqlite3_bind_*() 例程返回。
因此,使用其原生 API 将 QString 与 sqlite 一起使用的正确方法是:
// Create and evaluate a statement
sqlite3_stmt *statement;
// Note: return value should be checked for error here
sqlite3_prepare_v2(pointer_to_sqlite_db, sql.toUtf8().constData(), sql.length() + 1, &statement, NULL);
// Bind QString to SQL statement - it must be transient so that sql text persist even after function call is over and data is destructed
sqlite3_bind_text(statement, current_parameter++, text.toUtf8().constData(), -1, SQLITE_TRANSIENT);
// step
sqlite3_step(statement);
// clean up
sqlite3_finalize(statement);
如何将const char *
转换回QString
static QString StringFromUnsignedChar( const unsigned char *str )
return QString::fromUtf8(reinterpret_cast<const char*>(str));
QString result = StringFromUnsignedChar(sqlite3_column_text(statement, column));
【讨论】:
不需要到 std::string 的转换,如果你确实想要它,你可以使用 QString::fromStdstring以上是关于如何使用本机 sqlite 库而不是 QSql 从 sqlite 插入和检索 QString的主要内容,如果未能解决你的问题,请参考以下文章
如何在从cordova创建的本机代码中使用相同的android SQLite DB?
使用音频单元(混音器主机)从 iPod 库而不是预先选择的声音文件中播放。
CMake:是不是可以仅从静态库而不是源代码构建可执行文件?