Merge pull request #84 from DouglasHeriot/exception

Better exception messages when statements fail
This commit is contained in:
Sébastien Rombauts 2016-05-26 07:29:40 +02:00
commit bf61578f59
6 changed files with 100 additions and 36 deletions

View File

@ -378,7 +378,7 @@ private:
{ {
if (SQLITE_OK != aRet) if (SQLITE_OK != aRet)
{ {
throw SQLite::Exception(sqlite3_errstr(aRet)); throw SQLite::Exception(mpSQLite, aRet);
} }
} }

View File

@ -12,31 +12,8 @@
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <sstream>
#include <sqlite3.h>
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
/// Compatibility with non-clang compilers. /// Compatibility with non-clang compilers.
@ -56,3 +33,91 @@ public:
// Visual Studio 2013 does not support noexcept, and "throw()" is deprecated by C++11 // Visual Studio 2013 does not support noexcept, and "throw()" is deprecated by C++11
#define noexcept #define noexcept
#endif #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

View File

@ -457,7 +457,7 @@ private:
{ {
if (SQLITE_OK != aRet) if (SQLITE_OK != aRet)
{ {
throw SQLite::Exception(sqlite3_errstr(aRet)); throw SQLite::Exception(mStmtPtr, aRet);
} }
} }

View File

@ -31,8 +31,7 @@ Backup::Backup(Database& aDestDatabase,
apSrcDatabaseName); apSrcDatabaseName);
if (NULL == mpSQLiteBackup) if (NULL == mpSQLiteBackup)
{ {
std::string strerr = sqlite3_errmsg(aDestDatabase.getHandle()); throw SQLite::Exception(aDestDatabase.getHandle());
throw SQLite::Exception(strerr);
} }
} }

View File

@ -36,9 +36,9 @@ Database::Database(const char* apFilename,
const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs); const int ret = sqlite3_open_v2(apFilename, &mpSQLite, aFlags, apVfs);
if (SQLITE_OK != ret) 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 sqlite3_close(mpSQLite); // close is required even in case of error on opening
throw SQLite::Exception(strerr); throw exception;
} }
if (aBusyTimeoutMs > 0) 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()); const int ret = sqlite3_open_v2(aFilename.c_str(), &mpSQLite, aFlags, aVfs.empty() ? NULL : aVfs.c_str());
if (SQLITE_OK != ret) 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 sqlite3_close(mpSQLite); // close is required even in case of error on opening
throw SQLite::Exception(strerr); throw exception;
} }
if (aBusyTimeoutMs > 0) if (aBusyTimeoutMs > 0)

View File

@ -195,7 +195,7 @@ bool Statement::executeStep()
{ {
mbOk = false; mbOk = false;
mbDone = false; mbDone = false;
throw SQLite::Exception(sqlite3_errstr(ret)); throw SQLite::Exception(mStmtPtr, ret);
} }
} }
else else
@ -227,7 +227,7 @@ int Statement::exec()
{ {
mbOk = false; mbOk = false;
mbDone = false; mbDone = false;
throw SQLite::Exception(sqlite3_errstr(ret)); throw SQLite::Exception(mStmtPtr, ret);
} }
} }
else 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<int>(aQuery.size()), &mpStmt, NULL); const int ret = sqlite3_prepare_v2(apSQLite, aQuery.c_str(), static_cast<int>(aQuery.size()), &mpStmt, NULL);
if (SQLITE_OK != ret) if (SQLITE_OK != ret)
{ {
throw SQLite::Exception(sqlite3_errstr(ret)); throw SQLite::Exception(apSQLite, ret);
} }
// Initialize the reference counter of the sqlite3_stmt : // Initialize the reference counter of the sqlite3_stmt :
// used to share the mStmtPtr between Statement and Column objects; // used to share the mStmtPtr between Statement and Column objects;