| 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 |  | 
| 20 | namespace duckdb { | 
| 21 | enum class PhysicalType : uint8_t; | 
| 22 | struct LogicalType; | 
| 23 | struct hugeint_t; | 
| 24 |  | 
| 25 | inline 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 |  | 
| 43 | enum 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 | }; | 
| 85 | class HTTPException; | 
| 86 |  | 
| 87 | class Exception : public std::exception { | 
| 88 | public: | 
| 89 | 	DUCKDB_API explicit Exception(const string &msg); | 
| 90 | 	DUCKDB_API Exception(ExceptionType exception_type, const string &message); | 
| 91 |  | 
| 92 | 	ExceptionType type; | 
| 93 |  | 
| 94 | public: | 
| 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 |  | 
| 131 | private: | 
| 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 | 
| 141 | class StandardException : public Exception { | 
| 142 | public: | 
| 143 | 	DUCKDB_API StandardException(ExceptionType exception_type, const string &message); | 
| 144 | }; | 
| 145 |  | 
| 146 | class CatalogException : public StandardException { | 
| 147 | public: | 
| 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 |  | 
| 155 | class ConnectionException : public StandardException { | 
| 156 | public: | 
| 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 |  | 
| 165 | class ParserException : public StandardException { | 
| 166 | public: | 
| 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 |  | 
| 174 | class PermissionException : public StandardException { | 
| 175 | public: | 
| 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 |  | 
| 184 | class BinderException : public StandardException { | 
| 185 | public: | 
| 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 |  | 
| 193 | class ConversionException : public Exception { | 
| 194 | public: | 
| 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 |  | 
| 203 | class TransactionException : public Exception { | 
| 204 | public: | 
| 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 |  | 
| 213 | class NotImplementedException : public Exception { | 
| 214 | public: | 
| 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 |  | 
| 223 | class OutOfRangeException : public Exception { | 
| 224 | public: | 
| 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 |  | 
| 233 | class OutOfMemoryException : public Exception { | 
| 234 | public: | 
| 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 |  | 
| 243 | class SyntaxException : public Exception { | 
| 244 | public: | 
| 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 |  | 
| 252 | class ConstraintException : public Exception { | 
| 253 | public: | 
| 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 |  | 
| 262 | class DependencyException : public Exception { | 
| 263 | public: | 
| 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 |  | 
| 272 | class IOException : public Exception { | 
| 273 | public: | 
| 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 |  | 
| 283 | class MissingExtensionException : public Exception { | 
| 284 | public: | 
| 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 |  | 
| 293 | class HTTPException : public IOException { | 
| 294 | public: | 
| 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 , 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> () 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 |  | 
| 343 | private: | 
| 344 | 	int status_code; | 
| 345 | 	string reason; | 
| 346 | 	string response_body; | 
| 347 | 	std::multimap<string, string> ; | 
| 348 | }; | 
| 349 |  | 
| 350 | class SerializationException : public Exception { | 
| 351 | public: | 
| 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 |  | 
| 360 | class SequenceException : public Exception { | 
| 361 | public: | 
| 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 |  | 
| 370 | class InterruptException : public Exception { | 
| 371 | public: | 
| 372 | 	DUCKDB_API InterruptException(); | 
| 373 | }; | 
| 374 |  | 
| 375 | class FatalException : public Exception { | 
| 376 | public: | 
| 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 |  | 
| 383 | protected: | 
| 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 |  | 
| 391 | class InternalException : public FatalException { | 
| 392 | public: | 
| 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 |  | 
| 401 | class InvalidInputException : public Exception { | 
| 402 | public: | 
| 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 |  | 
| 411 | class CastException : public Exception { | 
| 412 | public: | 
| 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 |  | 
| 419 | class InvalidTypeException : public Exception { | 
| 420 | public: | 
| 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 |  | 
| 427 | class TypeMismatchException : public Exception { | 
| 428 | public: | 
| 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 |  | 
| 435 | class ValueOutOfRangeException : public Exception { | 
| 436 | public: | 
| 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 |  | 
| 445 | class ParameterNotAllowedException : public StandardException { | 
| 446 | public: | 
| 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) | 
| 458 | class ParameterNotResolvedException : public Exception { | 
| 459 | public: | 
| 460 | 	DUCKDB_API explicit ParameterNotResolvedException(); | 
| 461 | }; | 
| 462 |  | 
| 463 | } // namespace duckdb | 
| 464 |  |