1

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

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改用。谁能证实我的想法?还是我不在基地?

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

4

2 回答 2

1

是的,这段代码是错误的。文档说:

如果第五个参数是特殊值 SQLITE_STATIC,则 SQLite 假定信息在静态、非托管空间中

但该局部变量不是静态的。

如果堆栈的该部分恰好在执行查询之前避免被覆盖,则此代码可能会起作用。

于 2015-05-21T16:22:29.683 回答
0

C++如果有人在 sqlite ABI上创建现代包装器C,那么我们可以使用R 值引用来选择性地使用 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() 获取底层句柄,其实现是根据某人的突发奇想和幻想。

于 2019-05-09T04:30:33.803 回答