duckdb 0.4.1-dev754.0 → 0.4.1-dev790.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.
package/src/duckdb.cpp CHANGED
@@ -33160,6 +33160,8 @@ static inline int FastMemcmp(const void *str1, const void *str2, const size_t si
33160
33160
 
33161
33161
 
33162
33162
 
33163
+
33164
+
33163
33165
  namespace duckdb {
33164
33166
 
33165
33167
  class BufferManager;
@@ -33318,6 +33320,84 @@ private:
33318
33320
  const bool flush;
33319
33321
  };
33320
33322
 
33323
+ struct SBIterator {
33324
+ static int ComparisonValue(ExpressionType comparison);
33325
+
33326
+ SBIterator(GlobalSortState &gss, ExpressionType comparison, idx_t entry_idx_p = 0);
33327
+
33328
+ inline idx_t GetIndex() const {
33329
+ return entry_idx;
33330
+ }
33331
+
33332
+ inline void SetIndex(idx_t entry_idx_p) {
33333
+ const auto new_block_idx = entry_idx_p / block_capacity;
33334
+ if (new_block_idx != scan.block_idx) {
33335
+ scan.SetIndices(new_block_idx, 0);
33336
+ if (new_block_idx < block_count) {
33337
+ scan.PinRadix(scan.block_idx);
33338
+ block_ptr = scan.RadixPtr();
33339
+ if (!all_constant) {
33340
+ scan.PinData(*scan.sb->blob_sorting_data);
33341
+ }
33342
+ }
33343
+ }
33344
+
33345
+ scan.entry_idx = entry_idx_p % block_capacity;
33346
+ entry_ptr = block_ptr + scan.entry_idx * entry_size;
33347
+ entry_idx = entry_idx_p;
33348
+ }
33349
+
33350
+ inline SBIterator &operator++() {
33351
+ if (++scan.entry_idx < block_capacity) {
33352
+ entry_ptr += entry_size;
33353
+ ++entry_idx;
33354
+ } else {
33355
+ SetIndex(entry_idx + 1);
33356
+ }
33357
+
33358
+ return *this;
33359
+ }
33360
+
33361
+ inline SBIterator &operator--() {
33362
+ if (scan.entry_idx) {
33363
+ --scan.entry_idx;
33364
+ --entry_idx;
33365
+ entry_ptr -= entry_size;
33366
+ } else {
33367
+ SetIndex(entry_idx - 1);
33368
+ }
33369
+
33370
+ return *this;
33371
+ }
33372
+
33373
+ inline bool Compare(const SBIterator &other) const {
33374
+ int comp_res;
33375
+ if (all_constant) {
33376
+ comp_res = FastMemcmp(entry_ptr, other.entry_ptr, cmp_size);
33377
+ } else {
33378
+ comp_res = Comparators::CompareTuple(scan, other.scan, entry_ptr, other.entry_ptr, sort_layout, external);
33379
+ }
33380
+
33381
+ return comp_res <= cmp;
33382
+ }
33383
+
33384
+ // Fixed comparison parameters
33385
+ const SortLayout &sort_layout;
33386
+ const idx_t block_count;
33387
+ const idx_t block_capacity;
33388
+ const size_t cmp_size;
33389
+ const size_t entry_size;
33390
+ const bool all_constant;
33391
+ const bool external;
33392
+ const int cmp;
33393
+
33394
+ // Iteration state
33395
+ SBScanState scan;
33396
+ idx_t entry_idx;
33397
+ data_ptr_t block_ptr;
33398
+ data_ptr_t entry_ptr;
33399
+ };
33400
+
33321
33401
  } // namespace duckdb
33322
33402
 
33323
33403
 
@@ -35661,6 +35741,30 @@ void PayloadScanner::Scan(DataChunk &chunk) {
35661
35741
  total_scanned += scanned;
35662
35742
  }
35663
35743
 
35744
+ int SBIterator::ComparisonValue(ExpressionType comparison) {
35745
+ switch (comparison) {
35746
+ case ExpressionType::COMPARE_LESSTHAN:
35747
+ case ExpressionType::COMPARE_GREATERTHAN:
35748
+ return -1;
35749
+ case ExpressionType::COMPARE_LESSTHANOREQUALTO:
35750
+ case ExpressionType::COMPARE_GREATERTHANOREQUALTO:
35751
+ return 0;
35752
+ default:
35753
+ throw InternalException("Unimplemented comparison type for IEJoin!");
35754
+ }
35755
+ }
35756
+
35757
+ SBIterator::SBIterator(GlobalSortState &gss, ExpressionType comparison, idx_t entry_idx_p)
35758
+ : sort_layout(gss.sort_layout), block_count(gss.sorted_blocks[0]->radix_sorting_data.size()),
35759
+ block_capacity(gss.block_capacity), cmp_size(sort_layout.comparison_size), entry_size(sort_layout.entry_size),
35760
+ all_constant(sort_layout.all_constant), external(gss.external), cmp(ComparisonValue(comparison)),
35761
+ scan(gss.buffer_manager, gss), block_ptr(nullptr), entry_ptr(nullptr) {
35762
+
35763
+ scan.sb = gss.sorted_blocks[0].get();
35764
+ scan.block_idx = block_count;
35765
+ SetIndex(entry_idx_p);
35766
+ }
35767
+
35664
35768
  } // namespace duckdb
35665
35769
 
35666
35770
 
@@ -45348,6 +45452,10 @@ struct MapFun {
45348
45452
  static void RegisterFunction(BuiltinFunctions &set);
45349
45453
  };
45350
45454
 
45455
+ struct MapFromEntriesFun {
45456
+ static void RegisterFunction(BuiltinFunctions &set);
45457
+ };
45458
+
45351
45459
  struct MapExtractFun {
45352
45460
  static void RegisterFunction(BuiltinFunctions &set);
45353
45461
  };
@@ -45416,6 +45524,7 @@ struct StructExtractFun {
45416
45524
 
45417
45525
  MapInvalidReason CheckMapValidity(Vector &map, idx_t count,
45418
45526
  const SelectionVector &sel = *FlatVector::IncrementalSelectionVector());
45527
+ void MapConversionVerify(Vector &vector, idx_t count);
45419
45528
 
45420
45529
  } // namespace duckdb
45421
45530
 
@@ -60147,9 +60256,9 @@ public:
60147
60256
  using Orders = vector<BoundOrderByNode>;
60148
60257
  using Types = vector<LogicalType>;
60149
60258
 
60150
- WindowGlobalHashGroup(BufferManager &buffer_manager, const Orders &orders, const Types &payload_types,
60151
- idx_t max_mem, bool external)
60152
- : memory_per_thread(max_mem), count(0) {
60259
+ WindowGlobalHashGroup(BufferManager &buffer_manager, const Orders &partitions, const Orders &orders,
60260
+ const Types &payload_types, idx_t max_mem, bool external)
60261
+ : memory_per_thread(max_mem), count(0), partition_layout(partitions) {
60153
60262
 
60154
60263
  RowLayout payload_layout;
60155
60264
  payload_layout.Initialize(payload_types);
@@ -60165,11 +60274,47 @@ public:
60165
60274
  global_sort->PrepareMergePhase();
60166
60275
  }
60167
60276
 
60277
+ void ComputeMasks(ValidityMask &partition_mask, ValidityMask &order_mask);
60278
+
60168
60279
  const idx_t memory_per_thread;
60169
60280
  GlobalSortStatePtr global_sort;
60170
60281
  atomic<idx_t> count;
60282
+
60283
+ // Mask computation
60284
+ SortLayout partition_layout;
60171
60285
  };
60172
60286
 
60287
+ void WindowGlobalHashGroup::ComputeMasks(ValidityMask &partition_mask, ValidityMask &order_mask) {
60288
+ D_ASSERT(count > 0);
60289
+
60290
+ // Set up a comparator for the partition subset
60291
+ const auto partition_size = partition_layout.comparison_size;
60292
+
60293
+ SBIterator prev(*global_sort, ExpressionType::COMPARE_LESSTHAN);
60294
+ SBIterator curr(*global_sort, ExpressionType::COMPARE_LESSTHAN);
60295
+
60296
+ partition_mask.SetValidUnsafe(0);
60297
+ order_mask.SetValidUnsafe(0);
60298
+ for (++curr; curr.GetIndex() < count; ++curr) {
60299
+ // Compare the partition subset first because if that differs, then so does the full ordering
60300
+ int part_cmp = 0;
60301
+ if (partition_layout.all_constant) {
60302
+ part_cmp = FastMemcmp(prev.entry_ptr, curr.entry_ptr, partition_size);
60303
+ } else {
60304
+ part_cmp = Comparators::CompareTuple(prev.scan, curr.scan, prev.entry_ptr, curr.entry_ptr, partition_layout,
60305
+ prev.external);
60306
+ }
60307
+
60308
+ if (part_cmp) {
60309
+ partition_mask.SetValidUnsafe(curr.GetIndex());
60310
+ order_mask.SetValidUnsafe(curr.GetIndex());
60311
+ } else if (prev.Compare(curr)) {
60312
+ order_mask.SetValidUnsafe(curr.GetIndex());
60313
+ }
60314
+ ++prev;
60315
+ }
60316
+ }
60317
+
60173
60318
  // Global sink state
60174
60319
  class WindowGlobalSinkState : public GlobalSinkState {
60175
60320
  public:
@@ -60199,6 +60344,7 @@ public:
60199
60344
  orders.emplace_back(OrderType::ASCENDING, OrderByNullType::NULLS_FIRST, pexpr->Copy(),
60200
60345
  wexpr->partitions_stats[prt_idx]->Copy());
60201
60346
  }
60347
+ partitions.emplace_back(orders.back().Copy());
60202
60348
  }
60203
60349
 
60204
60350
  for (const auto &order : wexpr->orders) {
@@ -60215,8 +60361,8 @@ public:
60215
60361
  lock_guard<mutex> guard(lock);
60216
60362
 
60217
60363
  if (!ungrouped) {
60218
- ungrouped =
60219
- make_unique<WindowGlobalHashGroup>(buffer_manager, orders, payload_types, memory_per_thread, external);
60364
+ ungrouped = make_unique<WindowGlobalHashGroup>(buffer_manager, partitions, orders, payload_types,
60365
+ memory_per_thread, external);
60220
60366
  }
60221
60367
 
60222
60368
  return ungrouped.get();
@@ -60244,7 +60390,8 @@ public:
60244
60390
  auto &hash_group = hash_groups[group];
60245
60391
  if (!hash_group) {
60246
60392
  const auto maxmem = memory_per_thread / partition_info.n_partitions;
60247
- hash_group = make_unique<WindowGlobalHashGroup>(buffer_manager, orders, payload_types, maxmem, external);
60393
+ hash_group =
60394
+ make_unique<WindowGlobalHashGroup>(buffer_manager, partitions, orders, payload_types, maxmem, external);
60248
60395
  }
60249
60396
 
60250
60397
  return hash_group.get();
@@ -60271,6 +60418,7 @@ public:
60271
60418
  mutex lock;
60272
60419
 
60273
60420
  // Sorting
60421
+ Orders partitions;
60274
60422
  Orders orders;
60275
60423
  Types payload_types;
60276
60424
  HashGroupPtr ungrouped;
@@ -60671,7 +60819,7 @@ void WindowGlobalSinkState::Finalize() {
60671
60819
  global_sort.InitializeMergeRound();
60672
60820
  MergeSorter merge_sorter(global_sort, global_sort.buffer_manager);
60673
60821
  merge_sorter.PerformInMergeRound();
60674
- global_sort.CompleteMergeRound();
60822
+ global_sort.CompleteMergeRound(true);
60675
60823
  }
60676
60824
 
60677
60825
  // Sink it into a temporary local sink state
@@ -60714,120 +60862,6 @@ PhysicalWindow::PhysicalWindow(vector<LogicalType> types, vector<unique_ptr<Expr
60714
60862
  : PhysicalOperator(type, move(types), estimated_cardinality), select_list(move(select_list)) {
60715
60863
  }
60716
60864
 
60717
- struct MaskColumnOperator {
60718
- template <class INPUT_TYPE>
60719
- static INPUT_TYPE GetData(Vector &v, idx_t row_idx) {
60720
- auto data = FlatVector::GetData<INPUT_TYPE>(v);
60721
- return data[row_idx];
60722
- }
60723
- };
60724
-
60725
- struct MaskColumnOperatorValue {
60726
- template <class INPUT_TYPE>
60727
- static INPUT_TYPE GetData(Vector &v, idx_t row_idx) {
60728
- return v.GetValue(row_idx);
60729
- }
60730
- };
60731
-
60732
- template <typename INPUT_TYPE, class OP = MaskColumnOperator>
60733
- static void MaskTypedColumn(ValidityMask &mask, ChunkCollection &over_collection, const idx_t c) {
60734
- idx_t r = 0;
60735
- bool prev_valid;
60736
- INPUT_TYPE prev;
60737
- bool first_chunk = true;
60738
-
60739
- for (auto &chunk : over_collection.Chunks()) {
60740
- auto &v = chunk->data[c];
60741
- auto validity = FlatVector::Validity(v);
60742
- if (mask.CheckAllValid(r + chunk->size(), r)) {
60743
- #ifdef DEBUG
60744
- for (idx_t i = 0; i < chunk->size(); i++) {
60745
- D_ASSERT(mask.RowIsValid(r + i));
60746
- }
60747
- #endif
60748
- // all valid for this chunk: we can skip this
60749
- // we should update the "prev" values though
60750
- auto last_idx = chunk->size() - 1;
60751
- prev_valid = validity.RowIsValid(last_idx);
60752
- prev = OP::template GetData<INPUT_TYPE>(v, last_idx);
60753
- first_chunk = false;
60754
- r += chunk->size();
60755
- continue;
60756
- }
60757
- idx_t start_index = 0;
60758
- if (first_chunk) {
60759
- // record the first value (if this is the first chunk)
60760
- prev_valid = validity.RowIsValid(0);
60761
- prev = OP::template GetData<INPUT_TYPE>(v, 0);
60762
- first_chunk = false;
60763
- start_index++;
60764
- r++;
60765
- }
60766
- for (idx_t i = start_index; i < chunk->size(); i++) {
60767
- auto curr_valid = validity.RowIsValid(i);
60768
- auto curr = OP::template GetData<INPUT_TYPE>(v, i);
60769
-
60770
- if (!mask.RowIsValid(r)) {
60771
- if (curr_valid != prev_valid || (curr_valid && !Equals::Operation(curr, prev))) {
60772
- mask.SetValidUnsafe(r);
60773
- }
60774
- }
60775
- prev_valid = curr_valid;
60776
- prev = curr;
60777
- r++;
60778
- }
60779
- }
60780
- }
60781
-
60782
- static void MaskColumn(ValidityMask &mask, ChunkCollection &over_collection, const idx_t c) {
60783
- auto &vector = over_collection.GetChunk(0).data[c];
60784
- switch (vector.GetType().InternalType()) {
60785
- case PhysicalType::BOOL:
60786
- case PhysicalType::INT8:
60787
- MaskTypedColumn<int8_t>(mask, over_collection, c);
60788
- break;
60789
- case PhysicalType::INT16:
60790
- MaskTypedColumn<int16_t>(mask, over_collection, c);
60791
- break;
60792
- case PhysicalType::INT32:
60793
- MaskTypedColumn<int32_t>(mask, over_collection, c);
60794
- break;
60795
- case PhysicalType::INT64:
60796
- MaskTypedColumn<int64_t>(mask, over_collection, c);
60797
- break;
60798
- case PhysicalType::UINT8:
60799
- MaskTypedColumn<uint8_t>(mask, over_collection, c);
60800
- break;
60801
- case PhysicalType::UINT16:
60802
- MaskTypedColumn<uint16_t>(mask, over_collection, c);
60803
- break;
60804
- case PhysicalType::UINT32:
60805
- MaskTypedColumn<uint32_t>(mask, over_collection, c);
60806
- break;
60807
- case PhysicalType::UINT64:
60808
- MaskTypedColumn<uint64_t>(mask, over_collection, c);
60809
- break;
60810
- case PhysicalType::INT128:
60811
- MaskTypedColumn<hugeint_t>(mask, over_collection, c);
60812
- break;
60813
- case PhysicalType::FLOAT:
60814
- MaskTypedColumn<float>(mask, over_collection, c);
60815
- break;
60816
- case PhysicalType::DOUBLE:
60817
- MaskTypedColumn<double>(mask, over_collection, c);
60818
- break;
60819
- case PhysicalType::VARCHAR:
60820
- MaskTypedColumn<string_t>(mask, over_collection, c);
60821
- break;
60822
- case PhysicalType::INTERVAL:
60823
- MaskTypedColumn<interval_t>(mask, over_collection, c);
60824
- break;
60825
- default:
60826
- MaskTypedColumn<Value, MaskColumnOperatorValue>(mask, over_collection, c);
60827
- break;
60828
- }
60829
- }
60830
-
60831
60865
  static idx_t FindNextStart(const ValidityMask &mask, idx_t l, const idx_t r, idx_t &n) {
60832
60866
  if (mask.AllValid()) {
60833
60867
  auto start = MinValue(l + n - 1, r);
@@ -61656,31 +61690,12 @@ using WindowExpressions = vector<BoundWindowExpression *>;
61656
61690
 
61657
61691
  static void ComputeWindowExpressions(WindowExpressions &window_exprs, ChunkCollection &input,
61658
61692
  ChunkCollection &window_results, ChunkCollection &over,
61693
+ const ValidityMask &partition_mask, const ValidityMask &order_mask,
61659
61694
  WindowAggregationMode mode) {
61660
61695
  // Idempotency
61661
61696
  if (input.Count() == 0) {
61662
61697
  return;
61663
61698
  }
61664
- // Pick out a function for the OVER clause
61665
- auto over_expr = window_exprs[0];
61666
-
61667
- // Set bits for the start of each partition
61668
- vector<validity_t> partition_bits(ValidityMask::EntryCount(input.Count()), 0);
61669
- ValidityMask partition_mask(partition_bits.data());
61670
- partition_mask.SetValid(0);
61671
-
61672
- for (idx_t c = 0; c < over_expr->partitions.size(); ++c) {
61673
- MaskColumn(partition_mask, over, c);
61674
- }
61675
-
61676
- // Set bits for the start of each peer group.
61677
- // Partitions also break peer groups, so start with the partition bits.
61678
- const auto sort_col_count = over_expr->partitions.size() + over_expr->orders.size();
61679
- ValidityMask order_mask(partition_mask, input.Count());
61680
- for (idx_t c = over_expr->partitions.size(); c < sort_col_count; ++c) {
61681
- MaskColumn(order_mask, over, c);
61682
- }
61683
-
61684
61699
  // Compute the functions columnwise
61685
61700
  for (idx_t expr_idx = 0; expr_idx < window_exprs.size(); ++expr_idx) {
61686
61701
  ChunkCollection output(input.GetAllocator());
@@ -61714,6 +61729,24 @@ static void GeneratePartition(WindowLocalSourceState &state, WindowGlobalSinkSta
61714
61729
  // 3. Multiple partitions (sorting and hashing)
61715
61730
  const auto &input_types = op.children[0]->types;
61716
61731
 
61732
+ // How big is the partition?
61733
+ idx_t count = 0;
61734
+ if (hash_bin < gstate.hash_groups.size() && gstate.hash_groups[hash_bin]) {
61735
+ count = gstate.hash_groups[hash_bin]->count;
61736
+ } else if (gstate.rows && !hash_bin) {
61737
+ count = gstate.count;
61738
+ } else {
61739
+ return;
61740
+ }
61741
+
61742
+ // Initialise masks to false
61743
+ const auto bit_count = ValidityMask::ValidityMaskSize(count);
61744
+ vector<validity_t> partition_bits(bit_count, 0);
61745
+ ValidityMask partition_mask(partition_bits.data());
61746
+
61747
+ vector<validity_t> order_bits(bit_count, 0);
61748
+ ValidityMask order_mask(order_bits.data());
61749
+
61717
61750
  // Scan the sorted data into new Collections
61718
61751
  auto &allocator = gstate.allocator;
61719
61752
  ChunkCollection input(allocator);
@@ -61721,9 +61754,12 @@ static void GeneratePartition(WindowLocalSourceState &state, WindowGlobalSinkSta
61721
61754
  if (gstate.rows && !hash_bin) {
61722
61755
  // No partition - convert row collection to chunk collection
61723
61756
  ScanRowCollection(*gstate.rows, *gstate.strings, input, input_types);
61757
+ partition_mask.SetValidUnsafe(0);
61758
+ order_mask.SetValidUnsafe(0);
61724
61759
  } else if (hash_bin < gstate.hash_groups.size() && gstate.hash_groups[hash_bin]) {
61725
61760
  // Overwrite the collections with the sorted data
61726
61761
  state.hash_group = move(gstate.hash_groups[hash_bin]);
61762
+ state.hash_group->ComputeMasks(partition_mask, order_mask);
61727
61763
  const auto over_types = state.hash_group->global_sort->sort_layout.logical_types;
61728
61764
  ScanSortedPartition(state, input, input_types, over, over_types);
61729
61765
  } else {
@@ -61731,7 +61767,7 @@ static void GeneratePartition(WindowLocalSourceState &state, WindowGlobalSinkSta
61731
61767
  }
61732
61768
 
61733
61769
  ChunkCollection output(allocator);
61734
- ComputeWindowExpressions(window_exprs, input, output, over, gstate.mode);
61770
+ ComputeWindowExpressions(window_exprs, input, output, over, partition_mask, order_mask, gstate.mode);
61735
61771
  state.chunks.Merge(input);
61736
61772
  state.window_results.Merge(output);
61737
61773
  }
@@ -61832,7 +61868,7 @@ public:
61832
61868
  }
61833
61869
 
61834
61870
  void FinishEvent() override {
61835
- hash_group.global_sort->CompleteMergeRound();
61871
+ hash_group.global_sort->CompleteMergeRound(true);
61836
61872
  CreateMergeTasks(pipeline, *this, gstate, hash_group);
61837
61873
  }
61838
61874
 
@@ -66073,7 +66109,6 @@ private:
66073
66109
 
66074
66110
 
66075
66111
 
66076
-
66077
66112
  #include <thread>
66078
66113
 
66079
66114
  namespace duckdb {
@@ -66254,104 +66289,6 @@ OperatorResultType PhysicalIEJoin::Execute(ExecutionContext &context, DataChunk
66254
66289
  //===--------------------------------------------------------------------===//
66255
66290
  // Source
66256
66291
  //===--------------------------------------------------------------------===//
66257
- struct SBIterator {
66258
- static int ComparisonValue(ExpressionType comparison) {
66259
- switch (comparison) {
66260
- case ExpressionType::COMPARE_LESSTHAN:
66261
- case ExpressionType::COMPARE_GREATERTHAN:
66262
- return -1;
66263
- case ExpressionType::COMPARE_LESSTHANOREQUALTO:
66264
- case ExpressionType::COMPARE_GREATERTHANOREQUALTO:
66265
- return 0;
66266
- default:
66267
- throw InternalException("Unimplemented comparison type for IEJoin!");
66268
- }
66269
- }
66270
-
66271
- explicit SBIterator(GlobalSortState &gss, ExpressionType comparison, idx_t entry_idx_p = 0)
66272
- : sort_layout(gss.sort_layout), block_count(gss.sorted_blocks[0]->radix_sorting_data.size()),
66273
- block_capacity(gss.block_capacity), cmp_size(sort_layout.comparison_size), entry_size(sort_layout.entry_size),
66274
- all_constant(sort_layout.all_constant), external(gss.external), cmp(ComparisonValue(comparison)),
66275
- scan(gss.buffer_manager, gss), block_ptr(nullptr), entry_ptr(nullptr) {
66276
-
66277
- scan.sb = gss.sorted_blocks[0].get();
66278
- scan.block_idx = block_count;
66279
- SetIndex(entry_idx_p);
66280
- }
66281
-
66282
- inline idx_t GetIndex() const {
66283
- return entry_idx;
66284
- }
66285
-
66286
- inline void SetIndex(idx_t entry_idx_p) {
66287
- const auto new_block_idx = entry_idx_p / block_capacity;
66288
- if (new_block_idx != scan.block_idx) {
66289
- scan.SetIndices(new_block_idx, 0);
66290
- if (new_block_idx < block_count) {
66291
- scan.PinRadix(scan.block_idx);
66292
- block_ptr = scan.RadixPtr();
66293
- if (!all_constant) {
66294
- scan.PinData(*scan.sb->blob_sorting_data);
66295
- }
66296
- }
66297
- }
66298
-
66299
- scan.entry_idx = entry_idx_p % block_capacity;
66300
- entry_ptr = block_ptr + scan.entry_idx * entry_size;
66301
- entry_idx = entry_idx_p;
66302
- }
66303
-
66304
- inline SBIterator &operator++() {
66305
- if (++scan.entry_idx < block_capacity) {
66306
- entry_ptr += entry_size;
66307
- ++entry_idx;
66308
- } else {
66309
- SetIndex(entry_idx + 1);
66310
- }
66311
-
66312
- return *this;
66313
- }
66314
-
66315
- inline SBIterator &operator--() {
66316
- if (scan.entry_idx) {
66317
- --scan.entry_idx;
66318
- --entry_idx;
66319
- entry_ptr -= entry_size;
66320
- } else {
66321
- SetIndex(entry_idx - 1);
66322
- }
66323
-
66324
- return *this;
66325
- }
66326
-
66327
- inline bool Compare(const SBIterator &other) const {
66328
- int comp_res;
66329
- if (all_constant) {
66330
- comp_res = FastMemcmp(entry_ptr, other.entry_ptr, cmp_size);
66331
- } else {
66332
- comp_res = Comparators::CompareTuple(scan, other.scan, entry_ptr, other.entry_ptr, sort_layout, external);
66333
- }
66334
-
66335
- return comp_res <= cmp;
66336
- }
66337
-
66338
- // Fixed comparison parameters
66339
- const SortLayout &sort_layout;
66340
- const idx_t block_count;
66341
- const idx_t block_capacity;
66342
- const size_t cmp_size;
66343
- const size_t entry_size;
66344
- const bool all_constant;
66345
- const bool external;
66346
- const int cmp;
66347
-
66348
- // Iteration state
66349
- SBScanState scan;
66350
- idx_t entry_idx;
66351
- data_ptr_t block_ptr;
66352
- data_ptr_t entry_ptr;
66353
- };
66354
-
66355
66292
  struct IEJoinUnion {
66356
66293
  using SortedTable = PhysicalRangeJoin::GlobalSortedTable;
66357
66294
 
@@ -98427,7 +98364,7 @@ MapInvalidReason CheckMapValidity(Vector &map, idx_t count, const SelectionVecto
98427
98364
  return MapInvalidReason::VALID;
98428
98365
  }
98429
98366
 
98430
- static void MapConversionVerify(Vector &vector, idx_t count) {
98367
+ void MapConversionVerify(Vector &vector, idx_t count) {
98431
98368
  auto valid_check = CheckMapValidity(vector, count);
98432
98369
  switch (valid_check) {
98433
98370
  case MapInvalidReason::VALID:
@@ -98608,6 +98545,176 @@ void MapExtractFun::RegisterFunction(BuiltinFunctions &set) {
98608
98545
  }
98609
98546
 
98610
98547
  } // namespace duckdb
98548
+
98549
+
98550
+
98551
+
98552
+
98553
+
98554
+
98555
+ namespace duckdb {
98556
+
98557
+ struct VectorInfo {
98558
+ Vector &container;
98559
+ list_entry_t &data;
98560
+ };
98561
+
98562
+ static void MapStruct(Value &element, VectorInfo &keys, VectorInfo &values) {
98563
+ D_ASSERT(element.type().id() == LogicalTypeId::STRUCT);
98564
+ D_ASSERT(!element.IsNull());
98565
+ auto &key_value = StructValue::GetChildren(element);
98566
+ auto &key = key_value[0];
98567
+ auto &value = key_value[1];
98568
+
98569
+ if (key.IsNull()) {
98570
+ throw InvalidInputException("None of the keys of the map can be NULL");
98571
+ }
98572
+ // Add to the inner key/value lists of the resulting map
98573
+ ListVector::PushBack(keys.container, key);
98574
+ ListVector::PushBack(values.container, value);
98575
+ }
98576
+
98577
+ // FIXME: this operation has a time complexity of O(n^2)
98578
+ void CheckKeyUniqueness(VectorInfo &keys) {
98579
+ auto end = keys.data.offset + keys.data.length;
98580
+ auto &entries = ListVector::GetEntry(keys.container);
98581
+ for (auto lhs = keys.data.offset; lhs < end; lhs++) {
98582
+ auto element = entries.GetValue(lhs);
98583
+ D_ASSERT(!element.IsNull());
98584
+ for (auto rhs = lhs + 1; rhs < end; rhs++) {
98585
+ auto other = entries.GetValue(rhs);
98586
+ D_ASSERT(!other.IsNull());
98587
+
98588
+ if (element.type() != other.type()) {
98589
+ throw InvalidInputException("Not all keys are of the same type!");
98590
+ }
98591
+ if (element == other) {
98592
+ throw InvalidInputException("The given keys aren't unique");
98593
+ }
98594
+ }
98595
+ }
98596
+ }
98597
+
98598
+ static bool MapSingleList(VectorInfo &input, VectorInfo &keys, VectorInfo &values) {
98599
+ // Get the length and offset of this list from the argument data
98600
+ auto pair_amount = input.data.length;
98601
+ auto input_offset = input.data.offset;
98602
+
98603
+ // Loop over the list of structs
98604
+ idx_t inserted_values = 0;
98605
+ for (idx_t i = 0; i < pair_amount; i++) {
98606
+ auto index = i + input_offset;
98607
+ // Get the struct using the offset and the index;
98608
+ auto element = input.container.GetValue(index);
98609
+ if (element.IsNull()) {
98610
+ continue;
98611
+ }
98612
+ MapStruct(element, keys, values);
98613
+ inserted_values++;
98614
+ }
98615
+ // Set the length of the key value lists
98616
+ keys.data.length = inserted_values;
98617
+ values.data.length = inserted_values;
98618
+ return inserted_values != 0;
98619
+ }
98620
+
98621
+ static void MapFromEntriesFunction(DataChunk &args, ExpressionState &state, Vector &result) {
98622
+ D_ASSERT(result.GetType().id() == LogicalTypeId::MAP);
98623
+
98624
+ result.SetVectorType(duckdb::VectorType::FLAT_VECTOR);
98625
+
98626
+ // Get the arguments vector
98627
+ auto &input_list = args.data[0];
98628
+ auto arg_data = FlatVector::GetData<list_entry_t>(input_list);
98629
+ auto &entries = ListVector::GetEntry(input_list);
98630
+
98631
+ // Prepare the result vectors
98632
+ auto &child_entries = StructVector::GetEntries(result);
98633
+ D_ASSERT(child_entries.size() == 2);
98634
+ auto &key_vector = *child_entries[0];
98635
+ auto &value_vector = *child_entries[1];
98636
+ auto &result_validity = FlatVector::Validity(result);
98637
+
98638
+ // Get the offset+length data for the list(s)
98639
+ auto key_data = FlatVector::GetData<list_entry_t>(key_vector);
98640
+ auto value_data = FlatVector::GetData<list_entry_t>(value_vector);
98641
+
98642
+ auto &key_validity = FlatVector::Validity(key_vector);
98643
+ auto &value_validity = FlatVector::Validity(value_vector);
98644
+
98645
+ auto count = args.size();
98646
+
98647
+ UnifiedVectorFormat input_list_data;
98648
+ input_list.ToUnifiedFormat(count, input_list_data);
98649
+
98650
+ // Current offset into the keys/values list
98651
+ idx_t offset = 0;
98652
+
98653
+ // Transform to mapped values
98654
+ for (idx_t i = 0; i < count; i++) {
98655
+ VectorInfo input {entries, arg_data[i]};
98656
+ VectorInfo keys {key_vector, key_data[i]};
98657
+ VectorInfo values {value_vector, value_data[i]};
98658
+
98659
+ keys.data.offset = offset;
98660
+ values.data.offset = offset;
98661
+ auto row_valid = MapSingleList(input, keys, values);
98662
+ offset += keys.data.length;
98663
+
98664
+ // Check validity
98665
+ if (!row_valid || !input_list_data.validity.RowIsValid(i)) {
98666
+ key_validity.SetInvalid(i);
98667
+ value_validity.SetInvalid(i);
98668
+ result_validity.SetInvalid(i);
98669
+ }
98670
+ }
98671
+ MapConversionVerify(result, count);
98672
+ result.Verify(count);
98673
+ }
98674
+
98675
+ static unique_ptr<FunctionData> MapFromEntriesBind(ClientContext &context, ScalarFunction &bound_function,
98676
+ vector<unique_ptr<Expression>> &arguments) {
98677
+ child_list_t<LogicalType> child_types;
98678
+
98679
+ if (arguments.size() != 1) {
98680
+ throw InvalidInputException("The input argument must be a list of structs.");
98681
+ }
98682
+ auto &list = arguments[0]->return_type;
98683
+
98684
+ if (list.id() == LogicalTypeId::UNKNOWN) {
98685
+ bound_function.arguments.emplace_back(LogicalTypeId::UNKNOWN);
98686
+ bound_function.return_type = LogicalType(LogicalTypeId::SQLNULL);
98687
+ return nullptr;
98688
+ }
98689
+
98690
+ if (list.id() != LogicalTypeId::LIST) {
98691
+ throw InvalidInputException("The provided argument is not a list of structs");
98692
+ }
98693
+ auto &elem_type = ListType::GetChildType(list);
98694
+ if (elem_type.id() != LogicalTypeId::STRUCT) {
98695
+ throw InvalidInputException("The elements of the list must be structs");
98696
+ }
98697
+ auto &children = StructType::GetChildTypes(elem_type);
98698
+ if (children.size() != 2) {
98699
+ throw InvalidInputException("The provided struct type should only contain 2 fields, a key and a value");
98700
+ }
98701
+ child_types.push_back(make_pair("key", LogicalType::LIST(children[0].second)));
98702
+ child_types.push_back(make_pair("value", LogicalType::LIST(children[1].second)));
98703
+
98704
+ //! this is more for completeness reasons
98705
+ bound_function.return_type = LogicalType::MAP(move(child_types));
98706
+ return make_unique<VariableReturnBindData>(bound_function.return_type);
98707
+ }
98708
+
98709
+ void MapFromEntriesFun::RegisterFunction(BuiltinFunctions &set) {
98710
+ //! the arguments and return types are actually set in the binder function
98711
+ ScalarFunction fun("map_from_entries", {}, LogicalTypeId::MAP, MapFromEntriesFunction, MapFromEntriesBind);
98712
+ fun.null_handling = FunctionNullHandling::DEFAULT_NULL_HANDLING;
98713
+ fun.varargs = LogicalType::ANY;
98714
+ set.AddFunction(fun);
98715
+ }
98716
+
98717
+ } // namespace duckdb
98611
98718
  //===----------------------------------------------------------------------===//
98612
98719
  // DuckDB
98613
98720
  //
@@ -100127,6 +100234,7 @@ void BuiltinFunctions::RegisterNestedFunctions() {
100127
100234
  Register<ListRangeFun>();
100128
100235
  Register<ListFlattenFun>();
100129
100236
  Register<MapFun>();
100237
+ Register<MapFromEntriesFun>();
100130
100238
  Register<MapExtractFun>();
100131
100239
  Register<CardinalityFun>();
100132
100240
  }
@@ -105855,8 +105963,8 @@ static unique_ptr<FunctionData> StructExtractBind(ClientContext &context, Scalar
105855
105963
  if (key_child->HasParameter()) {
105856
105964
  throw ParameterNotResolvedException();
105857
105965
  }
105858
- if (key_child->return_type.id() != LogicalTypeId::VARCHAR ||
105859
- key_child->return_type.id() != LogicalTypeId::VARCHAR || !key_child->IsFoldable()) {
105966
+
105967
+ if (key_child->return_type.id() != LogicalTypeId::VARCHAR || !key_child->IsFoldable()) {
105860
105968
  throw BinderException("Key name for struct_extract needs to be a constant string");
105861
105969
  }
105862
105970
  Value key_val = ExpressionExecutor::EvaluateScalar(*key_child.get());