0

So I'm trying to use SQLite with MFC dialogues in Visual Studio 2010. I'm unclear as how to use the callback function in order for me to save result of the query, which is trying to count the number of tables in my database, into the variable m_Results. Is there anyway to do this, or is there anyway for me to access the nTables variable?

static int callback(void *data, int argc, char **argv, char **azColName){
    int i;
    fprintf(stderr, "%s: ", (const char*)data);
    data = argv[0];
    return 0;
}

BOOL CDBpracticeDlg::OnInitDialog(){
    ...

    // TODO: Add extra initialization here
    sqlite3 *db;
    char *zErrMsg = 0;
    int rc;
    char *sql;
    const char* data = "Callback function called";

    rc = sqlite3_open("structInfo_Test.db", &db);

    if( rc ){
        fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
        return(0);
    }else{
        fprintf(stderr, "Opened database successfully\n");
    }

    /* Create SQL statement */
    sql = "Select Count(*) as nTables FROM sqlite_master where type='table';";

    /* Execute SQL statement */
    rc = sqlite3_exec(db, sql, callback, &m_Results, &zErrMsg);
    if( rc != SQLITE_OK ){
        char error[200];
        strcpy(error,"SQL error: ");
        strcat(error,zErrMsg);
        m_Results = error;
        fprintf(stderr, "SQL error: %s\n", zErrMsg);
        sqlite3_free(zErrMsg);
    }else{
        fprintf(stdout, "Operation done successfully\n");
    }
    UpdateData(FALSE);
    sqlite3_close(db);

    return TRUE;  // return TRUE  unless you set the focus to a control
}

1 Answer 1

2

The callback for the sqlite3_exec API is widely underdocumented. The fact that it is purported with misleading parameter names doesn't help much, either. Providing more natural formal parameter names goes a long way:

static int callback(void* context,  // user-provided object (4th param to sqlite3_exec)
                    int columnCount,      // number of columns
                    char** columnValues,  // array of column values as C-style strings
                    char** columnName)    // array of column names as C-style strings

To update the m_Results object from the callback, you simply have to cast context to the correct type, and use that:

static int callback(void* context, int columnCount,
                    char** columnValues, char** columnNames) {
    CMyType& results = *static_cast<CMyType*>(context);
    // Use 'results' which is a reference to 'm_Results'.
    for (int index = 0; index < columnCount; ++index) {
        // Assuming CMyType has operator+=(const char*) (like a CString)
        results += columnNames[index];
        results += ": ";
        results += columnValues[index];
    }
    // Return 0 to continue invoking the callback for the remaining rows in the result
    // set. Returning non-zero will terminate the callbacks, and sqlite3_exec()
    // returns SQLITE_ABORT.
    return 0;

As an alternative, you can pass this in place of &m_Results to sqlite3_exec(), and invoke a public class member from your callback:

static int callback(void* context, int columnCount,
                    char** columnValues, char** columnNames) {
    CDBpracticeDlg* obj = static_cast<CDBpracticeDlg*>(context);
    // Delegate callback to class member implementation
    return obj->MyCallback(columnCount, columnValues, columnNames);
}

...

rc = sqlite3_exec(db, sql, callback, this, nullptr);
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for your answer. I tried you solution, but I was getting errors with the results += columnNames[index]; How do you concatenate two pointers?
@J.Ting: pass the CString to the function. Why bother with the pointers if you already have MFC
@J.Ting: Since you never told us, what type m_Results is, I had to assume one. This answer demonstrated, how to pass data to the callback. You'll have to work out the details on using that data yourself.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.