I'm having memory management related crashes when using SQLite. It only crashes once every 30 or so tries unless I enable Guard Malloc (a test mode) in Xcode, in which case it crashes the second time I prepare a statement, 100% of the time. I think it has to do with how I'm opening or using the database, but I can't find anything wrong, BUT I'm a newbie with SQLite. Is there anything I'm forgetting?
Wrapper function for opening:
int databaseConnect(sqlite3 **db){
int rc = sqlite3_open_v2(dbURL, db, SQLITE_OPEN_READWRITE, NULL);
if(rc!=SQLITE_OK){
fprintf(stderr, "Can't open database! Error: %s\n", sqlite3_errmsg(*db));
sqlite3_close_v2(*db);
return(SQL_ERROR);
}
return NO_ERROR;
}
Wrapper function for sending commands:
int databaseCommand(char* command, sqlite3* db){
char* error = NULL;
int ret = sqlite3_exec(db, command, NULL, 0, &error);
if (ret!=SQLITE_OK){
printf("SQL command aborted. Error: %s\n", error);
return SQL_ERROR; //EDIT: this will cause the database to close later
}
if (error) sqlite3_free(error);
return NO_ERROR;
}
How I use my opening function:
//ONCE IN MAIN THREAD, BEFORE ANY OTHER THREADS:
sqlite3* db = NULL;
databaseConnect(&db);
//call databaseCommmand a few times while creating tables...
sqlite3_close_v2(db);
//ONCE PER THREAD IN OTHER THREADS:
sqlite3* db = NULL; databaseConnect(&db);
How I use sqlite3_prepare_v2 in my non-main threads (and where it crashes):
struct LinkedList* databaseSelect(char* command, sqlite3* db){
sqlite3_stmt* stmt = NULL;
int retval = retval = sqlite3_prepare_v2(db,command,(strlen(command))*sizeof(char),&stmt,NULL); //crashes here the second time I run it
if(retval!=SQLITE_OK){
printf("Selecting data from database failed! Error: %s\n", sqlite3_errmsg(db));
sqlite3_free(stmt);
return NULL; //EDIT: this will cause the database to close later
}
// Then the function does stuff involving sqlite3_column_text and sqlite3_column_int…
sqlite3_free(stmt);
// return the linked list result
}
The error I get and the part of the SQLite3 library that causes it:
EXC_BAD_ACCESS (code=1) in this part of sqlite3.c:
/*
** Create a new virtual database engine.
*/
SQLITE_PRIVATE Vdbe *sqlite3VdbeCreate(sqlite3 *db){
Vdbe *p;
p = sqlite3DbMallocZero(db, sizeof(Vdbe) );
if( p==0 ) return 0;
p->db = db;
if( db->pVdbe ){
db->pVdbe->pPrev = p; //error is right here; db->pVdbe is pointing to invalid address
}
p->pNext = db->pVdbe;
p->pPrev = 0;
db->pVdbe = p;
p->magic = VDBE_MAGIC_INIT;
return p;
}
Whenever I use sqlite3_column_text, I copy the result immediately. I do not modify the result. In databaseCommand and databaseSelect, char* command is null-terminated and valid (I checked). Each thread uses its own database handle, each connected to the same database. However, in this test case, there is only one thread connected to the database at any given time.
If there really is nothing wrong here, I have to assume that I trampled the memory elsewhere in my program, and I can't find anything in the rest of the program that even looks a bit dangerous. Plus it's suspicious that SQLite is the one thing crashing every time.
The sqlite3_prepare_v2 documentation says:
The calling procedure is responsible for deleting the compiled SQL statement using sqlite3_finalize() after it has finished with it.
sqlite3_free() can be used only for raw memory allocated with sqlite3_alloc(), or when a function such as sqlite3_exec() is documented as requiring it.
Since you are using multiple threads operating on same database just make sure you close and reopen the database from these thread after every operation. You should also try not to neglect the error condition and add the close statement there also as shown below.
if(retval!=SQLITE_OK){
printf("Selecting data from database failed! Error: %s\n", sqlite3_errmsg(db));
sqlite3_free(stmt);
sqlite3_close(your_db_ptr);
......
}
sqlite3_prepare_v2() alone just compiles the SQL but does not run it. Call sqlite3_step() on the compiled statement to run it, or use sqlite3_exec() that combines prepare+step+finalize into one function call. From here.
Hope this helps.
Related
The main goal
I wrote a python simple program that adds a file to the recent files list in GTK3. It gets called when vim opens a file. It's working fine, but vim's startup time is multiplied by 10. Now I'm trying to port it to C so as to improve this flaw. Here is a demo of the python script I'm trying to port :
from gi import require_version
require_version('Gtk', '3.0')
from gi.repository import Gtk
manager = Gtk.RecentManager()
recent_data = Gtk.RecentData()
recent_data.app_name = "vim"
recent_data.mime_type = "text/plain"
recent_data.app_exec = "/usr/bin/vim"
manager.add_full("file:///home/lafleur/tweaks.txt", recent_data)
What I attempted
See the code sample below. It compiles fine, but I get a CRITICAL warning when I run it, and then the process succeeds, but the file doesn't show up in the recent files in Nautilus.
Here is the traceback :
$ ./a.out
adding file:///home/lafleur/tweaks.txt to recent files
(process:17646): GLib-GObject-CRITICAL **: 12:37:32.034: g_object_get: assertion 'G_IS_OBJECT (object)' failed
file added to recent files.
I'm unable to tell what went wrong. I followed docs in GNOME's GTK3 documentation. Those docs state that the mandatory arguments to gtk_recent_manager_add_full () are the gtk_recent_manager, a uri and a GtkRecentData object holding the file's MIME type, the application name and its callback. When compiled, the process complains that it needs an application description, which I added in the sample (see below). I found g_object_get ()'s definition here, but that doesn't give me any clue.
The question
My question is : how can I know what's happening and why the process fails to add the existing /home/lafleur/tweaks.txt to Nautilus' recent files listing ? How can I know what in my code is not a valid GObject ? Did I miss some initialization, as stated in this SO answer ?
Here is the code sample :
#include <gtk/gtk.h>
int main (int argc, char **argv)
{
GtkRecentData recent_data;
GtkRecentManager *manager;
GError *error = NULL;
gchar *uri;
gboolean retval;
uri = g_filename_to_uri ("/home/lafleur/tweaks.txt", NULL, &error);
manager = gtk_recent_manager_get_default ();
if (error) {
g_warning ("%s", error->message);
g_error_free (error);
} else {
recent_data.mime_type = "text/plain";
recent_data.app_name = "vim";
recent_data.app_exec = "/usr/bin/vim";
recent_data.description = "the vim editor";
g_print ("adding %s to recent files\n", uri);
retval = gtk_recent_manager_add_full (
manager,
uri,
&recent_data
);
if (retval == TRUE) {
g_print ("file added to recent files.\n");
} else {
g_warning ("there was a problem.\n");
}
g_free (uri);
}
return retval;
When using GTK API from C, you need to initialize GTK itself, with something like:
gtk_init (&argc, &argv);
where argc and argv are pointers to the arguments counter and vector that you get in your main. If you don't do this, anything that follows is undefined behaviour.
The Python bindings, for reasons of backward compatibility in the days of GTK 1 and 2, call gtk_init() automatically when imported.
Additionally, GtkRecentManager queues updates within the GTK main loop, to coalesce multiple writes into one; this is not normally an issue in GUI applications, but if you're writing a CLI tool, you will need to also spin the main loop until the GtkRecentManager emits the "changed" signal.
Your program will work once you modify it to call gtk_init() first, and then spin the main loop until the write is done, e.g.:
#include <stdlib.h>
#include <gtk/gtk.h>
int main (int argc, char **argv)
{
GError *error = NULL;
char *uri = g_filename_to_uri ("/home/lafleur/tweaks.txt", NULL, &error);
// Bail out early in case of error
if (error != NULL) {
g_warning ("%s", error->message);
g_error_free (error);
return EXIT_FAILURE;
}
// You can pass (NULL, NULL) if you don't have arguments; if you
// want to deal with the possibility of not having a display
// connection, you can use gtk_init_check() instead.
gtk_init (&argc, &argv);
// Create the recent manager
GtkRecentManager *manager = gtk_recent_manager_get_default ();
// Create a main loop; the recent manager will schedule writes
// within the loop, so it can coalesce multiple operations.
GMainLoop *loop = g_main_loop_new (NULL, FALSE);
// Once we receive the "changed" signal from the recent manager
// we stop the main loop; we use the "swapped" variant so that
// the callback will be invoked with the signal's user data
// as the first argument; in this case, we're going to call
// g_main_loop_quit() on the loop object
g_signal_connect_swapped (manager, "changed",
G_CALLBACK (g_main_loop_quit),
loop);
GtkRecentData recent_data = {
.mime_type = "text/plain",
.app_name = "vim",
// The "app_exec" key should be the command line needed to open
// the file you're adding; the %f escape sequence means "use the
// path of the file", whereas the %U escape sequence means "use
// the URL of the file".
.app_exec = "/usr/bin/vim %f",
.description = "the vim editor",
};
g_print ("adding %s to recent files\n", uri);
gboolean retval = gtk_recent_manager_add_full (
manager,
uri,
&recent_data
);
// Never compare boolean values for equality; gboolean is an int-sized
// type, which means anything that is not FALSE/0 will have a TRUE value
if (retval) {
g_print ("file added to recent files.\n");
} else {
g_warning ("there was a problem.\n");
}
g_free (uri);
// Start the loop; this will block until GtkRecentManager emits the
// "changed" signal, telling us the the recently used files list has
// been updated
g_main_loop_run (loop);
// Use standard exit codes
return retval ? EXIT_SUCCESS : EXIT_FAILURE;
}
Since you must call gtk_init(), you will need a connection to your display server; this means you cannot run this program under a pure virtual terminal outside of your graphical session. If you need to do that, you will need to write your own "recent manager", using the GBookmarkFile API, which is the same API GTK uses internally. The GBookmarkFile API is definitely more low level, though, and it requires you understand the file format and location used for the recently used files.
I'm trying to link sqlite3 library to CMakeList in Clion using the following code:
find_package(SQLite3)
target_link_libraries(IIWProject SQLite::SQLite3)
Library has been loaded but when i Run the code, Clion shows the following error:
SQL logic error
The database has been loaded but when sqlite3_prepare_v2(db, query, -1, &stmt, NULL) was called return SQL logic error
void get_db(sqlite3 **db){
int rc;
if ((rc = sqlite3_open("db_project.db", db)) != SQLITE_OK){
//fprintf(stderr, "Failed to open DB.\n");
fprintf(stderr,"Failed to open DB: %s\n\r", sqlite3_errstr(rc));
exit(EXIT_FAILURE);
}
}
int clear_table(sqlite3 *db){
sqlite3_stmt *stmt;
int rc;
char* query = "DELETE FROM resources";
if ((rc=sqlite3_prepare_v2(db, query, -1, &stmt, NULL)) != SQLITE_OK){
fprintf(stderr,"Failed to prepare statement: %s\n\r", sqlite3_errstr(rc));
return 1;
}
if ((rc = sqlite3_step(stmt)) != SQLITE_DONE){
fprintf(stderr,"Delete failed: %s\n\r", sqlite3_errstr(rc));
return 1;
}
return 0;
}
How can I try to fix it?
EDIT:
If I compile, without Clion manually, with gcc -lsqlite3,it work
Now that we've established that the table doesn't exist when you run your program though your IDE...
The current working directory when you run your program through a command line is different than the current working directory your IDE runs it in. Since you're using a relative path to the database file, this means you're using a different one depending on how you run your program. Only one of the databases actually has the table(s) you're trying to use.
Some solutions:
Use an absolute path to the database.
Configure your IDE to use the same working directory as when you're running your program through a command line.
Trying to truncate table but the output is Segmentation fault (core dumped).
Following is my code to truncate.
Table Name : DEPO
Since the function del_depo_data is called from different place and database is opened from where it is called so, didn't write the code to open open DB.
void del_depo_data()
{
sqlite3 *db;
char *zErrMsg = 0;
int rc;
char *sql;
sqlite3_stmt *res;
const char* data = "Callback function called";
/* Create merged SQL statement */
sql = "DELETE FROM TABLE DEPO";
rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
sqlite3_close(db);
return;
}
Solved.
Need to Open the DB inside the del_depo_data().
In the SQL Query there is a syntactical error.
Delete from DEPO will be there.
Since the function del_depo_data is called from different place and database is opened from where it is called so, didn't write the code to open open DB.
If you've opened a database somewhere else in your code, you need to pass the database handle (the sqlite3 *) to this function somehow. As it stands, you're declaring a local variable sqlite3 *db, but never initializing it to any value. This causes SQLite to crash.
Additionally, DELETE FROM TABLE tablename is not a valid SQLite syntax. The correct syntax is simply DELETE FROM tablename.
I know there have been questions asked before about this problem but none seem to shine a light on my problem which is, I am trying to compile a C application and want to access SQLite from within the code (as per test app below) using Eclips as a compile and debugging environment.
I know the .h files are being accessed. the code has as many lines commented out to do with iostream as I have tried to compile this as a C++ app as well.
I get errors one for each of 2 the SQL API.
The real question is do I have to set and How do I set a dependency in Eclipse to allow the api to resolve. Thanks
the code
#include <sqlite3.h>
int main()
{
int RetVal;
RetVal = OpenDB();
return RetVal;
}
int OpenDB()
{
sqlite3 *db; // database connection
int rc; // return code
char *errmsg; // pointer to an error string
/*
* open SQLite database file test.db
* use ":memory:" to use an in-memory database
*/
rc = sqlite3_open(":memory:", &db); //fails on this line
if (rc != SQLITE_OK)
{
goto out;
}
/* use the database... */
out:
/*
* close SQLite database
*/
sqlite3_close(db); //fails on this line
return 0;
}
You need to link the sqlite3 library along with your program:
gcc main.c -lsqlite3
I'm using SQLite 3 in a C application of mine. It has worked like a charm up until now, when I've started to write unit tests. The function in question is a pretty small. It opens an in-memory database, prepares a statement and then does some stuff with it. Problem is that the app crashes with a segmentation fault at the sqlite3_prepare_v2 function call. I've tried to debug it and check to see that all arguments are valid, which they seem to be.
Below, I've pasted a minimal example which causes segfault in the same way. The backtrace lists sqlite3LockAndPrepare as the function where it crashes (called by sqlite3_prepare_v2).
As I mentioned above, I use SQLite without any problems in the rest of my app. I just can't figure out what the difference in usage is, since it's split up in several different routines which also does other stuff. The one thing I can spot is the use of an in-memory database instead of on-disk, but I tried with it on disk, and it made no difference.
#include <stdlib.h>
#include <stdio.h>
#include <sqlite3.h>
int main(void)
{
sqlite3 *db;
sqlite3_stmt **stmt;
const char *str = "CREATE TABLE Test (t1 varchar(8) NOT NULL);";
if (SQLITE_OK != sqlite3_open(":memory:", &db)) {
printf("Can't open...\n");
return 1;
}
sqlite3_prepare_v2(db, str, -1, stmt, NULL);
return 0;
}
The fourth argument to sqlite3_prepare_v2() is supposed to be a valid pointer to an sqlite3_stmt *. You are instead passing an undefined value (since your variable stmt is never initialized). (Note, too, that even if that did not crash the program, you could not receive a pointer to the prepared statement that way.)
You should do this, instead:
int main(void)
{
sqlite3 *db;
sqlite3_stmt *stmt;
const char *str = "CREATE TABLE Test (t1 varchar(8) NOT NULL);";
/* ... create database ... */
sqlite3_prepare_v2(db, str, -1, &stmt, NULL);
return 0;
}