88#include < memory>
99#include < vector>
1010
11+ #ifdef __has_include
1112#if __has_include(<optional>)
13+ #define _MODERN_SQLITE_STD_OPTIONAL_SUPPORT
14+ #endif
15+ #endif
16+
17+ #ifdef _MODERN_SQLITE_STD_OPTIONAL_SUPPORT
1218#include < optional>
1319#endif
1420
1824
1925#include < sqlite3.h>
2026
21- #include < sqlite_modern_cpp/utility/function_traits.h>
27+ #include " sqlite_modern_cpp/utility/function_traits.h"
28+ #include " sqlite_modern_cpp/utility/uncaught_exceptions.h"
2229
2330namespace sqlite {
2431
25- struct sqlite_exception : public std ::runtime_error {
26- sqlite_exception (const char * msg):runtime_error(msg) {}
32+ class sqlite_exception : public std ::runtime_error {
33+ public:
34+ sqlite_exception (const char * msg, int code = -1 ): runtime_error(msg), code(code) {}
35+ sqlite_exception (int code): runtime_error(sqlite3_errstr(code)), code(code) {}
36+ int get_code () {return code;}
37+ private:
38+ int code;
2739 };
2840
2941 namespace exceptions {
@@ -64,33 +76,33 @@ namespace sqlite {
6476 class no_rows : public sqlite_exception { using sqlite_exception::sqlite_exception; };
6577
6678 static void throw_sqlite_error (const int & error_code) {
67- if (error_code == SQLITE_ERROR) throw exceptions::error (sqlite3_errstr ( error_code) );
68- else if (error_code == SQLITE_INTERNAL) throw exceptions::internal (sqlite3_errstr ( error_code) );
69- else if (error_code == SQLITE_PERM) throw exceptions::perm (sqlite3_errstr ( error_code) );
70- else if (error_code == SQLITE_ABORT) throw exceptions::abort (sqlite3_errstr ( error_code) );
71- else if (error_code == SQLITE_BUSY) throw exceptions::busy (sqlite3_errstr ( error_code) );
72- else if (error_code == SQLITE_LOCKED) throw exceptions::locked (sqlite3_errstr ( error_code) );
73- else if (error_code == SQLITE_NOMEM) throw exceptions::nomem (sqlite3_errstr ( error_code) );
74- else if (error_code == SQLITE_READONLY) throw exceptions::readonly (sqlite3_errstr ( error_code) );
75- else if (error_code == SQLITE_INTERRUPT) throw exceptions::interrupt (sqlite3_errstr ( error_code) );
76- else if (error_code == SQLITE_IOERR) throw exceptions::ioerr (sqlite3_errstr ( error_code) );
77- else if (error_code == SQLITE_CORRUPT) throw exceptions::corrupt (sqlite3_errstr ( error_code) );
78- else if (error_code == SQLITE_NOTFOUND) throw exceptions::notfound (sqlite3_errstr ( error_code) );
79- else if (error_code == SQLITE_FULL) throw exceptions::full (sqlite3_errstr ( error_code) );
80- else if (error_code == SQLITE_CANTOPEN) throw exceptions::cantopen (sqlite3_errstr ( error_code) );
81- else if (error_code == SQLITE_PROTOCOL) throw exceptions::protocol (sqlite3_errstr ( error_code) );
82- else if (error_code == SQLITE_EMPTY) throw exceptions::empty (sqlite3_errstr ( error_code) );
83- else if (error_code == SQLITE_SCHEMA) throw exceptions::schema (sqlite3_errstr ( error_code) );
84- else if (error_code == SQLITE_TOOBIG) throw exceptions::toobig (sqlite3_errstr ( error_code) );
85- else if (error_code == SQLITE_CONSTRAINT) throw exceptions::constraint (sqlite3_errstr ( error_code) );
86- else if (error_code == SQLITE_MISMATCH) throw exceptions::mismatch (sqlite3_errstr ( error_code) );
87- else if (error_code == SQLITE_MISUSE) throw exceptions::misuse (sqlite3_errstr ( error_code) );
88- else if (error_code == SQLITE_NOLFS) throw exceptions::nolfs (sqlite3_errstr ( error_code) );
89- else if (error_code == SQLITE_AUTH) throw exceptions::auth (sqlite3_errstr ( error_code) );
90- else if (error_code == SQLITE_FORMAT) throw exceptions::format (sqlite3_errstr ( error_code) );
91- else if (error_code == SQLITE_RANGE) throw exceptions::range (sqlite3_errstr ( error_code) );
92- else if (error_code == SQLITE_NOTADB) throw exceptions::notadb (sqlite3_errstr ( error_code) );
93- else throw sqlite_exception (sqlite3_errstr ( error_code) );
79+ if (error_code == SQLITE_ERROR) throw exceptions::error (error_code);
80+ else if (error_code == SQLITE_INTERNAL) throw exceptions::internal (error_code);
81+ else if (error_code == SQLITE_PERM) throw exceptions::perm (error_code);
82+ else if (error_code == SQLITE_ABORT) throw exceptions::abort (error_code);
83+ else if (error_code == SQLITE_BUSY) throw exceptions::busy (error_code);
84+ else if (error_code == SQLITE_LOCKED) throw exceptions::locked (error_code);
85+ else if (error_code == SQLITE_NOMEM) throw exceptions::nomem (error_code);
86+ else if (error_code == SQLITE_READONLY) throw exceptions::readonly (error_code);
87+ else if (error_code == SQLITE_INTERRUPT) throw exceptions::interrupt (error_code);
88+ else if (error_code == SQLITE_IOERR) throw exceptions::ioerr (error_code);
89+ else if (error_code == SQLITE_CORRUPT) throw exceptions::corrupt (error_code);
90+ else if (error_code == SQLITE_NOTFOUND) throw exceptions::notfound (error_code);
91+ else if (error_code == SQLITE_FULL) throw exceptions::full (error_code);
92+ else if (error_code == SQLITE_CANTOPEN) throw exceptions::cantopen (error_code);
93+ else if (error_code == SQLITE_PROTOCOL) throw exceptions::protocol (error_code);
94+ else if (error_code == SQLITE_EMPTY) throw exceptions::empty (error_code);
95+ else if (error_code == SQLITE_SCHEMA) throw exceptions::schema (error_code);
96+ else if (error_code == SQLITE_TOOBIG) throw exceptions::toobig (error_code);
97+ else if (error_code == SQLITE_CONSTRAINT) throw exceptions::constraint (error_code);
98+ else if (error_code == SQLITE_MISMATCH) throw exceptions::mismatch (error_code);
99+ else if (error_code == SQLITE_MISUSE) throw exceptions::misuse (error_code);
100+ else if (error_code == SQLITE_NOLFS) throw exceptions::nolfs (error_code);
101+ else if (error_code == SQLITE_AUTH) throw exceptions::auth (error_code);
102+ else if (error_code == SQLITE_FORMAT) throw exceptions::format (error_code);
103+ else if (error_code == SQLITE_RANGE) throw exceptions::range (error_code);
104+ else if (error_code == SQLITE_NOTADB) throw exceptions::notadb (error_code);
105+ else throw sqlite_exception (error_code);
94106 }
95107 }
96108
@@ -122,7 +134,6 @@ namespace sqlite {
122134
123135 database_binder (database_binder&& other) :
124136 _db (std::move(other._db)),
125- _sql (std::move(other._sql)),
126137 _stmt (std::move(other._stmt)),
127138 _inx (other._inx), execution_started(other.execution_started) { }
128139
@@ -149,8 +160,8 @@ namespace sqlite {
149160
150161 private:
151162 std::shared_ptr<sqlite3> _db;
152- std::u16string _sql;
153163 std::unique_ptr<sqlite3_stmt, decltype (&sqlite3_finalize)> _stmt;
164+ utility::UncaughtExceptionDetector _has_uncaught_exception;
154165
155166 int _inx;
156167
@@ -177,11 +188,11 @@ namespace sqlite {
177188 if ((hresult = sqlite3_step (_stmt.get ())) == SQLITE_ROW) {
178189 call_back ();
179190 } else if (hresult == SQLITE_DONE) {
180- throw exceptions::no_rows (" no rows to extract: exactly 1 row expected" );
191+ throw exceptions::no_rows (" no rows to extract: exactly 1 row expected" , SQLITE_DONE );
181192 }
182193
183194 if ((hresult = sqlite3_step (_stmt.get ())) == SQLITE_ROW) {
184- throw exceptions::more_rows (" not all rows extracted" );
195+ throw exceptions::more_rows (" not all rows extracted" , SQLITE_ROW );
185196 }
186197
187198 if (hresult != SQLITE_DONE) {
@@ -198,6 +209,14 @@ namespace sqlite {
198209 return tmp;
199210 }
200211
212+ sqlite3_stmt* _prepare (const std::string& sql) {
213+ int hresult;
214+ sqlite3_stmt* tmp = nullptr ;
215+ hresult = sqlite3_prepare_v2 (_db.get (), sql.data (), -1 , &tmp, nullptr );
216+ if ((hresult) != SQLITE_OK) exceptions::throw_sqlite_error (hresult);
217+ return tmp;
218+ }
219+
201220 template <typename Type>
202221 struct is_sqlite_value : public std ::integral_constant<
203222 bool ,
@@ -207,8 +226,8 @@ namespace sqlite {
207226 || std::is_same<std::u16string, Type>::value
208227 || std::is_same<sqlite_int64, Type>::value
209228 > { };
210- template <typename Type>
211- struct is_sqlite_value < std::vector<Type> > : public std::integral_constant<
229+ template <typename Type, typename Allocator >
230+ struct is_sqlite_value < std::vector<Type, Allocator > > : public std::integral_constant<
212231 bool ,
213232 std::is_floating_point<Type>::value
214233 || std::is_integral<Type>::value
@@ -218,9 +237,9 @@ namespace sqlite {
218237
219238 template <typename T> friend database_binder& operator <<(database_binder& db, const T& val);
220239 template <typename T> friend void get_col_from_db (database_binder& db, int inx, T& val);
221- /* for vector<T> support */
222- template <typename T> friend database_binder& operator <<(database_binder& db, const std::vector<T>& val);
223- template <typename T> friend void get_col_from_db (database_binder& db, int inx, std::vector<T>& val);
240+ /* for vector<T, A > support */
241+ template <typename T, typename A > friend database_binder& operator <<(database_binder& db, const std::vector<T, A >& val);
242+ template <typename T, typename A > friend void get_col_from_db (database_binder& db, int inx, std::vector<T, A >& val);
224243 /* for nullptr & unique_ptr support */
225244 friend database_binder& operator <<(database_binder& db, std::nullptr_t );
226245 template <typename T> friend database_binder& operator <<(database_binder& db, const std::unique_ptr<T>& val);
@@ -241,7 +260,7 @@ namespace sqlite {
241260 friend database_binder& operator <<(database_binder& db, const std::u16string& txt);
242261
243262
244- #if __has_include(<optional>)
263+ #ifdef _MODERN_SQLITE_STD_OPTIONAL_SUPPORT
245264 template <typename OptionalT> friend database_binder& operator <<(database_binder& db, const std::optional<OptionalT>& val);
246265 template <typename OptionalT> friend void get_col_from_db (database_binder& db, int inx, std::optional<OptionalT>& o);
247266#endif
@@ -255,18 +274,20 @@ namespace sqlite {
255274
256275 database_binder (std::shared_ptr<sqlite3> db, std::u16string const & sql):
257276 _db (db),
258- _sql (sql),
259277 _stmt (_prepare(sql), sqlite3_finalize),
260278 _inx (1 ) {
261279 }
262280
263281 database_binder (std::shared_ptr<sqlite3> db, std::string const & sql):
264- database_binder (db, std::u16string(sql.begin(), sql.end())) {}
282+ _db (db),
283+ _stmt (_prepare(sql), sqlite3_finalize),
284+ _inx (1 ) {
285+ }
265286
266287 ~database_binder () noexcept (false ) {
267288 /* Will be executed if no >>op is found, but not if an exception
268289 is in mid flight */
269- if (!execution_started && !std::uncaught_exception () && _stmt) {
290+ if (!execution_started && !_has_uncaught_exception && _stmt) {
270291 execute ();
271292 }
272293 }
@@ -310,13 +331,16 @@ namespace sqlite {
310331 auto ret = sqlite3_open16 (db_name.data (), &tmp);
311332 _db = std::shared_ptr<sqlite3>(tmp, [=](sqlite3* ptr) { sqlite3_close_v2 (ptr); }); // this will close the connection eventually when no longer needed.
312333 if (ret != SQLITE_OK) exceptions::throw_sqlite_error (ret);
313-
314-
315334 // _db.reset(tmp, sqlite3_close); // alternative close. (faster?)
316335 }
317336
318- database (std::string const & db_name):
319- database (std::u16string(db_name.begin(), db_name.end())) {}
337+ database (std::string const & db_name): _db(nullptr ) {
338+ sqlite3* tmp = nullptr ;
339+ auto ret = sqlite3_open (db_name.data (), &tmp);
340+ _db = std::shared_ptr<sqlite3>(tmp, [=](sqlite3* ptr) { sqlite3_close_v2 (ptr); }); // this will close the connection eventually when no longer needed.
341+ if (ret != SQLITE_OK) exceptions::throw_sqlite_error (ret);
342+ // _db.reset(tmp, sqlite3_close); // alternative close. (faster?)
343+ }
320344
321345 database (std::shared_ptr<sqlite3> db):
322346 _db (db) {}
@@ -471,8 +495,8 @@ namespace sqlite {
471495 }
472496 }
473497
474- // vector<T>
475- template <typename T> inline database_binder& operator <<(database_binder& db, const std::vector<T>& vec) {
498+ // vector<T, A >
499+ template <typename T, typename A > inline database_binder& operator <<(database_binder& db, const std::vector<T, A >& vec) {
476500 void const * buf = reinterpret_cast <void const *>(vec.data ());
477501 int bytes = vec.size () * sizeof (T);
478502 int hresult;
@@ -482,13 +506,13 @@ namespace sqlite {
482506 ++db._inx ;
483507 return db;
484508 }
485- template <typename T> inline void get_col_from_db (database_binder& db, int inx, std::vector<T>& vec) {
509+ template <typename T, typename A > inline void get_col_from_db (database_binder& db, int inx, std::vector<T, A >& vec) {
486510 if (sqlite3_column_type (db._stmt .get (), inx) == SQLITE_NULL) {
487511 vec.clear ();
488512 } else {
489513 int bytes = sqlite3_column_bytes (db._stmt .get (), inx);
490514 T const * buf = reinterpret_cast <T const *>(sqlite3_column_blob (db._stmt .get (), inx));
491- vec = std::vector<T>(buf, buf + bytes/sizeof (T));
515+ vec = std::vector<T, A >(buf, buf + bytes/sizeof (T));
492516 }
493517 }
494518
@@ -565,7 +589,7 @@ namespace sqlite {
565589 return db;
566590 }
567591 // std::optional support for NULL values
568- #if __has_include(<optional>)
592+ #ifdef _MODERN_SQLITE_STD_OPTIONAL_SUPPORT
569593 template <typename OptionalT> inline database_binder& operator <<(database_binder& db, const std::optional<OptionalT>& val) {
570594 if (val) {
571595 return operator << (std::move (db), std::move (*val));
0 commit comments