| 1 | #pragma once |
| 2 | |
| 3 | #include <cerrno> |
| 4 | #include <vector> |
| 5 | #include <memory> |
| 6 | |
| 7 | #include <Poco/Exception.h> |
| 8 | |
| 9 | #include <Common/StackTrace.h> |
| 10 | |
| 11 | namespace Poco { class Logger; } |
| 12 | |
| 13 | |
| 14 | namespace DB |
| 15 | { |
| 16 | |
| 17 | namespace ErrorCodes |
| 18 | { |
| 19 | extern const int POCO_EXCEPTION; |
| 20 | } |
| 21 | |
| 22 | class Exception : public Poco::Exception |
| 23 | { |
| 24 | public: |
| 25 | Exception() {} /// For deferred initialization. |
| 26 | Exception(const std::string & msg, int code) : Poco::Exception(msg, code) {} |
| 27 | Exception(const std::string & msg, const Exception & nested_exception, int code) |
| 28 | : Poco::Exception(msg, nested_exception, code), trace(nested_exception.trace) {} |
| 29 | |
| 30 | enum CreateFromPocoTag { CreateFromPoco }; |
| 31 | Exception(CreateFromPocoTag, const Poco::Exception & exc) : Poco::Exception(exc.displayText(), ErrorCodes::POCO_EXCEPTION) {} |
| 32 | |
| 33 | Exception * clone() const override { return new Exception(*this); } |
| 34 | void rethrow() const override { throw *this; } |
| 35 | const char * name() const throw() override { return "DB::Exception" ; } |
| 36 | const char * what() const throw() override { return message().data(); } |
| 37 | |
| 38 | /// Add something to the existing message. |
| 39 | void addMessage(const std::string & arg) { extendedMessage(arg); } |
| 40 | |
| 41 | const StackTrace & getStackTrace() const { return trace; } |
| 42 | |
| 43 | private: |
| 44 | StackTrace trace; |
| 45 | |
| 46 | const char * className() const throw() override { return "DB::Exception" ; } |
| 47 | }; |
| 48 | |
| 49 | |
| 50 | /// Contains an additional member `saved_errno`. See the throwFromErrno function. |
| 51 | class ErrnoException : public Exception |
| 52 | { |
| 53 | public: |
| 54 | ErrnoException(const std::string & msg, int code, int saved_errno_, const std::optional<std::string> & path_ = {}) |
| 55 | : Exception(msg, code), saved_errno(saved_errno_), path(path_) {} |
| 56 | |
| 57 | ErrnoException * clone() const override { return new ErrnoException(*this); } |
| 58 | void rethrow() const override { throw *this; } |
| 59 | |
| 60 | int getErrno() const { return saved_errno; } |
| 61 | const std::optional<std::string> getPath() const { return path; } |
| 62 | |
| 63 | private: |
| 64 | int saved_errno; |
| 65 | std::optional<std::string> path; |
| 66 | |
| 67 | const char * name() const throw() override { return "DB::ErrnoException" ; } |
| 68 | const char * className() const throw() override { return "DB::ErrnoException" ; } |
| 69 | }; |
| 70 | |
| 71 | |
| 72 | using Exceptions = std::vector<std::exception_ptr>; |
| 73 | |
| 74 | |
| 75 | std::string errnoToString(int code, int the_errno = errno); |
| 76 | [[noreturn]] void throwFromErrno(const std::string & s, int code, int the_errno = errno); |
| 77 | [[noreturn]] void throwFromErrnoWithPath(const std::string & s, const std::string & path, int code, |
| 78 | int the_errno = errno); |
| 79 | |
| 80 | |
| 81 | /** Try to write an exception to the log (and forget about it). |
| 82 | * Can be used in destructors in the catch-all block. |
| 83 | */ |
| 84 | void tryLogCurrentException(const char * log_name, const std::string & start_of_message = "" ); |
| 85 | void tryLogCurrentException(Poco::Logger * logger, const std::string & start_of_message = "" ); |
| 86 | |
| 87 | |
| 88 | /** Prints current exception in canonical format. |
| 89 | * with_stacktrace - prints stack trace for DB::Exception. |
| 90 | * check_embedded_stacktrace - if DB::Exception has embedded stacktrace then |
| 91 | * only this stack trace will be printed. |
| 92 | */ |
| 93 | std::string getCurrentExceptionMessage(bool with_stacktrace, bool check_embedded_stacktrace = false, |
| 94 | bool = true); |
| 95 | |
| 96 | /// Returns error code from ErrorCodes |
| 97 | int getCurrentExceptionCode(); |
| 98 | |
| 99 | |
| 100 | /// An execution status of any piece of code, contains return code and optional error |
| 101 | struct ExecutionStatus |
| 102 | { |
| 103 | int code = 0; |
| 104 | std::string message; |
| 105 | |
| 106 | ExecutionStatus() = default; |
| 107 | |
| 108 | explicit ExecutionStatus(int return_code, const std::string & exception_message = "" ) |
| 109 | : code(return_code), message(exception_message) {} |
| 110 | |
| 111 | static ExecutionStatus fromCurrentException(const std::string & start_of_message = "" ); |
| 112 | |
| 113 | std::string serializeText() const; |
| 114 | |
| 115 | void deserializeText(const std::string & data); |
| 116 | |
| 117 | bool tryDeserializeText(const std::string & data); |
| 118 | }; |
| 119 | |
| 120 | |
| 121 | void tryLogException(std::exception_ptr e, const char * log_name, const std::string & start_of_message = "" ); |
| 122 | void tryLogException(std::exception_ptr e, Poco::Logger * logger, const std::string & start_of_message = "" ); |
| 123 | |
| 124 | std::string getExceptionMessage(const Exception & e, bool with_stacktrace, bool check_embedded_stacktrace = false); |
| 125 | std::string getExceptionMessage(std::exception_ptr e, bool with_stacktrace); |
| 126 | |
| 127 | |
| 128 | void rethrowFirstException(const Exceptions & exceptions); |
| 129 | |
| 130 | |
| 131 | template <typename T> |
| 132 | std::enable_if_t<std::is_pointer_v<T>, T> exception_cast(std::exception_ptr e) |
| 133 | { |
| 134 | try |
| 135 | { |
| 136 | std::rethrow_exception(std::move(e)); |
| 137 | } |
| 138 | catch (std::remove_pointer_t<T> & concrete) |
| 139 | { |
| 140 | return &concrete; |
| 141 | } |
| 142 | catch (...) |
| 143 | { |
| 144 | return nullptr; |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | } |
| 149 | |