duckdb 0.8.2-dev2356.0 → 0.8.2-dev2399.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 (27) hide show
  1. package/binding.gyp +7 -7
  2. package/package.json +1 -1
  3. package/src/duckdb/extension/icu/icu-datefunc.cpp +9 -0
  4. package/src/duckdb/extension/icu/icu-datepart.cpp +7 -5
  5. package/src/duckdb/extension/icu/icu-strptime.cpp +1 -20
  6. package/src/duckdb/src/common/types/list_segment.cpp +42 -134
  7. package/src/duckdb/src/common/types/vector.cpp +21 -0
  8. package/src/duckdb/src/core_functions/aggregate/holistic/mode.cpp +5 -7
  9. package/src/duckdb/src/core_functions/aggregate/holistic/quantile.cpp +17 -19
  10. package/src/duckdb/src/core_functions/aggregate/nested/list.cpp +80 -61
  11. package/src/duckdb/src/execution/aggregate_hashtable.cpp +6 -0
  12. package/src/duckdb/src/execution/perfect_aggregate_hashtable.cpp +11 -5
  13. package/src/duckdb/src/execution/window_executor.cpp +18 -20
  14. package/src/duckdb/src/function/aggregate/distributive/count.cpp +2 -2
  15. package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
  16. package/src/duckdb/src/include/duckdb/common/types/list_segment.hpp +9 -11
  17. package/src/duckdb/src/include/duckdb/common/types/vector.hpp +7 -0
  18. package/src/duckdb/src/include/duckdb/common/vector_operations/aggregate_executor.hpp +7 -2
  19. package/src/duckdb/src/include/duckdb/execution/perfect_aggregate_hashtable.hpp +4 -2
  20. package/src/duckdb/src/include/duckdb/execution/window_segment_tree.hpp +0 -2
  21. package/src/duckdb/src/include/duckdb/function/aggregate_function.hpp +0 -1
  22. package/src/duckdb/src/parser/transform/expression/transform_function.cpp +3 -0
  23. package/src/duckdb/src/storage/serialization/serialize_constraint.cpp +2 -2
  24. package/src/duckdb/src/storage/serialization/serialize_create_info.cpp +2 -2
  25. package/src/duckdb/src/storage/serialization/serialize_parse_info.cpp +2 -2
  26. package/src/duckdb/src/storage/serialization/serialize_tableref.cpp +2 -4
  27. package/src/duckdb/ub_extension_icu_third_party_icu_i18n.cpp +6 -6
package/binding.gyp CHANGED
@@ -244,18 +244,18 @@
244
244
  "src/duckdb/third_party/zstd/compress/zstd_lazy.cpp",
245
245
  "src/duckdb/third_party/zstd/compress/zstd_ldm.cpp",
246
246
  "src/duckdb/third_party/zstd/compress/zstd_opt.cpp",
247
- "src/duckdb/extension/icu/./icu_extension.cpp",
248
- "src/duckdb/extension/icu/./icu-datetrunc.cpp",
249
- "src/duckdb/extension/icu/./icu-datepart.cpp",
250
247
  "src/duckdb/extension/icu/./icu-strptime.cpp",
248
+ "src/duckdb/extension/icu/./icu-datepart.cpp",
249
+ "src/duckdb/extension/icu/./icu-datesub.cpp",
251
250
  "src/duckdb/extension/icu/./icu-table-range.cpp",
252
- "src/duckdb/extension/icu/./icu-makedate.cpp",
253
- "src/duckdb/extension/icu/./icu-datefunc.cpp",
254
- "src/duckdb/extension/icu/./icu-list-range.cpp",
251
+ "src/duckdb/extension/icu/./icu-datetrunc.cpp",
255
252
  "src/duckdb/extension/icu/./icu-timebucket.cpp",
256
253
  "src/duckdb/extension/icu/./icu-dateadd.cpp",
254
+ "src/duckdb/extension/icu/./icu-list-range.cpp",
257
255
  "src/duckdb/extension/icu/./icu-timezone.cpp",
258
- "src/duckdb/extension/icu/./icu-datesub.cpp",
256
+ "src/duckdb/extension/icu/./icu-datefunc.cpp",
257
+ "src/duckdb/extension/icu/./icu_extension.cpp",
258
+ "src/duckdb/extension/icu/./icu-makedate.cpp",
259
259
  "src/duckdb/ub_extension_icu_third_party_icu_common.cpp",
260
260
  "src/duckdb/ub_extension_icu_third_party_icu_i18n.cpp",
261
261
  "src/duckdb/extension/icu/third_party/icu/stubdata/stubdata.cpp",
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "duckdb",
3
3
  "main": "./lib/duckdb.js",
4
4
  "types": "./lib/duckdb.d.ts",
5
- "version": "0.8.2-dev2356.0",
5
+ "version": "0.8.2-dev2399.0",
6
6
  "description": "DuckDB node.js API",
7
7
  "gypfile": true,
8
8
  "dependencies": {
@@ -5,6 +5,8 @@
5
5
  #include "duckdb/common/operator/multiply.hpp"
6
6
  #include "duckdb/common/types/timestamp.hpp"
7
7
 
8
+ #include "unicode/ucal.h"
9
+
8
10
  namespace duckdb {
9
11
 
10
12
  ICUDateFunc::BindData::BindData(const BindData &other)
@@ -34,6 +36,13 @@ ICUDateFunc::BindData::BindData(ClientContext &context) {
34
36
  if (U_FAILURE(success)) {
35
37
  throw Exception("Unable to create ICU calendar.");
36
38
  }
39
+
40
+ // Postgres always assumes times are given in the proleptic Gregorian calendar.
41
+ // ICU defaults to the Gregorian change in 1582, so we reset the change to the minimum date
42
+ // so that all dates are proleptic Gregorian.
43
+ // The only error here is if we have a non-Gregorian calendar,
44
+ // and we just ignore that and hope for the best...
45
+ ucal_setGregorianChange((UCalendar *)calendar.get(), U_DATE_MIN, &success); // NOLINT
37
46
  }
38
47
 
39
48
  bool ICUDateFunc::BindData::Equals(const FunctionData &other_p) const {
@@ -109,11 +109,8 @@ struct ICUDatePart : public ICUDateFunc {
109
109
 
110
110
  static int64_t ExtractEpoch(icu::Calendar *calendar, const uint64_t micros) {
111
111
  UErrorCode status = U_ZERO_ERROR;
112
- auto millis = calendar->getTime(status);
113
- millis += ExtractField(calendar, UCAL_ZONE_OFFSET);
114
- millis += ExtractField(calendar, UCAL_DST_OFFSET);
115
112
  // Truncate
116
- return millis / Interval::MSECS_PER_SEC;
113
+ return calendar->getTime(status) / Interval::MSECS_PER_SEC;
117
114
  }
118
115
 
119
116
  static int64_t ExtractTimezone(icu::Calendar *calendar, const uint64_t micros) {
@@ -200,7 +197,12 @@ struct ICUDatePart : public ICUDateFunc {
200
197
 
201
198
  calendar->set(UCAL_DATE, dd);
202
199
 
203
- return Date::EpochToDate(ExtractEpoch(calendar, 0));
200
+ // Offset to UTC
201
+ auto millis = calendar->getTime(status);
202
+ millis += ExtractField(calendar, UCAL_ZONE_OFFSET);
203
+ millis += ExtractField(calendar, UCAL_DST_OFFSET);
204
+
205
+ return Date::EpochToDate(millis / Interval::MSECS_PER_SEC);
204
206
  }
205
207
 
206
208
  static string_t MonthName(icu::Calendar *calendar, const uint64_t micros) {
@@ -273,26 +273,7 @@ struct ICUStrptime : public ICUDateFunc {
273
273
  }
274
274
 
275
275
  // Now get the parts in the given time zone
276
- date_t d;
277
- dtime_t t;
278
- Timestamp::Convert(result, d, t);
279
-
280
- int32_t data[7];
281
- Date::Convert(d, data[0], data[1], data[2]);
282
- calendar->set(UCAL_EXTENDED_YEAR, data[0]); // strptime doesn't understand eras
283
- calendar->set(UCAL_MONTH, data[1] - 1);
284
- calendar->set(UCAL_DATE, data[2]);
285
-
286
- Time::Convert(t, data[3], data[4], data[5], data[6]);
287
- calendar->set(UCAL_HOUR_OF_DAY, data[3]);
288
- calendar->set(UCAL_MINUTE, data[4]);
289
- calendar->set(UCAL_SECOND, data[5]);
290
-
291
- int32_t millis = data[6] / Interval::MICROS_PER_MSEC;
292
- uint64_t micros = data[6] % Interval::MICROS_PER_MSEC;
293
- calendar->set(UCAL_MILLISECOND, millis);
294
-
295
- result = GetTime(calendar, micros);
276
+ result = FromNaive(calendar, result);
296
277
  }
297
278
 
298
279
  return result;
@@ -96,7 +96,7 @@ static uint16_t GetCapacityForNewSegment(uint16_t capacity) {
96
96
  }
97
97
 
98
98
  //===--------------------------------------------------------------------===//
99
- // Create & Destroy
99
+ // Create
100
100
  //===--------------------------------------------------------------------===//
101
101
  template <class T>
102
102
  static ListSegment *CreatePrimitiveSegment(const ListSegmentFunctions &, ArenaAllocator &allocator, uint16_t capacity) {
@@ -174,56 +174,55 @@ static ListSegment *GetSegment(const ListSegmentFunctions &functions, ArenaAlloc
174
174
  // Append
175
175
  //===--------------------------------------------------------------------===//
176
176
  template <class T>
177
- static void WriteDataToPrimitiveSegment(const ListSegmentFunctions &functions, ArenaAllocator &allocator,
178
- ListSegment *segment, Vector &input, idx_t &entry_idx, idx_t &count) {
177
+ static void WriteDataToPrimitiveSegment(const ListSegmentFunctions &, ArenaAllocator &, ListSegment *segment,
178
+ RecursiveUnifiedVectorFormat &input_data, idx_t &entry_idx) {
179
179
 
180
- // get the vector data and the source index of the entry that we want to write
181
- auto input_data = FlatVector::GetData(input);
180
+ auto sel_entry_idx = input_data.unified.sel->get_index(entry_idx);
182
181
 
183
182
  // write null validity
184
183
  auto null_mask = GetNullMask(segment);
185
- auto is_null = FlatVector::IsNull(input, entry_idx);
186
- null_mask[segment->count] = is_null;
184
+ auto valid = input_data.unified.validity.RowIsValid(sel_entry_idx);
185
+ null_mask[segment->count] = !valid;
187
186
 
188
187
  // write value
189
- if (!is_null) {
190
- auto data = GetPrimitiveData<T>(segment);
191
- Store<T>(((T *)input_data)[entry_idx], data_ptr_cast(data + segment->count));
188
+ if (valid) {
189
+ auto segment_data = GetPrimitiveData<T>(segment);
190
+ auto input_data_ptr = UnifiedVectorFormat::GetData<T>(input_data.unified);
191
+ Store<T>(input_data_ptr[sel_entry_idx], data_ptr_cast(segment_data + segment->count));
192
192
  }
193
193
  }
194
194
 
195
195
  static void WriteDataToVarcharSegment(const ListSegmentFunctions &functions, ArenaAllocator &allocator,
196
- ListSegment *segment, Vector &input, idx_t &entry_idx, idx_t &count) {
196
+ ListSegment *segment, RecursiveUnifiedVectorFormat &input_data,
197
+ idx_t &entry_idx) {
197
198
 
198
- // get the vector data and the source index of the entry that we want to write
199
- auto input_data = FlatVector::GetData<string_t>(input);
199
+ auto sel_entry_idx = input_data.unified.sel->get_index(entry_idx);
200
200
 
201
201
  // write null validity
202
202
  auto null_mask = GetNullMask(segment);
203
- auto is_null = FlatVector::IsNull(input, entry_idx);
204
- null_mask[segment->count] = is_null;
203
+ auto valid = input_data.unified.validity.RowIsValid(sel_entry_idx);
204
+ null_mask[segment->count] = !valid;
205
205
 
206
206
  // set the length of this string
207
207
  auto str_length_data = GetListLengthData(segment);
208
208
  uint64_t str_length = 0;
209
209
 
210
210
  // get the string
211
- string_t str_t;
212
- if (!is_null) {
213
- str_t = input_data[entry_idx];
214
- str_length = str_t.GetSize();
211
+ string_t str_entry;
212
+ if (valid) {
213
+ str_entry = UnifiedVectorFormat::GetData<string_t>(input_data.unified)[sel_entry_idx];
214
+ str_length = str_entry.GetSize();
215
215
  }
216
216
 
217
217
  // we can reconstruct the offset from the length
218
218
  Store<uint64_t>(str_length, data_ptr_cast(str_length_data + segment->count));
219
-
220
- if (is_null) {
219
+ if (!valid) {
221
220
  return;
222
221
  }
223
222
 
224
223
  // write the characters to the linked list of child segments
225
224
  auto child_segments = Load<LinkedList>(data_ptr_cast(GetListChildData(segment)));
226
- for (char &c : str_t.GetString()) {
225
+ for (char &c : str_entry.GetString()) {
227
226
  auto child_segment = GetSegment(functions.child_functions.back(), allocator, child_segments);
228
227
  auto data = GetPrimitiveData<char>(child_segment);
229
228
  data[child_segment->count] = c;
@@ -236,37 +235,31 @@ static void WriteDataToVarcharSegment(const ListSegmentFunctions &functions, Are
236
235
  }
237
236
 
238
237
  static void WriteDataToListSegment(const ListSegmentFunctions &functions, ArenaAllocator &allocator,
239
- ListSegment *segment, Vector &input, idx_t &entry_idx, idx_t &count) {
238
+ ListSegment *segment, RecursiveUnifiedVectorFormat &input_data, idx_t &entry_idx) {
240
239
 
241
- // get the vector data and the source index of the entry that we want to write
242
- auto input_data = FlatVector::GetData<list_entry_t>(input);
240
+ auto sel_entry_idx = input_data.unified.sel->get_index(entry_idx);
243
241
 
244
242
  // write null validity
245
243
  auto null_mask = GetNullMask(segment);
246
- auto is_null = FlatVector::IsNull(input, entry_idx);
247
- null_mask[segment->count] = is_null;
244
+ auto valid = input_data.unified.validity.RowIsValid(sel_entry_idx);
245
+ null_mask[segment->count] = !valid;
248
246
 
249
247
  // set the length of this list
250
248
  auto list_length_data = GetListLengthData(segment);
251
249
  uint64_t list_length = 0;
252
250
 
253
- if (!is_null) {
251
+ if (valid) {
254
252
  // get list entry information
255
- auto list_entries = input_data;
256
- const auto &list_entry = list_entries[entry_idx];
253
+ const auto &list_entry = UnifiedVectorFormat::GetData<list_entry_t>(input_data.unified)[sel_entry_idx];
257
254
  list_length = list_entry.length;
258
255
 
259
- // get the child vector and its data
260
- auto lists_size = ListVector::GetListSize(input);
261
- auto &child_vector = ListVector::GetEntry(input);
262
-
263
256
  // loop over the child vector entries and recurse on them
264
257
  auto child_segments = Load<LinkedList>(data_ptr_cast(GetListChildData(segment)));
265
258
  D_ASSERT(functions.child_functions.size() == 1);
266
259
  for (idx_t child_idx = 0; child_idx < list_entry.length; child_idx++) {
267
260
  auto source_idx_child = list_entry.offset + child_idx;
268
- functions.child_functions[0].AppendRow(allocator, child_segments, child_vector, source_idx_child,
269
- lists_size);
261
+ functions.child_functions[0].AppendRow(allocator, child_segments, input_data.children.back(),
262
+ source_idx_child);
270
263
  }
271
264
  // store the updated linked list
272
265
  Store<LinkedList>(child_segments, data_ptr_cast(GetListChildData(segment)));
@@ -276,35 +269,34 @@ static void WriteDataToListSegment(const ListSegmentFunctions &functions, ArenaA
276
269
  }
277
270
 
278
271
  static void WriteDataToStructSegment(const ListSegmentFunctions &functions, ArenaAllocator &allocator,
279
- ListSegment *segment, Vector &input, idx_t &entry_idx, idx_t &count) {
272
+ ListSegment *segment, RecursiveUnifiedVectorFormat &input_data, idx_t &entry_idx) {
273
+
274
+ auto sel_entry_idx = input_data.unified.sel->get_index(entry_idx);
280
275
 
281
276
  // write null validity
282
277
  auto null_mask = GetNullMask(segment);
283
- auto is_null = FlatVector::IsNull(input, entry_idx);
284
- null_mask[segment->count] = is_null;
278
+ auto valid = input_data.unified.validity.RowIsValid(sel_entry_idx);
279
+ null_mask[segment->count] = !valid;
285
280
 
286
281
  // write value
287
- auto &children = StructVector::GetEntries(input);
288
- D_ASSERT(children.size() == functions.child_functions.size());
282
+ D_ASSERT(input_data.children.size() == functions.child_functions.size());
289
283
  auto child_list = GetStructData(segment);
290
284
 
291
285
  // write the data of each of the children of the struct
292
- for (idx_t child_count = 0; child_count < children.size(); child_count++) {
293
- auto child_list_segment = Load<ListSegment *>(data_ptr_cast(child_list + child_count));
294
- auto &child_function = functions.child_functions[child_count];
295
- child_function.write_data(child_function, allocator, child_list_segment, *children[child_count], entry_idx,
296
- count);
286
+ for (idx_t i = 0; i < input_data.children.size(); i++) {
287
+ auto child_list_segment = Load<ListSegment *>(data_ptr_cast(child_list + i));
288
+ auto &child_function = functions.child_functions[i];
289
+ child_function.write_data(child_function, allocator, child_list_segment, input_data.children[i], entry_idx);
297
290
  child_list_segment->count++;
298
291
  }
299
292
  }
300
293
 
301
- void ListSegmentFunctions::AppendRow(ArenaAllocator &allocator, LinkedList &linked_list, Vector &input,
302
- idx_t &entry_idx, idx_t &count) const {
294
+ void ListSegmentFunctions::AppendRow(ArenaAllocator &allocator, LinkedList &linked_list,
295
+ RecursiveUnifiedVectorFormat &input_data, idx_t &entry_idx) const {
303
296
 
304
- D_ASSERT(input.GetVectorType() == VectorType::FLAT_VECTOR);
305
297
  auto &write_data_to_segment = *this;
306
298
  auto segment = GetSegment(write_data_to_segment, allocator, linked_list);
307
- write_data_to_segment.write_data(write_data_to_segment, allocator, segment, input, entry_idx, count);
299
+ write_data_to_segment.write_data(write_data_to_segment, allocator, segment, input_data, entry_idx);
308
300
 
309
301
  linked_list.total_capacity++;
310
302
  segment->count++;
@@ -458,86 +450,6 @@ void ListSegmentFunctions::BuildListVector(const LinkedList &linked_list, Vector
458
450
  }
459
451
  }
460
452
 
461
- //===--------------------------------------------------------------------===//
462
- // Copy
463
- //===--------------------------------------------------------------------===//
464
- template <class T>
465
- static ListSegment *CopyDataFromPrimitiveSegment(const ListSegmentFunctions &, const ListSegment *source,
466
- ArenaAllocator &allocator) {
467
-
468
- auto target = (ListSegment *)AllocatePrimitiveData<T>(allocator, source->capacity);
469
- memcpy(target, source, sizeof(ListSegment) + source->capacity * (sizeof(bool) + sizeof(T)));
470
- target->next = nullptr;
471
- return target;
472
- }
473
-
474
- static ListSegment *CopyDataFromListSegment(const ListSegmentFunctions &functions, const ListSegment *source,
475
- ArenaAllocator &allocator) {
476
-
477
- // create an empty linked list for the child vector of target
478
- auto source_linked_child_list = Load<LinkedList>(const_data_ptr_cast(GetListChildData(source)));
479
-
480
- // create the segment
481
- auto target = reinterpret_cast<ListSegment *>(AllocateListData(allocator, source->capacity));
482
- memcpy(target, source,
483
- sizeof(ListSegment) + source->capacity * (sizeof(bool) + sizeof(uint64_t)) + sizeof(LinkedList));
484
- target->next = nullptr;
485
-
486
- auto target_linked_list = GetListChildData(target);
487
- LinkedList linked_list(source_linked_child_list.total_capacity, nullptr, nullptr);
488
- Store<LinkedList>(linked_list, data_ptr_cast(target_linked_list));
489
-
490
- // recurse to copy the linked child list
491
- auto target_linked_child_list = Load<LinkedList>(data_ptr_cast(GetListChildData(target)));
492
- D_ASSERT(functions.child_functions.size() == 1);
493
- functions.child_functions[0].CopyLinkedList(source_linked_child_list, target_linked_child_list, allocator);
494
-
495
- // store the updated linked list
496
- Store<LinkedList>(target_linked_child_list, data_ptr_cast(GetListChildData(target)));
497
- return target;
498
- }
499
-
500
- static ListSegment *CopyDataFromStructSegment(const ListSegmentFunctions &functions, const ListSegment *source,
501
- ArenaAllocator &allocator) {
502
-
503
- auto source_child_count = functions.child_functions.size();
504
- auto target = reinterpret_cast<ListSegment *>(AllocateStructData(allocator, source->capacity, source_child_count));
505
- memcpy(target, source,
506
- sizeof(ListSegment) + source->capacity * sizeof(bool) + source_child_count * sizeof(ListSegment *));
507
- target->next = nullptr;
508
-
509
- // recurse and copy the children
510
- auto source_child_segments = GetStructData(source);
511
- auto target_child_segments = GetStructData(target);
512
-
513
- for (idx_t i = 0; i < functions.child_functions.size(); i++) {
514
- auto child_function = functions.child_functions[i];
515
- auto source_child_segment = Load<ListSegment *>(const_data_ptr_cast(source_child_segments + i));
516
- auto target_child_segment = child_function.copy_data(child_function, source_child_segment, allocator);
517
- Store<ListSegment *>(target_child_segment, data_ptr_cast(target_child_segments + i));
518
- }
519
- return target;
520
- }
521
-
522
- void ListSegmentFunctions::CopyLinkedList(const LinkedList &source_list, LinkedList &target_list,
523
- ArenaAllocator &allocator) const {
524
- auto &copy_data_from_segment = *this;
525
- auto source_segment = source_list.first_segment;
526
-
527
- while (source_segment) {
528
- auto target_segment = copy_data_from_segment.copy_data(copy_data_from_segment, source_segment, allocator);
529
- source_segment = source_segment->next;
530
-
531
- if (!target_list.first_segment) {
532
- target_list.first_segment = target_segment;
533
- }
534
- if (target_list.last_segment) {
535
- target_list.last_segment->next = target_segment;
536
- }
537
- target_list.last_segment = target_segment;
538
- }
539
- }
540
-
541
453
  //===--------------------------------------------------------------------===//
542
454
  // Functions
543
455
  //===--------------------------------------------------------------------===//
@@ -546,7 +458,6 @@ void SegmentPrimitiveFunction(ListSegmentFunctions &functions) {
546
458
  functions.create_segment = CreatePrimitiveSegment<T>;
547
459
  functions.write_data = WriteDataToPrimitiveSegment<T>;
548
460
  functions.read_data = ReadDataFromPrimitiveSegment<T>;
549
- functions.copy_data = CopyDataFromPrimitiveSegment<T>;
550
461
  }
551
462
 
552
463
  void GetSegmentDataFunctions(ListSegmentFunctions &functions, const LogicalType &type) {
@@ -597,7 +508,6 @@ void GetSegmentDataFunctions(ListSegmentFunctions &functions, const LogicalType
597
508
  functions.create_segment = CreateListSegment;
598
509
  functions.write_data = WriteDataToVarcharSegment;
599
510
  functions.read_data = ReadDataFromVarcharSegment;
600
- functions.copy_data = CopyDataFromListSegment;
601
511
 
602
512
  functions.child_functions.emplace_back();
603
513
  SegmentPrimitiveFunction<char>(functions.child_functions.back());
@@ -607,7 +517,6 @@ void GetSegmentDataFunctions(ListSegmentFunctions &functions, const LogicalType
607
517
  functions.create_segment = CreateListSegment;
608
518
  functions.write_data = WriteDataToListSegment;
609
519
  functions.read_data = ReadDataFromListSegment;
610
- functions.copy_data = CopyDataFromListSegment;
611
520
 
612
521
  // recurse
613
522
  functions.child_functions.emplace_back();
@@ -618,7 +527,6 @@ void GetSegmentDataFunctions(ListSegmentFunctions &functions, const LogicalType
618
527
  functions.create_segment = CreateStructSegment;
619
528
  functions.write_data = WriteDataToStructSegment;
620
529
  functions.read_data = ReadDataFromStructSegment;
621
- functions.copy_data = CopyDataFromStructSegment;
622
530
 
623
531
  // recurse
624
532
  auto child_types = StructType::GetChildTypes(type);
@@ -892,6 +892,27 @@ void Vector::ToUnifiedFormat(idx_t count, UnifiedVectorFormat &format) {
892
892
  }
893
893
  }
894
894
 
895
+ void Vector::RecursiveToUnifiedFormat(Vector &input, idx_t count, RecursiveUnifiedVectorFormat &data) {
896
+
897
+ input.ToUnifiedFormat(count, data.unified);
898
+
899
+ if (input.GetType().InternalType() == PhysicalType::LIST) {
900
+ auto &child = ListVector::GetEntry(input);
901
+ auto child_count = ListVector::GetListSize(input);
902
+ data.children.emplace_back();
903
+ Vector::RecursiveToUnifiedFormat(child, child_count, data.children.back());
904
+
905
+ } else if (input.GetType().InternalType() == PhysicalType::STRUCT) {
906
+ auto &children = StructVector::GetEntries(input);
907
+ for (idx_t i = 0; i < children.size(); i++) {
908
+ data.children.emplace_back();
909
+ }
910
+ for (idx_t i = 0; i < children.size(); i++) {
911
+ Vector::RecursiveToUnifiedFormat(*children[i], count, data.children[i]);
912
+ }
913
+ }
914
+ }
915
+
895
916
  void Vector::Sequence(int64_t start, int64_t increment, idx_t count) {
896
917
  this->vector_type = VectorType::SEQUENCE_VECTOR;
897
918
  this->buffer = make_buffer<VectorBuffer>(sizeof(int64_t) * 3);
@@ -31,8 +31,6 @@ struct hash<duckdb::hugeint_t> {
31
31
 
32
32
  namespace duckdb {
33
33
 
34
- using FrameBounds = std::pair<idx_t, idx_t>;
35
-
36
34
  template <class KEY_TYPE>
37
35
  struct ModeState {
38
36
  struct ModeAttr {
@@ -225,31 +223,31 @@ struct ModeFunction {
225
223
  if (state.nonzero <= tau * state.frequency_map->size()) {
226
224
  state.Reset();
227
225
  // for f ∈ F do
228
- for (auto f = frame.first; f < frame.second; ++f) {
226
+ for (auto f = frame.start; f < frame.end; ++f) {
229
227
  if (included(f)) {
230
228
  state.ModeAdd(KEY_TYPE(data[f]), f);
231
229
  }
232
230
  }
233
231
  } else {
234
232
  // for f ∈ P \ F do
235
- for (auto p = prev.first; p < frame.first; ++p) {
233
+ for (auto p = prev.start; p < frame.start; ++p) {
236
234
  if (included(p)) {
237
235
  state.ModeRm(KEY_TYPE(data[p]), p);
238
236
  }
239
237
  }
240
- for (auto p = frame.second; p < prev.second; ++p) {
238
+ for (auto p = frame.end; p < prev.end; ++p) {
241
239
  if (included(p)) {
242
240
  state.ModeRm(KEY_TYPE(data[p]), p);
243
241
  }
244
242
  }
245
243
 
246
244
  // for f ∈ F \ P do
247
- for (auto f = frame.first; f < prev.first; ++f) {
245
+ for (auto f = frame.start; f < prev.start; ++f) {
248
246
  if (included(f)) {
249
247
  state.ModeAdd(KEY_TYPE(data[f]), f);
250
248
  }
251
249
  }
252
- for (auto f = prev.second; f < frame.second; ++f) {
250
+ for (auto f = prev.end; f < frame.end; ++f) {
253
251
  if (included(f)) {
254
252
  state.ModeAdd(KEY_TYPE(data[f]), f);
255
253
  }
@@ -37,8 +37,6 @@ inline interval_t operator-(const interval_t &lhs, const interval_t &rhs) {
37
37
  return Interval::FromMicro(Interval::GetMicro(lhs) - Interval::GetMicro(rhs));
38
38
  }
39
39
 
40
- using FrameBounds = std::pair<idx_t, idx_t>;
41
-
42
40
  template <typename SAVE_TYPE>
43
41
  struct QuantileState {
44
42
  using SaveType = SAVE_TYPE;
@@ -89,7 +87,7 @@ void ReuseIndexes(idx_t *index, const FrameBounds &frame, const FrameBounds &pre
89
87
  idx_t j = 0;
90
88
 
91
89
  // Copy overlapping indices
92
- for (idx_t p = 0; p < (prev.second - prev.first); ++p) {
90
+ for (idx_t p = 0; p < (prev.end - prev.start); ++p) {
93
91
  auto idx = index[p];
94
92
 
95
93
  // Shift down into any hole
@@ -98,7 +96,7 @@ void ReuseIndexes(idx_t *index, const FrameBounds &frame, const FrameBounds &pre
98
96
  }
99
97
 
100
98
  // Skip overlapping values
101
- if (frame.first <= idx && idx < frame.second) {
99
+ if (frame.start <= idx && idx < frame.end) {
102
100
  ++j;
103
101
  }
104
102
  }
@@ -106,15 +104,15 @@ void ReuseIndexes(idx_t *index, const FrameBounds &frame, const FrameBounds &pre
106
104
  // Insert new indices
107
105
  if (j > 0) {
108
106
  // Overlap: append the new ends
109
- for (auto f = frame.first; f < prev.first; ++f, ++j) {
107
+ for (auto f = frame.start; f < prev.start; ++f, ++j) {
110
108
  index[j] = f;
111
109
  }
112
- for (auto f = prev.second; f < frame.second; ++f, ++j) {
110
+ for (auto f = prev.end; f < frame.end; ++f, ++j) {
113
111
  index[j] = f;
114
112
  }
115
113
  } else {
116
114
  // No overlap: overwrite with new values
117
- for (auto f = frame.first; f < frame.second; ++f, ++j) {
115
+ for (auto f = frame.start; f < frame.end; ++f, ++j) {
118
116
  index[j] = f;
119
117
  }
120
118
  }
@@ -124,17 +122,17 @@ static idx_t ReplaceIndex(idx_t *index, const FrameBounds &frame, const FrameBou
124
122
  D_ASSERT(index);
125
123
 
126
124
  idx_t j = 0;
127
- for (idx_t p = 0; p < (prev.second - prev.first); ++p) {
125
+ for (idx_t p = 0; p < (prev.end - prev.start); ++p) {
128
126
  auto idx = index[p];
129
127
  if (j != p) {
130
128
  break;
131
129
  }
132
130
 
133
- if (frame.first <= idx && idx < frame.second) {
131
+ if (frame.start <= idx && idx < frame.end) {
134
132
  ++j;
135
133
  }
136
134
  }
137
- index[j] = frame.second - 1;
135
+ index[j] = frame.end - 1;
138
136
 
139
137
  return j;
140
138
  }
@@ -560,7 +558,7 @@ struct QuantileScalarOperation : public QuantileOperation {
560
558
 
561
559
  // Lazily initialise frame state
562
560
  auto prev_pos = state.pos;
563
- state.SetPos(frame.second - frame.first);
561
+ state.SetPos(frame.end - frame.start);
564
562
 
565
563
  auto index = state.w.data();
566
564
  D_ASSERT(index);
@@ -572,11 +570,11 @@ struct QuantileScalarOperation : public QuantileOperation {
572
570
  const auto q = bind_data.quantiles[0];
573
571
 
574
572
  bool replace = false;
575
- if (frame.first == prev.first + 1 && frame.second == prev.second + 1) {
573
+ if (frame.start == prev.start + 1 && frame.end == prev.end + 1) {
576
574
  // Fixed frame size
577
575
  const auto j = ReplaceIndex(index, frame, prev);
578
576
  // We can only replace if the number of NULLs has not changed
579
- if (included.AllValid() || included(prev.first) == included(prev.second)) {
577
+ if (included.AllValid() || included(prev.start) == included(prev.end)) {
580
578
  Interpolator<DISCRETE> interp(q, prev_pos, false);
581
579
  replace = CanReplace(index, data, j, interp.FRN, interp.CRN, included);
582
580
  if (replace) {
@@ -720,7 +718,7 @@ struct QuantileListOperation : public QuantileOperation {
720
718
 
721
719
  // Lazily initialise frame state
722
720
  auto prev_pos = state.pos;
723
- state.SetPos(frame.second - frame.first);
721
+ state.SetPos(frame.end - frame.start);
724
722
 
725
723
  auto index = state.w.data();
726
724
 
@@ -731,11 +729,11 @@ struct QuantileListOperation : public QuantileOperation {
731
729
  // then Q25 must be recomputed, but Q50 and Q75 are unaffected.
732
730
  // For a single element list, this reduces to the scalar case.
733
731
  std::pair<idx_t, idx_t> replaceable {state.pos, 0};
734
- if (frame.first == prev.first + 1 && frame.second == prev.second + 1) {
732
+ if (frame.start == prev.start + 1 && frame.end == prev.end + 1) {
735
733
  // Fixed frame size
736
734
  const auto j = ReplaceIndex(index, frame, prev);
737
735
  // We can only replace if the number of NULLs has not changed
738
- if (included.AllValid() || included(prev.first) == included(prev.second)) {
736
+ if (included.AllValid() || included(prev.start) == included(prev.end)) {
739
737
  for (const auto &q : bind_data.order) {
740
738
  const auto &quantile = bind_data.quantiles[q];
741
739
  Interpolator<DISCRETE> interp(quantile, prev_pos, false);
@@ -1062,7 +1060,7 @@ struct MedianAbsoluteDeviationOperation : public QuantileOperation {
1062
1060
 
1063
1061
  // Lazily initialise frame state
1064
1062
  auto prev_pos = state.pos;
1065
- state.SetPos(frame.second - frame.first);
1063
+ state.SetPos(frame.end - frame.start);
1066
1064
 
1067
1065
  auto index = state.w.data();
1068
1066
  D_ASSERT(index);
@@ -1085,11 +1083,11 @@ struct MedianAbsoluteDeviationOperation : public QuantileOperation {
1085
1083
  const float q = 0.5;
1086
1084
 
1087
1085
  bool replace = false;
1088
- if (frame.first == prev.first + 1 && frame.second == prev.second + 1) {
1086
+ if (frame.start == prev.start + 1 && frame.end == prev.end + 1) {
1089
1087
  // Fixed frame size
1090
1088
  const auto j = ReplaceIndex(index, frame, prev);
1091
1089
  // We can only replace if the number of NULLs has not changed
1092
- if (included.AllValid() || included(prev.first) == included(prev.second)) {
1090
+ if (included.AllValid() || included(prev.start) == included(prev.end)) {
1093
1091
  Interpolator<false> interp(q, prev_pos, false);
1094
1092
  replace = CanReplace(index, data, j, interp.FRN, interp.CRN, included);
1095
1093
  if (replace) {