sqlite3_bind_text不适合我,但bind-double工作得很好



我写了一个小类来处理SQLite准备的查询。如果我的变量在SQL是一个双代码运行良好给出一个值列表。但是当我绑定一个字符串时,我没有得到任何结果,因为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";

并为双精度

调用setVariable方法
pq.setVariable(1, 2.00);

查询正常工作,并且我得到匹配查询的行列表。

所以我的sqlite_bind_text调用一定有问题,我无法辨别。我做错了什么?
这是一台运行Visual Studio社区版的Windows 10机器,我在2023年2月22日下载了SQlite3。c++ v20。

我尝试了用引号"Milk"这没什么区别。如果我更改查询以包含实际字符串而不是问号,

where foodname = "Milk" order by price";

查询运行正确。
如果我在SQLite Studio中使用相同的数据库运行包含准备好的查询的问号,它会弹出一个输入变量值的地方:Milk例如,没有引号,它可以正常运行。

我有一种感觉,我错过了一些明显的东西,但我还没有发现它。建议欢迎。

两处修改使它最终工作。我将字符串sval设置为类级变量,这样它就不会被删除,并且使用strlen而不是sizeof。

sval = value;  //class level variable
const char* val1 = sval.c_str();
int rc = sqlite3_bind_text(stmt, 1,val1, strlen(val1), NULL);

可能的问题是,在实际执行SQL之前,c++string对象中的字符串被移动或删除。尝试传递SQLITE_TRANSIENT将字符串标记为"临时",以便SQLite自己在内部复制。

编辑:同样,不要使用sizeof(val1)作为长度参数,因为那只会给你char*的大小。您需要字符串的实际长度。所以:

int rc = sqlite3_bind_text(stmt, 1, val1, strlen(val1), SQLITE_TRANSIENT);

最新更新