In my program I need to connect to sqlite db from string.
I receive the sql db (UTF-8) as string from the user, I'm using the sqlite3_open function that receives file path of the db file so I'm creating a file, write the string to it and using it to connect to the db:
sqlite3*
SQLiteUtils::ConnectToDatabase(std::string const& dbStr)
{
sqlite3* db;
std::ofstream dst("sql.db", std::ios::binary);
dst << dbStr;
int const ret = sqlite3_open("sql.db", &db);
if (SQLITE_OK != ret) {
LOG_ERROR("Can't open database: " + std::string(sqlite3_errmsg(db)));
CloseConnectionToDatabase(db);
return nullptr;
}
return db;
}
Is there a way to connect to string without writing the string to file and connect to the file?
Thanks to #Shawn in the comments I used sqlite3_serialize() and sqlite3_deserialize().
This solution work for me:
const char* IN_MEMORY_DB = ":memory:";
sqlite3* ImportDatabase(const std::string &dbStr)
{
sqlite3 *db;
int ret = sqlite3_open(IN_MEMORY_DB, &db);
if (SQLITE_OK != ret)
{
return nullptr;
}
// give serialized buffer ownership to SQLite
unsigned int flags = SQLITE_DESERIALIZE_FREEONCLOSE|SQLITE_DESERIALIZE_RESIZEABLE;
// allocate the serialized buffer from heap, SQLite requires to dynamic allocation for deserialize to work correctly
unsigned char* data = static_cast<unsigned char*>(sqlite3_malloc(dbStr.size()));
if (nullptr == data)
{
sqlite3_close(db);
return nullptr;
}
for (int i = 0; i < dbStr.size(); ++i)
{
data[i] = static_cast<unsigned char>(dbStr[i]);
}
int err = sqlite3_deserialize(db, "main", data, dbStr.size(), dbStr.size(), flags);
if (err != SQLITE_OK)
{
sqlite3_close(db);
return nullptr;
}
return db;
}
In this solution I allocate the sql memory and copy the string to it without writing the data string to file in the middle.
How to connect to sqlite3 db from string
The default behaviour of sqlite3_open is to open/create the db, and so the only thing you need to do is:
int const ret = sqlite3_open(dbStr.c_str(), &db);
// ^^^^^^^^^^^^^
Related
I have a function:
int main()
{
MySQL::Connect("127.0.0.1", 3306, "root", "", "player");
MySQL::ExecuteQuery("select * from player");
while (row = mysql_fetch_row(res))
{
std::cout << row[2] << "\n";
MySQL::SetDatabase("account");
MySQL::ExecuteQuery("select * from account"); // This function causes a problem.
// while (row = mysql_fetch_row(res))
// break;
}
return 0;
}
Which should get everything of player names from player table what it does and what it display in console (I'm posting a screenshot of table in Navicat):
https://i.stack.imgur.com/n6HJQ.png
However, when MySQL::ExecuteQuery("select * from account"); function is used which selects everything in account table, the earlier std::cout display only one player name instead of two:
https://i.stack.imgur.com/q9ZkP.png
What can I do in this situation? Or is there another simple way to connect to MySQL in C++? Please help.
I attach files such as MySQL_Func.cpp and MySQL_Func.h which include problematic function:
.cpp:
#include "MySQL_Func.h"
#include "../Log.hpp"
MYSQL* conn;
MYSQL_ROW row;
MYSQL_RES* res;
std::string conf_ip;
unsigned int conf_port;
std::string conf_db;
std::string conf_login;
std::string conf_password;
std::string error = mysql_error(conn);
int err = 0;
namespace MySQL
{
void Connect(std::string ip, unsigned int port, std::string login, std::string password, std::string db)
{
conf_ip = ip;
conf_port = port;
conf_login = login;
conf_password = password;
conf_db = db;
if (conn != 0)
{
SendLog(0, "MySQL has been restared.");
mysql_close(conn);
}
conn = mysql_init(0);
if (!mysql_real_connect(conn, ip.c_str(), login.c_str(), password.c_str(), db.c_str(), port, NULL, 0))
{
error = mysql_error(conn);
SendLog(1, "Connection with database was failed: " + error + ".");
exit(1);
}
else
{
SendLog(0, "Successfully connected with database!");
}
}
void ExecuteQuery(std::string query)
{
err = mysql_query(conn, query.c_str());
res = mysql_store_result(conn);
if (res != 0) // Protection against NullPointer.
{
int total_rows = mysql_num_fields(res);
if (total_rows != 0) // If total rows isn't 0.
{
if (err)
{
error = mysql_error(conn);
SendLog(1, "Query execute failed:" + error + ".");
mysql_free_result(res);
exit(1);
}
else
{
SendLog(0, "Query has been sent (" + query + ")!");
}
}
else
{
SendLog(1, "Query has been sent: (" + query + ") but its value is 0.");
exit(0);
}
}
else
{
exit(1);
}
}
void SetDatabase(std::string current_db)
{
if (current_db != conf_db) // If current_db isn't conf_db.
MySQL::Connect(conf_ip, conf_port, conf_login, conf_password, current_db);
}
}
.h:
#pragma once
#include <iostream>
#include <mysql.h>
#include <string>
extern MYSQL* conn;
extern MYSQL_ROW row;
extern MYSQL_RES* res;
extern std::string conf_ip;
extern unsigned int conf_port;
extern std::string conf_db;
extern std::string conf_login;
extern std::string conf_password;
namespace MySQL
{
void Connect(std::string ip, unsigned int port, std::string login, std::string password, std::string db);
void ExecuteQuery(std::string query);
void SetDatabase(std::string database);
}
Your two calls to ExecuteQuery share state, namely the "currently active query" and the buffered resultset you downloaded with mysql_result_row.
This is called a non-reentrant function.
Some options:
have a dedicated connection for each query
Do a single query that somehow combines the results (ie JOIN the players and accounts table)
Fetch all the players first into a dedicated datastructure (eg std::vector or std::map), then do the query for accounts later.
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 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.
#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);
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;
}