public void finishOuter(VectorizedRowBatch batch,
      int allMatchCount, int equalKeySeriesCount, boolean atLeastOneNonMatch,
      boolean inputSelectedInUse, int inputLogicalSize,
      int spillCount, int hashMapResultCount) throws IOException, HiveException {

    // Get rid of spills before we start modifying the batch.
    if (spillCount > 0) {
      spillHashMapBatch(batch, (VectorMapJoinHashTableResult[]) hashMapResults,
          spills, spillHashMapResultIndices, spillCount);
    }

    int noMatchCount = 0;
    if (spillCount > 0) {

      // Subtract the spills to get all match and non-match rows.
      int nonSpillCount = subtractFromInputSelected(
              inputSelectedInUse, inputLogicalSize, spills, spillCount, nonSpills);

      if (LOG.isDebugEnabled()) {
        LOG.debug("finishOuter spillCount > 0" +
            " nonSpills " + intArrayToRangesString(nonSpills, nonSpillCount));
      }
  
      // Big table value expressions apply to ALL matching and non-matching rows.
      if (bigTableValueExpressions != null) {
  
        doValueExpr(batch, nonSpills, nonSpillCount);
  
      }
  
      if (atLeastOneNonMatch) {
        noMatchCount = subtract(nonSpills, nonSpillCount, allMatches, allMatchCount,
                noMatchs);

        if (LOG.isDebugEnabled()) {
          LOG.debug("finishOuter spillCount > 0" +
              " noMatchs " + intArrayToRangesString(noMatchs, noMatchCount));
        }

      }
    } else {

      // Run value expressions over original (whole) input batch.
      doValueExprOnInputSelected(batch, inputSelectedInUse, inputLogicalSize);

      if (atLeastOneNonMatch) {
        noMatchCount = subtractFromInputSelected(
            inputSelectedInUse, inputLogicalSize, allMatches, allMatchCount, noMatchs);

        if (LOG.isDebugEnabled()) {
          LOG.debug("finishOuter spillCount == 0" +
              " noMatchs " + intArrayToRangesString(noMatchs, noMatchCount));
        }
      }
    }

    // When we generate results into the overflow batch, we may still end up with fewer rows
    // in the big table batch.  So, nulSel and the batch's selected array will be rebuilt with
    // just the big table rows that need to be forwarded, minus any rows processed with the
    // overflow batch.
    if (allMatchCount > 0) {

      int numSel = 0;
      for (int i = 0; i < equalKeySeriesCount; i++) {
        int hashMapResultIndex = equalKeySeriesHashMapResultIndices[i];
        VectorMapJoinHashMapResult hashMapResult = hashMapResults[hashMapResultIndex];
        int allMatchesIndex = equalKeySeriesAllMatchIndices[i];
        boolean isSingleValue = equalKeySeriesIsSingleValue[i];
        int duplicateCount = equalKeySeriesDuplicateCounts[i];

        if (isSingleValue) {
          numSel = generateHashMapResultSingleValue(
                      batch, hashMapResult, allMatches, allMatchesIndex, duplicateCount, numSel);
        } else {
          generateHashMapResultMultiValue(
              batch, hashMapResult, allMatches, allMatchesIndex, duplicateCount);
        }
      }

      // The number of single value rows that were generated in the big table batch.
      batch.size = numSel;
      batch.selectedInUse = true;

      if (LOG.isDebugEnabled()) {
        LOG.debug("finishOuter allMatchCount > 0" +
            " batch.selected " + intArrayToRangesString(batch.selected, batch.size));
      }

    } else {
      batch.size = 0;
    }

    if (noMatchCount > 0) {
      if (batch.size > 0) {

        generateOuterNulls(batch, noMatchs, noMatchCount);
  
        // Merge noMatchs and (match) selected.
        int mergeCount = sortMerge(
                noMatchs, noMatchCount, batch.selected, batch.size, merged);
    
        if (LOG.isDebugEnabled()) {
          LOG.debug("finishOuter noMatchCount > 0 && batch.size > 0" +
              " merged " + intArrayToRangesString(merged, mergeCount));
        }

        System.arraycopy(merged, 0, batch.selected, 0, mergeCount);
        batch.size = mergeCount;
        batch.selectedInUse = true;
      } else {

        // We can use the whole batch for output of no matches.

        generateOuterNullsRepeatedAll(batch);

        System.arraycopy(noMatchs, 0, batch.selected, 0, noMatchCount);
        batch.size = noMatchCount;
        batch.selectedInUse = true;

        if (LOG.isDebugEnabled()) {
          LOG.debug("finishOuter noMatchCount > 0 && batch.size == 0" +
              " batch.selected " + intArrayToRangesString(batch.selected, batch.size));
        }
      }
    }
  }
Generate the outer join output results for one vectorized row batch.

@param batch
         The big table batch with any matching and any non matching rows both as
         selected in use.
@param allMatchCount
         Number of matches in allMatches.
@param equalKeySeriesCount
         Number of single value matches.
@param atLeastOneNonMatch
         Whether at least one row was a non-match.
@param inputSelectedInUse
         A copy of the batch's selectedInUse flag on input to the process method.
@param inputLogicalSize
         The batch's size on input to the process method.
@param spillCount
         Number of spills in spills.
@param hashMapResultCount
         Number of entries in hashMapResults.
ql/src/java/org/apache/hadoop/hive/ql/exec/vector/mapjoin/VectorMapJoinOuterGenerateResultOperator.java