@@ -123,7 +123,7 @@ void MergeJoin::initialize() {
123123 isSemiFilterJoin (joinType_)) {
124124 joinTracker_ = JoinTracker (preferredOutputBatchRows_, pool ());
125125 }
126- } else if (joinNode_->isAntiJoin ()) {
126+ } else if (joinNode_->isAntiJoin () || joinNode_-> isFullJoin () ) {
127127 // Anti join needs to track the left side rows that have no match on the
128128 // right.
129129 joinTracker_ = JoinTracker (preferredOutputBatchRows_, pool ());
@@ -411,7 +411,8 @@ bool MergeJoin::tryAddOutputRow(
411411 const RowVectorPtr& leftBatch,
412412 vector_size_t leftRow,
413413 const RowVectorPtr& rightBatch,
414- vector_size_t rightRow) {
414+ vector_size_t rightRow,
415+ bool isRightJoinForFullOuter) {
415416 if (outputSize_ == outputBatchSize_) {
416417 return false ;
417418 }
@@ -445,12 +446,15 @@ bool MergeJoin::tryAddOutputRow(
445446 filterRightInputProjections_);
446447
447448 if (joinTracker_) {
448- if (isRightJoin (joinType_) || isRightSemiFilterJoin (joinType_)) {
449+ if (isRightJoin (joinType_) || isRightSemiFilterJoin (joinType_) ||
450+ (isFullJoin (joinType_) && isRightJoinForFullOuter)) {
449451 // Record right-side row with a match on the left-side.
450- joinTracker_->addMatch (rightBatch, rightRow, outputSize_);
452+ joinTracker_->addMatch (
453+ rightBatch, rightRow, outputSize_, isRightJoinForFullOuter);
451454 } else {
452455 // Record left-side row with a match on the right-side.
453- joinTracker_->addMatch (leftBatch, leftRow, outputSize_);
456+ joinTracker_->addMatch (
457+ leftBatch, leftRow, outputSize_, isRightJoinForFullOuter);
454458 }
455459 }
456460 }
@@ -460,7 +464,8 @@ bool MergeJoin::tryAddOutputRow(
460464 if (isAntiJoin (joinType_)) {
461465 VELOX_CHECK (joinTracker_.has_value ());
462466 // Record left-side row with a match on the right-side.
463- joinTracker_->addMatch (leftBatch, leftRow, outputSize_);
467+ joinTracker_->addMatch (
468+ leftBatch, leftRow, outputSize_, isRightJoinForFullOuter);
464469 }
465470
466471 ++outputSize_;
@@ -478,14 +483,16 @@ bool MergeJoin::prepareOutput(
478483 return true ;
479484 }
480485
481- if (isRightJoin (joinType_) && right != currentRight_) {
482- return true ;
483- }
484-
485486 // If there is a new right, we need to flatten the dictionary.
486487 if (!isRightFlattened_ && right && currentRight_ != right) {
487488 flattenRightProjections ();
488489 }
490+
491+ if ((isRightJoin (joinType_) || isFullJoin (joinType_)) &&
492+ right != currentRight_) {
493+ return true ;
494+ }
495+
489496 return false ;
490497 }
491498
@@ -508,11 +515,15 @@ bool MergeJoin::prepareOutput(
508515 }
509516 } else {
510517 for (const auto & projection : leftProjections_) {
518+ auto column = left->childAt (projection.inputChannel );
519+ // Flatten the left column if the column already is DictionaryVector.
520+ if (column->wrappedVector ()->encoding () ==
521+ VectorEncoding::Simple::DICTIONARY ) {
522+ BaseVector::flattenVector (column);
523+ }
524+ column->clearContainingLazyAndWrapped ();
511525 localColumns[projection.outputChannel ] = BaseVector::wrapInDictionary (
512- {},
513- leftOutputIndices_,
514- outputBatchSize_,
515- left->childAt (projection.inputChannel ));
526+ {}, leftOutputIndices_, outputBatchSize_, column);
516527 }
517528 }
518529 currentLeft_ = left;
@@ -528,11 +539,10 @@ bool MergeJoin::prepareOutput(
528539 isRightFlattened_ = true ;
529540 } else {
530541 for (const auto & projection : rightProjections_) {
542+ auto column = right->childAt (projection.inputChannel );
543+ column->clearContainingLazyAndWrapped ();
531544 localColumns[projection.outputChannel ] = BaseVector::wrapInDictionary (
532- {},
533- rightOutputIndices_,
534- outputBatchSize_,
535- right->childAt (projection.inputChannel ));
545+ {}, rightOutputIndices_, outputBatchSize_, column);
536546 }
537547 isRightFlattened_ = false ;
538548 }
@@ -596,6 +606,39 @@ bool MergeJoin::prepareOutput(
596606bool MergeJoin::addToOutput () {
597607 if (isRightJoin (joinType_) || isRightSemiFilterJoin (joinType_)) {
598608 return addToOutputForRightJoin ();
609+ } else if (isFullJoin (joinType_) && filter_) {
610+ if (!leftForRightJoinMatch_) {
611+ leftForRightJoinMatch_ = leftMatch_;
612+ rightForRightJoinMatch_ = rightMatch_;
613+ }
614+
615+ if (leftMatch_ && rightMatch_ && !leftJoinForFullFinished_) {
616+ auto left = addToOutputForLeftJoin ();
617+ if (!leftMatch_) {
618+ leftJoinForFullFinished_ = true ;
619+ }
620+ if (left) {
621+ if (!leftMatch_) {
622+ leftMatch_ = leftForRightJoinMatch_;
623+ rightMatch_ = rightForRightJoinMatch_;
624+ }
625+
626+ return true ;
627+ }
628+ }
629+
630+ if (!leftMatch_ && !rightJoinForFullFinished_) {
631+ leftMatch_ = leftForRightJoinMatch_;
632+ rightMatch_ = rightForRightJoinMatch_;
633+ rightJoinForFullFinished_ = true ;
634+ }
635+
636+ auto right = addToOutputForRightJoin ();
637+
638+ leftForRightJoinMatch_ = leftMatch_;
639+ rightForRightJoinMatch_ = rightMatch_;
640+
641+ return right;
599642 } else {
600643 return addToOutputForLeftJoin ();
601644 }
@@ -688,7 +731,13 @@ bool MergeJoin::addToOutputImpl() {
688731 } else {
689732 for (auto innerRow = innerStartRow; innerRow < innerEndRow;
690733 ++innerRow) {
691- if (!tryAddOutputRow (leftBatch, innerRow, rightBatch, outerRow)) {
734+ const auto isRightJoinForFullOuter = isFullJoin (joinType_);
735+ if (!tryAddOutputRow (
736+ leftBatch,
737+ innerRow,
738+ rightBatch,
739+ outerRow,
740+ isRightJoinForFullOuter)) {
692741 outerMatch->setCursor (outerBatchIndex, outerRow);
693742 innerMatch->setCursor (innerBatchIndex, innerRow);
694743 return true ;
@@ -960,7 +1009,7 @@ RowVectorPtr MergeJoin::doGetOutput() {
9601009 isFullJoin (joinType_)) {
9611010 // If output_ is currently wrapping a different buffer, return it
9621011 // first.
963- if (prepareOutput (input_, nullptr )) {
1012+ if (prepareOutput (input_, rightInput_ )) {
9641013 output_->resize (outputSize_);
9651014 return std::move (output_);
9661015 }
@@ -985,7 +1034,7 @@ RowVectorPtr MergeJoin::doGetOutput() {
9851034 if (isRightJoin (joinType_) || isFullJoin (joinType_)) {
9861035 // If output_ is currently wrapping a different buffer, return it
9871036 // first.
988- if (prepareOutput (nullptr , rightInput_)) {
1037+ if (prepareOutput (input_ , rightInput_)) {
9891038 output_->resize (outputSize_);
9901039 return std::move (output_);
9911040 }
@@ -1035,6 +1084,8 @@ RowVectorPtr MergeJoin::doGetOutput() {
10351084 matchedLeftRows_ += leftEndRow - leftMatch_->startRowIndex ;
10361085 matchedRightRows_ += rightEndRow - rightMatch_->startRowIndex ;
10371086
1087+ leftJoinForFullFinished_ = false ;
1088+ rightJoinForFullFinished_ = false ;
10381089 if (!leftMatch_->complete || !rightMatch_->complete ) {
10391090 if (!leftMatch_->complete ) {
10401091 // Need to continue looking for the end of match.
@@ -1324,8 +1375,6 @@ void MergeJoin::updateOutputBatchSize(const RowVectorPtr& output) {
13241375RowVectorPtr MergeJoin::applyFilter (const RowVectorPtr& output) {
13251376 const auto numRows = output->size ();
13261377
1327- RowVectorPtr fullOuterOutput = nullptr ;
1328-
13291378 BufferPtr indices = allocateIndices (numRows, pool ());
13301379 auto * rawIndices = indices->asMutable <vector_size_t >();
13311380 vector_size_t numPassed = 0 ;
@@ -1342,84 +1391,41 @@ RowVectorPtr MergeJoin::applyFilter(const RowVectorPtr& output) {
13421391
13431392 // If all matches for a given left-side row fail the filter, add a row to
13441393 // the output with nulls for the right-side columns.
1345- const auto onMiss = [&](auto row) {
1394+ const auto onMiss = [&](auto row, bool isRightJoinForFullOuter ) {
13461395 if (isSemiFilterJoin (joinType_)) {
13471396 return ;
13481397 }
13491398 rawIndices[numPassed++] = row;
13501399
1351- if (isFullJoin (joinType_)) {
1352- // For filtered rows, it is necessary to insert additional data
1353- // to ensure the result set is complete. Specifically, we
1354- // need to generate two records: one record containing the
1355- // columns from the left table along with nulls for the
1356- // right table, and another record containing the columns
1357- // from the right table along with nulls for the left table.
1358- // For instance, the current output is filtered based on the condition
1359- // t > 1.
1360-
1361- // 1, 1
1362- // 2, 2
1363- // 3, 3
1364-
1365- // In this scenario, we need to additionally insert a record 1, 1.
1366- // Subsequently, we will set the values of the columns on the left to
1367- // null and the values of the columns on the right to null as well. By
1368- // doing so, we will obtain the final result set.
1369-
1370- // 1, null
1371- // null, 1
1372- // 2, 2
1373- // 3, 3
1374- fullOuterOutput = BaseVector::create<RowVector>(
1375- output->type (), output->size () + 1 , pool ());
1376-
1377- for (auto i = 0 ; i < row + 1 ; ++i) {
1378- for (auto j = 0 ; j < output->type ()->size (); ++j) {
1379- fullOuterOutput->childAt (j)->copy (
1380- output->childAt (j).get (), i, i, 1 );
1400+ if (!isRightJoin (joinType_)) {
1401+ if (isFullJoin (joinType_) && isRightJoinForFullOuter) {
1402+ for (auto & projection : leftProjections_) {
1403+ auto target = output->childAt (projection.outputChannel );
1404+ target->setNull (row, true );
13811405 }
1382- }
1383-
1384- for (auto j = 0 ; j < output->type ()->size (); ++j) {
1385- fullOuterOutput->childAt (j)->copy (
1386- output->childAt (j).get (), row + 1 , row, 1 );
1387- }
1388-
1389- for (auto i = row + 1 ; i < output->size (); ++i) {
1390- for (auto j = 0 ; j < output->type ()->size (); ++j) {
1391- fullOuterOutput->childAt (j)->copy (
1392- output->childAt (j).get (), i + 1 , i, 1 );
1406+ } else {
1407+ for (auto & projection : rightProjections_) {
1408+ auto target = output->childAt (projection.outputChannel );
1409+ target->setNull (row, true );
13931410 }
13941411 }
1395-
1396- for (auto & projection : leftProjections_) {
1397- auto & target = fullOuterOutput->childAt (projection.outputChannel );
1398- target->setNull (row, true );
1399- }
1400-
1401- for (auto & projection : rightProjections_) {
1402- auto & target = fullOuterOutput->childAt (projection.outputChannel );
1403- target->setNull (row + 1 , true );
1404- }
1405- } else if (!isRightJoin (joinType_)) {
1406- for (auto & projection : rightProjections_) {
1407- auto & target = output->childAt (projection.outputChannel );
1408- target->setNull (row, true );
1409- }
14101412 } else {
14111413 for (auto & projection : leftProjections_) {
1412- auto & target = output->childAt (projection.outputChannel );
1414+ auto target = output->childAt (projection.outputChannel );
14131415 target->setNull (row, true );
14141416 }
14151417 }
14161418 };
14171419
14181420 auto onMatch = [&](auto row, bool firstMatch) {
1419- const bool isNonSemiAntiJoin =
1420- !isSemiFilterJoin (joinType_) && !isAntiJoin (joinType_);
1421+ const bool isFullLeftJoin =
1422+ isFullJoin (joinType_) && !joinTracker_->isRightJoinForFullOuter (row);
1423+
1424+ const bool isNonSemiAntiFullJoin = !isSemiFilterJoin (joinType_) &&
1425+ !isAntiJoin (joinType_) && !isFullJoin (joinType_);
14211426
1422- if ((isSemiFilterJoin (joinType_) && firstMatch) || isNonSemiAntiJoin) {
1427+ if ((isSemiFilterJoin (joinType_) && firstMatch) ||
1428+ isNonSemiAntiFullJoin || isFullLeftJoin) {
14231429 rawIndices[numPassed++] = row;
14241430 }
14251431 };
@@ -1480,17 +1486,10 @@ RowVectorPtr MergeJoin::applyFilter(const RowVectorPtr& output) {
14801486
14811487 if (numPassed == numRows) {
14821488 // All rows passed.
1483- if (fullOuterOutput) {
1484- return fullOuterOutput;
1485- }
14861489 return output;
14871490 }
14881491
14891492 // Some, but not all rows passed.
1490- if (fullOuterOutput) {
1491- return wrap (numPassed, indices, fullOuterOutput);
1492- }
1493-
14941493 return wrap (numPassed, indices, output);
14951494}
14961495
0 commit comments