duckdb 0.3.2-dev273.0 → 0.3.2-dev287.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
@@ -21229,21 +21229,37 @@ idx_t LocalFileSystem::GetFilePointer(FileHandle &handle) {
21229
21229
  return ((WindowsFileHandle &)handle).position;
21230
21230
  }
21231
21231
 
21232
- void LocalFileSystem::Read(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) {
21233
- HANDLE hFile = ((WindowsFileHandle &)handle).fd;
21234
- DWORD bytes_read;
21232
+ static DWORD FSInternalRead(FileHandle &handle, HANDLE hFile, void *buffer, int64_t nr_bytes, idx_t location) {
21233
+ DWORD bytes_read = 0;
21234
+ bool overlapped_read = false;
21235
21235
  OVERLAPPED ov = {};
21236
21236
  ov.Internal = 0;
21237
21237
  ov.InternalHigh = 0;
21238
21238
  ov.Offset = location & 0xFFFFFFFF;
21239
21239
  ov.OffsetHigh = location >> 32;
21240
21240
  ov.hEvent = 0;
21241
- ReadFile(hFile, buffer, (DWORD)nr_bytes, NULL, &ov);
21242
- auto rc = GetOverlappedResult(hFile, &ov, &bytes_read, true);
21241
+ auto rc = ReadFile(hFile, buffer, (DWORD)nr_bytes, &bytes_read, &ov);
21243
21242
  if (rc == 0) {
21244
- auto error = GetLastErrorAsString();
21245
- throw IOException("Could not read file \"%s\": %s", handle.path, error);
21243
+ if (GetLastError() != ERROR_IO_PENDING) {
21244
+ auto error = GetLastErrorAsString();
21245
+ throw IOException("Could not read file \"%s\" (error in ReadFile): %s", handle.path, error);
21246
+ } else {
21247
+ overlapped_read = true;
21248
+ }
21249
+ }
21250
+ if (overlapped_read) {
21251
+ rc = GetOverlappedResult(hFile, &ov, &bytes_read, true);
21252
+ if (rc == 0) {
21253
+ auto error = GetLastErrorAsString();
21254
+ throw IOException("Could not read file \"%s\" (error in GetOverlappedResult): %s", handle.path, error);
21255
+ }
21246
21256
  }
21257
+ return bytes_read;
21258
+ }
21259
+
21260
+ void LocalFileSystem::Read(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) {
21261
+ HANDLE hFile = ((WindowsFileHandle &)handle).fd;
21262
+ auto bytes_read = FSInternalRead(handle, hFile, buffer, nr_bytes, location);
21247
21263
  if (bytes_read != nr_bytes) {
21248
21264
  throw IOException("Could not read all bytes from file \"%s\": wanted=%lld read=%lld", handle.path, nr_bytes,
21249
21265
  bytes_read);
@@ -21252,40 +21268,44 @@ void LocalFileSystem::Read(FileHandle &handle, void *buffer, int64_t nr_bytes, i
21252
21268
 
21253
21269
  int64_t LocalFileSystem::Read(FileHandle &handle, void *buffer, int64_t nr_bytes) {
21254
21270
  HANDLE hFile = ((WindowsFileHandle &)handle).fd;
21255
- DWORD bytes_read;
21256
21271
  auto &pos = ((WindowsFileHandle &)handle).position;
21257
- OVERLAPPED ov = {};
21258
- ov.Internal = 0;
21259
- ov.InternalHigh = 0;
21260
- ov.Offset = pos & 0xFFFFFFFF;
21261
- ov.OffsetHigh = pos >> 32;
21262
- ov.hEvent = 0;
21263
21272
  auto n = std::min<idx_t>(std::max<idx_t>(GetFileSize(handle), pos) - pos, nr_bytes);
21264
- ReadFile(hFile, buffer, (DWORD)n, NULL, &ov);
21265
- auto rc = GetOverlappedResult(hFile, &ov, &bytes_read, true);
21266
- if (rc == 0) {
21267
- auto error = GetLastErrorAsString();
21268
- throw IOException("Could not read file \"%s\": %s", handle.path, error);
21269
- }
21273
+ auto bytes_read = FSInternalRead(handle, hFile, buffer, n, pos);
21270
21274
  pos += bytes_read;
21271
21275
  return bytes_read;
21272
21276
  }
21273
21277
 
21274
- void LocalFileSystem::Write(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) {
21275
- HANDLE hFile = ((WindowsFileHandle &)handle).fd;
21276
- DWORD bytes_written;
21278
+ static DWORD FSInternalWrite(FileHandle &handle, HANDLE hFile, void *buffer, int64_t nr_bytes, idx_t location) {
21279
+ DWORD bytes_written = 0;
21280
+ bool overlapped_write = false;
21277
21281
  OVERLAPPED ov = {};
21278
21282
  ov.Internal = 0;
21279
21283
  ov.InternalHigh = 0;
21280
21284
  ov.Offset = location & 0xFFFFFFFF;
21281
21285
  ov.OffsetHigh = location >> 32;
21282
21286
  ov.hEvent = 0;
21283
- WriteFile(hFile, buffer, (DWORD)nr_bytes, NULL, &ov);
21284
- auto rc = GetOverlappedResult(hFile, &ov, &bytes_written, true);
21287
+ auto rc = WriteFile(hFile, buffer, (DWORD)nr_bytes, &bytes_written, &ov);
21285
21288
  if (rc == 0) {
21286
- auto error = GetLastErrorAsString();
21287
- throw IOException("Could not write file \"%s\": %s", handle.path, error);
21289
+ if (GetLastError() != ERROR_IO_PENDING) {
21290
+ auto error = GetLastErrorAsString();
21291
+ throw IOException("Could not write file \"%s\" (error in WriteFile): %s", handle.path, error);
21292
+ } else {
21293
+ overlapped_write = true;
21294
+ }
21288
21295
  }
21296
+ if (overlapped_write) {
21297
+ rc = GetOverlappedResult(hFile, &ov, &bytes_written, true);
21298
+ if (rc == 0) {
21299
+ auto error = GetLastErrorAsString();
21300
+ throw IOException("Could not write file \"%s\" (error in GetOverlappedResult): %s", handle.path, error);
21301
+ }
21302
+ }
21303
+ return bytes_written;
21304
+ }
21305
+
21306
+ void LocalFileSystem::Write(FileHandle &handle, void *buffer, int64_t nr_bytes, idx_t location) {
21307
+ HANDLE hFile = ((WindowsFileHandle &)handle).fd;
21308
+ auto bytes_written = FSInternalWrite(handle, hFile, buffer, nr_bytes, location);
21289
21309
  if (bytes_written != nr_bytes) {
21290
21310
  throw IOException("Could not write all bytes from file \"%s\": wanted=%lld wrote=%lld", handle.path, nr_bytes,
21291
21311
  bytes_written);
@@ -21294,20 +21314,8 @@ void LocalFileSystem::Write(FileHandle &handle, void *buffer, int64_t nr_bytes,
21294
21314
 
21295
21315
  int64_t LocalFileSystem::Write(FileHandle &handle, void *buffer, int64_t nr_bytes) {
21296
21316
  HANDLE hFile = ((WindowsFileHandle &)handle).fd;
21297
- DWORD bytes_written;
21298
21317
  auto &pos = ((WindowsFileHandle &)handle).position;
21299
- OVERLAPPED ov = {};
21300
- ov.Internal = 0;
21301
- ov.InternalHigh = 0;
21302
- ov.Offset = pos & 0xFFFFFFFF;
21303
- ov.OffsetHigh = pos >> 32;
21304
- ov.hEvent = 0;
21305
- WriteFile(hFile, buffer, (DWORD)nr_bytes, NULL, &ov);
21306
- auto rc = GetOverlappedResult(hFile, &ov, &bytes_written, true);
21307
- if (rc == 0) {
21308
- auto error = GetLastErrorAsString();
21309
- throw IOException("Could not write file \"%s\": %s", handle.path, error);
21310
- }
21318
+ auto bytes_written = FSInternalWrite(handle, hFile, buffer, nr_bytes, pos);
21311
21319
  pos += bytes_written;
21312
21320
  return bytes_written;
21313
21321
  }
@@ -29168,20 +29176,9 @@ private:
29168
29176
  } // namespace duckdb
29169
29177
 
29170
29178
 
29171
- //===----------------------------------------------------------------------===//
29172
- // DuckDB
29173
- //
29174
- // duckdb/common/sort/sort.hpp
29175
- //
29176
- //
29177
- //===----------------------------------------------------------------------===//
29178
-
29179
-
29180
-
29181
- //===----------------------------------------------------------------------===//
29182
29179
  // DuckDB
29183
29180
  //
29184
- // duckdb/common/sort/sorted_block.hpp
29181
+ // duckdb/common/fast_mem.hpp
29185
29182
  //
29186
29183
  //
29187
29184
  //===----------------------------------------------------------------------===//
@@ -29189,701 +29186,17 @@ private:
29189
29186
 
29190
29187
 
29191
29188
 
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
29189
 
29322
29190
 
29191
+ template <size_t SIZE>
29192
+ static inline void MemcpyFixed(void *dest, const void *src) {
29193
+ memcpy(dest, src, SIZE);
29194
+ }
29323
29195
 
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
- }
29196
+ template <size_t SIZE>
29197
+ static inline int MemcmpFixed(const void *str1, const void *str2) {
29198
+ return memcmp(str1, str2, SIZE);
29199
+ }
29887
29200
 
29888
29201
  namespace duckdb {
29889
29202
 
@@ -30408,151 +29721,847 @@ static inline void FastMemcpy(void *dest, const void *src, const size_t size) {
30408
29721
  case 256:
30409
29722
  return MemcpyFixed<256>(dest, src);
30410
29723
  default:
30411
- memcpy(dest, src, size);
29724
+ memcpy(dest, src, size);
29725
+ }
29726
+ // LCOV_EXCL_STOP
29727
+ }
29728
+
29729
+ //! This templated memcmp is significantly faster than std::memcmp,
29730
+ //! but only when you are calling memcmp with a const size in a loop.
29731
+ //! For instance `while (<cond>) { memcmp(<str1>, <str2>, const_size); ... }`
29732
+ static inline int FastMemcmp(const void *str1, const void *str2, const size_t size) {
29733
+ // LCOV_EXCL_START
29734
+ switch (size) {
29735
+ case 0:
29736
+ return 0;
29737
+ case 1:
29738
+ return MemcmpFixed<1>(str1, str2);
29739
+ case 2:
29740
+ return MemcmpFixed<2>(str1, str2);
29741
+ case 3:
29742
+ return MemcmpFixed<3>(str1, str2);
29743
+ case 4:
29744
+ return MemcmpFixed<4>(str1, str2);
29745
+ case 5:
29746
+ return MemcmpFixed<5>(str1, str2);
29747
+ case 6:
29748
+ return MemcmpFixed<6>(str1, str2);
29749
+ case 7:
29750
+ return MemcmpFixed<7>(str1, str2);
29751
+ case 8:
29752
+ return MemcmpFixed<8>(str1, str2);
29753
+ case 9:
29754
+ return MemcmpFixed<9>(str1, str2);
29755
+ case 10:
29756
+ return MemcmpFixed<10>(str1, str2);
29757
+ case 11:
29758
+ return MemcmpFixed<11>(str1, str2);
29759
+ case 12:
29760
+ return MemcmpFixed<12>(str1, str2);
29761
+ case 13:
29762
+ return MemcmpFixed<13>(str1, str2);
29763
+ case 14:
29764
+ return MemcmpFixed<14>(str1, str2);
29765
+ case 15:
29766
+ return MemcmpFixed<15>(str1, str2);
29767
+ case 16:
29768
+ return MemcmpFixed<16>(str1, str2);
29769
+ case 17:
29770
+ return MemcmpFixed<17>(str1, str2);
29771
+ case 18:
29772
+ return MemcmpFixed<18>(str1, str2);
29773
+ case 19:
29774
+ return MemcmpFixed<19>(str1, str2);
29775
+ case 20:
29776
+ return MemcmpFixed<20>(str1, str2);
29777
+ case 21:
29778
+ return MemcmpFixed<21>(str1, str2);
29779
+ case 22:
29780
+ return MemcmpFixed<22>(str1, str2);
29781
+ case 23:
29782
+ return MemcmpFixed<23>(str1, str2);
29783
+ case 24:
29784
+ return MemcmpFixed<24>(str1, str2);
29785
+ case 25:
29786
+ return MemcmpFixed<25>(str1, str2);
29787
+ case 26:
29788
+ return MemcmpFixed<26>(str1, str2);
29789
+ case 27:
29790
+ return MemcmpFixed<27>(str1, str2);
29791
+ case 28:
29792
+ return MemcmpFixed<28>(str1, str2);
29793
+ case 29:
29794
+ return MemcmpFixed<29>(str1, str2);
29795
+ case 30:
29796
+ return MemcmpFixed<30>(str1, str2);
29797
+ case 31:
29798
+ return MemcmpFixed<31>(str1, str2);
29799
+ case 32:
29800
+ return MemcmpFixed<32>(str1, str2);
29801
+ case 33:
29802
+ return MemcmpFixed<33>(str1, str2);
29803
+ case 34:
29804
+ return MemcmpFixed<34>(str1, str2);
29805
+ case 35:
29806
+ return MemcmpFixed<35>(str1, str2);
29807
+ case 36:
29808
+ return MemcmpFixed<36>(str1, str2);
29809
+ case 37:
29810
+ return MemcmpFixed<37>(str1, str2);
29811
+ case 38:
29812
+ return MemcmpFixed<38>(str1, str2);
29813
+ case 39:
29814
+ return MemcmpFixed<39>(str1, str2);
29815
+ case 40:
29816
+ return MemcmpFixed<40>(str1, str2);
29817
+ case 41:
29818
+ return MemcmpFixed<41>(str1, str2);
29819
+ case 42:
29820
+ return MemcmpFixed<42>(str1, str2);
29821
+ case 43:
29822
+ return MemcmpFixed<43>(str1, str2);
29823
+ case 44:
29824
+ return MemcmpFixed<44>(str1, str2);
29825
+ case 45:
29826
+ return MemcmpFixed<45>(str1, str2);
29827
+ case 46:
29828
+ return MemcmpFixed<46>(str1, str2);
29829
+ case 47:
29830
+ return MemcmpFixed<47>(str1, str2);
29831
+ case 48:
29832
+ return MemcmpFixed<48>(str1, str2);
29833
+ case 49:
29834
+ return MemcmpFixed<49>(str1, str2);
29835
+ case 50:
29836
+ return MemcmpFixed<50>(str1, str2);
29837
+ case 51:
29838
+ return MemcmpFixed<51>(str1, str2);
29839
+ case 52:
29840
+ return MemcmpFixed<52>(str1, str2);
29841
+ case 53:
29842
+ return MemcmpFixed<53>(str1, str2);
29843
+ case 54:
29844
+ return MemcmpFixed<54>(str1, str2);
29845
+ case 55:
29846
+ return MemcmpFixed<55>(str1, str2);
29847
+ case 56:
29848
+ return MemcmpFixed<56>(str1, str2);
29849
+ case 57:
29850
+ return MemcmpFixed<57>(str1, str2);
29851
+ case 58:
29852
+ return MemcmpFixed<58>(str1, str2);
29853
+ case 59:
29854
+ return MemcmpFixed<59>(str1, str2);
29855
+ case 60:
29856
+ return MemcmpFixed<60>(str1, str2);
29857
+ case 61:
29858
+ return MemcmpFixed<61>(str1, str2);
29859
+ case 62:
29860
+ return MemcmpFixed<62>(str1, str2);
29861
+ case 63:
29862
+ return MemcmpFixed<63>(str1, str2);
29863
+ case 64:
29864
+ return MemcmpFixed<64>(str1, str2);
29865
+ default:
29866
+ return memcmp(str1, str2, size);
29867
+ }
29868
+ // LCOV_EXCL_STOP
29869
+ }
29870
+
29871
+ } // namespace duckdb
29872
+
29873
+ //===----------------------------------------------------------------------===//
29874
+ // DuckDB
29875
+ //
29876
+ // duckdb/common/sort/sort.hpp
29877
+ //
29878
+ //
29879
+ //===----------------------------------------------------------------------===//
29880
+
29881
+
29882
+
29883
+ //===----------------------------------------------------------------------===//
29884
+ // DuckDB
29885
+ //
29886
+ // duckdb/common/sort/sorted_block.hpp
29887
+ //
29888
+ //
29889
+ //===----------------------------------------------------------------------===//
29890
+
29891
+
29892
+
29893
+
29894
+ namespace duckdb {
29895
+
29896
+ class BufferManager;
29897
+ struct RowDataBlock;
29898
+ struct SortLayout;
29899
+ struct GlobalSortState;
29900
+
29901
+ //! Object that holds sorted rows, and an accompanying heap if there are blobs
29902
+ struct SortedData {
29903
+ public:
29904
+ SortedData(const RowLayout &layout, BufferManager &buffer_manager, GlobalSortState &state);
29905
+ //! Number of rows that this object holds
29906
+ idx_t Count();
29907
+ //! Pin the current block so it can be read
29908
+ void Pin();
29909
+ //! Pointer to the row that is currently being read from
29910
+ data_ptr_t DataPtr() const;
29911
+ //! Pointer to the heap row that corresponds to the current row
29912
+ data_ptr_t HeapPtr() const;
29913
+ //! Advance one row
29914
+ void Advance(const bool &adv);
29915
+ //! Initialize new block to write to
29916
+ void CreateBlock();
29917
+ //! Reset read indices to the given indices
29918
+ void ResetIndices(idx_t block_idx_to, idx_t entry_idx_to);
29919
+ //! Create a slice that holds the rows between the start and end indices
29920
+ unique_ptr<SortedData> CreateSlice(idx_t start_block_index, idx_t start_entry_index, idx_t end_block_index,
29921
+ idx_t end_entry_index);
29922
+ //! Unswizzles all
29923
+ void Unswizzle();
29924
+
29925
+ public:
29926
+ //! Layout of this data
29927
+ const RowLayout layout;
29928
+ //! Data and heap blocks
29929
+ vector<RowDataBlock> data_blocks;
29930
+ vector<RowDataBlock> heap_blocks;
29931
+ //! Buffer handles to the data being currently read
29932
+ unique_ptr<BufferHandle> data_handle;
29933
+ unique_ptr<BufferHandle> heap_handle;
29934
+ //! Read indices
29935
+ idx_t block_idx;
29936
+ idx_t entry_idx;
29937
+ //! Whether the pointers in this sorted data are swizzled
29938
+ bool swizzled;
29939
+
29940
+ private:
29941
+ //! Pin fixed-size row data
29942
+ void PinData();
29943
+ //! Pin the accompanying heap data (if any)
29944
+ void PinHeap();
29945
+
29946
+ private:
29947
+ //! The buffer manager
29948
+ BufferManager &buffer_manager;
29949
+ //! The global state
29950
+ GlobalSortState &state;
29951
+ //! Pointers into the buffers being currently read
29952
+ data_ptr_t data_ptr;
29953
+ data_ptr_t heap_ptr;
29954
+ };
29955
+
29956
+ //! Block that holds sorted rows: radix, blob and payload data
29957
+ struct SortedBlock {
29958
+ public:
29959
+ SortedBlock(BufferManager &buffer_manager, GlobalSortState &gstate);
29960
+ //! Number of rows that this object holds
29961
+ idx_t Count() const;
29962
+ //! The remaining number of rows to be read from this object
29963
+ idx_t Remaining() const;
29964
+ //! Initialize this block to write data to
29965
+ void InitializeWrite();
29966
+ //! Init new block to write to
29967
+ void CreateBlock();
29968
+ //! Pins radix block with given index
29969
+ void PinRadix(idx_t pin_block_idx);
29970
+ //! Fill this sorted block by appending the blocks held by a vector of sorted blocks
29971
+ void AppendSortedBlocks(vector<unique_ptr<SortedBlock>> &sorted_blocks);
29972
+ //! Locate the block and entry index of a row in this block,
29973
+ //! given an index between 0 and the total number of rows in this block
29974
+ void GlobalToLocalIndex(const idx_t &global_idx, idx_t &local_block_index, idx_t &local_entry_index);
29975
+ //! Create a slice that holds the rows between the start and end indices
29976
+ unique_ptr<SortedBlock> CreateSlice(const idx_t start, const idx_t end);
29977
+
29978
+ //! Size (in bytes) of the heap of this block
29979
+ idx_t HeapSize() const;
29980
+ //! Total size (in bytes) of this block
29981
+ idx_t SizeInBytes() const;
29982
+
29983
+ public:
29984
+ //! Radix/memcmp sortable data
29985
+ vector<RowDataBlock> radix_sorting_data;
29986
+ unique_ptr<BufferHandle> radix_handle;
29987
+ idx_t block_idx;
29988
+ idx_t entry_idx;
29989
+ //! Variable sized sorting data
29990
+ unique_ptr<SortedData> blob_sorting_data;
29991
+ //! Payload data
29992
+ unique_ptr<SortedData> payload_data;
29993
+
29994
+ private:
29995
+ //! Buffer manager, and sorting layout constants
29996
+ BufferManager &buffer_manager;
29997
+ GlobalSortState &state;
29998
+ const SortLayout &sort_layout;
29999
+ const RowLayout &payload_layout;
30000
+ };
30001
+
30002
+ struct SortedDataScanner {
30003
+ public:
30004
+ SortedDataScanner(SortedData &sorted_data, GlobalSortState &global_sort_state);
30005
+
30006
+ //! Scans the next data chunk from the sorted data
30007
+ void Scan(DataChunk &chunk);
30008
+
30009
+ private:
30010
+ //! The sorted data being scanned
30011
+ SortedData &sorted_data;
30012
+ //! The total count of sorted_data
30013
+ const idx_t total_count;
30014
+ //! The global sort state
30015
+ GlobalSortState &global_sort_state;
30016
+ //! Addresses used to gather from the sorted data
30017
+ Vector addresses = Vector(LogicalType::POINTER);
30018
+ //! The number of rows scanned so far
30019
+ idx_t total_scanned;
30020
+ };
30021
+
30022
+ } // namespace duckdb
30023
+
30024
+
30025
+
30026
+
30027
+ namespace duckdb {
30028
+
30029
+ class RowLayout;
30030
+ struct LocalSortState;
30031
+
30032
+ struct SortConstants {
30033
+ static constexpr idx_t VALUES_PER_RADIX = 256;
30034
+ static constexpr idx_t MSD_RADIX_LOCATIONS = VALUES_PER_RADIX + 1;
30035
+ static constexpr idx_t INSERTION_SORT_THRESHOLD = 24;
30036
+ static constexpr idx_t MSD_RADIX_SORT_SIZE_THRESHOLD = 4;
30037
+ };
30038
+
30039
+ struct SortLayout {
30040
+ public:
30041
+ explicit SortLayout(const vector<BoundOrderByNode> &orders);
30042
+
30043
+ public:
30044
+ idx_t column_count;
30045
+ vector<OrderType> order_types;
30046
+ vector<OrderByNullType> order_by_null_types;
30047
+ vector<LogicalType> logical_types;
30048
+
30049
+ bool all_constant;
30050
+ vector<bool> constant_size;
30051
+ vector<idx_t> column_sizes;
30052
+ vector<idx_t> prefix_lengths;
30053
+ vector<BaseStatistics *> stats;
30054
+ vector<bool> has_null;
30055
+
30056
+ idx_t comparison_size;
30057
+ idx_t entry_size;
30058
+
30059
+ RowLayout blob_layout;
30060
+ unordered_map<idx_t, idx_t> sorting_to_blob_col;
30061
+ };
30062
+
30063
+ struct GlobalSortState {
30064
+ public:
30065
+ GlobalSortState(BufferManager &buffer_manager, const vector<BoundOrderByNode> &orders, RowLayout &payload_layout);
30066
+
30067
+ //! Add local state sorted data to this global state
30068
+ void AddLocalState(LocalSortState &local_sort_state);
30069
+ //! Prepares the GlobalSortState for the merge sort phase (after completing radix sort phase)
30070
+ void PrepareMergePhase();
30071
+ //! Initializes the global sort state for another round of merging
30072
+ void InitializeMergeRound();
30073
+ //! Completes the cascaded merge sort round
30074
+ void CompleteMergeRound();
30075
+
30076
+ public:
30077
+ //! The lock for updating the order global state
30078
+ mutex lock;
30079
+ //! The buffer manager
30080
+ BufferManager &buffer_manager;
30081
+
30082
+ //! Sorting and payload layouts
30083
+ const SortLayout sort_layout;
30084
+ const RowLayout payload_layout;
30085
+
30086
+ //! Sorted data
30087
+ vector<unique_ptr<SortedBlock>> sorted_blocks;
30088
+ vector<vector<unique_ptr<SortedBlock>>> sorted_blocks_temp;
30089
+ unique_ptr<SortedBlock> odd_one_out;
30090
+
30091
+ //! Pinned heap data (if sorting in memory)
30092
+ vector<RowDataBlock> heap_blocks;
30093
+ vector<unique_ptr<BufferHandle>> pinned_blocks;
30094
+
30095
+ //! Capacity (number of rows) used to initialize blocks
30096
+ idx_t block_capacity;
30097
+ //! Whether we are doing an external sort
30098
+ bool external;
30099
+
30100
+ //! Progress in merge path stage
30101
+ idx_t pair_idx;
30102
+ idx_t num_pairs;
30103
+ idx_t l_start;
30104
+ idx_t r_start;
30105
+ };
30106
+
30107
+ struct LocalSortState {
30108
+ public:
30109
+ LocalSortState();
30110
+
30111
+ //! Initialize the layouts and RowDataCollections
30112
+ void Initialize(GlobalSortState &global_sort_state, BufferManager &buffer_manager_p);
30113
+ //! Sink one DataChunk into the local sort state
30114
+ void SinkChunk(DataChunk &sort, DataChunk &payload);
30115
+ //! Size of accumulated data in bytes
30116
+ idx_t SizeInBytes() const;
30117
+ //! Sort the data accumulated so far
30118
+ void Sort(GlobalSortState &global_sort_state, bool reorder_heap);
30119
+
30120
+ private:
30121
+ //! Concatenate the blocks held by a RowDataCollection into a single block
30122
+ RowDataBlock ConcatenateBlocks(RowDataCollection &row_data);
30123
+ //! Sorts the data in the newly created SortedBlock
30124
+ void SortInMemory();
30125
+ //! Re-order the local state after sorting
30126
+ void ReOrder(GlobalSortState &gstate, bool reorder_heap);
30127
+ //! Re-order a SortedData object after sorting
30128
+ void ReOrder(SortedData &sd, data_ptr_t sorting_ptr, RowDataCollection &heap, GlobalSortState &gstate,
30129
+ bool reorder_heap);
30130
+
30131
+ public:
30132
+ //! Whether this local state has been initialized
30133
+ bool initialized;
30134
+ //! The buffer manager
30135
+ BufferManager *buffer_manager;
30136
+ //! The sorting and payload layouts
30137
+ const SortLayout *sort_layout;
30138
+ const RowLayout *payload_layout;
30139
+ //! Radix/memcmp sortable data
30140
+ unique_ptr<RowDataCollection> radix_sorting_data;
30141
+ //! Variable sized sorting data and accompanying heap
30142
+ unique_ptr<RowDataCollection> blob_sorting_data;
30143
+ unique_ptr<RowDataCollection> blob_sorting_heap;
30144
+ //! Payload data and accompanying heap
30145
+ unique_ptr<RowDataCollection> payload_data;
30146
+ unique_ptr<RowDataCollection> payload_heap;
30147
+ //! Sorted data
30148
+ vector<unique_ptr<SortedBlock>> sorted_blocks;
30149
+
30150
+ private:
30151
+ //! Selection vector and addresses for scattering the data to rows
30152
+ const SelectionVector &sel_ptr = FlatVector::INCREMENTAL_SELECTION_VECTOR;
30153
+ Vector addresses = Vector(LogicalType::POINTER);
30154
+ };
30155
+
30156
+ struct MergeSorter {
30157
+ public:
30158
+ MergeSorter(GlobalSortState &state, BufferManager &buffer_manager);
30159
+
30160
+ //! Finds and merges partitions until the current cascaded merge round is finished
30161
+ void PerformInMergeRound();
30162
+
30163
+ private:
30164
+ //! Computes the left and right block that will be merged next (Merge Path partition)
30165
+ void GetNextPartition();
30166
+ //! Finds the boundary of the next partition using binary search
30167
+ void GetIntersection(SortedBlock &l, SortedBlock &r, const idx_t diagonal, idx_t &l_idx, idx_t &r_idx);
30168
+ //! Compare values within SortedBlocks using a global index
30169
+ int CompareUsingGlobalIndex(SortedBlock &l, SortedBlock &r, const idx_t l_idx, const idx_t r_idx);
30170
+
30171
+ //! Finds the next partition and merges it
30172
+ void MergePartition();
30173
+
30174
+ //! Computes how the next 'count' tuples should be merged by setting the 'left_smaller' array
30175
+ void ComputeMerge(const idx_t &count, bool left_smaller[]);
30176
+
30177
+ //! Merges the radix sorting blocks according to the 'left_smaller' array
30178
+ void MergeRadix(const idx_t &count, const bool left_smaller[]);
30179
+ //! Merges SortedData according to the 'left_smaller' array
30180
+ void MergeData(SortedData &result_data, SortedData &l_data, SortedData &r_data, const idx_t &count,
30181
+ const bool left_smaller[], idx_t next_entry_sizes[]);
30182
+ //! Merges constant size rows according to the 'left_smaller' array
30183
+ 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,
30184
+ const idx_t &r_count, RowDataBlock *target_block, data_ptr_t &target_ptr, const idx_t &entry_size,
30185
+ const bool left_smaller[], idx_t &copied, const idx_t &count);
30186
+ //! Flushes constant size rows into the result
30187
+ void FlushRows(data_ptr_t &source_ptr, idx_t &source_entry_idx, const idx_t &source_count,
30188
+ RowDataBlock *target_block, data_ptr_t &target_ptr, const idx_t &entry_size, idx_t &copied,
30189
+ const idx_t &count);
30190
+ //! Flushes blob rows and accompanying heap
30191
+ void FlushBlobs(const RowLayout &layout, const idx_t &source_count, data_ptr_t &source_data_ptr,
30192
+ idx_t &source_entry_idx, data_ptr_t &source_heap_ptr, RowDataBlock *target_data_block,
30193
+ data_ptr_t &target_data_ptr, RowDataBlock *target_heap_block, BufferHandle &target_heap_handle,
30194
+ data_ptr_t &target_heap_ptr, idx_t &copied, const idx_t &count);
30195
+
30196
+ private:
30197
+ //! The global sorting state
30198
+ GlobalSortState &state;
30199
+ //! The sorting and payload layouts
30200
+ BufferManager &buffer_manager;
30201
+ const SortLayout &sort_layout;
30202
+
30203
+ //! The left, right and result blocks of the current partition
30204
+ unique_ptr<SortedBlock> left_block;
30205
+ unique_ptr<SortedBlock> right_block;
30206
+ SortedBlock *result;
30207
+ };
30208
+
30209
+ } // namespace duckdb
30210
+
30211
+
30212
+ namespace duckdb {
30213
+
30214
+ bool Comparators::TieIsBreakable(const idx_t &col_idx, const data_ptr_t row_ptr, const RowLayout &row_layout) {
30215
+ // Check if the blob is NULL
30216
+ ValidityBytes row_mask(row_ptr);
30217
+ idx_t entry_idx;
30218
+ idx_t idx_in_entry;
30219
+ ValidityBytes::GetEntryIndex(col_idx, entry_idx, idx_in_entry);
30220
+ if (!row_mask.RowIsValid(row_mask.GetValidityEntry(entry_idx), idx_in_entry)) {
30221
+ // Can't break a NULL tie
30222
+ return false;
30223
+ }
30224
+ if (row_layout.GetTypes()[col_idx].InternalType() == PhysicalType::VARCHAR) {
30225
+ const auto &tie_col_offset = row_layout.GetOffsets()[col_idx];
30226
+ string_t tie_string = Load<string_t>(row_ptr + tie_col_offset);
30227
+ if (tie_string.GetSize() < string_t::INLINE_LENGTH) {
30228
+ // No need to break the tie - we already compared the full string
30229
+ return false;
30230
+ }
30231
+ }
30232
+ return true;
30233
+ }
30234
+
30235
+ int Comparators::CompareTuple(const SortedBlock &left, const SortedBlock &right, const data_ptr_t &l_ptr,
30236
+ const data_ptr_t &r_ptr, const SortLayout &sort_layout, const bool &external_sort) {
30237
+ // Compare the sorting columns one by one
30238
+ int comp_res = 0;
30239
+ data_ptr_t l_ptr_offset = l_ptr;
30240
+ data_ptr_t r_ptr_offset = r_ptr;
30241
+ for (idx_t col_idx = 0; col_idx < sort_layout.column_count; col_idx++) {
30242
+ comp_res = FastMemcmp(l_ptr_offset, r_ptr_offset, sort_layout.column_sizes[col_idx]);
30243
+ if (comp_res == 0 && !sort_layout.constant_size[col_idx]) {
30244
+ comp_res =
30245
+ BreakBlobTie(col_idx, *left.blob_sorting_data, *right.blob_sorting_data, sort_layout, external_sort);
30246
+ }
30247
+ if (comp_res != 0) {
30248
+ break;
30249
+ }
30250
+ l_ptr_offset += sort_layout.column_sizes[col_idx];
30251
+ r_ptr_offset += sort_layout.column_sizes[col_idx];
30252
+ }
30253
+ return comp_res;
30254
+ }
30255
+
30256
+ int Comparators::CompareVal(const data_ptr_t l_ptr, const data_ptr_t r_ptr, const LogicalType &type) {
30257
+ switch (type.InternalType()) {
30258
+ case PhysicalType::VARCHAR:
30259
+ return TemplatedCompareVal<string_t>(l_ptr, r_ptr);
30260
+ case PhysicalType::LIST:
30261
+ case PhysicalType::STRUCT: {
30262
+ auto l_nested_ptr = Load<data_ptr_t>(l_ptr);
30263
+ auto r_nested_ptr = Load<data_ptr_t>(r_ptr);
30264
+ return CompareValAndAdvance(l_nested_ptr, r_nested_ptr, type);
30265
+ }
30266
+ default:
30267
+ throw NotImplementedException("Unimplemented CompareVal for type %s", type.ToString());
30268
+ }
30269
+ }
30270
+
30271
+ int Comparators::BreakBlobTie(const idx_t &tie_col, const SortedData &left, const SortedData &right,
30272
+ const SortLayout &sort_layout, const bool &external) {
30273
+ const idx_t &col_idx = sort_layout.sorting_to_blob_col.at(tie_col);
30274
+ data_ptr_t l_data_ptr = left.DataPtr();
30275
+ data_ptr_t r_data_ptr = right.DataPtr();
30276
+ if (!TieIsBreakable(col_idx, l_data_ptr, sort_layout.blob_layout)) {
30277
+ // Quick check to see if ties can be broken
30278
+ return 0;
30279
+ }
30280
+ // Align the pointers
30281
+ const auto &tie_col_offset = sort_layout.blob_layout.GetOffsets()[col_idx];
30282
+ l_data_ptr += tie_col_offset;
30283
+ r_data_ptr += tie_col_offset;
30284
+ // Do the comparison
30285
+ const int order = sort_layout.order_types[tie_col] == OrderType::DESCENDING ? -1 : 1;
30286
+ const auto &type = left.layout.GetTypes()[col_idx];
30287
+ int result;
30288
+ if (external) {
30289
+ // Store heap pointers
30290
+ data_ptr_t l_heap_ptr = left.HeapPtr();
30291
+ data_ptr_t r_heap_ptr = right.HeapPtr();
30292
+ // Unswizzle offset to pointer
30293
+ UnswizzleSingleValue(l_data_ptr, l_heap_ptr, type);
30294
+ UnswizzleSingleValue(r_data_ptr, r_heap_ptr, type);
30295
+ // Compare
30296
+ result = CompareVal(l_data_ptr, r_data_ptr, type);
30297
+ // Swizzle the pointers back to offsets
30298
+ SwizzleSingleValue(l_data_ptr, l_heap_ptr, type);
30299
+ SwizzleSingleValue(r_data_ptr, r_heap_ptr, type);
30300
+ } else {
30301
+ result = CompareVal(l_data_ptr, r_data_ptr, type);
30302
+ }
30303
+ return order * result;
30304
+ }
30305
+
30306
+ template <class T>
30307
+ int Comparators::TemplatedCompareVal(const data_ptr_t &left_ptr, const data_ptr_t &right_ptr) {
30308
+ const auto left_val = Load<T>(left_ptr);
30309
+ const auto right_val = Load<T>(right_ptr);
30310
+ if (Equals::Operation<T>(left_val, right_val)) {
30311
+ return 0;
30312
+ } else if (LessThan::Operation<T>(left_val, right_val)) {
30313
+ return -1;
30314
+ } else {
30315
+ return 1;
30316
+ }
30317
+ }
30318
+
30319
+ int Comparators::CompareValAndAdvance(data_ptr_t &l_ptr, data_ptr_t &r_ptr, const LogicalType &type) {
30320
+ switch (type.InternalType()) {
30321
+ case PhysicalType::BOOL:
30322
+ case PhysicalType::INT8:
30323
+ return TemplatedCompareAndAdvance<int8_t>(l_ptr, r_ptr);
30324
+ case PhysicalType::INT16:
30325
+ return TemplatedCompareAndAdvance<int16_t>(l_ptr, r_ptr);
30326
+ case PhysicalType::INT32:
30327
+ return TemplatedCompareAndAdvance<int32_t>(l_ptr, r_ptr);
30328
+ case PhysicalType::INT64:
30329
+ return TemplatedCompareAndAdvance<int64_t>(l_ptr, r_ptr);
30330
+ case PhysicalType::UINT8:
30331
+ return TemplatedCompareAndAdvance<uint8_t>(l_ptr, r_ptr);
30332
+ case PhysicalType::UINT16:
30333
+ return TemplatedCompareAndAdvance<uint16_t>(l_ptr, r_ptr);
30334
+ case PhysicalType::UINT32:
30335
+ return TemplatedCompareAndAdvance<uint32_t>(l_ptr, r_ptr);
30336
+ case PhysicalType::UINT64:
30337
+ return TemplatedCompareAndAdvance<uint64_t>(l_ptr, r_ptr);
30338
+ case PhysicalType::INT128:
30339
+ return TemplatedCompareAndAdvance<hugeint_t>(l_ptr, r_ptr);
30340
+ case PhysicalType::FLOAT:
30341
+ return TemplatedCompareAndAdvance<float>(l_ptr, r_ptr);
30342
+ case PhysicalType::DOUBLE:
30343
+ return TemplatedCompareAndAdvance<double>(l_ptr, r_ptr);
30344
+ case PhysicalType::INTERVAL:
30345
+ return TemplatedCompareAndAdvance<interval_t>(l_ptr, r_ptr);
30346
+ case PhysicalType::VARCHAR:
30347
+ return CompareStringAndAdvance(l_ptr, r_ptr);
30348
+ case PhysicalType::LIST:
30349
+ return CompareListAndAdvance(l_ptr, r_ptr, ListType::GetChildType(type));
30350
+ case PhysicalType::STRUCT:
30351
+ return CompareStructAndAdvance(l_ptr, r_ptr, StructType::GetChildTypes(type));
30352
+ default:
30353
+ throw NotImplementedException("Unimplemented CompareValAndAdvance for type %s", type.ToString());
30354
+ }
30355
+ }
30356
+
30357
+ template <class T>
30358
+ int Comparators::TemplatedCompareAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr) {
30359
+ auto result = TemplatedCompareVal<T>(left_ptr, right_ptr);
30360
+ left_ptr += sizeof(T);
30361
+ right_ptr += sizeof(T);
30362
+ return result;
30363
+ }
30364
+
30365
+ int Comparators::CompareStringAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr) {
30366
+ // Construct the string_t
30367
+ uint32_t left_string_size = Load<uint32_t>(left_ptr);
30368
+ uint32_t right_string_size = Load<uint32_t>(right_ptr);
30369
+ left_ptr += sizeof(uint32_t);
30370
+ right_ptr += sizeof(uint32_t);
30371
+ string_t left_val((const char *)left_ptr, left_string_size);
30372
+ string_t right_val((const char *)right_ptr, right_string_size);
30373
+ left_ptr += left_string_size;
30374
+ right_ptr += right_string_size;
30375
+ // Compare
30376
+ return TemplatedCompareVal<string_t>((data_ptr_t)&left_val, (data_ptr_t)&right_val);
30377
+ }
30378
+
30379
+ int Comparators::CompareStructAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr,
30380
+ const child_list_t<LogicalType> &types) {
30381
+ idx_t count = types.size();
30382
+ // Load validity masks
30383
+ ValidityBytes left_validity(left_ptr);
30384
+ ValidityBytes right_validity(right_ptr);
30385
+ left_ptr += (count + 7) / 8;
30386
+ right_ptr += (count + 7) / 8;
30387
+ // Initialize variables
30388
+ bool left_valid;
30389
+ bool right_valid;
30390
+ idx_t entry_idx;
30391
+ idx_t idx_in_entry;
30392
+ // Compare
30393
+ int comp_res = 0;
30394
+ for (idx_t i = 0; i < count; i++) {
30395
+ ValidityBytes::GetEntryIndex(i, entry_idx, idx_in_entry);
30396
+ left_valid = left_validity.RowIsValid(left_validity.GetValidityEntry(entry_idx), idx_in_entry);
30397
+ right_valid = right_validity.RowIsValid(right_validity.GetValidityEntry(entry_idx), idx_in_entry);
30398
+ auto &type = types[i].second;
30399
+ if ((left_valid && right_valid) || TypeIsConstantSize(type.InternalType())) {
30400
+ comp_res = CompareValAndAdvance(left_ptr, right_ptr, types[i].second);
30401
+ }
30402
+ if (!left_valid && !right_valid) {
30403
+ comp_res = 0;
30404
+ } else if (!left_valid) {
30405
+ comp_res = 1;
30406
+ } else if (!right_valid) {
30407
+ comp_res = -1;
30408
+ }
30409
+ if (comp_res != 0) {
30410
+ break;
30411
+ }
30412
+ }
30413
+ return comp_res;
30414
+ }
30415
+
30416
+ int Comparators::CompareListAndAdvance(data_ptr_t &left_ptr, data_ptr_t &right_ptr, const LogicalType &type) {
30417
+ // Load list lengths
30418
+ auto left_len = Load<idx_t>(left_ptr);
30419
+ auto right_len = Load<idx_t>(right_ptr);
30420
+ left_ptr += sizeof(idx_t);
30421
+ right_ptr += sizeof(idx_t);
30422
+ // Load list validity masks
30423
+ ValidityBytes left_validity(left_ptr);
30424
+ ValidityBytes right_validity(right_ptr);
30425
+ left_ptr += (left_len + 7) / 8;
30426
+ right_ptr += (right_len + 7) / 8;
30427
+ // Compare
30428
+ int comp_res = 0;
30429
+ idx_t count = MinValue(left_len, right_len);
30430
+ if (TypeIsConstantSize(type.InternalType())) {
30431
+ // Templated code for fixed-size types
30432
+ switch (type.InternalType()) {
30433
+ case PhysicalType::BOOL:
30434
+ case PhysicalType::INT8:
30435
+ comp_res = TemplatedCompareListLoop<int8_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30436
+ break;
30437
+ case PhysicalType::INT16:
30438
+ comp_res = TemplatedCompareListLoop<int16_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30439
+ break;
30440
+ case PhysicalType::INT32:
30441
+ comp_res = TemplatedCompareListLoop<int32_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30442
+ break;
30443
+ case PhysicalType::INT64:
30444
+ comp_res = TemplatedCompareListLoop<int64_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30445
+ break;
30446
+ case PhysicalType::UINT8:
30447
+ comp_res = TemplatedCompareListLoop<uint8_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30448
+ break;
30449
+ case PhysicalType::UINT16:
30450
+ comp_res = TemplatedCompareListLoop<uint16_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30451
+ break;
30452
+ case PhysicalType::UINT32:
30453
+ comp_res = TemplatedCompareListLoop<uint32_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30454
+ break;
30455
+ case PhysicalType::UINT64:
30456
+ comp_res = TemplatedCompareListLoop<uint64_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30457
+ break;
30458
+ case PhysicalType::INT128:
30459
+ comp_res = TemplatedCompareListLoop<hugeint_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30460
+ break;
30461
+ case PhysicalType::FLOAT:
30462
+ comp_res = TemplatedCompareListLoop<float>(left_ptr, right_ptr, left_validity, right_validity, count);
30463
+ break;
30464
+ case PhysicalType::DOUBLE:
30465
+ comp_res = TemplatedCompareListLoop<double>(left_ptr, right_ptr, left_validity, right_validity, count);
30466
+ break;
30467
+ case PhysicalType::INTERVAL:
30468
+ comp_res = TemplatedCompareListLoop<interval_t>(left_ptr, right_ptr, left_validity, right_validity, count);
30469
+ break;
30470
+ default:
30471
+ throw NotImplementedException("CompareListAndAdvance for fixed-size type %s", type.ToString());
30472
+ }
30473
+ } else {
30474
+ // Variable-sized list entries
30475
+ bool left_valid;
30476
+ bool right_valid;
30477
+ idx_t entry_idx;
30478
+ idx_t idx_in_entry;
30479
+ // Size (in bytes) of all variable-sizes entries is stored before the entries begin,
30480
+ // to make deserialization easier. We need to skip over them
30481
+ left_ptr += left_len * sizeof(idx_t);
30482
+ right_ptr += right_len * sizeof(idx_t);
30483
+ for (idx_t i = 0; i < count; i++) {
30484
+ ValidityBytes::GetEntryIndex(i, entry_idx, idx_in_entry);
30485
+ left_valid = left_validity.RowIsValid(left_validity.GetValidityEntry(entry_idx), idx_in_entry);
30486
+ right_valid = right_validity.RowIsValid(right_validity.GetValidityEntry(entry_idx), idx_in_entry);
30487
+ if (left_valid && right_valid) {
30488
+ switch (type.InternalType()) {
30489
+ case PhysicalType::LIST:
30490
+ comp_res = CompareListAndAdvance(left_ptr, right_ptr, ListType::GetChildType(type));
30491
+ break;
30492
+ case PhysicalType::VARCHAR:
30493
+ comp_res = CompareStringAndAdvance(left_ptr, right_ptr);
30494
+ break;
30495
+ case PhysicalType::STRUCT:
30496
+ comp_res = CompareStructAndAdvance(left_ptr, right_ptr, StructType::GetChildTypes(type));
30497
+ break;
30498
+ default:
30499
+ throw NotImplementedException("CompareListAndAdvance for variable-size type %s", type.ToString());
30500
+ }
30501
+ } else if (!left_valid && !right_valid) {
30502
+ comp_res = 0;
30503
+ } else if (left_valid) {
30504
+ comp_res = -1;
30505
+ } else {
30506
+ comp_res = 1;
30507
+ }
30508
+ if (comp_res != 0) {
30509
+ break;
30510
+ }
30511
+ }
30412
30512
  }
30413
- // LCOV_EXCL_STOP
30513
+ // All values that we looped over were equal
30514
+ if (comp_res == 0 && left_len != right_len) {
30515
+ // Smaller lists first
30516
+ if (left_len < right_len) {
30517
+ comp_res = -1;
30518
+ } else {
30519
+ comp_res = 1;
30520
+ }
30521
+ }
30522
+ return comp_res;
30414
30523
  }
30415
30524
 
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);
30525
+ template <class T>
30526
+ int Comparators::TemplatedCompareListLoop(data_ptr_t &left_ptr, data_ptr_t &right_ptr,
30527
+ const ValidityBytes &left_validity, const ValidityBytes &right_validity,
30528
+ const idx_t &count) {
30529
+ int comp_res = 0;
30530
+ bool left_valid;
30531
+ bool right_valid;
30532
+ idx_t entry_idx;
30533
+ idx_t idx_in_entry;
30534
+ for (idx_t i = 0; i < count; i++) {
30535
+ ValidityBytes::GetEntryIndex(i, entry_idx, idx_in_entry);
30536
+ left_valid = left_validity.RowIsValid(left_validity.GetValidityEntry(entry_idx), idx_in_entry);
30537
+ right_valid = right_validity.RowIsValid(right_validity.GetValidityEntry(entry_idx), idx_in_entry);
30538
+ comp_res = TemplatedCompareAndAdvance<T>(left_ptr, right_ptr);
30539
+ if (!left_valid && !right_valid) {
30540
+ comp_res = 0;
30541
+ } else if (!left_valid) {
30542
+ comp_res = 1;
30543
+ } else if (!right_valid) {
30544
+ comp_res = -1;
30545
+ }
30546
+ if (comp_res != 0) {
30547
+ break;
30548
+ }
30554
30549
  }
30555
- // LCOV_EXCL_STOP
30550
+ return comp_res;
30551
+ }
30552
+
30553
+ void Comparators::UnswizzleSingleValue(data_ptr_t data_ptr, const data_ptr_t &heap_ptr, const LogicalType &type) {
30554
+ if (type.InternalType() == PhysicalType::VARCHAR) {
30555
+ data_ptr += sizeof(uint32_t) + string_t::PREFIX_LENGTH;
30556
+ }
30557
+ Store<data_ptr_t>(heap_ptr + Load<idx_t>(data_ptr), data_ptr);
30558
+ }
30559
+
30560
+ void Comparators::SwizzleSingleValue(data_ptr_t data_ptr, const data_ptr_t &heap_ptr, const LogicalType &type) {
30561
+ if (type.InternalType() == PhysicalType::VARCHAR) {
30562
+ data_ptr += sizeof(uint32_t) + string_t::PREFIX_LENGTH;
30563
+ }
30564
+ Store<idx_t>(Load<data_ptr_t>(data_ptr) - heap_ptr, data_ptr);
30556
30565
  }
30557
30566
 
30558
30567
  } // namespace duckdb
@@ -31557,6 +31566,7 @@ void LocalSortState::SortInMemory() {
31557
31566
 
31558
31567
 
31559
31568
 
31569
+
31560
31570
  //===----------------------------------------------------------------------===//
31561
31571
  // DuckDB
31562
31572
  //
@@ -31932,7 +31942,7 @@ void LocalSortState::ReOrder(SortedData &sd, data_ptr_t sorting_ptr, RowDataColl
31932
31942
  const idx_t sorting_entry_size = gstate.sort_layout.entry_size;
31933
31943
  for (idx_t i = 0; i < count; i++) {
31934
31944
  auto index = Load<uint32_t>(sorting_ptr);
31935
- memcpy(ordered_data_ptr, unordered_data_ptr + index * row_width, row_width);
31945
+ FastMemcpy(ordered_data_ptr, unordered_data_ptr + index * row_width, row_width);
31936
31946
  ordered_data_ptr += row_width;
31937
31947
  sorting_ptr += sorting_entry_size;
31938
31948
  }