1//===----------------------------------------------------------------------===//
2// DuckDB
3//
4// duckdb/common/exception.hpp
5//
6//
7//===----------------------------------------------------------------------===//
8
9#pragma once
10
11#include "duckdb/common/assert.hpp"
12#include "duckdb/common/exception_format_value.hpp"
13#include "duckdb/common/shared_ptr.hpp"
14#include "duckdb/common/map.hpp"
15#include "duckdb/common/typedefs.hpp"
16
17#include <vector>
18#include <stdexcept>
19
20namespace duckdb {
21enum class PhysicalType : uint8_t;
22struct LogicalType;
23struct hugeint_t;
24
25inline void assert_restrict_function(const void *left_start, const void *left_end, const void *right_start,
26 const void *right_end, const char *fname, int linenr) {
27 // assert that the two pointers do not overlap
28#ifdef DEBUG
29 if (!(left_end <= right_start || right_end <= left_start)) {
30 printf("ASSERT RESTRICT FAILED: %s:%d\n", fname, linenr);
31 D_ASSERT(0);
32 }
33#endif
34}
35
36#define ASSERT_RESTRICT(left_start, left_end, right_start, right_end) \
37 assert_restrict_function(left_start, left_end, right_start, right_end, __FILE__, __LINE__)
38
39//===--------------------------------------------------------------------===//
40// Exception Types
41//===--------------------------------------------------------------------===//
42
43enum class ExceptionType {
44 INVALID = 0, // invalid type
45 OUT_OF_RANGE = 1, // value out of range error
46 CONVERSION = 2, // conversion/casting error
47 UNKNOWN_TYPE = 3, // unknown type
48 DECIMAL = 4, // decimal related
49 MISMATCH_TYPE = 5, // type mismatch
50 DIVIDE_BY_ZERO = 6, // divide by 0
51 OBJECT_SIZE = 7, // object size exceeded
52 INVALID_TYPE = 8, // incompatible for operation
53 SERIALIZATION = 9, // serialization
54 TRANSACTION = 10, // transaction management
55 NOT_IMPLEMENTED = 11, // method not implemented
56 EXPRESSION = 12, // expression parsing
57 CATALOG = 13, // catalog related
58 PARSER = 14, // parser related
59 PLANNER = 15, // planner related
60 SCHEDULER = 16, // scheduler related
61 EXECUTOR = 17, // executor related
62 CONSTRAINT = 18, // constraint related
63 INDEX = 19, // index related
64 STAT = 20, // stat related
65 CONNECTION = 21, // connection related
66 SYNTAX = 22, // syntax related
67 SETTINGS = 23, // settings related
68 BINDER = 24, // binder related
69 NETWORK = 25, // network related
70 OPTIMIZER = 26, // optimizer related
71 NULL_POINTER = 27, // nullptr exception
72 IO = 28, // IO exception
73 INTERRUPT = 29, // interrupt
74 FATAL = 30, // Fatal exceptions are non-recoverable, and render the entire DB in an unusable state
75 INTERNAL = 31, // Internal exceptions indicate something went wrong internally (i.e. bug in the code base)
76 INVALID_INPUT = 32, // Input or arguments error
77 OUT_OF_MEMORY = 33, // out of memory
78 PERMISSION = 34, // insufficient permissions
79 PARAMETER_NOT_RESOLVED = 35, // parameter types could not be resolved
80 PARAMETER_NOT_ALLOWED = 36, // parameter types not allowed
81 DEPENDENCY = 37, // dependency
82 HTTP = 38,
83 MISSING_EXTENSION = 39 // Thrown when an extension is used but not loaded
84};
85class HTTPException;
86
87class Exception : public std::exception {
88public:
89 DUCKDB_API explicit Exception(const string &msg);
90 DUCKDB_API Exception(ExceptionType exception_type, const string &message);
91
92 ExceptionType type;
93
94public:
95 DUCKDB_API const char *what() const noexcept override;
96 DUCKDB_API const string &RawMessage() const;
97
98 DUCKDB_API static string ExceptionTypeToString(ExceptionType type);
99 [[noreturn]] DUCKDB_API static void ThrowAsTypeWithMessage(ExceptionType type, const string &message,
100 const std::shared_ptr<Exception> &original);
101 virtual std::shared_ptr<Exception> Copy() const {
102 return make_shared<Exception>(args: type, args: raw_message_);
103 }
104 DUCKDB_API const HTTPException &AsHTTPException() const;
105
106 template <typename... Args>
107 static string ConstructMessage(const string &msg, Args... params) {
108 const std::size_t num_args = sizeof...(Args);
109 if (num_args == 0)
110 return msg;
111 std::vector<ExceptionFormatValue> values;
112 return ConstructMessageRecursive(msg, values, params...);
113 }
114
115 DUCKDB_API static string ConstructMessageRecursive(const string &msg, std::vector<ExceptionFormatValue> &values);
116
117 template <class T, typename... Args>
118 static string ConstructMessageRecursive(const string &msg, std::vector<ExceptionFormatValue> &values, T param,
119 Args... params) {
120 values.push_back(ExceptionFormatValue::CreateFormatValue<T>(param));
121 return ConstructMessageRecursive(msg, values, params...);
122 }
123
124 DUCKDB_API static bool UncaughtException();
125
126 DUCKDB_API static string GetStackTrace(int max_depth = 120);
127 static string FormatStackTrace(string message = "") {
128 return (message + "\n" + GetStackTrace());
129 }
130
131private:
132 string exception_message_;
133 string raw_message_;
134};
135
136//===--------------------------------------------------------------------===//
137// Exception derived classes
138//===--------------------------------------------------------------------===//
139
140//! Exceptions that are StandardExceptions do NOT invalidate the current transaction when thrown
141class StandardException : public Exception {
142public:
143 DUCKDB_API StandardException(ExceptionType exception_type, const string &message);
144};
145
146class CatalogException : public StandardException {
147public:
148 DUCKDB_API explicit CatalogException(const string &msg);
149
150 template <typename... Args>
151 explicit CatalogException(const string &msg, Args... params) : CatalogException(ConstructMessage(msg, params...)) {
152 }
153};
154
155class ConnectionException : public StandardException {
156public:
157 DUCKDB_API explicit ConnectionException(const string &msg);
158
159 template <typename... Args>
160 explicit ConnectionException(const string &msg, Args... params)
161 : ConnectionException(ConstructMessage(msg, params...)) {
162 }
163};
164
165class ParserException : public StandardException {
166public:
167 DUCKDB_API explicit ParserException(const string &msg);
168
169 template <typename... Args>
170 explicit ParserException(const string &msg, Args... params) : ParserException(ConstructMessage(msg, params...)) {
171 }
172};
173
174class PermissionException : public StandardException {
175public:
176 DUCKDB_API explicit PermissionException(const string &msg);
177
178 template <typename... Args>
179 explicit PermissionException(const string &msg, Args... params)
180 : PermissionException(ConstructMessage(msg, params...)) {
181 }
182};
183
184class BinderException : public StandardException {
185public:
186 DUCKDB_API explicit BinderException(const string &msg);
187
188 template <typename... Args>
189 explicit BinderException(const string &msg, Args... params) : BinderException(ConstructMessage(msg, params...)) {
190 }
191};
192
193class ConversionException : public Exception {
194public:
195 DUCKDB_API explicit ConversionException(const string &msg);
196
197 template <typename... Args>
198 explicit ConversionException(const string &msg, Args... params)
199 : ConversionException(ConstructMessage(msg, params...)) {
200 }
201};
202
203class TransactionException : public Exception {
204public:
205 DUCKDB_API explicit TransactionException(const string &msg);
206
207 template <typename... Args>
208 explicit TransactionException(const string &msg, Args... params)
209 : TransactionException(ConstructMessage(msg, params...)) {
210 }
211};
212
213class NotImplementedException : public Exception {
214public:
215 DUCKDB_API explicit NotImplementedException(const string &msg);
216
217 template <typename... Args>
218 explicit NotImplementedException(const string &msg, Args... params)
219 : NotImplementedException(ConstructMessage(msg, params...)) {
220 }
221};
222
223class OutOfRangeException : public Exception {
224public:
225 DUCKDB_API explicit OutOfRangeException(const string &msg);
226
227 template <typename... Args>
228 explicit OutOfRangeException(const string &msg, Args... params)
229 : OutOfRangeException(ConstructMessage(msg, params...)) {
230 }
231};
232
233class OutOfMemoryException : public Exception {
234public:
235 DUCKDB_API explicit OutOfMemoryException(const string &msg);
236
237 template <typename... Args>
238 explicit OutOfMemoryException(const string &msg, Args... params)
239 : OutOfMemoryException(ConstructMessage(msg, params...)) {
240 }
241};
242
243class SyntaxException : public Exception {
244public:
245 DUCKDB_API explicit SyntaxException(const string &msg);
246
247 template <typename... Args>
248 explicit SyntaxException(const string &msg, Args... params) : SyntaxException(ConstructMessage(msg, params...)) {
249 }
250};
251
252class ConstraintException : public Exception {
253public:
254 DUCKDB_API explicit ConstraintException(const string &msg);
255
256 template <typename... Args>
257 explicit ConstraintException(const string &msg, Args... params)
258 : ConstraintException(ConstructMessage(msg, params...)) {
259 }
260};
261
262class DependencyException : public Exception {
263public:
264 DUCKDB_API explicit DependencyException(const string &msg);
265
266 template <typename... Args>
267 explicit DependencyException(const string &msg, Args... params)
268 : DependencyException(ConstructMessage(msg, params...)) {
269 }
270};
271
272class IOException : public Exception {
273public:
274 DUCKDB_API explicit IOException(const string &msg);
275 explicit IOException(ExceptionType exception_type, const string &msg) : Exception(exception_type, msg) {
276 }
277
278 template <typename... Args>
279 explicit IOException(const string &msg, Args... params) : IOException(ConstructMessage(msg, params...)) {
280 }
281};
282
283class MissingExtensionException : public Exception {
284public:
285 DUCKDB_API explicit MissingExtensionException(const string &msg);
286
287 template <typename... Args>
288 explicit MissingExtensionException(const string &msg, Args... params)
289 : MissingExtensionException(ConstructMessage(msg, params...)) {
290 }
291};
292
293class HTTPException : public IOException {
294public:
295 template <typename>
296 struct ResponseShape {
297 typedef int status;
298 };
299
300 template <class RESPONSE, typename ResponseShape<decltype(RESPONSE::status)>::status = 0, typename... ARGS>
301 explicit HTTPException(RESPONSE &response, const string &msg, ARGS... params)
302 : HTTPException(response.status, response.body, response.headers, response.reason, msg, params...) {
303 }
304
305 template <typename>
306 struct ResponseWrapperShape {
307 typedef int code;
308 };
309 template <class RESPONSE, typename ResponseWrapperShape<decltype(RESPONSE::code)>::code = 0, typename... ARGS>
310 explicit HTTPException(RESPONSE &response, const string &msg, ARGS... params)
311 : HTTPException(response.code, response.body, response.headers, response.error, msg, params...) {
312 }
313
314 template <typename HEADERS, typename... ARGS>
315 explicit HTTPException(int status_code, string response_body, HEADERS headers, const string &reason,
316 const string &msg, ARGS... params)
317 : IOException(ExceptionType::HTTP, ConstructMessage(msg, params...)), status_code(status_code), reason(reason),
318 response_body(std::move(response_body)) {
319 this->headers.insert(headers.begin(), headers.end());
320 D_ASSERT(this->headers.size() > 0);
321 }
322
323 std::shared_ptr<Exception> Copy() const {
324 return make_shared<HTTPException>(args: status_code, args: response_body, args: headers, args: reason, args: RawMessage());
325 }
326
327 const std::multimap<std::string, std::string> GetHeaders() const {
328 return headers;
329 }
330 int GetStatusCode() const {
331 return status_code;
332 }
333 const string &GetResponseBody() const {
334 return response_body;
335 }
336 const string &GetReason() const {
337 return reason;
338 }
339 [[noreturn]] void Throw() const {
340 throw HTTPException(status_code, response_body, headers, reason, RawMessage());
341 }
342
343private:
344 int status_code;
345 string reason;
346 string response_body;
347 std::multimap<string, string> headers;
348};
349
350class SerializationException : public Exception {
351public:
352 DUCKDB_API explicit SerializationException(const string &msg);
353
354 template <typename... Args>
355 explicit SerializationException(const string &msg, Args... params)
356 : SerializationException(ConstructMessage(msg, params...)) {
357 }
358};
359
360class SequenceException : public Exception {
361public:
362 DUCKDB_API explicit SequenceException(const string &msg);
363
364 template <typename... Args>
365 explicit SequenceException(const string &msg, Args... params)
366 : SequenceException(ConstructMessage(msg, params...)) {
367 }
368};
369
370class InterruptException : public Exception {
371public:
372 DUCKDB_API InterruptException();
373};
374
375class FatalException : public Exception {
376public:
377 explicit FatalException(const string &msg) : FatalException(ExceptionType::FATAL, msg) {
378 }
379 template <typename... Args>
380 explicit FatalException(const string &msg, Args... params) : FatalException(ConstructMessage(msg, params...)) {
381 }
382
383protected:
384 DUCKDB_API explicit FatalException(ExceptionType type, const string &msg);
385 template <typename... Args>
386 explicit FatalException(ExceptionType type, const string &msg, Args... params)
387 : FatalException(type, ConstructMessage(msg, params...)) {
388 }
389};
390
391class InternalException : public FatalException {
392public:
393 DUCKDB_API explicit InternalException(const string &msg);
394
395 template <typename... Args>
396 explicit InternalException(const string &msg, Args... params)
397 : InternalException(ConstructMessage(msg, params...)) {
398 }
399};
400
401class InvalidInputException : public Exception {
402public:
403 DUCKDB_API explicit InvalidInputException(const string &msg);
404
405 template <typename... Args>
406 explicit InvalidInputException(const string &msg, Args... params)
407 : InvalidInputException(ConstructMessage(msg, params...)) {
408 }
409};
410
411class CastException : public Exception {
412public:
413 DUCKDB_API CastException(const PhysicalType origType, const PhysicalType newType);
414 DUCKDB_API CastException(const LogicalType &origType, const LogicalType &newType);
415 DUCKDB_API
416 CastException(const string &msg); //! Needed to be able to recreate the exception after it's been serialized
417};
418
419class InvalidTypeException : public Exception {
420public:
421 DUCKDB_API InvalidTypeException(PhysicalType type, const string &msg);
422 DUCKDB_API InvalidTypeException(const LogicalType &type, const string &msg);
423 DUCKDB_API
424 InvalidTypeException(const string &msg); //! Needed to be able to recreate the exception after it's been serialized
425};
426
427class TypeMismatchException : public Exception {
428public:
429 DUCKDB_API TypeMismatchException(const PhysicalType type_1, const PhysicalType type_2, const string &msg);
430 DUCKDB_API TypeMismatchException(const LogicalType &type_1, const LogicalType &type_2, const string &msg);
431 DUCKDB_API
432 TypeMismatchException(const string &msg); //! Needed to be able to recreate the exception after it's been serialized
433};
434
435class ValueOutOfRangeException : public Exception {
436public:
437 DUCKDB_API ValueOutOfRangeException(const int64_t value, const PhysicalType origType, const PhysicalType newType);
438 DUCKDB_API ValueOutOfRangeException(const hugeint_t value, const PhysicalType origType, const PhysicalType newType);
439 DUCKDB_API ValueOutOfRangeException(const double value, const PhysicalType origType, const PhysicalType newType);
440 DUCKDB_API ValueOutOfRangeException(const PhysicalType varType, const idx_t length);
441 DUCKDB_API ValueOutOfRangeException(
442 const string &msg); //! Needed to be able to recreate the exception after it's been serialized
443};
444
445class ParameterNotAllowedException : public StandardException {
446public:
447 DUCKDB_API explicit ParameterNotAllowedException(const string &msg);
448
449 template <typename... Args>
450 explicit ParameterNotAllowedException(const string &msg, Args... params)
451 : ParameterNotAllowedException(ConstructMessage(msg, params...)) {
452 }
453};
454
455//! Special exception that should be thrown in the binder if parameter types could not be resolved
456//! This will cause prepared statements to be forcibly rebound with the actual parameter values
457//! This exception is fatal if thrown outside of the binder (i.e. it should never be thrown outside of the binder)
458class ParameterNotResolvedException : public Exception {
459public:
460 DUCKDB_API explicit ParameterNotResolvedException();
461};
462
463} // namespace duckdb
464