diff --git a/README.md b/README.md index 1f79aa6e..ade74e00 100644 --- a/README.md +++ b/README.md @@ -377,8 +377,8 @@ To support all possible values, you can use `variant #include #include -#include #include #include #include @@ -34,93 +33,10 @@ #include +#include "sqlite_modern_cpp/errors.h" #include "sqlite_modern_cpp/utility/function_traits.h" #include "sqlite_modern_cpp/utility/uncaught_exceptions.h" -namespace sqlite { - - class sqlite_exception: public std::runtime_error { - public: - sqlite_exception(const char* msg, std::string sql, int code = -1): runtime_error(msg), code(code), sql(sql) {} - sqlite_exception(int code, std::string sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {} - int get_code() const {return code;} - std::string get_sql() const {return sql;} - private: - int code; - std::string sql; - }; - - namespace exceptions { - //One more or less trivial derived error class for each SQLITE error. - //Note the following are not errors so have no classes: - //SQLITE_OK, SQLITE_NOTICE, SQLITE_WARNING, SQLITE_ROW, SQLITE_DONE - // - //Note these names are exact matches to the names of the SQLITE error codes. - class error: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class internal: public sqlite_exception{ using sqlite_exception::sqlite_exception; }; - class perm: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class abort: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class busy: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class locked: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class nomem: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class readonly: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class interrupt: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class ioerr: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class corrupt: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class notfound: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class full: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class cantopen: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class protocol: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class empty: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class schema: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class toobig: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class constraint: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class mismatch: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class misuse: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class nolfs: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class auth: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class format: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class range: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class notadb: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - - //Some additional errors are here for the C++ interface - class more_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class no_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; }; - class reexecution: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements need to be reset before calling them again - class more_statements: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements can only contain one statement - - static void throw_sqlite_error(const int& error_code, const std::string &sql = "") { - if(error_code == SQLITE_ERROR) throw exceptions::error(error_code, sql); - else if(error_code == SQLITE_INTERNAL) throw exceptions::internal(error_code, sql); - else if(error_code == SQLITE_PERM) throw exceptions::perm(error_code, sql); - else if(error_code == SQLITE_ABORT) throw exceptions::abort(error_code, sql); - else if(error_code == SQLITE_BUSY) throw exceptions::busy(error_code, sql); - else if(error_code == SQLITE_LOCKED) throw exceptions::locked(error_code, sql); - else if(error_code == SQLITE_NOMEM) throw exceptions::nomem(error_code, sql); - else if(error_code == SQLITE_READONLY) throw exceptions::readonly(error_code, sql); - else if(error_code == SQLITE_INTERRUPT) throw exceptions::interrupt(error_code, sql); - else if(error_code == SQLITE_IOERR) throw exceptions::ioerr(error_code, sql); - else if(error_code == SQLITE_CORRUPT) throw exceptions::corrupt(error_code, sql); - else if(error_code == SQLITE_NOTFOUND) throw exceptions::notfound(error_code, sql); - else if(error_code == SQLITE_FULL) throw exceptions::full(error_code, sql); - else if(error_code == SQLITE_CANTOPEN) throw exceptions::cantopen(error_code, sql); - else if(error_code == SQLITE_PROTOCOL) throw exceptions::protocol(error_code, sql); - else if(error_code == SQLITE_EMPTY) throw exceptions::empty(error_code, sql); - else if(error_code == SQLITE_SCHEMA) throw exceptions::schema(error_code, sql); - else if(error_code == SQLITE_TOOBIG) throw exceptions::toobig(error_code, sql); - else if(error_code == SQLITE_CONSTRAINT) throw exceptions::constraint(error_code, sql); - else if(error_code == SQLITE_MISMATCH) throw exceptions::mismatch(error_code, sql); - else if(error_code == SQLITE_MISUSE) throw exceptions::misuse(error_code, sql); - else if(error_code == SQLITE_NOLFS) throw exceptions::nolfs(error_code, sql); - else if(error_code == SQLITE_AUTH) throw exceptions::auth(error_code, sql); - else if(error_code == SQLITE_FORMAT) throw exceptions::format(error_code, sql); - else if(error_code == SQLITE_RANGE) throw exceptions::range(error_code, sql); - else if(error_code == SQLITE_NOTADB) throw exceptions::notadb(error_code, sql); - else throw sqlite_exception(error_code, sql); - } - } -} - #ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT #include "sqlite_modern_cpp/utility/variant.h" #endif @@ -171,7 +87,7 @@ namespace sqlite { while((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {} if(hresult != SQLITE_DONE) { - exceptions::throw_sqlite_error(hresult, sql()); + errors::throw_sqlite_error(hresult, sql()); } } @@ -192,7 +108,7 @@ namespace sqlite { void used(bool state) { if(execution_started == true && state == true) { - throw exceptions::reexecution("Already used statement executed again! Please reset() first!",sql()); + throw errors::reexecution("Already used statement executed again! Please reset() first!",sql()); } execution_started = state; } @@ -216,7 +132,7 @@ namespace sqlite { } if(hresult != SQLITE_DONE) { - exceptions::throw_sqlite_error(hresult, sql()); + errors::throw_sqlite_error(hresult, sql()); } } @@ -227,15 +143,15 @@ namespace sqlite { if((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) { call_back(); } else if(hresult == SQLITE_DONE) { - throw exceptions::no_rows("no rows to extract: exactly 1 row expected", sql(), SQLITE_DONE); + throw errors::no_rows("no rows to extract: exactly 1 row expected", sql(), SQLITE_DONE); } if((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) { - throw exceptions::more_rows("not all rows extracted", sql(), SQLITE_ROW); + throw errors::more_rows("not all rows extracted", sql(), SQLITE_ROW); } if(hresult != SQLITE_DONE) { - exceptions::throw_sqlite_error(hresult, sql()); + errors::throw_sqlite_error(hresult, sql()); } } @@ -254,9 +170,9 @@ namespace sqlite { sqlite3_stmt* tmp = nullptr; const char *remaining; hresult = sqlite3_prepare_v2(_db.get(), sql.data(), -1, &tmp, &remaining); - if(hresult != SQLITE_OK) exceptions::throw_sqlite_error(hresult, sql); + if(hresult != SQLITE_OK) errors::throw_sqlite_error(hresult, sql); if(!std::all_of(remaining, sql.data() + sql.size(), [](char ch) {return std::isblank(ch);})) - throw exceptions::more_statements("Multiple semicolon separated statements are unsupported", sql); + throw errors::more_statements("Multiple semicolon separated statements are unsupported", sql); return tmp; } @@ -470,7 +386,8 @@ namespace sqlite { sqlite3* tmp = nullptr; auto ret = sqlite3_open_v2(db_name.data(), &tmp, static_cast(config.flags), config.zVfs); _db = std::shared_ptr(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); + if(ret != SQLITE_OK) errors::throw_sqlite_error(_db ? sqlite3_extended_errcode(_db.get()) : ret); + sqlite3_extended_result_codes(_db.get(), true); if(config.encoding == Encoding::UTF16) *this << R"(PRAGMA encoding = "UTF-16";)"; } @@ -484,7 +401,8 @@ namespace sqlite { sqlite3* tmp = nullptr; auto ret = sqlite3_open_v2(db_name_utf8.data(), &tmp, static_cast(config.flags), config.zVfs); _db = std::shared_ptr(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); + if(ret != SQLITE_OK) errors::throw_sqlite_error(_db ? sqlite3_extended_errcode(_db.get()) : ret); + sqlite3_extended_result_codes(_db.get(), true); if(config.encoding != Encoding::UTF8) *this << R"(PRAGMA encoding = "UTF-16";)"; } @@ -525,7 +443,7 @@ namespace sqlite { nullptr, nullptr, [](void* ptr){ delete static_cast(ptr); })) - exceptions::throw_sqlite_error(result); + errors::throw_sqlite_error(result); } template @@ -541,7 +459,7 @@ namespace sqlite { [](void* ptr){ delete static_cast(ptr); })) - exceptions::throw_sqlite_error(result); + errors::throw_sqlite_error(result); } }; @@ -598,7 +516,7 @@ namespace sqlite { 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) { - exceptions::throw_sqlite_error(hresult, db.sql()); + errors::throw_sqlite_error(hresult, db.sql()); } ++db._inx; return db; @@ -625,7 +543,7 @@ namespace sqlite { 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) { - exceptions::throw_sqlite_error(hresult, db.sql()); + errors::throw_sqlite_error(hresult, db.sql()); } ++db._inx; @@ -653,7 +571,7 @@ namespace sqlite { 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) { - exceptions::throw_sqlite_error(hresult, db.sql()); + errors::throw_sqlite_error(hresult, db.sql()); } ++db._inx; @@ -681,7 +599,7 @@ namespace sqlite { 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) { - exceptions::throw_sqlite_error(hresult, db.sql()); + errors::throw_sqlite_error(hresult, db.sql()); } ++db._inx; @@ -711,7 +629,7 @@ namespace sqlite { int bytes = vec.size() * sizeof(T); int hresult; if((hresult = sqlite3_bind_blob(db._stmt.get(), db._inx, buf, bytes, SQLITE_TRANSIENT)) != SQLITE_OK) { - exceptions::throw_sqlite_error(hresult, db.sql()); + errors::throw_sqlite_error(hresult, db.sql()); } ++db._inx; return db; @@ -744,7 +662,7 @@ namespace sqlite { inline database_binder& operator <<(database_binder& db, std::nullptr_t) { int hresult; if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) { - exceptions::throw_sqlite_error(hresult, db.sql()); + errors::throw_sqlite_error(hresult, db.sql()); } ++db._inx; return db; @@ -806,7 +724,7 @@ namespace sqlite { 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) { - exceptions::throw_sqlite_error(hresult, db.sql()); + errors::throw_sqlite_error(hresult, db.sql()); } ++db._inx; @@ -837,7 +755,7 @@ namespace sqlite { 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) { - exceptions::throw_sqlite_error(hresult, db.sql()); + errors::throw_sqlite_error(hresult, db.sql()); } ++db._inx; @@ -877,7 +795,7 @@ namespace sqlite { } int hresult; if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) { - exceptions::throw_sqlite_error(hresult, db.sql()); + errors::throw_sqlite_error(hresult, db.sql()); } ++db._inx; @@ -918,7 +836,7 @@ namespace sqlite { } int hresult; if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) { - exceptions::throw_sqlite_error(hresult, db.sql()); + errors::throw_sqlite_error(hresult, db.sql()); } ++db._inx; diff --git a/hdr/sqlite_modern_cpp/errors.h b/hdr/sqlite_modern_cpp/errors.h new file mode 100644 index 00000000..60faaecc --- /dev/null +++ b/hdr/sqlite_modern_cpp/errors.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include + +#include + +namespace sqlite { + + class sqlite_exception: public std::runtime_error { + public: + sqlite_exception(const char* msg, std::string sql, int code = -1): runtime_error(msg), code(code), sql(sql) {} + sqlite_exception(int code, std::string sql): runtime_error(sqlite3_errstr(code)), code(code), sql(sql) {} + int get_code() const {return code & 0xFF;} + int get_extended_code() const {return code;} + std::string get_sql() const {return sql;} + private: + int code; + std::string sql; + }; + + namespace errors { + //One more or less trivial derived error class for each SQLITE error. + //Note the following are not errors so have no classes: + //SQLITE_OK, SQLITE_NOTICE, SQLITE_WARNING, SQLITE_ROW, SQLITE_DONE + // + //Note these names are exact matches to the names of the SQLITE error codes. +#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \ + class name: public sqlite_exception { using sqlite_exception::sqlite_exception; };\ + derived +#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \ + class base ## _ ## sub: public base { using base::base; }; +#include "lists/error_codes.h" +#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED +#undef SQLITE_MODERN_CPP_ERROR_CODE + + //Some additional errors are here for the C++ interface + class more_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; }; + class no_rows: public sqlite_exception { using sqlite_exception::sqlite_exception; }; + class reexecution: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements need to be reset before calling them again + class more_statements: public sqlite_exception { using sqlite_exception::sqlite_exception; }; // Prepared statements can only contain one statement + + static void throw_sqlite_error(const int& error_code, const std::string &sql = "") { + switch(error_code & 0xFF) { +#define SQLITE_MODERN_CPP_ERROR_CODE(NAME,name,derived) \ + case SQLITE_ ## NAME: switch(error_code) { \ + derived \ + default: throw name(error_code, sql); \ + } +#define SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BASE,SUB,base,sub) \ + case SQLITE_ ## BASE ## _ ## SUB: throw base ## _ ## sub(error_code, sql); +#include "lists/error_codes.h" +#undef SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED +#undef SQLITE_MODERN_CPP_ERROR_CODE + default: throw sqlite_exception(error_code, sql); + } + } + } + namespace exceptions = errors; +} diff --git a/hdr/sqlite_modern_cpp/lists/error_codes.h b/hdr/sqlite_modern_cpp/lists/error_codes.h new file mode 100644 index 00000000..195aa7d4 --- /dev/null +++ b/hdr/sqlite_modern_cpp/lists/error_codes.h @@ -0,0 +1,95 @@ +SQLITE_MODERN_CPP_ERROR_CODE(ERROR,error,) +SQLITE_MODERN_CPP_ERROR_CODE(INTERNAL,internal,) +SQLITE_MODERN_CPP_ERROR_CODE(PERM,perm,) +SQLITE_MODERN_CPP_ERROR_CODE(ABORT,abort, + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(ABORT,ROLLBACK,abort,rollback) +) +SQLITE_MODERN_CPP_ERROR_CODE(BUSY,busy, + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BUSY,RECOVERY,busy,recovery) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(BUSY,SNAPSHOT,busy,snapshot) +) +SQLITE_MODERN_CPP_ERROR_CODE(LOCKED,locked, + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(LOCKED,SHAREDCACHE,locked,sharedcache) +) +SQLITE_MODERN_CPP_ERROR_CODE(NOMEM,nomem,) +SQLITE_MODERN_CPP_ERROR_CODE(READONLY,readonly,) +SQLITE_MODERN_CPP_ERROR_CODE(INTERRUPT,interrupt,) +SQLITE_MODERN_CPP_ERROR_CODE(IOERR,ioerr, + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,READ,ioerr,read) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHORT_READ,ioerr,short_read) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,WRITE,ioerr,write) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,FSYNC,ioerr,fsync) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,DIR_FSYNC,ioerr,dir_fsync) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,TRUNCATE,ioerr,truncate) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,FSTAT,ioerr,fstat) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,UNLOCK,ioerr,unlock) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,RDLOCK,ioerr,rdlock) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,DELETE,ioerr,delete) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,BLOCKED,ioerr,blocked) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,NOMEM,ioerr,nomem) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,ACCESS,ioerr,access) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,CHECKRESERVEDLOCK,ioerr,checkreservedlock) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,LOCK,ioerr,lock) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,CLOSE,ioerr,close) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,DIR_CLOSE,ioerr,dir_close) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHMOPEN,ioerr,shmopen) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHMSIZE,ioerr,shmsize) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHMLOCK,ioerr,shmlock) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SHMMAP,ioerr,shmmap) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,SEEK,ioerr,seek) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,DELETE_NOENT,ioerr,delete_noent) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,MMAP,ioerr,mmap) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,GETTEMPPATH,ioerr,gettemppath) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,CONVPATH,ioerr,convpath) +#if SQLITE_VERSION_NUMBER >= 3009000 + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,VNODE,ioerr,vnode) +#endif +#if SQLITE_VERSION_NUMBER >= 3010000 + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(IOERR,AUTH,ioerr,auth) +#endif +) +SQLITE_MODERN_CPP_ERROR_CODE(CORRUPT,corrupt, + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CORRUPT,VTAB,corrupt,vtab) +) +SQLITE_MODERN_CPP_ERROR_CODE(NOTFOUND,notfound,) +SQLITE_MODERN_CPP_ERROR_CODE(FULL,full,) +SQLITE_MODERN_CPP_ERROR_CODE(CANTOPEN,cantopen, + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN,NOTEMPDIR,cantopen,notempdir) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN,ISDIR,cantopen,isdir) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN,FULLPATH,cantopen,fullpath) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CANTOPEN,CONVPATH,cantopen,convpath) +) +SQLITE_MODERN_CPP_ERROR_CODE(PROTOCOL,protocol,) +SQLITE_MODERN_CPP_ERROR_CODE(EMPTY,empty,) +SQLITE_MODERN_CPP_ERROR_CODE(SCHEMA,schema,) +SQLITE_MODERN_CPP_ERROR_CODE(TOOBIG,toobig,) +SQLITE_MODERN_CPP_ERROR_CODE(CONSTRAINT,constraint, + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,CHECK,constraint,check) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,COMMITHOOK,constraint,commithook) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,FOREIGNKEY,constraint,foreignkey) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,FUNCTION,constraint,function) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,NOTNULL,constraint,notnull) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,PRIMARYKEY,constraint,primarykey) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,TRIGGER,constraint,trigger) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,UNIQUE,constraint,unique) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,VTAB,constraint,vtab) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(CONSTRAINT,ROWID,constraint,rowid) +) +SQLITE_MODERN_CPP_ERROR_CODE(MISMATCH,mismatch,) +SQLITE_MODERN_CPP_ERROR_CODE(MISUSE,misuse,) +SQLITE_MODERN_CPP_ERROR_CODE(NOLFS,nolfs,) +SQLITE_MODERN_CPP_ERROR_CODE(AUTH,auth, +#if SQLITE_VERSION_NUMBER >= 3009000 + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(AUTH,USER,auth,user) +#endif +) +SQLITE_MODERN_CPP_ERROR_CODE(FORMAT,format,) +SQLITE_MODERN_CPP_ERROR_CODE(RANGE,range,) +SQLITE_MODERN_CPP_ERROR_CODE(NOTADB,notadb,) +SQLITE_MODERN_CPP_ERROR_CODE(NOTICE,notice, + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(NOTICE,RECOVER_WAL,notice,recover_wal) + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(NOTICE,RECOVER_ROLLBACK,notice,recover_rollback) +) +SQLITE_MODERN_CPP_ERROR_CODE(WARNING,warning, + SQLITE_MODERN_CPP_ERROR_CODE_EXTENDED(WARNING,AUTOINDEX,warning,autoindex) +) diff --git a/hdr/sqlite_modern_cpp/sqlcipher.h b/hdr/sqlite_modern_cpp/sqlcipher.h index 6d2c3d88..da0f0189 100644 --- a/hdr/sqlite_modern_cpp/sqlcipher.h +++ b/hdr/sqlite_modern_cpp/sqlcipher.h @@ -23,22 +23,22 @@ namespace sqlite { void set_key(const std::string &key) { if(auto ret = sqlite3_key(_db.get(), key.data(), key.size())) - exceptions::throw_sqlite_error(ret); + errors::throw_sqlite_error(ret); } void set_key(const std::string &key, const std::string &db_name) { if(auto ret = sqlite3_key_v2(_db.get(), db_name.c_str(), key.data(), key.size())) - exceptions::throw_sqlite_error(ret); + errors::throw_sqlite_error(ret); } void rekey(const std::string &new_key) { if(auto ret = sqlite3_rekey(_db.get(), new_key.data(), new_key.size())) - exceptions::throw_sqlite_error(ret); + errors::throw_sqlite_error(ret); } void rekey(const std::string &new_key, const std::string &db_name) { if(auto ret = sqlite3_rekey_v2(_db.get(), db_name.c_str(), new_key.data(), new_key.size())) - exceptions::throw_sqlite_error(ret); + errors::throw_sqlite_error(ret); } }; } diff --git a/hdr/sqlite_modern_cpp/utility/variant.h b/hdr/sqlite_modern_cpp/utility/variant.h index 65c63ba5..11a8429f 100644 --- a/hdr/sqlite_modern_cpp/utility/variant.h +++ b/hdr/sqlite_modern_cpp/utility/variant.h @@ -1,5 +1,6 @@ #pragma once +#include "../errors.h" #include #include #include @@ -30,7 +31,7 @@ namespace sqlite::utility { template inline void variant_select_null(Callback&&callback) { if constexpr(std::is_same_v::type, void>) { - throw exceptions::mismatch("NULL is unsupported by this variant.", "", SQLITE_MISMATCH); + throw errors::mismatch("NULL is unsupported by this variant.", "", SQLITE_MISMATCH); } else { std::forward(callback)(typename VariantFirstNullable::type()); } @@ -65,7 +66,7 @@ namespace sqlite::utility { template inline auto variant_select_integer(Callback&&callback) { if constexpr(std::is_same_v::type, void>) { - throw exceptions::mismatch("Integer is unsupported by this variant.", "", SQLITE_MISMATCH); + throw errors::mismatch("Integer is unsupported by this variant.", "", SQLITE_MISMATCH); } else { std::forward(callback)(typename VariantFirstIntegerable::type()); } @@ -100,7 +101,7 @@ namespace sqlite::utility { template inline auto variant_select_float(Callback&&callback) { if constexpr(std::is_same_v::type, void>) { - throw exceptions::mismatch("Real is unsupported by this variant.", "", SQLITE_MISMATCH); + throw errors::mismatch("Real is unsupported by this variant.", "", SQLITE_MISMATCH); } else { std::forward(callback)(typename VariantFirstFloatable::type()); } @@ -135,7 +136,7 @@ namespace sqlite::utility { template inline void variant_select_text(Callback&&callback) { if constexpr(std::is_same_v::type, void>) { - throw exceptions::mismatch("Text is unsupported by this variant.", "", SQLITE_MISMATCH); + throw errors::mismatch("Text is unsupported by this variant.", "", SQLITE_MISMATCH); } else { std::forward(callback)(typename VariantFirstTextable::type()); } @@ -166,7 +167,7 @@ namespace sqlite::utility { template inline auto variant_select_blob(Callback&&callback) { if constexpr(std::is_same_v::type, void>) { - throw exceptions::mismatch("Blob is unsupported by this variant.", "", SQLITE_MISMATCH); + throw errors::mismatch("Blob is unsupported by this variant.", "", SQLITE_MISMATCH); } else { std::forward(callback)(typename VariantFirstBlobable::type()); } diff --git a/tests/exceptions.cc b/tests/exceptions.cc index 47581246..c79b0f5b 100644 --- a/tests/exceptions.cc +++ b/tests/exceptions.cc @@ -17,7 +17,7 @@ int main() { 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) { + } catch (errors::constraint& e) { cerr << e.get_code() << ": " << e.what() << " during " << quoted(e.get_sql()) << endl; expception_thrown = true; @@ -29,9 +29,6 @@ int main() { cerr << "Wrong statement failed\n"; exit(EXIT_FAILURE); } - } catch (...) { - cerr << "Ok, we have our excpetion thrown" << endl; - expception_thrown = true; } if(!expception_thrown) { diff --git a/tests/extended_exceptions.cc b/tests/extended_exceptions.cc new file mode 100644 index 00000000..937d02f1 --- /dev/null +++ b/tests/extended_exceptions.cc @@ -0,0 +1,39 @@ +#include +#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 (errors::constraint_primarykey& e) { + cerr << e.get_code() << '/' << e.get_extended_code() << ": " << e.what() << " during " + << quoted(e.get_sql()) << endl; + expception_thrown = true; +#if SQLITE_VERSION_NUMBER >= 3014000 + if(e.get_sql() != "INSERT INTO person (id,name) VALUES (1,'jack')") { +#else + if(e.get_sql() != "INSERT INTO person (id,name) VALUES (?,?)") { +#endif + cerr << "Wrong statement failed\n"; + exit(EXIT_FAILURE); + } + } + + if(!expception_thrown) { + exit(EXIT_FAILURE); + } + + exit(EXIT_SUCCESS); +} diff --git a/tests/flags.cc b/tests/flags.cc index 5ebe4897..ed1f116d 100644 --- a/tests/flags.cc +++ b/tests/flags.cc @@ -93,7 +93,7 @@ int main() db << "INSERT INTO foo VALUES (?)" << "invalid"; cout << "Unexpected success on line " << __LINE__ << endl; exit(EXIT_FAILURE); - } catch(exceptions::readonly&) {} + } catch(errors::readonly&) {} } } catch(sqlite_exception e) diff --git a/tests/prepared_statment.cc b/tests/prepared_statment.cc index 5cd63882..b50d356d 100644 --- a/tests/prepared_statment.cc +++ b/tests/prepared_statment.cc @@ -86,7 +86,7 @@ int main() { try { prep.execute(); exit(EXIT_FAILURE); - } catch(exceptions::reexecution& ex) { + } catch(errors::reexecution& ex) { // Thats ok here } catch(...) { exit(EXIT_FAILURE); diff --git a/tests/sqlcipher.cc b/tests/sqlcipher.cc index 3c299bf9..87e32c29 100644 --- a/tests/sqlcipher.cc +++ b/tests/sqlcipher.cc @@ -48,7 +48,7 @@ int main() cout << "Can open with wrong key"; exit(EXIT_FAILURE); - } catch(exceptions::notadb) { + } catch(errors::notadb) { // Expected, wrong key } {