SQLite3 Insert statement error, but error message blank? - c++

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

Related

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

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

MySQL in C++ Seg Fault

I'm implementing mySQL in C++ and ran into an issue. I'm getting a seg fault. And I'm not sure why.
Was hoping someone would know what is going on.
The seg fault seems to be happening somewhere after the MYSQL_ROW productList; line, I haven't been able to pin point where though.
void Receiving::getProduct(const string productToReturn) {
MYSQL *connect, mysql; //Pointers to MySQL
connect = mysql_init(&mysql); // Initialize the connections
int totalRows = 0;
connect = mysql_real_connect(connect,SERVER,USER,PASSWORD,DATABASE,0,NULL,0); //Connect to database
if(connect) { //If connection successful
string sqlQuery; //will hold query
MYSQL_RES *resSetProduct; //define product result set
MYSQL_ROW productList; //define row for product
sqlQuery = "SELECT * FROM Inventory WHERE item_id = \' "; //Create query with desired product id
sqlQuery += productToReturn;
sqlQuery += " \'";
mysql_query(connect, sqlQuery.c_str()); // Send query to the database
resSetProduct = mysql_store_result(connect); // Receive the result and store it in resSetProduct
totalRows = mysql_num_rows(resSetProduct); // count of stored rows
if(totalRows == 0){ //nothing found
cout << "Sorry! No inventory found for that product!" << endl;
}
else {
cout << "Product Id In Stock" << endl;
while( (productList = mysql_fetch_row(resSetProduct)) != NULL ) { //printout the products
cout << productList[0] << " " << productList[1] << endl;
}
}
mysql_free_result(resSetProduct);
}
else //Failed to connect
cerr << "Failed To Connect!";
mysql_close(connect);
}
You should check if mysql_query returns zero. If it does not, mysql_store_result will return NULL and mysql_num_rows might fail with a segfault.
If mysql_query returns non-zero you can check the error codes according to the mysql documentation, eg. here: MySQL mysql_query
As soon as those errors are cleared, mysql_num_rows should not segfault anymore.

I combined two strings in c++ but get a wrong out put

while(in) {
memset(str, 0,1024);
in.getline(str, 1024); // delim defaults to '\n'
string output = modifyString(str);
if (output != ""){
cout << output << endl;
string output1 = "INSERT INTO DATA_SRC "\
"VALUES (" + output + ");";
cout << output1 << endl;
const char * command = output1.c_str();
cout << output << endl;
rc = sqlite3_exec(db, command, callback, 0, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
return 1;
}
}
for here, I + two string together.
And the out put intially is:
'D3318','D.A. Kline','Quantitative determination of sugars in fruits by GLC separation of TMS derivatives',1970,'Journal of AOAC International',53,6,1198,1202
which is good. But after I combine it to others.
Expected:
INSERT INTO DATA_SRC VALUES ('D3318','D.A. Kline','Quantitative determination of sugars in fruits by GLC separation of TMS derivatives',1970,'Journal of AOAC International',53,6,1198,1202);
Reality:
INSERT INTO DATA_SRC VALUES ('D3318','D.A. Kline','Quantitative determination of sugars in fruits by GLC separation of TMS derivatives',1970,'Journal of AOAC In);rnational',53,6,1198,1202
I do not now why.
Your modifyString function (which you didn't show) is copying a null byte to the end of the string. The string output functions will stop on a null byte, in order to be compatible with C-strings.

Insert entry into SQLite3 table in a conditional C++ loop statement

I am using SQLite3 header files in my C++ program and trying to create a table and insert data onto it, it works fine on a regular input.
It shows error when I use it in a C++ loop with changing variables.
I am using the database to insert my reading from RS-232.
Here is my code:
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char *sql;
std::string sql_str;
std::ostringstream temp;
std::string command;
/* Open database */
rc = sqlite3_open("test_1.db", &db);
if (rc){
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}
else{
fprintf(stderr, "Opened database successfully\n");
}
std::string str;
std::ostringstream oss;
oss << id_count; // stornig the primary id int values into a string
str = "INSERT INTO M_DATA (ID, DETAILS) VALUES(";
str += oss.str(); //copying the int primary id
str += ", '";
std::string str_t1(szBuffer); //Copying character aray to a string
str += str_t1; //concatening the string
str += "');";
//printing what the database takes
//output_file << std::endl << str << std::endl;
char * writable = new char[str.size() + 1];
std::copy(str.begin(), str.end(), writable);
writable[str.size()] = '\0'; // don't forget the terminating 0
sql = writable;
output_file << std::endl << "## SQL COMMAND : " << sql << "#" << std::endl;
// don't forget to free the string after finished using it
delete[] writable;
rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
if (rc != SQLITE_OK){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
output_file << std::endl << "** SQL ERROR : " << zErrMsg << "*" << std::endl;
sqlite3_free(zErrMsg);
}
else{
fprintf(stdout, "Records created successfully\n");
}
// _sleep(3000);
sqlite3_close(db);
My issue is I have a szBuffer which changes everytime, and I have to insert it as a new entry into the table.
Is there a way to increment the Primary Key and store my string into it?
The sz buffer at a single line will give data like: For Ex:
szBuffer : ersion = 1 [SPI]: MinorVersion = 2 [SPI]: Real Time
= 1434260351 [SPI]: SR # = SBB-ST1000090
The SQL command in the string I pass is like this:
SQL COMMAND : INSERT INTO M_DATA (ID, DETAILS) VALUES(9,
'ersion = 1 [SPI]: MinorVersion = 2 [SPI]: Real Time = 1434260351
[SPI]: SR # = SBB-ST1000090');
The Error which I get is like:
SQL ERROR : near "¸”_": syntax error
I am not sure if I am doing this right or wrong.
Can we use the insert statement in a loop? Am I passing the string the right way? (It looks correct to me when I print it out.)
But why do I get an error?
Is there any better way to enter my data?
I am very new to this so I tried search the internet, but no one is doing it the way I did it.
Please help.
Many Thanks.
(Almost) never build a SQL statement via string concatenation. Use a prepared statement and bind the parameter values.
// Prepare the statement
sqlite3_stmt* stmt;
int result = sqlite3_prepare_v2(db, "INSERT INTO M_DATA (ID, DETAILS) VALUES(?, ?);", -1, &stmt, nullptr);
// TODO: Handle when result != SQLITE_OK
while(/* whatever you wanted to loop on */)
{
// Bind in the parameter values
result = sqlite3_bind_int(stmt, 1, id_count);
// TODO: Handle when result != SQLITE_OK
result = sqlite3_bind_text(stmt, 2, szBuffer, -1, SQLITE_STATIC);
// TODO: Handle when result != SQLITE_OK
// Invoke the statement
result = sqlite3_step(stmt);
// TODO: Handle when result != SQLITE_OK
// Reset the statement to allow binding variables on the next iteration
result = sqlite3_reset(stmt);
}
// Release the statement
sqlite3_finalize(stmt);

c++ : Create database using SQLite for Insert & update

I am trying to create a database in c++ using sqlite3 lib.. I am getting error sqlite3_prepare_v2'
was not declared in this scope as shown in logcat.
log file
..\src\Test.cpp: In function 'int main(int, const char**)':
..\src\Test.cpp:21:85: error: 'sqlite3_prepare_v2' was not declared in this scope
..\src\Test.cpp:30:13: error: variable 'sqlite3 in' has initializer but incomplete type
..\src\Test.cpp:30:30: error: invalid use of incomplete type 'sqlite3 {aka struct sqlite3}'
..\src\/sqlite3.h:73:16: error: forward declaration of 'sqlite3 {aka struct sqlite3}'
Here is my code
#include <iostream>
using namespace std;
#include "sqlite3.h"
int main (int argc, const char * argv[]) {
sqlite3 *db;
sqlite3_open("test.db", & db);
string createQuery = "CREATE TABLE IF NOT EXISTS items (busid INTEGER PRIMARY KEY, ipaddr TEXT, time TEXT NOT NULL DEFAULT (NOW()));";
sqlite3_stmt *createStmt;
cout << "Creating Table Statement" << endl;
sqlite3_prepare_v2(db, createQuery.c_str(), createQuery.size(), &createStmt, NULL);
cout << "Stepping Table Statement" << endl;
if (sqlite3_step(createStmt) != SQLITE_DONE) cout << "Didn't Create Table!" << endl;
string insertQuery = "INSERT INTO items (time, ipaddr) VALUES ('test', '192.168.1.1');"; // WORKS!
sqlite3_stmt *insertStmt;
cout << "Creating Insert Statement" << endl;
sqlite3_prepare(db, insertQuery.c_str(), insertQuery.size(), &insertStmt, NULL);
cout << "Stepping Insert Statement" << endl;
if (sqlite3_step(insertStmt) != SQLITE_DONE) cout << "Didn't Insert Item!" << endl;
cout << "Success!" << endl;
return 0;
}
please help me out. thanks.....
#include <sqlite3.h>
should contain sqlite3_prepare_v2 and struct sqlite3. Make sure you're including the right sqlite3.h file.
Also in sqlite3_prepare_v2 the 3rd arg can be (and should be in your case) -1 so the sql is read to the first null terminator.
Working bare-metal sample using sqlite 3.7.11:
#include <sqlite3.h>
int test()
{
sqlite3* pDb = NULL;
sqlite3_stmt* query = NULL;
int ret = 0;
do // avoid nested if's
{
// initialize engine
if (SQLITE_OK != (ret = sqlite3_initialize()))
{
printf("Failed to initialize library: %d\n", ret);
break;
}
// open connection to a DB
if (SQLITE_OK != (ret = sqlite3_open_v2("test.db", &pDb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL)))
{
printf("Failed to open conn: %d\n", ret);
break;
}
// prepare the statement
if (SQLITE_OK != (ret = sqlite3_prepare_v2(pDb, "SELECT 2012", -1, &query, NULL)))
{
printf("Failed to prepare insert: %d, %s\n", ret, sqlite3_errmsg(pDb));
break;
}
// step to 1st row of data
if (SQLITE_ROW != (ret = sqlite3_step(query))) // see documentation, this can return more values as success
{
printf("Failed to step: %d, %s\n", ret, sqlite3_errmsg(pDb));
break;
}
// ... and print the value of column 0 (expect 2012 here)
printf("Value from sqlite: %s", sqlite3_column_text(query, 0));
} while (false);
// cleanup
if (NULL != query) sqlite3_finalize(query);
if (NULL != pDb) sqlite3_close(pDb);
sqlite3_shutdown();
return ret;
}
Hope this helps
Guys , creating database using sqlite3 in c/c++, here I'm using follwing steps...
1) Firstly you include MinGw file .
2) Add header file sqlite3.h, sqlite3.c in your src folder.
3) Add libr folder , in libr here include these file
mysqlite.h, shell.c, sqlite3.c, sqlite3.h, sqlite3ext.h
After then start your coding...
#include <iostream>
using namespace std;
#include "sqlite3.h"
int main (int argc, const char * argv[]) {
sqlite3 *db;
sqlite3_open("test1.db", & db);
string createQuery = "CREATE TABLE IF NOT EXISTS items (userid INTEGER PRIMARY KEY, ipaddr
TEXT,username TEXT,useradd TEXT,userphone INTEGER,age INTEGER, "
"time TEXT NOT NULL DEFAULT
(NOW()));";
sqlite3_stmt *createStmt;
cout << "Creating Table Statement" << endl;
sqlite3_prepare(db, createQuery.c_str(), createQuery.size(), &createStmt, NULL);
cout << "Stepping Table Statement" << endl;
if (sqlite3_step(createStmt) != SQLITE_DONE) cout << "Didn't Create Table!" << endl;
string insertQuery = "INSERT INTO items (time, ipaddr,username,useradd,userphone,age)
VALUES ('7:30', '192.187.27.55','vivekanand','kolkatta','04456823948',74);"; // WORKS!
sqlite3_stmt *insertStmt;
cout << "Creating Insert Statement" << endl;
sqlite3_prepare(db, insertQuery.c_str(), insertQuery.size(), &insertStmt, NULL);
cout << "Stepping Insert Statement" << endl;
if (sqlite3_step(insertStmt) != SQLITE_DONE) cout << "Didn't Insert Item!" << endl;
return 0;
}
go through this link. I am not sure. It might help you out.
I think their is no sqlite3_prepare_v2 in sqlite3.h lib, so try this.. sqlite3_prepare_v2 can be replaced by sqlite3_prepare, but more care is needed, because it changes the semantics of subsequent calls slightly.