From 18f61c6d8ba9e2a61fef7c51df07d878a9c562ae Mon Sep 17 00:00:00 2001 From: amin roosta Date: Sun, 19 Jun 2016 16:29:51 +0430 Subject: [PATCH] trying to fix exceptions --- README.md | 30 ++++++++++-- hdr/sqlite_modern_cpp.h | 104 +++++++++++++++++++--------------------- tests/exceptions.cc | 32 +++++++++++++ 3 files changed, 106 insertions(+), 60 deletions(-) create mode 100644 tests/exceptions.cc diff --git a/README.md b/README.md index cbe16938..3f1625cc 100644 --- a/README.md +++ b/README.md @@ -99,16 +99,16 @@ It is possible to retain and reuse statments this will keep the query plan and i ps >> [&](int a,int b){ ... }; // after a successfull execution the statment needs to be reset to be execute again. This will reset the bound values too! - ps->reset(); + ps.reset(); // If you dont need the returned values you can execute it like this - ps->execute(); // the statment will not be reset! + ps.execute(); // the statment will not be reset! // there is a convinience operator to execute and reset in one go 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 + ps.used(true); // or false if you want it to execute even if it was used // Usage Example: @@ -153,7 +153,6 @@ Take this example on how to deal with a database backup using SQLITEs own functi Transactions ===== You can use transactions with `begin;`, `commit;` and `rollback;` commands. -*(don't forget to put all the semicolons at the end of each query)*. ```c++ db << "begin;"; // begin a transaction ... @@ -286,7 +285,28 @@ 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::exceptions::constraint. Note that all errors are derived from sqlite::sqlite_exception and that itself is derived from std::runtime_exception. -*node: for NDK use the full path to your database file : `sqlite::database db("/data/data/com.your.package/dbfile.db")`*. +```c++ + 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.what() << endl; + } + /* you can catch specific exceptions as well, + catch(sqlite::exceptions::constraint e) { } */ +``` + +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 ===== diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index 6a864a50..054d9c26 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -116,7 +116,12 @@ namespace sqlite { class database_binder { public: - typedef std::unique_ptr chain_type; + database_binder(database_binder&& other) = default; + // database_binder is not copyable + database_binder() = delete; + database_binder(const database_binder& other) = delete; + database_binder& operator=(const database_binder&) = delete; + void reset() { sqlite3_reset(_stmt.get()); @@ -208,30 +213,23 @@ namespace sqlite { > { }; - template friend database_binder::chain_type& operator <<(database_binder::chain_type& db, const T& val); + template friend database_binder& operator <<(database_binder& db, const T& val); template friend void get_col_from_db(database_binder& db, int inx, T& val); /* for vector support */ - template friend database_binder::chain_type& operator <<(database_binder::chain_type& db, const std::vector& val); + template friend database_binder& operator <<(database_binder& db, const std::vector& val); template friend void get_col_from_db(database_binder& db, int inx, std::vector& val); /* for nullptr & unique_ptr support */ - friend database_binder::chain_type& operator <<(database_binder::chain_type& db, std::nullptr_t); - template friend database_binder::chain_type& operator <<(database_binder::chain_type& db, const std::unique_ptr& val); + friend database_binder& operator <<(database_binder& db, std::nullptr_t); + template friend database_binder& operator <<(database_binder& db, const std::unique_ptr& val); template friend void get_col_from_db(database_binder& db, int inx, std::unique_ptr& val); template friend T operator++(database_binder& db, int); #ifdef _MODERN_SQLITE_BOOST_OPTIONAL_SUPPORT - template friend database_binder::chain_type& operator <<(database_binder::chain_type& db, const boost::optional& val); + template friend database_binder& operator <<(database_binder& db, const boost::optional& val); template friend void get_col_from_db(database_binder& db, int inx, boost::optional& o); #endif - - database_binder() = delete; - database_binder(const database_binder& other) = delete; - database_binder& operator=(const database_binder&) = delete; - database_binder(const database_binder&& other) = delete; - - public: database_binder(std::shared_ptr db, std::u16string const & sql): @@ -299,19 +297,19 @@ namespace sqlite { database(std::shared_ptr db): _db(db) {} - database_binder::chain_type operator<<(const std::string& sql) { - return database_binder::chain_type(new database_binder(_db, sql)); + database_binder operator<<(const std::string& sql) { + return database_binder(_db, sql); } - database_binder::chain_type operator<<(const char* sql) { + database_binder operator<<(const char* sql) { return *this << std::string(sql); } - database_binder::chain_type operator<<(const std::u16string& sql) { - return database_binder::chain_type(new database_binder(_db, sql)); + database_binder operator<<(const std::u16string& sql) { + return database_binder(_db, sql); } - database_binder::chain_type operator<<(const char16_t* sql) { + database_binder operator<<(const char16_t* sql) { return *this << std::u16string(sql); } @@ -372,12 +370,12 @@ namespace sqlite { }; // int - template<> inline database_binder::chain_type& operator<<(database_binder::chain_type& db, const int& val) { + template<> inline database_binder& operator<<(database_binder& db, const int& val) { int hresult; - if((hresult = sqlite3_bind_int(db->_stmt.get(), db->_inx, val)) != SQLITE_OK) { + if((hresult = sqlite3_bind_int(db._stmt.get(), db._inx, val)) != SQLITE_OK) { exceptions::throw_sqlite_error(hresult); } - ++db->_inx; + ++db._inx; return db; } template<> inline void get_col_from_db(database_binder& db, int inx, int& val) { @@ -389,13 +387,13 @@ namespace sqlite { } // sqlite_int64 - template<> inline database_binder::chain_type& operator <<(database_binder::chain_type& db, const sqlite_int64& val) { + template<> inline database_binder& operator <<(database_binder& db, const sqlite_int64& val) { int hresult; - if((hresult = sqlite3_bind_int64(db->_stmt.get(), db->_inx, val)) != SQLITE_OK) { + if((hresult = sqlite3_bind_int64(db._stmt.get(), db._inx, val)) != SQLITE_OK) { exceptions::throw_sqlite_error(hresult); } - ++db->_inx; + ++db._inx; return db; } template<> inline void get_col_from_db(database_binder& db, int inx, sqlite3_int64& i) { @@ -407,13 +405,13 @@ namespace sqlite { } // float - template<> inline database_binder::chain_type& operator <<(database_binder::chain_type& db, const float& val) { + template<> inline database_binder& operator <<(database_binder& db, const float& val) { int hresult; - if((hresult = sqlite3_bind_double(db->_stmt.get(), db->_inx, double(val))) != SQLITE_OK) { + if((hresult = sqlite3_bind_double(db._stmt.get(), db._inx, double(val))) != SQLITE_OK) { exceptions::throw_sqlite_error(hresult); } - ++db->_inx; + ++db._inx; return db; } template<> inline void get_col_from_db(database_binder& db, int inx, float& f) { @@ -425,13 +423,13 @@ namespace sqlite { } // double - template<> inline database_binder::chain_type& operator <<(database_binder::chain_type& db, const double& val) { + template<> inline database_binder& operator <<(database_binder& db, const double& val) { int hresult; - if((hresult = sqlite3_bind_double(db->_stmt.get(), db->_inx, val)) != SQLITE_OK) { + if((hresult = sqlite3_bind_double(db._stmt.get(), db._inx, val)) != SQLITE_OK) { exceptions::throw_sqlite_error(hresult); } - ++db->_inx; + ++db._inx; return db; } template<> inline void get_col_from_db(database_binder& db, int inx, double& d) { @@ -443,14 +441,14 @@ namespace sqlite { } // vector - template inline database_binder::chain_type& operator<<(database_binder::chain_type& db, const std::vector& vec) { + template inline database_binder& operator<<(database_binder& db, const std::vector& vec) { void const* buf = reinterpret_cast(vec.data()); int bytes = vec.size() * sizeof(T); int hresult; - if((hresult = sqlite3_bind_blob(db->_stmt.get(), db->_inx, buf, bytes, SQLITE_TRANSIENT)) != SQLITE_OK) { + if((hresult = sqlite3_bind_blob(db._stmt.get(), db._inx, buf, bytes, SQLITE_TRANSIENT)) != SQLITE_OK) { exceptions::throw_sqlite_error(hresult); } - ++db->_inx; + ++db._inx; return db; } template inline void get_col_from_db(database_binder& db, int inx, std::vector& vec) { @@ -464,16 +462,16 @@ namespace sqlite { } /* for nullptr support */ - inline database_binder::chain_type& operator <<(database_binder::chain_type& db, std::nullptr_t) { + inline database_binder& operator <<(database_binder& db, std::nullptr_t) { int hresult; - if((hresult = sqlite3_bind_null(db->_stmt.get(), db->_inx)) != SQLITE_OK) { + if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) { exceptions::throw_sqlite_error(hresult); } - ++db->_inx; + ++db._inx; return db; } /* for nullptr support */ - template inline database_binder::chain_type& operator <<(database_binder::chain_type& db, const std::unique_ptr& val) { + template inline database_binder& operator <<(database_binder& db, const std::unique_ptr& val) { if(val) db << *val; else @@ -503,16 +501,16 @@ namespace sqlite { } // Convert char* to string to trigger op<<(..., const std::string ) - template inline database_binder::chain_type& operator <<(database_binder::chain_type& db, const char(&STR)[N]) { return db << std::string(STR); } - template inline database_binder::chain_type& operator <<(database_binder::chain_type& db, const char16_t(&STR)[N]) { return db << std::u16string(STR); } + template inline database_binder& operator <<(database_binder& db, const char(&STR)[N]) { return db << std::string(STR); } + template inline database_binder& operator <<(database_binder& db, const char16_t(&STR)[N]) { return db << std::u16string(STR); } - template<> inline database_binder::chain_type& operator <<(database_binder::chain_type& db, const std::string& txt) { + template<> inline database_binder& operator <<(database_binder& db, const std::string& txt) { int hresult; - if((hresult = sqlite3_bind_text(db->_stmt.get(), db->_inx, txt.data(), -1, SQLITE_TRANSIENT)) != SQLITE_OK) { + if((hresult = sqlite3_bind_text(db._stmt.get(), db._inx, txt.data(), -1, SQLITE_TRANSIENT)) != SQLITE_OK) { exceptions::throw_sqlite_error(hresult); } - ++db->_inx; + ++db._inx; return db; } // std::u16string @@ -526,27 +524,27 @@ namespace sqlite { } - template<> inline database_binder::chain_type& operator <<(database_binder::chain_type& db, const std::u16string& txt) { + template<> inline database_binder& operator <<(database_binder& db, const std::u16string& txt) { int hresult; - if((hresult = sqlite3_bind_text16(db->_stmt.get(), db->_inx, txt.data(), -1, SQLITE_TRANSIENT)) != SQLITE_OK) { + if((hresult = sqlite3_bind_text16(db._stmt.get(), db._inx, txt.data(), -1, SQLITE_TRANSIENT)) != SQLITE_OK) { exceptions::throw_sqlite_error(hresult); } - ++db->_inx; + ++db._inx; return db; } // boost::optinal support for NULL values #ifdef _MODERN_SQLITE_BOOST_OPTIONAL_SUPPORT - template inline database_binder::chain_type& operator <<(database_binder::chain_type& db, const boost::optional& val) { + template inline database_binder& operator <<(database_binder& db, const boost::optional& val) { if(val) { return operator << (std::move(db), std::move(*val)); } int hresult; - if((hresult = sqlite3_bind_null(db->_stmt.get(), db->_inx)) != SQLITE_OK) { + if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) { exceptions::throw_sqlite_error(hresult); } - ++db->_inx; + ++db._inx; return db; } @@ -561,14 +559,10 @@ namespace sqlite { } #endif - // there is too much magic here, val might be rValue or lValue - template void operator >> (database_binder::chain_type& db, T&& val) { *db >> std::forward(val); } - template void operator >> (database_binder::chain_type&& db, T&& val) { db >> std::forward(val); } - // Some ppl are lazy so we have a operator for proper prep. statemant handling. - void inline operator++(database_binder::chain_type& db, int) { db->execute(); db->reset(); } + void inline operator++(database_binder& db, int) { db.execute(); db.reset(); } // Convert the rValue binder to a reference and call first op<<, its needed for the call that creates the binder (be carfull of recursion here!) - template database_binder::chain_type& operator << (database_binder::chain_type&& db, const T& val) { return db << val; } + template database_binder& operator << (database_binder&& db, const T& val) { return db << val; } } diff --git a/tests/exceptions.cc b/tests/exceptions.cc new file mode 100644 index 00000000..3aabe8ee --- /dev/null +++ b/tests/exceptions.cc @@ -0,0 +1,32 @@ +#include +#include +#include +#include +#include +using namespace sqlite; +using namespace std; + + +int main() { + database db(":memory:"); + db << "CREATE TABLE person (id integer primary key not null, name TEXT);"; + bool expception_thrown = false; + + 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) { + cerr << e.what() << endl; + expception_thrown = true; + } catch (...) { + cerr << "Ok, we have our excpetion thrown" << endl; + expception_thrown = true; + } + + if(!expception_thrown) { + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); +}