我知道这可能是一个非常愚蠢的错误,但我已经坐了几个小时盯着几行代码,浏览文档,我仍然不知道为什么会发生这种情况:
我正在为 C++11 中的 SQLite C API 编写一个方便的包装类。当建立与数据库的连接时,该函数sql
准备一个语句,必要时将参数绑定到它,然后执行它。准备和执行工作正常,绑定一个参数工作正常,但如果我想绑定多个参数,所有值将始终设置为列表中的最后一个参数。
该sql
函数如下所示:
template <typename... Args>
bool sql(const std::string &query, const Args &... args)
{
sql_statement call;
if(sqlite3_prepare_v2(database_, query.data(), -1, &call.statement, nullptr)
!= SQLITE_OK)
{
return false;
}
if(!bind(call.statement, 1, args...)) {
return false;
}
return sqlite3_step(call.statement) == SQLITE_DONE;
}
sql_statement
是一个包装结构,sqlite3_stmt
它只在语句超出范围时释放它。database_
是工作数据库的句柄。不过,我不确定此功能是否与问题有关。作为麻烦制造者,我宁愿想到的是在bind
函数中调用的sql
函数。这里是:
template <typename T, typename... Args>
bool bind(sqlite3_stmt *statement, int current, const T &first, const Args &... args)
{
std::stringstream ss;
ss << first;
if(sqlite3_bind_text(statement, current,
ss.str().data(), ss.str().length(), SQLITE_STATIC) != SQLITE_OK)
{
return false;
}
return bind(statement, current+1, args...);
}
bool bind(sqlite3_stmt *, int) { return true; }
注意没有错误,函数返回true。我已经用各种输入对此进行了调试;考虑这个例子:
if(!db.sql("INSERT INTO test (name, age) VALUES (?, ?);", "nijansen", 23)) {
std::cerr << db.error() << std::endl;
return 1;
}
当我调试 的函数调用时bind
,递归按预期工作,因此它将值[1] nijansen
和[2] 23
. SQLite C API 的文档说“最左边的 SQL 参数的索引为 1”,所以这不应该是问题。尽管如此,在数据库中查询的结果是:id: 1, name: 23, age: 23
. 我真的很感激再看这个问题。