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)
{
throw SQLite::Exception(sqlite3_errstr(aRet));
throw SQLite::Exception(mpSQLite, aRet);
}
}

View File

@ -12,31 +12,8 @@
#include <stdexcept>
#include <string>
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 <sstream>
#include <sqlite3.h>
/// 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

View File

@ -457,7 +457,7 @@ private:
{
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);
if (NULL == mpSQLiteBackup)
{
std::string strerr = sqlite3_errmsg(aDestDatabase.getHandle());
throw SQLite::Exception(strerr);
throw SQLite::Exception(aDestDatabase.getHandle());
}
}

View File

@ -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)

View File

@ -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<int>(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;