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