Related
Hi I am playing around with sqlite3 using C++. I am storing an array as BLOB and try to extract it from the database. However, when I select data from the database I got free():invalid size error after the function selectTable() finishes and before main() finishes. So I am a bit confused.
The output on the command line is
selectTable func
Opened database successfully
before finalzie
after close DB
free(): invalid size
Aborted
Below is backtrace from gdb and the code
Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig#entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 __GI_raise (sig=sig#entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1 0x00007ffff717a801 in __GI_abort () at abort.c:79
#2 0x00007ffff71c3897 in __libc_message (action=action#entry=do_abort,
fmt=fmt#entry=0x7ffff72f0b9a "%s\n") at ../sysdeps/posix/libc_fatal.c:181
#3 0x00007ffff71ca90a in malloc_printerr (
str=str#entry=0x7ffff72eeda0 "free(): invalid size") at malloc.c:5350
#4 0x00007ffff71d1e2c in _int_free (have_lock=0,
p=0x7ffff7de5990 <_dl_init+864>, av=0x7ffff7525c40 <main_arena>)
at malloc.c:4161
#5 __GI___libc_free (mem=0x7ffff7de59a0 <_dl_fini>) at malloc.c:3124
#6 0x0000555555555b48 in main ()
int main() {
const char* dir = "testBLOB.db";
sqlite3* DB;
//createDB(dir);
//createTable(dir);
//clearTable(dir);
for(int i = 0; i < 50; i++) {
//insertTable(dir);
}
cout << "selectTable func" << endl;
selectTable(dir);
cout << "Out of selectTable func" << endl;
return 0;
}
static int createDB(const char* s) {
sqlite3* DB;
int exit = 0;
exit = sqlite3_open(s, &DB);
if(!exit) {
//cout << "opened db" << endl;
}
sqlite3_close(DB);
return 0;
}
static int createTable(const char* s) {
sqlite3* DB;
string sql = "CREATE TABLE IF NOT EXISTS test("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"name TEXT NOT NULL, "
"vector BLOB"
");";
try {
int exit = 0;
exit = sqlite3_open(s, &DB);
char* messageError;
exit = sqlite3_exec(DB, sql.c_str(), NULL, 0, &messageError);
//cout << "Hello, World!" << endl;
if(exit != SQLITE_OK) {
cerr << "Error creating table" << endl;
} else {
sqlite3_close(DB);
}
} catch (const exception & e) {
cerr << e.what();
}
return 0;
};
static int insertTable(const char* s) {
sqlite3* DB;
long double nums [100] = {63.3448897849,56.5751700134,75.6611442415,44.4839808971,12.1012110357,39.8311006389,55.4628689524,44.1856083913,31.8941372232,36.7439371495,64.1919152947,46.6041307466,16.8129922477,26.4797506344,33.0942127905,87.7671523992,76.4743660304,26.895728291,71.6418628151,39.4279836297,33.1511476055,21.9412133656,49.2985876344,54.7288568945,61.7644413811,39.5360580159,48.2049240243,15.0657890486,74.8453755862,3.9697162327,46.3309272981,3.6967671205,29.4109279366,35.2237159178,71.2944696538,83.2668276235,8.6042287278,29.018178646,53.9090162771,74.1875874704,13.362141479,85.534882156,46.1570578637,16.6535624939,60.4663891357,46.4002226626,43.5334234645,5.9192657242,6.4233909782,70.9674985846,16.7364288218,6.140383666,1.6295357671,41.5132888558,7.0105695897,93.7402324433,67.9067125381,79.2202639865,73.9691802822,83.7211616527,95.1748897322,77.6210081594,52.6691899363,45.9668407426,30.0850082804,99.8853106577,44.4116175004,66.7492926269,80.344211132,2.9125625332,13.1282558744,77.1323341686,31.6479987137,12.0439293147,52.34792652,10.0973593886,11.1281788415,42.3558223361,26.0832770714,78.8802218674,65.7943757958,39.4931075012,62.3669620437,40.5895497709,75.5671730948,32.0576337297,97.9215110968,9.9871548843,46.6131220896,11.0937537323,59.9746432863,25.2756546914,39.1604177152,21.5325516688,55.5211448299,29.0247732257,10.4586600007,53.0534949121,77.3997550972,48.2887426956};
int rc = sqlite3_open_v2(s, &DB, SQLITE_OPEN_READWRITE,NULL);
if(rc != SQLITE_OK) {
} else {
string sql = "INSERT INTO test (name, vector) VALUES ('test', ?)";
try {
sqlite3_stmt *stmt = NULL;
rc = sqlite3_prepare_v2(DB, sql.c_str(), -1, &stmt, NULL);
if(rc != SQLITE_OK) {
cerr << "Error preparing stmt" << endl;
} else {
rc = sqlite3_bind_blob(stmt,1, nums, 1600, SQLITE_STATIC);
if(rc != SQLITE_OK) {
cerr << "bind failed" << endl;
} else {
rc = sqlite3_step(stmt);
if(rc != SQLITE_DONE) {
cerr << "no" << endl;
}
}
}
sqlite3_finalize(stmt);
} catch (const exception & e) {
cerr << e.what();
}
}
sqlite3_close(DB);
return 0;
};
static string selectTable(const char* s) {
sqlite3 *db;
int rc;
/* Open database */
rc = sqlite3_open(s, &db);
if( rc ) {
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
return(0);
} else {
fprintf(stderr, "Opened database successfully\n");
}
sqlite3_stmt *stmt;
/* Create SQL statement */
const char* sql = "SELECT * FROM test";
if (sqlite3_prepare_v2(db, sql, -1, &stmt, 0) != SQLITE_OK)
{
return 0;
}
int result = 0;
while (true)
{
result = sqlite3_step(stmt);
if (result == SQLITE_ROW)
{
// Get the size of the vector
int size = sqlite3_column_bytes(stmt, 2);
// Get the pointer to data
long double * p = (long double *)sqlite3_column_blob(stmt,2);
// Initialize the vector with the data
vector<long double> data(p, p+size);
allVects.push_back(data);
}
else
{
//cout << "not SQLITE_ROW" << endl;
break;
}
}
cout<< "before finalzie" << endl;
sqlite3_finalize(stmt);
while(sqlite3_close(db)!= SQLITE_OK) {
cout << "not ok" << endl;
}
cout<< "after close db" << endl;
}
I figured it out by myself. It's because the return type of my function selectTable() is string, however inside function it does not return a string. It's weird that my compiler did not complaint about it tho...
Similar issue is observed when return type of a function is bool and nothing is returned from that function. Even when return type is bool, call stack shows "invalid free" performed on a string. This was quite misleading.
Behavior is undefined when return statement is missing in a function except main().
In my scenario -
Crash is observed when the code is built with g++ version 8.3.0 on debian10(buster slim).
Same code works fine when it is built with g++ version 6.3.0 on debian9(stretch slim).
Developer will be able to detect this during the compile time based on the compiler options enabled. for eg: -Wall
Please note that this is independent of SQLite usage.
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
i have a sqlite3 database and i need to query on it using visual c++ 2013?
i am using sqlite3.h for creating connection an manipulate database;
i am using this code to retraive data :
sqlite3_stmt *stmt;
sqlite3_prepare_v2(db, "SELECT * FROM response where list_id =?", -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, *2*);
tree<SensorState>::iterator itr = sensorTree.begin();
for (;;)
{
int rc = sqlite3_step(stmt);
if (rc == SQLITE_DONE){
break;
}
else if (rc != SQLITE_ROW){
cout << "error in reading sensore with error No: " << rc;
break;
}
const char* name = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 2));
int value = sqlite3_column_int(stmt, 3);
cout << name<< "->" << value <<endl;
}
now in terminal i am getting this outbut:
but it must show this output:
s1->5
s2->2
s4->2
how can i rea string correctly from sqlite3 using c++?
I am developing a multithreaded cpp app that reads data from an sqlite database. I am running into a problem with multithreaded read attempts causing an "unknown error" to be thrown. I assume this has to be something like database locking.
My question is the following - Why does the database lock on read operations? I would understand if it was reading/writing, but this app only executes select statements.
Potential solutions to my problem: Throw some mutexes at the sections, switch from sqlite to some other database..
I realize sqlite is not an incredibly strong database, so am leaning more toward switching to some other database. Any suggestions?
Thanks!
The code:
//generate a db connection//
bool open(string filename){
if(sqlite3_open(filename.c_str(), &database) == SQLITE_OK)
{
return true;
}
return false;
}
//Query database//
vector<vector<string>> query(string query){
sqlite3_stmt *statement;
vector<vector<string>> results;
if(sqlite3_prepare_v2(database, query.c_str(), -1, &statement, 0) == SQLITE_OK)
{
int cols = sqlite3_column_count(statement);
int result = 0;
while(true)
{
result = sqlite3_step(statement);
if(result == SQLITE_ROW)
{
vector<string> values;
for(int col = 0; col < cols; col++)
{
auto temp_val = (char*)sqlite3_column_text(statement, col);
if(!temp_val){
cout << "FAIL" << endl;
}
else{
values.emplace_back(temp_val);
}
}
results.push_back(values);
}
else
{
break;
}
}
sqlite3_finalize(statement);
}
string error = sqlite3_errmsg(database);
if(error != "not an error") cout << query << " " << error << endl;
return results;
}
void close(){
sqlite3_close(database);
}
You say you are using a single connection from multiple threads. This is probably not the best idea, and depending on the options configured in your particular SQLite installation, it may not work at all. For more on this, see here: https://www.sqlite.org/threadsafe.html
As you can see, a full diagnosis of your problem requires looking at how your SQLite package was built...but you can try setting runtime options to see if that helps, as described on the above page.
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.)