Refine SQLite3 error types with new exception handling (#2145)

Signed-off-by: yuanlu <2573580691@qq.com>
This commit is contained in:
元路 2024-09-06 15:37:09 +08:00 committed by GitHub
parent 1326205483
commit 59919f33ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 251 additions and 9 deletions

View File

@ -137,15 +137,24 @@ class SqlError : public Failure
/// SQLSTATE string describing the error type, if known; or empty string.
const std::string sqlState_;
const int errcode_{0};
const int extendedErrcode_{0};
public:
DROGON_EXPORT explicit SqlError(const std::string &msg = "",
const std::string &Q = "",
const char sqlstate[] = nullptr);
DROGON_EXPORT explicit SqlError(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode);
DROGON_EXPORT virtual ~SqlError() noexcept;
/// The query whose execution triggered the exception
DROGON_EXPORT const std::string &query() const noexcept;
DROGON_EXPORT const std::string &sqlState() const noexcept;
DROGON_EXPORT int errcode() const noexcept;
DROGON_EXPORT int extendedErrcode() const noexcept;
};
/// "Help, I don't know whether transaction was committed successfully!"
@ -293,6 +302,14 @@ class FeatureNotSupported : public SqlError
: SqlError(err, Q, sqlstate)
{
}
explicit FeatureNotSupported(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: SqlError(msg, Q, errcode, extendedErrcode)
{
}
};
/// Error in data provided to SQL statement
@ -305,6 +322,14 @@ class DataException : public SqlError
: SqlError(err, Q, sqlstate)
{
}
explicit DataException(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: SqlError(msg, Q, errcode, extendedErrcode)
{
}
};
class IntegrityConstraintViolation : public SqlError
@ -316,6 +341,14 @@ class IntegrityConstraintViolation : public SqlError
: SqlError(err, Q, sqlstate)
{
}
explicit IntegrityConstraintViolation(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: SqlError(msg, Q, errcode, extendedErrcode)
{
}
};
class RestrictViolation : public IntegrityConstraintViolation
@ -327,6 +360,14 @@ class RestrictViolation : public IntegrityConstraintViolation
: IntegrityConstraintViolation(err, Q, sqlstate)
{
}
explicit RestrictViolation(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: IntegrityConstraintViolation(msg, Q, errcode, extendedErrcode)
{
}
};
class NotNullViolation : public IntegrityConstraintViolation
@ -338,6 +379,14 @@ class NotNullViolation : public IntegrityConstraintViolation
: IntegrityConstraintViolation(err, Q, sqlstate)
{
}
explicit NotNullViolation(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: IntegrityConstraintViolation(msg, Q, errcode, extendedErrcode)
{
}
};
class ForeignKeyViolation : public IntegrityConstraintViolation
@ -349,6 +398,14 @@ class ForeignKeyViolation : public IntegrityConstraintViolation
: IntegrityConstraintViolation(err, Q, sqlstate)
{
}
explicit ForeignKeyViolation(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: IntegrityConstraintViolation(msg, Q, errcode, extendedErrcode)
{
}
};
class UniqueViolation : public IntegrityConstraintViolation
@ -360,6 +417,14 @@ class UniqueViolation : public IntegrityConstraintViolation
: IntegrityConstraintViolation(err, Q, sqlstate)
{
}
explicit UniqueViolation(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: IntegrityConstraintViolation(msg, Q, errcode, extendedErrcode)
{
}
};
class CheckViolation : public IntegrityConstraintViolation
@ -371,6 +436,14 @@ class CheckViolation : public IntegrityConstraintViolation
: IntegrityConstraintViolation(err, Q, sqlstate)
{
}
explicit CheckViolation(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: IntegrityConstraintViolation(msg, Q, errcode, extendedErrcode)
{
}
};
class InvalidCursorState : public SqlError
@ -382,6 +455,14 @@ class InvalidCursorState : public SqlError
: SqlError(err, Q, sqlstate)
{
}
explicit InvalidCursorState(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: SqlError(msg, Q, errcode, extendedErrcode)
{
}
};
class InvalidSqlStatementName : public SqlError
@ -393,6 +474,14 @@ class InvalidSqlStatementName : public SqlError
: SqlError(err, Q, sqlstate)
{
}
explicit InvalidSqlStatementName(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: SqlError(msg, Q, errcode, extendedErrcode)
{
}
};
class InvalidCursorName : public SqlError
@ -404,6 +493,14 @@ class InvalidCursorName : public SqlError
: SqlError(err, Q, sqlstate)
{
}
explicit InvalidCursorName(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: SqlError(msg, Q, errcode, extendedErrcode)
{
}
};
class SyntaxError : public SqlError
@ -419,6 +516,15 @@ class SyntaxError : public SqlError
: SqlError(err, Q, sqlstate), errorPosition_(pos)
{
}
explicit SyntaxError(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode,
int pos = -1)
: SqlError(msg, Q, errcode, extendedErrcode), errorPosition_(pos)
{
}
};
class UndefinedColumn : public SyntaxError
@ -430,6 +536,14 @@ class UndefinedColumn : public SyntaxError
: SyntaxError(err, Q, sqlstate)
{
}
explicit UndefinedColumn(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: SyntaxError(msg, Q, errcode, extendedErrcode)
{
}
};
class UndefinedFunction : public SyntaxError
@ -441,6 +555,14 @@ class UndefinedFunction : public SyntaxError
: SyntaxError(err, Q, sqlstate)
{
}
explicit UndefinedFunction(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: SyntaxError(msg, Q, errcode, extendedErrcode)
{
}
};
class UndefinedTable : public SyntaxError
@ -452,6 +574,14 @@ class UndefinedTable : public SyntaxError
: SyntaxError(err, Q, sqlstate)
{
}
explicit UndefinedTable(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: SyntaxError(msg, Q, errcode, extendedErrcode)
{
}
};
class InsufficientPrivilege : public SqlError
@ -463,6 +593,14 @@ class InsufficientPrivilege : public SqlError
: SqlError(err, Q, sqlstate)
{
}
explicit InsufficientPrivilege(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: SqlError(msg, Q, errcode, extendedErrcode)
{
}
};
/// Resource shortage on the server
@ -475,6 +613,14 @@ class InsufficientResources : public SqlError
: SqlError(err, Q, sqlstate)
{
}
explicit InsufficientResources(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: SqlError(msg, Q, errcode, extendedErrcode)
{
}
};
class DiskFull : public InsufficientResources
@ -486,6 +632,14 @@ class DiskFull : public InsufficientResources
: InsufficientResources(err, Q, sqlstate)
{
}
explicit DiskFull(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: InsufficientResources(msg, Q, errcode, extendedErrcode)
{
}
};
class OutOfMemory : public InsufficientResources
@ -497,6 +651,14 @@ class OutOfMemory : public InsufficientResources
: InsufficientResources(err, Q, sqlstate)
{
}
explicit OutOfMemory(const std::string &msg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: InsufficientResources(msg, Q, errcode, extendedErrcode)
{
}
};
class TooManyConnections : public BrokenConnection

View File

@ -42,7 +42,23 @@ BrokenConnection::BrokenConnection(const std::string &whatarg)
SqlError::SqlError(const std::string &whatarg,
const std::string &Q,
const char sqlstate[])
: Failure(whatarg), query_(Q), sqlState_(sqlstate ? sqlstate : "")
: Failure(whatarg),
query_(Q),
sqlState_(sqlstate ? sqlstate : ""),
errcode_(0),
extendedErrcode_(0)
{
}
SqlError::SqlError(const std::string &whatarg,
const std::string &Q,
const int errcode,
const int extendedErrcode)
: Failure(whatarg),
query_(Q),
sqlState_(""),
errcode_(errcode),
extendedErrcode_(extendedErrcode)
{
}
@ -60,6 +76,16 @@ const std::string &SqlError::sqlState() const noexcept
return sqlState_;
}
int SqlError::errcode() const noexcept
{
return errcode_;
}
int SqlError::extendedErrcode() const noexcept
{
return extendedErrcode_;
}
InDoubtError::InDoubtError(const std::string &whatarg) : Failure(whatarg)
{
}

View File

@ -14,7 +14,10 @@
#include "Sqlite3Connection.h"
#include "Sqlite3ResultImpl.h"
#include <drogon/orm/Exception.h>
#include <drogon/utils/Utilities.h>
#include <stdexcept>
#include <string>
#include <string_view>
#include <cctype>
#include <exception>
@ -24,14 +27,54 @@
using namespace drogon;
using namespace drogon::orm;
namespace
{
}
std::once_flag Sqlite3Connection::once_;
void Sqlite3Connection::onError(
const std::string_view &sql,
const std::function<void(const std::exception_ptr &)> &exceptCallback)
const std::function<void(const std::exception_ptr &)> &exceptCallback,
const int &extendedErrcode)
{
auto exceptPtr = std::make_exception_ptr(
SqlError(sqlite3_errmsg(connectionPtr_.get()), std::string{sql}));
int errcode = extendedErrcode & 0xFF; // low 8 bit
#define ORM_ERR_CASE(code, type) \
case code: \
{ \
auto exceptPtr = std::make_exception_ptr( \
drogon::orm::type(sqlite3_errmsg(connectionPtr_.get()), \
std::string{sql}, \
errcode, \
extendedErrcode)); \
exceptCallback(exceptPtr); \
return; \
};
switch (extendedErrcode)
{
ORM_ERR_CASE(SQLITE_CONSTRAINT_NOTNULL, NotNullViolation)
ORM_ERR_CASE(SQLITE_CONSTRAINT_FOREIGNKEY, ForeignKeyViolation)
ORM_ERR_CASE(SQLITE_CONSTRAINT_PRIMARYKEY, UniqueViolation)
ORM_ERR_CASE(SQLITE_CONSTRAINT_UNIQUE, UniqueViolation)
ORM_ERR_CASE(SQLITE_CONSTRAINT_CHECK, CheckViolation)
}
switch (errcode)
{
ORM_ERR_CASE(SQLITE_MISMATCH, DataException)
ORM_ERR_CASE(SQLITE_CONSTRAINT, IntegrityConstraintViolation)
ORM_ERR_CASE(SQLITE_PERM, InsufficientPrivilege)
ORM_ERR_CASE(SQLITE_AUTH, InsufficientPrivilege)
ORM_ERR_CASE(SQLITE_NOMEM, OutOfMemory)
ORM_ERR_CASE(SQLITE_FULL, DiskFull)
}
#undef ORM_ERR_CASE
auto exceptPtr =
std::make_exception_ptr(SqlError(sqlite3_errmsg(connectionPtr_.get()),
std::string{sql},
errcode,
extendedErrcode));
exceptCallback(exceptPtr);
}
@ -148,7 +191,8 @@ void Sqlite3Connection::execSqlInQueue(
: nullptr;
if (ret != SQLITE_OK || !stmtPtr)
{
onError(sql, exceptCallback);
int ext_ret = sqlite3_extended_errcode(connectionPtr_.get());
onError(sql, exceptCallback, ext_ret);
idleCb_();
return;
}
@ -207,13 +251,14 @@ void Sqlite3Connection::execSqlInQueue(
}
if (bindRet != SQLITE_OK)
{
onError(sql, exceptCallback);
int eret = sqlite3_extended_errcode(connectionPtr_.get());
onError(sql, exceptCallback, eret);
sqlite3_reset(stmt);
idleCb_();
return;
}
}
int r;
int r, er;
int columnNum = sqlite3_column_count(stmt);
auto resultPtr = std::make_shared<Sqlite3ResultImpl>();
for (int i = 0; i < columnNum; ++i)
@ -233,6 +278,10 @@ void Sqlite3Connection::execSqlInQueue(
// Readonly, hold read lock;
std::shared_lock<SharedMutex> lock(*sharedMutexPtr_);
r = stmtStep(stmt, resultPtr, columnNum);
if (r != SQLITE_DONE)
{
er = sqlite3_extended_errcode(connectionPtr_.get());
}
sqlite3_reset(stmt);
}
else
@ -246,12 +295,16 @@ void Sqlite3Connection::execSqlInQueue(
resultPtr->insertId_ =
sqlite3_last_insert_rowid(connectionPtr_.get());
}
else
{
er = sqlite3_extended_errcode(connectionPtr_.get());
}
sqlite3_reset(stmt);
}
if (r != SQLITE_DONE)
{
onError(sql, exceptCallback);
onError(sql, exceptCallback, er);
sqlite3_reset(stmt);
idleCb_();
return;

View File

@ -75,7 +75,8 @@ class Sqlite3Connection : public DbConnection,
const std::function<void(const std::exception_ptr &)> &exceptCallback);
void onError(
const std::string_view &sql,
const std::function<void(const std::exception_ptr &)> &exceptCallback);
const std::function<void(const std::exception_ptr &)> &exceptCallback,
const int &extendedErrcode);
int stmtStep(sqlite3_stmt *stmt,
const std::shared_ptr<Sqlite3ResultImpl> &resultPtr,
int columnNum);