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