/** Definition of Drogon Db exception classes. * * Copyright (c) 2003-2018, Jeroen T. Vermeulen. * * See COPYING for copyright license. If you did not receive a file called * COPYING with this source code, please notify the distributor of this mistake, * or contact the author. */ // taken from libpqxx and modified /** * * @file Exception.h * @author An Tao * * Copyright 2018, An Tao. All rights reserved. * https://github.com/an-tao/drogon * Use of this source code is governed by a MIT license * that can be found in the License file. * * Drogon * */ #pragma once #include #include #include #include namespace drogon { namespace orm { /// Mixin base class to identify drogon-db-specific exception types /** * If you wish to catch all exception types specific to drogon db for some * reason, * catch this type. All of drogon db's exception classes are derived from it * through multiple-inheritance (they also fit into the standard library's * exception hierarchy in more fitting places). * * This class is not derived from std::exception, since that could easily lead * to exception classes with multiple std::exception base-class objects. As * Bart Samwel points out, "catch" is subject to some nasty fineprint in such * cases. */ class DROGON_EXPORT DrogonDbException { public: /// Support run-time polymorphism, and keep this class abstract virtual ~DrogonDbException() noexcept { } /// Return std::exception base-class object /** * Use this to get at the exception's what() function, or to downcast to a * more specific type using dynamic_cast. * * Casting directly from DrogonDbException to a specific exception type is * not likely to work since DrogonDbException is not (and could not safely * be) derived from std::exception. * * For example, to test dynamically whether an exception is an SqlError: * * @code * try * { * // ... * } * catch (const drogon::orm::DrogonDbException &e) * { * std::cerr << e.base().what() << std::endl; * const drogon::orm::SqlError *s=dynamic_cast(&e.base()); * if (s) std::cerr << "Query was: " << s->query() << std::endl; * } * @endcode */ virtual const std::exception &base() const noexcept { static std::exception except; return except; } //[t00] }; /// Run-time Failure encountered by drogon orm lib, similar to /// std::runtime_error class Failure : public DrogonDbException, public std::runtime_error { const std::exception &base() const noexcept override { return *this; } public: DROGON_EXPORT explicit Failure(const std::string &); }; /// Exception class for lost or failed backend connection. /** * @warning When this happens on Unix-like systems, you may also get a SIGPIPE * signal. That signal aborts the program by default, so if you wish to be able * to continue after a connection breaks, be sure to disarm this signal. * * If you're working on a Unix-like system, see the manual page for * @c signal (2) on how to deal with SIGPIPE. The easiest way to make this * signal harmless is to make your program ignore it: * * @code * #include * * int main() * { * signal(SIGPIPE, SIG_IGN); * // ... * @endcode */ class BrokenConnection : public Failure { public: DROGON_EXPORT BrokenConnection(); DROGON_EXPORT explicit BrokenConnection(const std::string &); }; /// Exception class for failed queries. /** Carries, in addition to a regular error message, a copy of the failed query * and (if available) the SQLSTATE value accompanying the error. */ class SqlError : public Failure { /// Query string. Empty if unknown. const std::string query_; /// SQLSTATE string describing the error type, if known; or empty string. const std::string sqlState_; public: DROGON_EXPORT explicit SqlError(const std::string &msg = "", const std::string &Q = "", const char sqlstate[] = nullptr); 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; }; /// "Help, I don't know whether transaction was committed successfully!" /** Exception that might be thrown in rare cases where the connection to the * database is lost while finishing a database transaction, and there's no way * of telling whether it was actually executed by the backend. In this case * the database is left in an indeterminate (but consistent) state, and only * manual inspection will tell which is the case. */ class InDoubtError : public Failure { public: DROGON_EXPORT explicit InDoubtError(const std::string &); }; /// The backend saw itself forced to roll back the ongoing transaction. class TransactionRollback : public Failure { public: DROGON_EXPORT explicit TransactionRollback(const std::string &); }; /// Transaction failed to serialize. Please retry it. /** Can only happen at transaction isolation levels REPEATABLE READ and * SERIALIZABLE. * * The current transaction cannot be committed without violating the guarantees * made by its isolation level. This is the effect of a conflict with another * ongoing transaction. The transaction may still succeed if you try to * perform it again. */ class SerializationFailure : public TransactionRollback { public: DROGON_EXPORT explicit SerializationFailure(const std::string &); }; /// We can't tell whether our last statement succeeded. class StatementCompletionUnknown : public TransactionRollback { public: DROGON_EXPORT explicit StatementCompletionUnknown(const std::string &); }; /// The ongoing transaction has deadlocked. Retrying it may help. class DeadlockDetected : public TransactionRollback { public: DROGON_EXPORT explicit DeadlockDetected(const std::string &); }; /// Internal error in internal library class InternalError : public DrogonDbException, public std::logic_error { const std::exception &base() const noexcept override { return *this; } public: DROGON_EXPORT explicit InternalError(const std::string &); }; /// Timeout error in when executing the SQL statement. class TimeoutError : public DrogonDbException, public std::logic_error { const std::exception &base() const noexcept override { return *this; } public: DROGON_EXPORT explicit TimeoutError(const std::string &); }; /// Error in usage of drogon orm library, similar to std::logic_error class UsageError : public DrogonDbException, public std::logic_error { const std::exception &base() const noexcept override { return *this; } public: DROGON_EXPORT explicit UsageError(const std::string &); }; /// Invalid argument passed to drogon orm lib, similar to std::invalid_argument class ArgumentError : public DrogonDbException, public std::invalid_argument { const std::exception &base() const noexcept override { return *this; } public: DROGON_EXPORT explicit ArgumentError(const std::string &); }; /// Value conversion failed, e.g. when converting "Hello" to int. class ConversionError : public DrogonDbException, public std::domain_error { const std::exception &base() const noexcept override { return *this; } public: DROGON_EXPORT explicit ConversionError(const std::string &); }; /// Something is out of range, similar to std::out_of_range class RangeError : public DrogonDbException, public std::out_of_range { const std::exception &base() const noexcept override { return *this; } public: DROGON_EXPORT explicit RangeError(const std::string &); }; /// Query returned an unexpected number of rows. class UnexpectedRows : public RangeError { const std::exception &base() const noexcept override { return *this; } public: explicit UnexpectedRows(const std::string &msg) : RangeError(msg) { } }; /// Database feature not supported in current setup class FeatureNotSupported : public SqlError { public: explicit FeatureNotSupported(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) { } }; /// Error in data provided to SQL statement class DataException : public SqlError { public: explicit DataException(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) { } }; class IntegrityConstraintViolation : public SqlError { public: explicit IntegrityConstraintViolation(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) { } }; class RestrictViolation : public IntegrityConstraintViolation { public: explicit RestrictViolation(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : IntegrityConstraintViolation(err, Q, sqlstate) { } }; class NotNullViolation : public IntegrityConstraintViolation { public: explicit NotNullViolation(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : IntegrityConstraintViolation(err, Q, sqlstate) { } }; class ForeignKeyViolation : public IntegrityConstraintViolation { public: explicit ForeignKeyViolation(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : IntegrityConstraintViolation(err, Q, sqlstate) { } }; class UniqueViolation : public IntegrityConstraintViolation { public: explicit UniqueViolation(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : IntegrityConstraintViolation(err, Q, sqlstate) { } }; class CheckViolation : public IntegrityConstraintViolation { public: explicit CheckViolation(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : IntegrityConstraintViolation(err, Q, sqlstate) { } }; class InvalidCursorState : public SqlError { public: explicit InvalidCursorState(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) { } }; class InvalidSqlStatementName : public SqlError { public: explicit InvalidSqlStatementName(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) { } }; class InvalidCursorName : public SqlError { public: explicit InvalidCursorName(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) { } }; class SyntaxError : public SqlError { public: /// Approximate position in string where error occurred, or -1 if unknown. const int errorPosition_; explicit SyntaxError(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr, int pos = -1) : SqlError(err, Q, sqlstate), errorPosition_(pos) { } }; class UndefinedColumn : public SyntaxError { public: explicit UndefinedColumn(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : SyntaxError(err, Q, sqlstate) { } }; class UndefinedFunction : public SyntaxError { public: explicit UndefinedFunction(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : SyntaxError(err, Q, sqlstate) { } }; class UndefinedTable : public SyntaxError { public: explicit UndefinedTable(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : SyntaxError(err, Q, sqlstate) { } }; class InsufficientPrivilege : public SqlError { public: explicit InsufficientPrivilege(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) { } }; /// Resource shortage on the server class InsufficientResources : public SqlError { public: explicit InsufficientResources(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : SqlError(err, Q, sqlstate) { } }; class DiskFull : public InsufficientResources { public: explicit DiskFull(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : InsufficientResources(err, Q, sqlstate) { } }; class OutOfMemory : public InsufficientResources { public: explicit OutOfMemory(const std::string &err, const std::string &Q = "", const char sqlstate[] = nullptr) : InsufficientResources(err, Q, sqlstate) { } }; class TooManyConnections : public BrokenConnection { public: explicit TooManyConnections(const std::string &err) : BrokenConnection(err) { } }; // /// PL/pgSQL error // /** Exceptions derived from this class are errors from PL/pgSQL procedures. // */ // class PQXX_LIBEXPORT plpgsql_error : public sql_error // { // public: // explicit plpgsql_error( // const std::string &err, // const std::string &Q = "", // const char sqlstate[] = nullptr) : sql_error(err, Q, sqlstate) {} // }; // /// Exception raised in PL/pgSQL procedure // class PQXX_LIBEXPORT plpgsql_raise : public plpgsql_error // { // public: // explicit plpgsql_raise( // const std::string &err, // const std::string &Q = "", // const char sqlstate[] = nullptr) : plpgsql_error(err, Q, sqlstate) {} // }; // class PQXX_LIBEXPORT plpgsql_no_data_found : public plpgsql_error // { // public: // explicit plpgsql_no_data_found( // const std::string &err, // const std::string &Q = "", // const char sqlstate[] = nullptr) : plpgsql_error(err, Q, sqlstate) {} // }; // class PQXX_LIBEXPORT plpgsql_too_many_rows : public plpgsql_error // { // public: // explicit plpgsql_too_many_rows( // const std::string &err, // const std::string &Q = "", // const char sqlstate[] = nullptr) : plpgsql_error(err, Q, sqlstate) {} // }; using DrogonDbExceptionCallback = std::function; } // namespace orm } // namespace drogon