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
11namespace Poco { class Logger; }
12
13
14namespace DB
15{
16
17namespace ErrorCodes
18{
19 extern const int POCO_EXCEPTION;
20}
21
22class Exception : public Poco::Exception
23{
24public:
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
43private:
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.
51class ErrnoException : public Exception
52{
53public:
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
63private:
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
72using Exceptions = std::vector<std::exception_ptr>;
73
74
75std::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 */
84void tryLogCurrentException(const char * log_name, const std::string & start_of_message = "");
85void 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 */
93std::string getCurrentExceptionMessage(bool with_stacktrace, bool check_embedded_stacktrace = false,
94 bool with_extra_info = true);
95
96/// Returns error code from ErrorCodes
97int getCurrentExceptionCode();
98
99
100/// An execution status of any piece of code, contains return code and optional error
101struct 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
121void tryLogException(std::exception_ptr e, const char * log_name, const std::string & start_of_message = "");
122void tryLogException(std::exception_ptr e, Poco::Logger * logger, const std::string & start_of_message = "");
123
124std::string getExceptionMessage(const Exception & e, bool with_stacktrace, bool check_embedded_stacktrace = false);
125std::string getExceptionMessage(std::exception_ptr e, bool with_stacktrace);
126
127
128void rethrowFirstException(const Exceptions & exceptions);
129
130
131template <typename T>
132std::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