【问题标题】:How does binding parameters work in SQLite3 (with minimal example)?绑定参数在 SQLite3 中如何工作(以最小的示例)?
【发布时间】:2015-08-04 20:34:25
【问题描述】:

有人建议在 SQLite 中使用参数绑定来加速重复查询。但是,如果我有多个绑定参数,它就不起作用。我没有看到我的错误。所有 SQLite 函数都返回 SQLITE_OK...

下面,我写了一个最小的例子。它创建一个表,创建三个条目,然后查询两次,一次使用一个绑定参数,一次使用两个绑定参数。第一次返回一个结果,这是正确的。第二个返回零结果,sqlite3_step() 返回 101 (SQLITE_DONE)。为什么它也不返回一个结果?

#include <vector>
#include <sqlite3.h>

int main(int argc, char * argv[])
{
  sqlite3 * pDB;
  int iReturn = sqlite3_open("./Test.db", &pDB);
  if (iReturn != SQLITE_OK) {
    return 1;
  }

  // create table
  {
    std::string str = "CREATE TABLE Names(ID INTEGER PRIMARY KEY, Name VARCHAR(30))";
    iReturn = sqlite3_exec(pDB, str.c_str(), NULL, NULL, NULL);
    if (iReturn != SQLITE_OK) {
      sqlite3_close(pDB);
      return 1;
    }
  }

  // insert data using binding
  {
    std::string str = "INSERT INTO Names(Name) VALUES(?)";
    sqlite3_stmt * pStmt = nullptr;

    iReturn = sqlite3_prepare_v2(pDB, str.c_str(), str.size() + 1, &pStmt, nullptr);
    if (iReturn != SQLITE_OK) {
      sqlite3_close(pDB);
      return 1;
    }

    printf("The statement %s has %d parameter(s).\n", str.c_str(), sqlite3_bind_parameter_count(pStmt));

    std::vector<std::string> vecNames;
    vecNames.push_back("Smith");
    vecNames.push_back("Morpheus");
    vecNames.push_back("Neo");

    for (unsigned int i = 0, iEnd = vecNames.size(); i != iEnd; ++i)
    {
      iReturn = sqlite3_bind_text(pStmt, 1, vecNames[i].c_str(), vecNames[i].size() + 1, nullptr);
      if (iReturn != SQLITE_OK) {
        return 1;
      }

      if (sqlite3_step(pStmt) != SQLITE_DONE) {
        sqlite3_finalize(pStmt);
        sqlite3_close(pDB);
        return 1;
      }

      sqlite3_reset(pStmt);
      sqlite3_clear_bindings(pStmt);
    }

  }

  // query using one bind parameter
  {
    sqlite3_stmt * pStmt = nullptr;
    string str = "SELECT ID FROM Names WHERE Name=?1";
    iReturn = sqlite3_prepare_v2(pDB, str.c_str(), str.size() + 1, &pStmt, nullptr);
    if (iReturn != SQLITE_OK) {
      return 1;
    }

    printf("The statement %s has %d parameters(s).\n", str.c_str(), sqlite3_bind_parameter_count(pStmt));

    // fourth parameter is length = position of \0
    iReturn = sqlite3_bind_text(pStmt, 1, "Neo", 3, NULL);
    if (iReturn != SQLITE_OK) {
      return 1;
    }

    vector<string> vecResults;
    char cBuffer[1024];
    string strBuffer;
    while (sqlite3_step(pStmt) == SQLITE_ROW)
    {
      sprintf(cBuffer, "%s", sqlite3_column_text(pStmt, 0));
      strBuffer = cBuffer;
      vecResults.push_back(strBuffer);
    }

    sqlite3_finalize(pStmt);

    printf("Found %d results.\n", vecResults.size());
    for (unsigned int i = 0, iEnd = vecResults.size(); i != iEnd; ++i)
    {
      printf("%d: %s\n", i, vecResults[i].c_str());
    }
  }

  // query using two bind parameters
  {
    sqlite3_stmt * pStmt = nullptr;
    string str = "SELECT ID FROM Names WHERE Name=?1 AND ID=?2";
    iReturn = sqlite3_prepare_v2(pDB, str.c_str(), str.size() + 1, &pStmt, nullptr);
    if (iReturn != SQLITE_OK) {
      return 1;
    }

    printf("The statement %s has %d parameters(s).\n", str.c_str(), sqlite3_bind_parameter_count(pStmt));

    // fourth parameter is length = position of \0
    iReturn = sqlite3_bind_text(pStmt, 1, "Neo", 3, NULL);
    if (iReturn != SQLITE_OK) {
      return 1;
    }


    iReturn = sqlite3_bind_text(pStmt, 2, "3", 2, NULL);
    if (iReturn != SQLITE_OK) {
      return 1;
    }


    vector<string> vecResults;
    char cBuffer[1024];
    string strBuffer;
    while (sqlite3_step(pStmt) == SQLITE_ROW)
    {
      sprintf(cBuffer, "%s", sqlite3_column_text(pStmt, 0));
      strBuffer = cBuffer;
      vecResults.push_back(strBuffer);
    }

    sqlite3_finalize(pStmt);

    printf("Found %d results.\n", vecResults.size());
    for (unsigned int i = 0, iEnd = vecResults.size(); i != iEnd; ++i)
    {
      printf("%d: %s\n", i, vecResults[i].c_str());
    }
  }

  sqlite3_close(pDB);

  return 0;
}

【问题讨论】:

  • 注意。有点不一致的代码。作为 sqlite 样本不好。 - NULL 与 nullptr。 - api 用法:sqlite3_bind_text() - 带或不带终止符。 - 没有那些 boost::scope_exit 守卫

标签: c++ sqlite


【解决方案1】:

因为该行不是字符串。

将第二个参数的绑定更改为sqlite3_bind_int(pStmt, 2, 3);,它应该可以正常工作。

另外,为什么你的名字行是 VARCHAR(30) 而不是 TEXT?

【讨论】:

  • 在 SQLite 中,VARCHARTEXT 的含义完全相同:它赋予列文本关联性。
  • 如果 sqlite3_bind_text() 无法将我的参数(TEXT 类型)绑定到列 ID(INTEGER 类型),为什么它会返回 SQLITE_OK?如果至少没有警告我,这不是糟糕的设计吗? (另见stackoverflow.com/q/31809625/4675398
  • 可以很好的绑定,但是不能执行。
  • 很好;-)。但是 sqlite3_step() 返回 SQLITE_DONE 而不是 SQLITE_BAD_BINDING 之类的东西。我怎样才能调试出了什么问题?请看我的另一个问题:stackoverflow.com/q/31809625/4675398
  • 哈哈!我的问题是我没有将 SQLITE_TRANSIENT 作为 sqlite3_bind_text() 中的最后一个参数。 SQLITE_TRANSIENT 复制我绑定的内容,这是必要的,因为我绑定的内容只存在于本地。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-06
  • 1970-01-01
  • 1970-01-01
  • 2016-06-09
  • 2013-10-08
  • 2019-05-23
相关资源
最近更新 更多