duckdb 0.3.3-dev482.0 → 0.3.3-dev508.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "duckdb",
3
3
  "main": "./lib/duckdb.js",
4
- "version": "0.3.3-dev482.0",
4
+ "version": "0.3.3-dev508.0",
5
5
  "description": "DuckDB node.js API",
6
6
  "gypfile": true,
7
7
  "dependencies": {
package/src/duckdb.cpp CHANGED
@@ -32766,6 +32766,16 @@ void DataChunk::Split(DataChunk &other, idx_t split_idx) {
32766
32766
  other.SetCardinality(*this);
32767
32767
  }
32768
32768
 
32769
+ void DataChunk::Fuse(DataChunk &other) {
32770
+ D_ASSERT(other.size() == size());
32771
+ const idx_t num_cols = other.data.size();
32772
+ for (idx_t col_idx = 0; col_idx < num_cols; ++col_idx) {
32773
+ data.emplace_back(move(other.data[col_idx]));
32774
+ vector_caches.emplace_back(move(other.vector_caches[col_idx]));
32775
+ }
32776
+ other.Destroy();
32777
+ }
32778
+
32769
32779
  void DataChunk::Append(const DataChunk &other, bool resize, SelectionVector *sel, idx_t sel_count) {
32770
32780
  idx_t new_size = sel ? size() + sel_count : size() + other.size();
32771
32781
  if (other.size() == 0) {
@@ -57834,8 +57844,28 @@ PhysicalPiecewiseMergeJoin::PhysicalPiecewiseMergeJoin(LogicalOperator &op, uniq
57834
57844
  JoinType join_type, idx_t estimated_cardinality)
57835
57845
  : PhysicalComparisonJoin(op, PhysicalOperatorType::PIECEWISE_MERGE_JOIN, move(cond), join_type,
57836
57846
  estimated_cardinality) {
57837
- // for now we only support one condition!
57838
- D_ASSERT(conditions.size() == 1);
57847
+ // Reorder the conditions so that ranges are at the front.
57848
+ // TODO: use stats to improve the choice?
57849
+ if (conditions.size() > 1) {
57850
+ auto conditions_p = std::move(conditions);
57851
+ conditions.resize(conditions_p.size());
57852
+ idx_t range_position = 0;
57853
+ idx_t other_position = conditions_p.size();
57854
+ for (idx_t i = 0; i < conditions_p.size(); ++i) {
57855
+ switch (conditions_p[i].comparison) {
57856
+ case ExpressionType::COMPARE_LESSTHAN:
57857
+ case ExpressionType::COMPARE_LESSTHANOREQUALTO:
57858
+ case ExpressionType::COMPARE_GREATERTHAN:
57859
+ case ExpressionType::COMPARE_GREATERTHANOREQUALTO:
57860
+ conditions[range_position++] = std::move(conditions_p[i]);
57861
+ break;
57862
+ default:
57863
+ conditions[--other_position] = std::move(conditions_p[i]);
57864
+ break;
57865
+ }
57866
+ }
57867
+ }
57868
+
57839
57869
  for (auto &cond : conditions) {
57840
57870
  D_ASSERT(cond.left->return_type == cond.right->return_type);
57841
57871
  join_key_types.push_back(cond.left->return_type);
@@ -57854,8 +57884,16 @@ PhysicalPiecewiseMergeJoin::PhysicalPiecewiseMergeJoin(LogicalOperator &op, uniq
57854
57884
  lhs_orders.emplace_back(BoundOrderByNode(OrderType::DESCENDING, OrderByNullType::NULLS_LAST, move(left)));
57855
57885
  rhs_orders.emplace_back(BoundOrderByNode(OrderType::DESCENDING, OrderByNullType::NULLS_LAST, move(right)));
57856
57886
  break;
57887
+ case ExpressionType::COMPARE_NOTEQUAL:
57888
+ case ExpressionType::COMPARE_DISTINCT_FROM:
57889
+ // Allowed in multi-predicate joins, but can't be first/sort.
57890
+ D_ASSERT(!lhs_orders.empty());
57891
+ lhs_orders.emplace_back(BoundOrderByNode(OrderType::INVALID, OrderByNullType::NULLS_LAST, move(left)));
57892
+ rhs_orders.emplace_back(BoundOrderByNode(OrderType::INVALID, OrderByNullType::NULLS_LAST, move(right)));
57893
+ break;
57894
+
57857
57895
  default:
57858
- // COMPARE NOT EQUAL not supported with merge join
57896
+ // COMPARE EQUAL not supported with merge join
57859
57897
  throw NotImplementedException("Unimplemented join type for merge join");
57860
57898
  }
57861
57899
  }
@@ -57871,6 +57909,7 @@ public:
57871
57909
  MergeJoinGlobalState(BufferManager &buffer_manager, const vector<BoundOrderByNode> &orders, RowLayout &rhs_layout)
57872
57910
  : rhs_global_sort_state(buffer_manager, orders, rhs_layout), rhs_has_null(0), rhs_count(0),
57873
57911
  memory_per_thread(0) {
57912
+ D_ASSERT(orders.size() == 1);
57874
57913
  }
57875
57914
 
57876
57915
  inline idx_t Count() const {
@@ -57892,11 +57931,12 @@ public:
57892
57931
  };
57893
57932
 
57894
57933
  unique_ptr<GlobalSinkState> PhysicalPiecewiseMergeJoin::GetGlobalSinkState(ClientContext &context) const {
57895
- // Get the payload layout from the rhs types
57934
+ // Get the payload layout from the rhs types and tail predicates
57896
57935
  RowLayout rhs_layout;
57897
- auto types = children[1]->types;
57898
- rhs_layout.Initialize(types);
57899
- auto state = make_unique<MergeJoinGlobalState>(BufferManager::GetBufferManager(context), rhs_orders, rhs_layout);
57936
+ rhs_layout.Initialize(children[1]->types);
57937
+ vector<BoundOrderByNode> rhs_order;
57938
+ rhs_order.emplace_back(rhs_orders[0].Copy());
57939
+ auto state = make_unique<MergeJoinGlobalState>(BufferManager::GetBufferManager(context), rhs_order, rhs_layout);
57900
57940
  // Set external (can be force with the PRAGMA)
57901
57941
  auto &config = ClientConfig::GetConfig(context);
57902
57942
  state->rhs_global_sort_state.external = config.force_external;
@@ -57963,6 +58003,94 @@ unique_ptr<LocalSinkState> PhysicalPiecewiseMergeJoin::GetLocalSinkState(Executi
57963
58003
  return move(result);
57964
58004
  }
57965
58005
 
58006
+ static idx_t PiecewiseMergeNulls(DataChunk &keys, const vector<JoinCondition> &conditions) {
58007
+ // Merge the validity masks of the comparison keys into the primary
58008
+ // Return the number of NULLs in the resulting chunk
58009
+ D_ASSERT(keys.ColumnCount() > 0);
58010
+ const auto count = keys.size();
58011
+
58012
+ size_t all_constant = 0;
58013
+ for (auto &v : keys.data) {
58014
+ if (v.GetVectorType() == VectorType::CONSTANT_VECTOR) {
58015
+ ++all_constant;
58016
+ }
58017
+ }
58018
+
58019
+ auto &primary = keys.data[0];
58020
+ if (all_constant == keys.data.size()) {
58021
+ // Either all NULL or no NULLs
58022
+ for (auto &v : keys.data) {
58023
+ if (ConstantVector::IsNull(v)) {
58024
+ ConstantVector::SetNull(primary, true);
58025
+ return count;
58026
+ }
58027
+ }
58028
+ return 0;
58029
+ } else if (keys.ColumnCount() > 1) {
58030
+ // Normalify the primary, as it will need to merge arbitrary validity masks
58031
+ primary.Normalify(count);
58032
+ auto &pvalidity = FlatVector::Validity(primary);
58033
+ for (size_t c = 1; c < keys.data.size(); ++c) {
58034
+ // Skip comparisons that accept NULLs
58035
+ if (conditions[c].comparison == ExpressionType::COMPARE_DISTINCT_FROM) {
58036
+ continue;
58037
+ }
58038
+ // Orrify the rest, as the sort code will do this anyway.
58039
+ auto &v = keys.data[c];
58040
+ VectorData vdata;
58041
+ v.Orrify(count, vdata);
58042
+ auto &vvalidity = vdata.validity;
58043
+ if (vvalidity.AllValid()) {
58044
+ continue;
58045
+ }
58046
+ pvalidity.EnsureWritable();
58047
+ switch (v.GetVectorType()) {
58048
+ case VectorType::FLAT_VECTOR: {
58049
+ // Merge entire entries
58050
+ auto pmask = pvalidity.GetData();
58051
+ const auto entry_count = pvalidity.EntryCount(count);
58052
+ for (idx_t entry_idx = 0; entry_idx < entry_count; ++entry_idx) {
58053
+ pmask[entry_idx] &= vvalidity.GetValidityEntry(entry_idx);
58054
+ }
58055
+ break;
58056
+ }
58057
+ case VectorType::CONSTANT_VECTOR:
58058
+ // All or nothing
58059
+ if (ConstantVector::IsNull(v)) {
58060
+ pvalidity.SetAllInvalid(count);
58061
+ return count;
58062
+ }
58063
+ break;
58064
+ default:
58065
+ // One by one
58066
+ for (idx_t i = 0; i < count; ++i) {
58067
+ const auto idx = vdata.sel->get_index(i);
58068
+ if (!vvalidity.RowIsValidUnsafe(idx)) {
58069
+ pvalidity.SetInvalidUnsafe(i);
58070
+ }
58071
+ }
58072
+ break;
58073
+ }
58074
+ }
58075
+ return count - pvalidity.CountValid(count);
58076
+ } else {
58077
+ return count - CountValid(primary, count);
58078
+ }
58079
+ }
58080
+
58081
+ static inline void SinkPiecewiseMergeChunk(LocalSortState &sort_state, DataChunk &join_keys, DataChunk &input) {
58082
+ if (join_keys.ColumnCount() > 1) {
58083
+ // Only sort the first key
58084
+ DataChunk join_head;
58085
+ join_head.data.emplace_back(Vector(join_keys.data[0]));
58086
+ join_head.SetCardinality(join_keys.size());
58087
+
58088
+ sort_state.SinkChunk(join_head, input);
58089
+ } else {
58090
+ sort_state.SinkChunk(join_keys, input);
58091
+ }
58092
+ }
58093
+
57966
58094
  SinkResultType PhysicalPiecewiseMergeJoin::Sink(ExecutionContext &context, GlobalSinkState &gstate_p,
57967
58095
  LocalSinkState &lstate_p, DataChunk &input) const {
57968
58096
  auto &gstate = (MergeJoinGlobalState &)gstate_p;
@@ -57982,15 +58110,11 @@ SinkResultType PhysicalPiecewiseMergeJoin::Sink(ExecutionContext &context, Globa
57982
58110
  lstate.rhs_executor.Execute(input, join_keys);
57983
58111
 
57984
58112
  // Count the NULLs so we can exclude them later
57985
- // TODO: Sort any comparison NULLs to the end using an initial sort column
57986
- const auto count = join_keys.size();
57987
- for (auto &key : join_keys.data) {
57988
- lstate.rhs_has_null += (count - CountValid(key, count));
57989
- }
57990
- lstate.rhs_count += count;
58113
+ lstate.rhs_has_null += PiecewiseMergeNulls(join_keys, conditions);
58114
+ lstate.rhs_count += join_keys.size();
57991
58115
 
57992
58116
  // Sink the data into the local sort state
57993
- local_sort_state.SinkChunk(join_keys, input);
58117
+ SinkPiecewiseMergeChunk(local_sort_state, join_keys, input);
57994
58118
 
57995
58119
  // When sorting data reaches a certain size, we sort it
57996
58120
  if (local_sort_state.SizeInBytes() >= gstate.memory_per_thread) {
@@ -58115,9 +58239,9 @@ public:
58115
58239
  : op(op), buffer_manager(buffer_manager), force_external(force_external), left_position(0), first_fetch(true),
58116
58240
  finished(true), right_position(0), right_chunk_index(0) {
58117
58241
  vector<LogicalType> condition_types;
58118
- for (auto &cond : op.conditions) {
58119
- lhs_executor.AddExpression(*cond.left);
58120
- condition_types.push_back(cond.left->return_type);
58242
+ for (auto &order : op.lhs_orders) {
58243
+ lhs_executor.AddExpression(*order.expression);
58244
+ condition_types.push_back(order.expression->return_type);
58121
58245
  }
58122
58246
  lhs_keys.Initialize(condition_types);
58123
58247
  if (IsLeftOuterJoin(op.join_type)) {
@@ -58125,6 +58249,18 @@ public:
58125
58249
  memset(lhs_found_match.get(), 0, sizeof(bool) * STANDARD_VECTOR_SIZE);
58126
58250
  }
58127
58251
  lhs_layout.Initialize(op.children[0]->types);
58252
+ lhs_payload.Initialize(op.children[0]->types);
58253
+
58254
+ lhs_order.emplace_back(op.lhs_orders[0].Copy());
58255
+
58256
+ // Set up shared data for multiple predicates
58257
+ sel.Initialize(STANDARD_VECTOR_SIZE);
58258
+ condition_types.clear();
58259
+ for (auto &order : op.rhs_orders) {
58260
+ rhs_executor.AddExpression(*order.expression);
58261
+ condition_types.push_back(order.expression->return_type);
58262
+ }
58263
+ rhs_keys.Initialize(condition_types);
58128
58264
  }
58129
58265
 
58130
58266
  const PhysicalPiecewiseMergeJoin &op;
@@ -58133,8 +58269,10 @@ public:
58133
58269
 
58134
58270
  // Block sorting
58135
58271
  DataChunk lhs_keys;
58272
+ DataChunk lhs_payload;
58136
58273
  ExpressionExecutor lhs_executor;
58137
58274
  unique_ptr<bool[]> lhs_found_match;
58275
+ vector<BoundOrderByNode> lhs_order;
58138
58276
  RowLayout lhs_layout;
58139
58277
  unique_ptr<LocalSortState> lhs_local_state;
58140
58278
  unique_ptr<GlobalSortState> lhs_global_state;
@@ -58151,6 +58289,12 @@ public:
58151
58289
  idx_t right_chunk_index;
58152
58290
  idx_t right_base;
58153
58291
 
58292
+ // Secondary predicate shared data
58293
+ SelectionVector sel;
58294
+ DataChunk rhs_keys;
58295
+ DataChunk rhs_input;
58296
+ ExpressionExecutor rhs_executor;
58297
+
58154
58298
  public:
58155
58299
  void ResolveJoinKeys(DataChunk &input) {
58156
58300
  // resolve the join keys for the input
@@ -58158,18 +58302,14 @@ public:
58158
58302
  lhs_executor.Execute(input, lhs_keys);
58159
58303
 
58160
58304
  // Count the NULLs so we can exclude them later
58161
- // TODO: Sort any multi-comparison NULLs to the end using an initial sort column
58162
58305
  lhs_count = lhs_keys.size();
58163
- for (auto &key : lhs_keys.data) {
58164
- lhs_has_null = lhs_count - CountValid(key, lhs_count);
58165
- break;
58166
- }
58306
+ lhs_has_null = PiecewiseMergeNulls(lhs_keys, op.conditions);
58167
58307
 
58168
58308
  // sort by join key
58169
- lhs_global_state = make_unique<GlobalSortState>(buffer_manager, op.lhs_orders, lhs_layout);
58309
+ lhs_global_state = make_unique<GlobalSortState>(buffer_manager, lhs_order, lhs_layout);
58170
58310
  lhs_local_state = make_unique<LocalSortState>();
58171
58311
  lhs_local_state->Initialize(*lhs_global_state, buffer_manager);
58172
- lhs_local_state->SinkChunk(lhs_keys, input);
58312
+ SinkPiecewiseMergeChunk(*lhs_local_state, lhs_keys, input);
58173
58313
 
58174
58314
  // Set external (can be force with the PRAGMA)
58175
58315
  lhs_global_state->external = force_external;
@@ -58180,6 +58320,17 @@ public:
58180
58320
  merge_sorter.PerformInMergeRound();
58181
58321
  lhs_global_state->CompleteMergeRound();
58182
58322
  }
58323
+
58324
+ // Scan the sorted payload
58325
+ D_ASSERT(lhs_global_state->sorted_blocks.size() == 1);
58326
+
58327
+ PayloadScanner scanner(*lhs_global_state->sorted_blocks[0]->payload_data, *lhs_global_state);
58328
+ lhs_payload.Reset();
58329
+ scanner.Scan(lhs_payload);
58330
+
58331
+ // Recompute the sorted keys from the sorted input
58332
+ lhs_keys.Reset();
58333
+ lhs_executor.Execute(lhs_payload, lhs_keys);
58183
58334
  }
58184
58335
 
58185
58336
  void Finalize(PhysicalOperator *op, ExecutionContext &context) override {
@@ -58228,8 +58379,8 @@ struct BlockMergeInfo {
58228
58379
  }
58229
58380
  };
58230
58381
 
58231
- static void SliceSortedPayload(DataChunk &payload, BlockMergeInfo &info, const idx_t result_count, const idx_t vcount,
58232
- const idx_t left_cols = 0) {
58382
+ static idx_t SliceSortedPayload(DataChunk &payload, BlockMergeInfo &info, const idx_t result_count,
58383
+ const idx_t left_cols = 0) {
58233
58384
  // There should only be one sorted block if they have been sorted
58234
58385
  D_ASSERT(info.state.sorted_blocks.size() == 1);
58235
58386
  SBScanState read_state(info.state.buffer_manager, info.state);
@@ -58238,33 +58389,50 @@ static void SliceSortedPayload(DataChunk &payload, BlockMergeInfo &info, const i
58238
58389
 
58239
58390
  // We have to create pointers for the entire block
58240
58391
  // because unswizzle works on ranges not selections.
58241
- read_state.SetIndices(info.block_idx, info.base_idx);
58392
+ const auto first_idx = info.result.get_index(0);
58393
+ read_state.SetIndices(info.block_idx, info.base_idx + first_idx);
58242
58394
  read_state.PinData(sorted_data);
58243
58395
  const auto data_ptr = read_state.DataPtr(sorted_data);
58244
- const auto next = vcount - info.base_idx;
58245
58396
 
58246
58397
  // Set up a batch of pointers to scan data from
58247
- Vector addresses(LogicalType::POINTER, next);
58398
+ Vector addresses(LogicalType::POINTER, result_count);
58248
58399
  auto data_pointers = FlatVector::GetData<data_ptr_t>(addresses);
58249
58400
 
58250
- // Set up the data pointers
58401
+ // Set up the data pointers for the values that are actually referenced
58402
+ // and normalise the selection vector to zero
58251
58403
  data_ptr_t row_ptr = data_ptr;
58252
58404
  const idx_t &row_width = sorted_data.layout.GetRowWidth();
58253
- for (idx_t i = 0; i < next; ++i) {
58254
- data_pointers[i] = row_ptr;
58255
- row_ptr += row_width;
58405
+
58406
+ auto prev_idx = first_idx;
58407
+ info.result.set_index(0, 0);
58408
+ idx_t addr_count = 0;
58409
+ data_pointers[addr_count++] = row_ptr;
58410
+ for (idx_t i = 1; i < result_count; ++i) {
58411
+ const auto row_idx = info.result.get_index(i);
58412
+ info.result.set_index(i, row_idx - first_idx);
58413
+ if (row_idx == prev_idx) {
58414
+ continue;
58415
+ }
58416
+ row_ptr += (row_idx - prev_idx) * row_width;
58417
+ data_pointers[addr_count++] = row_ptr;
58418
+ prev_idx = row_idx;
58256
58419
  }
58257
58420
  // Unswizzle the offsets back to pointers (if needed)
58258
58421
  if (!sorted_data.layout.AllConstant() && info.state.external) {
58422
+ const auto next = prev_idx + 1;
58259
58423
  RowOperations::UnswizzlePointers(sorted_data.layout, data_ptr, read_state.payload_heap_handle->Ptr(), next);
58260
58424
  }
58261
58425
 
58262
58426
  // Deserialize the payload data
58427
+ auto sel = FlatVector::IncrementalSelectionVector();
58263
58428
  for (idx_t col_idx = 0; col_idx < sorted_data.layout.ColumnCount(); col_idx++) {
58264
58429
  const auto col_offset = sorted_data.layout.GetOffsets()[col_idx];
58265
- RowOperations::Gather(addresses, info.result, payload.data[left_cols + col_idx],
58266
- *FlatVector::IncrementalSelectionVector(), result_count, col_offset, col_idx);
58430
+ auto &col = payload.data[left_cols + col_idx];
58431
+ RowOperations::Gather(addresses, *sel, col, *sel, addr_count, col_offset, col_idx);
58432
+ col.Slice(info.result, result_count);
58267
58433
  }
58434
+
58435
+ return first_idx;
58268
58436
  }
58269
58437
 
58270
58438
  static void MergeJoinPinSortingBlock(SBScanState &scan, const idx_t block_idx) {
@@ -58372,16 +58540,9 @@ void PhysicalPiecewiseMergeJoin::ResolveSimpleJoin(ExecutionContext &context, Da
58372
58540
  memset(found_match, 0, sizeof(found_match));
58373
58541
  MergeJoinSimpleBlocks(state, gstate, found_match, conditions[0].comparison);
58374
58542
 
58375
- // extract the sorted payload
58376
- idx_t left_position = 0;
58543
+ // use the sorted payload
58377
58544
  const auto lhs_not_null = state.lhs_count - state.lhs_has_null;
58378
- BlockMergeInfo left_info(*state.lhs_global_state, 0, 0, left_position, lhs_not_null);
58379
- left_info.result.Initialize(nullptr);
58380
-
58381
- DataChunk payload;
58382
- payload.Initialize(input.GetTypes());
58383
- SliceSortedPayload(payload, left_info, state.lhs_count, state.lhs_count);
58384
- payload.SetCardinality(state.lhs_count);
58545
+ auto &payload = state.lhs_payload;
58385
58546
 
58386
58547
  // now construct the result based on the join result
58387
58548
  switch (join_type) {
@@ -58488,11 +58649,37 @@ static idx_t MergeJoinComplexBlocks(BlockMergeInfo &l, BlockMergeInfo &r, const
58488
58649
  return result_count;
58489
58650
  }
58490
58651
 
58652
+ static idx_t SelectJoinTail(const ExpressionType &condition, Vector &left, Vector &right, const SelectionVector *sel,
58653
+ idx_t count, SelectionVector *true_sel) {
58654
+ switch (condition) {
58655
+ case ExpressionType::COMPARE_NOTEQUAL:
58656
+ return VectorOperations::NotEquals(left, right, sel, count, true_sel, nullptr);
58657
+ case ExpressionType::COMPARE_LESSTHAN:
58658
+ return VectorOperations::LessThan(left, right, sel, count, true_sel, nullptr);
58659
+ case ExpressionType::COMPARE_GREATERTHAN:
58660
+ return VectorOperations::GreaterThan(left, right, sel, count, true_sel, nullptr);
58661
+ case ExpressionType::COMPARE_LESSTHANOREQUALTO:
58662
+ return VectorOperations::LessThanEquals(left, right, sel, count, true_sel, nullptr);
58663
+ case ExpressionType::COMPARE_GREATERTHANOREQUALTO:
58664
+ return VectorOperations::GreaterThanEquals(left, right, sel, count, true_sel, nullptr);
58665
+ case ExpressionType::COMPARE_DISTINCT_FROM:
58666
+ return VectorOperations::DistinctFrom(left, right, sel, count, true_sel, nullptr);
58667
+ case ExpressionType::COMPARE_NOT_DISTINCT_FROM:
58668
+ case ExpressionType::COMPARE_EQUAL:
58669
+ default:
58670
+ throw InternalException("Unsupported comparison type for PhysicalPiecewiseMergeJoin");
58671
+ }
58672
+
58673
+ return count;
58674
+ }
58675
+
58491
58676
  OperatorResultType PhysicalPiecewiseMergeJoin::ResolveComplexJoin(ExecutionContext &context, DataChunk &input,
58492
58677
  DataChunk &chunk, OperatorState &state_p) const {
58493
58678
  auto &state = (PiecewiseMergeJoinState &)state_p;
58494
58679
  auto &gstate = (MergeJoinGlobalState &)*sink_state;
58495
58680
  auto &rsorted = *gstate.rhs_global_sort_state.sorted_blocks[0];
58681
+ const auto left_cols = input.ColumnCount();
58682
+ const auto tail_cols = conditions.size() - 1;
58496
58683
  do {
58497
58684
  if (state.first_fetch) {
58498
58685
  state.ResolveJoinKeys(input);
@@ -58508,7 +58695,7 @@ OperatorResultType PhysicalPiecewiseMergeJoin::ResolveComplexJoin(ExecutionConte
58508
58695
  if (IsLeftOuterJoin(join_type)) {
58509
58696
  // left join: before we move to the next chunk, see if we need to output any vectors that didn't
58510
58697
  // have a match found
58511
- PhysicalJoin::ConstructLeftJoinResult(input, chunk, state.lhs_found_match.get());
58698
+ PhysicalJoin::ConstructLeftJoinResult(state.lhs_payload, chunk, state.lhs_found_match.get());
58512
58699
  memset(state.lhs_found_match.get(), 0, sizeof(bool) * STANDARD_VECTOR_SIZE);
58513
58700
  }
58514
58701
  state.first_fetch = true;
@@ -58537,22 +58724,60 @@ OperatorResultType PhysicalPiecewiseMergeJoin::ResolveComplexJoin(ExecutionConte
58537
58724
  state.finished = true;
58538
58725
  }
58539
58726
  } else {
58727
+ // found matches: extract them
58728
+ chunk.Reset();
58729
+ for (idx_t c = 0; c < state.lhs_payload.ColumnCount(); ++c) {
58730
+ chunk.data[c].Slice(state.lhs_payload.data[c], left_info.result, result_count);
58731
+ }
58732
+ const auto first_idx = SliceSortedPayload(chunk, right_info, result_count, left_cols);
58733
+ chunk.SetCardinality(result_count);
58734
+
58735
+ auto sel = FlatVector::IncrementalSelectionVector();
58736
+ if (tail_cols) {
58737
+ // If there are more expressions to compute,
58738
+ // split the result chunk into the left and right halves
58739
+ // so we can compute the values for comparison.
58740
+ chunk.Split(state.rhs_input, left_cols);
58741
+ state.rhs_executor.SetChunk(state.rhs_input);
58742
+ state.rhs_keys.Reset();
58743
+
58744
+ auto tail_count = result_count;
58745
+ for (size_t cmp_idx = 1; cmp_idx < conditions.size(); ++cmp_idx) {
58746
+ Vector left(state.lhs_keys.data[cmp_idx]);
58747
+ left.Slice(left_info.result, result_count);
58748
+
58749
+ auto &right = state.rhs_keys.data[cmp_idx];
58750
+ state.rhs_executor.ExecuteExpression(cmp_idx, right);
58751
+
58752
+ if (tail_count < result_count) {
58753
+ left.Slice(*sel, tail_count);
58754
+ right.Slice(*sel, tail_count);
58755
+ }
58756
+ tail_count =
58757
+ SelectJoinTail(conditions[cmp_idx].comparison, left, right, sel, tail_count, &state.sel);
58758
+ sel = &state.sel;
58759
+ }
58760
+ chunk.Fuse(state.rhs_input);
58761
+
58762
+ if (tail_count < result_count) {
58763
+ result_count = tail_count;
58764
+ chunk.Slice(*sel, result_count);
58765
+ }
58766
+ }
58767
+
58540
58768
  // found matches: mark the found matches if required
58541
58769
  if (state.lhs_found_match) {
58542
58770
  for (idx_t i = 0; i < result_count; i++) {
58543
- state.lhs_found_match[left_info.result[i]] = true;
58771
+ state.lhs_found_match[left_info.result[sel->get_index(i)]] = true;
58544
58772
  }
58545
58773
  }
58546
58774
  if (gstate.rhs_found_match) {
58547
58775
  // Absolute position of the block + start position inside that block
58548
- const idx_t base_index = state.right_base + right_info.base_idx;
58776
+ const idx_t base_index = right_info.base_idx + first_idx;
58549
58777
  for (idx_t i = 0; i < result_count; i++) {
58550
- gstate.rhs_found_match[base_index + right_info.result[i]] = true;
58778
+ gstate.rhs_found_match[base_index + right_info.result[sel->get_index(i)]] = true;
58551
58779
  }
58552
58780
  }
58553
- // found matches: output them
58554
- SliceSortedPayload(chunk, left_info, result_count, input.size());
58555
- SliceSortedPayload(chunk, right_info, result_count, right_info.entry_idx + 1, input.ColumnCount());
58556
58781
  chunk.SetCardinality(result_count);
58557
58782
  chunk.Verify();
58558
58783
  }
@@ -58638,7 +58863,7 @@ void PhysicalPiecewiseMergeJoin::GetData(ExecutionContext &context, DataChunk &r
58638
58863
 
58639
58864
  // ConstructFullOuterJoinResult(sink.rhs_found_match.get(), sink.right_chunks, chunk, state.right_outer_position);
58640
58865
  DataChunk rhs_chunk;
58641
- rhs_chunk.Initialize(children[1]->types);
58866
+ rhs_chunk.Initialize(sink.rhs_global_sort_state.payload_layout.GetTypes());
58642
58867
  SelectionVector rsel(STANDARD_VECTOR_SIZE);
58643
58868
  for (;;) {
58644
58869
  // Read the next sorted chunk
@@ -58660,12 +58885,14 @@ void PhysicalPiecewiseMergeJoin::GetData(ExecutionContext &context, DataChunk &r
58660
58885
 
58661
58886
  if (result_count > 0) {
58662
58887
  // if there were any tuples that didn't find a match, output them
58663
- const idx_t left_column_count = result.ColumnCount() - rhs_chunk.ColumnCount();
58888
+ const idx_t left_column_count = children[0]->types.size();
58664
58889
  for (idx_t col_idx = 0; col_idx < left_column_count; ++col_idx) {
58665
58890
  result.data[col_idx].SetVectorType(VectorType::CONSTANT_VECTOR);
58666
58891
  ConstantVector::SetNull(result.data[col_idx], true);
58667
58892
  }
58668
- for (idx_t col_idx = 0; col_idx < rhs_chunk.ColumnCount(); ++col_idx) {
58893
+ const idx_t right_column_count = children[1]->types.size();
58894
+ ;
58895
+ for (idx_t col_idx = 0; col_idx < right_column_count; ++col_idx) {
58669
58896
  result.data[left_column_count + col_idx].Slice(rhs_chunk.data[col_idx], rsel, result_count);
58670
58897
  }
58671
58898
  result.SetCardinality(result_count);
@@ -65382,16 +65609,28 @@ unique_ptr<PhysicalOperator> PhysicalPlanGenerator::CreatePlan(LogicalComparison
65382
65609
  }
65383
65610
 
65384
65611
  bool has_equality = false;
65385
- bool has_inequality = false;
65612
+ // bool has_inequality = false;
65613
+ bool has_range = false;
65386
65614
  bool has_null_equal_conditions = false;
65387
- for (auto &cond : op.conditions) {
65388
- if (cond.comparison == ExpressionType::COMPARE_EQUAL ||
65389
- cond.comparison == ExpressionType::COMPARE_NOT_DISTINCT_FROM) {
65615
+ for (size_t c = 0; c < op.conditions.size(); ++c) {
65616
+ auto &cond = op.conditions[c];
65617
+ switch (cond.comparison) {
65618
+ case ExpressionType::COMPARE_EQUAL:
65619
+ case ExpressionType::COMPARE_NOT_DISTINCT_FROM:
65390
65620
  has_equality = true;
65391
- }
65392
- if (cond.comparison == ExpressionType::COMPARE_NOTEQUAL ||
65393
- cond.comparison == ExpressionType::COMPARE_DISTINCT_FROM) {
65394
- has_inequality = true;
65621
+ break;
65622
+ case ExpressionType::COMPARE_LESSTHAN:
65623
+ case ExpressionType::COMPARE_GREATERTHAN:
65624
+ case ExpressionType::COMPARE_LESSTHANOREQUALTO:
65625
+ case ExpressionType::COMPARE_GREATERTHANOREQUALTO:
65626
+ has_range = true;
65627
+ break;
65628
+ case ExpressionType::COMPARE_NOTEQUAL:
65629
+ case ExpressionType::COMPARE_DISTINCT_FROM:
65630
+ // has_inequality = true;
65631
+ break;
65632
+ default:
65633
+ throw NotImplementedException("Unimplemented comparison join");
65395
65634
  }
65396
65635
  if (cond.null_values_are_equal) {
65397
65636
  has_null_equal_conditions = true;
@@ -65428,8 +65667,17 @@ unique_ptr<PhysicalOperator> PhysicalPlanGenerator::CreatePlan(LogicalComparison
65428
65667
  op.estimated_cardinality, perfect_join_stats);
65429
65668
 
65430
65669
  } else {
65431
- if (op.conditions.size() == 1 && !has_inequality) {
65432
- D_ASSERT(!has_null_equal_conditions); // we support this for this join for now
65670
+ bool can_merge = has_range;
65671
+ switch (op.join_type) {
65672
+ case JoinType::SEMI:
65673
+ case JoinType::ANTI:
65674
+ case JoinType::MARK:
65675
+ can_merge = can_merge && op.conditions.size() == 1;
65676
+ break;
65677
+ default:
65678
+ break;
65679
+ }
65680
+ if (can_merge) {
65433
65681
  // range join: use piecewise merge join
65434
65682
  plan = make_unique<PhysicalPiecewiseMergeJoin>(op, move(left), move(right), move(op.conditions),
65435
65683
  op.join_type, op.estimated_cardinality);
package/src/duckdb.hpp CHANGED
@@ -11,8 +11,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
11
11
  #pragma once
12
12
  #define DUCKDB_AMALGAMATION 1
13
13
  #define DUCKDB_AMALGAMATION_EXTENDED 1
14
- #define DUCKDB_SOURCE_ID "032192a4c"
15
- #define DUCKDB_VERSION "v0.3.3-dev482"
14
+ #define DUCKDB_SOURCE_ID "271ccd2bd"
15
+ #define DUCKDB_VERSION "v0.3.3-dev508"
16
16
  //===----------------------------------------------------------------------===//
17
17
  // DuckDB
18
18
  //
@@ -4114,6 +4114,9 @@ public:
4114
4114
  //! Splits the DataChunk in two
4115
4115
  DUCKDB_API void Split(DataChunk &other, idx_t split_idx);
4116
4116
 
4117
+ //! Fuses a DataChunk onto the right of this one, and destroys the other. Inverse of Split.
4118
+ DUCKDB_API void Fuse(DataChunk &other);
4119
+
4117
4120
  //! Turn all the vectors from the chunk into flat vectors
4118
4121
  DUCKDB_API void Normalify();
4119
4122