1 | #include "duckdb/common/exception.hpp" |
2 | |
3 | #include "duckdb/common/string_util.hpp" |
4 | #include "duckdb/common/to_string.hpp" |
5 | #include "duckdb/common/types.hpp" |
6 | |
7 | #ifdef DUCKDB_CRASH_ON_ASSERT |
8 | #include "duckdb/common/printer.hpp" |
9 | #include <stdio.h> |
10 | #include <stdlib.h> |
11 | #endif |
12 | #ifdef DUCKDB_DEBUG_STACKTRACE |
13 | #include <execinfo.h> |
14 | #endif |
15 | |
16 | namespace duckdb { |
17 | |
18 | Exception::Exception(const string &msg) : std::exception(), type(ExceptionType::INVALID), raw_message_(msg) { |
19 | exception_message_ = msg; |
20 | } |
21 | |
22 | Exception::Exception(ExceptionType exception_type, const string &message) |
23 | : std::exception(), type(exception_type), raw_message_(message) { |
24 | exception_message_ = ExceptionTypeToString(type: exception_type) + " Error: " + message; |
25 | } |
26 | |
27 | const char *Exception::what() const noexcept { |
28 | return exception_message_.c_str(); |
29 | } |
30 | |
31 | const string &Exception::RawMessage() const { |
32 | return raw_message_; |
33 | } |
34 | |
35 | bool Exception::UncaughtException() { |
36 | #if __cplusplus >= 201703L |
37 | return std::uncaught_exceptions() > 0; |
38 | #else |
39 | return std::uncaught_exception(); |
40 | #endif |
41 | } |
42 | |
43 | string Exception::GetStackTrace(int max_depth) { |
44 | #ifdef DUCKDB_DEBUG_STACKTRACE |
45 | string result; |
46 | auto callstack = unique_ptr<void *[]>(new void *[max_depth]); |
47 | int frames = backtrace(callstack.get(), max_depth); |
48 | char **strs = backtrace_symbols(callstack.get(), frames); |
49 | for (int i = 0; i < frames; i++) { |
50 | result += strs[i]; |
51 | result += "\n" ; |
52 | } |
53 | free(strs); |
54 | return "\n" + result; |
55 | #else |
56 | // Stack trace not available. Toggle DUCKDB_DEBUG_STACKTRACE in exception.cpp to enable stack traces. |
57 | return "" ; |
58 | #endif |
59 | } |
60 | |
61 | string Exception::ConstructMessageRecursive(const string &msg, std::vector<ExceptionFormatValue> &values) { |
62 | #ifdef DEBUG |
63 | // Verify that we have the required amount of values for the message |
64 | idx_t parameter_count = 0; |
65 | for (idx_t i = 0; i < msg.size(); i++) { |
66 | if (msg[i] != '%') { |
67 | continue; |
68 | } |
69 | if (i < msg.size() && msg[i + 1] == '%') { |
70 | i++; |
71 | continue; |
72 | } |
73 | parameter_count++; |
74 | } |
75 | if (parameter_count != values.size()) { |
76 | throw InternalException("Primary exception: %s\nSecondary exception in ConstructMessageRecursive: Expected %d " |
77 | "parameters, received %d" , |
78 | msg.c_str(), parameter_count, values.size()); |
79 | } |
80 | |
81 | #endif |
82 | return ExceptionFormatValue::Format(msg, values); |
83 | } |
84 | |
85 | string Exception::ExceptionTypeToString(ExceptionType type) { |
86 | switch (type) { |
87 | case ExceptionType::INVALID: |
88 | return "Invalid" ; |
89 | case ExceptionType::OUT_OF_RANGE: |
90 | return "Out of Range" ; |
91 | case ExceptionType::CONVERSION: |
92 | return "Conversion" ; |
93 | case ExceptionType::UNKNOWN_TYPE: |
94 | return "Unknown Type" ; |
95 | case ExceptionType::DECIMAL: |
96 | return "Decimal" ; |
97 | case ExceptionType::MISMATCH_TYPE: |
98 | return "Mismatch Type" ; |
99 | case ExceptionType::DIVIDE_BY_ZERO: |
100 | return "Divide by Zero" ; |
101 | case ExceptionType::OBJECT_SIZE: |
102 | return "Object Size" ; |
103 | case ExceptionType::INVALID_TYPE: |
104 | return "Invalid type" ; |
105 | case ExceptionType::SERIALIZATION: |
106 | return "Serialization" ; |
107 | case ExceptionType::TRANSACTION: |
108 | return "TransactionContext" ; |
109 | case ExceptionType::NOT_IMPLEMENTED: |
110 | return "Not implemented" ; |
111 | case ExceptionType::EXPRESSION: |
112 | return "Expression" ; |
113 | case ExceptionType::CATALOG: |
114 | return "Catalog" ; |
115 | case ExceptionType::PARSER: |
116 | return "Parser" ; |
117 | case ExceptionType::BINDER: |
118 | return "Binder" ; |
119 | case ExceptionType::PLANNER: |
120 | return "Planner" ; |
121 | case ExceptionType::SCHEDULER: |
122 | return "Scheduler" ; |
123 | case ExceptionType::EXECUTOR: |
124 | return "Executor" ; |
125 | case ExceptionType::CONSTRAINT: |
126 | return "Constraint" ; |
127 | case ExceptionType::INDEX: |
128 | return "Index" ; |
129 | case ExceptionType::STAT: |
130 | return "Stat" ; |
131 | case ExceptionType::CONNECTION: |
132 | return "Connection" ; |
133 | case ExceptionType::SYNTAX: |
134 | return "Syntax" ; |
135 | case ExceptionType::SETTINGS: |
136 | return "Settings" ; |
137 | case ExceptionType::OPTIMIZER: |
138 | return "Optimizer" ; |
139 | case ExceptionType::NULL_POINTER: |
140 | return "NullPointer" ; |
141 | case ExceptionType::IO: |
142 | return "IO" ; |
143 | case ExceptionType::INTERRUPT: |
144 | return "INTERRUPT" ; |
145 | case ExceptionType::FATAL: |
146 | return "FATAL" ; |
147 | case ExceptionType::INTERNAL: |
148 | return "INTERNAL" ; |
149 | case ExceptionType::INVALID_INPUT: |
150 | return "Invalid Input" ; |
151 | case ExceptionType::OUT_OF_MEMORY: |
152 | return "Out of Memory" ; |
153 | case ExceptionType::PERMISSION: |
154 | return "Permission" ; |
155 | case ExceptionType::PARAMETER_NOT_RESOLVED: |
156 | return "Parameter Not Resolved" ; |
157 | case ExceptionType::PARAMETER_NOT_ALLOWED: |
158 | return "Parameter Not Allowed" ; |
159 | case ExceptionType::DEPENDENCY: |
160 | return "Dependency" ; |
161 | case ExceptionType::HTTP: |
162 | return "HTTP" ; |
163 | default: |
164 | return "Unknown" ; |
165 | } |
166 | } |
167 | |
168 | const HTTPException &Exception::AsHTTPException() const { |
169 | D_ASSERT(type == ExceptionType::HTTP); |
170 | const auto &e = static_cast<const HTTPException *>(this); |
171 | D_ASSERT(e->GetStatusCode() != 0); |
172 | D_ASSERT(e->GetHeaders().size() > 0); |
173 | return *e; |
174 | } |
175 | |
176 | void Exception::ThrowAsTypeWithMessage(ExceptionType type, const string &message, |
177 | const std::shared_ptr<Exception> &original) { |
178 | switch (type) { |
179 | case ExceptionType::OUT_OF_RANGE: |
180 | throw OutOfRangeException(message); |
181 | case ExceptionType::CONVERSION: |
182 | throw ConversionException(message); // FIXME: make a separation between Conversion/Cast exception? |
183 | case ExceptionType::INVALID_TYPE: |
184 | throw InvalidTypeException(message); |
185 | case ExceptionType::MISMATCH_TYPE: |
186 | throw TypeMismatchException(message); |
187 | case ExceptionType::TRANSACTION: |
188 | throw TransactionException(message); |
189 | case ExceptionType::NOT_IMPLEMENTED: |
190 | throw NotImplementedException(message); |
191 | case ExceptionType::CATALOG: |
192 | throw CatalogException(message); |
193 | case ExceptionType::CONNECTION: |
194 | throw ConnectionException(message); |
195 | case ExceptionType::PARSER: |
196 | throw ParserException(message); |
197 | case ExceptionType::PERMISSION: |
198 | throw PermissionException(message); |
199 | case ExceptionType::SYNTAX: |
200 | throw SyntaxException(message); |
201 | case ExceptionType::CONSTRAINT: |
202 | throw ConstraintException(message); |
203 | case ExceptionType::BINDER: |
204 | throw BinderException(message); |
205 | case ExceptionType::IO: |
206 | throw IOException(message); |
207 | case ExceptionType::SERIALIZATION: |
208 | throw SerializationException(message); |
209 | case ExceptionType::INTERRUPT: |
210 | throw InterruptException(); |
211 | case ExceptionType::INTERNAL: |
212 | throw InternalException(message); |
213 | case ExceptionType::INVALID_INPUT: |
214 | throw InvalidInputException(message); |
215 | case ExceptionType::OUT_OF_MEMORY: |
216 | throw OutOfMemoryException(message); |
217 | case ExceptionType::PARAMETER_NOT_ALLOWED: |
218 | throw ParameterNotAllowedException(message); |
219 | case ExceptionType::PARAMETER_NOT_RESOLVED: |
220 | throw ParameterNotResolvedException(); |
221 | case ExceptionType::FATAL: |
222 | throw FatalException(message); |
223 | case ExceptionType::DEPENDENCY: |
224 | throw DependencyException(message); |
225 | case ExceptionType::HTTP: { |
226 | original->AsHTTPException().Throw(); |
227 | } |
228 | default: |
229 | throw Exception(type, message); |
230 | } |
231 | } |
232 | |
233 | StandardException::StandardException(ExceptionType exception_type, const string &message) |
234 | : Exception(exception_type, message) { |
235 | } |
236 | |
237 | CastException::CastException(const PhysicalType orig_type, const PhysicalType new_type) |
238 | : Exception(ExceptionType::CONVERSION, |
239 | "Type " + TypeIdToString(type: orig_type) + " can't be cast as " + TypeIdToString(type: new_type)) { |
240 | } |
241 | |
242 | CastException::CastException(const LogicalType &orig_type, const LogicalType &new_type) |
243 | : Exception(ExceptionType::CONVERSION, |
244 | "Type " + orig_type.ToString() + " can't be cast as " + new_type.ToString()) { |
245 | } |
246 | |
247 | CastException::CastException(const string &msg) : Exception(ExceptionType::CONVERSION, msg) { |
248 | } |
249 | |
250 | ValueOutOfRangeException::ValueOutOfRangeException(const int64_t value, const PhysicalType orig_type, |
251 | const PhysicalType new_type) |
252 | : Exception(ExceptionType::CONVERSION, "Type " + TypeIdToString(type: orig_type) + " with value " + |
253 | to_string(val: (intmax_t)value) + |
254 | " can't be cast because the value is out of range " |
255 | "for the destination type " + |
256 | TypeIdToString(type: new_type)) { |
257 | } |
258 | |
259 | ValueOutOfRangeException::ValueOutOfRangeException(const double value, const PhysicalType orig_type, |
260 | const PhysicalType new_type) |
261 | : Exception(ExceptionType::CONVERSION, "Type " + TypeIdToString(type: orig_type) + " with value " + to_string(val: value) + |
262 | " can't be cast because the value is out of range " |
263 | "for the destination type " + |
264 | TypeIdToString(type: new_type)) { |
265 | } |
266 | |
267 | ValueOutOfRangeException::ValueOutOfRangeException(const hugeint_t value, const PhysicalType orig_type, |
268 | const PhysicalType new_type) |
269 | : Exception(ExceptionType::CONVERSION, "Type " + TypeIdToString(type: orig_type) + " with value " + value.ToString() + |
270 | " can't be cast because the value is out of range " |
271 | "for the destination type " + |
272 | TypeIdToString(type: new_type)) { |
273 | } |
274 | |
275 | ValueOutOfRangeException::ValueOutOfRangeException(const PhysicalType var_type, const idx_t length) |
276 | : Exception(ExceptionType::OUT_OF_RANGE, |
277 | "The value is too long to fit into type " + TypeIdToString(type: var_type) + "(" + to_string(val: length) + ")" ) { |
278 | } |
279 | |
280 | ValueOutOfRangeException::ValueOutOfRangeException(const string &msg) : Exception(ExceptionType::OUT_OF_RANGE, msg) { |
281 | } |
282 | |
283 | ConversionException::ConversionException(const string &msg) : Exception(ExceptionType::CONVERSION, msg) { |
284 | } |
285 | |
286 | InvalidTypeException::InvalidTypeException(PhysicalType type, const string &msg) |
287 | : Exception(ExceptionType::INVALID_TYPE, "Invalid Type [" + TypeIdToString(type) + "]: " + msg) { |
288 | } |
289 | |
290 | InvalidTypeException::InvalidTypeException(const LogicalType &type, const string &msg) |
291 | : Exception(ExceptionType::INVALID_TYPE, "Invalid Type [" + type.ToString() + "]: " + msg) { |
292 | } |
293 | |
294 | InvalidTypeException::InvalidTypeException(const string &msg) : Exception(ExceptionType::INVALID_TYPE, msg) { |
295 | } |
296 | |
297 | TypeMismatchException::TypeMismatchException(const PhysicalType type_1, const PhysicalType type_2, const string &msg) |
298 | : Exception(ExceptionType::MISMATCH_TYPE, |
299 | "Type " + TypeIdToString(type: type_1) + " does not match with " + TypeIdToString(type: type_2) + ". " + msg) { |
300 | } |
301 | |
302 | TypeMismatchException::TypeMismatchException(const LogicalType &type_1, const LogicalType &type_2, const string &msg) |
303 | : Exception(ExceptionType::MISMATCH_TYPE, |
304 | "Type " + type_1.ToString() + " does not match with " + type_2.ToString() + ". " + msg) { |
305 | } |
306 | |
307 | TypeMismatchException::TypeMismatchException(const string &msg) : Exception(ExceptionType::MISMATCH_TYPE, msg) { |
308 | } |
309 | |
310 | TransactionException::TransactionException(const string &msg) : Exception(ExceptionType::TRANSACTION, msg) { |
311 | } |
312 | |
313 | NotImplementedException::NotImplementedException(const string &msg) : Exception(ExceptionType::NOT_IMPLEMENTED, msg) { |
314 | } |
315 | |
316 | OutOfRangeException::OutOfRangeException(const string &msg) : Exception(ExceptionType::OUT_OF_RANGE, msg) { |
317 | } |
318 | |
319 | CatalogException::CatalogException(const string &msg) : StandardException(ExceptionType::CATALOG, msg) { |
320 | } |
321 | |
322 | ConnectionException::ConnectionException(const string &msg) : StandardException(ExceptionType::CONNECTION, msg) { |
323 | } |
324 | |
325 | ParserException::ParserException(const string &msg) : StandardException(ExceptionType::PARSER, msg) { |
326 | } |
327 | |
328 | PermissionException::PermissionException(const string &msg) : StandardException(ExceptionType::PERMISSION, msg) { |
329 | } |
330 | |
331 | SyntaxException::SyntaxException(const string &msg) : Exception(ExceptionType::SYNTAX, msg) { |
332 | } |
333 | |
334 | ConstraintException::ConstraintException(const string &msg) : Exception(ExceptionType::CONSTRAINT, msg) { |
335 | } |
336 | |
337 | DependencyException::DependencyException(const string &msg) : Exception(ExceptionType::DEPENDENCY, msg) { |
338 | } |
339 | |
340 | BinderException::BinderException(const string &msg) : StandardException(ExceptionType::BINDER, msg) { |
341 | } |
342 | |
343 | IOException::IOException(const string &msg) : Exception(ExceptionType::IO, msg) { |
344 | } |
345 | |
346 | MissingExtensionException::MissingExtensionException(const string &msg) |
347 | : Exception(ExceptionType::MISSING_EXTENSION, msg) { |
348 | } |
349 | |
350 | SerializationException::SerializationException(const string &msg) : Exception(ExceptionType::SERIALIZATION, msg) { |
351 | } |
352 | |
353 | SequenceException::SequenceException(const string &msg) : Exception(ExceptionType::SERIALIZATION, msg) { |
354 | } |
355 | |
356 | InterruptException::InterruptException() : Exception(ExceptionType::INTERRUPT, "Interrupted!" ) { |
357 | } |
358 | |
359 | FatalException::FatalException(ExceptionType type, const string &msg) : Exception(type, msg) { |
360 | } |
361 | |
362 | InternalException::InternalException(const string &msg) : FatalException(ExceptionType::INTERNAL, msg) { |
363 | #ifdef DUCKDB_CRASH_ON_ASSERT |
364 | Printer::Print("ABORT THROWN BY INTERNAL EXCEPTION: " + msg); |
365 | abort(); |
366 | #endif |
367 | } |
368 | |
369 | InvalidInputException::InvalidInputException(const string &msg) : Exception(ExceptionType::INVALID_INPUT, msg) { |
370 | } |
371 | |
372 | OutOfMemoryException::OutOfMemoryException(const string &msg) : Exception(ExceptionType::OUT_OF_MEMORY, msg) { |
373 | } |
374 | |
375 | ParameterNotAllowedException::ParameterNotAllowedException(const string &msg) |
376 | : StandardException(ExceptionType::PARAMETER_NOT_ALLOWED, msg) { |
377 | } |
378 | |
379 | ParameterNotResolvedException::ParameterNotResolvedException() |
380 | : Exception(ExceptionType::PARAMETER_NOT_RESOLVED, "Parameter types could not be resolved" ) { |
381 | } |
382 | |
383 | } // namespace duckdb |
384 | |