Using callback function to retrieve NULL values in C++ / SQLite - c++

I am using C++ and SQLite for a basic messageboard system. I have Datetime fields in my Messages table called 'posted' for the original post date, and 'edited' for the edited date, which is NULL if the message has not been edited. I can post messages successfully but I am running into problems when trying to display posted messages with a NULL edited value.
static int getData(const char* s)
{
sqlite3* DB;
int exit = sqlite3_open(s, &DB);
string sql = "SELECT MSGID, POSTED, EDITED, CONTENT FROM MESSAGES WHERE USERID IS '123' ";
"ORDER BY DATETIME(POSTED) DESC;";
sqlite3_exec(DB, sql.c_str(), callback, NULL, NULL);
sqlite3_close(DB);
return 0;
}
static int callback(void* NotUsed, int argc, char** argv, char** azColName)
{
for (int i = 0; i < argc; i++) {
cout << azColName[i] << ": " << argv[i] << endl;
}
return 0;
}
In the console this returns:
MSGID: 1
POSTED: 2020-03-27 12:14:59
EDITED:
Then diverts to the end of the program without displaying the content value.
I am setting EDITED to NULL when posting a message, and I've also tried leaving out setting the value at all, and entering an empty string, but I'm getting the same problem. If I remove EDITED from the SQL statement, it continues to the end and shows the CONTENT value.
static int getData(const char* s)
{
sqlite3* DB;
int exit = sqlite3_open(s, &DB);
string sql = "SELECT MSGID, POSTED, CONTENT FROM MESSAGES WHERE USERID IS '123' ";
"ORDER BY DATETIME(POSTED) DESC;";
sqlite3_exec(DB, sql.c_str(), callback, NULL, NULL);
sqlite3_close(DB);
return 0;
}
static int callback(void* NotUsed, int argc, char** argv, char** azColName)
{
for (int i = 0; i < argc; i++) {
cout << azColName[i] << ": " << argv[i] << endl;
}
return 0;
}
returns
MSGID: 1
POSTED: 2020-03-27 12:14:59
CONTENT: This is a message
so I assume it is something to do with how the callback function handles the NULL value, but I'm struggling to find guidance on how to display the NULL values and continue with the rest of the For loop.
Thanks!
EDIT:
Following on from Paul Sanders' prompt, I've amended the callback function to the following, which is displaying how I wanted it to:
static int callbackMsg(void* NotUsed, int argc, char** argv, char** azColName)
{
for (int i = 0; i < argc; i++) {
cout << azColName[i] << ": ";
if (argv[i]) {
cout << argv[i] << endl;
}
else
cout << endl;
continue;
}
cout << endl;
return 0;
}
MSGID: 1
POSTED: 2020-03-27 12:14:59
EDITED:
CONTENT: This is a message

Related

formatting sqlite3_exec result

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

SQLite3 Insert statement error, but error message blank?

I'm working on a basic program to learn how to use SQLite3; a user gives input on a song they'd like to add to a SQLite database, and it is inserted. As far as I can seen, the insert statement I'm generating- while not pretty- is a valid statement, but once it reaches my queryDatabase() function it enters the error clause. It prints "Error in execution: ", but when it moves on to errmsg, it seems to enter into a state where nothing happens/no actual error message is printed until I enter .quit. I've tried altering the print line like cout << "ERROR EXECUTING SQL: " << errmsg << "End";, and "End" never prints.
Here is the section of code that calls the queryDatabase() function/passes the command string. args refers to a vector that contains the user input:
string sqlq;
sqlq = "INSERT INTO songs (sid, title, composer) VALUES(";
sqlq.append(args[2]); sqlq.append(", "); sqlq.append("\'"); sqlq.append(args[3]); sqlq.append("\'"); sqlq.append(", "); sqlq.append("\'"); sqlq.append(args[4]); sqlq.append("\'"); sqlq.append(");");
data.queryDatabase(sqlq);
and here is the queryDatabase() function:
sqlite3 *db;
char * errmsg = 0;
int rc;
void Data::queryDatabase(string queryString){
if(queryString.empty()) return;
const char * sqlQuery = queryString.c_str();
rc = sqlite3_exec(db, sqlQuery, callback, (void *) data, &errmsg);
if( rc != SQLITE_OK) {
cout << "Error in execution: " << errmsg;
} else {
cout << "\nSQL QUERY SUCCEEDED\n";
}
}
Both queryString and sqlQuery print INSERT INTO songs (sid, title, composer) VALUES(1905, 'Anti-rage', 'Emperor X'); which as far as I know is a valid command, as copy and pasting this when working direct in the database from terminal results in the song being added. Why might this not be inserting correctly, and why am I not being given an error message?
MODIFIED FOR MORE INFO:
Here's the callback
static int callback(
void * data, //pass through data provided to sqlite3_exec() [4th argument]
int argc, //# of cols in table row
char ** argv, //array of strings representing table row values
char ** azColName //array of strings representing column names
){
for (int i=0; i<argc; i++){
cout << argv[i] << ", ";
}
cout << "\n";
return 0;
}

SQLite - Retrieve BLOB Encrypted Data

I am trying to retrieve blob encrypted data from a sqlite file. Here is my current code:
sqlite3 *db; char *error;
int rc;
rc = sqlite3_open("db.sq", &db);
if (rc)
{
cout << "Connection Error";
sqlite3_close(db);
}
else {
char **results = NULL;
int rows, columns;
const char *sqlSelect = "SELECT password FROM users";
sqlite3_get_table(db, sqlSelect, &results, &rows, &columns, &error);
if (rc) {
system("color 0c");
cout << "Query Error";
}
else {
for (int i = 2; i < rows*2; i += 1) {
cout << results[i] << endl;
}
}
}
The only thing this prints, however, is a bunch of smiley faces. I assume that I am getting the data wrong, as I remember seeing a way to get blob information in the documentation, but I am not sure how to implement that.
The documentation for blob: https://www.sqlite.org/c3ref/column_blob.html

Proper use of callback function of sqlite3 in C++

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

Basic doubt in QT using C++ about making objects

int main (int argc, char* argv[])
{
QApplication app(argc, argv);
QTextStream cout(stdout, QIODevice::WriteOnly);
// Declarations of variables
int answer = 0;
do {
// local variables to the loop:
int factArg = 0;
int fact(1);
factArg = QInputDialog::getInteger(0, "Factorial Calculator",
"Factorial of:", 1);
cout << "User entered: " << factArg << endl;
int i=2;
while (i <= factArg) {
fact = fact * i;
++i;
}
QString response = QString("The factorial of %1 is %2.\n%3")
.arg(factArg).arg(fact)
.arg("Do you want to compute another factorial?");
answer = QMessageBox::question(0, "Play again?", response,
QMessageBox::Yes | QMessageBox::No);
} while (answer == QMessageBox::Yes);
return EXIT_SUCCESS;
}
Link taken from here
originally from above link...
Can you help me out with "QInputDialog..(4th line of do while loop)" How do I get to know about which arguments does it have?
I saw the documentation but i couldnt find out, whats this "0" and "1" in arguments..
Read the docs. Basically - first is a parent widget (NULL in this case), and the 1 after label is a default value.