【问题标题】:C++ SQLite3 not deleting with prepared statementC ++ SQLite3不使用准备好的语句删除
【发布时间】:2017-08-04 15:48:45
【问题描述】:

我在 C++ 中有以下代码来删除所有不在向量 ID 中的 ID。打印了应该删除的 ID,但是由于 ID 绑定,DELETE 似乎失败了。 (当我从语句中删除 ID 并只绑定引用时,效果很好)。

这就是数据库的创建方式:

CREATE TABLE IF NOT EXISTS Files (
    ID LONGTEXT DEFAULT NULL,
    Reference LONGTEXT NOT NULL,
    FilePath LONGTEXT PRIMARY KEY NOT NULL,
    ProcessedOn LONGTEXT NOT NULL)

删除正确ID的代码:

rc = sqlite3_prepare_v2(db, "SELECT ID FROM Files WHERE Reference=? AND ID IS NOT NULL", -1, &stmt, 0);
sqlite3_bind_text(stmt, 1, Settings["Reference"].c_str(), Settings["Reference"].length(), 0);
CheckDBError(rc);
rc = sqlite3_step(stmt);
sqlite3_stmt* stmt2;
int rc2 = sqlite3_prepare_v2(db, "DELETE FROM Files WHERE ID=? AND Reference=?", -1, &stmt2, 0);
CheckDBError(rc2);
while(rc == SQLITE_ROW) {
    string IDToCheck = (const char*)sqlite3_column_text(stmt, 0);
    cout << "Checking: " << IDToCheck << endl;
    if (find(IDs.begin(), IDs.end(), IDToCheck) == IDs.end()) {
        cout << "Delete " << IDToCheck << endl;

        //SHOWS ME THE CORRECT ID's BUT THE DELETE IS NOT WORKING. THE 
        //STATEMENT IS EXECUTED PROPERLY WHEN I ONLY USE IT WITH BOUND
        //REFERENCE, SO BINDING the IDToCheck GOES WRONG?

        sqlite3_bind_text(stmt2, 1, IDToCheck.c_str(), IDToCheck.length(), 0);
        sqlite3_bind_text(stmt2, 1, Settings["Reference"].c_str(), Settings["Reference"].length(), 0);
        rc2 = sqlite3_step(stmt2);
        }
    rc = sqlite3_step(stmt);
    }
sqlite3_finalize(stmt);
sqlite3_finalize(stmt2);

【问题讨论】:

  • “似乎失败了”“不工作”你能说得更具体点吗?
  • 您是否使用调试器来验证您是否将预期值传递给sqlite3_bind_text() 函数?
  • rcrc2 怎么样?并阅读sqlite3_bind_text() documentation 对其最后一个参数的看法。
  • 如果某个步骤失败,您需要检查返回值并记录相应的错误信息。最后一个参数不能是0
  • 正确的。您不了解文档的哪一部分?

标签: c++ sqlite prepared-statement


【解决方案1】:

sqlite3_bind_text() documentation 说:

BLOB 和字符串绑定接口的第五个参数是一个析构函数,用于在 SQLite 处理完 BLOB 或字符串后对其进行处理。即使调用绑定 API 失败,也会调用析构函数来处理 BLOB 或字符串。如果第五个参数是特殊值 SQLITE_STATIC,则 SQLite 假定信息位于静态、非托管空间中,不需要释放。如果第五个参数的值为 SQLITE_TRANSIENT,则 SQLite 在 sqlite3_bind_*() 例程返回之前立即生成自己的数据私有副本。

您没有使用显式析构函数释放的动态缓冲区,因此您不能使用函数指针。 c_str() 返回的缓冲区不是非托管的,所以不能使用SQLITE_STATIC。 所以你必须使用SQLITE_TRANSIENT

此外,您必须检查错误(检查rc2,并致电sqlite3_errmsg()

另外,您需要reset 该语句才能再次执行。

【讨论】:

  • 如果我加SQLITE_TRANSIENT,只执行第一个delete语句?
  • 嗯?你为什么问这个?这是你观察到的吗?
  • 是的...我执行了应用程序,现在只执行了第一个删除语句。但是,当我将 ID 与sqlite3_bind_int64 绑定时,会出现同样的情况,只执行第一个删除语句
  • 重置语句似乎是重点。我添加了重置行,现在它可以按预期工作了!谢谢,你帮了我很多忙!
猜你喜欢
  • 1970-01-01
  • 2010-11-05
  • 2013-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多