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