Proper use of callback function of sqlite3 in C++

前端 未结 2 521
独厮守ぢ
独厮守ぢ 2020-12-08 08:43

I have the following C++ code for testing purposes in conjunction with SQLite3. It\'s a class called customer with a callback function declared. This callback f

相关标签:
2条回答
  • 2020-12-08 09:07

    Using sqlite3_exec has the disadvantages that you have to convert some values back from a string to a number, and that it needs to allocate memory for all result records (which can lead to problems when reading large tables). Furthermore, the callback always is a separate function (even if it's in the same class).

    For your example query, using the sqlite3_prepare/sqlite3_step/sqlite3_finalize API would look like this:

    void one_customer::readFromDB(sqlite3* db, int id)
    {
        sqlite3_stmt *stmt;
        int rc = sqlite3_prepare_v2(db, "SELECT FirstName, LastName, Age"
                                        " FROM customerTable"
                                        " WHERE Id = ?", -1, &stmt, NULL);
        if (rc != SQLITE_OK)
            throw string(sqlite3_errmsg(db));
    
        rc = sqlite3_bind_int(stmt, 1, id);    // Using parameters ("?") is not
        if (rc != SQLITE_OK) {                 // really necessary, but recommended
            string errmsg(sqlite3_errmsg(db)); // (especially for strings) to avoid
            sqlite3_finalize(stmt);            // formatting problems and SQL
            throw errmsg;                      // injection attacks.
        }
    
        rc = sqlite3_step(stmt);
        if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
            string errmsg(sqlite3_errmsg(db));
            sqlite3_finalize(stmt);
            throw errmsg;
        }
        if (rc == SQLITE_DONE) {
            sqlite3_finalize(stmt);
            throw string("customer not found");
        }
    
        this->id         = id;
        this->first_name = string(sqlite3_column_text(stmt, 0));
        this->last_name  = string(sqlite3_column_text(stmt, 1));
        this->age        =        sqlite3_column_int(stmt, 2);
    
        sqlite3_finalize(stmt);
    }
    

    (This code handles errors by just throwing a string with the error message.)

    0 讨论(0)
  • 2020-12-08 09:12

    What one typically does in this case is take advantage of the void * (which you call NotUsed) parameter of the callback -- a parameter you define when you install the callback. For C++, you would typically set that parameter to the this pointer to your interested object, and you would make the callback (an extern "C" function in a c++ source file) a friend method to your class (if necessary).

    This would look like this:

    class customer
    {
        ...
    public:
        int callback(int argc, char **argv, char **azColName);
    };
    
    static int c_callback(void *param, int argc, char **argv, char **azColName)
    {
        customer* cust = reinterpret_cast<customer*>(param);
        return cust->callback(argc, argv, azColName);
    }
    
    char* customer::getCustomer(int id)
    {
        ...
        rc = sqlite3_exec(db, sql, c_callback, this, &errMsg);
        ...
    }
    
    int customer::callback(int argc, char **argv, char **azColName)
    {
        ...
    }
    
    0 讨论(0)
提交回复
热议问题