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
8namespace duckdb {
9
10ExceptionFormatValue::ExceptionFormatValue(double dbl_val)
11 : type(ExceptionFormatValueType::FORMAT_VALUE_TYPE_DOUBLE), dbl_val(dbl_val) {
12}
13ExceptionFormatValue::ExceptionFormatValue(int64_t int_val)
14 : type(ExceptionFormatValueType::FORMAT_VALUE_TYPE_INTEGER), int_val(int_val) {
15}
16ExceptionFormatValue::ExceptionFormatValue(hugeint_t huge_val)
17 : type(ExceptionFormatValueType::FORMAT_VALUE_TYPE_STRING), str_val(Hugeint::ToString(input: huge_val)) {
18}
19ExceptionFormatValue::ExceptionFormatValue(string str_val)
20 : type(ExceptionFormatValueType::FORMAT_VALUE_TYPE_STRING), str_val(std::move(str_val)) {
21}
22
23template <>
24ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(PhysicalType value) {
25 return ExceptionFormatValue(TypeIdToString(type: value));
26}
27template <>
28ExceptionFormatValue
29ExceptionFormatValue::CreateFormatValue(LogicalType value) { // NOLINT: templating requires us to copy value here
30 return ExceptionFormatValue(value.ToString());
31}
32template <>
33ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(float value) {
34 return ExceptionFormatValue(double(value));
35}
36template <>
37ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(double value) {
38 return ExceptionFormatValue(double(value));
39}
40template <>
41ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(string value) {
42 return ExceptionFormatValue(std::move(value));
43}
44
45template <>
46ExceptionFormatValue
47ExceptionFormatValue::CreateFormatValue(SQLString value) { // NOLINT: templating requires us to copy value here
48 return KeywordHelper::WriteQuoted(text: value.raw_string, quote: '\'');
49}
50
51template <>
52ExceptionFormatValue
53ExceptionFormatValue::CreateFormatValue(SQLIdentifier value) { // NOLINT: templating requires us to copy value here
54 return KeywordHelper::WriteOptionallyQuoted(text: value.raw_string, quote: '"');
55}
56
57template <>
58ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(const char *value) {
59 return ExceptionFormatValue(string(value));
60}
61template <>
62ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(char *value) {
63 return ExceptionFormatValue(string(value));
64}
65template <>
66ExceptionFormatValue ExceptionFormatValue::CreateFormatValue(hugeint_t value) {
67 return ExceptionFormatValue(value);
68}
69
70string 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