1 | #include "duckdb/common/exception.hpp" |
2 | #include "duckdb/common/types.hpp" |
3 | #include "fmt/format.h" |
4 | #include "fmt/printf.h" |
5 | #include "duckdb/common/types/hugeint.hpp" |
6 | #include "duckdb/parser/keyword_helper.hpp" |
7 | |
8 | namespace duckdb { |
9 | |
10 | ExceptionFormatValue::ExceptionFormatValue(double dbl_val) |
11 | : type(ExceptionFormatValueType::FORMAT_VALUE_TYPE_DOUBLE), dbl_val(dbl_val) { |
12 | } |
13 | ExceptionFormatValue::ExceptionFormatValue(int64_t int_val) |
14 | : type(ExceptionFormatValueType::FORMAT_VALUE_TYPE_INTEGER), int_val(int_val) { |
15 | } |
16 | ExceptionFormatValue::ExceptionFormatValue(hugeint_t huge_val) |
17 | : type(ExceptionFormatValueType::FORMAT_VALUE_TYPE_STRING), str_val(Hugeint::ToString(input: huge_val)) { |
18 | } |
19 | ExceptionFormatValue::ExceptionFormatValue(string str_val) |
20 | : type(ExceptionFormatValueType::FORMAT_VALUE_TYPE_STRING), str_val(std::move(str_val)) { |
21 | } |
22 | |
23 | template <> |
24 | ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(PhysicalType value) { |
25 | return ExceptionFormatValue(TypeIdToString(type: value)); |
26 | } |
27 | template <> |
28 | ExceptionFormatValue |
29 | ExceptionFormatValue::CreateFormatValue(LogicalType value) { // NOLINT: templating requires us to copy value here |
30 | return ExceptionFormatValue(value.ToString()); |
31 | } |
32 | template <> |
33 | ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(float value) { |
34 | return ExceptionFormatValue(double(value)); |
35 | } |
36 | template <> |
37 | ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(double value) { |
38 | return ExceptionFormatValue(double(value)); |
39 | } |
40 | template <> |
41 | ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(string value) { |
42 | return ExceptionFormatValue(std::move(value)); |
43 | } |
44 | |
45 | template <> |
46 | ExceptionFormatValue |
47 | ExceptionFormatValue::CreateFormatValue(SQLString value) { // NOLINT: templating requires us to copy value here |
48 | return KeywordHelper::WriteQuoted(text: value.raw_string, quote: '\''); |
49 | } |
50 | |
51 | template <> |
52 | ExceptionFormatValue |
53 | ExceptionFormatValue::CreateFormatValue(SQLIdentifier value) { // NOLINT: templating requires us to copy value here |
54 | return KeywordHelper::WriteOptionallyQuoted(text: value.raw_string, quote: '"'); |
55 | } |
56 | |
57 | template <> |
58 | ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(const char *value) { |
59 | return ExceptionFormatValue(string(value)); |
60 | } |
61 | template <> |
62 | ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(char *value) { |
63 | return ExceptionFormatValue(string(value)); |
64 | } |
65 | template <> |
66 | ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(hugeint_t value) { |
67 | return ExceptionFormatValue(value); |
68 | } |
69 | |
70 | string ExceptionFormatValue::Format(const string &msg, std::vector<ExceptionFormatValue> &values) { |
71 | try { |
72 | std::vector<duckdb_fmt::basic_format_arg<duckdb_fmt::printf_context>> format_args; |
73 | for (auto &val : values) { |
74 | switch (val.type) { |
75 | case ExceptionFormatValueType::FORMAT_VALUE_TYPE_DOUBLE: |
76 | format_args.push_back(x: duckdb_fmt::internal::make_arg<duckdb_fmt::printf_context>(value: val.dbl_val)); |
77 | break; |
78 | case ExceptionFormatValueType::FORMAT_VALUE_TYPE_INTEGER: |
79 | format_args.push_back(x: duckdb_fmt::internal::make_arg<duckdb_fmt::printf_context>(value: val.int_val)); |
80 | break; |
81 | case ExceptionFormatValueType::FORMAT_VALUE_TYPE_STRING: |
82 | format_args.push_back(x: duckdb_fmt::internal::make_arg<duckdb_fmt::printf_context>(value: val.str_val)); |
83 | break; |
84 | } |
85 | } |
86 | return duckdb_fmt::vsprintf(format: msg, args: duckdb_fmt::basic_format_args<duckdb_fmt::printf_context>( |
87 | format_args.data(), static_cast<int>(format_args.size()))); |
88 | } catch (std::exception &ex) { // LCOV_EXCL_START |
89 | // work-around for oss-fuzz limiting memory which causes issues here |
90 | if (StringUtil::Contains(haystack: ex.what(), needle: "fuzz mode" )) { |
91 | throw Exception(msg); |
92 | } |
93 | throw InternalException(std::string("Primary exception: " ) + msg + |
94 | "\nSecondary exception in ExceptionFormatValue: " + ex.what()); |
95 | } // LCOV_EXCL_STOP |
96 | } |
97 | |
98 | } // namespace duckdb |
99 | |