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.
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'm making a cocos2dx (c++) android game and I'm trying to implement SQLite but I can't even create a table!
Here's the function where i open database and create a table inside:
void HelloWorld::initDB() {
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
std::string wpath = FileUtils::getInstance()->getWritablePath() + "save.db";
FILE *f = fopen(wpath.c_str(), "r");
if (f == NULL) {
firstLogin = true;
} else {
firstLogin = false;
}
fclose(f);
#endif
int result;
result = sqlite3_open(wpath.c_str(), &db);
if (result != SQLITE_OK) {
CCLOG("open database failed, number %d", result);
}
if(firstLogin) {
sql_query("CREATE TABLE IF NOT EXISTS data(variable, value)");
insertVariableInt("coins", 0);
insertVariableInt("timesPlayed", 0);
insertVariableInt("highScore", 0);
}
}
And here is my sql_query() function:
int HelloWorld::sql_query(const char * query,int (*callback)(void*,int,char**,char**), void* data)
{
char* errMsg = 0;
int result = sqlite3_exec(db, query, callback, data, &errMsg);
if (errMsg) {
CCLOG("SQLite3: %s", errMsg);
sqlite3_free(errMsg);
}
return result;
}
When I run my game, save.db file is created but there's no table inside, it's EMPTY! (0 bytes). And it gives me NO errors, it gives me just an empty save.db file.
How can I solve this problem? THANKS!
I tested your code and I could create the data table.
SQLite version 3.16.2 2017-01-06 16:32:41
Enter ".help" for usage hints.
sqlite> .tables
data
I see you're calling sql_query with only one parameter. Did you overload that method or did you define default argument values? Anyway here's the code I use. Note that you can call isFileExist instead of fopen.
MainMenu::MainMenu() {
std::string wpath = FileUtils::getInstance()->getWritablePath() + "save.db";
bool firstLogin = FileUtils::getInstance()->isFileExist(wpath);
int result = sqlite3_open(wpath.c_str(), &db);
if (result != SQLITE_OK) {
CCLOG("open database failed, number %d", result);
}
if(firstLogin) {
sql_query("CREATE TABLE IF NOT EXISTS data(variable, value)", nullptr, nullptr);
}
}
int MainMenu::sql_query(const char * query,int (*callback)(void*,int,char**,char**), void* data)
{
char* errMsg = 0;
int result = sqlite3_exec(db, query, callback, data, &errMsg);
if (errMsg) {
CCLOG("SQLite3: %s", errMsg);
sqlite3_free(errMsg);
}
return result;
}
I am implementing a function that receives any SQL statement and then executes it.
void dbExec(std::string str, bool vertical)
{
sqlite3 *db; // Create db object
char *zErrMsg = 0;
int rc;
const char *sql = str.c_str(); // Convert string to char
sqlite3_stmt *stmt = NULL; // SQL statement
/* Open Database */
rc = sqlite3_open("db/survey.db",&db);
if (rc)
{
fprintf(stderr, "DBOPEN_ERR: %s\n", sqlite3_errmsg(db));
}
/* Execute SQL statement */
rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); // Prepare statement
if (rc != SQLITE_OK )
{ // Check error
fprintf(stderr, "DB error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
int cols = sqlite3_column_count(stmt); // Number of columns
const char *data = NULL; // data char pointer
if (vertical)
{
sqlite3_step( stmt );
for (int i = 0; i < cols; i++)
{
// Print column name and info
data = (const char*)sqlite3_column_text( stmt, i );
std::cout << std::setw(20) << sqlite3_column_name(stmt,i)
<< std::setw(30) << (data ? data : "[NULL]" );
printf("\n");
}
}
else
{
for (int i = 0; i < cols; i++)
{
// Print column name
std::cout << std::setw(15) << sqlite3_column_name(stmt,i);
}
printf("\n");
while ( sqlite3_step( stmt ) == SQLITE_ROW )
{
// print each row
for (int i = 0; i < cols; i++)
{
data = (const char*)sqlite3_column_text( stmt, i );
std::cout << std::setw(15) << (data ? data : "[NULL]" );
}
printf("\n");
}
}
/* Close Database */
sqlite3_close(db);
}
When the str argument is:
SELECT * FROM TABLE
it works perfect. If the str argument is:
INSERT INTO TABLE (COL1) VALUES(100)
it doesn't work.
However, if inside of the function I add the following line:
str = "INSERT INTO TABLE (COL1) VALUES(100)";
it works perfect. I tried many things but I still can't figure out what's going on... Any ideas?
Thanks!
EDIT:
The function dbExec is being called in this way:
void addBorehole()
{
std::string statement;
statement = "INSERT INTO BOREHOLE (TOTAL_DEPTH) VALUES (45)";
dbExec(statement, false);
}
OK, the problem was solved by writing the following line before closing the database:
sqlite3_finalize( stmt );
Info: https://sqlite.org/c3ref/close.html
If the database connection is associated with unfinalized prepared
statements or unfinished sqlite3_backup objects then sqlite3_close()
will leave the database connection open and return SQLITE_BUSY.
However, I still didn't get why it worked when I hardcoded the statement inside of the function.
Thank you!
Your problem is that the database is busy (SQLITE_BUSY). The documentation sais:
[...] SQLITE_BUSY indicates a conflict with a separate database connection, probably in a separate process [...]
So there must be a process that is blocking your database.
To get the process which is blocking the database you can do the following (Copied from the Stack Exchange network).
Linux:
$ fuser development.db
This command will show what process is locking the file:
> development.db: 5430
Just kill the process...
kill -9 5430
Windows:
PowerShell method:
IF((Test-Path -Path $FileOrFolderPath) -eq $false) {
Write-Warning "File or directory does not exist."
}
Else {
$LockingProcess = CMD /C "openfiles /query /fo table | find /I ""$FileOrFolderPath"""
Write-Host $LockingProcess
}
More details How to find out which process is locking a file or folder in Windows
The other method for Windows would be to use the ProcessExplorer.
I'm having great difficulty to find a working example on the net regarding getting multiple values from a SQlite DB using xcode and cocos2dx. Here is the sql query I have:
char sql_query[100];
sprintf(sql_query, "SELECT * FROM SQList WHERE ColumnD BETWEEN %d AND %d ORDER BY RANDOM() LIMIT 1", MinColumnD, MaxColumnD);
The query it self seems to work, the main problem is how do I get the values that I collect from 'select *' into another int or char parameter so that I can use it?
Some example I found referred to using a callback to a struct or mentioned about using sqlite3_prepare_v2 and the step method.
I'm unable to find an example for either methods though, please help!
When using sqlite3_exec, you have to convert all values from strings, and you have to use the callback's void * pointer or some global variable to return data:
struct MyData {
string A;
int B, C;
};
int exec_callback(void *ptr, int argc, char *argv[], char *names[])
{
vector<MyData> *list = reinterpret_cast<vector<MyData> *>(ptr);
MyData d;
d.A = argv[0] ? argv[0] : "";
d.B = atoi(argv[1]);
d.C = atoi(argv[2]);
list->push_back(d);
return 0;
}
void query_with_exec()
{
vector<MyData> list;
char *errmsg = NULL;
sqlite3_exec(db, "SELECT a, b, c FROM SQList /* WHERE ... */",
exec_callback, &list, &errmsg);
if (errmsg) {
printf("error: %s!\n", errmsg);
return;
}
// use list ...
}
When using sqlite3_prepare*, you have to call sqlite3_step in a loop until it does not return SQLITE_ROW anymore (when you expect only one record, you can call it only once):
void query_with_step()
{
vector<MyData> list;
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, "SELECT a, b, c FROM SQList /* WHERE ... */",
-1, &stmt, NULL);
if (rc != SQLITE_OK) {
printf("error: %s!\n", sqlite3_errmsg(db));
return;
}
for (;;) {
rc = sqlite3_step(stmt);
if (rc == SQLITE_DONE)
break;
if (rc != SQLITE_ROW) {
printf("error: %s!\n", sqlite3_errmsg(db));
break;
}
MyData d;
const char *text = (const char *)sqlite3_column_text(stmt, 0);
d.A = text ? text : "";
d.B = sqlite3_column_int(stmt, 1);
d.C = sqlite3_column_int(stmt, 2);
list.push_back(d);
}
sqlite3_finalize(stmt);
// use list ...
}
Get the values using "SELECT" query and store your char and int values in an array.Create a NSMUtableArray and store the values which you will get from SELECT query .The following code will help you
-(int)find_putts_count:(int)holeno{
sqlite3 *database;
NSString *databasePath;
NSMUtableArray *arr_tracking_details = [[NSMUtableArray alloc] init];
int putts = -1;
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:#"GolfElite.sqlite"];
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK)
{
// Setup the SQL Statement and compile it for faster access
NSString *sqlStatement = nil;
sqlStatement = [NSString stringWithFormat:#"select Putts from Holes WHERE HoleNo == %d and ShotNo == %d and PlayerId == '%#'",holeno,1,[arr_players_id objectAtIndex:scorecard_player_no]];
sqlite3_stmt *compiledStatement;
if(sqlite3_prepare_v2(database, [sqlStatement UTF8String], -1, &compiledStatement, NULL) == SQLITE_OK)
{
if(sqlite3_step(compiledStatement) == SQLITE_ROW)
{
[arr_tracking_details addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement, 3)]];
[arr_tracking_details addObject:[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement,6)]];
[arr_tracking_details addObject:[NSString stringWithFormat:#"%d",(int)sqlite3_column_int(compiledStatement, 4)]];
putts = (int)sqlite3_column_int(compiledStatement, 0);
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
return putts;
}
I decided to use SQLite as it allows to store database into a single file. I think I have managed to do a database with SQLite Database Browser.
How can I read that data in a C/C++ program?
A example using sqlite read:
#include <stdio.h>
#include <sqlite3.h>
#include <string.h>
int main(int argc, char** argv)
{
const char* username = "satyam";
char q[999];
sqlite3* db;
sqlite3_stmt* stmt;
int row = 0;
int bytes;
const unsigned char* text;
if (2 == argc) {
username = argv[1];
}
q[sizeof q - 1] = '\0';
snprintf(
q,
sizeof q - 1,
"SELECT ipaddr FROM items WHERE username = '%s'",
username
);
if (sqlite3_open ("test.db", &db) != SQLITE_OK) {
fprintf(stderr, "Error opening database.\n");
return 2;
}
printf("Query: %s\n", q);
sqlite3_prepare(db, q, sizeof q, &stmt, NULL);
bool done = false;
while (!done) {
printf("In select while\n");
switch (sqlite3_step (stmt)) {
case SQLITE_ROW:
bytes = sqlite3_column_bytes(stmt, 0);
text = sqlite3_column_text(stmt, 1);
printf ("count %d: %s (%d bytes)\n", row, text, bytes);
row++;
break;
case SQLITE_DONE:
done = true;
break;
default:
fprintf(stderr, "Failed.\n");
return 1;
}
}
sqlite3_finalize(stmt);
return 0;
}
How about the 'An Introduction to Sqlite C/C++ Interface', and there is a whole C++ example here on CodeProject.
This is bits of the more full sample,
#include "CppSQLite.h"
#include <ctime>
#include <iostream>
using namespace std;
const char* gszFile = "C:\\test.db";
int main(int argc, char** argv)
{
try
{
int i, fld;
time_t tmStart, tmEnd;
CppSQLiteDB db;
cout << "SQLite Version: " << db.SQLiteVersion() << endl;
db.open(gszFile);
cout << db.execScalar("select count(*) from emp;")
<< " rows in emp table in ";
db.Close();
}
catch (CppSQLiteException& e)
{
cerr << e.errorCode() << ":" << e.errorMessage() << endl;
}
}
One way to do it without additional wrappers
#include <stdio.h>
#include <string>
using std::string;
#include <sstream>
using std::stringstream;
#include "sqlite3.h"
bool find_employee(int _id)
{
bool found = false;
sqlite3* db;
sqlite3_stmt* stmt;
stringstream ss;
// create sql statement string
// if _id is not 0, search for id, otherwise print all IDs
// this can also be achieved with the default sqlite3_bind* utilities
if(_id) { ss << "select * from employees where id = " << _id << ";"; }
else { ss << "select * from employees;"; }
string sql(ss.str());
//the resulting sql statement
printf("sql: %s\n", sql.c_str());
//get link to database object
if(sqlite3_open("data/test.db", &db) != SQLITE_OK) {
printf("ERROR: can't open database: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return found;
}
// compile sql statement to binary
if(sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, NULL) != SQLITE_OK) {
printf("ERROR: while compiling sql: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
sqlite3_finalize(stmt);
return found;
}
// execute sql statement, and while there are rows returned, print ID
int ret_code = 0;
while((ret_code = sqlite3_step(stmt)) == SQLITE_ROW) {
printf("TEST: ID = %d\n", sqlite3_column_int(stmt, 0));
found = true;
}
if(ret_code != SQLITE_DONE) {
//this error handling could be done better, but it works
printf("ERROR: while performing sql: %s\n", sqlite3_errmsg(db));
printf("ret_code = %d\n", ret_code);
}
printf("entry %s\n", found ? "found" : "not found");
//release resources
sqlite3_finalize(stmt);
sqlite3_close(db);
return found;
}