我写了一个小类来处理SQLite准备查询。如果我在SQL中的变量是double,代码运行良好,给出一个值列表。但是当我绑定一个字符串时,我没有得到任何结果,因为sqlite3_step函数立即返回SQLITE_DONE。
失败的查询是`
string prepsql =
"Select foodname, price, storename from prices \
join foods on (foods.foodkey = prices.foodkey) \
join stores on (stores.storekey = prices.storekey) \
where foodname = ? order by price";
`
调用函数的C++代码是
PreparedQuery pq(db, prepsql);
pq.setVariable(1, "Milk");
pq.execute();
调用SQLite函数的实际代码是
PreparedQuery::PreparedQuery(sqltDatabase db, string query):
Query(db, query) {
int rc = sqlite3_prepare_v2(db.getDb(), query.c_str(), query.size(),
&stmt, nullptr);
checkerr(rc);
}
//bind a text value to the query
void PreparedQuery::setVariable(int index, string value) {
string sval = value;
auto val1 = sval.c_str();
int rc = sqlite3_bind_text(stmt, 1,val1, sizeof(val1), NULL);
checkerr(rc);
}
//bind a double value to the query
void PreparedQuery::setVariable(int index, double value) {
int rc = sqlite3_bind_double(stmt, 1, value);
checkerr(rc);
}
//execute the query and get back the column names and values
int PreparedQuery::execute() {
while (sqlite3_step(stmt) != SQLITE_DONE){
for (int col = 0; col < sqlite3_column_count(stmt); col++) {
const char* name = sqlite3_column_name(stmt, col);
const unsigned char* val = sqlite3_column_text(stmt, col);
std::cout << name << " is " << val << std::endl;
}
}
sqlite3_finalize(stmt);
return 0;
}
但是,如果我将查询的最后一部分改为使用双精度型
where price > ? order by price";
并为double调用setVariable方法
pq.setVariable(1, 2.00);
查询工作正常,我得到一个匹配查询的行列表。
所以我的sqlite_bind_text调用一定有什么我无法辨别的错误。我可能做错了什么。
这是一台运行Visual Studio Community Edition的Windows 10机器,我于2023年2月22日下载了SQLite3。C++ v20。
我尝试了用引号“Milk”括起来的字符串参数,结果没有什么不同。如果我将查询更改为包含实际字符串而不是问号,
where foodname = \"Milk\" order by price";
查询正确运行。
如果我使用相同的数据库在SQLite Studio中运行包含准备好的查询的问号,它会弹出一个地方来输入变量值:例如Milk,不带引号,它可以正常运行。
我有一种感觉,我错过了一些明显的东西,但我还没有发现它。建议欢迎。
2条答案
按热度按时间6xfqseft1#
两处修改使其最终成功:我将字符串sval作为类级别的变量,这样它就不会被删除;使用strlen而不是sizeof。
z9smfwbn2#
很可能,问题是在实际执行SQL之前,C++
string
对象中的字符串被移动或删除。尝试传递SQLITE_TRANSIENT
以将字符串标记为“临时”,以便SQLite创建自己的内部副本。