Git Product home page Git Product logo

sqlite_modern_cpp's Introduction

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.
      // If you're using C++17, `std::string_view` and `std::u16string_view` can be used as string types.
      // 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;

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

      // a for loop can be used too:
      // with named variables
      for(auto &&row : db << "select age,name,weight from user where age > ? ;" << 18) {
         int age; string name; double weight;
         row >> age >> name >> weight;
         cout << age << ' ' << name << ' ' << weight << endl;
      }
      // or with a tuple
      for(tuple<int, string, double> row : db << "select age,name,weight from user where age > ? ;" << 18) {
         cout << get<0>(row) << ' ' << get<1>(row) << ' ' << get<2>(row) << endl;
      }

      // selects the count(*) from user table
      // note that you can extract a single column single row result only to : int,long,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 (const 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.execute();
// or like this
ps++;

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

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 (const 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 the optional library is not available, the experimental/optional one will be used instead.

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>. It is also possible to use a variant with std::monostate in order to catch null values.

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 (const sqlite_exception& e) {
   cerr  << e.get_code() << ": " << e.what() << " during "
         << e.get_sql() << endl;
}
/* you can catch specific exceptions as well,
   catch(const sqlite::errors::constraint &e) {  } */
/* and even more specific exceptions
   catch(const 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 (const 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").

Installation

The project is header only.
Simply point your compiler at the hdr/ directory.

Contributing

Install cmake and build the project.
Dependencies will be installed automatically (using hunter).

mkdir build
cd ./build
cmake ..
make

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

sqlite_modern_cpp's People

Contributors

aminroosta avatar barrybingo avatar bryant1410 avatar cbeiraod avatar chris-bond avatar epsilon-phase avatar jangxyz avatar jgaa avatar jimmyjxiao avatar keramer avatar killili avatar knairda avatar mordechaimaman avatar mqudsi avatar renathoaz avatar rturrado avatar semsevens avatar shaglund avatar tokuchan avatar ulrichbayer avatar unphased avatar vadz avatar visweswaran1998 avatar vitaliidemediuk avatar zauguin avatar zouquan741 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sqlite_modern_cpp's Issues

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.

Ability to get sqlite3 handle in sqlite::database

Hi,

I think it would be beneficial to have an accessor the the sqlite3 "db_" member in sqlite::database. I need to call a specific function but I don't want to mess with the sqlite3 initialization myself.

Is that something you think is worth adding ?

Thank you !

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?

Support for unsigned integers

There is currently no overload of operator<< that support sqlite_uint64, only sqlite_int64 (see SQLite documentation on 64-Bit Integer Types). As a side note, the documentation also recommends using the sqlite3_* versions over the sqlite_* ones.

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.

License file missing?

Hi, nice library Thanks for sharing but the license file is missing can you please add it Thanks

Select calls get called twice

Hi,

while implementing my little Logger feature i noticed that i get to many sqlite_step calls, it looks like the _extract methods use reset() at the end and in doing so reset execution_started which leads to another execution of the query when it leaves the scope.
I would fix it but i lack the time right now to test it and i think thats an urgent one to fix.

Gcc 6.1.1 compiling problem about 'does not match any template declaration'

The library works well when I use Fedora 23 whose gcc's version is gcc-c++-5.3.1-6.fc23.x86_64.rpm.
But after I updated to Fedora 24 in which gcc's version is gcc-c++-6.1.1-3.fc24.x86_64.rpm, the problem occurred.

When I compiling my project, It shows:

In file included from nb.cc:5:0:
/usr/local/include/sqlite_modern_cpp.h:494:25: error: template-id โ€˜get_col_from_db<>โ€™ for โ€˜void sqlite::get_col_from_db(sqlite::database_binder&, int, std::__cxx11::string&)โ€™ does not match any template declaration
  template<> inline void get_col_from_db(database_binder& db, int inx, std::string & s) {
                         ^~~~~~~~~~~~~~~
/usr/local/include/sqlite_modern_cpp.h:454:35: note: candidates are: template<class T> void sqlite::get_col_from_db(sqlite::database_binder&, int, std::vector<Type>&)
  template<typename T> inline void get_col_from_db(database_binder& db, int inx, std::vector<T>& vec) {
                                   ^~~~~~~~~~~~~~~
/usr/local/include/sqlite_modern_cpp.h:483:35: note:                 template<class T> void sqlite::get_col_from_db(sqlite::database_binder&, int, std::unique_ptr<T>&)
  template<typename T> inline void get_col_from_db(database_binder& db, int inx, std::unique_ptr<T>& _ptr_) {
                                   ^~~~~~~~~~~~~~~
/usr/local/include/sqlite_modern_cpp.h:507:37: error: template-id โ€˜operator<< <>โ€™ for โ€˜sqlite::database_binder& sqlite::operator<<(sqlite::database_binder&, const string&)โ€™ does not match any template declaration
  template<> inline database_binder& operator <<(database_binder& db, const std::string& txt) {
                                     ^~~~~~~~
/usr/local/include/sqlite_modern_cpp.h:444:47: note: candidates are: template<class T> sqlite::database_binder& sqlite::operator<<(sqlite::database_binder&, const std::vector<Type>&)
  template<typename T> inline database_binder& operator<<(database_binder& db, const std::vector<T>& vec) {

I'm very confused.
After I reading this article -- Why Not Specialize Function Templates?, I think it may due to the specialized function templates.
So I replace all specialized function templates with nontemplate functions and add them to be friends of class database_binder in file /usr/local/include/sqlite_modern_cpp.h.
And then it works.
Although this solved my problem, but I think it may be not the best way.
Here is my solution: Comparing changes

Some thougts, and questions

Hi, first i have to say that i really like this lib (i use it in two projetcs already).

But i have a few issues with it and wanted to ask if you share my opinion befor requesting a poll.

First it only compiles on VC, i made afew changes and got it running on MacOS and Linux. Namely moved stuff around because c++11 allows template specialisation only at namespace level. It now looks a bit ugly but is c++11 conformant now. Question is, do you care about that?

Secondly i have made some changes to the constructor to attach to a already open DB connection, fairly simple but a break in youre design, do you care?

And last, i am trying to get it to transparently support MySQL too. Whats youre thought about that.

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?

open as readonly

I am interested to use 1 sqlite database file shared between 2 programs, 1 as a writer and 1 as a reader. Sometimes I have the exception locked or busy thrown at the writer program.
Do you plan to support with flags as those from open_v2 here?
https://www.sqlite.org/c3ref/open.html

Expose last insert row id from database_binder

Since database_binder::chain_type is essentially a prepared statement, it would be useful to have access to the last insert row id from such an object, for instance when storing it on an object that is used to write data.

GCC 5.4.0 Compilation Error

/usr/local/include/sqlite_modern_cpp.h:63: error: 'printf' is not a member of 'sqlite::exceptions'
if(error_code == SQLITE_ERROR) throw exceptions::error(sqlite3_errstr(error_code));

Any Ideas?

Using GCC 5.4.0 in C++/14 mode, also tested CLANG and get a very similar error.
^

Cannot catch constraint exception

I'm trying to insert a row that produces a primary key constraint failure but the program crashes before I can catch the exception.

try {
db << "INSERT INTO tb_mytable (mytable_id,description) VALUES (?,?)" << 1 << "cannot catch exception";
// inserting again to produce error
db << "INSERT INTO tb_mytable (mytable_id,description) VALUES (?,?)" << 1 << "cannot catch exception";
} catch (exception e)
{
cerr << e.what() << endl;
} catch (...)
{
cerr << "this does not work either" << endl;
}

libc++abi.dylib: terminating with uncaught exception of type sqlite::exceptions::constraint: constraint failed
The program has unexpectedly finished.

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.

Development and Releases

Hi,
on the subject that came up in the last merge comments so everybody sees this.

I too think we should release a new version because so much has changed since last time.
Any suggestions what we should do for the next release or what we can do better?

Bad custom constructor behavior in #63 fix

The fix for #63 as in pull-request #64 have problems.

The custom constructor takes some members from the target object but nullifies them afterwards:

database_binder(database_binder&& other) :
		_db(std::move(other._db)),
		_sql(std::move(other._sql)),
		_stmt(std::move(other._stmt)),
		_inx(other._inx), execution_started(other.execution_started) {
			_db = nullptr;
			_stmt = nullptr;
	}

In the initialization list it takes (moves) the db & stmt, but discards them on the body. The fix is to leave the body empty (I think the idea was to do other.{_db,_stmt} = nullptr instead, but that's not need as the move constructor from std::shared_ptr() will take care of that).

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)) ===|

multiple statements fail - expected behavior?

I've noticed that when feeding in multiple semicolon-delimited statements as part of a single string, only the first statement is actually executed. for example:

database db("test.db");
db << "create table 'data'('col' integer); create table 'meta'('col' integer);";
// only the first table is created

The practical use case here is executing a whole bunch of statements to setup the schema when creating a new db.

if I split the string on semicolons and feed each string in, everything works. If this is expected behavior, it should probably be documented - even though I notice the the usage idioms only show examples of single statements.

License

I'd like to use this wrapper in a proprietary project, but cannot legally do so without a permissive license. As far as I can tell, there is no license attached to this project, which means it falls under standard copyright law.

Keramer, I am by no means pushing you into choosing a license that is more permissive than you are comfortable with. My hope is that from the start you wanted others to use and modify this code freely, but simply neglected to pick a license that explicitly allows such actions.

VS 2013 error C2440: '<function-style-cast>'

Hi, when I am compiling I get errors like:
Error 1 error C2440: '<function-style-cast>' : cannot convert from 'const char *' to 'sqlite::exceptions::error' ...\hdr\sqlite_modern_cpp.h 63 1

Could you suggest a solution?

'arity' is not a member ...

I'm getting the following error when I try to build ... any ideas please?

sqlite\sqlite_modern_cpp.h(301): error C2039: 'arity': is not a member of 'sqlite::utility::function_traits'

This is my code, where setting is a wchar* and value a &wstring

try { *awdb << "SELECT value FROM settings WHERE setting = ?" << setting >> value; }

Add pass-by-reference option for `operator>>`

While trying to make good use of the lambda syntax for pulling out results from a query, I hit an issue where the function is being passed by value (and thus copied), causing my results to get lost when the operator exited and the variable went out of scope.

In short, I want to create class instances for each result row, but also want to avoid code repetition. I currently have something similar to this:

// Note that this example is stripped down, and missing a lot of boilerplate.
class Route;

template<typename Target, typename... AttrTypes>
class Builder {
  public:
    std::vector<Target> results;

    void operator()(AttrTypes... args) {
      results.emplace_back(std::forward<AttrTypes&&>(args)...);
    };
};

Builder<Route, std::string, std::string> route_builder;


class Route {
  public:
    std::string attribute1;
    std::string attribute2;

    Route(std::string a1, std::string a2) : attribute1(a1), attribute2(a2) {};

    std::vector<Route> all(sqlite::database db) {
      route_builder.results.empty();
      db << "SELECT * FROM routes;"
        >> route_builder;
      return route_builder.results;
    };
};

The relevant code for this issue is in Route::all() at the end of the code block above, with the expression >> route_builder. I am passing an instance of the Builder class, which implements operator() (as required by utility::function_traits), and is thus runnable by the >> implementation.

However, the current implementation takes the argument by value, meaning a local copy of the instance is created for use in the function, and any side effects are discarded when that variable falls out of scope (when operator>> returns).

In other words, route_builder.results - which I would expect to contain the Route instances of each row returned from the query - is actually empty, because the operations were performed on an ephemeral copy of the instance.


My solution to this was to modify the Function specialization of operator>> to take its parameter by reference:

template <typename Function>
typename std::enable_if<!is_sqlite_value<Function>::value, void>::type operator>>(
  Function& func) {
  typedef utility::function_traits<Function> traits;

  this->_extract([&func, this]() {
    binder<traits::arity>::run(*this, func);
  });
}

However, this does not work with the original, intended behavior of using a temporary lambda as the argument:

db << "SELECT route_short_name FROM route;" >> [&](std::string short_name) {
  // This fails to compile, since this lambda is not an lvalue and therefore
  // db::operator>> can not take a reference to it.
};

To get around this, a new specialization that takes an rvalue reference for these temporaries can be introduced. The resulting changes to the header would look like this:

template <typename Function>
typename std::enable_if<!is_sqlite_value<Function>::value, void>::type operator>>(
  Function& func) {
  ...
}

template <typename Function>
typename std::enable_if<!is_sqlite_value<Function>::value, void>::type operator>>(
  Function&& func) {
  ...
}

This works because lvalues will prefer matching to the lvalue reference specialization (the first one), and rvalue temporaries will prefer matching to the rvalue reference specialization.

I have tested this implementation with classes defining operator() and direct lambdas, and both are working as of now. That said, though, I do not consider myself an expert in C++, so I'm not sure if this is a feasible solution.

Prepared statements as class members?

Hi, I've been using this for a couple of days now, and I haven't been able to figure out how to keep the prepared statements bound up as class members since I don't want to have to recreate them each time the function is called.

I've tried using database_binder, but apparently it isn't really meant to be assigned, so while I have to assume this is possible, I don't know which type I should assign it to.

Anyway, aside from this little niggling issue I've had, this library is really nice.

Edit: I'm very... silly I guess

I just need to use move on it.

Problem with "PRAGMA journal_mode = WAL"

I am using the following commands in order to speed up the code.
database db(table.c_str());
db << "PRAGMA journal_mode = WAL";
db << "PRAGMA synchronous = NORMAL";


The problem is that I am getting the following error while debuging the code:
In __cxa_throw () (/usr/lib/x86_64-linux-gnu/libstdc++.so.6)
#1 0x000000000041e9e7 in sqlite::database_binder::~database_binder (this=0x7fffffffdb10, __in_chrg=) at๏ฟฝ๏ฟฝ/home/documents/3rdpartysqlite_modern_cpp.h:96

๏ฟฝ๏ฟฝ/home/documents/3rdparty/sqlite_modern_cpp.h:96:2480:beg:0x41e9e7
At ๏ฟฝ๏ฟฝ/home/documents/3rdparty/sqlite_modern_cpp.h:96
Debugger finished with status 0


Solution:

sqlite3 *handle;
sqlite3_open(table.c_str(), &handle);
sqlite3_exec(handle, "pragma journal_mode = WAL", NULL, NULL, NULL);
sqlite3_exec(handle, "PRAGMA synchronous = NORMAL", NULL, NULL, NULL);
database db(handle);
//WORK HERE
sqlite3_close(handle);

Support for long and long long missing?

Hi,
according to the documentation in your examples this library should support long and long long as types:

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

But when I'm trying use it with a long value I get this error:

 error: undefined reference to 'sqlite::database_binder& sqlite::operator<< <long>(sqlite::database_binder&, long const&)'

Casting the value to an int before using it in the statement makes it work.
When I took a look at the sqlite_modern_cpp.h file I can't find a fitting function for long values.

So is the documentation wrong or am I just to stupid to use it with a long?

sqlite memory leak on failed open

The sqlite::database constructor has a potential memory leak if opening the database fails for whatever reason:

database(std::u16string const & db_name): _db(nullptr) {
			sqlite3* tmp = nullptr;
			auto ret = sqlite3_open16(db_name.data(), &tmp);
			if(ret != SQLITE_OK) exceptions::throw_sqlite_error(ret);

			_db = std::shared_ptr<sqlite3>(tmp, [=](sqlite3* ptr) { sqlite3_close_v2(ptr); }); // this will close the connection eventually when no longer needed.

			//_db.reset(tmp, sqlite3_close); // alternative close. (faster?)
		}

accordingly to https://www.sqlite.org/c3ref/close.html one must close the handle even if open returned an error. The above can be fixed by moving the fail check and the exception throwing after defining the _db shared_ptr, so it will call sqlite3_close_v2 at stack unwinding. One can prefer to do an explicit close instead, which is cheaper but more verbose. I took the 1st approach, below:

database(std::u16string const & db_name): _db(nullptr) {
			sqlite3* tmp = nullptr;
			auto ret = sqlite3_open16(db_name.data(), &tmp);
			_db = std::shared_ptr<sqlite3>(tmp, [=](sqlite3* ptr) { sqlite3_close_v2(ptr); }); // this will close the connection eventually when no longer needed.
   			if(ret != SQLITE_OK) exceptions::throw_sqlite_error(ret);
			//_db.reset(tmp, sqlite3_close); // alternative close. (faster?)
		}

access to sql statement

Certainly for debugging and logging it would be very helpful to have access to the last sql statement either thru the database object or thru the exception handler ... like get_code() ... get_sql().

Is this possible?

Archlinux integration !

Hello,
Just for information I maintain the package of SQL Modern CPP in AUR !
You can find it here or for arch user yaourt -S sqlite_modern_cpp

Hava nice day !

Compiling errors with Qt5.4.1 on OSX10.10

I just copy&paste the sample code in READE. (The previous issue posted by me is using an old version. It has no errors.)

13:09:28: Running steps for project UseSqlModernCpp...
13:09:28: Configuration unchanged, skipping qmake step.
13:09:28: Starting: "/usr/bin/make" 
/Users/mac/Qt5.4.1/5.4/clang_64/bin/qmake -spec macx-clang CONFIG+=debug CONFIG+=x86_64 CONFIG+=declarative_debug CONFIG+=qml_debug -o Makefile ../UseSqlModernCpp/UseSqlModernCpp.pro
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++ -c -pipe -g -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk -std=c++11 -stdlib=libc++ -mmacosx-version-min=10.7 -Wall -W -fPIE -DQT_QML_DEBUG -DQT_DECLARATIVE_DEBUG -DQT_QUICK_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_CORE_LIB -I../UseSqlModernCpp -I. -I../../Qt5.4.1/5.4/clang_64/lib/QtQuick.framework/Versions/5/Headers -I../../Qt5.4.1/5.4/clang_64/lib/QtGui.framework/Versions/5/Headers -I../../Qt5.4.1/5.4/clang_64/lib/QtQml.framework/Versions/5/Headers -I../../Qt5.4.1/5.4/clang_64/lib/QtNetwork.framework/Versions/5/Headers -I../../Qt5.4.1/5.4/clang_64/lib/QtCore.framework/Versions/5/Headers -I. -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/System/Library/Frameworks/OpenGL.framework/Versions/A/Headers -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/System/Library/Frameworks/AGL.framework/Headers -I../../Qt5.4.1/5.4/clang_64/mkspecs/macx-clang -F/Users/mac/Qt5.4.1/5.4/clang_64/lib -o util.o ../UseSqlModernCpp/util.cpp
In file included from ../UseSqlModernCpp/util.cpp:3:
../UseSqlModernCpp/sqlite_modern_cpp.h:149:10: error: no member named 'get_col_from_db' in 'sqlite::database_binder'
                        this->get_col_from_db(0, value);
                        ~~~~  ^
../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) {
                            ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:766:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, _CharT __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:773:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, char __cn)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:806:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, char __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:813:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, signed char __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:820:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, unsigned char __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:827:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, const _CharT* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:834:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, const char* __strn)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:880:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, const char* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:887:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, const signed char* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:895:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, const unsigned char* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1065:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os,
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1082:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, shared_ptr<_Yp> const& __p)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1089:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, const bitset<_Size>& __x)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1051:5: note: candidate template ignored: disabled by 'enable_if' [with _Stream = sqlite::database_binder, _Tp = int]
    !is_lvalue_reference<_Stream>::value &&
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1074:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, const error_code& __ec)
^
../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) {
                            ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:766:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, _CharT __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:773:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, char __cn)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:806:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, char __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:813:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, signed char __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:820:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, unsigned char __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:827:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, const _CharT* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:834:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, const char* __strn)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:880:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, const char* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:887:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, const signed char* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:895:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, const unsigned char* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1065:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os,
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1082:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, shared_ptr<_Yp> const& __p)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1089:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, const bitset<_Size>& __x)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1051:5: note: candidate template ignored: disabled by 'enable_if' [with _Stream = sqlite::database_binder, _Tp = int]
    !is_lvalue_reference<_Stream>::value &&
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1074:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, const error_code& __ec)
^
../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) {
                            ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:766:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, _CharT __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:773:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, char __cn)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:806:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, char __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:813:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, signed char __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:820:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, unsigned char __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:827:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, const _CharT* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:834:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, const char* __strn)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:880:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, const char* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:887:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, const signed char* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:895:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database_binder'
operator<<(basic_ostream<char, _Traits>& __os, const unsigned char* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1065:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os,
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1082:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, shared_ptr<_Yp> const& __p)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1089:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, const bitset<_Size>& __x)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1051:5: note: candidate template ignored: disabled by 'enable_if' [with _Stream = sqlite::database_binder, _Tp = int]
    !is_lvalue_reference<_Stream>::value &&
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1074:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database_binder'
operator<<(basic_ostream<_CharT, _Traits>& __os, const error_code& __ec)
^
4 errors generated.
make: *** [util.o] Error 1
13:09:31: The process "/usr/bin/make" exited with code 2.
Error while building/deploying project UseSqlModernCpp (kit: Desktop Qt 5.4.1 clang 64bit)
When executing step "Make"
13:09:31: Elapsed time: 00:03.

Bad database_binder destructor behavior

database_binder design suffers from a minor shortcoming. It has a defaulted move constructor and a destructor path that assumes every object was fully initialized by the parametrized constructor.

These are subtle contradictions, because when the move constructor is used for in-place initialization, the "moved" object is empty. So, for instance:

database_binder
    class dbFront {
    std::unique_ptr<database_binder> storedProcedure;
    database db;
     dbFront(const std::string &dbFile, const std::string &key): db(dbFile) {
     db << "PRAGMA key = '" << key << "'";
     createTables(db);
     storedProcedure = std::make_unique<database_binder>(db << "INSERT INTO log (a, b) VALUES(?,?)");
    }

(I understand the unique_ptr implications, it's beside the point. There are other scenarios where move constructor would apply. The reason unique_ptr was chosen is that I need to initialize the stored procedure as class members and there's no default constructor. We could add one, but, if at a later time, we decided to replace/update the stored procedure object [by move], the bug would trigger).

There are "two objects" created on the storedProcedure = ... line; the one returned by db << "..." which is moved into the empty one allocated by std::make_unique.

The default move construtor works ok, the problem with above is that the object returned by the "db << "..." statement, after the move, is replaced by the empty object, and this one has no statement at the _stmt member, nor a pointer to the db for that matter.

The empty object destructor is called on site, and it tries to call execute(), which won't work and throws.

There are many ways to fix it - I think the most polite would be to have a custom move construtor, but what I did instead was to check if the _stmt is valid and only call execute in this case:

~database_binder() noexcept(false) {
			/* Will be executed if no >>op is found, but not if an exception
			is in mid flight */
			if(!execution_started && !std::uncaught_exception() && _stmt) {
				execute();
			}
		}

Shouldn't statement->execute() set used to true?

Hello,

Thanks for this library, I just migrated a project over from CppSqlite (which I'd been maintaining) over to this.

I have a question on prepared statements - is there a reason manually calling execute on a statement (and not statement++) does not set used to true? From the documentation and going by logic, I assumed execute() would execute the statement and set it to used. reset would unbind parameters and set used to false. But that's not the case since it remains "unused" even after explicitly executing and will run once more before destructing unless used(false) is manually called.

Thanks.

New sqlite.c

Any change a new sqlite source will be used soon?

Currently used here is 3.8 but 3.11 is available.

How to use a functor to replace the lambda one?

Hello,
Thank you for this great sqlite wrapper! It's very convenient.
While using the wrapper is delightful, a problem about eliminating similar code occurs.

The functor:

struct ItemResultHandler {
    explicit ItemResultHandler(QVariantMap& map_) : map(map_) {}
    void operator() ( int id, std::string name, double price, int qty ) {
         map.insert("id", id);
         map.insert("name", QString::fromStdString(name));   
         map.insert("price", price);
         map.insert("qty", qty);
    }
    QVariantMap& map;
};

The code:

QVariantMap getItemById(int id) {
  QVariantMap map;
  database db(dbfile);
  db << "select id,name,price,qty from items where id=?"
     << id 
     >> ItemResultHandler(map);
  return map;
}

It has compiling errors:

../../myapp/src/utility/function_traits.h:12: error: type 'void (ItemResultHandler::*)(std::__1::basic_string<char>, std::__1::basic_string<char>, int, int)' cannot be used prior to '::' because it has no members
        decltype(&Function::operator())
                  ^
 ../../myapp/src/sqlite_modern_cpp.h:218: error: incomplete definition of type 'sqlite::utility::function_traits<ItemResultHandler>'
                        binder<traits::arity>::run(*this, func);
                               ~~~~~~^~

I have posted a question in SO. Could you please have a look at it? Thank you in advance.
http://stackoverflow.com/questions/30387896/how-to-eliminate-multiple-similar-sql-queries-with-one-resultset-hander

seems uint64_t not supported?

Hi,
Thank you for this very convenient library!
I just downloaded the latest code. When uint64_t inserting, the following link error occurs:

error: undefined reference to `std::unique_ptr<sqlite::database_binder, std::default_delete<sqlite::database_binder> >& sqlite::operator<< <unsigned long long>(std::unique_ptr<sqlite::database_binder, std::default_delete<sqlite::database_binder> >&, unsigned long long const&)'

Is it necessary to write a special template for uint64_t?

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).

blob handle

Would it be nice if there is support for blob handle (e.g. using sqlite3_blob_open and sqlite3_blob_read)? Some blobs can be quite big so I am interested to query only the top few bytes.

latest push breaks build utf16string link

Using the latest release I now cannot build :( using Visual Studio 2017

error LNK2001: unresolved external symbol "__declspec(dllimport) public: static class std::locale::id std::codecvt<char16_t,char,struct _Mbstatet>::id" (_imp?id@?$codecvt@_SDU_Mbstatet@@@std@@2V0locale@2@A)

Example doesn't work

I tried to compile the example that is currently in readme, and got these errors. My environment is
clang++:

Apple LLVM version 7.3.0 (clang-703.0.29)
Target: x86_64-apple-darwin15.4.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
sqlite.cpp:36:12: error: invalid operands to binary expression ('sqlite::database' and 'const char16_t *')
        db << u"insert into user (age,name,weight) values (?,?,?);" // utf16 query string
        ~~ ^  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
selkei/sneezymud/sqlite_modern_cpp/hdr/sqlite_modern_cpp.h:297:31: note: candidate function not viable: no known conversion from 'const char16_t [51]' to 'const std::string' (aka 'const basic_string<char, char_traits<char>, allocator<char> >') for 1st argument
                database_binder::chain_type operator<<(const std::string& sql) {
                                            ^
selkei/sneezymud/sqlite_modern_cpp/hdr/sqlite_modern_cpp.h:301:31: note: candidate function not viable: no known conversion from 'const char16_t [51]' to 'const char *' for 1st argument
                database_binder::chain_type operator<<(const char* sql) {
                                            ^
selkei/sneezymud/sqlite_modern_cpp/hdr/sqlite_modern_cpp.h:465:62: note: candidate function [with N = 51] not viable: no known conversion from 'sqlite::database' to 'database_binder::chain_type &' (aka 'unique_ptr<sqlite::database_binder> &') for 1st argument
        template<std::size_t N> inline database_binder::chain_type& operator <<(database_binder::chain_type& db, const char16_t(&STR)[N]) { return db << std::u16string(STR); }
                                                                    ^
selkei/sneezymud/sqlite_modern_cpp/hdr/sqlite_modern_cpp.h:530:52: note: candidate function [with T = char16_t [51]] not viable: no known conversion from 'sqlite::database' to 'database_binder::chain_type' (aka 'unique_ptr<sqlite::database_binder>') for 1st argument
        template<typename T> database_binder::chain_type& operator << (database_binder::chain_type&& db, const T& val) { return db << val; }
                                                          ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:778:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database'
operator<<(basic_ostream<_CharT, _Traits>& __os, _CharT __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:785:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database'
operator<<(basic_ostream<_CharT, _Traits>& __os, char __cn)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:818:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database'
operator<<(basic_ostream<char, _Traits>& __os, char __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:825:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database'
operator<<(basic_ostream<char, _Traits>& __os, signed char __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:832:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database'
operator<<(basic_ostream<char, _Traits>& __os, unsigned char __c)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:839:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database'
operator<<(basic_ostream<_CharT, _Traits>& __os, const _CharT* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:846:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database'
operator<<(basic_ostream<_CharT, _Traits>& __os, const char* __strn)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:892:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database'
operator<<(basic_ostream<char, _Traits>& __os, const char* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:899:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database'
operator<<(basic_ostream<char, _Traits>& __os, const signed char* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:907:1: note: candidate template ignored: could not match 'basic_ostream<char, type-parameter-0-0>' against 'sqlite::database'
operator<<(basic_ostream<char, _Traits>& __os, const unsigned char* __str)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1077:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database'
operator<<(basic_ostream<_CharT, _Traits>& __os,
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1094:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database'
operator<<(basic_ostream<_CharT, _Traits>& __os, shared_ptr<_Yp> const& __p)
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1101:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database'
operator<<(basic_ostream<_CharT, _Traits>& __os, const bitset<_Size>& __x)
^
selkei/sneezymud/sqlite_modern_cpp/hdr/sqlite_modern_cpp.h:433:59: note: candidate template ignored: could not match 'vector<type-parameter-0-0, allocator<type-parameter-0-0> >' against 'char16_t const[51]'
        template<typename T> inline database_binder::chain_type& operator<<(database_binder::chain_type& db, const std::vector<T>& vec) {
                                                                 ^
selkei/sneezymud/sqlite_modern_cpp/hdr/sqlite_modern_cpp.h:464:62: note: candidate template ignored: could not match 'const char' against 'const char16_t'
        template<std::size_t N> inline database_binder::chain_type& operator <<(database_binder::chain_type& db, const char(&STR)[N]) { return db << std::string(STR); }
                                                                    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1063:5: note: candidate template ignored: disabled by 'enable_if' [with _Stream = sqlite::database &, _Tp = char16_t [51]]
    !is_lvalue_reference<_Stream>::value &&
    ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1086:1: note: candidate template ignored: could not match 'basic_ostream<type-parameter-0-0, type-parameter-0-1>' against 'sqlite::database'
operator<<(basic_ostream<_CharT, _Traits>& __os, const error_code& __ec)
^
1 error generated.

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 ?

Just wondering why use UTF-16 instead of UTF-8?

Hi, this isn't a problem or anything, I am just reading the code in order to figure out how I wanted to extend it and I noticed that UTF-16 is being used and I am simply curious about why this was chosen.

The general opinion seems to be that UTF-16 isn't as appealing

Compile Error when using boost::optional.

Hi,

I ran into a compile error when using the boost::optional extension with VS2015:

Error   C2248   'sqlite::database_binder::_stmt': cannot access private member declared in class     'sqlite::database_binder'  
...\sqlite_modern_cpp\hdr\sqlite_modern_cpp\extensions\boost_optional.h:18  

My code looks like this:

db << "SELECT `Id`, `ItemTypeId`,`ToUser`,`FromUser`,`Content` FROM `UndeliveredItems`  WHERE ToUser = ?;"
        << to_user_id 
        >> tie(item.id, item.item_type_id, item.to_user_id, item.from_user_id, item.content);

with item.content beeing boost::optional<std::string> content;

It seems like the friend declaration template<typename T> friend void get_col_from_db(database_binder& ddb, int inx, T& val); in class database_binder is not correctly kicking in.

Do you have any suggestions to fix the issue?

Thank you

global database

I must be missing something here but how do I use the database object as a member variable in a class and then open the database object with a given filename?

variadic function args to database?

This is not an issue but a request for help please. I have created a variadic function and need to send the variable args list to the database. .... thanks!

template<typename... AttrTypes>  
static vector<Action> get(weak_ptr<sqlite::database> awdb_, const T& sql, AttrTypes... args) {
    *awdb_.lock() << sql
    << args (this is incorrect and needs to be unpacked, how?)
}

latest build has new line errors

sqlite_modern_cpp.h(11): warning C4067: unexpected tokens following preprocessor directive - expected a newline
sqlite_modern_cpp.h(244): warning C4067: unexpected tokens following preprocessor directive - expected a newline
sqlite_modern_cpp.h(558): warning C4067: unexpected tokens following preprocessor directive - expected a newline

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?

operator << doesn't return a prepared statement

Following the example on the front page:

database db(":memory:");
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;
ps.execute();

I get a database_binder which has no execute method.

I expect a prepared statement.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.