mirror of
https://gitee.com/an-tao/drogon.git
synced 2024-11-29 10:17:38 +08:00
Refine SQLite3 error types with new exception handling (#2145)
Signed-off-by: yuanlu <2573580691@qq.com>
This commit is contained in:
parent
1326205483
commit
59919f33ef
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user