SQLiteCpp icon indicating copy to clipboard operation
SQLiteCpp copied to clipboard

dynamically create 'DB' item and use it until close

Open gencer opened this issue 9 years ago • 14 comments

On native sqlite3 library i can assign db object to a class variable and use it in other methods without open everytime.

But with SQLiteC++, I cannot share the object. Assertion or memory errors occured.

All I want create SQLite::Database and assign it to class so the whole class can use the db as needed without explicitly open everytime.

gencer avatar Sep 17 '16 11:09 gencer

Hi, I am not sure of what is the problem you get. Can you share the exact log of assertion or the type of memory errors ?

Are you sharing the Database accross multiple threads? This is not allowed by SQLite itself (at least not with default compile options)

SRombauts avatar Sep 17 '16 12:09 SRombauts

No, Not like that. Let me explain;

class A {
public:
  static void openDb();
  static void insertValue(const char*);
private:
  static SQLite::Database db;
};

void A::openDb() {
  //something like this->db
  db(db_path, params)
}

void A::insertValue(const char *value) {
  //this->db or just db or A::db...
  SQLite::Statement query(db, "insert into...");
}

insertValue does not accept db, db* or &db. It wants me to dynamically open database each time i fire the method.

Hovewer, If i declare db beginning of .cpp file i can use it. But the problem is, my method provides the db file path. so i need to create/open that db somewhere in my method.

gencer avatar Sep 17 '16 12:09 gencer

Okay, what I understand is that you want to open the db dynamically (that is, not in the constructor like in my examples) and then use it many times until closes.

Best way to do this would be to use a pointer to Database.

Let me get back home to make an example for you.

SRombauts avatar Sep 17 '16 12:09 SRombauts

@SRombauts exactly! Thank you for the example. I am awaiting your reply on this.

BTW, For this case, which is more stable or proper? Opening every time and close at the end of execution? Or use it until app gets closed? (DB will be small as few mb's. Rows extensively inserted and deleted.

Note: I also tried this: SQLite::Database db = new SQLite::Database(...); But this time query() method does not accept db item.

gencer avatar Sep 17 '16 12:09 gencer

So, first of all, here is how I use SQLiteCpp usually, with constructors (RAII):


class A {
public:
    A(const char* path);
    void insertValue(const char* value);
private:
    SQLite::Database    db;
    SQLite::Statement   insert;
};

A::A(const char* path) :
    db(path),
    insert(db, "INSERT INTO test VALUES (NULL, ?)")
{
}

void A::insertValue(const char* value)
{
    insert.bind(value);
    insert.exec();
}

int main ()
{
    A a("test.db3") // "CREATE TABLE test (id INTEGER PRIMARY KEY, msg TEXT)";
    a.insertValue("example");
}

SRombauts avatar Sep 17 '16 14:09 SRombauts

And then, an example with dynamic allocation, using shared/unique pointers:


#include <SQLiteCpp/SQLiteCpp.h>

#include <iostream>
#include <memory>

class A {
public:
    void open(const char* path);
    void insertValue(const char* value);

private:
    std::unique_ptr<SQLite::Database>   db;
    std::unique_ptr<SQLite::Statement>  insert;
};

void A::open(const char* path)
{
    db.reset(new SQLite::Database(path));
    insert.reset (new SQLite::Statement(*db, "INSERT INTO test VALUES (NULL, ?)"));
}

void A::insertValue(const char* value)
{
    if (db && insert)
    {
        std::cout << insert->getQuery().c_str() << " with '" << value << "'" << std::endl;
        insert->reset();
        insert->bind(value);
        insert->exec();
    }
}

int main ()
{
    A a;
    a.open("test.db3"); // "CREATE TABLE test (id INTEGER PRIMARY KEY, msg TEXT)";
    a.insertValue("example");
    return EXIT_SUCCESS;
}

All this is untested, no time presently...

SRombauts avatar Sep 17 '16 14:09 SRombauts

@SRombauts above code worked smoothly without single error. I also managed to adapt to my static classes.

Thanks!

gencer avatar Sep 17 '16 18:09 gencer

Very nice, I'll make à real example out of it for everyone else. Cheers !

SRombauts avatar Sep 18 '16 18:09 SRombauts

Just in case anyone needs to do something like this where the SQLite wrapper objects have a lifetime beyond the scope of one method call, I also tried the approach above but I used std::unique_ptr and it seems to work fine. std::unique_ptr suits my needs better in most cases.

gminorcoles avatar Dec 26 '18 03:12 gminorcoles

If I understand correctly, @SRombauts, do you open the db every time you want to make a query? Why not open a db and do inserts, updates and selects, without closing it every time? Is there any downside to keep it open?

pha377 avatar Oct 06 '21 14:10 pha377

If I understand correctly, do you open the db every time you want to make a query? Why not open a db and do inserts, updates and selects, without closing it every time? Is there any downside to keep it open?

Of course not. Only open once at startup then use until connection lost (db is deleted or something went wrong). You should not open db every time unless you have specific use case for it.

gencer avatar Oct 06 '21 14:10 gencer

I've got your point, and I was planning the same, the questions is about the way @SRombauts uses it.

pha377 avatar Oct 06 '21 14:10 pha377

If I understand correctly, @SRombauts, do you open the db every time you want to make a query? No, you can see above (albeit with a very small example) that I open the db once and for all in the main() function. On an other project, I actually close it if unused for some time, and then reopen it on next usage. In all real life example I use unique ptr or "optional" storage

SRombauts avatar Oct 06 '21 15:10 SRombauts

I don't really understand much what you do, because I know very little, however I've just managed to get it to work with unique_ptr. Thanks to smart people like you, more basic people like me can do something more or less useful. Thanks!

pha377 avatar Oct 06 '21 16:10 pha377