I have a table(Item) with attribute of id,item
id|itemName
1|noodle
2|burger
Basically I would like to ask is there anyway that I can compare a input results against my database
record?
e.g if I input noodle and there's is a matching record "noodle" in my in my database it will return found;
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
#include <string>
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
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;
}
int main(int argc, char* argv[])
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
const char *sql;
std::string itemName;
rc = sqlite3_open("test.db", &db);
if( rc ) {
// failed
fprintf(stderr, "Can't open database: %s\n",
sqlite3_errmsg(db));
}
else
{
// success
fprintf(stderr, "Open database successfully\n");
}
std::cout << "Enter a Item" << std::endl;
std::cin >> itemName;
sql = "select * from Item";
rc = sqlite3_exec(db,sql, callback, 0, &zErrMsg);
if(//how do I compare the itemName from my database against the user input)
{
}
sqlite3_close(db);
return 0;
}
Instead of a callback you can use a parameter to specify just the record you need:
std::cin >> itemName;
sql = "select id from Item where itemName = ?";
sqlite3_stmt *stmt;
sqlite3_prepare_v2(db, sql, -1, &stmt, NULL);
// set the ? parameter to the itemname you are looking for:
sqlite3_bind_text(stmt, 1, itemName.c_str(), -1, SQLITE_TRANSIENT);
if(sqlite3_step(stmt) == SQLITE_ROW )
{
int id=sqlite3_column_int(stmt,0);
std::cout << "Found id=" << id << std::endl;
}
sqlite3_finalize(stmt);
sqlite3_close(db);
Related
Hello how would I go about formatting the result of
sql = "SELECT * from COMPANY ORDER BY ID";
rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
I read there are console commands for it on here https://www.tutorialspoint.com/sqlite/sqlite_commands.htm
so I tried
std::string c3 = "sqlite>.header on";
std::string c1 = "sqlite>.mode column";
cout << system(c3.c_str()) << endl;
cout << system(c1.c_str()) << endl;
but that didn't work to get a table format like result
How would I do this? I've been googling for 3 hours and still didn't get anywhere
You can't control the formatting from the sqlite3 user program, so using system() to call it will not control the C API.
You should do this using the callback function. From the same tutorialpoint site:
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;
}
While using SQLite in C++98, how to convert stringstream to Unicode and pass it to sqlite3_exec()? I constantly have this error:
error C2440: 'initializing' : cannot convert from 'std::basic_string<_Elem,_Traits,_Ax>' to 'std::basic_string<_Elem,_Traits,_Ax>'
1> with"
Code:
int main(int argc, char* argv[]) {
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char *sql;
const char* data = "Callback function called";
tstringstream tstrsSQL;
tstrsSQL.imbue(std::locale("C"));
std::string s = tstrsSQL.str(); // converting stringstream to char?
const char* p = s.c_str();
/* Open database */
rc = sqlite3_open("db.db3", &db);
if( rc ) {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
return(0);
} else {
fprintf(stderr, "Opened database successfully\n");
}
/* Create SQL statement */
tstrsSQL << _T("SELECT") something ("FROM") << table;
/* Execute SQL statement */
rc = sqlite3_exec(db, p, callback, (void*)data, &zErrMsg); // p needs to be unicode
You are using tstringstream, which I guess uses std::wstringstream if UNICODE is defined, so its str() gives a std::basic_string<wchar_t>.
But you get the result into a std::string, which is std::basic_string<char>. So the assignment fails.
Anyway, you take the result and use it in sqlite3_exec(), which takes a const char* as input.
That's why you shouldn't use tstringstream, you should use std::stringstream, and remove the _T from all of the string literals.
Minimal, complete, working code:
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
stringstream strstream;
strstream << "Hello World";
string str = strstream.str();
cout << str << endl;
return 0;
}
I'm writing a c++ program that has two functions that can run completely independent one from another. So i want to break them into two programs.
The problem is that both of them rely on the same set of functions (that can grow or change). What i want to do is include this set of functions as a header in both programs so i dont have to copy/paste every time i change something (i also hate duplicating functions or anything).
I know is a silly question but i couldn't find any documentation on the matter.
If the code is necessary ask for it and i will post it.
Thanks!
EDIT:
Adding code:
The functions that can run independent are make_video() and delete_video()
Please have in mind that this is far from done.
#include <sys/types.h>
#include <sys/stat.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string>
#include <cstring>
#include <dirent.h>
#include <vector>
#include <time.h>
#include <csignal>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
#include <mysql/mysql.h>
#include <mysql_connection.h>
#include <mysql_driver.h>
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
struct config_t{
std::string sql_host; //mysql host
std::string sql_user; //mysql user
std::string sql_pass; //mysql password
std::string sql_db; //zoneminder database name
std::string sql_ev_zm; //zoneminder events table
std::string sql_ev_vid; //video events table
std::string sql_ev_videxp; //video events expiration table
std::string sql_mon; //zm monitors table
std::string dir_ev; //Zoneminder events directory
std::string dir_vid; //manager videos directory
std::string dir_ram; //Ramfs mount directory
std::string ram_size; //ramfs size
};
int is_dir(const char *pathname){
struct stat info;
if( stat( pathname, &info ) != 0 )
return -1;
else if( info.st_mode & S_IFDIR ) // S_ISDIR() doesn't exist on my windows
return 1;
else
return 0;
}
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}
// trim from start (copying)
static inline std::string ltrimmed(std::string s) {
ltrim(s);
return s;
}
// trim from end (copying)
static inline std::string rtrimmed(std::string s) {
rtrim(s);
return s;
}
// trim from both ends (copying)
static inline std::string trimmed(std::string s) {
trim(s);
return s;
}
bool DirectoryExists ( const char* path ){
if( path == NULL )return false;
DIR *d;
d = opendir(path);
if (d){
closedir(d);
return true;
}
return false;
}
std::ifstream::pos_type filesize(const char* filename){
std::ifstream in(filename, std::ifstream::ate | std::ifstream::binary);
return in.tellg();
}
bool mount_ramfs(config_t *conf){
return false;
}
bool make_video(config_t *conf, std::string path = "", int depth = 0){
try{
sql::mysql::MySQL_Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;
driver = sql::mysql::get_mysql_driver_instance();
con = driver->connect(conf->sql_host, conf->sql_user, conf->sql_pass);
stmt = con->createStatement();
stmt->execute("USE " + conf->sql_db);
std::string query = "SELECT Id, MonitorId, StartTime, EndTime, Length, Frames FROM " + conf->sql_ev_zm + " WHERE EndTime IS NOT NULL LIMIT 10"; //select a bunch of events for processing, EndTime NOT NULL means that the event is complete and not corrupted
//syslog (LOG_DEBUG, "Mysql Query: %s", query.c_str());
res = stmt->executeQuery(query);
// SELECT Id, MonitorId, StartTime FROM Events WHERE StartTime < NOW() - INTERVAL 1 DAY ORDER BY Id ASC LIMIT 1
// SELECT Id, MonitorId, StartTime FROM Events WHERE StartTime LIKE "%2015-11-18%" and MonitorId = 56
// conf.dir_ev + "/" + MonitorId + "/" + todir(StartTime)
while (res->next()) {
int id = res->getInt("Id");
int monitor = res->getInt("MonitorId");
std::string start_time = res->getString("StartTime");
std::string end_time = res->getString("EndTime");
int lenght = res->getInt("Length");
int frames = res->getInt("Frames");
//Get event directory form table data; the dir structure is id/YY/MM/DD/HH/mm/ss/
char sttm[60] = {};
std::strcpy(sttm, start_time.c_str());
char * tkn = (char*)malloc(60);
std::stringstream pathSS;
pathSS << conf->dir_ev << '/' << id << '/'; //prepare the path
tkn = std::strtok (sttm," -:"); //here we tokenize the StartTime field to match the source directory structure
if (tkn != NULL) {
pathSS << tkn[2] << tkn[3] << '/';
tkn = std::strtok (NULL, " -:");
}
while (tkn != NULL) {
pathSS << tkn << '/';
tkn = std::strtok (NULL, " -:");
}
std::string src = pathSS.str();
pathSS.clear();
pathSS << conf->dir_vid << '/' << id << '/'; //prepare the path
std::string dest = pathSS.str();
pathSS.clear();
tkn = std::strtok (sttm," -:"); //here we tokenize the StartTime field to make the destinantion and filename
while (tkn != NULL) {
pathSS << tkn << '_'; //sadly this will always lead to "_.mp4" but its not that bad or important
tkn = std::strtok (NULL, " -:");
}
pathSS << ".mp4";
std::string fname = pathSS.str();
pathSS.clear();
//do event video and
/*std::string cmd = "mkdir -p " + conf->dir_vid + path;
syslog (LOG_DEBUG, "%s", cmd.c_str());
std::system(cmd.c_str());
cmd = "tar -zcf " + conf->dir_vid + path + "/" + dirlist[i] +".tar.gz " + conf->dir_ev + path + "/" + dirlist[i];
syslog (LOG_DEBUG, "%s", cmd.c_str());
std::system(cmd.c_str());
cmd = "rm -rf " + conf->dir_ev + src + "*";
syslog (LOG_DEBUG, "%s", cmd.c_str());
std::system(cmd.c_str());*/
try{
//insert new row in videos table
pathSS << "INSERT INTO " << conf->sql_ev_vid << " (startTime, endTime, monitor, filename) VALUES (\'" << start_time << "\', \'" << end_time << "\', " << monitor << ",\'" << dest << fname << "\')";
stmt->execute(pathSS.str());
pathSS.clear();
//delete non existing event
pathSS << "DELETE FROM " << conf->sql_ev_zm << " WHERE Id = " << id;
stmt->execute(pathSS.str());
pathSS.clear();
}
catch(sql::SQLException &e){
syslog (LOG_ERR, "Mysql Exception: %s, ERRNO %i, MySQL State: %s", e.what(), e.getErrorCode(), std::string(e.getSQLState()).c_str());
exit(EXIT_FAILURE);
}
}
delete res;
delete stmt;
delete con;
}
catch(sql::SQLException &e){
syslog (LOG_ERR, "Mysql Exception: %s, ERRNO %i, MySQL State: %s", e.what(), e.getErrorCode(), std::string(e.getSQLState()).c_str());
exit(EXIT_FAILURE);
}
return true;
}
bool delete_video(config_t *conf){
try{
sql::mysql::MySQL_Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;
sql::ResultSet *subres;
driver = sql::mysql::get_mysql_driver_instance();
con = driver->connect(conf->sql_host, conf->sql_user, conf->sql_pass);
stmt = con->createStatement();
stmt->execute("USE " + conf->sql_db);
std::string query = "SELECT monitor, recording_days FROM " + conf->sql_ev_videxp + " WHERE 1";
//syslog (LOG_DEBUG, "Mysql Query: %s", query.c_str());
res = stmt->executeQuery(query);
// SELECT Id, MonitorId, StartTime FROM Events WHERE StartTime < NOW() - INTERVAL 1 DAY ORDER BY Id ASC LIMIT 1
// SELECT Id, MonitorId, StartTime FROM Events WHERE StartTime LIKE "%2015-11-18%" and MonitorId = 56
// conf.dir_ev + "/" + MonitorId + "/" + todir(StartTime)
while (res->next()) {
int id = res->getInt("Id");
int r_days = res->getInt("recording_days");
//syslog (LOG_DEBUG, "Id: %i, Recording Days: %i", id, r_days);
std::stringstream subQuerySS;
subQuerySS << "SELECT id, file FROM " << conf->sql_ev_vid << " WHERE date < NOW() - INTERVAL " << r_days << " DAY AND monitor = " << id;
std::string subQuery = subQuerySS.str();
subQuerySS.clear();
//syslog (LOG_DEBUG, "Mysql Query: %s", subQuery.c_str());
subres = stmt->executeQuery(subQuery);
while (subres->next()) {
int subid = subres->getInt("id");
std::string file = subres->getString("file");
std::string cmd = "rm -f " + file;
syslog (LOG_DEBUG, "%s", cmd.c_str());
std::system(cmd.c_str());
std::stringstream delQuerySS;
delQuerySS << "DELETE FROM " << conf->sql_ev_vid << " WHERE id = " << subid;
std::string delQuery = delQuerySS.str();
delQuerySS.clear();
syslog (LOG_DEBUG, "Mysql Query: %s", delQuery.c_str());
stmt->execute(delQuery);
}
}
delete res;
delete subres;
delete stmt;
delete con;
}
catch(sql::SQLException &e){
syslog (LOG_ERR, "Mysql Exception: %s, ERRNO %i, MySQL State: %s", e.what(), e.getErrorCode(), std::string(e.getSQLState()).c_str());
exit(EXIT_FAILURE);
}
return true;
}
void signalHandler( int signum ){
syslog (LOG_NOTICE, "signal received (%i)", signum);
closelog();
exit(signum);
}
int main(void) {
/* Our process ID and Session ID */
pid_t pid, sid;
/* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If we got a good PID, then
we can exit the parent process. */
if (pid > 0) {
std::ofstream pid_file;
pid_file.open("evmanager.pid", std::ofstream::trunc);
if( pid_file.is_open()){
pid_file << pid;
pid_file.close();
}
exit(EXIT_SUCCESS);
}
/* Change the file mode mask */
umask(0);
setlogmask (LOG_UPTO (LOG_DEBUG));
openlog ("dt_event_manager", LOG_PID, LOG_DAEMON);
syslog (LOG_NOTICE, "Program started by User %d", getuid ());
/* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
syslog (LOG_ERR, "SID Creation Failed");
exit(EXIT_FAILURE);
}
/* Change the current working directory */
if ((chdir("/")) < 0) {
syslog (LOG_ERR, "Failed while Changing directory to /");
exit(EXIT_FAILURE);
}
/* Read Initial Configuration */
std::ifstream conf_file;
std::string line;
config_t conf;
conf_file.open("/etc/zm/evmanager.conf");
if( conf_file.is_open()){
while( std::getline(conf_file, line) ){
if(line[0] == '#')continue;
std::istringstream is_line(line);
std::string key;
if( std::getline(is_line, key, '=') ){
std::string value;
if( std::getline(is_line, value) ){
trim(key);
trim(value);
if( key == "sql_host" )conf.sql_host = value; //mysql host
else if( key == "sql_user" )conf.sql_user = value; //mysql user
else if( key == "sql_pass" )conf.sql_pass = value; //mysql password
else if( key == "sql_db")conf.sql_db = value; //zoneminder database name
else if( key == "sql_ev_zm" )conf.sql_ev_zm = value; //zoneminder events table
else if( key == "sql_ev_vid" )conf.sql_ev_vid = value; //video events table
else if( key == "sql_ev_videxp" )conf.sql_ev_videxp = value; //Zoneminder videos expiration directory
else if( key == "sql_mon" )conf.sql_mon = value; //Zoneminder Monitors directory
else if( key == "dir_ev" )conf.dir_ev = value; //Zoneminder events directory
else if( key == "dir_vid" )conf.dir_vid = value; //Manager Videos directory
else if( key == "dir_ram" )conf.dir_ram = value; //Ramfs mount dir
else if( key == "ram_size" )conf.ram_size = value; //Ramfs size
else{
syslog (LOG_ERR, "Bad config readout");
exit(EXIT_FAILURE);
}
}
}
}
}
else{
syslog (LOG_ERR, "Failed to open configuration file");
exit(EXIT_FAILURE);
}
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
/* Daemon-specific initialization goes here */
/* The Big Loop */
signal(SIGINT, signalHandler);
syslog (LOG_INFO, "Daemon Started");
while (1) {
make_video();
delete_video();
sleep(10); /* wait 10 seconds */
}
exit(EXIT_SUCCESS);
}
This is a great question. I actually solve this issue a lot with students, as I was a C++ tutor.
As an example, let's say if this was your main:
//main.cpp:
#include <iostream>
#include "add.h" /// This comes in later :)
using namespace std;
int main()
{
cout << "2+3=" << add(2,3) << endl;
return 0;
}
You need to create a header file for the add function, like this:
//add.h
#ifndef ADD_H_INCLUDED
#define ADD_H_INCLUDED
int add(int a, int b);
#endif // ADD_H_INCLUDED
But then you need to actually define what the add function actually does:
//add.cpp
#include "add.h"
int add(int a, int b) {
return a + b;
}
Now you can choose to put multiple functions in a single header file, or each function can have its own header file, but it's your choice :) I hope this helps!
You have a number of options. The simplest is to create several files, perhaps like this:
shared_header.hpp
shared_functionality.cpp
prog_a.cpp
prog_b.cpp
Then program A is compiled with sources prog_a.cpp and shared_functionality.cpp, and program B is compiled with sources prog_b.cpp and shared_functionality.cpp. All source files include the header, and prog_a.cpp and prog_b.cpp define their own main function each.
I am a beginner to C++ and SQLlite and trying to compile code which can manipulate the results of a query from SQLite.
I am having difficulties in storing the results to a .txt file, which will enable me to manipulate results, and don't know where to start,
As a result, I can only see one row in MA.txt however I would like to store all of the results,
I want to store results into a .txt file because after I store the results, I have to divide the results into predefined lengths and find max and min values and report the first row and last row as well.
#include <iostream>
#include <iomanip>
#include <ctime>
#include <stdlib.h>
#include <sqlite3.h>
#include <string>
#include <locale>
#include <sstream>
#include <time.h>
#include <stdio.h>
#include <fstream>
#include <vector>
using namespace std;
static int callback2(void *data, int argc, char **argv, char **azColName)
{
ofstream os;
os.open("MA.txt");
os << argv[0] << endl;
return 0;
os.close();
}
int main(int argc, char* argv [])
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
const char* data = "Callback function called";
rc = sqlite3_open("test.db", &db);
if (rc){
cout << "Can't open database: %s\n" << sqlite3_errmsg(db);
exit(0);
}
string sql = "SELECT * from forex;";
rc = sqlite3_exec(db, sql.c_str(), callback2, (void*) data, &zErrMsg);
if (rc != SQLITE_OK){
cout << "SQL error:" << zErrMsg;
sqlite3_free(zErrMsg);
}
return 0;
}
I changed the code however I got "os does not name a type" error while compiling,
where should I put the offsting, sorry I am really a noobie:(
#include <iostream>
#include <iomanip>
#include <ctime>
#include <stdlib.h>
#include <sqlite3.h>
#include <string>
#include <locale>
#include <sstream>
#include <time.h>
#include <stdio.h>
#include <fstream>
#include <vector>
using namespace std;
ofstream os;
os.open("MA.txt");
static int callback2(void *data, int argc, char **argv, char **azColName)
{
os << argv[0] << endl;
return 0;
}
int main(int argc, char* argv [])
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
const char* data = "Callback function called";
rc = sqlite3_open("test.db", &db);
if (rc){
cout << "Can't open database: %s\n" << sqlite3_errmsg(db);
exit(0);
}
string sql = "SELECT * from forex;";
rc = sqlite3_exec(db, sql.c_str(), callback2, (void*) data, &zErrMsg);
if (rc != SQLITE_OK){
cout << "SQL error:" << zErrMsg;
sqlite3_free(zErrMsg);
}
return 0;
os.close();
}
I think that this is because of the way you are opening the file. You are opening it every time you read a new record and this causes it to go back to the beginning every time.
One way to fix this is to declare the ofstream outside the function and open it outside the function and close it at the very end. Another way to fix it is to open the ofstream with the std::app flag set, so that it will append to the file instead of rewriting it.
Another thing is that you are returning '0' from the call back function. You need to return SQLITE_OK to tell it to continue.
Not sure if this will work because I haven't tested it, but try this code:
#include <iostream>
#include <iomanip>
#include <ctime>
#include <stdlib.h>
#include <sqlite3.h>
#include <string>
#include <locale>
#include <sstream>
#include <time.h>
#include <stdio.h>
#include <fstream>
#include <vector>
using namespace std;
static int callback2(void *data, int argc, char **argv, char **azColName) {
ofstream os("MA.txt", ios::app);
os << argv[0] << endl;
os.close();
return SQLITE_OK;
}
int main(int argc, char* argv []) {
sqlite3 *db;
char *zErrMsg = 0;
int rc;
const char* data = "Callback function called";
rc = sqlite3_open("test.db", &db);
if (rc){
cout << "Can't open database: %s\n" << sqlite3_errmsg(db);
exit(0);
}
char sql[21] = "SELECT * from forex;";
rc = sqlite3_exec(db, sql.c_str(), callback2, NULL, &zErrMsg);
if (rc != SQLITE_OK){
cout << "SQL error:" << zErrMsg;
sqlite3_free(zErrMsg);
}
return 0;
}
I have the following C++ code for testing purposes in conjunction with SQLite3.
It's a class called customer with a callback function declared. This callback function is called whenever sqlite3_exec() returns results (records) from the SQLite database.
What I don't like about this construction is that source code to process the results is located in a call back function outside of the class rather than the results being processed by the class method from which sqlite3_exec() is called.
I could use global variables that will be used in the class method after the callback function has finished extracting the values from the SQL query results. But what if there is more than one record and the call back function is called several times. Then I need to work with arrays unless I make sure that I will only have single results.
Do I need to forget about the callback function and go into deeper calls of the SQLite API?
Or do I need to go to a C++ wrapper, I suppose that there is no call back mechanism there and the results being passed back to the class method itself?
// customer
#include "Customer\customer.h"
//## begin module%50E6CCB50119.additionalDeclarations preserve=yes
static int callback(void *NotUsed, int argc, char **argv, char **azColName)
{
int i;
char* columnName;
char* columnValueString;
short int columnValueShortInt = 0;
int columnValueInt = 0;
cout << "begin of callback function\n";
for(i=0; i<argc; i++)
{
columnName = azColName[i];
if (strcmp(columnName, "FirstName")==0 || strcmp(columnName, "LastName")==0)
{
columnValueString = argv[i];
cout << "columnName = " << columnName << "; value = " << columnValueString <<"\n";
}
else
{
if(strcmp(columnName, "Age")==0)
{
stringstream(argv[i]) >> columnValueShortInt;
cout << "columnName = " << columnName << "; value = " << columnValueShortInt <<"\n";
}
else // strcmp(columnName, "Id")==0)
{
stringstream(argv[i]) >> columnValueInt;
cout << "columnName = " << columnName << "; value = " << columnValueInt <<"\n";
}
}
}
cout << "end of call back function \n";
return 0;
}
//## end module%50E6CCB50119.additionalDeclarations
// Class customer
customer::customer ()
//## begin customer::customer%50F969EE01E4.hasinit preserve=no
//## end customer::customer%50F969EE01E4.hasinit
//## begin customer::customer%50F969EE01E4.initialization preserve=yes
//## end customer::customer%50F969EE01E4.initialization
{
//## begin customer::customer%50F969EE01E4.body preserve=yes
customerId = 0;
zErrMsg = 0;
customerDataBaseRc = sqlite3_open("customerdb", &customerDataBase);
if(customerDataBaseRc)
{
fprintf(stderr, "Can't open database %s\n", sqlite3_errmsg(customerDataBase));
sqlite3_close(customerDataBase);
}
const char * pSQL[6];
const char * sqlStatement;
pSQL[0] = "create table customerTable (Id int, FirstName varchar(30), LastName varchar(30), Age smallint)";
// execute all the sql statements
for(int i = 0; i < 1; i++)
{
customerDataBaseRc = sqlite3_exec(customerDataBase, pSQL[i], callback, 0, &zErrMsg);
if( customerDataBaseRc !=SQLITE_OK )
{
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
break; // break the loop if error occur
}
}
//## end customer::customer%50F969EE01E4.body
}
customer::~customer ()
{
//## begin customer::~customer%50F93279003E.body preserve=yes
const char *pSQL[6];
// Remove all data in customerTable
pSQL[0] = "delete from customerTable";
// Drop the table from database
pSQL[1] = "drop table customerTable";
// execute all the sql statements
for(int i = 0; i < 2; i++)
{
customerDataBaseRc = sqlite3_exec(customerDataBase, pSQL[i], callback, 0, &zErrMsg);
if( customerDataBaseRc !=SQLITE_OK )
{
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
break; // break the loop if error occur
}
}
cout << "destructor";
//## end customer::~customer%50F93279003E.body
}
//## Other Operations (implementation)
unsigned int customer::createCustomer (char iCustomerFirstName[20], char iCustomerLastName[20], unsigned short iCustomerAge)
{
//## begin customer::createCustomer%50EBFFA3036B.body preserve=yes
const char *sqlStatement;
string result; // string which will contain the result
ostringstream convert; // stream used for the conversion
convert << "insert into customerTable (Id, FirstName, LastName, Age) values (" << customerId << ", '" << iCustomerFirstName << "', '" << iCustomerLastName << "', " << iCustomerAge << ")";
result = convert.str(); // set 'Result' to the contents of the stream
sqlStatement = result.c_str();
// Execute sql statement
customerDataBaseRc = sqlite3_exec(customerDataBase, sqlStatement, callback, 0, &zErrMsg);
// Check for errors
if(customerDataBaseRc !=SQLITE_OK )
{
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
return customerId++;
//## end customer::createCustomer%50EBFFA3036B.body
}
char * customer::getCustomer (unsigned int iCustomerId)
{
//## begin customer::getCustomer%50ED3D700186.body preserve=yes
const char *sqlStatement;
char *tmp ="blabla";
string result; // string which will contain the result
ostringstream convert; // stream used for the conversion
convert << "select * from customerTable where Id = " << iCustomerId;
result = convert.str(); // set 'Result' to the contents of the stream
sqlStatement = result.c_str();
// Execute the sql statement
customerDataBaseRc = sqlite3_exec(customerDataBase, sqlStatement, callback, 0, &zErrMsg);
// Check for errors
if(customerDataBaseRc !=SQLITE_OK )
{
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
return tmp;
//## end customer::getCustomer%50ED3D700186.body
}
// Additional Declarations
//## begin customer%50E6CCB50119.declarations preserve=yes
//## end customer%50E6CCB50119.declarations
//## begin module%50E6CCB50119.epilog preserve=yes
//## end module%50E6CCB50119.epilog
What one typically does in this case is take advantage of the void * (which you call NotUsed) parameter of the callback -- a parameter you define when you install the callback. For C++, you would typically set that parameter to the this pointer to your interested object, and you would make the callback (an extern "C" function in a c++ source file) a friend method to your class (if necessary).
This would look like this:
class customer
{
...
public:
int callback(int argc, char **argv, char **azColName);
};
static int c_callback(void *param, int argc, char **argv, char **azColName)
{
customer* cust = reinterpret_cast<customer*>(param);
return cust->callback(argc, argv, azColName);
}
char* customer::getCustomer(int id)
{
...
rc = sqlite3_exec(db, sql, c_callback, this, &errMsg);
...
}
int customer::callback(int argc, char **argv, char **azColName)
{
...
}
Using sqlite3_exec has the disadvantages that you have to convert some values back from a string to a number, and that it needs to allocate memory for all result records (which can lead to problems when reading large tables).
Furthermore, the callback always is a separate function (even if it's in the same class).
For your example query, using the sqlite3_prepare/sqlite3_step/sqlite3_finalize API would look like this:
void one_customer::readFromDB(sqlite3* db, int id)
{
sqlite3_stmt *stmt;
int rc = sqlite3_prepare_v2(db, "SELECT FirstName, LastName, Age"
" FROM customerTable"
" WHERE Id = ?", -1, &stmt, NULL);
if (rc != SQLITE_OK)
throw string(sqlite3_errmsg(db));
rc = sqlite3_bind_int(stmt, 1, id); // Using parameters ("?") is not
if (rc != SQLITE_OK) { // really necessary, but recommended
string errmsg(sqlite3_errmsg(db)); // (especially for strings) to avoid
sqlite3_finalize(stmt); // formatting problems and SQL
throw errmsg; // injection attacks.
}
rc = sqlite3_step(stmt);
if (rc != SQLITE_ROW && rc != SQLITE_DONE) {
string errmsg(sqlite3_errmsg(db));
sqlite3_finalize(stmt);
throw errmsg;
}
if (rc == SQLITE_DONE) {
sqlite3_finalize(stmt);
throw string("customer not found");
}
this->id = id;
this->first_name = string(sqlite3_column_text(stmt, 0));
this->last_name = string(sqlite3_column_text(stmt, 1));
this->age = sqlite3_column_int(stmt, 2);
sqlite3_finalize(stmt);
}
(This code handles errors by just throwing a string with the error message.)