| 618 | } else { |
| 619 | return addToOutputForLeftJoin(); |
| 620 | } |
| 621 | } |
| 622 | |
| 623 | bool MergeJoin::addToOutputForLeftJoin() { |
| 624 | size_t firstLeftBatch; |
| 625 | vector_size_t leftStartIndex; |
| 626 | if (leftMatch_->cursor) { |
| 627 | firstLeftBatch = leftMatch_->cursor->batchIndex; |
| 628 | leftStartIndex = leftMatch_->cursor->index; |
| 629 | } else { |
| 630 | firstLeftBatch = 0; |
| 631 | leftStartIndex = leftMatch_->startIndex; |
| 632 | } |
| 633 | |
| 634 | size_t numLefts = leftMatch_->inputs.size(); |
| 635 | for (size_t l = firstLeftBatch; l < numLefts; ++l) { |
| 636 | auto left = leftMatch_->inputs[l]; |
| 637 | auto leftStart = l == firstLeftBatch ? leftStartIndex : 0; |
| 638 | auto leftEnd = l == numLefts - 1 ? leftMatch_->endIndex : left->size(); |
| 639 | |
| 640 | for (auto i = leftStart; i < leftEnd; ++i) { |
| 641 | auto firstRightBatch = |
| 642 | (l == firstLeftBatch && i == leftStart && rightMatch_->cursor) |
| 643 | ? rightMatch_->cursor->batchIndex |
| 644 | : 0; |
| 645 | |
| 646 | auto rightStartIndex = |
| 647 | (l == firstLeftBatch && i == leftStart && rightMatch_->cursor) |
| 648 | ? rightMatch_->cursor->index |
| 649 | : rightMatch_->startIndex; |
| 650 | |
| 651 | auto numRights = rightMatch_->inputs.size(); |
| 652 | for (size_t r = firstRightBatch; r < numRights; ++r) { |
| 653 | auto right = rightMatch_->inputs[r]; |
| 654 | auto rightStart = r == firstRightBatch ? rightStartIndex : 0; |
| 655 | auto rightEnd = |
| 656 | r == numRights - 1 ? rightMatch_->endIndex : right->size(); |
| 657 | |
| 658 | if (prepareOutput(left, right)) { |
| 659 | output_->resize(outputSize_); |
| 660 | leftMatch_->setCursor(l, i); |
| 661 | rightMatch_->setCursor(r, rightStart); |
| 662 | return true; |
| 663 | } |
| 664 | |
| 665 | // TODO: Since semi joins only require determining if there is at least |
| 666 | // one match on the other side, we could explore specialized algorithms |
| 667 | // or data structures that short-circuit the join process once a match |
| 668 | // is found. |
| 669 | if (isLeftSemiFilterJoin(joinType_) && !filter_) { |
| 670 | // LeftSemiFilter produce each row from the left at most once. |
| 671 | rightEnd = rightStart + 1; |
| 672 | } |
| 673 | |
| 674 | for (auto j = rightStart; j < rightEnd; ++j) { |
| 675 | if (outputSize_ == outputBatchSize_) { |
| 676 | // If we run out of space in the current output_, we will need to |
| 677 | // produce a buffer and continue processing left later. In this |
nothing calls this directly
no test coverage detected