Retrieve and store data from sqlite to array c/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);

Related

Storing public keys in database (C++)

I am trying to store the public key (PK) and signature (generated by crypto++ library) to sqlite database. I first encoded the keys as:
pk[node].BEREncode(CryptoPP::StringSink(pkstring).Ref());
and then store them in the database. But as the PK and signature have special characteres, they are not stored correctly into the database. What I used for storing is:
char * PK = (char*) malloc (BC.trans[l].PK.length()+1); //use malloc to manually manage the memory
std::strcpy(PK,BC.trans[l].PK.c_str());
char *zSQL = sqlite3_mprintf("INSERT INTO BC (PK VALUES ('%q');", PK);
rc = sqlite3_exec(db, zSQL, callback, (void*)data, &zErrMsg);// executes the command in sqlite and returns the status (whether stroing was successful or not.
free(PK);
The string should be copied to the char, and the issue happens exactly here in copying the content into the char. I think its because the string has special characters. For hash I have the same follow but it works perfectly fine. Only for PK and signature. I used memcpy and strncpy as well. Nothing works for this and still the keys are not stored correctly in the database.
Any thoughts?
I've updated with the full code. Now I can store the PK and its seems to be fine, but when I ask the database to remove a bunch of records, nothing happens. That means something is wrong again.
Here is the code:
int Network_Nodes =10;
int Block_Size=10;
int BC_lenght=0;
int Fin_BC_size =50;
std::vector<CryptoPP::RSA::PrivateKey> prk;
std::vector<CryptoPP::RSA::PublicKey> pk;
std::vector<std::string> prev_t;
struct Block {
std::string block_hash;
std::string block_num;
struct transactions {
std::string TransactionID;
std::string previousTransactionID;
std::string PK;
std::string Sign;
};
std::vector<transactions> trans;
} BC;
int generatekey()
{
for (int i=0;i<Network_Nodes;i++)
{
CryptoPP::AutoSeededRandomPool rng;
CryptoPP::InvertibleRSAFunction param;
param.GenerateRandomWithKeySize(rng,3072);
CryptoPP::RSA::PrivateKey privatekey(param);
CryptoPP::RSA::PublicKey publickey (param);
prk.push_back(privatekey);
pk.push_back(publickey);
}
return 0;
}
///////////////////////////////////////////////////////////////
void initialization()
{
for (int i=0;i<=Network_Nodes;i++)
{
prev_t.push_back("NULL");
}
//Creating database
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char *sql;
const char* data = "Callback function called";
/* Open database */
rc = sqlite3_open("RemovableBC.db", &db);
if( rc ) {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
return;
} else {
// fprintf(stdout, "Opened database successfully\n");
}
sql = "DROP TABLE BC";
rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
/* Create a table in the data base to be used for storing data. Create SQL statement */
sql = "CREATE TABLE BC(" \
"T_ID TEXT ," \
"P_T_ID TEXT ," \
"PK BLOB ," \
"Signature BLOB ," \
"Block_ID TEXT );";
/* Execute SQL statement */
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, "Table created successfully\n");
}
sqlite3_close(db);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
void fill_the_block(std::string block_content)
{
const char* data = "Callback function called";
SHA256 hash;
string digest;
sqlite3 *db=NULL;
char *sql;
char *zErrMsg = 0;
int rc;
char sqlStr[2000];
/* Open database */
rc = sqlite3_open("RemovableBC.db", &db);
if( rc ) {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
return;
} else {
// fprintf(stdout, "Opened database successfully\n");
}
StringSource s(block_content, true, new HashFilter(hash, new HexEncoder(new StringSink(digest))));
BC.block_hash=digest;
for (int l=0 ; l<Block_Size ; l++)
{
char *begin = sqlStr;
char *end = begin + sizeof(sqlStr);
std::fill(begin, end, 0);
char *zSQL = sqlite3_mprintf("INSERT INTO BC ( T_ID , P_T_ID , PK , Signature , Block_ID ) VALUES ('%q','%q','%q','%q','%q');", BC.trans[l].TransactionID.c_str() ,BC.trans[l].previousTransactionID.c_str() ,BC.trans[l].PK.c_str() ,BC.trans[l].Sign.c_str(),BC.block_hash.c_str());
rc = sqlite3_exec(db, zSQL, callback, (void*)data, &zErrMsg);
sqlite3_free(zSQL);
if( rc != SQLITE_OK ) {
fprintf(stderr, "SQL error in populating : %s\n", zErrMsg);
sqlite3_free(zErrMsg);
} else {
}
sqlite3_close(db); //We close the connection we have with the database
}
///////////////////////////////////////////////////////////////////////////
void populate_bc ()
{
int generated_blocks=0;
int stored_trans_in_block=0;
int node=0;
std::string block_content,trans_cont;
std::string pkstring;
std::string signature;
std::string mes ="This message is going to be singed";
while (BC_lenght <=Fin_BC_size )
{
if (generated_blocks <= 10){
if (node >= Network_Nodes)
{
node=0; //cout << "step 4" <<endl;
}
if (stored_trans_in_block >= Block_Size)
{
cout << "block size is "<< BC_lenght<<endl;
fill_the_block(block_content);
BC_lenght++;
block_content.clear();
stored_trans_in_block=0;
for(int o=0; o<stored_trans_in_block;o++)
{
BC.trans[o] = {};
}
BC.trans = {};
BC ={};
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (prev_t[node]=="NULL")
{
// cout << "We are populating on behafe of "<< node<< endl;
trans_cont="";
BC.trans.push_back(Block::transactions());
BC.trans[stored_trans_in_block].previousTransactionID ="NULL";
// byte public_key[] = pk[node];
std::string endoced_pub;
Base64Encoder pubKeySink(new StringSink(endoced_pub));
pk[node].DEREncode(pubKeySink);
pk[node].BEREncode(CryptoPP::StringSink(pkstring).Ref());
BC.trans[stored_trans_in_block].PK=endoced_pub;
CryptoPP::AutoSeededRandomPool rng;
CryptoPP::RSASSA_PKCS1v15_SHA_Signer signer(prk[node]);
CryptoPP::StringSource ss1(mes, true,
new CryptoPP::SignerFilter(rng, signer,
new CryptoPP::StringSink(signature)
) // SignerFilter
); // StringSource
// cout << "step 1" <<endl;
BC.trans[stored_trans_in_block].Sign=signature;
trans_cont = "NULL" + pkstring + signature;
SHA256 hash;
string digest;
StringSource s(trans_cont, true, new HashFilter(hash, new HexEncoder(new StringSink(digest))));
// cout << "step 2" <<endl;
BC.trans[stored_trans_in_block].TransactionID=digest;
prev_t[node] =digest; // This keeps the previous transaction of each node in an array and thus we can later use to populate the BC
block_content+=digest; // This is to calculate the ID of the block which is the hash of all TIDs (hash of hash of all trnasctions)
node++;
stored_trans_in_block++;
// cout << "step 3" <<endl;
}//end of if (prev_t[node]=="NULL")
else
{// cout << "step 6" <<endl;
trans_cont="";
BC.trans.push_back(Block::transactions());
BC.trans[stored_trans_in_block].previousTransactionID =prev_t[node];
std::string endoced_pub;
Base64Encoder pubKeySink(new StringSink(endoced_pub));
pk[node].DEREncode(pubKeySink);
// pubKeySink.MessageEnd();
// pk[node].BEREncode(CryptoPP::StringSink(pkstring).Ref());
BC.trans[stored_trans_in_block].PK = endoced_pub;
// BC.trans[stored_trans_in_block].PK= pk[node];
CryptoPP::AutoSeededRandomPool rng;
CryptoPP::RSASSA_PKCS1v15_SHA_Signer signer(prk[node]);
CryptoPP::StringSource ss1(mes, true,
new CryptoPP::SignerFilter(rng, signer,
new CryptoPP::StringSink(signature)
) // SignerFilter
); // StringSource
BC.trans[stored_trans_in_block].Sign=signature;
trans_cont = prev_t[node] + pkstring + signature;
SHA256 hash;
string digest;
StringSource s(trans_cont, true, new HashFilter(hash, new HexEncoder(new StringSink(digest))));
BC.trans[stored_trans_in_block].TransactionID=digest;
prev_t[node] =digest;
block_content+=digest;
node++;
stored_trans_in_block++;
}
generated_blocks++;
}
else
{
generated_blocks=0;
}
}
}
//////////////////////////////////////////////////////////////////////////////////////
void remove_node (int i)
{
std::string search_node; //This is the ID of the transaction that we need to search for in the BC,
sqlite3 *db;
std::string endoced_pub;
Base64Encoder pubKeySink(new StringSink(endoced_pub));
pk[i].DEREncode(pubKeySink);
// pubKeySink.MessageEnd();
char *sql;
int rc;
char *zErrMsg = 0;
const char* data = "Callback function called";
/* Open database */
rc = sqlite3_open("RemovableBC.db", &db);
if( rc ) {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
return;
} else {
// fprintf(stderr, "Opened database successfully\n");
}
/* Execute SQL statement */
// char *zSQL = sqlite3_mprintf("DELETE from BC");
char * Search_NODE = (char*) malloc (endoced_pub.length()+1);
std::strcpy(Search_NODE,endoced_pub.c_str());
std::strcpy(Search_NODE,search_node.c_str());
// char *zSQL = sqlite3_mprintf("DELETE from BC where PK = '%q';", Search_NODE);
char *zSQL = sqlite3_mprintf("UPDATE BC set Signature = null and PK = null where PK = '%q';", endoced_pub.c_str());
rc = sqlite3_exec(db, zSQL, callback, (void*)data, &zErrMsg);
cout<< endoced_pub.c_str()<<endl;
if( rc != SQLITE_OK ) {
fprintf(stderr, "SQL error in removing a record: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
} else {
// fprintf(stdout, "Operation done successfully\n");
}
sqlite3_close(db);
free(Search_NODE);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main() {
auto initial = std::chrono::high_resolution_clock::now();
generatekey();
cout << "Keys are generated for " <<Network_Nodes << " nodes..." << endl;
clock_t begin_block_pup = clock();
initialization();
cout << "Initializing previous transaction vector..." << endl;
//clock_t ti =clock();
//double time = double (ti)/CLOCKS_PER_SEC;
clock_t ti2 =clock();
double time2 = double (ti2)/CLOCKS_PER_SEC;
//cout << "second time is " << done <<endl;
populate_bc();
cout << "BC has been populated with "<< BC_lenght <<" blocks..." << endl;
return 0;
}
The problem with your system, is that you need to store the PK data as either a BLOB or encode it into 7 bit ASCII.
Sqlite has some internationalization support, and may convert raw binary data stored as a string into a different form. (e.g. UTF-8 conversion)
So either use a blob as in the answer to this question SO : sqlite blob,
or first convert the bytes to 7 bit ascii (e.g. b64 encode), then store the data.
Remembering you would need to b64 decode the results afterwards.

sqlite3_prepare_v2 returning error 1 code

I wanted to clean up my sql insert function and use prepared statements instead of a hacked string within sqlite3_exec. I keep getting issues trying to use it. Here is the code:
void Database::insert(char* tableName,int time1,int x,int y,int z)
{
int i;
i = sqlite3_prepare_v2(db, "insert into ?1 values(?2, ?3, ?4, ?5);", -1, &stmt, NULL);
sqlite3_bind_text(stmt, 1, tableName, -1, SQLITE_STATIC);
std::cout <<i<< std::endl;
sqlite3_bind_int(stmt, 2, time1);
std::cout <<"made it int1"<< std::endl;
sqlite3_bind_int(stmt, 3, x);
std::cout <<"made it int2"<< std::endl;
sqlite3_bind_int(stmt, 4, y);
std::cout <<"made it int3"<< std::endl;
sqlite3_bind_int(stmt, 5, z);
rc = sqlite3_step(stmt);
if (rc != SQLITE_OK) {
std::cout << "SQL error: "<< errMsg << std::endl;
} else {
std::cout << "insert successfully" << std::endl;
}
std::cout << "boom2"<< std::endl;
sqlite3_finalize(stmt);
}
database.h file:
#ifndef DATABASE_H
#define DATABASE_H
#include <sqlite3.h>
#include <iostream>
#include <stdio.h>
class Database
{
public:
Database(char* name);
~Database();
int openConnection(char* name);
void insert(char* table, int vTime, int x, int y, int z);
void closeConnection();
void createTable(char* dbName);
void getData(char* table, int time1);
private:
sqlite3* db;
sqlite3_stmt *stmt;
char *errMsg;
int rc;
char* dbName;
std::string sqlStatement;
const char* sql;
};
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;
}
#endif // DATABASE_H
When I run this code, I get a seg fault 11 when trying to insert something into the provided table. I get errors related to prepare returning 1 and rc being code 21 (SQL_MISUSE). My question is what is wrong with my prepared statement?
You get the SQL_MISUSE error because you tried to use a prepared statement that did not exist.
The prepare failed because you tried to use a parameter for a table name. Parameters work only for literal values in expressions, not for table/column names.

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

how to get result which is returned with C callback in C++

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

Can I use for loop insert SQL?

#include <iostream>
#include "libpq-fe.h"
using namespace std;
void CloseConn(PGconn *conn)
{
PQfinish(conn);
getchar();
}
PGconn *ConnectDB()
{
PGconn *conn = NULL;
// Make a connection to the database
conn = PQconnectdb("user=postgres password=password dbname=postgres hostaddr=192.168.xxx.xxx port=5432");
// Check to see that the backend connection was successfully made
if (PQstatus(conn) != CONNECTION_OK)
{
cout << "Connection to database failed.\n";
CloseConn(conn);
}
cout << "Connection to database - OK\n";
return conn;
}
void InsertEmployeeRec(PGconn *conn)
{
int nFields;
// Append the SQL statment
std::string sSQL;
// problem start-------------------------
for(int i=0;i<10;i++)
{
sSQL.append("INSERT INTO test(lat,lng) VALUES (i,20)");
}
//problem end----------------------------
// Execute with sql statement
PGresult *res = PQexec(conn, sSQL.c_str());
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
cout << "Insert test record failed\n";
PQclear(res);
CloseConn(conn);
}
cout << "Insert test record - OK";
// Clear result
PQclear(res);
}
int main(int argc, char *argv[ ])
{
PGconn *conn = NULL;
conn = ConnectDB();
if (conn != NULL)
{
InsertEmployeeRec(conn);
CloseConn(conn);
}
return 0;
}
and in terminal
alan#alan-virtual-machine:~/文件$ g++ ex6.cpp -I /usr/include/postgresql -l pq -o ex6
alan#alan-virtual-machine:~/文件$ ./ex6
Connection to database - OK
Insert test record failed
*** Error in `./ex6': corrupted double-linked list: 0x08eadad0 ***
But if I remove for loop and modify
INSERT INTO test(lat,lng) VALUES (i,20)
to
INSERT INTO test(lat,lng) VALUES (20,20)
it can work.
Linux Ubuntu 13.04 g++ compiler
I refer to http://www.askyb.com/cpp/c-postgresql-example/
The problem resides in the fact that 'i' is not been evaluated inside the string. To solve that, you can create the string with correct value and send it to the insert command.
for(int i=0;i<10;i++)
{
char buffer[256];
snprintf(buffer, 256, "INSERT INTO test(lat,lng) VALUES (%d,20)", i);
sSQL.append(buffer);
}
Of course, you need to adjust your buffer adequately
The problem is that you're not sending i. It looks like PQexecParams is the function you want:
PGresult *PQexecParams(PGconn *conn,
const char *command,
int nParams,
const Oid *paramTypes,
const char * const *paramValues,
const int *paramLengths,
const int *paramFormats,
int resultFormat);