duckdb 0.3.2-dev275.0 → 0.3.2-dev277.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
@@ -29168,20 +29168,9 @@ private:
29168
29168
  } // namespace duckdb
29169
29169
 
29170
29170
 
29171
- //===----------------------------------------------------------------------===//
29172
- // DuckDB
29173
- //
29174
- // duckdb/common/sort/sort.hpp
29175
- //
29176
- //
29177
- //===----------------------------------------------------------------------===//
29178
-
29179
-
29180
-
29181
- //===----------------------------------------------------------------------===//
29182
29171
  // DuckDB
29183
29172
  //
29184
- // duckdb/common/sort/sorted_block.hpp
29173
+ // duckdb/common/fast_mem.hpp
29185
29174
  //
29186
29175
  //
29187
29176
  //===----------------------------------------------------------------------===//
@@ -29189,701 +29178,17 @@ private:
29189
29178
 
29190
29179
 
29191
29180
 
29192
- namespace duckdb {
29193
-
29194
- class BufferManager;
29195
- struct RowDataBlock;
29196
- struct SortLayout;
29197
- struct GlobalSortState;
29198
-
29199
- //! Object that holds sorted rows, and an accompanying heap if there are blobs
29200
- struct SortedData {
29201
- public:
29202
- SortedData(const RowLayout &layout, BufferManager &buffer_manager, GlobalSortState &state);
29203
- //! Number of rows that this object holds
29204
- idx_t Count();
29205
- //! Pin the current block so it can be read
29206
- void Pin();
29207
- //! Pointer to the row that is currently being read from
29208
- data_ptr_t DataPtr() const;
29209
- //! Pointer to the heap row that corresponds to the current row
29210
- data_ptr_t HeapPtr() const;
29211
- //! Advance one row
29212
- void Advance(const bool &adv);
29213
- //! Initialize new block to write to
29214
- void CreateBlock();
29215
- //! Reset read indices to the given indices
29216
- void ResetIndices(idx_t block_idx_to, idx_t entry_idx_to);
29217
- //! Create a slice that holds the rows between the start and end indices
29218
- unique_ptr<SortedData> CreateSlice(idx_t start_block_index, idx_t start_entry_index, idx_t end_block_index,
29219
- idx_t end_entry_index);
29220
- //! Unswizzles all
29221
- void Unswizzle();
29222
-
29223
- public:
29224
- //! Layout of this data
29225
- const RowLayout layout;
29226
- //! Data and heap blocks
29227
- vector<RowDataBlock> data_blocks;
29228
- vector<RowDataBlock> heap_blocks;
29229
- //! Buffer handles to the data being currently read
29230
- unique_ptr<BufferHandle> data_handle;
29231
- unique_ptr<BufferHandle> heap_handle;
29232
- //! Read indices
29233
- idx_t block_idx;
29234
- idx_t entry_idx;
29235
- //! Whether the pointers in this sorted data are swizzled
29236
- bool swizzled;
29237
-
29238
- private:
29239
- //! Pin fixed-size row data
29240
- void PinData();
29241
- //! Pin the accompanying heap data (if any)
29242
- void PinHeap();
29243
-
29244
- private:
29245
- //! The buffer manager
29246
- BufferManager &buffer_manager;
29247
- //! The global state
29248
- GlobalSortState &state;
29249
- //! Pointers into the buffers being currently read
29250
- data_ptr_t data_ptr;
29251
- data_ptr_t heap_ptr;
29252
- };
29253
-
29254
- //! Block that holds sorted rows: radix, blob and payload data
29255
- struct SortedBlock {
29256
- public:
29257
- SortedBlock(BufferManager &buffer_manager, GlobalSortState &gstate);
29258
- //! Number of rows that this object holds
29259
- idx_t Count() const;
29260
- //! The remaining number of rows to be read from this object
29261
- idx_t Remaining() const;
29262
- //! Initialize this block to write data to
29263
- void InitializeWrite();
29264
- //! Init new block to write to
29265
- void CreateBlock();
29266
- //! Pins radix block with given index
29267
- void PinRadix(idx_t pin_block_idx);
29268
- //! Fill this sorted block by appending the blocks held by a vector of sorted blocks
29269
- void AppendSortedBlocks(vector<unique_ptr<SortedBlock>> &sorted_blocks);
29270
- //! Locate the block and entry index of a row in this block,
29271
- //! given an index between 0 and the total number of rows in this block
29272
- void GlobalToLocalIndex(const idx_t &global_idx, idx_t &local_block_index, idx_t &local_entry_index);
29273
- //! Create a slice that holds the rows between the start and end indices
29274
- unique_ptr<SortedBlock> CreateSlice(const idx_t start, const idx_t end);
29275
-
29276
- //! Size (in bytes) of the heap of this block
29277
- idx_t HeapSize() const;
29278
- //! Total size (in bytes) of this block
29279
- idx_t SizeInBytes() const;
29280
-
29281
- public:
29282
- //! Radix/memcmp sortable data
29283
- vector<RowDataBlock> radix_sorting_data;
29284
- unique_ptr<BufferHandle> radix_handle;
29285
- idx_t block_idx;
29286
- idx_t entry_idx;
29287
- //! Variable sized sorting data
29288
- unique_ptr<SortedData> blob_sorting_data;
29289
- //! Payload data
29290
- unique_ptr<SortedData> payload_data;
29291
-
29292
- private:
29293
- //! Buffer manager, and sorting layout constants
29294
- BufferManager &buffer_manager;
29295
- GlobalSortState &state;
29296
- const SortLayout &sort_layout;
29297
- const RowLayout &payload_layout;
29298
- };
29299
-
29300
- struct SortedDataScanner {
29301
- public:
29302
- SortedDataScanner(SortedData &sorted_data, GlobalSortState &global_sort_state);
29303
-
29304
- //! Scans the next data chunk from the sorted data
29305
- void Scan(DataChunk &chunk);
29306
-
29307
- private:
29308
- //! The sorted data being scanned
29309
- SortedData &sorted_data;
29310
- //! The total count of sorted_data
29311
- const idx_t total_count;
29312
- //! The global sort state
29313
- GlobalSortState &global_sort_state;
29314
- //! Addresses used to gather from the sorted data
29315
- Vector addresses = Vector(LogicalType::POINTER);
29316
- //! The number of rows scanned so far
29317
- idx_t total_scanned;
29318
- };
29319
-
29320
- } // namespace duckdb
29321
29181
 
29322
29182
 
29183
+ template <size_t SIZE>
29184
+ static inline void MemcpyFixed(void *dest, const void *src) {
29185
+ memcpy(dest, src, SIZE);
29186
+ }
29323
29187
 
29324
-
29325
- namespace duckdb {
29326
-
29327
- class RowLayout;
29328
- struct LocalSortState;
29329
-
29330
- struct SortConstants {
29331
- static constexpr idx_t VALUES_PER_RADIX = 256;
29332
- static constexpr idx_t MSD_RADIX_LOCATIONS = VALUES_PER_RADIX + 1;
29333
- static constexpr idx_t INSERTION_SORT_THRESHOLD = 24;
29334
- static constexpr idx_t MSD_RADIX_SORT_SIZE_THRESHOLD = 4;
29335
- };
29336
-
29337
- struct SortLayout {
29338
- public:
29339
- explicit SortLayout(const vector<BoundOrderByNode> &orders);
29340
-
29341
- public:
29342
- idx_t column_count;
29343
- vector<OrderType> order_types;
29344
- vector<OrderByNullType> order_by_null_types;
29345
- vector<LogicalType> logical_types;
29346
-
29347
- bool all_constant;
29348
- vector<bool> constant_size;
29349
- vector<idx_t> column_sizes;
29350
- vector<idx_t> prefix_lengths;
29351
- vector<BaseStatistics *> stats;
29352
- vector<bool> has_null;
29353
-
29354
- idx_t comparison_size;
29355
- idx_t entry_size;
29356
-
29357
- RowLayout blob_layout;
29358
- unordered_map<idx_t, idx_t> sorting_to_blob_col;
29359
- };
29360
-
29361
- struct GlobalSortState {
29362
- public:
29363
- GlobalSortState(BufferManager &buffer_manager, const vector<BoundOrderByNode> &orders, RowLayout &payload_layout);
29364
-
29365
- //! Add local state sorted data to this global state
29366
- void AddLocalState(LocalSortState &local_sort_state);
29367
- //! Prepares the GlobalSortState for the merge sort phase (after completing radix sort phase)
29368
- void PrepareMergePhase();
29369
- //! Initializes the global sort state for another round of merging
29370
- void InitializeMergeRound();
29371
- //! Completes the cascaded merge sort round
29372
- void CompleteMergeRound();
29373
-
29374
- public:
29375
- //! The lock for updating the order global state
29376
- mutex lock;
29377
- //! The buffer manager
29378
- BufferManager &buffer_manager;
29379
-
29380
- //! Sorting and payload layouts
29381
- const SortLayout sort_layout;
29382
- const RowLayout payload_layout;
29383
-
29384
- //! Sorted data
29385
- vector<unique_ptr<SortedBlock>> sorted_blocks;
29386
- vector<vector<unique_ptr<SortedBlock>>> sorted_blocks_temp;
29387
- unique_ptr<SortedBlock> odd_one_out;
29388
-
29389
- //! Pinned heap data (if sorting in memory)
29390
- vector<RowDataBlock> heap_blocks;
29391
- vector<unique_ptr<BufferHandle>> pinned_blocks;
29392
-
29393
- //! Capacity (number of rows) used to initialize blocks
29394
- idx_t block_capacity;
29395
- //! Whether we are doing an external sort
29396
- bool external;
29397
-
29398
- //! Progress in merge path stage
29399
- idx_t pair_idx;
29400
- idx_t num_pairs;
29401
- idx_t l_start;
29402
- idx_t r_start;
29403
- };
29404
-
29405
- struct LocalSortState {
29406
- public:
29407
- LocalSortState();
29408
-
29409
- //! Initialize the layouts and RowDataCollections
29410
- void Initialize(GlobalSortState &global_sort_state, BufferManager &buffer_manager_p);
29411
- //! Sink one DataChunk into the local sort state
29412
- void SinkChunk(DataChunk &sort, DataChunk &payload);
29413
- //! Size of accumulated data in bytes
29414
- idx_t SizeInBytes() const;
29415
- //! Sort the data accumulated so far
29416
- void Sort(GlobalSortState &global_sort_state, bool reorder_heap);
29417
-
29418
- private:
29419
- //! Concatenate the blocks held by a RowDataCollection into a single block
29420
- RowDataBlock ConcatenateBlocks(RowDataCollection &row_data);
29421
- //! Sorts the data in the newly created SortedBlock
29422
- void SortInMemory();
29423
- //! Re-order the local state after sorting
29424
- void ReOrder(GlobalSortState &gstate, bool reorder_heap);
29425
- //! Re-order a SortedData object after sorting
29426
- void ReOrder(SortedData &sd, data_ptr_t sorting_ptr, RowDataCollection &heap, GlobalSortState &gstate,
29427
- bool reorder_heap);
29428
-
29429
- public:
29430
- //! Whether this local state has been initialized
29431
- bool initialized;
29432
- //! The buffer manager
29433
- BufferManager *buffer_manager;
29434
- //! The sorting and payload layouts
29435
- const SortLayout *sort_layout;
29436
- const RowLayout *payload_layout;
29437
- //! Radix/memcmp sortable data
29438
- unique_ptr<RowDataCollection> radix_sorting_data;
29439
- //! Variable sized sorting data and accompanying heap
29440
- unique_ptr<RowDataCollection> blob_sorting_data;
29441
- unique_ptr<RowDataCollection> blob_sorting_heap;
29442
- //! Payload data and accompanying heap
29443
- unique_ptr<RowDataCollection> payload_data;
29444
- unique_ptr<RowDataCollection> payload_heap;
29445
- //! Sorted data
29446
- vector<unique_ptr<SortedBlock>> sorted_blocks;
29447
-
29448
- private:
29449
- //! Selection vector and addresses for scattering the data to rows
29450
- const SelectionVector &sel_ptr = FlatVector::INCREMENTAL_SELECTION_VECTOR;
29451
- Vector addresses = Vector(LogicalType::POINTER);
29452
- };
29453
-
29454
- struct MergeSorter {
29455
- public:
29456
- MergeSorter(GlobalSortState &state, BufferManager &buffer_manager);
29457
-
29458
- //! Finds and merges partitions until the current cascaded merge round is finished
29459
- void PerformInMergeRound();
29460
-
29461
- private:
29462
- //! Computes the left and right block that will be merged next (Merge Path partition)
29463
- void GetNextPartition();
29464
- //! Finds the boundary of the next partition using binary search
29465
- void GetIntersection(SortedBlock &l, SortedBlock &r, const idx_t diagonal, idx_t &l_idx, idx_t &r_idx);
29466
- //! Compare values within SortedBlocks using a global index
29467
- int CompareUsingGlobalIndex(SortedBlock &l, SortedBlock &r, const idx_t l_idx, const idx_t r_idx);
29468
-
29469
- //! Finds the next partition and merges it
29470
- void MergePartition();
29471
-
29472
- //! Computes how the next 'count' tuples should be merged by setting the 'left_smaller' array
29473
- void ComputeMerge(const idx_t &count, bool left_smaller[]);
29474
-
29475
- //! Merges the radix sorting blocks according to the 'left_smaller' array
29476
- void MergeRadix(const idx_t &count, const bool left_smaller[]);
29477
- //! Merges SortedData according to the 'left_smaller' array
29478
- void MergeData(SortedData &result_data, SortedData &l_data, SortedData &r_data, const idx_t &count,
29479
- const bool left_smaller[], idx_t next_entry_sizes[]);
29480
- //! Merges constant size rows according to the 'left_smaller' array
29481
- void MergeRows(data_ptr_t &l_ptr, idx_t &l_entry_idx, const idx_t &l_count, data_ptr_t &r_ptr, idx_t &r_entry_idx,
29482
- const idx_t &r_count, RowDataBlock *target_block, data_ptr_t &target_ptr, const idx_t &entry_size,
29483
- const bool left_smaller[], idx_t &copied, const idx_t &count);
29484
- //! Flushes constant size rows into the result
29485
- void FlushRows(data_ptr_t &source_ptr, idx_t &source_entry_idx, const idx_t &source_count,
29486
- RowDataBlock *target_block, data_ptr_t &target_ptr, const idx_t &entry_size, idx_t &copied,
29487
- const idx_t &count);
29488
- //! Flushes blob rows and accompanying heap
29489
- void FlushBlobs(const RowLayout &layout, const idx_t &source_count, data_ptr_t &source_data_ptr,
29490
- idx_t &source_entry_idx, data_ptr_t &source_heap_ptr, RowDataBlock *target_data_block,
29491
- data_ptr_t &target_data_ptr, RowDataBlock *target_heap_block, BufferHandle &target_heap_handle,
29492
- data_ptr_t &target_heap_ptr, idx_t &copied, const idx_t &count);
29493
-
29494
- private:
29495
- //! The global sorting state
29496
- GlobalSortState &state;
29497
- //! The sorting and payload layouts
29498
- BufferManager &buffer_manager;
29499
- const SortLayout &sort_layout;
29500
-
29501
- //! The left, right and result blocks of the current partition
29502
- unique_ptr<SortedBlock> left_block;
29503
- unique_ptr<SortedBlock> right_block;
29504
- SortedBlock *result;
29505
- };
29506
-
29507
- } // namespace duckdb
29508
-
29509
-
29510
- namespace duckdb {
29511
-
29512
- bool Comparators::TieIsBreakable(const idx_t &col_idx, const data_ptr_t row_ptr, const RowLayout &row_layout) {
29513
- // Check if the blob is NULL
29514
- ValidityBytes row_mask(row_ptr);
29515
- idx_t entry_idx;
29516
- idx_t idx_in_entry;
29517
- ValidityBytes::GetEntryIndex(col_idx, entry_idx, idx_in_entry);
29518
- if (!row_mask.RowIsValid(row_mask.GetValidityEntry(entry_idx), idx_in_entry)) {
29519
- // Can't break a NULL tie
29520
- return false;
29521
- }
29522
- if (row_layout.GetTypes()[col_idx].InternalType() == PhysicalType::VARCHAR) {
29523
- const auto &tie_col_offset = row_layout.GetOffsets()[col_idx];
29524
- string_t tie_string = Load<string_t>(row_ptr + tie_col_offset);
29525
- if (tie_string.GetSize() < string_t::INLINE_LENGTH) {
29526
- // No need to break the tie - we already compared the full string
29527
- return false;
29528
- }
29529
- }
29530
- return true;
29531
- }
29532
-
29533
- int Comparators::CompareTuple(const SortedBlock &left, const SortedBlock &right, const data_ptr_t &l_ptr,
29534
- const data_ptr_t &r_ptr, const SortLayout &sort_layout, const bool &external_sort) {
29535
- // Compare the sorting columns one by one
29536
- int comp_res = 0;
29537
- data_ptr_t l_ptr_offset = l_ptr;
29538
- data_ptr_t r_ptr_offset = r_ptr;
29539
- for (idx_t col_idx = 0; col_idx < sort_layout.column_count; col_idx++) {
29540
- comp_res = memcmp(l_ptr_offset, r_ptr_offset, sort_layout.column_sizes[col_idx]);
29541
- if (comp_res == 0 && !sort_layout.constant_size[col_idx]) {
29542
- comp_res =
29543
- BreakBlobTie(col_idx, *left.blob_sorting_data, *right.blob_sorting_data, sort_layout, external_sort);
29544
- }
29545
- if (comp_res != 0) {
29546
- break;
29547
- }
29548
- l_ptr_offset += sort_layout.column_sizes[col_idx];
29549
- r_ptr_offset += sort_layout.column_sizes[col_idx];
29550
- }
29551
- return comp_res;
29552
- }
29553
-
29554
- int Comparators::CompareVal(const data_ptr_t l_ptr, const data_ptr_t r_ptr, const LogicalType &type) {
29555
- switch (type.InternalType()) {
29556
- case PhysicalType::VARCHAR:
29557
- return TemplatedCompareVal<string_t>(l_ptr, r_ptr);
29558
- case PhysicalType::LIST:
29559
- case PhysicalType::STRUCT: {
29560
- auto l_nested_ptr = Load<data_ptr_t>(l_ptr);
29561
- auto r_nested_ptr = Load<data_ptr_t>(r_ptr);
29562
- return CompareValAndAdvance(l_nested_ptr, r_nested_ptr, type);
29563
- }
29564
- default:
29565
- throw NotImplementedException("Unimplemented CompareVal for type %s", type.ToString());
29566
- }
29567
- }
29568
-
29569
- int Comparators::BreakBlobTie(const idx_t &tie_col, const SortedData &left, const SortedData &right,
29570
- const SortLayout &sort_layout, const bool &external) {
29571
- const idx_t &col_idx = sort_layout.sorting_to_blob_col.at(tie_col);
29572
- data_ptr_t l_data_ptr = left.DataPtr();
29573
- data_ptr_t r_data_ptr = right.DataPtr();
29574
- if (!TieIsBreakable(col_idx, l_data_ptr, sort_layout.blob_layout)) {
29575
- // Quick check to see if ties can be broken
29576
- return 0;
29577
- }
29578
- // Align the pointers
29579
- const auto &tie_col_offset = sort_layout.blob_layout.GetOffsets()[col_idx];
29580
- l_data_ptr += tie_col_offset;
29581
- r_data_ptr += tie_col_offset;
29582
- // Do the comparison
29583
- const int order = sort_layout.order_types[tie_col] == OrderType::DESCENDING ? -1 : 1;
29584
- const auto &type = left.layout.GetTypes()[col_idx];
29585
- int result;
29586
- if (external) {
29587
- // Store heap pointers
29588
- data_ptr_t l_heap_ptr = left.HeapPtr();
29589
- data_ptr_t r_heap_ptr = right.HeapPtr();
29590
- // Unswizzle offset to pointer
29591
- UnswizzleSingleValue(l_data_ptr, l_heap_ptr, type);
29592
- UnswizzleSingleValue(r_data_ptr, r_heap_ptr, type);
29593
- // Compare
29594
- result = CompareVal(l_data_ptr, r_data_ptr, type);
29595
- // Swizzle the pointers back to offsets
29596
- SwizzleSingleValue(l_data_ptr, l_heap_ptr, type);
29597
- SwizzleSingleValue(r_data_ptr, r_heap_ptr, type);
29598
- } else {
29599
- result = CompareVal(l_data_ptr, r_data_ptr, type);
29600
- }
29601
- return order * result;
29602
- }
29603
-
29604
- template <class T>
29605
- int Comparators::TemplatedCompareVal(const data_ptr_t &left_ptr, const data_ptr_t &right_ptr) {
29606
- const auto left_val = Load<T>(left_ptr);
29607
- const auto right_val = Load<T>(right_ptr);
29608
- if (Equals::Operation<T>(left_val, right_val)) {
29609
- return 0;
29610
- } else if (LessThan::Operation<T>(left_val, right_val)) {
29611
- return -1;
29612
- } else {
29613
- return 1;
29614
- }
29615
- }
29616
-
29617
- int Comparators::CompareValAndAdvance(data_ptr_t &l_ptr, data_ptr_t &r_ptr, const LogicalType &type) {
29618
- switch (type.InternalType()) {
29619
- case PhysicalType::BOOL:
29620
- case PhysicalType::INT8:
29621
- return TemplatedCompareAndAdvance<int8_t>(l_ptr, r_ptr);
29622
- case PhysicalType::INT16:
29623
- return TemplatedCompareAndAdvance<int16_t>(l_ptr, r_ptr);
29624
- case PhysicalType::INT32:
29625
- return TemplatedCompareAndAdvance<int32_t>(l_ptr, r_ptr);
29626
- case PhysicalType::INT64:
29627
- return TemplatedCompareAndAdvance<int64_t>(l_ptr, r_ptr);
29628
- case PhysicalType::UINT8:
29629
- return TemplatedCompareAndAdvance<uint8_t>(l_ptr, r_ptr);
29630
- case PhysicalType::UINT16:
29631
- return TemplatedCompareAndAdvance<uint16_t>(l_ptr, r_ptr);
29632
- case PhysicalType::UINT32:
29633
- return TemplatedCompareAndAdvance<uint32_t>(l_ptr, r_ptr);
29634
- case PhysicalType::UINT64:
29635
- return TemplatedCompareAndAdvance<uint64_t>(l_ptr, r_ptr);
29636
- case PhysicalType::INT128:
29637
- return TemplatedCompareAndAdvance<hugeint_t>(l_ptr, r_ptr);
29638
- case PhysicalType::FLOAT:
29639
- return TemplatedCompareAndAdvance<float>(l_ptr, r_ptr);
29640
- case PhysicalType::DOUBLE:
29641
- return TemplatedCompareAndAdvance<double>(l_ptr, r_ptr);
29642
- case PhysicalType::INTERVAL:
29643
- return TemplatedCompareAndAdvance<interval_t>(l_ptr, r_ptr);
29644
- case PhysicalType::VARCHAR:
29645
- return CompareStringAndAdvance(l_ptr, r_ptr);
29646
- case PhysicalType::LIST:
29647
- return CompareListAndAdvance(l_ptr, r_ptr, ListType::GetChildType(type));
29648
- case PhysicalType::STRUCT:
29649
- return CompareStructAndAdvance(l_ptr, r_ptr, StructType::GetChildTypes(type));
29650
- default:
29651
- throw NotImplementedException("Unimplemented CompareValAndAdvance for type %s", type.ToString());
29652
- }
29653
- }
29654
-
29655
- template <class T>
29656
- int Comparators::TemplatedCompareAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr) {
29657
- auto result = TemplatedCompareVal<T>(left_ptr, right_ptr);
29658
- left_ptr += sizeof(T);
29659
- right_ptr += sizeof(T);
29660
- return result;
29661
- }
29662
-
29663
- int Comparators::CompareStringAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr) {
29664
- // Construct the string_t
29665
- uint32_t left_string_size = Load<uint32_t>(left_ptr);
29666
- uint32_t right_string_size = Load<uint32_t>(right_ptr);
29667
- left_ptr += sizeof(uint32_t);
29668
- right_ptr += sizeof(uint32_t);
29669
- string_t left_val((const char *)left_ptr, left_string_size);
29670
- string_t right_val((const char *)right_ptr, right_string_size);
29671
- left_ptr += left_string_size;
29672
- right_ptr += right_string_size;
29673
- // Compare
29674
- return TemplatedCompareVal<string_t>((data_ptr_t)&left_val, (data_ptr_t)&right_val);
29675
- }
29676
-
29677
- int Comparators::CompareStructAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr,
29678
- const child_list_t<LogicalType> &types) {
29679
- idx_t count = types.size();
29680
- // Load validity masks
29681
- ValidityBytes left_validity(left_ptr);
29682
- ValidityBytes right_validity(right_ptr);
29683
- left_ptr += (count + 7) / 8;
29684
- right_ptr += (count + 7) / 8;
29685
- // Initialize variables
29686
- bool left_valid;
29687
- bool right_valid;
29688
- idx_t entry_idx;
29689
- idx_t idx_in_entry;
29690
- // Compare
29691
- int comp_res = 0;
29692
- for (idx_t i = 0; i < count; i++) {
29693
- ValidityBytes::GetEntryIndex(i, entry_idx, idx_in_entry);
29694
- left_valid = left_validity.RowIsValid(left_validity.GetValidityEntry(entry_idx), idx_in_entry);
29695
- right_valid = right_validity.RowIsValid(right_validity.GetValidityEntry(entry_idx), idx_in_entry);
29696
- auto &type = types[i].second;
29697
- if ((left_valid && right_valid) || TypeIsConstantSize(type.InternalType())) {
29698
- comp_res = CompareValAndAdvance(left_ptr, right_ptr, types[i].second);
29699
- }
29700
- if (!left_valid && !right_valid) {
29701
- comp_res = 0;
29702
- } else if (!left_valid) {
29703
- comp_res = 1;
29704
- } else if (!right_valid) {
29705
- comp_res = -1;
29706
- }
29707
- if (comp_res != 0) {
29708
- break;
29709
- }
29710
- }
29711
- return comp_res;
29712
- }
29713
-
29714
- int Comparators::CompareListAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr, const LogicalType &type) {
29715
- // Load list lengths
29716
- auto left_len = Load<idx_t>(left_ptr);
29717
- auto right_len = Load<idx_t>(right_ptr);
29718
- left_ptr += sizeof(idx_t);
29719
- right_ptr += sizeof(idx_t);
29720
- // Load list validity masks
29721
- ValidityBytes left_validity(left_ptr);
29722
- ValidityBytes right_validity(right_ptr);
29723
- left_ptr += (left_len + 7) / 8;
29724
- right_ptr += (right_len + 7) / 8;
29725
- // Compare
29726
- int comp_res = 0;
29727
- idx_t count = MinValue(left_len, right_len);
29728
- if (TypeIsConstantSize(type.InternalType())) {
29729
- // Templated code for fixed-size types
29730
- switch (type.InternalType()) {
29731
- case PhysicalType::BOOL:
29732
- case PhysicalType::INT8:
29733
- comp_res = TemplatedCompareListLoop<int8_t>(left_ptr, right_ptr, left_validity, right_validity, count);
29734
- break;
29735
- case PhysicalType::INT16:
29736
- comp_res = TemplatedCompareListLoop<int16_t>(left_ptr, right_ptr, left_validity, right_validity, count);
29737
- break;
29738
- case PhysicalType::INT32:
29739
- comp_res = TemplatedCompareListLoop<int32_t>(left_ptr, right_ptr, left_validity, right_validity, count);
29740
- break;
29741
- case PhysicalType::INT64:
29742
- comp_res = TemplatedCompareListLoop<int64_t>(left_ptr, right_ptr, left_validity, right_validity, count);
29743
- break;
29744
- case PhysicalType::UINT8:
29745
- comp_res = TemplatedCompareListLoop<uint8_t>(left_ptr, right_ptr, left_validity, right_validity, count);
29746
- break;
29747
- case PhysicalType::UINT16:
29748
- comp_res = TemplatedCompareListLoop<uint16_t>(left_ptr, right_ptr, left_validity, right_validity, count);
29749
- break;
29750
- case PhysicalType::UINT32:
29751
- comp_res = TemplatedCompareListLoop<uint32_t>(left_ptr, right_ptr, left_validity, right_validity, count);
29752
- break;
29753
- case PhysicalType::UINT64:
29754
- comp_res = TemplatedCompareListLoop<uint64_t>(left_ptr, right_ptr, left_validity, right_validity, count);
29755
- break;
29756
- case PhysicalType::INT128:
29757
- comp_res = TemplatedCompareListLoop<hugeint_t>(left_ptr, right_ptr, left_validity, right_validity, count);
29758
- break;
29759
- case PhysicalType::FLOAT:
29760
- comp_res = TemplatedCompareListLoop<float>(left_ptr, right_ptr, left_validity, right_validity, count);
29761
- break;
29762
- case PhysicalType::DOUBLE:
29763
- comp_res = TemplatedCompareListLoop<double>(left_ptr, right_ptr, left_validity, right_validity, count);
29764
- break;
29765
- case PhysicalType::INTERVAL:
29766
- comp_res = TemplatedCompareListLoop<interval_t>(left_ptr, right_ptr, left_validity, right_validity, count);
29767
- break;
29768
- default:
29769
- throw NotImplementedException("CompareListAndAdvance for fixed-size type %s", type.ToString());
29770
- }
29771
- } else {
29772
- // Variable-sized list entries
29773
- bool left_valid;
29774
- bool right_valid;
29775
- idx_t entry_idx;
29776
- idx_t idx_in_entry;
29777
- // Size (in bytes) of all variable-sizes entries is stored before the entries begin,
29778
- // to make deserialization easier. We need to skip over them
29779
- left_ptr += left_len * sizeof(idx_t);
29780
- right_ptr += right_len * sizeof(idx_t);
29781
- for (idx_t i = 0; i < count; i++) {
29782
- ValidityBytes::GetEntryIndex(i, entry_idx, idx_in_entry);
29783
- left_valid = left_validity.RowIsValid(left_validity.GetValidityEntry(entry_idx), idx_in_entry);
29784
- right_valid = right_validity.RowIsValid(right_validity.GetValidityEntry(entry_idx), idx_in_entry);
29785
- if (left_valid && right_valid) {
29786
- switch (type.InternalType()) {
29787
- case PhysicalType::LIST:
29788
- comp_res = CompareListAndAdvance(left_ptr, right_ptr, ListType::GetChildType(type));
29789
- break;
29790
- case PhysicalType::VARCHAR:
29791
- comp_res = CompareStringAndAdvance(left_ptr, right_ptr);
29792
- break;
29793
- case PhysicalType::STRUCT:
29794
- comp_res = CompareStructAndAdvance(left_ptr, right_ptr, StructType::GetChildTypes(type));
29795
- break;
29796
- default:
29797
- throw NotImplementedException("CompareListAndAdvance for variable-size type %s", type.ToString());
29798
- }
29799
- } else if (!left_valid && !right_valid) {
29800
- comp_res = 0;
29801
- } else if (left_valid) {
29802
- comp_res = -1;
29803
- } else {
29804
- comp_res = 1;
29805
- }
29806
- if (comp_res != 0) {
29807
- break;
29808
- }
29809
- }
29810
- }
29811
- // All values that we looped over were equal
29812
- if (comp_res == 0 && left_len != right_len) {
29813
- // Smaller lists first
29814
- if (left_len < right_len) {
29815
- comp_res = -1;
29816
- } else {
29817
- comp_res = 1;
29818
- }
29819
- }
29820
- return comp_res;
29821
- }
29822
-
29823
- template <class T>
29824
- int Comparators::TemplatedCompareListLoop(data_ptr_t &left_ptr, data_ptr_t &right_ptr,
29825
- const ValidityBytes &left_validity, const ValidityBytes &right_validity,
29826
- const idx_t &count) {
29827
- int comp_res = 0;
29828
- bool left_valid;
29829
- bool right_valid;
29830
- idx_t entry_idx;
29831
- idx_t idx_in_entry;
29832
- for (idx_t i = 0; i < count; i++) {
29833
- ValidityBytes::GetEntryIndex(i, entry_idx, idx_in_entry);
29834
- left_valid = left_validity.RowIsValid(left_validity.GetValidityEntry(entry_idx), idx_in_entry);
29835
- right_valid = right_validity.RowIsValid(right_validity.GetValidityEntry(entry_idx), idx_in_entry);
29836
- comp_res = TemplatedCompareAndAdvance<T>(left_ptr, right_ptr);
29837
- if (!left_valid && !right_valid) {
29838
- comp_res = 0;
29839
- } else if (!left_valid) {
29840
- comp_res = 1;
29841
- } else if (!right_valid) {
29842
- comp_res = -1;
29843
- }
29844
- if (comp_res != 0) {
29845
- break;
29846
- }
29847
- }
29848
- return comp_res;
29849
- }
29850
-
29851
- void Comparators::UnswizzleSingleValue(data_ptr_t data_ptr, const data_ptr_t &heap_ptr, const LogicalType &type) {
29852
- if (type.InternalType() == PhysicalType::VARCHAR) {
29853
- data_ptr += sizeof(uint32_t) + string_t::PREFIX_LENGTH;
29854
- }
29855
- Store<data_ptr_t>(heap_ptr + Load<idx_t>(data_ptr), data_ptr);
29856
- }
29857
-
29858
- void Comparators::SwizzleSingleValue(data_ptr_t data_ptr, const data_ptr_t &heap_ptr, const LogicalType &type) {
29859
- if (type.InternalType() == PhysicalType::VARCHAR) {
29860
- data_ptr += sizeof(uint32_t) + string_t::PREFIX_LENGTH;
29861
- }
29862
- Store<idx_t>(Load<data_ptr_t>(data_ptr) - heap_ptr, data_ptr);
29863
- }
29864
-
29865
- } // namespace duckdb
29866
- // DuckDB
29867
- //
29868
- // duckdb/common/fast_mem.hpp
29869
- //
29870
- //
29871
- //===----------------------------------------------------------------------===//
29872
-
29873
-
29874
-
29875
-
29876
-
29877
-
29878
- template <size_t SIZE>
29879
- static inline void MemcpyFixed(void *dest, const void *src) {
29880
- memcpy(dest, src, SIZE);
29881
- }
29882
-
29883
- template <size_t SIZE>
29884
- static inline int MemcmpFixed(const void *str1, const void *str2) {
29885
- return memcmp(str1, str2, SIZE);
29886
- }
29188
+ template <size_t SIZE>
29189
+ static inline int MemcmpFixed(const void *str1, const void *str2) {
29190
+ return memcmp(str1, str2, SIZE);
29191
+ }
29887
29192
 
29888
29193
  namespace duckdb {
29889
29194
 
@@ -30408,151 +29713,847 @@ static inline void FastMemcpy(void *dest, const void *src, const size_t size) {
30408
29713
  case 256:
30409
29714
  return MemcpyFixed<256>(dest, src);
30410
29715
  default:
30411
- memcpy(dest, src, size);
29716
+ memcpy(dest, src, size);
29717
+ }
29718
+ // LCOV_EXCL_STOP
29719
+ }
29720
+
29721
+ //! This templated memcmp is significantly faster than std::memcmp,
29722
+ //! but only when you are calling memcmp with a const size in a loop.
29723
+ //! For instance `while (<cond>) { memcmp(<str1>, <str2>, const_size); ... }`
29724
+ static inline int FastMemcmp(const void *str1, const void *str2, const size_t size) {
29725
+ // LCOV_EXCL_START
29726
+ switch (size) {
29727
+ case 0:
29728
+ return 0;
29729
+ case 1:
29730
+ return MemcmpFixed<1>(str1, str2);
29731
+ case 2:
29732
+ return MemcmpFixed<2>(str1, str2);
29733
+ case 3:
29734
+ return MemcmpFixed<3>(str1, str2);
29735
+ case 4:
29736
+ return MemcmpFixed<4>(str1, str2);
29737
+ case 5:
29738
+ return MemcmpFixed<5>(str1, str2);
29739
+ case 6:
29740
+ return MemcmpFixed<6>(str1, str2);
29741
+ case 7:
29742
+ return MemcmpFixed<7>(str1, str2);
29743
+ case 8:
29744
+ return MemcmpFixed<8>(str1, str2);
29745
+ case 9:
29746
+ return MemcmpFixed<9>(str1, str2);
29747
+ case 10:
29748
+ return MemcmpFixed<10>(str1, str2);
29749
+ case 11:
29750
+ return MemcmpFixed<11>(str1, str2);
29751
+ case 12:
29752
+ return MemcmpFixed<12>(str1, str2);
29753
+ case 13:
29754
+ return MemcmpFixed<13>(str1, str2);
29755
+ case 14:
29756
+ return MemcmpFixed<14>(str1, str2);
29757
+ case 15:
29758
+ return MemcmpFixed<15>(str1, str2);
29759
+ case 16:
29760
+ return MemcmpFixed<16>(str1, str2);
29761
+ case 17:
29762
+ return MemcmpFixed<17>(str1, str2);
29763
+ case 18:
29764
+ return MemcmpFixed<18>(str1, str2);
29765
+ case 19:
29766
+ return MemcmpFixed<19>(str1, str2);
29767
+ case 20:
29768
+ return MemcmpFixed<20>(str1, str2);
29769
+ case 21:
29770
+ return MemcmpFixed<21>(str1, str2);
29771
+ case 22:
29772
+ return MemcmpFixed<22>(str1, str2);
29773
+ case 23:
29774
+ return MemcmpFixed<23>(str1, str2);
29775
+ case 24:
29776
+ return MemcmpFixed<24>(str1, str2);
29777
+ case 25:
29778
+ return MemcmpFixed<25>(str1, str2);
29779
+ case 26:
29780
+ return MemcmpFixed<26>(str1, str2);
29781
+ case 27:
29782
+ return MemcmpFixed<27>(str1, str2);
29783
+ case 28:
29784
+ return MemcmpFixed<28>(str1, str2);
29785
+ case 29:
29786
+ return MemcmpFixed<29>(str1, str2);
29787
+ case 30:
29788
+ return MemcmpFixed<30>(str1, str2);
29789
+ case 31:
29790
+ return MemcmpFixed<31>(str1, str2);
29791
+ case 32:
29792
+ return MemcmpFixed<32>(str1, str2);
29793
+ case 33:
29794
+ return MemcmpFixed<33>(str1, str2);
29795
+ case 34:
29796
+ return MemcmpFixed<34>(str1, str2);
29797
+ case 35:
29798
+ return MemcmpFixed<35>(str1, str2);
29799
+ case 36:
29800
+ return MemcmpFixed<36>(str1, str2);
29801
+ case 37:
29802
+ return MemcmpFixed<37>(str1, str2);
29803
+ case 38:
29804
+ return MemcmpFixed<38>(str1, str2);
29805
+ case 39:
29806
+ return MemcmpFixed<39>(str1, str2);
29807
+ case 40:
29808
+ return MemcmpFixed<40>(str1, str2);
29809
+ case 41:
29810
+ return MemcmpFixed<41>(str1, str2);
29811
+ case 42:
29812
+ return MemcmpFixed<42>(str1, str2);
29813
+ case 43:
29814
+ return MemcmpFixed<43>(str1, str2);
29815
+ case 44:
29816
+ return MemcmpFixed<44>(str1, str2);
29817
+ case 45:
29818
+ return MemcmpFixed<45>(str1, str2);
29819
+ case 46:
29820
+ return MemcmpFixed<46>(str1, str2);
29821
+ case 47:
29822
+ return MemcmpFixed<47>(str1, str2);
29823
+ case 48:
29824
+ return MemcmpFixed<48>(str1, str2);
29825
+ case 49:
29826
+ return MemcmpFixed<49>(str1, str2);
29827
+ case 50:
29828
+ return MemcmpFixed<50>(str1, str2);
29829
+ case 51:
29830
+ return MemcmpFixed<51>(str1, str2);
29831
+ case 52:
29832
+ return MemcmpFixed<52>(str1, str2);
29833
+ case 53:
29834
+ return MemcmpFixed<53>(str1, str2);
29835
+ case 54:
29836
+ return MemcmpFixed<54>(str1, str2);
29837
+ case 55:
29838
+ return MemcmpFixed<55>(str1, str2);
29839
+ case 56:
29840
+ return MemcmpFixed<56>(str1, str2);
29841
+ case 57:
29842
+ return MemcmpFixed<57>(str1, str2);
29843
+ case 58:
29844
+ return MemcmpFixed<58>(str1, str2);
29845
+ case 59:
29846
+ return MemcmpFixed<59>(str1, str2);
29847
+ case 60:
29848
+ return MemcmpFixed<60>(str1, str2);
29849
+ case 61:
29850
+ return MemcmpFixed<61>(str1, str2);
29851
+ case 62:
29852
+ return MemcmpFixed<62>(str1, str2);
29853
+ case 63:
29854
+ return MemcmpFixed<63>(str1, str2);
29855
+ case 64:
29856
+ return MemcmpFixed<64>(str1, str2);
29857
+ default:
29858
+ return memcmp(str1, str2, size);
29859
+ }
29860
+ // LCOV_EXCL_STOP
29861
+ }
29862
+
29863
+ } // namespace duckdb
29864
+
29865
+ //===----------------------------------------------------------------------===//
29866
+ // DuckDB
29867
+ //
29868
+ // duckdb/common/sort/sort.hpp
29869
+ //
29870
+ //
29871
+ //===----------------------------------------------------------------------===//
29872
+
29873
+
29874
+
29875
+ //===----------------------------------------------------------------------===//
29876
+ // DuckDB
29877
+ //
29878
+ // duckdb/common/sort/sorted_block.hpp
29879
+ //
29880
+ //
29881
+ //===----------------------------------------------------------------------===//
29882
+
29883
+
29884
+
29885
+
29886
+ namespace duckdb {
29887
+
29888
+ class BufferManager;
29889
+ struct RowDataBlock;
29890
+ struct SortLayout;
29891
+ struct GlobalSortState;
29892
+
29893
+ //! Object that holds sorted rows, and an accompanying heap if there are blobs
29894
+ struct SortedData {
29895
+ public:
29896
+ SortedData(const RowLayout &layout, BufferManager &buffer_manager, GlobalSortState &state);
29897
+ //! Number of rows that this object holds
29898
+ idx_t Count();
29899
+ //! Pin the current block so it can be read
29900
+ void Pin();
29901
+ //! Pointer to the row that is currently being read from
29902
+ data_ptr_t DataPtr() const;
29903
+ //! Pointer to the heap row that corresponds to the current row
29904
+ data_ptr_t HeapPtr() const;
29905
+ //! Advance one row
29906
+ void Advance(const bool &adv);
29907
+ //! Initialize new block to write to
29908
+ void CreateBlock();
29909
+ //! Reset read indices to the given indices
29910
+ void ResetIndices(idx_t block_idx_to, idx_t entry_idx_to);
29911
+ //! Create a slice that holds the rows between the start and end indices
29912
+ unique_ptr<SortedData> CreateSlice(idx_t start_block_index, idx_t start_entry_index, idx_t end_block_index,
29913
+ idx_t end_entry_index);
29914
+ //! Unswizzles all
29915
+ void Unswizzle();
29916
+
29917
+ public:
29918
+ //! Layout of this data
29919
+ const RowLayout layout;
29920
+ //! Data and heap blocks
29921
+ vector<RowDataBlock> data_blocks;
29922
+ vector<RowDataBlock> heap_blocks;
29923
+ //! Buffer handles to the data being currently read
29924
+ unique_ptr<BufferHandle> data_handle;
29925
+ unique_ptr<BufferHandle> heap_handle;
29926
+ //! Read indices
29927
+ idx_t block_idx;
29928
+ idx_t entry_idx;
29929
+ //! Whether the pointers in this sorted data are swizzled
29930
+ bool swizzled;
29931
+
29932
+ private:
29933
+ //! Pin fixed-size row data
29934
+ void PinData();
29935
+ //! Pin the accompanying heap data (if any)
29936
+ void PinHeap();
29937
+
29938
+ private:
29939
+ //! The buffer manager
29940
+ BufferManager &buffer_manager;
29941
+ //! The global state
29942
+ GlobalSortState &state;
29943
+ //! Pointers into the buffers being currently read
29944
+ data_ptr_t data_ptr;
29945
+ data_ptr_t heap_ptr;
29946
+ };
29947
+
29948
+ //! Block that holds sorted rows: radix, blob and payload data
29949
+ struct SortedBlock {
29950
+ public:
29951
+ SortedBlock(BufferManager &buffer_manager, GlobalSortState &gstate);
29952
+ //! Number of rows that this object holds
29953
+ idx_t Count() const;
29954
+ //! The remaining number of rows to be read from this object
29955
+ idx_t Remaining() const;
29956
+ //! Initialize this block to write data to
29957
+ void InitializeWrite();
29958
+ //! Init new block to write to
29959
+ void CreateBlock();
29960
+ //! Pins radix block with given index
29961
+ void PinRadix(idx_t pin_block_idx);
29962
+ //! Fill this sorted block by appending the blocks held by a vector of sorted blocks
29963
+ void AppendSortedBlocks(vector<unique_ptr<SortedBlock>> &sorted_blocks);
29964
+ //! Locate the block and entry index of a row in this block,
29965
+ //! given an index between 0 and the total number of rows in this block
29966
+ void GlobalToLocalIndex(const idx_t &global_idx, idx_t &local_block_index, idx_t &local_entry_index);
29967
+ //! Create a slice that holds the rows between the start and end indices
29968
+ unique_ptr<SortedBlock> CreateSlice(const idx_t start, const idx_t end);
29969
+
29970
+ //! Size (in bytes) of the heap of this block
29971
+ idx_t HeapSize() const;
29972
+ //! Total size (in bytes) of this block
29973
+ idx_t SizeInBytes() const;
29974
+
29975
+ public:
29976
+ //! Radix/memcmp sortable data
29977
+ vector<RowDataBlock> radix_sorting_data;
29978
+ unique_ptr<BufferHandle> radix_handle;
29979
+ idx_t block_idx;
29980
+ idx_t entry_idx;
29981
+ //! Variable sized sorting data
29982
+ unique_ptr<SortedData> blob_sorting_data;
29983
+ //! Payload data
29984
+ unique_ptr<SortedData> payload_data;
29985
+
29986
+ private:
29987
+ //! Buffer manager, and sorting layout constants
29988
+ BufferManager &buffer_manager;
29989
+ GlobalSortState &state;
29990
+ const SortLayout &sort_layout;
29991
+ const RowLayout &payload_layout;
29992
+ };
29993
+
29994
+ struct SortedDataScanner {
29995
+ public:
29996
+ SortedDataScanner(SortedData &sorted_data, GlobalSortState &global_sort_state);
29997
+
29998
+ //! Scans the next data chunk from the sorted data
29999
+ void Scan(DataChunk &chunk);
30000
+
30001
+ private:
30002
+ //! The sorted data being scanned
30003
+ SortedData &sorted_data;
30004
+ //! The total count of sorted_data
30005
+ const idx_t total_count;
30006
+ //! The global sort state
30007
+ GlobalSortState &global_sort_state;
30008
+ //! Addresses used to gather from the sorted data
30009
+ Vector addresses = Vector(LogicalType::POINTER);
30010
+ //! The number of rows scanned so far
30011
+ idx_t total_scanned;
30012
+ };
30013
+
30014
+ } // namespace duckdb
30015
+
30016
+
30017
+
30018
+
30019
+ namespace duckdb {
30020
+
30021
+ class RowLayout;
30022
+ struct LocalSortState;
30023
+
30024
+ struct SortConstants {
30025
+ static constexpr idx_t VALUES_PER_RADIX = 256;
30026
+ static constexpr idx_t MSD_RADIX_LOCATIONS = VALUES_PER_RADIX + 1;
30027
+ static constexpr idx_t INSERTION_SORT_THRESHOLD = 24;
30028
+ static constexpr idx_t MSD_RADIX_SORT_SIZE_THRESHOLD = 4;
30029
+ };
30030
+
30031
+ struct SortLayout {
30032
+ public:
30033
+ explicit SortLayout(const vector<BoundOrderByNode> &orders);
30034
+
30035
+ public:
30036
+ idx_t column_count;
30037
+ vector<OrderType> order_types;
30038
+ vector<OrderByNullType> order_by_null_types;
30039
+ vector<LogicalType> logical_types;
30040
+
30041
+ bool all_constant;
30042
+ vector<bool> constant_size;
30043
+ vector<idx_t> column_sizes;
30044
+ vector<idx_t> prefix_lengths;
30045
+ vector<BaseStatistics *> stats;
30046
+ vector<bool> has_null;
30047
+
30048
+ idx_t comparison_size;
30049
+ idx_t entry_size;
30050
+
30051
+ RowLayout blob_layout;
30052
+ unordered_map<idx_t, idx_t> sorting_to_blob_col;
30053
+ };
30054
+
30055
+ struct GlobalSortState {
30056
+ public:
30057
+ GlobalSortState(BufferManager &buffer_manager, const vector<BoundOrderByNode> &orders, RowLayout &payload_layout);
30058
+
30059
+ //! Add local state sorted data to this global state
30060
+ void AddLocalState(LocalSortState &local_sort_state);
30061
+ //! Prepares the GlobalSortState for the merge sort phase (after completing radix sort phase)
30062
+ void PrepareMergePhase();
30063
+ //! Initializes the global sort state for another round of merging
30064
+ void InitializeMergeRound();
30065
+ //! Completes the cascaded merge sort round
30066
+ void CompleteMergeRound();
30067
+
30068
+ public:
30069
+ //! The lock for updating the order global state
30070
+ mutex lock;
30071
+ //! The buffer manager
30072
+ BufferManager &buffer_manager;
30073
+
30074
+ //! Sorting and payload layouts
30075
+ const SortLayout sort_layout;
30076
+ const RowLayout payload_layout;
30077
+
30078
+ //! Sorted data
30079
+ vector<unique_ptr<SortedBlock>> sorted_blocks;
30080
+ vector<vector<unique_ptr<SortedBlock>>> sorted_blocks_temp;
30081
+ unique_ptr<SortedBlock> odd_one_out;
30082
+
30083
+ //! Pinned heap data (if sorting in memory)
30084
+ vector<RowDataBlock> heap_blocks;
30085
+ vector<unique_ptr<BufferHandle>> pinned_blocks;
30086
+
30087
+ //! Capacity (number of rows) used to initialize blocks
30088
+ idx_t block_capacity;
30089
+ //! Whether we are doing an external sort
30090
+ bool external;
30091
+
30092
+ //! Progress in merge path stage
30093
+ idx_t pair_idx;
30094
+ idx_t num_pairs;
30095
+ idx_t l_start;
30096
+ idx_t r_start;
30097
+ };
30098
+
30099
+ struct LocalSortState {
30100
+ public:
30101
+ LocalSortState();
30102
+
30103
+ //! Initialize the layouts and RowDataCollections
30104
+ void Initialize(GlobalSortState &global_sort_state, BufferManager &buffer_manager_p);
30105
+ //! Sink one DataChunk into the local sort state
30106
+ void SinkChunk(DataChunk &sort, DataChunk &payload);
30107
+ //! Size of accumulated data in bytes
30108
+ idx_t SizeInBytes() const;
30109
+ //! Sort the data accumulated so far
30110
+ void Sort(GlobalSortState &global_sort_state, bool reorder_heap);
30111
+
30112
+ private:
30113
+ //! Concatenate the blocks held by a RowDataCollection into a single block
30114
+ RowDataBlock ConcatenateBlocks(RowDataCollection &row_data);
30115
+ //! Sorts the data in the newly created SortedBlock
30116
+ void SortInMemory();
30117
+ //! Re-order the local state after sorting
30118
+ void ReOrder(GlobalSortState &gstate, bool reorder_heap);
30119
+ //! Re-order a SortedData object after sorting
30120
+ void ReOrder(SortedData &sd, data_ptr_t sorting_ptr, RowDataCollection &heap, GlobalSortState &gstate,
30121
+ bool reorder_heap);
30122
+
30123
+ public:
30124
+ //! Whether this local state has been initialized
30125
+ bool initialized;
30126
+ //! The buffer manager
30127
+ BufferManager *buffer_manager;
30128
+ //! The sorting and payload layouts
30129
+ const SortLayout *sort_layout;
30130
+ const RowLayout *payload_layout;
30131
+ //! Radix/memcmp sortable data
30132
+ unique_ptr<RowDataCollection> radix_sorting_data;
30133
+ //! Variable sized sorting data and accompanying heap
30134
+ unique_ptr<RowDataCollection> blob_sorting_data;
30135
+ unique_ptr<RowDataCollection> blob_sorting_heap;
30136
+ //! Payload data and accompanying heap
30137
+ unique_ptr<RowDataCollection> payload_data;
30138
+ unique_ptr<RowDataCollection> payload_heap;
30139
+ //! Sorted data
30140
+ vector<unique_ptr<SortedBlock>> sorted_blocks;
30141
+
30142
+ private:
30143
+ //! Selection vector and addresses for scattering the data to rows
30144
+ const SelectionVector &sel_ptr = FlatVector::INCREMENTAL_SELECTION_VECTOR;
30145
+ Vector addresses = Vector(LogicalType::POINTER);
30146
+ };
30147
+
30148
+ struct MergeSorter {
30149
+ public:
30150
+ MergeSorter(GlobalSortState &state, BufferManager &buffer_manager);
30151
+
30152
+ //! Finds and merges partitions until the current cascaded merge round is finished
30153
+ void PerformInMergeRound();
30154
+
30155
+ private:
30156
+ //! Computes the left and right block that will be merged next (Merge Path partition)
30157
+ void GetNextPartition();
30158
+ //! Finds the boundary of the next partition using binary search
30159
+ void GetIntersection(SortedBlock &l, SortedBlock &r, const idx_t diagonal, idx_t &l_idx, idx_t &r_idx);
30160
+ //! Compare values within SortedBlocks using a global index
30161
+ int CompareUsingGlobalIndex(SortedBlock &l, SortedBlock &r, const idx_t l_idx, const idx_t r_idx);
30162
+
30163
+ //! Finds the next partition and merges it
30164
+ void MergePartition();
30165
+
30166
+ //! Computes how the next 'count' tuples should be merged by setting the 'left_smaller' array
30167
+ void ComputeMerge(const idx_t &count, bool left_smaller[]);
30168
+
30169
+ //! Merges the radix sorting blocks according to the 'left_smaller' array
30170
+ void MergeRadix(const idx_t &count, const bool left_smaller[]);
30171
+ //! Merges SortedData according to the 'left_smaller' array
30172
+ void MergeData(SortedData &result_data, SortedData &l_data, SortedData &r_data, const idx_t &count,
30173
+ const bool left_smaller[], idx_t next_entry_sizes[]);
30174
+ //! Merges constant size rows according to the 'left_smaller' array
30175
+ void MergeRows(data_ptr_t &l_ptr, idx_t &l_entry_idx, const idx_t &l_count, data_ptr_t &r_ptr, idx_t &r_entry_idx,
30176
+ const idx_t &r_count, RowDataBlock *target_block, data_ptr_t &target_ptr, const idx_t &entry_size,
30177
+ const bool left_smaller[], idx_t &copied, const idx_t &count);
30178
+ //! Flushes constant size rows into the result
30179
+ void FlushRows(data_ptr_t &source_ptr, idx_t &source_entry_idx, const idx_t &source_count,
30180
+ RowDataBlock *target_block, data_ptr_t &target_ptr, const idx_t &entry_size, idx_t &copied,
30181
+ const idx_t &count);
30182
+ //! Flushes blob rows and accompanying heap
30183
+ void FlushBlobs(const RowLayout &layout, const idx_t &source_count, data_ptr_t &source_data_ptr,
30184
+ idx_t &source_entry_idx, data_ptr_t &source_heap_ptr, RowDataBlock *target_data_block,
30185
+ data_ptr_t &target_data_ptr, RowDataBlock *target_heap_block, BufferHandle &target_heap_handle,
30186
+ data_ptr_t &target_heap_ptr, idx_t &copied, const idx_t &count);
30187
+
30188
+ private:
30189
+ //! The global sorting state
30190
+ GlobalSortState &state;
30191
+ //! The sorting and payload layouts
30192
+ BufferManager &buffer_manager;
30193
+ const SortLayout &sort_layout;
30194
+
30195
+ //! The left, right and result blocks of the current partition
30196
+ unique_ptr<SortedBlock> left_block;
30197
+ unique_ptr<SortedBlock> right_block;
30198
+ SortedBlock *result;
30199
+ };
30200
+
30201
+ } // namespace duckdb
30202
+
30203
+
30204
+ namespace duckdb {
30205
+
30206
+ bool Comparators::TieIsBreakable(const idx_t &col_idx, const data_ptr_t row_ptr, const RowLayout &row_layout) {
30207
+ // Check if the blob is NULL
30208
+ ValidityBytes row_mask(row_ptr);
30209
+ idx_t entry_idx;
30210
+ idx_t idx_in_entry;
30211
+ ValidityBytes::GetEntryIndex(col_idx, entry_idx, idx_in_entry);
30212
+ if (!row_mask.RowIsValid(row_mask.GetValidityEntry(entry_idx), idx_in_entry)) {
30213
+ // Can't break a NULL tie
30214
+ return false;
30215
+ }
30216
+ if (row_layout.GetTypes()[col_idx].InternalType() == PhysicalType::VARCHAR) {
30217
+ const auto &tie_col_offset = row_layout.GetOffsets()[col_idx];
30218
+ string_t tie_string = Load<string_t>(row_ptr + tie_col_offset);
30219
+ if (tie_string.GetSize() < string_t::INLINE_LENGTH) {
30220
+ // No need to break the tie - we already compared the full string
30221
+ return false;
30222
+ }
30223
+ }
30224
+ return true;
30225
+ }
30226
+
30227
+ int Comparators::CompareTuple(const SortedBlock &left, const SortedBlock &right, const data_ptr_t &l_ptr,
30228
+ const data_ptr_t &r_ptr, const SortLayout &sort_layout, const bool &external_sort) {
30229
+ // Compare the sorting columns one by one
30230
+ int comp_res = 0;
30231
+ data_ptr_t l_ptr_offset = l_ptr;
30232
+ data_ptr_t r_ptr_offset = r_ptr;
30233
+ for (idx_t col_idx = 0; col_idx < sort_layout.column_count; col_idx++) {
30234
+ comp_res = FastMemcmp(l_ptr_offset, r_ptr_offset, sort_layout.column_sizes[col_idx]);
30235
+ if (comp_res == 0 && !sort_layout.constant_size[col_idx]) {
30236
+ comp_res =
30237
+ BreakBlobTie(col_idx, *left.blob_sorting_data, *right.blob_sorting_data, sort_layout, external_sort);
30238
+ }
30239
+ if (comp_res != 0) {
30240
+ break;
30241
+ }
30242
+ l_ptr_offset += sort_layout.column_sizes[col_idx];
30243
+ r_ptr_offset += sort_layout.column_sizes[col_idx];
30244
+ }
30245
+ return comp_res;
30246
+ }
30247
+
30248
+ int Comparators::CompareVal(const data_ptr_t l_ptr, const data_ptr_t r_ptr, const LogicalType &type) {
30249
+ switch (type.InternalType()) {
30250
+ case PhysicalType::VARCHAR:
30251
+ return TemplatedCompareVal<string_t>(l_ptr, r_ptr);
30252
+ case PhysicalType::LIST:
30253
+ case PhysicalType::STRUCT: {
30254
+ auto l_nested_ptr = Load<data_ptr_t>(l_ptr);
30255
+ auto r_nested_ptr = Load<data_ptr_t>(r_ptr);
30256
+ return CompareValAndAdvance(l_nested_ptr, r_nested_ptr, type);
30257
+ }
30258
+ default:
30259
+ throw NotImplementedException("Unimplemented CompareVal for type %s", type.ToString());
30260
+ }
30261
+ }
30262
+
30263
+ int Comparators::BreakBlobTie(const idx_t &tie_col, const SortedData &left, const SortedData &right,
30264
+ const SortLayout &sort_layout, const bool &external) {
30265
+ const idx_t &col_idx = sort_layout.sorting_to_blob_col.at(tie_col);
30266
+ data_ptr_t l_data_ptr = left.DataPtr();
30267
+ data_ptr_t r_data_ptr = right.DataPtr();
30268
+ if (!TieIsBreakable(col_idx, l_data_ptr, sort_layout.blob_layout)) {
30269
+ // Quick check to see if ties can be broken
30270
+ return 0;
30271
+ }
30272
+ // Align the pointers
30273
+ const auto &tie_col_offset = sort_layout.blob_layout.GetOffsets()[col_idx];
30274
+ l_data_ptr += tie_col_offset;
30275
+ r_data_ptr += tie_col_offset;
30276
+ // Do the comparison
30277
+ const int order = sort_layout.order_types[tie_col] == OrderType::DESCENDING ? -1 : 1;
30278
+ const auto &type = left.layout.GetTypes()[col_idx];
30279
+ int result;
30280
+ if (external) {
30281
+ // Store heap pointers
30282
+ data_ptr_t l_heap_ptr = left.HeapPtr();
30283
+ data_ptr_t r_heap_ptr = right.HeapPtr();
30284
+ // Unswizzle offset to pointer
30285
+ UnswizzleSingleValue(l_data_ptr, l_heap_ptr, type);
30286
+ UnswizzleSingleValue(r_data_ptr, r_heap_ptr, type);
30287
+ // Compare
30288
+ result = CompareVal(l_data_ptr, r_data_ptr, type);
30289
+ // Swizzle the pointers back to offsets
30290
+ SwizzleSingleValue(l_data_ptr, l_heap_ptr, type);
30291
+ SwizzleSingleValue(r_data_ptr, r_heap_ptr, type);
30292
+ } else {
30293
+ result = CompareVal(l_data_ptr, r_data_ptr, type);
30294
+ }
30295
+ return order * result;
30296
+ }
30297
+
30298
+ template <class T>
30299
+ int Comparators::TemplatedCompareVal(const data_ptr_t &left_ptr, const data_ptr_t &right_ptr) {
30300
+ const auto left_val = Load<T>(left_ptr);
30301
+ const auto right_val = Load<T>(right_ptr);
30302
+ if (Equals::Operation<T>(left_val, right_val)) {
30303
+ return 0;
30304
+ } else if (LessThan::Operation<T>(left_val, right_val)) {
30305
+ return -1;
30306
+ } else {
30307
+ return 1;
30308
+ }
30309
+ }
30310
+
30311
+ int Comparators::CompareValAndAdvance(data_ptr_t &l_ptr, data_ptr_t &r_ptr, const LogicalType &type) {
30312
+ switch (type.InternalType()) {
30313
+ case PhysicalType::BOOL:
30314
+ case PhysicalType::INT8:
30315
+ return TemplatedCompareAndAdvance<int8_t>(l_ptr, r_ptr);
30316
+ case PhysicalType::INT16:
30317
+ return TemplatedCompareAndAdvance<int16_t>(l_ptr, r_ptr);
30318
+ case PhysicalType::INT32:
30319
+ return TemplatedCompareAndAdvance<int32_t>(l_ptr, r_ptr);
30320
+ case PhysicalType::INT64:
30321
+ return TemplatedCompareAndAdvance<int64_t>(l_ptr, r_ptr);
30322
+ case PhysicalType::UINT8:
30323
+ return TemplatedCompareAndAdvance<uint8_t>(l_ptr, r_ptr);
30324
+ case PhysicalType::UINT16:
30325
+ return TemplatedCompareAndAdvance<uint16_t>(l_ptr, r_ptr);
30326
+ case PhysicalType::UINT32:
30327
+ return TemplatedCompareAndAdvance<uint32_t>(l_ptr, r_ptr);
30328
+ case PhysicalType::UINT64:
30329
+ return TemplatedCompareAndAdvance<uint64_t>(l_ptr, r_ptr);
30330
+ case PhysicalType::INT128:
30331
+ return TemplatedCompareAndAdvance<hugeint_t>(l_ptr, r_ptr);
30332
+ case PhysicalType::FLOAT:
30333
+ return TemplatedCompareAndAdvance<float>(l_ptr, r_ptr);
30334
+ case PhysicalType::DOUBLE:
30335
+ return TemplatedCompareAndAdvance<double>(l_ptr, r_ptr);
30336
+ case PhysicalType::INTERVAL:
30337
+ return TemplatedCompareAndAdvance<interval_t>(l_ptr, r_ptr);
30338
+ case PhysicalType::VARCHAR:
30339
+ return CompareStringAndAdvance(l_ptr, r_ptr);
30340
+ case PhysicalType::LIST:
30341
+ return CompareListAndAdvance(l_ptr, r_ptr, ListType::GetChildType(type));
30342
+ case PhysicalType::STRUCT:
30343
+ return CompareStructAndAdvance(l_ptr, r_ptr, StructType::GetChildTypes(type));
30344
+ default:
30345
+ throw NotImplementedException("Unimplemented CompareValAndAdvance for type %s", type.ToString());
30346
+ }
30347
+ }
30348
+
30349
+ template <class T>
30350
+ int Comparators::TemplatedCompareAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr) {
30351
+ auto result = TemplatedCompareVal<T>(left_ptr, right_ptr);
30352
+ left_ptr += sizeof(T);
30353
+ right_ptr += sizeof(T);
30354
+ return result;
30355
+ }
30356
+
30357
+ int Comparators::CompareStringAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr) {
30358
+ // Construct the string_t
30359
+ uint32_t left_string_size = Load<uint32_t>(left_ptr);
30360
+ uint32_t right_string_size = Load<uint32_t>(right_ptr);
30361
+ left_ptr += sizeof(uint32_t);
30362
+ right_ptr += sizeof(uint32_t);
30363
+ string_t left_val((const char *)left_ptr, left_string_size);
30364
+ string_t right_val((const char *)right_ptr, right_string_size);
30365
+ left_ptr += left_string_size;
30366
+ right_ptr += right_string_size;
30367
+ // Compare
30368
+ return TemplatedCompareVal<string_t>((data_ptr_t)&left_val, (data_ptr_t)&right_val);
30369
+ }
30370
+
30371
+ int Comparators::CompareStructAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr,
30372
+ const child_list_t<LogicalType> &types) {
30373
+ idx_t count = types.size();
30374
+ // Load validity masks
30375
+ ValidityBytes left_validity(left_ptr);
30376
+ ValidityBytes right_validity(right_ptr);
30377
+ left_ptr += (count + 7) / 8;
30378
+ right_ptr += (count + 7) / 8;
30379
+ // Initialize variables
30380
+ bool left_valid;
30381
+ bool right_valid;
30382
+ idx_t entry_idx;
30383
+ idx_t idx_in_entry;
30384
+ // Compare
30385
+ int comp_res = 0;
30386
+ for (idx_t i = 0; i < count; i++) {
30387
+ ValidityBytes::GetEntryIndex(i, entry_idx, idx_in_entry);
30388
+ left_valid = left_validity.RowIsValid(left_validity.GetValidityEntry(entry_idx), idx_in_entry);
30389
+ right_valid = right_validity.RowIsValid(right_validity.GetValidityEntry(entry_idx), idx_in_entry);
30390
+ auto &type = types[i].second;
30391
+ if ((left_valid && right_valid) || TypeIsConstantSize(type.InternalType())) {
30392
+ comp_res = CompareValAndAdvance(left_ptr, right_ptr, types[i].second);
30393
+ }
30394
+ if (!left_valid && !right_valid) {
30395
+ comp_res = 0;
30396
+ } else if (!left_valid) {
30397
+ comp_res = 1;
30398
+ } else if (!right_valid) {
30399
+ comp_res = -1;
30400
+ }
30401
+ if (comp_res != 0) {
30402
+ break;
30403
+ }
30404
+ }
30405
+ return comp_res;
30406
+ }
30407
+
30408
+ int Comparators::CompareListAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr, const LogicalType &type) {
30409
+ // Load list lengths
30410
+ auto left_len = Load<idx_t>(left_ptr);
30411
+ auto right_len = Load<idx_t>(right_ptr);
30412
+ left_ptr += sizeof(idx_t);
30413
+ right_ptr += sizeof(idx_t);
30414
+ // Load list validity masks
30415
+ ValidityBytes left_validity(left_ptr);
30416
+ ValidityBytes right_validity(right_ptr);
30417
+ left_ptr += (left_len + 7) / 8;
30418
+ right_ptr += (right_len + 7) / 8;
30419
+ // Compare
30420
+ int comp_res = 0;
30421
+ idx_t count = MinValue(left_len, right_len);
30422
+ if (TypeIsConstantSize(type.InternalType())) {
30423
+ // Templated code for fixed-size types
30424
+ switch (type.InternalType()) {
30425
+ case PhysicalType::BOOL:
30426
+ case PhysicalType::INT8:
30427
+ comp_res = TemplatedCompareListLoop<int8_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30428
+ break;
30429
+ case PhysicalType::INT16:
30430
+ comp_res = TemplatedCompareListLoop<int16_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30431
+ break;
30432
+ case PhysicalType::INT32:
30433
+ comp_res = TemplatedCompareListLoop<int32_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30434
+ break;
30435
+ case PhysicalType::INT64:
30436
+ comp_res = TemplatedCompareListLoop<int64_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30437
+ break;
30438
+ case PhysicalType::UINT8:
30439
+ comp_res = TemplatedCompareListLoop<uint8_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30440
+ break;
30441
+ case PhysicalType::UINT16:
30442
+ comp_res = TemplatedCompareListLoop<uint16_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30443
+ break;
30444
+ case PhysicalType::UINT32:
30445
+ comp_res = TemplatedCompareListLoop<uint32_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30446
+ break;
30447
+ case PhysicalType::UINT64:
30448
+ comp_res = TemplatedCompareListLoop<uint64_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30449
+ break;
30450
+ case PhysicalType::INT128:
30451
+ comp_res = TemplatedCompareListLoop<hugeint_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30452
+ break;
30453
+ case PhysicalType::FLOAT:
30454
+ comp_res = TemplatedCompareListLoop<float>(left_ptr, right_ptr, left_validity, right_validity, count);
30455
+ break;
30456
+ case PhysicalType::DOUBLE:
30457
+ comp_res = TemplatedCompareListLoop<double>(left_ptr, right_ptr, left_validity, right_validity, count);
30458
+ break;
30459
+ case PhysicalType::INTERVAL:
30460
+ comp_res = TemplatedCompareListLoop<interval_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30461
+ break;
30462
+ default:
30463
+ throw NotImplementedException("CompareListAndAdvance for fixed-size type %s", type.ToString());
30464
+ }
30465
+ } else {
30466
+ // Variable-sized list entries
30467
+ bool left_valid;
30468
+ bool right_valid;
30469
+ idx_t entry_idx;
30470
+ idx_t idx_in_entry;
30471
+ // Size (in bytes) of all variable-sizes entries is stored before the entries begin,
30472
+ // to make deserialization easier. We need to skip over them
30473
+ left_ptr += left_len * sizeof(idx_t);
30474
+ right_ptr += right_len * sizeof(idx_t);
30475
+ for (idx_t i = 0; i < count; i++) {
30476
+ ValidityBytes::GetEntryIndex(i, entry_idx, idx_in_entry);
30477
+ left_valid = left_validity.RowIsValid(left_validity.GetValidityEntry(entry_idx), idx_in_entry);
30478
+ right_valid = right_validity.RowIsValid(right_validity.GetValidityEntry(entry_idx), idx_in_entry);
30479
+ if (left_valid && right_valid) {
30480
+ switch (type.InternalType()) {
30481
+ case PhysicalType::LIST:
30482
+ comp_res = CompareListAndAdvance(left_ptr, right_ptr, ListType::GetChildType(type));
30483
+ break;
30484
+ case PhysicalType::VARCHAR:
30485
+ comp_res = CompareStringAndAdvance(left_ptr, right_ptr);
30486
+ break;
30487
+ case PhysicalType::STRUCT:
30488
+ comp_res = CompareStructAndAdvance(left_ptr, right_ptr, StructType::GetChildTypes(type));
30489
+ break;
30490
+ default:
30491
+ throw NotImplementedException("CompareListAndAdvance for variable-size type %s", type.ToString());
30492
+ }
30493
+ } else if (!left_valid && !right_valid) {
30494
+ comp_res = 0;
30495
+ } else if (left_valid) {
30496
+ comp_res = -1;
30497
+ } else {
30498
+ comp_res = 1;
30499
+ }
30500
+ if (comp_res != 0) {
30501
+ break;
30502
+ }
30503
+ }
30412
30504
  }
30413
- // LCOV_EXCL_STOP
30505
+ // All values that we looped over were equal
30506
+ if (comp_res == 0 && left_len != right_len) {
30507
+ // Smaller lists first
30508
+ if (left_len < right_len) {
30509
+ comp_res = -1;
30510
+ } else {
30511
+ comp_res = 1;
30512
+ }
30513
+ }
30514
+ return comp_res;
30414
30515
  }
30415
30516
 
30416
- //! This templated memcmp is significantly faster than std::memcmp,
30417
- //! but only when you are calling memcmp with a const size in a loop.
30418
- //! For instance `while (<cond>) { memcmp(<str1>, <str2>, const_size); ... }`
30419
- static inline int FastMemcmp(const void *str1, const void *str2, const size_t size) {
30420
- // LCOV_EXCL_START
30421
- switch (size) {
30422
- case 0:
30423
- return 0;
30424
- case 1:
30425
- return MemcmpFixed<1>(str1, str2);
30426
- case 2:
30427
- return MemcmpFixed<2>(str1, str2);
30428
- case 3:
30429
- return MemcmpFixed<3>(str1, str2);
30430
- case 4:
30431
- return MemcmpFixed<4>(str1, str2);
30432
- case 5:
30433
- return MemcmpFixed<5>(str1, str2);
30434
- case 6:
30435
- return MemcmpFixed<6>(str1, str2);
30436
- case 7:
30437
- return MemcmpFixed<7>(str1, str2);
30438
- case 8:
30439
- return MemcmpFixed<8>(str1, str2);
30440
- case 9:
30441
- return MemcmpFixed<9>(str1, str2);
30442
- case 10:
30443
- return MemcmpFixed<10>(str1, str2);
30444
- case 11:
30445
- return MemcmpFixed<11>(str1, str2);
30446
- case 12:
30447
- return MemcmpFixed<12>(str1, str2);
30448
- case 13:
30449
- return MemcmpFixed<13>(str1, str2);
30450
- case 14:
30451
- return MemcmpFixed<14>(str1, str2);
30452
- case 15:
30453
- return MemcmpFixed<15>(str1, str2);
30454
- case 16:
30455
- return MemcmpFixed<16>(str1, str2);
30456
- case 17:
30457
- return MemcmpFixed<17>(str1, str2);
30458
- case 18:
30459
- return MemcmpFixed<18>(str1, str2);
30460
- case 19:
30461
- return MemcmpFixed<19>(str1, str2);
30462
- case 20:
30463
- return MemcmpFixed<20>(str1, str2);
30464
- case 21:
30465
- return MemcmpFixed<21>(str1, str2);
30466
- case 22:
30467
- return MemcmpFixed<22>(str1, str2);
30468
- case 23:
30469
- return MemcmpFixed<23>(str1, str2);
30470
- case 24:
30471
- return MemcmpFixed<24>(str1, str2);
30472
- case 25:
30473
- return MemcmpFixed<25>(str1, str2);
30474
- case 26:
30475
- return MemcmpFixed<26>(str1, str2);
30476
- case 27:
30477
- return MemcmpFixed<27>(str1, str2);
30478
- case 28:
30479
- return MemcmpFixed<28>(str1, str2);
30480
- case 29:
30481
- return MemcmpFixed<29>(str1, str2);
30482
- case 30:
30483
- return MemcmpFixed<30>(str1, str2);
30484
- case 31:
30485
- return MemcmpFixed<31>(str1, str2);
30486
- case 32:
30487
- return MemcmpFixed<32>(str1, str2);
30488
- case 33:
30489
- return MemcmpFixed<33>(str1, str2);
30490
- case 34:
30491
- return MemcmpFixed<34>(str1, str2);
30492
- case 35:
30493
- return MemcmpFixed<35>(str1, str2);
30494
- case 36:
30495
- return MemcmpFixed<36>(str1, str2);
30496
- case 37:
30497
- return MemcmpFixed<37>(str1, str2);
30498
- case 38:
30499
- return MemcmpFixed<38>(str1, str2);
30500
- case 39:
30501
- return MemcmpFixed<39>(str1, str2);
30502
- case 40:
30503
- return MemcmpFixed<40>(str1, str2);
30504
- case 41:
30505
- return MemcmpFixed<41>(str1, str2);
30506
- case 42:
30507
- return MemcmpFixed<42>(str1, str2);
30508
- case 43:
30509
- return MemcmpFixed<43>(str1, str2);
30510
- case 44:
30511
- return MemcmpFixed<44>(str1, str2);
30512
- case 45:
30513
- return MemcmpFixed<45>(str1, str2);
30514
- case 46:
30515
- return MemcmpFixed<46>(str1, str2);
30516
- case 47:
30517
- return MemcmpFixed<47>(str1, str2);
30518
- case 48:
30519
- return MemcmpFixed<48>(str1, str2);
30520
- case 49:
30521
- return MemcmpFixed<49>(str1, str2);
30522
- case 50:
30523
- return MemcmpFixed<50>(str1, str2);
30524
- case 51:
30525
- return MemcmpFixed<51>(str1, str2);
30526
- case 52:
30527
- return MemcmpFixed<52>(str1, str2);
30528
- case 53:
30529
- return MemcmpFixed<53>(str1, str2);
30530
- case 54:
30531
- return MemcmpFixed<54>(str1, str2);
30532
- case 55:
30533
- return MemcmpFixed<55>(str1, str2);
30534
- case 56:
30535
- return MemcmpFixed<56>(str1, str2);
30536
- case 57:
30537
- return MemcmpFixed<57>(str1, str2);
30538
- case 58:
30539
- return MemcmpFixed<58>(str1, str2);
30540
- case 59:
30541
- return MemcmpFixed<59>(str1, str2);
30542
- case 60:
30543
- return MemcmpFixed<60>(str1, str2);
30544
- case 61:
30545
- return MemcmpFixed<61>(str1, str2);
30546
- case 62:
30547
- return MemcmpFixed<62>(str1, str2);
30548
- case 63:
30549
- return MemcmpFixed<63>(str1, str2);
30550
- case 64:
30551
- return MemcmpFixed<64>(str1, str2);
30552
- default:
30553
- return memcmp(str1, str2, size);
30517
+ template <class T>
30518
+ int Comparators::TemplatedCompareListLoop(data_ptr_t &left_ptr, data_ptr_t &right_ptr,
30519
+ const ValidityBytes &left_validity, const ValidityBytes &right_validity,
30520
+ const idx_t &count) {
30521
+ int comp_res = 0;
30522
+ bool left_valid;
30523
+ bool right_valid;
30524
+ idx_t entry_idx;
30525
+ idx_t idx_in_entry;
30526
+ for (idx_t i = 0; i < count; i++) {
30527
+ ValidityBytes::GetEntryIndex(i, entry_idx, idx_in_entry);
30528
+ left_valid = left_validity.RowIsValid(left_validity.GetValidityEntry(entry_idx), idx_in_entry);
30529
+ right_valid = right_validity.RowIsValid(right_validity.GetValidityEntry(entry_idx), idx_in_entry);
30530
+ comp_res = TemplatedCompareAndAdvance<T>(left_ptr, right_ptr);
30531
+ if (!left_valid && !right_valid) {
30532
+ comp_res = 0;
30533
+ } else if (!left_valid) {
30534
+ comp_res = 1;
30535
+ } else if (!right_valid) {
30536
+ comp_res = -1;
30537
+ }
30538
+ if (comp_res != 0) {
30539
+ break;
30540
+ }
30554
30541
  }
30555
- // LCOV_EXCL_STOP
30542
+ return comp_res;
30543
+ }
30544
+
30545
+ void Comparators::UnswizzleSingleValue(data_ptr_t data_ptr, const data_ptr_t &heap_ptr, const LogicalType &type) {
30546
+ if (type.InternalType() == PhysicalType::VARCHAR) {
30547
+ data_ptr += sizeof(uint32_t) + string_t::PREFIX_LENGTH;
30548
+ }
30549
+ Store<data_ptr_t>(heap_ptr + Load<idx_t>(data_ptr), data_ptr);
30550
+ }
30551
+
30552
+ void Comparators::SwizzleSingleValue(data_ptr_t data_ptr, const data_ptr_t &heap_ptr, const LogicalType &type) {
30553
+ if (type.InternalType() == PhysicalType::VARCHAR) {
30554
+ data_ptr += sizeof(uint32_t) + string_t::PREFIX_LENGTH;
30555
+ }
30556
+ Store<idx_t>(Load<data_ptr_t>(data_ptr) - heap_ptr, data_ptr);
30556
30557
  }
30557
30558
 
30558
30559
  } // namespace duckdb
@@ -31557,6 +31558,7 @@ void LocalSortState::SortInMemory() {
31557
31558
 
31558
31559
 
31559
31560
 
31561
+
31560
31562
  //===----------------------------------------------------------------------===//
31561
31563
  // DuckDB
31562
31564
  //
@@ -31932,7 +31934,7 @@ void LocalSortState::ReOrder(SortedData &sd, data_ptr_t sorting_ptr, RowDataColl
31932
31934
  const idx_t sorting_entry_size = gstate.sort_layout.entry_size;
31933
31935
  for (idx_t i = 0; i < count; i++) {
31934
31936
  auto index = Load<uint32_t>(sorting_ptr);
31935
- memcpy(ordered_data_ptr, unordered_data_ptr + index * row_width, row_width);
31937
+ FastMemcpy(ordered_data_ptr, unordered_data_ptr + index * row_width, row_width);
31936
31938
  ordered_data_ptr += row_width;
31937
31939
  sorting_ptr += sorting_entry_size;
31938
31940
  }