duckdb 0.7.2-dev2820.0 → 0.7.2-dev2867.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb/extension/icu/icu-datepart.cpp +51 -1
  3. package/src/duckdb/extension/parquet/parquet-extension.cpp +5 -4
  4. package/src/duckdb/src/common/local_file_system.cpp +1 -3
  5. package/src/duckdb/src/common/multi_file_reader.cpp +11 -8
  6. package/src/duckdb/src/execution/operator/schema/physical_create_type.cpp +11 -2
  7. package/src/duckdb/src/function/table/read_csv.cpp +7 -4
  8. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  9. package/src/duckdb/src/include/duckdb/common/multi_file_reader.hpp +5 -4
  10. package/src/duckdb/src/include/duckdb/execution/operator/schema/physical_create_type.hpp +4 -0
  11. package/src/duckdb/src/include/duckdb/main/database.hpp +1 -0
  12. package/src/duckdb/src/include/duckdb/main/database_manager.hpp +3 -0
  13. package/src/duckdb/src/include/duckdb/main/extension_helper.hpp +0 -2
  14. package/src/duckdb/src/include/duckdb/parser/tableref/pivotref.hpp +3 -0
  15. package/src/duckdb/src/include/duckdb/parser/transformer.hpp +5 -1
  16. package/src/duckdb/src/main/attached_database.cpp +5 -3
  17. package/src/duckdb/src/main/database.cpp +34 -37
  18. package/src/duckdb/src/main/extension/extension_load.cpp +13 -34
  19. package/src/duckdb/src/parser/transform/statement/transform_create_function.cpp +1 -4
  20. package/src/duckdb/src/parser/transform/statement/transform_create_view.cpp +2 -4
  21. package/src/duckdb/src/parser/transform/statement/transform_pivot_stmt.cpp +43 -24
  22. package/src/duckdb/src/parser/transform/tableref/transform_pivot.cpp +3 -0
  23. package/src/duckdb/src/planner/binder/statement/bind_create.cpp +17 -28
  24. package/src/duckdb/third_party/fmt/format.cc +0 -5
  25. package/src/duckdb/third_party/fmt/include/fmt/core.h +10 -12
  26. package/src/duckdb/third_party/fmt/include/fmt/format-inl.h +2 -33
  27. package/src/duckdb/third_party/fmt/include/fmt/format.h +61 -24
  28. package/src/duckdb/third_party/fmt/include/fmt/printf.h +15 -1
  29. package/src/duckdb/third_party/libpg_query/include/nodes/parsenodes.hpp +1 -0
  30. package/src/duckdb/third_party/libpg_query/src_backend_parser_gram.cpp +10735 -10674
@@ -18,33 +18,45 @@
18
18
 
19
19
  namespace duckdb {
20
20
 
21
- void Transformer::AddPivotEntry(string enum_name, unique_ptr<SelectNode> base, unique_ptr<ParsedExpression> column) {
21
+ void Transformer::AddPivotEntry(string enum_name, unique_ptr<SelectNode> base, unique_ptr<ParsedExpression> column,
22
+ unique_ptr<QueryNode> subquery) {
22
23
  if (parent) {
23
- parent->AddPivotEntry(std::move(enum_name), std::move(base), std::move(column));
24
+ parent->AddPivotEntry(std::move(enum_name), std::move(base), std::move(column), std::move(subquery));
24
25
  return;
25
26
  }
26
27
  auto result = make_uniq<CreatePivotEntry>();
27
28
  result->enum_name = std::move(enum_name);
28
29
  result->base = std::move(base);
29
30
  result->column = std::move(column);
31
+ result->subquery = std::move(subquery);
30
32
 
31
33
  pivot_entries.push_back(std::move(result));
32
34
  }
33
35
 
34
36
  bool Transformer::HasPivotEntries() {
35
- if (parent) {
36
- return parent->HasPivotEntries();
37
- }
38
- return !pivot_entries.empty();
37
+ return !GetPivotEntries().empty();
39
38
  }
40
39
 
41
40
  idx_t Transformer::PivotEntryCount() {
41
+ return GetPivotEntries().size();
42
+ }
43
+
44
+ vector<unique_ptr<Transformer::CreatePivotEntry>> &Transformer::GetPivotEntries() {
42
45
  if (parent) {
43
- return parent->PivotEntryCount();
46
+ return parent->GetPivotEntries();
44
47
  }
45
- return pivot_entries.size();
48
+ return pivot_entries;
46
49
  }
47
50
 
51
+ void Transformer::PivotEntryCheck(const string &type) {
52
+ auto &entries = GetPivotEntries();
53
+ if (!entries.empty()) {
54
+ throw ParserException(
55
+ "PIVOT statements with pivot elements extracted from the data cannot be used in %ss.\nIn order to use "
56
+ "PIVOT in a %s the PIVOT values must be manually specified, e.g.:\nPIVOT ... ON %s IN (val1, val2, ...)",
57
+ type, type, entries[0]->column->ToString());
58
+ }
59
+ }
48
60
  unique_ptr<SQLStatement> Transformer::GenerateCreateEnumStmt(unique_ptr<CreatePivotEntry> entry) {
49
61
  auto result = make_uniq<CreateStatement>();
50
62
  auto info = make_uniq<CreateTypeInfo>();
@@ -57,23 +69,30 @@ unique_ptr<SQLStatement> Transformer::GenerateCreateEnumStmt(unique_ptr<CreatePi
57
69
  info->on_conflict = OnCreateConflict::REPLACE_ON_CONFLICT;
58
70
 
59
71
  // generate the query that will result in the enum creation
60
- auto select_node = std::move(entry->base);
61
- auto columnref = entry->column->Copy();
62
- auto cast = make_uniq<CastExpression>(LogicalType::VARCHAR, std::move(columnref));
63
- select_node->select_list.push_back(std::move(cast));
64
-
65
- auto is_not_null = make_uniq<OperatorExpression>(ExpressionType::OPERATOR_IS_NOT_NULL, std::move(entry->column));
66
- select_node->where_clause = std::move(is_not_null);
67
-
68
- // order by the column
69
- select_node->modifiers.push_back(make_uniq<DistinctModifier>());
70
- auto modifier = make_uniq<OrderModifier>();
71
- modifier->orders.emplace_back(OrderType::ASCENDING, OrderByNullType::ORDER_DEFAULT,
72
- make_uniq<ConstantExpression>(Value::INTEGER(1)));
73
- select_node->modifiers.push_back(std::move(modifier));
72
+ unique_ptr<QueryNode> subselect;
73
+ if (!entry->subquery) {
74
+ auto select_node = std::move(entry->base);
75
+ auto columnref = entry->column->Copy();
76
+ auto cast = make_uniq<CastExpression>(LogicalType::VARCHAR, std::move(columnref));
77
+ select_node->select_list.push_back(std::move(cast));
78
+
79
+ auto is_not_null =
80
+ make_uniq<OperatorExpression>(ExpressionType::OPERATOR_IS_NOT_NULL, std::move(entry->column));
81
+ select_node->where_clause = std::move(is_not_null);
82
+
83
+ // order by the column
84
+ select_node->modifiers.push_back(make_uniq<DistinctModifier>());
85
+ auto modifier = make_uniq<OrderModifier>();
86
+ modifier->orders.emplace_back(OrderType::ASCENDING, OrderByNullType::ORDER_DEFAULT,
87
+ make_uniq<ConstantExpression>(Value::INTEGER(1)));
88
+ select_node->modifiers.push_back(std::move(modifier));
89
+ subselect = std::move(select_node);
90
+ } else {
91
+ subselect = std::move(entry->subquery);
92
+ }
74
93
 
75
94
  auto select = make_uniq<SelectStatement>();
76
- select->node = std::move(select_node);
95
+ select->node = std::move(subselect);
77
96
  info->query = std::move(select);
78
97
  info->type = LogicalType::INVALID;
79
98
 
@@ -150,7 +169,7 @@ unique_ptr<QueryNode> Transformer::TransformPivotStatement(duckdb_libpgquery::PG
150
169
  auto new_select = make_uniq<SelectNode>();
151
170
  ExtractCTEsRecursive(new_select->cte_map);
152
171
  new_select->from_table = source->Copy();
153
- AddPivotEntry(enum_name, std::move(new_select), col.pivot_expressions[0]->Copy());
172
+ AddPivotEntry(enum_name, std::move(new_select), col.pivot_expressions[0]->Copy(), std::move(col.subquery));
154
173
  col.pivot_enum = enum_name;
155
174
  }
156
175
 
@@ -59,6 +59,9 @@ PivotColumn Transformer::TransformPivotColumn(duckdb_libpgquery::PGPivot *pivot)
59
59
  col.entries.push_back(std::move(entry));
60
60
  }
61
61
  }
62
+ if (pivot->subquery) {
63
+ col.subquery = TransformSelectNode(reinterpret_cast<duckdb_libpgquery::PGSelectStmt *>(pivot->subquery));
64
+ }
62
65
  if (pivot->pivot_enum) {
63
66
  col.pivot_enum = pivot->pivot_enum;
64
67
  }
@@ -8,6 +8,8 @@
8
8
  #include "duckdb/parser/expression/constant_expression.hpp"
9
9
  #include "duckdb/parser/expression/function_expression.hpp"
10
10
  #include "duckdb/parser/expression/subquery_expression.hpp"
11
+ #include "duckdb/planner/expression/bound_cast_expression.hpp"
12
+ #include "duckdb/planner/expression/bound_columnref_expression.hpp"
11
13
  #include "duckdb/parser/parsed_data/create_index_info.hpp"
12
14
  #include "duckdb/parser/parsed_data/create_macro_info.hpp"
13
15
  #include "duckdb/parser/parsed_data/create_view_info.hpp"
@@ -24,6 +26,7 @@
24
26
  #include "duckdb/planner/operator/logical_create_table.hpp"
25
27
  #include "duckdb/planner/operator/logical_get.hpp"
26
28
  #include "duckdb/planner/operator/logical_distinct.hpp"
29
+ #include "duckdb/planner/operator/logical_projection.hpp"
27
30
  #include "duckdb/planner/parsed_data/bound_create_table_info.hpp"
28
31
  #include "duckdb/planner/query_node/bound_select_node.hpp"
29
32
  #include "duckdb/planner/tableref/bound_basetableref.hpp"
@@ -605,41 +608,27 @@ BoundStatement Binder::Bind(CreateStatement &stmt) {
605
608
  }
606
609
  case CatalogType::TYPE_ENTRY: {
607
610
  auto &schema = BindCreateSchema(*stmt.info);
608
- auto &create_type_info = (CreateTypeInfo &)(*stmt.info);
611
+ auto &create_type_info = stmt.info->Cast<CreateTypeInfo>();
609
612
  result.plan = make_uniq<LogicalCreate>(LogicalOperatorType::LOGICAL_CREATE_TYPE, std::move(stmt.info), &schema);
610
613
  if (create_type_info.query) {
611
614
  // CREATE TYPE mood AS ENUM (SELECT 'happy')
612
- auto &select_stmt = create_type_info.query->Cast<SelectStatement>();
613
- auto &query_node = *select_stmt.node;
614
-
615
- // We always add distinct modifier implicitly
616
- bool need_to_add = true;
617
- if (!query_node.modifiers.empty()) {
618
- if (query_node.modifiers[0]->type == ResultModifierType::DISTINCT_MODIFIER) {
619
- // There are cases where the same column is grouped repeatedly
620
- // CREATE TYPE mood AS ENUM (SELECT DISTINCT ON(x) x FROM test);
621
- // When we push into a constant expression
622
- // => CREATE TYPE mood AS ENUM (SELECT DISTINCT ON(x, x) x FROM test);
623
- auto &distinct_modifier = (DistinctModifier &)*query_node.modifiers[0];
624
- if (distinct_modifier.distinct_on_targets.empty()) {
625
- need_to_add = false;
626
- }
627
- }
628
- }
629
-
630
- // Add distinct modifier
631
- if (need_to_add) {
632
- auto distinct_modifier = make_uniq<DistinctModifier>();
633
- query_node.modifiers.emplace(query_node.modifiers.begin(), std::move(distinct_modifier));
634
- }
635
-
636
615
  auto query_obj = Bind(*create_type_info.query);
637
616
  auto query = std::move(query_obj.plan);
638
617
 
639
618
  auto &sql_types = query_obj.types;
640
- if (sql_types.size() != 1 || sql_types[0].id() != LogicalType::VARCHAR) {
619
+ if (sql_types.size() != 1) {
641
620
  // add cast expression?
642
- throw BinderException("The query must return one varchar column");
621
+ throw BinderException("The query must return a single column");
622
+ }
623
+ if (sql_types[0].id() != LogicalType::VARCHAR) {
624
+ // push a projection casting to varchar
625
+ vector<unique_ptr<Expression>> select_list;
626
+ auto ref = make_uniq<BoundColumnRefExpression>(sql_types[0], query->GetColumnBindings()[0]);
627
+ auto cast_expr = BoundCastExpression::AddCastToType(context, std::move(ref), LogicalType::VARCHAR);
628
+ select_list.push_back(std::move(cast_expr));
629
+ auto proj = make_uniq<LogicalProjection>(GenerateTableIndex(), std::move(select_list));
630
+ proj->AddChild(std::move(query));
631
+ query = std::move(proj);
643
632
  }
644
633
 
645
634
  result.plan->AddChild(std::move(query));
@@ -660,7 +649,7 @@ BoundStatement Binder::Bind(CreateStatement &stmt) {
660
649
  }
661
650
  case CatalogType::DATABASE_ENTRY: {
662
651
  // not supported in DuckDB yet but allow extensions to intercept and implement this functionality
663
- auto &base = (CreateDatabaseInfo &)*stmt.info;
652
+ auto &base = stmt.info->Cast<CreateDatabaseInfo>();
664
653
  string database_name = base.name;
665
654
  string source_path = base.path;
666
655
 
@@ -128,11 +128,6 @@ int (*instantiate_format_float)(double, int, internal::float_specs,
128
128
  internal::buffer<char>&) =
129
129
  internal::format_float;
130
130
 
131
- #ifndef FMT_STATIC_THOUSANDS_SEPARATOR
132
- template FMT_API internal::locale_ref::locale_ref(const std::locale& loc);
133
- template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
134
- #endif
135
-
136
131
  // Explicit instantiations for char.
137
132
 
138
133
  template FMT_API std::string internal::grouping_impl<char>(locale_ref);
@@ -62,15 +62,9 @@
62
62
 
63
63
  // Check if relaxed C++14 constexpr is supported.
64
64
  // GCC doesn't allow throw in constexpr until version 6 (bug 67371).
65
- #ifndef FMT_USE_CONSTEXPR
66
- # define FMT_USE_CONSTEXPR \
67
- (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \
68
- (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \
69
- !FMT_NVCC
70
- #endif
71
65
  #if FMT_USE_CONSTEXPR
72
- # define FMT_CONSTEXPR constexpr
73
- # define FMT_CONSTEXPR_DECL constexpr
66
+ # define FMT_CONSTEXPR inline
67
+ # define FMT_CONSTEXPR_DECL
74
68
  #else
75
69
  # define FMT_CONSTEXPR inline
76
70
  # define FMT_CONSTEXPR_DECL
@@ -323,6 +317,10 @@ template <typename Char> class basic_string_view {
323
317
  size_ -= n;
324
318
  }
325
319
 
320
+ std::string to_string() {
321
+ return std::string((char *) data(), size());
322
+ }
323
+
326
324
  // Lexicographically compare this string reference to other.
327
325
  int compare(basic_string_view other) const {
328
326
  size_t str_size = size_ < other.size_ ? size_ : other.size_;
@@ -416,7 +414,7 @@ template <typename S>
416
414
  struct is_compile_string : std::is_base_of<compile_string, S> {};
417
415
 
418
416
  template <typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
419
- constexpr basic_string_view<typename S::char_type> to_string_view(const S& s) {
417
+ FMT_CONSTEXPR basic_string_view<typename S::char_type> to_string_view(const S& s) {
420
418
  return s;
421
419
  }
422
420
 
@@ -442,7 +440,7 @@ struct error_handler {
442
440
  FMT_CONSTEXPR error_handler(const error_handler&) = default;
443
441
 
444
442
  // This function is intentionally not constexpr to give a compile-time error.
445
- FMT_NORETURN FMT_API void on_error(const char* message);
443
+ FMT_NORETURN FMT_API void on_error(std::string message);
446
444
  };
447
445
  } // namespace internal
448
446
 
@@ -520,7 +518,7 @@ class basic_format_parse_context : private ErrorHandler {
520
518
 
521
519
  FMT_CONSTEXPR void check_arg_id(basic_string_view<Char>) {}
522
520
 
523
- FMT_CONSTEXPR void on_error(const char* message) {
521
+ FMT_CONSTEXPR void on_error(std::string message) {
524
522
  ErrorHandler::on_error(message);
525
523
  }
526
524
 
@@ -1158,7 +1156,7 @@ template <typename OutputIt, typename Char> class basic_format_context {
1158
1156
  format_arg arg(basic_string_view<char_type> name);
1159
1157
 
1160
1158
  internal::error_handler error_handler() { return {}; }
1161
- void on_error(const char* message) { error_handler().on_error(message); }
1159
+ void on_error(std::string message) { error_handler().on_error(message); }
1162
1160
 
1163
1161
  // Returns an iterator to the beginning of the output range.
1164
1162
  iterator out() { return out_; }
@@ -17,10 +17,6 @@
17
17
  #include <cstdarg>
18
18
  #include <cstring> // for std::memmove
19
19
  #include <cwchar>
20
- #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
21
- # include <locale>
22
- #endif
23
-
24
20
  #if FMT_EXCEPTIONS
25
21
  # define FMT_TRY try
26
22
  # define FMT_CATCH(x) catch (x)
@@ -162,45 +158,18 @@ FMT_FUNC void report_error(format_func func, int error_code,
162
158
  }
163
159
  } // namespace internal
164
160
 
165
- #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
166
- namespace internal {
167
-
168
- template <typename Locale>
169
- locale_ref::locale_ref(const Locale& loc) : locale_(&loc) {
170
- static_assert(std::is_same<Locale, std::locale>::value, "");
171
- }
172
-
173
- template <typename Locale> Locale locale_ref::get() const {
174
- static_assert(std::is_same<Locale, std::locale>::value, "");
175
- return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
176
- }
177
-
178
- template <typename Char> FMT_FUNC std::string grouping_impl(locale_ref loc) {
179
- return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>()).grouping();
180
- }
181
- template <typename Char> FMT_FUNC Char thousands_sep_impl(locale_ref loc) {
182
- return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
183
- .thousands_sep();
184
- }
185
- template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref loc) {
186
- return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
187
- .decimal_point();
188
- }
189
- } // namespace internal
190
- #else
191
161
  template <typename Char>
192
162
  FMT_FUNC std::string internal::grouping_impl(locale_ref) {
193
163
  return "\03";
194
164
  }
195
165
  template <typename Char>
196
166
  FMT_FUNC Char internal::thousands_sep_impl(locale_ref) {
197
- return FMT_STATIC_THOUSANDS_SEPARATOR;
167
+ return ',';
198
168
  }
199
169
  template <typename Char>
200
170
  FMT_FUNC Char internal::decimal_point_impl(locale_ref) {
201
171
  return '.';
202
172
  }
203
- #endif
204
173
 
205
174
  namespace internal {
206
175
 
@@ -1203,7 +1172,7 @@ template <> struct formatter<internal::bigint> {
1203
1172
  }
1204
1173
  };
1205
1174
 
1206
- FMT_FUNC void internal::error_handler::on_error(const char* message) {
1175
+ FMT_FUNC void internal::error_handler::on_error(std::string message) {
1207
1176
  FMT_THROW(duckdb::Exception(message));
1208
1177
  }
1209
1178
 
@@ -951,6 +951,7 @@ template <typename Char> struct basic_format_specs {
951
951
  sign_t sign : 3;
952
952
  bool alt : 1; // Alternate form ('#').
953
953
  internal::fill_t<Char> fill;
954
+ char thousands;
954
955
 
955
956
  constexpr basic_format_specs()
956
957
  : width(0),
@@ -959,7 +960,8 @@ template <typename Char> struct basic_format_specs {
959
960
  align(align::none),
960
961
  sign(sign::none),
961
962
  alt(false),
962
- fill(internal::fill_t<Char>::make()) {}
963
+ fill(internal::fill_t<Char>::make()),
964
+ thousands('\0'){}
963
965
  };
964
966
 
965
967
  using format_specs = basic_format_specs<char>;
@@ -1124,9 +1126,13 @@ int snprintf_float(T value, int precision, float_specs specs,
1124
1126
  template <typename T> T promote_float(T value) { return value; }
1125
1127
  inline double promote_float(float value) { return value; }
1126
1128
 
1127
- template <typename Handler>
1128
- FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) {
1129
- switch (spec) {
1129
+ template <typename Spec, typename Handler>
1130
+ FMT_CONSTEXPR void handle_int_type_spec(const Spec& specs, Handler&& handler) {
1131
+ if (specs.thousands != '\0') {
1132
+ handler.on_num();
1133
+ return;
1134
+ }
1135
+ switch (specs.type) {
1130
1136
  case 0:
1131
1137
  case 'd':
1132
1138
  handler.on_dec();
@@ -1143,17 +1149,24 @@ FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) {
1143
1149
  handler.on_oct();
1144
1150
  break;
1145
1151
  case 'n':
1152
+ case 'l':
1153
+ case 'L':
1146
1154
  handler.on_num();
1147
1155
  break;
1148
1156
  default:
1149
- handler.on_error();
1157
+ handler.on_error("Invalid type specifier \"" + std::string(1, specs.type) + "\" for formatting a value of type int");
1150
1158
  }
1151
1159
  }
1152
1160
 
1153
1161
  template <typename ErrorHandler = error_handler, typename Char>
1154
1162
  FMT_CONSTEXPR float_specs parse_float_type_spec(
1155
1163
  const basic_format_specs<Char>& specs, ErrorHandler&& eh = {}) {
1164
+
1156
1165
  auto result = float_specs();
1166
+ if (specs.thousands != '\0') {
1167
+ eh.on_error("Thousand separators are not supported for floating point numbers");
1168
+ return result;
1169
+ }
1157
1170
  result.trailing_zeros = specs.alt;
1158
1171
  switch (specs.type) {
1159
1172
  case 0:
@@ -1193,10 +1206,12 @@ FMT_CONSTEXPR float_specs parse_float_type_spec(
1193
1206
  result.format = float_format::hex;
1194
1207
  break;
1195
1208
  case 'n':
1209
+ case 'l':
1210
+ case 'L':
1196
1211
  result.locale = true;
1197
1212
  break;
1198
1213
  default:
1199
- eh.on_error("invalid type specifier");
1214
+ eh.on_error("Invalid type specifier \"" + std::string(1, specs.type) + "\" for formatting a value of type float");
1200
1215
  break;
1201
1216
  }
1202
1217
  return result;
@@ -1219,17 +1234,17 @@ FMT_CONSTEXPR void handle_cstring_type_spec(Char spec, Handler&& handler) {
1219
1234
  else if (spec == 'p')
1220
1235
  handler.on_pointer();
1221
1236
  else
1222
- handler.on_error("invalid type specifier");
1237
+ handler.on_error("Invalid type specifier \"" + std::string(1, spec) + "\" for formatting a value of type string");
1223
1238
  }
1224
1239
 
1225
1240
  template <typename Char, typename ErrorHandler>
1226
1241
  FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler&& eh) {
1227
- if (spec != 0 && spec != 's') eh.on_error("invalid type specifier");
1242
+ if (spec != 0 && spec != 's') eh.on_error("Invalid type specifier \"" + std::string(1, spec) + "\" for formatting a value of type string");
1228
1243
  }
1229
1244
 
1230
1245
  template <typename Char, typename ErrorHandler>
1231
1246
  FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler&& eh) {
1232
- if (spec != 0 && spec != 'p') eh.on_error("invalid type specifier");
1247
+ if (spec != 0 && spec != 'p') eh.on_error("Invalid type specifier \"" + std::string(1, spec) + "\" for formatting a value of type pointer");
1233
1248
  }
1234
1249
 
1235
1250
  template <typename ErrorHandler> class int_type_checker : private ErrorHandler {
@@ -1242,8 +1257,8 @@ template <typename ErrorHandler> class int_type_checker : private ErrorHandler {
1242
1257
  FMT_CONSTEXPR void on_oct() {}
1243
1258
  FMT_CONSTEXPR void on_num() {}
1244
1259
 
1245
- FMT_CONSTEXPR void on_error() {
1246
- ErrorHandler::on_error("invalid type specifier");
1260
+ FMT_CONSTEXPR void on_error(std::string error) {
1261
+ ErrorHandler::on_error(error);
1247
1262
  }
1248
1263
  };
1249
1264
 
@@ -1500,7 +1515,7 @@ template <typename Range> class basic_writer {
1500
1515
  void on_num() {
1501
1516
  std::string groups = grouping<char_type>(writer.locale_);
1502
1517
  if (groups.empty()) return on_dec();
1503
- auto sep = thousands_sep<char_type>(writer.locale_);
1518
+ auto sep = specs.thousands;
1504
1519
  if (!sep) return on_dec();
1505
1520
  int num_digits = count_digits(abs_value);
1506
1521
  int size = num_digits;
@@ -1514,11 +1529,11 @@ template <typename Range> class basic_writer {
1514
1529
  if (group == groups.cend())
1515
1530
  size += sep_size * ((num_digits - 1) / groups.back());
1516
1531
  writer.write_int(size, get_prefix(), specs,
1517
- num_writer{abs_value, size, groups, sep});
1532
+ num_writer{abs_value, size, groups, static_cast<char_type>(sep)});
1518
1533
  }
1519
1534
 
1520
- FMT_NORETURN void on_error() {
1521
- FMT_THROW(duckdb::Exception("invalid type specifier"));
1535
+ FMT_NORETURN void on_error(std::string error) {
1536
+ FMT_THROW(duckdb::Exception(error));
1522
1537
  }
1523
1538
  };
1524
1539
 
@@ -1597,7 +1612,7 @@ template <typename Range> class basic_writer {
1597
1612
 
1598
1613
  template <typename T, typename Spec>
1599
1614
  void write_int(T value, const Spec& spec) {
1600
- handle_int_type_spec(spec.type, int_writer<T, Spec>(*this, value, spec));
1615
+ handle_int_type_spec(spec, int_writer<T, Spec>(*this, value, spec));
1601
1616
  }
1602
1617
 
1603
1618
  template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
@@ -1958,6 +1973,10 @@ template <typename Char> class specs_setter {
1958
1973
  FMT_CONSTEXPR void on_plus() { specs_.sign = sign::plus; }
1959
1974
  FMT_CONSTEXPR void on_minus() { specs_.sign = sign::minus; }
1960
1975
  FMT_CONSTEXPR void on_space() { specs_.sign = sign::space; }
1976
+ FMT_CONSTEXPR void on_comma() { specs_.thousands = ','; }
1977
+ FMT_CONSTEXPR void on_underscore() { specs_.thousands = '_'; }
1978
+ FMT_CONSTEXPR void on_single_quote() { specs_.thousands = '\''; }
1979
+ FMT_CONSTEXPR void on_thousands(char sep) { specs_.thousands = sep; }
1961
1980
  FMT_CONSTEXPR void on_hash() { specs_.alt = true; }
1962
1981
 
1963
1982
  FMT_CONSTEXPR void on_zero() {
@@ -2066,7 +2085,7 @@ struct auto_id {};
2066
2085
  template <typename Context>
2067
2086
  FMT_CONSTEXPR typename Context::format_arg get_arg(Context& ctx, int id) {
2068
2087
  auto arg = ctx.arg(id);
2069
- if (!arg) ctx.on_error("argument index out of range");
2088
+ if (!arg) ctx.on_error("Argument index \"" + std::to_string(id) + "\" out of range");
2070
2089
  return arg;
2071
2090
  }
2072
2091
 
@@ -2092,7 +2111,7 @@ class specs_handler : public specs_setter<typename Context::char_type> {
2092
2111
  get_arg(arg_id), context_.error_handler());
2093
2112
  }
2094
2113
 
2095
- void on_error(const char* message) { context_.on_error(message); }
2114
+ void on_error(std::string message) { context_.on_error(message); }
2096
2115
 
2097
2116
  private:
2098
2117
  // This is only needed for compatibility with gcc 4.4.
@@ -2176,7 +2195,7 @@ class dynamic_specs_handler
2176
2195
  specs_.precision_ref = make_arg_ref(arg_id);
2177
2196
  }
2178
2197
 
2179
- FMT_CONSTEXPR void on_error(const char* message) {
2198
+ FMT_CONSTEXPR void on_error(std::string message) {
2180
2199
  context_.on_error(message);
2181
2200
  }
2182
2201
 
@@ -2242,7 +2261,7 @@ template <typename SpecHandler, typename Char> struct width_adapter {
2242
2261
  handler.on_dynamic_width(id);
2243
2262
  }
2244
2263
 
2245
- FMT_CONSTEXPR void on_error(const char* message) {
2264
+ FMT_CONSTEXPR void on_error(std::string message) {
2246
2265
  handler.on_error(message);
2247
2266
  }
2248
2267
 
@@ -2259,7 +2278,7 @@ template <typename SpecHandler, typename Char> struct precision_adapter {
2259
2278
  handler.on_dynamic_precision(id);
2260
2279
  }
2261
2280
 
2262
- FMT_CONSTEXPR void on_error(const char* message) {
2281
+ FMT_CONSTEXPR void on_error(std::string message) {
2263
2282
  handler.on_error(message);
2264
2283
  }
2265
2284
 
@@ -2370,6 +2389,24 @@ FMT_CONSTEXPR const Char* parse_format_specs(const Char* begin, const Char* end,
2370
2389
  handler.on_space();
2371
2390
  ++begin;
2372
2391
  break;
2392
+ case ',':
2393
+ handler.on_comma();
2394
+ ++begin;
2395
+ break;
2396
+ case '_':
2397
+ handler.on_underscore();
2398
+ ++begin;
2399
+ break;
2400
+ case '\'':
2401
+ handler.on_single_quote();
2402
+ ++begin;
2403
+ break;
2404
+ case 't':
2405
+ ++begin;
2406
+ if (begin == end) return begin;
2407
+ handler.on_thousands(*begin);
2408
+ ++begin;
2409
+ break;
2373
2410
  }
2374
2411
  if (begin == end) return begin;
2375
2412
 
@@ -2420,7 +2457,7 @@ template <typename Handler, typename Char> struct id_adapter {
2420
2457
  FMT_CONSTEXPR void operator()(basic_string_view<Char> id) {
2421
2458
  handler.on_arg_id(id);
2422
2459
  }
2423
- FMT_CONSTEXPR void on_error(const char* message) {
2460
+ FMT_CONSTEXPR void on_error(std::string message) {
2424
2461
  handler.on_error(message);
2425
2462
  }
2426
2463
  Handler& handler;
@@ -2524,7 +2561,7 @@ class format_string_checker {
2524
2561
  return arg_id_ < num_args ? parse_funcs_[arg_id_](context_) : begin;
2525
2562
  }
2526
2563
 
2527
- FMT_CONSTEXPR void on_error(const char* message) {
2564
+ FMT_CONSTEXPR void on_error(std::string message) {
2528
2565
  context_.on_error(message);
2529
2566
  }
2530
2567
 
@@ -2889,7 +2926,7 @@ typename basic_format_context<Range, Char>::format_arg
2889
2926
  basic_format_context<Range, Char>::arg(basic_string_view<char_type> name) {
2890
2927
  map_.init(args_);
2891
2928
  format_arg arg = map_.find(name);
2892
- if (arg.type() == internal::none_type) this->on_error("argument not found");
2929
+ if (arg.type() == internal::none_type) this->on_error("Argument with name \"" + name.to_string() + "\" not found, did you mean to use it as a format specifier (e.g. {:" + name.to_string() + "}");
2893
2930
  return arg;
2894
2931
  }
2895
2932
 
@@ -363,7 +363,7 @@ template <typename OutputIt, typename Char> class basic_printf_context {
363
363
 
364
364
  basic_format_parse_context<Char>& parse_context() { return parse_ctx_; }
365
365
 
366
- FMT_CONSTEXPR void on_error(const char* message) {
366
+ FMT_CONSTEXPR void on_error(std::string message) {
367
367
  parse_ctx_.on_error(message);
368
368
  }
369
369
 
@@ -393,6 +393,15 @@ void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
393
393
  case '#':
394
394
  specs.alt = true;
395
395
  break;
396
+ case ',':
397
+ specs.thousands = ',';
398
+ break;
399
+ case '\'':
400
+ specs.thousands = '\'';
401
+ break;
402
+ case '_':
403
+ specs.thousands = '_';
404
+ break;
396
405
  default:
397
406
  return;
398
407
  }
@@ -472,6 +481,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
472
481
  if (arg_index == 0) on_error("argument index out of range");
473
482
 
474
483
  // Parse precision.
484
+ bool empty_precision = false;
475
485
  if (it != end && *it == '.') {
476
486
  ++it;
477
487
  c = it != end ? *it : 0;
@@ -484,6 +494,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
484
494
  static_cast<int>(visit_format_arg(internal::printf_precision_handler(), get_arg()));
485
495
  } else {
486
496
  specs.precision = 0;
497
+ empty_precision = true;
487
498
  }
488
499
  }
489
500
 
@@ -554,6 +565,9 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
554
565
  break;
555
566
  }
556
567
  }
568
+ if (specs.type == 'd' && empty_precision) {
569
+ specs.thousands = '.';
570
+ }
557
571
 
558
572
  start = it;
559
573
 
@@ -1171,6 +1171,7 @@ typedef struct PGPivot {
1171
1171
  PGList *pivot_columns; /* The column names to pivot on */
1172
1172
  PGList *unpivot_columns;/* The column names to unpivot */
1173
1173
  PGList *pivot_value; /* The set of pivot values */
1174
+ PGNode *subquery; /* Subquery to fetch valid pivot values (if any) */
1174
1175
  char *pivot_enum; /* The enum to fetch the unique values from */
1175
1176
  } PGPivot;
1176
1177