Determine last invocation of callback - c++

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
}

Related

How do I store into a C++ variables using sqlite3?

I'm new in the world of C++.
I'm trying to store into a variable a value contained in a sqlite table that I've created but I don't know how to do (I research a lot befor asking here).
So, after I open the DB connection I execute this:
char* sql = new char[4096];
strcpy(sql, statement.c_str());
/* Execute SQL statement */
int rc = sqlite3_exec(DB, sql, callback, 0, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL ERROR: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
} else {
fprintf(stdout, "STATEMENT:\n\n%s\n\nEXECUTED SUCCESSFULLY!\n\n", statement.c_str());
}
And I get this:
OPENED DATABASE SUCCESSFULLY
sent = 0
sent = 0
sent = 0
sent = 0
sent = 0
sent = 1
sent = 1
sent = 1
STATEMENT:
SELECT sent FROM Message;
EXECUTED SUCCESSFULLY!
What I want to do is to store the value contained in "sent" (the datatype in the db is boolean) in a int variables that I can manipulate to check some condition. Or maybe to store all the values into a int array.
How can I do? Please help me!
Thanks a lot!
EDIT:
I'm using sqlite3 library.
And this is my callback function:
static int callback(void *NotUsed, int argc, char **argv, char **azColName) {
int i;
for(i = 0; i<argc; i++) {
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
Don't use sqlite3_exec() for anything that needs to do anything with the results of a query, or anything that involves user-supplied values. Use a prepared statement.
Something like
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(DB, statement.c_str(), statement.length(), &stmt, nullptr);
if (rc != SQLITE_OK) {
// handle the error
}
// Loop through the results, a row at a time.
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
int sent = sqlite3_column_int(stmt, 0);
// etc.
}
// Free the statement when done.
sqlite3_finalize(stmt);
callback is a function called for each row of the result set. You can assign the values to an array or vector in that function. https://www.sqlite.org/c3ref/exec.html
The 2nd argument to the sqlite3_exec() callback function is the number
of columns in the result. The 3rd argument to the sqlite3_exec()
callback is an array of pointers to strings obtained as if from
sqlite3_column_text(), one for each column. If an element of a result
row is NULL then the corresponding string pointer for the
sqlite3_exec() callback is a NULL pointer. The 4th argument to the
sqlite3_exec() callback is an array of pointers to strings where each
entry represents the name of corresponding result column as obtained
from sqlite3_column_name().
You need something like:
int callback(void *p, int size, char **column_text, char **column_name) {
if (size == 0) return -1;
auto &container = *static_cast<std::vector<std::string>*>(p);
if (!column_text[0]) container.push_back("NULL");
else container.push_back(column_text[0]);
return 0;
}
and then you can store the values in your container with:
std::vector<std::string> container;
/* Execute SQL statement */
int rc = sqlite3_exec(DB, statement.c_str(), callback, &container, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL ERROR: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
} else {
fprintf(stdout, "STATEMENT:\n\n%s\n\nEXECUTED SUCCESSFULLY!\n\n", statement.c_str());
}

Retrieve and store data from sqlite to array c/c++

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);

sqlite3 C++ how sto assign SELECT data to a variable for later use?

I'm making a simple C++ application that is supposed to take some int ID's from sqlite3 database, store them in array for later use. From what I've read, I MUST use the callback function in order to do so. The problem is, I don't know how to proceed after that.
This is the most common example of the sqlite3 callback function I keep finding:
static int callback(void *data, int argc, char **argv, char **azColName){
int i;
fprintf(stderr, "%s: ", (const char*)data);
for(i = 0; i<argc; i++){
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
What I would like to do, is to not simply print out the data but to return it into the main function and assign to a variable for later use.
Would appreciate if anyone provided an example of how to properly do so.

sqlite3 change in the func callback the parameter void* notUsed to int* C++

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;
}

Using sqlite3 in visual c++

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 );