The C++14 wrapper around sqlite library

Build Status

sqlite modern cpp wrapper

This library is a lightweight modern wrapper around sqlite C api .

#include<iostream>
#include <sqlite_modern_cpp.h>
using namespace  sqlite;
using namespace std;

int main() {

   try {
      // creates a database file 'dbfile.db' if it does not exists.
      database db("dbfile.db");

      // executes the query and creates a 'user' table
      db <<
         "create table if not exists user ("
         "   _id integer primary key autoincrement not null,"
         "   age int,"
         "   name text,"
         "   weight real"
         ");";

      // inserts a new user record.
      // binds the fields to '?' .
      // note that only types allowed for bindings are :
      //      int ,long, long long, float, double
      //      string , u16string
      // sqlite3 only supports utf8 and utf16 strings, you should use std::string for utf8 and std::u16string for utf16.
      // note that u"my text" is a utf16 string literal of type char16_t * .
      db << "insert into user (age,name,weight) values (?,?,?);"
         << 20
         << u"bob"
         << 83.25;

      int age = 21;
      float weight = 68.5;
      string name = "jack";
      db << u"insert into user (age,name,weight) values (?,?,?);" // utf16 query string
         << age
         << name
         << weight;

      cout << "The new record got assigned id " << db.last_insert_rowid() << endl;

      // slects from user table on a condition ( age > 18 ) and executes
      // the lambda for each row returned .
      db << "select age,name,weight from user where age > ? ;"
         << 18
         >> [&](int age, string name, double weight) {
            cout << age << ' ' << name << ' ' << weight << endl;
         };

      // selects the count(*) from user table
      // note that you can extract a single culumn single row result only to : int,long,long,float,double,string,u16string
      int count = 0;
      db << "select count(*) from user" >> count;
      cout << "cout : " << count << endl;

      // you can also extract multiple column rows
      db << "select age, name from user where _id=1;" >> tie(age, name);
      cout << "Age = " << age << ", name = " << name << endl;

      // this also works and the returned value will be automatically converted to string
      string str_count;
      db << "select count(*) from user" >> str_count;
      cout << "scount : " << str_count << endl;
   }
   catch (exception& e) {
      cout << e.what() << endl;
   }
}

You can not execute multiple statements separated by semicolons in one go.

Additional flags

You can pass additional open flags to SQLite by using a config object:

sqlite_config config;
config.flags = OpenFlags::READONLY
database db("some_db", config);
int a;
// Now you can only read from db
auto ps = db << "select a from table where something = ? and anotherthing = ?" >> a;
config.flags = OpenFlags::READWRITE | OpenFlags::CREATE; // This is the default
config.encoding = Encoding::UTF16; // The encoding is respected only if you create a new database
database db2("some_db2", config);
// If some_db2 didn't exists before, it will be created with UTF-16 encoding.

Prepared Statements

It is possible to retain and reuse statments this will keep the query plan and in case of an complex query or many uses might increase the performance significantly.

database db(":memory:");

// if you use << on a sqlite::database you get a prepared statment back
// this will not be executed till it gets destroyed or you execute it explicitly
auto ps = db << "select a,b from table where something = ? and anotherthing = ?"; // get a prepared parsed and ready statment

// first if needed bind values to it
ps << 5;
int tmp = 8;
ps << tmp;

// now you can execute it with `operator>>` or `execute()`.
// If the statement was executed once it will not be executed again when it goes out of scope.
// But beware that it will execute on destruction if it wasn't executed!
ps >> [&](int a,int b){ ... };

// after a successfull execution the statment can be executed again, but the bound values are resetted.
// If you dont need the returned values you can execute it like this
ps++; // Does reset the bound values
// or like this
ps.execute(); // Does NOT reset the bound values, but we can reset them manually:
ps.reset();

// To disable the execution of a statment when it goes out of scope and wasn't used
ps.used(true); // or false if you want it to execute even if it was used

// Usage Example:

auto ps = db << "insert into complex_table_with_lots_of_indices values (?,?,?)";
int i = 0;
while( i < 100000 ){
   ps << long_list[i++] << long_list[i++] << long_list[i++];
   ps++; // Equal to: ps.execute(); ps.reset();
}

Shared Connections

If you need the handle to the database connection to execute sqlite3 commands directly you can get a managed shared_ptr to it, so it will not close as long as you have a referenc to it.

Take this example on how to deal with a database backup using SQLITEs own functions in a safe and modern way.

try {
   database backup("backup");		//Open the database file we want to backup to

   auto con = db.connection();   // get a handle to the DB we want to backup in our scope
                                 // this way we are sure the DB is open and ok while we backup

   // Init Backup and make sure its freed on exit or exceptions!
   auto state =
      std::unique_ptr<sqlite3_backup,decltype(&sqlite3_backup_finish)>(
      sqlite3_backup_init(backup.connection().get(), "main", con.get(), "main"),
      sqlite3_backup_finish
      );

   if(state) {
      int rc;
      // Each iteration of this loop copies 500 database pages from database db to the backup database.
      do {
         rc = sqlite3_backup_step(state.get(), 500);
         std::cout << "Remaining " << sqlite3_backup_remaining(state.get()) << "/" << sqlite3_backup_pagecount(state.get()) << "\n";
      } while(rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED);
   }
} // Release allocated resources.

Transactions

You can use transactions with begin;, commit; and rollback; commands.

db << "begin;"; // begin a transaction ...   
db << "insert into user (age,name,weight) values (?,?,?);"
   << 20
   << u"bob"
   << 83.25f;
db << "insert into user (age,name,weight) values (?,?,?);" // utf16 string
   << 21
   << u"jack"
   << 68.5;
db << "commit;"; // commit all the changes.

db << "begin;"; // begin another transaction ....
db << "insert into user (age,name,weight) values (?,?,?);" // utf16 string
   << 19
   << u"chirs"
   << 82.7;
db << "rollback;"; // cancel this transaction ...

Blob

Use std::vector<T> to store and retrieve blob data.
T could be char,short,int,long,long long, float or double.

db << "CREATE TABLE person (name TEXT, numbers BLOB);";
db << "INSERT INTO person VALUES (?, ?)" << "bob" << vector<int> { 1, 2, 3, 4};
db << "INSERT INTO person VALUES (?, ?)" << "sara" << vector<double> { 1.0, 2.0, 3.0, 4.0};

vector<int> numbers_bob;
db << "SELECT numbers from person where name = ?;" << "bob" >> numbers_bob;

db << "SELECT numbers from person where name = ?;" << "sara" >> [](vector<double> numbers_sara){
    for(auto e : numbers_sara) cout << e << ' '; cout << endl;
};

NULL values

If you have databases where some rows may be null, you can use std::unique_ptr<T> to retain the NULL values between C++ variables and the database.

db << "CREATE TABLE tbl (id integer,age integer, name string, img blob);";
db << "INSERT INTO tbl VALUES (?, ?, ?, ?);" << 1 << 24 << "bob" << vector<int> { 1, 2 , 3};
unique_ptr<string> ptr_null; // you can even bind empty unique_ptr<T>
db << "INSERT INTO tbl VALUES (?, ?, ?, ?);" << 2 << nullptr << ptr_null << nullptr;

db << "select age,name,img from tbl where id = 1"
		>> [](unique_ptr<int> age_p, unique_ptr<string> name_p, unique_ptr<vector<int>> img_p) {
			if(age_p == nullptr || name_p == nullptr || img_p == nullptr) {
				cerr << "ERROR: values should not be null" << std::endl;
			}

			cout << "age:" << *age_p << " name:" << *name_p << " img:";
			for(auto i : *img_p) cout << i << ","; cout << endl;
		};

db << "select age,name,img from tbl where id = 2"
		>> [](unique_ptr<int> age_p, unique_ptr<string> name_p, unique_ptr<vector<int>> img_p) {
			if(age_p != nullptr || name_p != nullptr || img_p != nullptr) {
				cerr << "ERROR: values should be nullptr" << std::endl;
				exit(EXIT_FAILURE);
			}

			cout << "OK all three values are nullptr" << endl;
		};

SQLCipher

We have native support for SQLCipher. If you want to use encrypted databases, include the sqlite_moder_cpp/sqlcipher.h header. Then create a sqlcipher_database instead.

#include<iostream>
#include <sqlite_modern_cpp/sqlcipher.h>
using namespace sqlite;
using namespace std;

int main() {
   try {
      // creates a database file 'dbfile.db' if it does not exists with password 'secret'
      sqlcipher_config config;
      config.key = secret;
      sqlcipher_database db("dbfile.db", config);

      // executes the query and creates a 'user' table
      db <<
         "create table if not exists user ("
         "   _id integer primary key autoincrement not null,"
         "   age int,"
         "   name text,"
         "   weight real"
         ");";

      // More queries ...
      db.rekey("new_secret"); // Change the password of the already encrypted database.

      // Even more queries ..
   }
   catch (exception& e) { cout << e.what() << endl; }
}

NULL values (C++17)

You can use std::optional<T> as an alternative for std::unique_ptr<T> to work with NULL values.

#include <sqlite_modern_cpp.h>

struct User {
   long long _id;
   std::optional<int> age;
   std::optional<string> name;
   std::optional<real> weight;
};

int main() {
   User user;
   user.name = "bob";

   // Same database as above
   database db("dbfile.db");

   // Here, age and weight will be inserted as NULL in the database.
   db << "insert into user (age,name,weight) values (?,?,?);"
      << user.age
      << user.name
      << user.weight;
   user._id = db.last_insert_rowid();

   // Here, the User instance will retain the NULL value(s) from the database.
   db << "select _id,age,name,weight from user where age > ? ;"
      << 18
      >> [&](long long id,
         std::optional<int> age,
         std::optional<string> name
         std::optional<real> weight) {

      cout << "id=" << _id
         << " age = " << (age ? to_string(*age) ? string("NULL"))
         << " name = " << (name ? *name : string("NULL"))
         << " weight = " << (weight ? to_string(*weight) : string(NULL))
         << endl;
   };
}

If you do not have C++17 support, you can use boost optional instead by defining _MODERN_SQLITE_BOOST_OPTIONAL_SUPPORT before importing the sqlite_modern_cpp header.

If the optional library is not available, the experimental/optional one will be used instead.

Note: boost support is deprecated and will be removed in future versions.

Variant type support (C++17)

If your columns may have flexible types, you can use C++17's std::variant to extract the value.

db << "CREATE TABLE tbl (id integer, data);";
db << "INSERT INTO tbl VALUES (?, ?);" << 1 << vector<int> { 1, 2, 3};
db << "INSERT INTO tbl VALUES (?, ?);" << 2 << 2.5;

db << "select data from tbl where id = 1"
		>> [](std::variant<vector<int>, double> data) {
			if(data.index() != 1) {
				cerr << "ERROR: we expected a blob" << std::endl;
			}

			for(auto i : get<vector<int>>(data)) cout << i << ","; cout << endl;
		};

db << "select data from tbl where id = 2"
		>> [](std::variant<vector<int>, double> data) {
			if(data.index() != 2) {
				cerr << "ERROR: we expected a real number" << std::endl;
			}

			cout << get<double>(data) << endl;
		};

If you read a specific type and this type does not match the actual type in the SQlite database, yor data will be converted. This does not happen if you use a variant. If the variant does an alternative of the same value type, an mismatch exception will be thrown. The value types are NULL, integer, real number, text and BLOB. To support all possible values, you can use variant<nullptr_t, sqlite_int64, double, string, vector<char>.

Errors

On error, the library throws an error class indicating the type of error. The error classes are derived from the SQLITE3 error names, so if the error code is SQLITE_CONSTRAINT, the error class thrown is sqlite::errors::constraint. SQLite3 extended error names are supported too. So there is e.g. a class sqlite::errors::constraint_primarykey derived from sqlite::errors::constraint. Note that all errors are derived from sqlite::sqlite_exception and that itself is derived from std::runtime_exception. sqlite::sqlite_exception has a get_code() member function to get the SQLITE3 error code or get_extended_code() to get the extended error code. Additionally you can use get_sql() to see the SQL statement leading to the error.

database db(":memory:");
db << "create table person (id integer primary key not null, name text);";

try {
   db << "insert into person (id, name) values (?,?)" << 1 << "jack";
   // inserting again to produce error
   db << "insert into person (id, name) values (?,?)" << 1 << "jack";
}
/* if you are trying to catch all sqlite related exceptions
 * make sure to catch them by reference */
catch (sqlite_exception& e) {
   cerr  << e.get_code() << ": " << e.what() << " during "
         << e.get_sql() << endl;
}
/* you can catch specific exceptions as well,
   catch(sqlite::errors::constraint e) {  } */
/* and even more specific exceptions
   catch(sqlite::errors::constraint_primarykey e) {  } */

You can also register a error logging function with sqlite::error_log. The <sqlite_modern_cpp/log.h> header has to be included to make this function available. The call to sqlite::error_log has to be the first call to any sqlite_modern_cpp function by your program.

error_log(
   [&](sqlite_exception& e) {
      cerr  << e.get_code() << ": " << e.what() << endl;
   },
   [&](errors::misuse& e) {
      /* You can behave differently to specific errors */
   }
);
database db(":memory:");
db << "create table person (id integer primary key not null, name text);";

try {
   db << "insert into person (id, name) values (?,?)" << 1 << "jack";
   // inserting again to produce error
   db << "insert into person (id, name) values (?,?)" << 1 << "jack";
}
catch (sqlite_exception& e) {}

Custom SQL functions

To extend SQLite with custom functions, you just implement them in C++:

database db(":memory:");
db.define("tgamma", [](double i) {return std::tgamma(i);});
db << "CREATE TABLE numbers (number INTEGER);";

for(auto i=0; i!=10; ++i)
   db << "INSERT INTO numbers VALUES (?);" << i;

db << "SELECT number, tgamma(number+1) FROM numbers;" >> [](double number, double factorial) {
   cout << number << "! = " << factorial << '\n';
};

NDK support

Just Make sure you are using the full path of your database file : sqlite::database db("/data/data/com.your.package/dbfile.db").

Building and Installing

The usual way works for installing:

./configure && make && sudo make install

Note, there's nothing to make, so you there's no need to run configure and you can simply point your compiler at the hdr/ directory.

Breaking Changes

See breaking changes documented in each Release.

Package managers

Pull requests are welcome 😉

License

MIT license - http://www.opensource.org/licenses/mit-license.php

Comments
  • Removed potentially-misleading dead code and comment

    Removed potentially-misleading dead code and comment

    Since ptr is being passed by value to the lambda expression, setting ptr to null will have no effect past that single line.

    The combination of the code and the comment which implies there is an additional benefit/security in doing so might mislead a maintainer or developer down the road.

  • Ability to specify blob data

    Ability to specify blob data

    I'm in the middle of reading the code and understanding it but it's taking some time.

    But I've gotten far enough to have some questions. I want an easy way to use this wrapper to handle blobs. It seems challenging because is_sqlite_value isn't true for pointer types and furthermore I am not sure how it would work. I guess passing in a tuple of a pointer type and a byte count would suffice.

    Does that make sense for the way to extend this so it can be done?

  • Exceptions

    Exceptions

    Hi,

    now that we have the stuff from @KnairdA (thx) i would like to purpose some changes ;)

    First i would like to introduce a new exception and then i would like to make it easier to decide if it is a error or a suggestion.

    I have a exception that is thrown in _extract if the query did not return a row but a function was given to handle one. The purpose of this is to make sure that the function was called or that vales are realy assigned to the "output" variables.

    But in other cases it might not be a error that nothing is returned, so i made it a 'sqlite::data_exception' and if its handled properly it can be ignored. I did the same to the "not all rows handled" exception.

    Do you think it fits the spirit of this lib? And if so should we convert the std::runtime_error for sql errors to a special exception, too?

  • Support explicit insertion of boost::none

    Support explicit insertion of boost::none

    It would be useful to support explicitly inserting NULL values by writing boost::none, like this:

    db << "INSERT INTO foo(field) VALUES (?)" << boost::none;
    

    Currently this does not work because boost::none is a special type, and not automatically converted to any of the overloads for boost::optional.

  • Can't Debug Under GDB

    Can't Debug Under GDB

    Guys, I decided to use sqlite_modern_cpp libarary in my project, but i came across with one problem, i can't debug with GDB, i'm using NetBeans on cross compilation with a beaglebone black. The compilation process and execution works fine, but when i try to debug with gdb, it returns a SIGSEV or a SIGILL, that only happens with the sqlite_modern_cpp library, any idea ?

  • invalid operands to binary expression

    invalid operands to binary expression

    I pulled the latest source code, still no luck. I use Qt5.4.1 on OSX10.10. The test code is still from README file. The source code:

             db << "insert into user (age,name,weight) values (?,?,?);"
                 << 20      // <-- here is the error line indicated by QtCreator.
                 << u"bob" // utf16 string
                 << 83.25f;
    

    The compiling errors:

    ../UseSqlModernCpp/util.cpp:40:14: error: invalid operands to binary expression ('sqlite::database_binder' and 'int')
                 << 20
                 ^  ~~
    ../UseSqlModernCpp/sqlite_modern_cpp.h:258:29: note: candidate function [with T = int] not viable: expects an l-value for 1st argument
    template<> database_binder& operator <<(database_binder& db, const int& val) {
                                ^
    ../UseSqlModernCpp/util.cpp:45:14: error: invalid operands to binary expression ('sqlite::database_binder' and 'int')
                 << 21
                 ^  ~~
    ../UseSqlModernCpp/sqlite_modern_cpp.h:258:29: note: candidate function [with T = int] not viable: expects an l-value for 1st argument
    template<> database_binder& operator <<(database_binder& db, const int& val) {
                                ^
    ../UseSqlModernCpp/util.cpp:54:14: error: invalid operands to binary expression ('sqlite::database_binder' and 'int')
                 << 18
                 ^  ~~
    ../UseSqlModernCpp/sqlite_modern_cpp.h:258:29: note: candidate function [with T = int] not viable: expects an l-value for 1st argument
    template<> database_binder& operator <<(database_binder& db, const int& val) {
                                ^
    3 errors generated.
    make: *** [util.o] Error 1
    14:20:12: The process "/usr/bin/make" exited with code 2.
    Error while building/deploying project UseSqlModernCpp (kit: Desktop Qt 5.4.1 clang 64bit)
    

    There are many other warnings, I eliminated them via removing 'using namespace ' lines. It seems that database_binder's operator<< is mixed (or polluted) with std::ostream's operator<< each other when "using namespace" lines are used.

  • No write actions possible from try-catch block

    No write actions possible from try-catch block

    Opening multiple databases prohibits INSERT operations on the db opened last. There are no errors thrown, the INSERT is just never performed.

    Is this an intended behaviour? I planned to open the second database for logging purposes.

    This is happening on a ubuntu 15.10 machine with clang++-3.7 as compiler (and -std=c++14).

  • UTF-16 vs UTF-8 encodings

    UTF-16 vs UTF-8 encodings

    While convenient for windows users, UTF-16 is, generally speaking, less convenient from a portability point of view. On Linux UTF-8 is more common. Not sure about MacOS.

    Currently, sqlite_modern_cpp prefers to use UTF-16 everywhere, from filenames to database encoding and stored strings themselves, and tries to convert from "standard" encoding to u16string using it's iterator construtor.

    There are a few shortcomings from these decisions, some of which are manageable and some I consider to be bugs. Let's see:

    1. From sqlite wording, regarding database creation: "The default encoding will be UTF-8 for databases created using sqlite3_open() or sqlite3_open_v2(). The default encoding for databases created using sqlite3_open16() will be UTF-16 in the native byte order." And from pragma encoding docs: "Once an encoding has been set for a database, it cannot be changed". The main concern here is that even windows users might prefer the database to store data in utf-8 as most strings are single-byte representable and storing them in UTF-16 takes more disk space. The ideal scenario would be for the user to select the database encoding at database creation time. I do believe (didn't test) that there's still time for user to run db << "PRAGMA encoding = "UTF-8""; right after opening the database for the first time, as sqlite uses deferred creation - but this should be documented anyway.

    2. In several instances, from accepting the database name in constructor to sending strings to sqlite api, there's a std::string -> std::u16string conversion using u16string's constructor that accepts a char-by-char iterator, as in std::u16string(orig.begin(), orig.end()). The problem is that std::string charset is undefined, and unsafe for anything other than ASC-II, so while std::string could be e.g. utf8 (as in Linux, depending on user locale), it maybe anything on windows, from CP_ACP to CP_OEMCP), and storing one and retrieving other may lead to hard to track problems. I'm not sure which would be best here: to have explicit std::u8string overloads which pass utf8 direct to sqlite (which happily expects utf-8), or fix the conversions to utf16 (I don't think using std::u8string and iterators is enough for converting, from what I've read, something like std::wstring_convert or std::codecvt_utf8 might be required). I'm also not sure what to assume with standard std::string .

    While the code simply works for most scenarios, specially when the language is english and no special chars are involved, these are serious concerns for i18n-aware applications. Also, my programs all uses utf-8 with multibyte chars and it seems to work - but I didn't conduce enough tests to see if sqlite is handling the queries correctly, i.e. if it's matching the text as it should). Perhaps I'm wrong and std::u16string(u8str.begin(), u8str.end()) actually converts the encoding - but I didn't find any docs suggesting so.

    Sorry to put so many points in a single report, but I think these can be further distilled on the discussion.

  • Error with lots of arguments

    Error with lots of arguments

    From @hanito:

    Hello Again sorry for the problems, excuse me I always bring problems. Hope that they are helping lol . Can you help me please. I created the following table:


    CREATE TABLE IF NOT EXISTS ENTITE_CANDIDATE (ID INTEGER PRIMARY KEY NOT NULL, ID_KBP TEXT NOT NULL, wiki_title TEXT, type TEXT NOT NULL, NOM TEXT NOT NULL, CLASSE TEXT, wikiPageInLinkCountCleaned TEXT, wikiPageRank TEXT, wikiHITS TEXT, wikiPageOutLinkCountCleaned TEXT, TFIDF TEXT);"
    

    When I want to retrieve the informations by using the following query i get the following error:

    db << "SELECT * FROM ENTITE_CANDIDATE WHERE ID =? ;"
                             << ids.first
                             >> [& ](int id, string id_kbp, string wiki_title, string type, string name, string classe, string wikiPageInLinkCountCleaned, string wikiPageRank, string wikiHITS, string wikiPageOutLinkCountCleaned, string tfidf)
                          {
                              cout <<" ==> " << tfidf << endl;
                          };
    
    ||=== Build: Debug in entityLinking (compiler: GNU GCC Compiler) ===|
    /home/hani/Documents/articles/Architecture/Modules/entityLinking/3rdparty/sqlite_modern_cpp.h||In instantiation of ‘sqlite::database_binder::operator>>(FUNC) [with FUNC = LinkEntities::link()::__lambda9]::__lambda6’:|
    /home/hani/Documents/articles/Architecture/Modules/entityLinking/3rdparty/sqlite_modern_cpp.h|215|required from ‘struct sqlite::database_binder::operator>>(FUNC) [with FUNC = LinkEntities::link()::__lambda9]::__lambda6’|
    /home/hani/Documents/articles/Architecture/Modules/entityLinking/3rdparty/sqlite_modern_cpp.h|214|required from ‘void sqlite::database_binder::operator>>(FUNC) [with FUNC = LinkEntities::link()::__lambda9]’|
    /home/hani/Documents/articles/Architecture/Modules/entityLinking/LinkEntities.cpp|86|required from here|
    /home/hani/Documents/articles/Architecture/Modules/entityLinking/3rdparty/sqlite_modern_cpp.h|38|error: ‘static void sqlite::binder<N>::run(sqlite::database_binder&, F) [with F = LinkEntities::link()::__lambda9; int N = 11]’ is private|
    /home/hani/Documents/articles/Architecture/Modules/entityLinking/3rdparty/sqlite_modern_cpp.h|215|error: within this context|
    /home/hani/Documents/articles/Architecture/Modules/entityLinking/3rdparty/sqlite_modern_cpp.h|38|error: ‘static void sqlite::binder<N>::run(sqlite::database_binder&, F) [with F = LinkEntities::link()::__lambda9; int N = 11]’, declared using local type ‘LinkEntities::link()::__lambda9’, is used but never defined [-fpermissive]|
    /usr/include/c++/4.8/functional|2443|error: ‘std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = sqlite::database_binder::operator>>(FUNC) [with FUNC = LinkEntities::link()::__lambda9]::__lambda6; <template-parameter-2-2> = void; _Res = void; _ArgTypes = {}]’, declared using local type ‘sqlite::database_binder::operator>>(FUNC) [with FUNC = LinkEntities::link()::__lambda9]::__lambda6’, is used but never defined [-fpermissive]|
    ||=== Build failed: 4 error(s), 4 warning(s) (0 minute(s), 3 second(s)) ===|
    
  • Alternative iterator interface

    Alternative iterator interface

    I think this feels more natural than the interface from #103 and it makes lifetime questions easier. The database_binder behaves like a container now:

    for(auto &&row : db << "select age,name,weight from user where age > ? ;" << 21) {
      int _age;
      string _name;
      double _weight;
      row >> _age >> _name >> _weight;
      cout << _age << ' ' << _name << ' ' << _weight << endl;
    }
    // or
    for(std::tuple<int, string, double> row : db << "select age,name,weight from user where age > ? ;" << 21) {
      cout << std::get<int>(row) << ' ' << std::get<string>(row) << ' ' << std::get<double>(row) << endl;
    }
    

    @Killili What do you think? It's not our usual stream-op interface, but I think this makes it clearer that the range doesn't exists independent from the statement.

  • get_sql() returns empty string

    get_sql() returns empty string

    I'm creating and using a prepared statement auto ps = db << 'select field from mytable'; etc, For testing I changed the field name to an incorrect value. An exception was correctly thrown. However get_sql() returned an empty string.

    Am I missing something?

  • with C++20

    with C++20

    VS2019, use C++20: std::is_pod_v can't be used, compilation failed. And in VS2019, use C++17: need to #define _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS, otherwise compilation failed. Looking forward to updating,thanks.

  • Usage of `std::optional` fails under MSVC 14.2 / VS 2019

    Usage of `std::optional` fails under MSVC 14.2 / VS 2019

    Usage of std::optional and the << operator will compile fine with gcc/linux but will fail with a template error when tried to be compiled with MSVC 14.2/ Visual Studio 2019:

    I prepared a simple code and project to reproduce it:

    either

    git clone https://github.com/Superlokkus/bug_demo.git 
    cd bug_demo
    git submodule update --init --recursive
    mkdir bin
    cd bin
    cmake ..
    cmake --build .
    

    or look simple code is:

    void insert_data() {
        long id {1337};
        auto opt_field = std::optional<double>(4.2);
        auto db = get_database();
    
        db << "insert or replace into test(id,opt_field) values (?,?);"
        << id << opt_field;
    }
    

    will fail with

    C:\Users\markus\develop\bug_demo\vendor\sqlite_modern_cpp\hdr\sqlite_modern_cpp.h(905,90): error C2678: binary '<<': no operator found which takes a left-hand operand of type 'sqlite::database_binder' (or there is no acceptable conversion) [C:\Users\markus\develop\bug_demo\bin\bug_demo.vcxproj] C:\Users\markus\develop\bug_demo\vendor\sqlite_modern_cpp\hdr\sqlite_modern_cpp.h(765,27): message : could be 'sqlite::database_binder &sqlite::operator <<(sqlite::database_binder &,const std::u16string &)' [C:\Users\markus\develop\bug_demo\bin\bug_demo.vcxproj] C:\Users\markus\develop\bug_demo\vendor\sqlite_modern_cpp\hdr\sqlite_modern_cpp.h(735,27): message : or 'sqlite::database_binder &sqlite::operator <<(sqlite::database_binder &,const std::string &)' [C:\Users\markus\develop\bug_demo\bin\bug_demo.vcxproj] C:\Users\markus\develop\bug_demo\vendor\sqlite_modern_cpp\hdr\sqlite_modern_cpp.h(613,27): message : or 'sqlite::database_binder &sqlite::operator <<(sqlite::database_binder &,const double &)' [C:\Users\markus\develop\bug_demo\bin\bug_demo.vcxproj] C:\Users\markus\develop\bug_demo\vendor\sqlite_modern_cpp\hdr\sqlite_modern_cpp.h(586,27): message : or 'sqlite::database_binder &sqlite::operator <<(sqlite::database_binder &,const float &)' [C:\Users\markus\develop\bug_demo\bin\bug_demo.vcxproj] C:\Users\markus\develop\bug_demo\vendor\sqlite_modern_cpp\hdr\sqlite_modern_cpp.h(559,27): message : or 'sqlite::database_binder &sqlite::operator <<(sqlite::database_binder &,const sqlite_int64 &)' [C:\Users\markus\develop\bug_demo\bin\bug_demo.vcxproj] C:\Users\markus\develop\bug_demo\vendor\sqlite_modern_cpp\hdr\sqlite_modern_cpp.h(533,27): message : or 'sqlite::database_binder &sqlite::operator <<(sqlite::database_binder &,const int &)' [C:\Users\markus\develop\bug_demo\bin\bug_demo.vcxproj] C:\Users\markus\develop\bug_demo\vendor\sqlite_modern_cpp\hdr\sqlite_modern_cpp.h(674,26): message : or 'sqlite::database_binder &sqlite::operator <<(sqlite::database_binder &,std::nullptr_t)' [C:\Users\markus\develop\bug_demo\bin\bug_demo.vcxproj] C:\Users\markus\develop\bug_demo\vendor\sqlite_modern_cpp\hdr\sqlite_modern_cpp.h(905,41): message : or 'sqlite::database_binder &&sqlite::operator <<<std::optional>(sqlite::database_binder &&,const T &)' [C:\Users\markus\develop\bug_demo\bin\bug_demo.vcxproj] with [ T=std::optional > ] C:\Users\markus\develop\bug_demo\vendor\sqlite_modern_cpp\hdr\sqlite_modern_cpp.h(905,90): message : while trying to match the argument list '(sqlite::database_binder, const T)' [C:\Users\markus\develop\bug_demo\bin\bug_demo.vcxproj] with [ T=std::optional > ] C:\Users\markus\develop\bug_demo\main.cpp(25): message : see reference to function template instantiation 'sqlite::database_binder &&sqlite::operator <<<std::optional>(sqlite::database_binder &&,const T &)' being compiled [C:\Users\markus\develop\bug_demo\bin\bug_demo.vcxproj] with [ T=std::optional > ]

    Besides some warnings about

    sqlite_modern_cpp\lists/error_codes.h(6,1): warning C4065: switch statement contains 'default' but no 'case' labels

    Working around the issue with unique_ptr works, I guess only some overload where forgotten, I assume the same is true for std::variant

  • Ability to interrupt queries

    Ability to interrupt queries

    Application may require queries to be interrupt. AFAIK, sqlitemoderncpp does not provide any way to do that.

    For now, I'll try to use sqlite3_interrupt(m_db.connection().get());. But that would be great to have it in the API.

  • ability to change database name

    ability to change database name

    Hello, i was wondering is it possible to change the database name? Since i am using this for a javascript module, Basically what i wanted to do is just maybe allow a default constructor with no arguments passed for sqlite::database so i can change it. Basically like this:

    sqlite::database db;
    
    void use_db(string name) {
      db = sqlite::database(name);
    }
    
React-native-quick-sqlite - ⚡️ The fastest SQLite implementation for react-native.
React-native-quick-sqlite - ⚡️ The fastest SQLite implementation for react-native.

React Native Quick SQLite The **fastest** SQLite implementation for react-native. Copy typeORM patch-package from example dir npm i react-nati

Dec 30, 2022
Yet another SQLite wrapper for Nim

Yet another SQLite wrapper for Nim Features: Design for ARC/ORC, you don’t need to close the connection manually Use importdb macro to create helper f

Jan 4, 2023
Lightweight C++ wrapper for SQLite

NLDatabase Lightweight C++ wrapper for SQLite. Requirements C++11 compiler SQLite 3 Usage Let's open a database file and read some rows: #include "NLD

Sep 20, 2019
❤️ SQLite ORM light header only library for modern C++
❤️ SQLite ORM light header only library for modern C++

SQLite ORM SQLite ORM light header only library for modern C++ Status Branch Travis Appveyor master dev Advantages No raw string queries Intuitive syn

Dec 30, 2022
A friendly and lightweight C++ database library for MySQL, PostgreSQL, SQLite and ODBC.

QTL QTL is a C ++ library for accessing SQL databases and currently supports MySQL, SQLite, PostgreSQL and ODBC. QTL is a lightweight library that con

Dec 12, 2022
SQLean: all the missing SQLite functions

SQLite has very few functions compared to other DBMS. SQLite authors see this as a feature rather than a bug, because SQLite has extension mechanism in place.

Jan 8, 2023
An SQLite binding for node.js with built-in encryption, focused on simplicity and (async) performance

Description An SQLite (more accurately SQLite3MultipleCiphers) binding for node.js focused on simplicity and (async) performance. When dealing with en

May 15, 2022
Fork of sqlite4java with updated SQLite and very basic compiler hardening enabled.

Download latest version: sqlite4java-392 with SQLite 3.8.7, Windows/Linux/Mac OS X/Android binaries OSGi bundle 1.0.392 with sqlite4java-392 Files for

Oct 26, 2022
An updated fork of sqlite_protobuf, a SQLite extension for extracting values from serialized Protobuf messages.

This fork of sqlite_protobuf fixes some issues (e.g., #15) and removes the test suite that we do not use. It also comes with proto_table, a C library

Oct 19, 2022
Serverless SQLite database read from and write to Object Storage Service, run on FaaS platform.

serverless-sqlite Serverless SQLite database read from and write to Object Storage Service, run on FaaS platform. NOTES: This repository is still in t

May 12, 2022
Verneuil is a VFS extension for SQLite that asynchronously replicates databases to S3-compatible blob stores.
Verneuil is a VFS extension for SQLite that asynchronously replicates databases to S3-compatible blob stores.

Verneuil: streaming replication for sqlite Verneuil1 [vɛʁnœj] is a VFS (OS abstraction layer) for sqlite that accesses local database files like the d

Dec 21, 2022
C++ ORM for SQLite

Hiberlite ORM C++ object-relational mapping with API inspired by the awesome Boost.Serialization - that means almost no API to learn. Usage Just compi

Dec 28, 2022
Unofficial git mirror of SQLite sources (see link for build instructions)

SQLite Source Repository This repository contains the complete source code for the SQLite database engine. Some test scripts are also included. Howeve

Dec 25, 2022
A hook for Project Zomboid that intercepts files access for savegames and puts them in an SQLite DB instead.

ZomboidDB This project consists of a library and patcher that results in file calls for your savegame(s) being transparently intercepted and redirecte

Aug 27, 2022
Writing a sqlite clone from scratch in C++

如何用C++实现一个简易数据库 基于cstack/db_tutorial C语言版本 KCNyu 2022/2/2 作为笔者写的第一个系列型教程,还是选择基于前人的教程经验以及添加一些自己个人的探索。也许有很多纰漏之处,希望大家指正。 1. 数据库是什么? 数据库是“按照数据结构来组织、存储和管理数

Dec 27, 2022
C++11 wrapper for the LMDB embedded B+ tree database library.

lmdb++: a C++11 wrapper for LMDB This is a comprehensive C++ wrapper for the LMDB embedded database library, offering both an error-checked procedural

Dec 27, 2022
SQLite3++ - C++ wrapper of SQLite3 API

ANNOUNCEMENTS Use files in headeronly_src directory. The files in src are exactly same but in the form of h/cpp files, which you need to compile and l

Jan 3, 2023
SQLiteC++ (SQLiteCpp) is a smart and easy to use C++ SQLite3 wrapper.
SQLiteC++ (SQLiteCpp) is a smart and easy to use C++ SQLite3 wrapper.

SQLiteC++ SQLiteC++ (SQLiteCpp) is a smart and easy to use C++ SQLite3 wrapper. About SQLiteC++: SQLiteC++ offers an encapsulation around the native C

Dec 31, 2022
VSQLite++ - A welldesigned and portable SQLite3 Wrapper for C++ (C)

VSQLite++ - A welldesigned and portable SQLite3 Wrapper for C++ (C)

Dec 29, 2021