I am using visual studio 2015 and i want to use sqlite3 with it, i have managed to integrate sqlite3 into it, but i can only use it through native c style, i cannot use sqlite using classes as we do in c++. There is a table test in my database which contain values (id int , id1 int , name string)
For example this program runs fine
void forprinting(string a)
{
cout << a<<"\n";
}
int callback(void *NotUsed, int argc, char **argv, char **azColName) {
int i;
string testing;
string test2;
for (i = 0; i<argc; i++)
{
testing = testing + azColName[i];//irrelevant
test2 += argv[i];
}
forprinting(test2);
printf("\n");
return 0;
}
int main()
{
char *zErrMsg = 0;
sqlite3 *db;
int rc;
rc = sqlite3_open("DATA.db", &db);
char *data;
const char *sql;
sql = "SELECT * FROM test;";
sqlite3_exec(db, sql, callback, 0, &zErrMsg);
sqlite3_close(db);
system("pause");
return 0;
}
The output of this program is 0 0 test
which is fine but when i try to implement the same logic using classes i get the error here
#include <iostream>
#include <stdio.h>
using namespace std;
void forprinting(string a) {
cout << a << "\n";
}
class testingSqlite {
public :
int callback(void *NotUsed, int argc, char **argv, char **azColName) {
int i;
string testing;
string test2;
for (i = 0; i<argc; i++) {
testing = testing + azColName[i];
test2 += argv[i];
}
forprinting(test2);
printf("\n");
return 0;
}
void initiate() {
char *zErrMsg = 0;
sqlite3 *db;
int rc;
rc = sqlite3_open("DATA.db", &db);
char *data;
const char *sql;
sql = "SELECT * FROM test;";
sqlite3_exec(db, sql, callback, 0, &zErrMsg);
sqlite3_close(db);
}
};
int main()
{
testingSqlite test1;
test1.initiate();
system("pause");
return 0;
}
I know its a bad practice to define functions in class but i was in hurry. And it is giving
Error C3867 'testingSqlite::callback': non-standard syntax; use '&' to create a pointer to member
Error (active) argument of type "int (testingSqlite::*)(void *NotUsed, int argc, char **argv, char **azColName)" is incompatible with parameter of type "int (*)(void *, int, char **, char **)"
I tried to change the function arguments to fix it but nothing yet works.
This:
sqlite3_exec(db, sql, callback, 0, &zErrMsg);
Should be:
sqlite3_exec(db, sql, &testingSqlite::callback, 0, &zErrMsg);
The latter is the correct "member of" syntax. If you ever could use the former, it was nonstandard (some compilers did allow it).
That said, it won't work either because the function signature does not indicate it can be a member function.
Instead, you can use the "void *" of the parameter list.
That is, you must create something like
int callback(void *o, int argc, char **argv, char **cname)
{
testingSqlite op* = reinterpret_cast<testingSqlite *>(o);
return op->callback( argc, argv, cname );
}
This means your callback in tesingSqlite doesn't take the void *
You also provide c style callback as the function pointer, not your member function. You also must provide the 'this' pointer as the 4th parameter (it becomes the void * when it calls you back), like:
sqlite3_exec( db, sql, callback, this, &zErrMsg );
Related
I have a column of integers(containing port numbers) in my sqlite data base. Now I want to retrieve list of ports from sqlite in an array form in a function and send data to those port numbers. I tried to make a struct having pointer to Vector but it didn't work out. Making char pointers caused Segmentation error. Here is my code:
struct ConnIDs{
vector<int*> *ids;
};
static int callback(void *NotUsed, int argc, char **argv, char **szColName)
{
ConnIDs *first=(ConnIDs *)NotUsed;
for(int i = 0; i < argc; i++)
{
if (strcmp(szColName[i], "ConnID") == 0)
{
first->ids->push_back(argv[i]);
}
std::cout << szColName[i] << " = " << argv[i] << std::endl;
}
std::cout << "\n";
return 0;
}
int main(){
int result;
sqlite3 *db;
ConnIDs first;
int count = 0;
char *szErrMsg = 0;
int rc = sqlite3_open("Sqlite_Test.db", &db);
if(rc)
{
std::cout << "Can't open database\n";
} else
{
std::cout << "Open database successfully\n";
}
char *pSQL2[1];
pSQL2[0] = "Select * from Subscribers";
rc = sqlite3_exec(db, pSQL2[0], callback, &first, &szErrMsg);
if(rc != SQLITE_OK)
{
std::cout << "SQL Error: " << szErrMsg << std::endl;
sqlite3_free(szErrMsg);
break;
}
else
{
printf("count: %s\n", first.ids);
}
}
This isn't an error regarding sqlite at all, it's just an uninitialised pointer. Let's look at the relevant code:
struct ConnIDs{
vector<int*> *ids;
};
...
ConnIDs first;
rc = sqlite3_exec(db, pSQL2[0], callback, &first, &szErrMsg);
...
static int callback(void *NotUsed, int argc, char **argv, char **szColName)
{
ConnIDs *first=(ConnIDs *)NotUsed;
for(int i = 0; i < argc; i++)
if (strcmp(szColName[i], "ConnID") == 0)
first->ids->push_back(argv[i]);
}
I've omitted unnecessary parts. first is an object of ConnIDs, which is a std::vector<int*>* - it's a pointer to a vector. You pass first into your callback, then immediately try to push into ids; however, you haven't initialised ids, so it's just pointing to rubbish.
The simplest fix is to just not make it a std::vector<int*>* and instead just make it std::vector<int*>, although I'm not certain int* is the correct type here, it will really depend on the data in your database. I would imagine either just int or std::string may be more applicable, but I'll leave that to you:
With the above change, your code will work as-is but you'll need to change first->ids->push_back to first->ids.push_back
Additional notes:
char *pSQL2[1];
pSQL2[0] = "Select * from Subscribers";
rc = sqlite3_exec(db, pSQL2[0], callback, &first, &szErrMsg);
This is kinda weird. I'd probably either just write rc = sqlite3_exec(db, "Select * from Subscribers", ...) or
auto query = "Select * from Subscribers";
rc = sqlite3_exec(db, query.c_str(), callback, &first, &szErrMsg);
I need to return a integer from callback, but I not succeeded.
I tried - but nothing.
I will be very glad if you will help me.
Here is my code:
using namespace std;
int main()
{
sqlite3* db;
char* zErrMsg;
sqlite3_open("try.db", &db);
//do something...
string query = "select * from myTable";
int *ptr;
sqlite3_exec(db, query.c_str(), callback, ptr, &zErrMsg);
cout << ptr << endl;
system ("pause");
return 0;
}
int callback(void* notUsed, int argc, char** argv, char** azCol)
{
/*
chane void* notUsed to int*
???how???
*/
return 0;
}
You have to pass an address of valid memory (e.g. on stack) or allocate it (heap) to the callback function, if you allocate you have to free it also.
The forth argument of the sqlite3_exec() function will be the first argument of the callback() function wich is of type void*. So if you pass the address of an int you have to interpret the void* as an int*.
I changed it so the memory (int someNumber) is in the callers function (main) and pass the address of it. In the callback function you need to cast the void* to the pointer type you expect, here int* and assign a value.
It should be:
...
int main()
{
...
int someNumber;
sqlite3_exec(db, query.c_str(), callback, &someNumber, &zErrMsg);
cout << someNumber << endl;
...
}
int callback(void* someNumberArg, int argc, char** argv, char** azCol)
{
int* someNumber = reinterpret_cast<int*> (someNumberArg);
*someNumber = 42;
return 0;
}
I am rather new to handle C callbacks in C++. I made a sqlite wrapper c++ class, which just calls sqlite3_exec().
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
SqliteAccessor* sqlite = static_cast<SqliteAccessor*> NotUsed;
if(argc > 0) {
sqlite->set_table_exists(true);
}
return 0;
}
class SqliteAccessor{
public:
bool has_table(const string dbName, const string tblName)
{
string sql;
sql = "SELECT " + quote_string(tblName) + "FROM " + quote_string(dbName)
+ "WHERE type = 'table' AND name = " + quote_string(tblName) + ";";
char *zErrMsg = 0;
int rc = sqlite3_exec(m_db, sql.c_str(), callback, (void*) this, &zErrMsg);
if( rc != SQLITE_OK ){
printf("SQL error: %s", zErrMsg);
sqlite3_free(zErrMsg);
}
// anyway to return the result directly?
// return hasTable;
}
// can I avoid the following methods and the member variable?
void set_table_exists(bool isExist) { m_table_exist = isExist; }
bool get_table_exists() { return m_table_exist; }
private:
static bool m_table_exist;
};
int caller(){
SqliteAccessor sqlite;
// to check if table exist
if (sqlite->has_table()){
// will above work or
// I should do with an extra call to query the changed state?
}
}
Now, I am quite confused how the caller can get the result from sqlite wrapper. I think, the caller cannot have the result by simply calling has_table(), because the result is returned from the callback, by set_table_exists(). So shall the caller get the result by making another call, e.g. call sqlite->get_table_exists() ?
Then this implies for every callback, I need to make a member variable (also has to be static) in class SqliteAccessor, and a pair of set/get_state(), which will be very cumbersome.
How to design the class to make it nice to use by caller?
Unfortunately, our code base does not support c++11.
If you are on C++11 consider using a lambda instead of a callback.
class SqliteAccessor{
public:
bool has_table(const string dbName, const string tblName)
{
bool hasTable = false;
string sql;
sql = "SELECT " + quote_string(tblName) + "FROM " + quote_string(dbName)
+ "WHERE type = 'table' AND name = " + quote_string(tblName) + ";";
char *zErrMsg = 0;
int rc = sqlite3_exec(m_db, sql.c_str(), [&](void *NotUsed, int argc, char **argv, char **azColName){
SqliteAccessor* sqlite = static_cast<SqliteAccessor*> NotUsed;
if(argc > 0) {
hasTable = true;
}
}
, (void*) this, &zErrMsg);
if( rc != SQLITE_OK ){
printf("SQL error: %s", zErrMsg);
sqlite3_free(zErrMsg);
}
return hasTable;
}
};
If you don't have access to C++11, you can always manually write your functor. You lose a bit of conciseness and locality though. The nice part is that the functor can save the state you need.
struct callback{
bool operator(void *NotUsed, int argc, char **argv, char **azColName)
{
SqliteAccessor* sqlite = static_cast<SqliteAccessor*> NotUsed;
if(argc > 0) {
hasTable = true;
}
return false;
}
bool hasTable;
};
class SqliteAccessor{
public:
bool has_table(const string dbName, const string tblName)
{
bool hasTable = false;
string sql;
sql = "SELECT " + quote_string(tblName) + "FROM " + quote_string(dbName)
+ "WHERE type = 'table' AND name = " + quote_string(tblName) + ";";
char *zErrMsg = 0;
callback c;
int rc = sqlite3_exec(m_db, sql.c_str(), c, (void*) this, &zErrMsg);
if( rc != SQLITE_OK ){
printf("SQL error: %s", zErrMsg);
sqlite3_free(zErrMsg);
}
return c.hasTable;
}
};
The way I would do it is to make the callback a private static member function and basically do what you did. Like this:
class SqliteAccessor
{
public:
bool has_table(const std::string dbName, const std::string tblName);
private:
static int callback(void *NotUsed, int argc, char **argv, char **azColName);
bool m_hasTable;
};
int SqliteAccessor::callback(void *NotUsed, int argc, char **argv, char **azColName)
{
SqliteAccessor* sqlite = static_cast<SqliteAccessor*>(NotUsed);
if(argc > 0) sqlite->m_hasTable = true;
return 0;
}
bool SqliteAccessor::has_table(const std::string dbName, const std::string tblName)
{
m_hasTable = false;
string sql = "SELECT " + quote_string(tblName) + "FROM " + quote_string(dbName)
+ "WHERE type = 'table' AND name = " + quote_string(tblName) + ";";
char *zErrMsg = 0;
int rc = sqlite3_exec(m_db, sql.c_str(), callback, (void*) this, &zErrMsg);
if( rc != SQLITE_OK )
{
printf("SQL error: %s", zErrMsg);
sqlite3_free(zErrMsg);
}
return m_hasTable;
}
int caller()
{
SqliteAccessor sqlite;
// to check if table exist
if (sqlite.has_table())
{
// do stuff :)
}
}
If sqlite3_exec() does not work with static functions, you can try with a global function like this:
class SqliteAccessor
{
public:
bool has_table(const std::string dbName, const std::string tblName);
private:
bool m_hasTable;
friend int callback(void *NotUsed, int argc, char **argv, char **azColName);
};
int callback(void *NotUsed, int argc, char **argv, char **azColName)
{
SqliteAccessor* sqlite = static_cast<SqliteAccessor*>(NotUsed);
if(argc > 0) sqlite->m_hasTable = true;
return 0;
}
In c++, using sqlite3, a callback function is used to retrieve select results from the database:
rc = sqlite3_exec(db, query, callback, 0, &sqlErrorMsg);
With each record returned from the database this function is called:
static int callback(void *NotUsed, int argc, char **argv, char **azColName) {
int i;
std::cout << "Called\n";
for(i = 0;i < argc;i++) {
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
/** Example **/
//if(last) do something; //to demonstrate that I need access to this information inside of the callback
return 0;
}
I need a way to determine the last call to this function (on the last record of sql).
I assumed it would take some minds more experienced in c++. I'm still somewhat of a novice, so tips are always welcome. Thanks in advance.
Solution (with help from ):
rc = sqlite3_exec(db, sql, callback, (void*)rowCount, &zErrMsg);
Then in the callback
static callback(void* rowCount, int argc, char** argv, char** azColName) { //here the integer is converted to hex, but converting it is easy enough
}
I'm trying to do it
class Foo
{
static int ReadSelfFromBase(void *userarg, int argc, char **argv, char **ColName){...}
public:
void Bar(sqlite3* db)
{
...
rc = sqlite3_exec(db, "select * from test", &ReadSelfFromBase, this, &zErrMsg);
...
}
}
int main()
{
Foo test;
...
test.Bar(db);
}
But callback doesn't call. If a do this
int main()
{
rc = sqlite3_exec(db, "select * from test", Foo::ReadSelfFromBase, NULL, &zErrMsg);
}
it all well. Does anybody know how solve this problem
PS Sorry for bad English
Since ReadSelfFromBase is a static function, Foo::ReadSelfFromBase should work the same in the Bar method as it does in main.
it's better to use Foo::ReadSelfFromBase any where you want, you know, it's static.