In sqlite3's C API, the function sqlite3_exec requires a callback function as a parameter, defined by
static int callback(void* data, int argc, char** argv, char** azColName)
I would like to have it work using a wrapper function to execute before the main callback. I.e. pass down my wrapper function to sqlite3_exec() which calls the actual callback.
A practical use case to illustrate what I am trying to achieve would be logging the response. As the code to log the response would (in my use case) not change across varying queries, since it can loop through the number of columns sent, I would like to have the logging defined once (i.e. in the wrapper) rather than re-defining it for all arbitrary amount of future callback functions defined.
This seems like the way to go but I don't know how to implement this.
I have tried creating a wrapper that takes in another argument - the actual callback, but passing this of course doesn't work as the function definition is then different.
Update: Example code that does not compile
#include <sqlite3.h>
#include <iostream>
#include <vector>
class Callback
{
public:
Callback( int(*callback)(void* data, int argc, char** argv, char** azColName), void* data )
: m_callback(callback), m_data(data) {}
~Callback(){}
public:
int CallbackWrapper(void* data, int argc, char** argv, char** azColName)
{
//Do something
return m_callback(m_data, argc, argv, azColName);
}
private:
int (*m_callback)(void* data, int argc, char** argv, char** azColName);
void* m_data;
};
class Product_Queries
{
public:
Product_Queries() {}
~Product_Queries() {}
public:
int GetProductIds_Callback(void* data, int argc, char** argv, char** azColName){
std::vector<int>* ids = (std::vector<int>*)data;
ids->push_back(std::stoi(argv[0]));
return 0;
}
};
int main(int argc, char* argv[])
{
sqlite3* db;
sqlite3_open("database.db", &db);
Product_Queries product_queries;
std::vector<int> productIds;
Callback callback(product_queries.GetProductIds_Callback, (void*)&productIds); //Error here
sqlite3_exec(db, "SELECT id FROM Products", callback.CallbackWrapper, nullptr, nullptr); //Error here
sqlite3_close(db);
return 0;
}
Both errors are invalid use of non-static member function
Something along these lines, perhaps:
struct OriginalCallback {
int (*callback)(void*,int,char**,char**);
void* data;
};
int WrapperCallback(void* data, int argc, char** argv, char** col_names) {
// Do the work
OriginalCallback* original = static_cast<OriginalCallback*>(data);
return original->callback(original->data, argc, argv, col_names);
}
int WrapSqliteExec(sqlite3* db, const char *sql,
int (*callback)(void*,int,char**,char**),
void* data, char **errmsg) {
OriginalCallback original{callback, data};
return sqlite3_exec(db, sql, WrapperCallback, &original, errmsg);
}