Sqlite C++ 中的预准备语句如何工作

Noc*_*era 5 c++ database sqlite c++17

我不知道如何在我的 Sqlite3 代码中实现准备好的语句

#include <iostream>
#include <sqlite3.h>
#include <stdio.h>

static int callback (void* NotUsed, int argc, char** argv, char** azColName) {
    int i;
    for (i = 0; i < argc; i++) {
        std::cout << ("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
    }
    std::cout << ("\n");
    return 0;
}

int main (int argc, char* argv[]) {
    sqlite3* db;
    char* zErrMsg = 0;
    int rc;
    char* sql;

    /* Open database */
    rc = sqlite3_open ("test.db", &db);

    if (rc) {
        std::cerr << "Can't open database: \n" << sqlite3_errmsg (db);
        return (0);
    }
    else {
        std::cout << "Opened database successfully\n";
    }
    std::string newName;
    std::cin >> newName;
    /* Create SQL statement */
    sql = "UPDATE company SET name = newName WHERE id = 1";


    /* Execute SQL statement */
    rc = sqlite3_exec (db, sql, callback, 0, &zErrMsg);

    if (rc != SQLITE_OK) {
        std::cout << "SQL error: \n" << zErrMsg;
        sqlite3_free (zErrMsg);
    }
    else {
        std::cout << "Records created successfully\n";
    }
    sqlite3_close (db);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

用户必须输入 newName,并且该变量应用于更新数据库中的字段。这种方式不起作用,因为Sql脚本正在搜索列。在互联网上我发现,我必须使用准备好的声明,但我不知道如何实现它。

jro*_*rok 10

您从一条 sql 语句开始,其中包含您希望稍后绑定的参数的占位符。在这里,我使用一个问号作为占位符,但文档中还描述了其他选项。

std::string sql = "UPDATE company SET name = ? WHERE id = 1";
Run Code Online (Sandbox Code Playgroud)

然后构建一个准备好的语句(或“编译”,正如他们在 sqlite 文档中所说的那样)。您通常会使用sqlite_prepare_v2函数,但还有其他函数(例如,当您的语句以 utf-8 以外的其他方式编码时)。

sqlite3_stmt* stmt; // will point to prepared stamement object
sqlite3_prepare_v2(
    db,            // the handle to your (opened and ready) database
    sql.c_str(),    // the sql statement, utf-8 encoded
    sql.length(),   // max length of sql statement
    &stmt,          // this is an "out" parameter, the compiled statement goes here
    nullptr);       // pointer to the tail end of sql statement (when there are 
                    // multiple statements inside the string; can be null)
Run Code Online (Sandbox Code Playgroud)

然后绑定参数。有一大堆可用的功能。您到底使用哪一种取决于您绑定到参数的数据类型。在这里,我们绑定文本,因此我们使用sqlite3_bind_text:

std::string newName = /* get name from user */;
sqlite3_bind_text(
    stmt,             // previously compiled prepared statement object
    1,                // parameter index, 1-based
    newName.c_str(),  // the data
    newName.length(), // length of data
    SQLITE_STATIC);   // this parameter is a little tricky - it's a pointer to the callback
                      // function that frees the data after the call to this function.
                      // It can be null if the data doesn't need to be freed, or like in this case,
                      // special value SQLITE_STATIC (the data is managed by the std::string
                      // object and will be freed automatically).
Run Code Online (Sandbox Code Playgroud)

因此,准备好的声明已准备就绪。现在您可以通过将其传递给来执行它sqlite3_step:

 sqlite3_step(stmt); // you'll want to check the return value, read on...
Run Code Online (Sandbox Code Playgroud)

现在,当您单步执行一条应该返回结果表行的语句时,SQLITE_ROW只要有结果行要处理,并且SQLITE_DONE没有剩余结果行,该函数就会继续返回。您可以使用sqlite3_column_*系列函数从结果行中获取单列。我会让你自己解决这个问题。

对于您拥有的简单更新语句,将在第一次调用时sqlite3_step返回。SQLITE_DONE更多信息和可能的错误代码请参见此处。

全部完成后,您将通过销毁准备好的语句来完成。

sqlite3_finalize(stmt);

我希望这能让你开始。