Skip to content

Commit 0a78e1d

Browse files
committed
Move exception-related stuff into error header
1 parent 75a40b3 commit 0a78e1d

File tree

10 files changed

+142
-93
lines changed

10 files changed

+142
-93
lines changed

README.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -377,8 +377,8 @@ To support all possible values, you can use `variant<nullptr_t, sqlite_int64, do
377377
Errors
378378
----
379379

380-
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.
381-
sqlite::sqlite_exception has a `get_code()` member function to get the SQLITE3 error code.
380+
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.
381+
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.
382382
Additionally you can use `get_sql()` to see the SQL statement leading to the error.
383383

384384
```c++
@@ -397,7 +397,9 @@ Additionally you can use `get_sql()` to see the SQL statement leading to the err
397397
<< e.get_sql() << endl;
398398
}
399399
/* you can catch specific exceptions as well,
400-
catch(sqlite::exceptions::constraint e) { } */
400+
catch(sqlite::errors::constraint e) { } */
401+
/* and even more specific exceptions
402+
catch(sqlite::errors::constraint_primarykey e) { } */
401403
```
402404
403405
Custom SQL functions

hdr/sqlite_modern_cpp.h

+23-76
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
#include <cctype>
55
#include <string>
66
#include <functional>
7-
#include <stdexcept>
87
#include <ctime>
98
#include <tuple>
109
#include <memory>
@@ -34,62 +33,10 @@
3433

3534
#include <sqlite3.h>
3635

36+
#include "sqlite_modern_cpp/errors.h"
3737
#include "sqlite_modern_cpp/utility/function_traits.h"
3838
#include "sqlite_modern_cpp/utility/uncaught_exceptions.h"
3939

40-
namespace sqlite {
41-
42-
class sqlite_exception: public std::runtime_error {
43-
public:
44-
sqlite_exception(const char* msg, std::string sql, int code = -1): runtime_error(msg), code(code), sql(sql) {}
45-
sqlite_exception(int code, std::string sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {}
46-
int get_code() const {return code & 0xFF;}
47-
int get_extended_code() const {return code;}
48-
std::string get_sql() const {return sql;}
49-
private:
50-
int code;
51-
std::string sql;
52-
};
53-
54-
namespace exceptions {
55-
//One more or less trivial derived error class for each SQLITE error.
56-
//Note the following are not errors so have no classes:
57-
//SQLITE_OK, SQLITE_NOTICE, SQLITE_WARNING, SQLITE_ROW, SQLITE_DONE
58-
//
59-
//Note these names are exact matches to the names of the SQLITE error codes.
60-
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
61-
class name: public sqlite_exception { using sqlite_exception::sqlite_exception; };\
62-
derived
63-
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \
64-
class base ## _ ## sub: public base { using base::base; };
65-
#include "sqlite_modern_cpp/lists/error_codes.h"
66-
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
67-
#undef SQLITE_MODERN_CPP_ERROR_CODE
68-
69-
//Some additional errors are here for the C++ interface
70-
class more_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
71-
class no_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
72-
class reexecution: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements need to be reset before calling them again
73-
class more_statements: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements can only contain one statement
74-
75-
static void throw_sqlite_error(const int& error_code, const std::string &sql = "") {
76-
switch(error_code & 0xFF) {
77-
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
78-
case SQLITE_ ## NAME: switch(error_code) { \
79-
derived \
80-
default: throw exceptions::name(error_code, sql); \
81-
}
82-
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \
83-
case SQLITE_ ## BASE ## _ ## SUB: throw base ## _ ## sub(error_code, sql);
84-
#include "sqlite_modern_cpp/lists/error_codes.h"
85-
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
86-
#undef SQLITE_MODERN_CPP_ERROR_CODE
87-
default: throw sqlite_exception(error_code, sql);
88-
}
89-
}
90-
}
91-
}
92-
9340
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
9441
#include "sqlite_modern_cpp/utility/variant.h"
9542
#endif
@@ -140,7 +87,7 @@ namespace sqlite {
14087
while((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {}
14188

14289
if(hresult != SQLITE_DONE) {
143-
exceptions::throw_sqlite_error(hresult, sql());
90+
errors::throw_sqlite_error(hresult, sql());
14491
}
14592

14693
}
@@ -161,7 +108,7 @@ namespace sqlite {
161108

162109
void used(bool state) {
163110
if(execution_started == true && state == true) {
164-
throw exceptions::reexecution("Already used statement executed again! Please reset() first!",sql());
111+
throw errors::reexecution("Already used statement executed again! Please reset() first!",sql());
165112
}
166113
execution_started = state;
167114
}
@@ -185,7 +132,7 @@ namespace sqlite {
185132
}
186133

187134
if(hresult != SQLITE_DONE) {
188-
exceptions::throw_sqlite_error(hresult, sql());
135+
errors::throw_sqlite_error(hresult, sql());
189136
}
190137
}
191138

@@ -196,15 +143,15 @@ namespace sqlite {
196143
if((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {
197144
call_back();
198145
} else if(hresult == SQLITE_DONE) {
199-
throw exceptions::no_rows("no rows to extract: exactly 1 row expected", sql(), SQLITE_DONE);
146+
throw errors::no_rows("no rows to extract: exactly 1 row expected", sql(), SQLITE_DONE);
200147
}
201148

202149
if((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {
203-
throw exceptions::more_rows("not all rows extracted", sql(), SQLITE_ROW);
150+
throw errors::more_rows("not all rows extracted", sql(), SQLITE_ROW);
204151
}
205152

206153
if(hresult != SQLITE_DONE) {
207-
exceptions::throw_sqlite_error(hresult, sql());
154+
errors::throw_sqlite_error(hresult, sql());
208155
}
209156
}
210157

@@ -223,9 +170,9 @@ namespace sqlite {
223170
sqlite3_stmt* tmp = nullptr;
224171
const char *remaining;
225172
hresult = sqlite3_prepare_v2(_db.get(), sql.data(), -1, &tmp, &remaining);
226-
if(hresult != SQLITE_OK) exceptions::throw_sqlite_error(hresult, sql);
173+
if(hresult != SQLITE_OK) errors::throw_sqlite_error(hresult, sql);
227174
if(!std::all_of(remaining, sql.data() + sql.size(), [](char ch) {return std::isblank(ch);}))
228-
throw exceptions::more_statements("Multiple semicolon separated statements are unsupported", sql);
175+
throw errors::more_statements("Multiple semicolon separated statements are unsupported", sql);
229176
return tmp;
230177
}
231178

@@ -439,7 +386,7 @@ namespace sqlite {
439386
sqlite3* tmp = nullptr;
440387
auto ret = sqlite3_open_v2(db_name.data(), &tmp, static_cast<int>(config.flags), config.zVfs);
441388
_db = std::shared_ptr<sqlite3>(tmp, [=](sqlite3* ptr) { sqlite3_close_v2(ptr); }); // this will close the connection eventually when no longer needed.
442-
if(ret != SQLITE_OK) exceptions::throw_sqlite_error(_db ? sqlite3_extended_errcode(_db.get()) : ret);
389+
if(ret != SQLITE_OK) errors::throw_sqlite_error(_db ? sqlite3_extended_errcode(_db.get()) : ret);
443390
sqlite3_extended_result_codes(_db.get(), true);
444391
if(config.encoding == Encoding::UTF16)
445392
*this << R"(PRAGMA encoding = "UTF-16";)";
@@ -454,7 +401,7 @@ namespace sqlite {
454401
sqlite3* tmp = nullptr;
455402
auto ret = sqlite3_open_v2(db_name_utf8.data(), &tmp, static_cast<int>(config.flags), config.zVfs);
456403
_db = std::shared_ptr<sqlite3>(tmp, [=](sqlite3* ptr) { sqlite3_close_v2(ptr); }); // this will close the connection eventually when no longer needed.
457-
if(ret != SQLITE_OK) exceptions::throw_sqlite_error(_db ? sqlite3_extended_errcode(_db.get()) : ret);
404+
if(ret != SQLITE_OK) errors::throw_sqlite_error(_db ? sqlite3_extended_errcode(_db.get()) : ret);
458405
sqlite3_extended_result_codes(_db.get(), true);
459406
if(config.encoding != Encoding::UTF8)
460407
*this << R"(PRAGMA encoding = "UTF-16";)";
@@ -496,7 +443,7 @@ namespace sqlite {
496443
nullptr, nullptr, [](void* ptr){
497444
delete static_cast<decltype(funcPtr)>(ptr);
498445
}))
499-
exceptions::throw_sqlite_error(result);
446+
errors::throw_sqlite_error(result);
500447
}
501448

502449
template <typename StepFunction, typename FinalFunction>
@@ -512,7 +459,7 @@ namespace sqlite {
512459
[](void* ptr){
513460
delete static_cast<decltype(funcPtr)>(ptr);
514461
}))
515-
exceptions::throw_sqlite_error(result);
462+
errors::throw_sqlite_error(result);
516463
}
517464

518465
};
@@ -569,7 +516,7 @@ namespace sqlite {
569516
inline database_binder& operator<<(database_binder& db, const int& val) {
570517
int hresult;
571518
if((hresult = sqlite3_bind_int(db._stmt.get(), db._inx, val)) != SQLITE_OK) {
572-
exceptions::throw_sqlite_error(hresult, db.sql());
519+
errors::throw_sqlite_error(hresult, db.sql());
573520
}
574521
++db._inx;
575522
return db;
@@ -596,7 +543,7 @@ namespace sqlite {
596543
inline database_binder& operator <<(database_binder& db, const sqlite_int64& val) {
597544
int hresult;
598545
if((hresult = sqlite3_bind_int64(db._stmt.get(), db._inx, val)) != SQLITE_OK) {
599-
exceptions::throw_sqlite_error(hresult, db.sql());
546+
errors::throw_sqlite_error(hresult, db.sql());
600547
}
601548

602549
++db._inx;
@@ -624,7 +571,7 @@ namespace sqlite {
624571
inline database_binder& operator <<(database_binder& db, const float& val) {
625572
int hresult;
626573
if((hresult = sqlite3_bind_double(db._stmt.get(), db._inx, double(val))) != SQLITE_OK) {
627-
exceptions::throw_sqlite_error(hresult, db.sql());
574+
errors::throw_sqlite_error(hresult, db.sql());
628575
}
629576

630577
++db._inx;
@@ -652,7 +599,7 @@ namespace sqlite {
652599
inline database_binder& operator <<(database_binder& db, const double& val) {
653600
int hresult;
654601
if((hresult = sqlite3_bind_double(db._stmt.get(), db._inx, val)) != SQLITE_OK) {
655-
exceptions::throw_sqlite_error(hresult, db.sql());
602+
errors::throw_sqlite_error(hresult, db.sql());
656603
}
657604

658605
++db._inx;
@@ -682,7 +629,7 @@ namespace sqlite {
682629
int bytes = vec.size() * sizeof(T);
683630
int hresult;
684631
if((hresult = sqlite3_bind_blob(db._stmt.get(), db._inx, buf, bytes, SQLITE_TRANSIENT)) != SQLITE_OK) {
685-
exceptions::throw_sqlite_error(hresult, db.sql());
632+
errors::throw_sqlite_error(hresult, db.sql());
686633
}
687634
++db._inx;
688635
return db;
@@ -715,7 +662,7 @@ namespace sqlite {
715662
inline database_binder& operator <<(database_binder& db, std::nullptr_t) {
716663
int hresult;
717664
if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) {
718-
exceptions::throw_sqlite_error(hresult, db.sql());
665+
errors::throw_sqlite_error(hresult, db.sql());
719666
}
720667
++db._inx;
721668
return db;
@@ -777,7 +724,7 @@ namespace sqlite {
777724
inline database_binder& operator <<(database_binder& db, const std::string& txt) {
778725
int hresult;
779726
if((hresult = sqlite3_bind_text(db._stmt.get(), db._inx, txt.data(), -1, SQLITE_TRANSIENT)) != SQLITE_OK) {
780-
exceptions::throw_sqlite_error(hresult, db.sql());
727+
errors::throw_sqlite_error(hresult, db.sql());
781728
}
782729

783730
++db._inx;
@@ -808,7 +755,7 @@ namespace sqlite {
808755
inline database_binder& operator <<(database_binder& db, const std::u16string& txt) {
809756
int hresult;
810757
if((hresult = sqlite3_bind_text16(db._stmt.get(), db._inx, txt.data(), -1, SQLITE_TRANSIENT)) != SQLITE_OK) {
811-
exceptions::throw_sqlite_error(hresult, db.sql());
758+
errors::throw_sqlite_error(hresult, db.sql());
812759
}
813760

814761
++db._inx;
@@ -848,7 +795,7 @@ namespace sqlite {
848795
}
849796
int hresult;
850797
if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) {
851-
exceptions::throw_sqlite_error(hresult, db.sql());
798+
errors::throw_sqlite_error(hresult, db.sql());
852799
}
853800

854801
++db._inx;
@@ -889,7 +836,7 @@ namespace sqlite {
889836
}
890837
int hresult;
891838
if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) {
892-
exceptions::throw_sqlite_error(hresult, db.sql());
839+
errors::throw_sqlite_error(hresult, db.sql());
893840
}
894841

895842
++db._inx;

hdr/sqlite_modern_cpp/errors.h

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include <stdexcept>
5+
6+
#include <sqlite3.h>
7+
8+
namespace sqlite {
9+
10+
class sqlite_exception: public std::runtime_error {
11+
public:
12+
sqlite_exception(const char* msg, std::string sql, int code = -1): runtime_error(msg), code(code), sql(sql) {}
13+
sqlite_exception(int code, std::string sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {}
14+
int get_code() const {return code & 0xFF;}
15+
int get_extended_code() const {return code;}
16+
std::string get_sql() const {return sql;}
17+
private:
18+
int code;
19+
std::string sql;
20+
};
21+
22+
namespace errors {
23+
//One more or less trivial derived error class for each SQLITE error.
24+
//Note the following are not errors so have no classes:
25+
//SQLITE_OK, SQLITE_NOTICE, SQLITE_WARNING, SQLITE_ROW, SQLITE_DONE
26+
//
27+
//Note these names are exact matches to the names of the SQLITE error codes.
28+
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
29+
class name: public sqlite_exception { using sqlite_exception::sqlite_exception; };\
30+
derived
31+
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \
32+
class base ## _ ## sub: public base { using base::base; };
33+
#include "lists/error_codes.h"
34+
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
35+
#undef SQLITE_MODERN_CPP_ERROR_CODE
36+
37+
//Some additional errors are here for the C++ interface
38+
class more_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
39+
class no_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; };
40+
class reexecution: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements need to be reset before calling them again
41+
class more_statements: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements can only contain one statement
42+
43+
static void throw_sqlite_error(const int& error_code, const std::string &sql = "") {
44+
switch(error_code & 0xFF) {
45+
#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \
46+
case SQLITE_ ## NAME: switch(error_code) { \
47+
derived \
48+
default: throw name(error_code, sql); \
49+
}
50+
#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \
51+
case SQLITE_ ## BASE ## _ ## SUB: throw base ## _ ## sub(error_code, sql);
52+
#include "lists/error_codes.h"
53+
#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED
54+
#undef SQLITE_MODERN_CPP_ERROR_CODE
55+
default: throw sqlite_exception(error_code, sql);
56+
}
57+
}
58+
}
59+
namespace exceptions = errors;
60+
}

hdr/sqlite_modern_cpp/sqlcipher.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,22 @@ namespace sqlite {
2323

2424
void set_key(const std::string &key) {
2525
if(auto ret = sqlite3_key(_db.get(), key.data(), key.size()))
26-
exceptions::throw_sqlite_error(ret);
26+
errors::throw_sqlite_error(ret);
2727
}
2828

2929
void set_key(const std::string &key, const std::string &db_name) {
3030
if(auto ret = sqlite3_key_v2(_db.get(), db_name.c_str(), key.data(), key.size()))
31-
exceptions::throw_sqlite_error(ret);
31+
errors::throw_sqlite_error(ret);
3232
}
3333

3434
void rekey(const std::string &new_key) {
3535
if(auto ret = sqlite3_rekey(_db.get(), new_key.data(), new_key.size()))
36-
exceptions::throw_sqlite_error(ret);
36+
errors::throw_sqlite_error(ret);
3737
}
3838

3939
void rekey(const std::string &new_key, const std::string &db_name) {
4040
if(auto ret = sqlite3_rekey_v2(_db.get(), db_name.c_str(), new_key.data(), new_key.size()))
41-
exceptions::throw_sqlite_error(ret);
41+
errors::throw_sqlite_error(ret);
4242
}
4343
};
4444
}

0 commit comments

Comments
 (0)