duckdb 0.8.2-dev5080.0 → 0.8.2-dev5154.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 (38) hide show
  1. package/package.json +1 -1
  2. package/src/duckdb/extension/icu/icu-dateadd.cpp +11 -19
  3. package/src/duckdb/extension/icu/icu-datepart.cpp +44 -53
  4. package/src/duckdb/extension/icu/icu-datesub.cpp +10 -15
  5. package/src/duckdb/extension/icu/icu-datetrunc.cpp +6 -8
  6. package/src/duckdb/extension/icu/icu-list-range.cpp +6 -8
  7. package/src/duckdb/extension/icu/icu-makedate.cpp +8 -10
  8. package/src/duckdb/extension/icu/icu-strptime.cpp +30 -32
  9. package/src/duckdb/extension/icu/icu-table-range.cpp +6 -9
  10. package/src/duckdb/extension/icu/icu-timebucket.cpp +5 -7
  11. package/src/duckdb/extension/icu/icu-timezone.cpp +18 -29
  12. package/src/duckdb/extension/icu/icu_extension.cpp +18 -25
  13. package/src/duckdb/extension/icu/include/icu-dateadd.hpp +1 -1
  14. package/src/duckdb/extension/icu/include/icu-datepart.hpp +1 -1
  15. package/src/duckdb/extension/icu/include/icu-datesub.hpp +1 -1
  16. package/src/duckdb/extension/icu/include/icu-datetrunc.hpp +1 -1
  17. package/src/duckdb/extension/icu/include/icu-list-range.hpp +1 -1
  18. package/src/duckdb/extension/icu/include/icu-makedate.hpp +1 -1
  19. package/src/duckdb/extension/icu/include/icu-strptime.hpp +1 -1
  20. package/src/duckdb/extension/icu/include/icu-table-range.hpp +1 -1
  21. package/src/duckdb/extension/icu/include/icu-timebucket.hpp +1 -1
  22. package/src/duckdb/extension/icu/include/icu-timezone.hpp +1 -1
  23. package/src/duckdb/extension/json/json_functions/read_json.cpp +15 -0
  24. package/src/duckdb/src/catalog/catalog.cpp +4 -0
  25. package/src/duckdb/src/core_functions/aggregate/holistic/quantile.cpp +75 -27
  26. package/src/duckdb/src/core_functions/function_list.cpp +1 -1
  27. package/src/duckdb/src/core_functions/scalar/struct/struct_pack.cpp +22 -18
  28. package/src/duckdb/src/execution/operator/schema/physical_attach.cpp +4 -1
  29. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  30. package/src/duckdb/src/include/duckdb/core_functions/scalar/struct_functions.hpp +5 -2
  31. package/src/duckdb/src/include/duckdb/main/config.hpp +3 -0
  32. package/src/duckdb/src/include/duckdb/main/extension_entries.hpp +26 -0
  33. package/src/duckdb/src/include/duckdb/main/extension_util.hpp +14 -0
  34. package/src/duckdb/src/include/duckdb/planner/extension_callback.hpp +26 -0
  35. package/src/duckdb/src/main/database.cpp +6 -0
  36. package/src/duckdb/src/main/extension/extension_util.cpp +56 -0
  37. package/src/duckdb/src/main/settings/settings.cpp +4 -0
  38. package/src/duckdb/src/storage/single_file_block_manager.cpp +11 -0
@@ -2,6 +2,7 @@
2
2
  #include "duckdb/common/types/time.hpp"
3
3
  #include "duckdb/common/types/timestamp.hpp"
4
4
  #include "duckdb/function/cast/cast_function_set.hpp"
5
+ #include "duckdb/main/extension_util.hpp"
5
6
  #include "duckdb/parser/parsed_data/create_scalar_function_info.hpp"
6
7
  #include "duckdb/parser/parsed_data/create_table_function_info.hpp"
7
8
  #include "include/icu-datefunc.hpp"
@@ -143,8 +144,8 @@ struct ICUFromNaiveTimestamp : public ICUDateFunc {
143
144
  return BoundCastInfo(CastFromNaive, std::move(cast_data));
144
145
  }
145
146
 
146
- static void AddCasts(ClientContext &context) {
147
- auto &config = DBConfig::GetConfig(context);
147
+ static void AddCasts(DatabaseInstance &db) {
148
+ auto &config = DBConfig::GetConfig(db);
148
149
  auto &casts = config.GetCastFunctions();
149
150
 
150
151
  casts.RegisterCastFunction(LogicalType::TIMESTAMP, LogicalType::TIMESTAMP_TZ, BindCastFromNaive);
@@ -206,8 +207,8 @@ struct ICUToNaiveTimestamp : public ICUDateFunc {
206
207
  return BoundCastInfo(CastToNaive, std::move(cast_data));
207
208
  }
208
209
 
209
- static void AddCasts(ClientContext &context) {
210
- auto &config = DBConfig::GetConfig(context);
210
+ static void AddCasts(DatabaseInstance &db) {
211
+ auto &config = DBConfig::GetConfig(db);
211
212
  auto &casts = config.GetCastFunctions();
212
213
 
213
214
  casts.RegisterCastFunction(LogicalType::TIMESTAMP_TZ, LogicalType::TIMESTAMP, BindCastToNaive);
@@ -262,18 +263,14 @@ struct ICULocalTimestampFunc : public ICUDateFunc {
262
263
  rdata[0] = GetLocalTimestamp(state);
263
264
  }
264
265
 
265
- static void AddFunction(const string &name, ClientContext &context) {
266
+ static void AddFunction(const string &name, DatabaseInstance &db) {
266
267
  ScalarFunctionSet set(name);
267
268
  set.AddFunction(ScalarFunction({}, LogicalType::TIMESTAMP, Execute, BindNow));
268
-
269
- CreateScalarFunctionInfo func_info(set);
270
- auto &catalog = Catalog::GetSystemCatalog(context);
271
- catalog.AddFunction(context, func_info);
269
+ ExtensionUtil::RegisterFunction(db, set);
272
270
  }
273
271
  };
274
272
 
275
273
  struct ICULocalTimeFunc : public ICUDateFunc {
276
-
277
274
  static void Execute(DataChunk &input, ExpressionState &state, Vector &result) {
278
275
  D_ASSERT(input.ColumnCount() == 0);
279
276
  result.SetVectorType(VectorType::CONSTANT_VECTOR);
@@ -282,13 +279,10 @@ struct ICULocalTimeFunc : public ICUDateFunc {
282
279
  rdata[0] = Timestamp::GetTime(local);
283
280
  }
284
281
 
285
- static void AddFunction(const string &name, ClientContext &context) {
282
+ static void AddFunction(const string &name, DatabaseInstance &db) {
286
283
  ScalarFunctionSet set(name);
287
284
  set.AddFunction(ScalarFunction({}, LogicalType::TIME, Execute, ICULocalTimestampFunc::BindNow));
288
-
289
- CreateScalarFunctionInfo func_info(set);
290
- auto &catalog = Catalog::GetSystemCatalog(context);
291
- catalog.AddFunction(context, func_info);
285
+ ExtensionUtil::RegisterFunction(db, set);
292
286
  }
293
287
  };
294
288
 
@@ -326,16 +320,13 @@ struct ICUTimeZoneFunc : public ICUDateFunc {
326
320
  }
327
321
  }
328
322
 
329
- static void AddFunction(const string &name, ClientContext &context) {
323
+ static void AddFunction(const string &name, DatabaseInstance &db) {
330
324
  ScalarFunctionSet set(name);
331
325
  set.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::TIMESTAMP}, LogicalType::TIMESTAMP_TZ,
332
326
  Execute<ICUFromNaiveTimestamp>, Bind));
333
327
  set.AddFunction(ScalarFunction({LogicalType::VARCHAR, LogicalType::TIMESTAMP_TZ}, LogicalType::TIMESTAMP,
334
328
  Execute<ICUToNaiveTimestamp>, Bind));
335
-
336
- CreateScalarFunctionInfo func_info(set);
337
- auto &catalog = Catalog::GetSystemCatalog(context);
338
- catalog.AddFunction(context, func_info);
329
+ ExtensionUtil::AddFunctionOverload(db, set);
339
330
  }
340
331
  };
341
332
 
@@ -343,21 +334,19 @@ timestamp_t ICUDateFunc::FromNaive(icu::Calendar *calendar, timestamp_t naive) {
343
334
  return ICUFromNaiveTimestamp::Operation(calendar, naive);
344
335
  }
345
336
 
346
- void RegisterICUTimeZoneFunctions(ClientContext &context) {
337
+ void RegisterICUTimeZoneFunctions(DatabaseInstance &db) {
347
338
  // Table functions
348
- auto &catalog = Catalog::GetSystemCatalog(context);
349
339
  TableFunction tz_names("pg_timezone_names", {}, ICUTimeZoneFunction, ICUTimeZoneBind, ICUTimeZoneInit);
350
- CreateTableFunctionInfo tz_names_info(std::move(tz_names));
351
- catalog.CreateTableFunction(context, tz_names_info);
340
+ ExtensionUtil::RegisterFunction(db, tz_names);
352
341
 
353
342
  // Scalar functions
354
- ICUTimeZoneFunc::AddFunction("timezone", context);
355
- ICULocalTimestampFunc::AddFunction("current_localtimestamp", context);
356
- ICULocalTimeFunc::AddFunction("current_localtime", context);
343
+ ICUTimeZoneFunc::AddFunction("timezone", db);
344
+ ICULocalTimestampFunc::AddFunction("current_localtimestamp", db);
345
+ ICULocalTimeFunc::AddFunction("current_localtime", db);
357
346
 
358
347
  // Casts
359
- ICUFromNaiveTimestamp::AddCasts(context);
360
- ICUToNaiveTimestamp::AddCasts(context);
348
+ ICUFromNaiveTimestamp::AddCasts(db);
349
+ ICUToNaiveTimestamp::AddCasts(db);
361
350
  }
362
351
 
363
352
  } // namespace duckdb
@@ -8,6 +8,7 @@
8
8
  #include "duckdb/main/config.hpp"
9
9
  #include "duckdb/main/connection.hpp"
10
10
  #include "duckdb/main/database.hpp"
11
+ #include "duckdb/main/extension_util.hpp"
11
12
  #include "duckdb/parser/parsed_data/create_collation_info.hpp"
12
13
  #include "duckdb/parser/parsed_data/create_scalar_function_info.hpp"
13
14
  #include "duckdb/parser/parsed_data/create_table_function_info.hpp"
@@ -220,11 +221,9 @@ static void SetICUCalendar(ClientContext &context, SetScope scope, Value &parame
220
221
  }
221
222
  }
222
223
 
223
- void IcuExtension::Load(DuckDB &db) {
224
- Connection con(db);
225
- con.BeginTransaction();
226
-
227
- auto &catalog = Catalog::GetSystemCatalog(*con.context);
224
+ void IcuExtension::Load(DuckDB &ddb) {
225
+ auto &db = *ddb.instance;
226
+ auto &catalog = Catalog::GetSystemCatalog(db);
228
227
 
229
228
  // iterate over all the collations
230
229
  int32_t count;
@@ -241,17 +240,14 @@ void IcuExtension::Load(DuckDB &db) {
241
240
  collation = StringUtil::Lower(collation);
242
241
 
243
242
  CreateCollationInfo info(collation, GetICUFunction(collation), false, true);
244
- info.on_conflict = OnCreateConflict::IGNORE_ON_CONFLICT;
245
- catalog.CreateCollation(*con.context, info);
243
+ ExtensionUtil::RegisterCollation(db, info);
246
244
  }
247
245
  ScalarFunction sort_key("icu_sort_key", {LogicalType::VARCHAR, LogicalType::VARCHAR}, LogicalType::VARCHAR,
248
246
  ICUCollateFunction, ICUSortKeyBind);
249
-
250
- CreateScalarFunctionInfo sort_key_info(std::move(sort_key));
251
- catalog.CreateFunction(*con.context, sort_key_info);
247
+ ExtensionUtil::RegisterFunction(db, sort_key);
252
248
 
253
249
  // Time Zones
254
- auto &config = DBConfig::GetConfig(*db.instance);
250
+ auto &config = DBConfig::GetConfig(db);
255
251
  duckdb::unique_ptr<icu::TimeZone> tz(icu::TimeZone::createDefault());
256
252
  icu::UnicodeString tz_id;
257
253
  std::string tz_string;
@@ -259,16 +255,16 @@ void IcuExtension::Load(DuckDB &db) {
259
255
  config.AddExtensionOption("TimeZone", "The current time zone", LogicalType::VARCHAR, Value(tz_string),
260
256
  SetICUTimeZone);
261
257
 
262
- RegisterICUDateAddFunctions(*con.context);
263
- RegisterICUDatePartFunctions(*con.context);
264
- RegisterICUDateSubFunctions(*con.context);
265
- RegisterICUDateTruncFunctions(*con.context);
266
- RegisterICUMakeDateFunctions(*con.context);
267
- RegisterICUTableRangeFunctions(*con.context);
268
- RegisterICUListRangeFunctions(*con.context);
269
- RegisterICUStrptimeFunctions(*con.context);
270
- RegisterICUTimeBucketFunctions(*con.context);
271
- RegisterICUTimeZoneFunctions(*con.context);
258
+ RegisterICUDateAddFunctions(db);
259
+ RegisterICUDatePartFunctions(db);
260
+ RegisterICUDateSubFunctions(db);
261
+ RegisterICUDateTruncFunctions(db);
262
+ RegisterICUMakeDateFunctions(db);
263
+ RegisterICUTableRangeFunctions(db);
264
+ RegisterICUListRangeFunctions(db);
265
+ RegisterICUStrptimeFunctions(db);
266
+ RegisterICUTimeBucketFunctions(db);
267
+ RegisterICUTimeZoneFunctions(db);
272
268
 
273
269
  // Calendars
274
270
  UErrorCode status = U_ZERO_ERROR;
@@ -277,10 +273,7 @@ void IcuExtension::Load(DuckDB &db) {
277
273
  SetICUCalendar);
278
274
 
279
275
  TableFunction cal_names("icu_calendar_names", {}, ICUCalendarFunction, ICUCalendarBind, ICUCalendarInit);
280
- CreateTableFunctionInfo cal_names_info(std::move(cal_names));
281
- catalog.CreateTableFunction(*con.context, cal_names_info);
282
-
283
- con.Commit();
276
+ ExtensionUtil::RegisterFunction(db, cal_names);
284
277
  }
285
278
 
286
279
  std::string IcuExtension::Name() {
@@ -12,6 +12,6 @@
12
12
 
13
13
  namespace duckdb {
14
14
 
15
- void RegisterICUDateAddFunctions(ClientContext &context);
15
+ void RegisterICUDateAddFunctions(DatabaseInstance &db);
16
16
 
17
17
  } // namespace duckdb
@@ -12,6 +12,6 @@
12
12
 
13
13
  namespace duckdb {
14
14
 
15
- void RegisterICUDatePartFunctions(ClientContext &context);
15
+ void RegisterICUDatePartFunctions(DatabaseInstance &db);
16
16
 
17
17
  } // namespace duckdb
@@ -12,6 +12,6 @@
12
12
 
13
13
  namespace duckdb {
14
14
 
15
- void RegisterICUDateSubFunctions(ClientContext &context);
15
+ void RegisterICUDateSubFunctions(DatabaseInstance &db);
16
16
 
17
17
  } // namespace duckdb
@@ -12,6 +12,6 @@
12
12
 
13
13
  namespace duckdb {
14
14
 
15
- void RegisterICUDateTruncFunctions(ClientContext &context);
15
+ void RegisterICUDateTruncFunctions(DatabaseInstance &db);
16
16
 
17
17
  } // namespace duckdb
@@ -12,6 +12,6 @@
12
12
 
13
13
  namespace duckdb {
14
14
 
15
- void RegisterICUListRangeFunctions(ClientContext &context);
15
+ void RegisterICUListRangeFunctions(DatabaseInstance &db);
16
16
 
17
17
  } // namespace duckdb
@@ -12,6 +12,6 @@
12
12
 
13
13
  namespace duckdb {
14
14
 
15
- void RegisterICUMakeDateFunctions(ClientContext &context);
15
+ void RegisterICUMakeDateFunctions(DatabaseInstance &db);
16
16
 
17
17
  } // namespace duckdb
@@ -12,6 +12,6 @@
12
12
 
13
13
  namespace duckdb {
14
14
 
15
- void RegisterICUStrptimeFunctions(ClientContext &context);
15
+ void RegisterICUStrptimeFunctions(DatabaseInstance &db);
16
16
 
17
17
  } // namespace duckdb
@@ -12,6 +12,6 @@
12
12
 
13
13
  namespace duckdb {
14
14
 
15
- void RegisterICUTableRangeFunctions(ClientContext &context);
15
+ void RegisterICUTableRangeFunctions(DatabaseInstance &db);
16
16
 
17
17
  } // namespace duckdb
@@ -12,6 +12,6 @@
12
12
 
13
13
  namespace duckdb {
14
14
 
15
- void RegisterICUTimeBucketFunctions(ClientContext &context);
15
+ void RegisterICUTimeBucketFunctions(DatabaseInstance &db);
16
16
 
17
17
  } // namespace duckdb
@@ -12,6 +12,6 @@
12
12
 
13
13
  namespace duckdb {
14
14
 
15
- void RegisterICUTimeZoneFunctions(ClientContext &context);
15
+ void RegisterICUTimeZoneFunctions(DatabaseInstance &db);
16
16
 
17
17
  } // namespace duckdb
@@ -229,6 +229,21 @@ unique_ptr<FunctionData> ReadJSONBind(ClientContext &context, TableFunctionBindI
229
229
  transform_options.error_unknown_key = bind_data->auto_detect && !bind_data->ignore_errors;
230
230
  transform_options.delay_error = true;
231
231
 
232
+ if (bind_data->auto_detect) {
233
+ // JSON may contain columns such as "id" and "Id", which are duplicates for us due to case-insensitivity
234
+ // We rename them so we can parse the file anyway. Note that we can't change bind_data->names,
235
+ // because the JSON reader gets columns by exact name, not position
236
+ case_insensitive_map_t<idx_t> name_count_map;
237
+ for (auto &name : names) {
238
+ auto it = name_count_map.find(name);
239
+ if (it == name_count_map.end()) {
240
+ name_count_map[name] = 1;
241
+ } else {
242
+ name = StringUtil::Format("%s_%llu", name, it->second++);
243
+ }
244
+ }
245
+ }
246
+
232
247
  return std::move(bind_data);
233
248
  }
234
249
 
@@ -479,6 +479,8 @@ bool Catalog::AutoLoadExtensionByCatalogEntry(ClientContext &context, CatalogTyp
479
479
  extension_name = ExtensionHelper::FindExtensionInEntries(entry_name, EXTENSION_COPY_FUNCTIONS);
480
480
  } else if (type == CatalogType::TYPE_ENTRY) {
481
481
  extension_name = ExtensionHelper::FindExtensionInEntries(entry_name, EXTENSION_TYPES);
482
+ } else if (type == CatalogType::COLLATION_ENTRY) {
483
+ extension_name = ExtensionHelper::FindExtensionInEntries(entry_name, EXTENSION_COLLATIONS);
482
484
  }
483
485
 
484
486
  if (!extension_name.empty() && ExtensionHelper::CanAutoloadExtension(extension_name)) {
@@ -536,6 +538,8 @@ CatalogException Catalog::CreateMissingEntryException(ClientContext &context, co
536
538
  extension_name = ExtensionHelper::FindExtensionInEntries(entry_name, EXTENSION_TYPES);
537
539
  } else if (type == CatalogType::COPY_FUNCTION_ENTRY) {
538
540
  extension_name = ExtensionHelper::FindExtensionInEntries(entry_name, EXTENSION_COPY_FUNCTIONS);
541
+ } else if (type == CatalogType::COLLATION_ENTRY) {
542
+ extension_name = ExtensionHelper::FindExtensionInEntries(entry_name, EXTENSION_COLLATIONS);
539
543
  }
540
544
 
541
545
  // if we found an extension that can handle this catalog entry, create an error hinting the user
@@ -288,12 +288,40 @@ struct QuantileCompare {
288
288
  }
289
289
  };
290
290
 
291
+ // Avoid using naked Values in inner loops...
292
+ struct QuantileValue {
293
+ explicit QuantileValue(const Value &v) : val(v), dbl(v.GetValue<double>()) {
294
+ const auto &type = val.type();
295
+ switch (type.id()) {
296
+ case LogicalTypeId::DECIMAL: {
297
+ integral = IntegralValue::Get(v);
298
+ scaling = Hugeint::POWERS_OF_TEN[DecimalType::GetScale(type)];
299
+ break;
300
+ }
301
+ default:
302
+ break;
303
+ }
304
+ }
305
+
306
+ Value val;
307
+
308
+ // DOUBLE
309
+ double dbl;
310
+
311
+ // DECIMAL
312
+ hugeint_t integral;
313
+ hugeint_t scaling;
314
+ };
315
+
316
+ bool operator==(const QuantileValue &x, const QuantileValue &y) {
317
+ return x.val == y.val;
318
+ }
319
+
291
320
  // Continuous interpolation
292
321
  template <bool DISCRETE>
293
322
  struct Interpolator {
294
- Interpolator(const Value &q, const idx_t n_p, const bool desc_p)
295
- : desc(desc_p), RN((double)(n_p - 1) * q.GetValue<double>()), FRN(floor(RN)), CRN(ceil(RN)), begin(0),
296
- end(n_p) {
323
+ Interpolator(const QuantileValue &q, const idx_t n_p, const bool desc_p)
324
+ : desc(desc_p), RN((double)(n_p - 1) * q.dbl), FRN(floor(RN)), CRN(ceil(RN)), begin(0), end(n_p) {
297
325
  }
298
326
 
299
327
  template <class INPUT_TYPE, class TARGET_TYPE, typename ACCESSOR = QuantileDirect<INPUT_TYPE>>
@@ -336,21 +364,20 @@ struct Interpolator {
336
364
  // Discrete "interpolation"
337
365
  template <>
338
366
  struct Interpolator<true> {
339
- static inline idx_t Index(const Value &q, const idx_t n) {
367
+ static inline idx_t Index(const QuantileValue &q, const idx_t n) {
340
368
  idx_t floored;
341
- const auto &type = q.type();
342
- switch (type.id()) {
369
+ switch (q.val.type().id()) {
343
370
  case LogicalTypeId::DECIMAL: {
344
371
  // Integer arithmetic for accuracy
345
- const auto integral = IntegralValue::Get(q);
346
- const auto scaling = Hugeint::POWERS_OF_TEN[DecimalType::GetScale(type)];
372
+ const auto integral = q.integral;
373
+ const auto scaling = q.scaling;
347
374
  const auto scaled_q = DecimalMultiplyOverflowCheck::Operation<hugeint_t, hugeint_t, hugeint_t>(n, integral);
348
375
  const auto scaled_n = DecimalMultiplyOverflowCheck::Operation<hugeint_t, hugeint_t, hugeint_t>(n, scaling);
349
376
  floored = Cast::Operation<hugeint_t, idx_t>((scaled_n - scaled_q) / scaling);
350
377
  break;
351
378
  }
352
379
  default:
353
- const auto scaled_q = (double)(n * q.GetValue<double>());
380
+ const auto scaled_q = (double)(n * q.dbl);
354
381
  floored = floor(n - scaled_q);
355
382
  break;
356
383
  }
@@ -358,7 +385,7 @@ struct Interpolator<true> {
358
385
  return MaxValue<idx_t>(1, n - floored) - 1;
359
386
  }
360
387
 
361
- Interpolator(const Value &q, const idx_t n_p, bool desc_p)
388
+ Interpolator(const QuantileValue &q, const idx_t n_p, bool desc_p)
362
389
  : desc(desc_p), FRN(Index(q, n_p)), CRN(FRN), begin(0), end(n_p) {
363
390
  }
364
391
 
@@ -420,17 +447,18 @@ struct QuantileBindData : public FunctionData {
420
447
  }
421
448
 
422
449
  explicit QuantileBindData(const Value &quantile_p)
423
- : quantiles(1, QuantileAbs(quantile_p)), order(1, 0), desc(quantile_p < 0) {
450
+ : quantiles(1, QuantileValue(QuantileAbs(quantile_p))), order(1, 0), desc(quantile_p < 0) {
424
451
  }
425
452
 
426
453
  explicit QuantileBindData(const vector<Value> &quantiles_p) {
454
+ vector<Value> normalised;
427
455
  size_t pos = 0;
428
456
  size_t neg = 0;
429
457
  for (idx_t i = 0; i < quantiles_p.size(); ++i) {
430
458
  const auto &q = quantiles_p[i];
431
459
  pos += (q > 0);
432
460
  neg += (q < 0);
433
- quantiles.emplace_back(QuantileAbs(q));
461
+ normalised.emplace_back(QuantileAbs(q));
434
462
  order.push_back(i);
435
463
  }
436
464
  if (pos && neg) {
@@ -438,8 +466,12 @@ struct QuantileBindData : public FunctionData {
438
466
  }
439
467
  desc = (neg > 0);
440
468
 
441
- IndirectLess<Value> lt(quantiles.data());
469
+ IndirectLess<Value> lt(normalised.data());
442
470
  std::sort(order.begin(), order.end(), lt);
471
+
472
+ for (const auto &q : normalised) {
473
+ quantiles.emplace_back(QuantileValue(q));
474
+ }
443
475
  }
444
476
 
445
477
  QuantileBindData(const QuantileBindData &other) : order(other.order), desc(other.desc) {
@@ -460,16 +492,24 @@ struct QuantileBindData : public FunctionData {
460
492
  static void Serialize(Serializer &serializer, const optional_ptr<FunctionData> bind_data_p,
461
493
  const AggregateFunction &function) {
462
494
  auto &bind_data = bind_data_p->Cast<QuantileBindData>();
463
- serializer.WriteProperty(100, "quantiles", bind_data.quantiles);
495
+ vector<Value> raw;
496
+ for (const auto &q : bind_data.quantiles) {
497
+ raw.emplace_back(q.val);
498
+ }
499
+ serializer.WriteProperty(100, "quantiles", raw);
464
500
  serializer.WriteProperty(101, "order", bind_data.order);
465
501
  serializer.WriteProperty(102, "desc", bind_data.desc);
466
502
  }
467
503
 
468
504
  static unique_ptr<FunctionData> Deserialize(Deserializer &deserializer, AggregateFunction &function) {
469
505
  auto result = make_uniq<QuantileBindData>();
470
- deserializer.ReadProperty(100, "quantiles", result->quantiles);
506
+ vector<Value> raw;
507
+ deserializer.ReadProperty(100, "quantiles", raw);
471
508
  deserializer.ReadProperty(101, "order", result->order);
472
509
  deserializer.ReadProperty(102, "desc", result->desc);
510
+ for (const auto &r : raw) {
511
+ result->quantiles.emplace_back(QuantileValue(r));
512
+ }
473
513
  return std::move(result);
474
514
  }
475
515
 
@@ -478,7 +518,7 @@ struct QuantileBindData : public FunctionData {
478
518
  throw NotImplementedException("FIXME: serializing quantiles with decimals is not supported right now");
479
519
  }
480
520
 
481
- vector<Value> quantiles;
521
+ vector<QuantileValue> quantiles;
482
522
  vector<idx_t> order;
483
523
  bool desc;
484
524
  };
@@ -566,7 +606,7 @@ struct QuantileScalarOperation : public QuantileOperation {
566
606
  auto &bind_data = aggr_input_data.bind_data->Cast<QuantileBindData>();
567
607
 
568
608
  // Find the two positions needed
569
- const auto q = bind_data.quantiles[0];
609
+ const auto &q = bind_data.quantiles[0];
570
610
 
571
611
  bool replace = false;
572
612
  if (frame.start == prev.start + 1 && frame.end == prev.end + 1) {
@@ -1041,7 +1081,11 @@ struct MedianAbsoluteDeviationOperation : public QuantileOperation {
1041
1081
  return;
1042
1082
  }
1043
1083
  using SAVE_TYPE = typename STATE::SaveType;
1044
- Interpolator<false> interp(0.5, state.v.size(), false);
1084
+ D_ASSERT(finalize_data.input.bind_data);
1085
+ auto &bind_data = finalize_data.input.bind_data->Cast<QuantileBindData>();
1086
+ D_ASSERT(bind_data.quantiles.size() == 1);
1087
+ const auto &q = bind_data.quantiles[0];
1088
+ Interpolator<false> interp(q, state.v.size(), false);
1045
1089
  const auto med = interp.template Operation<SAVE_TYPE, MEDIAN_TYPE>(state.v.data(), finalize_data.result);
1046
1090
 
1047
1091
  MadAccessor<SAVE_TYPE, T, MEDIAN_TYPE> accessor(med);
@@ -1050,8 +1094,8 @@ struct MedianAbsoluteDeviationOperation : public QuantileOperation {
1050
1094
 
1051
1095
  template <class STATE, class INPUT_TYPE, class RESULT_TYPE>
1052
1096
  static void Window(const INPUT_TYPE *data, const ValidityMask &fmask, const ValidityMask &dmask,
1053
- AggregateInputData &, STATE &state, const FrameBounds &frame, const FrameBounds &prev,
1054
- Vector &result, idx_t ridx, idx_t bias) {
1097
+ AggregateInputData &aggr_input_data, STATE &state, const FrameBounds &frame,
1098
+ const FrameBounds &prev, Vector &result, idx_t ridx, idx_t bias) {
1055
1099
  auto rdata = FlatVector::GetData<RESULT_TYPE>(result);
1056
1100
  auto &rmask = FlatVector::Validity(result);
1057
1101
 
@@ -1079,7 +1123,10 @@ struct MedianAbsoluteDeviationOperation : public QuantileOperation {
1079
1123
  std::partition(index2, index2 + state.pos, included);
1080
1124
 
1081
1125
  // Find the two positions needed for the median
1082
- const float q = 0.5;
1126
+ D_ASSERT(aggr_input_data.bind_data);
1127
+ auto &bind_data = aggr_input_data.bind_data->Cast<QuantileBindData>();
1128
+ D_ASSERT(bind_data.quantiles.size() == 1);
1129
+ const auto &q = bind_data.quantiles[0];
1083
1130
 
1084
1131
  bool replace = false;
1085
1132
  if (frame.start == prev.start + 1 && frame.end == prev.end + 1) {
@@ -1124,12 +1171,18 @@ struct MedianAbsoluteDeviationOperation : public QuantileOperation {
1124
1171
  }
1125
1172
  };
1126
1173
 
1174
+ unique_ptr<FunctionData> BindMedian(ClientContext &context, AggregateFunction &function,
1175
+ vector<unique_ptr<Expression>> &arguments) {
1176
+ return make_uniq<QuantileBindData>(Value::DECIMAL(int16_t(5), 2, 1));
1177
+ }
1178
+
1127
1179
  template <typename INPUT_TYPE, typename MEDIAN_TYPE, typename TARGET_TYPE>
1128
1180
  AggregateFunction GetTypedMedianAbsoluteDeviationAggregateFunction(const LogicalType &input_type,
1129
1181
  const LogicalType &target_type) {
1130
1182
  using STATE = QuantileState<INPUT_TYPE>;
1131
1183
  using OP = MedianAbsoluteDeviationOperation<MEDIAN_TYPE>;
1132
1184
  auto fun = AggregateFunction::UnaryAggregateDestructor<STATE, INPUT_TYPE, TARGET_TYPE, OP>(input_type, target_type);
1185
+ fun.bind = BindMedian;
1133
1186
  fun.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT;
1134
1187
  fun.window = AggregateFunction::UnaryWindow<STATE, INPUT_TYPE, TARGET_TYPE, OP>;
1135
1188
  return fun;
@@ -1173,11 +1226,6 @@ AggregateFunction GetMedianAbsoluteDeviationAggregateFunction(const LogicalType
1173
1226
  }
1174
1227
  }
1175
1228
 
1176
- unique_ptr<FunctionData> BindMedian(ClientContext &context, AggregateFunction &function,
1177
- vector<unique_ptr<Expression>> &arguments) {
1178
- return make_uniq<QuantileBindData>(Value::DECIMAL(int16_t(5), 2, 1));
1179
- }
1180
-
1181
1229
  unique_ptr<FunctionData> BindMedianDecimal(ClientContext &context, AggregateFunction &function,
1182
1230
  vector<unique_ptr<Expression>> &arguments) {
1183
1231
  auto bind_data = BindMedian(context, function, arguments);
@@ -1195,7 +1243,7 @@ unique_ptr<FunctionData> BindMedianAbsoluteDeviationDecimal(ClientContext &conte
1195
1243
  function = GetMedianAbsoluteDeviationAggregateFunction(arguments[0]->return_type);
1196
1244
  function.name = "mad";
1197
1245
  function.order_dependent = AggregateOrderDependent::NOT_ORDER_DEPENDENT;
1198
- return nullptr;
1246
+ return BindMedian(context, function, arguments);
1199
1247
  }
1200
1248
 
1201
1249
  static const Value &CheckQuantile(const Value &quantile_val) {
@@ -281,7 +281,7 @@ static StaticFunctionDefinition internal_functions[] = {
281
281
  DUCKDB_SCALAR_FUNCTION(RightFun),
282
282
  DUCKDB_SCALAR_FUNCTION(RightGraphemeFun),
283
283
  DUCKDB_SCALAR_FUNCTION_SET(RoundFun),
284
- DUCKDB_SCALAR_FUNCTION_ALIAS(RowFun),
284
+ DUCKDB_SCALAR_FUNCTION(RowFun),
285
285
  DUCKDB_SCALAR_FUNCTION(RpadFun),
286
286
  DUCKDB_SCALAR_FUNCTION_SET(RtrimFun),
287
287
  DUCKDB_SCALAR_FUNCTION_SET(SecondsFun),
@@ -30,6 +30,7 @@ static void StructPackFunction(DataChunk &args, ExpressionState &state, Vector &
30
30
  result.Verify(args.size());
31
31
  }
32
32
 
33
+ template <bool IS_STRUCT_PACK>
33
34
  static unique_ptr<FunctionData> StructPackBind(ClientContext &context, ScalarFunction &bound_function,
34
35
  vector<unique_ptr<Expression>> &arguments) {
35
36
  case_insensitive_set_t name_collision_set;
@@ -39,25 +40,20 @@ static unique_ptr<FunctionData> StructPackBind(ClientContext &context, ScalarFun
39
40
  throw Exception("Can't pack nothing into a struct");
40
41
  }
41
42
  child_list_t<LogicalType> struct_children;
42
- bool unnamed = false;
43
43
  for (idx_t i = 0; i < arguments.size(); i++) {
44
44
  auto &child = arguments[i];
45
- if (child->alias.empty()) {
46
- if (bound_function.name == "struct_pack") {
45
+ string alias;
46
+ if (IS_STRUCT_PACK) {
47
+ if (child->alias.empty()) {
47
48
  throw BinderException("Need named argument for struct pack, e.g. STRUCT_PACK(a := b)");
48
- } else {
49
- D_ASSERT(bound_function.name == "row");
50
- if (i > 1) {
51
- D_ASSERT(unnamed);
52
- }
53
- unnamed = true;
54
49
  }
50
+ alias = child->alias;
51
+ if (name_collision_set.find(alias) != name_collision_set.end()) {
52
+ throw BinderException("Duplicate struct entry name \"%s\"", alias);
53
+ }
54
+ name_collision_set.insert(alias);
55
55
  }
56
- if (!child->alias.empty() && name_collision_set.find(child->alias) != name_collision_set.end()) {
57
- throw BinderException("Duplicate struct entry name \"%s\"", child->alias);
58
- }
59
- name_collision_set.insert(child->alias);
60
- struct_children.push_back(make_pair(child->alias, arguments[i]->return_type));
56
+ struct_children.push_back(make_pair(alias, arguments[i]->return_type));
61
57
  }
62
58
 
63
59
  // this is more for completeness reasons
@@ -75,10 +71,10 @@ unique_ptr<BaseStatistics> StructPackStats(ClientContext &context, FunctionStati
75
71
  return struct_stats.ToUnique();
76
72
  }
77
73
 
78
- ScalarFunction StructPackFun::GetFunction() {
79
- // the arguments and return types are actually set in the binder function
80
- ScalarFunction fun("struct_pack", {}, LogicalTypeId::STRUCT, StructPackFunction, StructPackBind, nullptr,
81
- StructPackStats);
74
+ template <bool IS_STRUCT_PACK>
75
+ ScalarFunction GetStructPackFunction() {
76
+ ScalarFunction fun(IS_STRUCT_PACK ? "struct_pack" : "row", {}, LogicalTypeId::STRUCT, StructPackFunction,
77
+ StructPackBind<IS_STRUCT_PACK>, nullptr, StructPackStats);
82
78
  fun.varargs = LogicalType::ANY;
83
79
  fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING;
84
80
  fun.serialize = VariableReturnBindData::Serialize;
@@ -86,4 +82,12 @@ ScalarFunction StructPackFun::GetFunction() {
86
82
  return fun;
87
83
  }
88
84
 
85
+ ScalarFunction StructPackFun::GetFunction() {
86
+ return GetStructPackFunction<true>();
87
+ }
88
+
89
+ ScalarFunction RowFun::GetFunction() {
90
+ return GetStructPackFunction<false>();
91
+ }
92
+
89
93
  } // namespace duckdb
@@ -56,7 +56,10 @@ SourceResultType PhysicalAttach::GetData(ExecutionContext &context, DataChunk &c
56
56
 
57
57
  // if we are loading a database type from an extension - check if that extension is loaded
58
58
  if (!type.empty()) {
59
- if (!db.ExtensionIsLoaded(type)) {
59
+ if (!Catalog::TryAutoLoad(context.client, type)) {
60
+ // FIXME: Here it might be preferrable to use an AutoLoadOrThrow kind of function
61
+ // so that either there will be success or a message to throw, and load will be
62
+ // attempted only once respecting the autoloading options
60
63
  ExtensionHelper::LoadExternalExtension(context.client, type);
61
64
  }
62
65
  }