@Test
  public void testWithSortingOnManyColumns() throws Exception {
    CollectingProjector collectingProjector = new CollectingProjector();

    // order by col2 asc, col1 desc nulls first
    final SortingBucketMerger merger =
        new SortingBucketMerger(
            collectingProjector,
            2,
            new int[] {1, 0},
            new boolean[] {false, true},
            new Boolean[] {null, true},
            Optional.<Executor>absent());
    collectingProjector.startProjection(mock(ExecutionState.class));
    BucketPage page1 =
        createPage(
            Arrays.asList(new Object[] {"A", "0"}, new Object[] {"A", "1"}),
            Arrays.asList(new Object[] {"D", "1"}, new Object[] {"C", "1"}));
    BucketPage page2 =
        createPage(
            Arrays.asList(
                new Object[] {"C", "8"}, new Object[] {"B", "8"}, new Object[] {null, "9"}),
            Arrays.asList(
                new Object[] {"C", "2"}, new Object[] {"C", "6"}, new Object[] {"A", "9"}));

    final Iterator<BucketPage> pageIter = Iterators.forArray(page1, page2);
    if (pageIter.hasNext()) {
      merger.nextPage(
          pageIter.next(),
          new PageConsumeListener() {
            @Override
            public void needMore() {
              if (pageIter.hasNext()) {
                merger.nextPage(pageIter.next(), this);
              } else {
                merger.finish();
              }
            }

            @Override
            public void finish() {
              merger.finish();
            }
          });
    } else {
      merger.finish();
    }
    assertRows(
        collectingProjector.result().get(),
        "A| 0",
        "D| 1",
        "C| 1",
        "A| 1",
        "C| 2",
        "C| 6",
        "C| 8",
        "B| 8",
        "NULL| 9",
        "A| 9");
  }
  private Bucket mergeWith(int buckets, @Nullable Boolean nullsFirst, BucketPage... pages)
      throws ExecutionException, InterruptedException {

    CollectingProjector collectingProjector = new CollectingProjector();
    final SortingBucketMerger merger =
        new SortingBucketMerger(
            collectingProjector,
            buckets,
            new int[] {0},
            new boolean[] {false},
            new Boolean[] {nullsFirst},
            Optional.<Executor>absent());
    collectingProjector.startProjection(mock(ExecutionState.class));

    final Iterator<BucketPage> pageIter = Iterators.forArray(pages);
    if (pageIter.hasNext()) {
      merger.nextPage(
          pageIter.next(),
          new PageConsumeListener() {
            @Override
            public void needMore() {
              if (pageIter.hasNext()) {
                merger.nextPage(pageIter.next(), this);
              } else {
                merger.finish();
              }
            }

            @Override
            public void finish() {
              merger.finish();
            }
          });
    } else {
      merger.finish();
    }
    return collectingProjector.result().get();
  }