SQLite SQLITE_STATIC 局部变量问题

SQLite SQLITE_STATIC Local Variable Issue

我正在查看一些供应商代码并且有这样的查询:

BOOL BindQuery(sqlite3_stmt* stmt, PARAMS* params)
{
    char temp[150] = "";
    char paramBuf[10] = "";
    if (currStmt == NULL) return FALSE;

    sprintf(paramBuf, "%d", (int)params->someParam);
    strcpy(temp, "%");
    strcat(temp, tempVolt);
    strcat(temp, "%");
    sqlite3_bind_text(stmt, 4, temp, strlen(temp), SQLITE_STATIC);
    return TRUE;
}

稍后执行查询。问题是这个查询永远不会匹配,即使它应该匹配。

我认为问题在于 sqlite3_bind_text 绑定了一个局部变量,而 SQLite 保留了指向原始局部变量的指针。所以当它超出范围时,它可能已经被覆盖了。解决方法似乎是改用 SQLITE_TRANSIENT 。谁能证实我的想法?还是我跑题了?

另一个奇怪的问题是供应商永远无法复制它。运气?

是的,这段代码是错误的。 documentation 表示:

If the fifth argument is the special value SQLITE_STATIC, then SQLite assumes that the information is in static, unmanaged space

但是那个局部变量不是静态的。

如果堆栈的那部分恰好在执行查询之前避免被覆盖,则此代码可能有效。

如果有人在 sqlite C ABI 上创建现代 C++ 包装器,那么 我们可以使用 R-Value 引用 来选择性地使用 SQL_TRANSIENT 对于传递的临时对象。

如下所示

class Statement
{
/*Other Logic*/
/* Other Bind() overloads using SQLITE_STATIC */
void Bind(const int index, std::string && text) const
{
  if(SQLITE_OK != sqlite3_bind_text(FetchABI(),index,text.c_str(),text.size(),SQLITE_TRANSIENT))
{
 // Error Handling
}
}
/* Bind overload for std::wstring */
};

当我们传递临时对象时,编译器足够聪明,可以选择正确的重载,因此我们避免了 SQLite 在每个地方制作私有副本的成本(小型应用程序可能不需要)

main()

里面
Statement obj;
obj.Prepare(cx,"Select ?1"); // cx is the connection not defined here for brevity
obj.Bind(1,std::string("This value is copied"));
// Or the second overload
obj.Bind(1,std::wstring(L"This too is copied"));

注意:FetchABI()获取底层句柄,其实现是根据某人的心血来潮和幻想。