diff --git a/include/SQLiteCpp/Database.h b/include/SQLiteCpp/Database.h index f64c995..b82ccc6 100644 --- a/include/SQLiteCpp/Database.h +++ b/include/SQLiteCpp/Database.h @@ -378,7 +378,7 @@ private: { if (SQLITE_OK != aRet) { - throw SQLite::Exception(sqlite3_errstr(aRet)); + throw SQLite::Exception(mpSQLite, aRet); } } diff --git a/include/SQLiteCpp/Exception.h b/include/SQLiteCpp/Exception.h index ae7a8ed..e3a5ece 100644 --- a/include/SQLiteCpp/Exception.h +++ b/include/SQLiteCpp/Exception.h @@ -12,31 +12,8 @@ #include #include - - -namespace SQLite -{ - - -/** - * @brief Encapsulation of the error message from SQLite3, based on std::runtime_error. - */ -class Exception : public std::runtime_error -{ -public: - /** - * @brief Encapsulation of the error message from SQLite3, based on std::runtime_error. - * - * @param[in] aErrorMessage The string message describing the SQLite error - */ - explicit Exception(const std::string& aErrorMessage) : - std::runtime_error(aErrorMessage) - { - } -}; - - -} // namespace SQLite +#include +#include /// Compatibility with non-clang compilers. @@ -56,3 +33,91 @@ public: // Visual Studio 2013 does not support noexcept, and "throw()" is deprecated by C++11 #define noexcept #endif + + +namespace SQLite +{ + + +/** + * @brief Encapsulation of the error message from SQLite3, based on std::runtime_error. + */ +class Exception : public std::runtime_error +{ +public: + /** + * @brief Encapsulation of the error message from SQLite3, based on std::runtime_error. + * + * @param[in] aErrorMessage The string message describing the SQLite error + */ + explicit Exception(const std::string& aErrorMessage) : + std::runtime_error(aErrorMessage), + mErrcode(-1), // 0 would be SQLITE_OK, which doesn't make sense + mExtendedErrcode(-1) + { + } + + /** + * @brief Encapsulation of the error message from SQLite3, based on std::runtime_error. + * + * @param[in] apSQLite The SQLite object, to obtain detailed error messages from. + */ + explicit Exception(sqlite3* apSQLite) : + std::runtime_error(sqlite3_errmsg(apSQLite)), + mErrcode(sqlite3_errcode(apSQLite)), + mExtendedErrcode(sqlite3_extended_errcode(apSQLite)) + { + } + + /** + * @brief Encapsulation of the error message from SQLite3, based on std::runtime_error. + * + * @param[in] apSQLite The SQLite object, to obtain detailed error messages from. + * @param[in] ret Return value from function call that failed. + */ + explicit Exception(sqlite3* apSQLite, int ret) : + std::runtime_error(sqlite3_errmsg(apSQLite)), + mErrcode(ret), + mExtendedErrcode(sqlite3_extended_errcode(apSQLite)) + { + } + + /** + * @brief Encapsulation of the error message from SQLite3, based on std::runtime_error. + * + * @param[in] apSQLite The SQLite object, to obtain detailed error messages from. + * @param[in] ret Return value from function call that failed. + * @param[in] aErrorMessage String providing more context, added to the SQLite errmsg + */ + explicit Exception(sqlite3* apSQLite, int ret, const std::string &aErrorMessage) : + std::runtime_error(aErrorMessage + ": " + sqlite3_errmsg(apSQLite)), + mErrcode(ret), + mExtendedErrcode(sqlite3_extended_errcode(apSQLite)) + { + } + + /// @brief Return the result code (if any, otherwise -1). + inline int getErrorCode() const noexcept // nothrow + { + return mErrcode; + } + + /// @brief Return the extended numeric result code (if any, otherwise -1). + inline int getExtendedErrorCode() const noexcept // nothrow + { + return mExtendedErrcode; + } + + /// @brief Return a string, solely based on the error code + inline const char *getErrStr() const noexcept // nothrow + { + return sqlite3_errstr(mErrcode); + } + +private: + const int mErrcode; + const int mExtendedErrcode; +}; + + +} // namespace SQLite diff --git a/include/SQLiteCpp/Statement.h b/include/SQLiteCpp/Statement.h index 3ee3162..dc44b6e 100644 --- a/include/SQLiteCpp/Statement.h +++ b/include/SQLiteCpp/Statement.h @@ -457,7 +457,7 @@ private: { if (SQLITE_OK != aRet) { - throw SQLite::Exception(sqlite3_errstr(aRet)); + throw SQLite::Exception(mStmtPtr, aRet); } } diff --git a/src/Backup.cpp b/src/Backup.cpp index ba8815a..c46ecfd 100644 --- a/src/Backup.cpp +++ b/src/Backup.cpp @@ -31,8 +31,7 @@ Backup::Backup(Database& aDestDatabase, apSrcDatabaseName); if (NULL == mpSQLiteBackup) { - std::string strerr = sqlite3_errmsg(aDestDatabase.getHandle()); - throw SQLite::Exception(strerr); + throw SQLite::Exception(aDestDatabase.getHandle()); } } diff --git a/src/Database.cpp b/src/Database.cpp index 2ce2183..f19dee9 100644 --- a/src/Database.cpp +++ b/src/Database.cpp @@ -36,9 +36,9 @@ Database::Database(const char* apFilename, const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs); if (SQLITE_OK != ret) { - std::string strerr = sqlite3_errstr(ret); + const SQLite::Exception exception(mpSQLite, ret); // must create before closing sqlite3_close(mpSQLite); // close is required even in case of error on opening - throw SQLite::Exception(strerr); + throw exception; } if (aBusyTimeoutMs > 0) @@ -58,9 +58,9 @@ Database::Database(const std::string& aFilename, const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? NULL : aVfs.c_str()); if (SQLITE_OK != ret) { - std::string strerr = sqlite3_errstr(ret); + const SQLite::Exception exception(mpSQLite, ret); // must create before closing sqlite3_close(mpSQLite); // close is required even in case of error on opening - throw SQLite::Exception(strerr); + throw exception; } if (aBusyTimeoutMs > 0) diff --git a/src/Statement.cpp b/src/Statement.cpp index 20d4bc5..eec9a92 100644 --- a/src/Statement.cpp +++ b/src/Statement.cpp @@ -195,7 +195,7 @@ bool Statement::executeStep() { mbOk = false; mbDone = false; - throw SQLite::Exception(sqlite3_errstr(ret)); + throw SQLite::Exception(mStmtPtr, ret); } } else @@ -227,7 +227,7 @@ int Statement::exec() { mbOk = false; mbDone = false; - throw SQLite::Exception(sqlite3_errstr(ret)); + throw SQLite::Exception(mStmtPtr, ret); } } else @@ -317,7 +317,7 @@ Statement::Ptr::Ptr(sqlite3* apSQLite, std::string& aQuery) : const int ret = sqlite3_prepare_v2(apSQLite, aQuery.c_str(), static_cast(aQuery.size()), &mpStmt, NULL); if (SQLITE_OK != ret) { - throw SQLite::Exception(sqlite3_errstr(ret)); + throw SQLite::Exception(apSQLite, ret); } // Initialize the reference counter of the sqlite3_stmt : // used to share the mStmtPtr between Statement and Column objects;