@Override
  public QueryResult process(final QueryResult bindings, final int operandID) {
    if (operandID < this.operandResults.length) {
      this.operandResults[operandID] = bindings;
    } else
      System.err.println(
          "NAryMergeJoin is a "
              + this.operandResults.length
              + "-ary operator, but received the operand number "
              + operandID);
    boolean go = true;
    for (int i = 0; i < this.operandResults.length; i++) {
      if (this.operandResults[i] == null) {
        go = false;
        break;
      }
    }
    if (go) {

      this.comp.setVariables(this.intersectionVariables);

      if (this.minimum == null) return null;

      @SuppressWarnings("unchecked")
      final Iterator<Bindings>[] itb = new Iterator[this.operandResults.length];
      for (int i = 0; i < this.operandResults.length; i++) {
        itb[i] = this.operandResults[i].oneTimeIterator();
      }

      final ParallelIterator<Bindings> currentResult =
          (this.intersectionVariables.size() == 0)
              ? MergeJoin.cartesianProductIterator(this.operandResults)
              : MergeJoin.mergeJoinIterator(
                  itb, this.comp, this.intersectionVariables, this.minimum, this.maximum);
      if (currentResult != null && currentResult.hasNext()) {
        final QueryResult result =
            QueryResult.createInstance(
                new SIPParallelIterator<Bindings, Bindings>() {

                  int number = 0;

                  @Override
                  public void close() {
                    currentResult.close();
                  }

                  @Override
                  public boolean hasNext() {
                    if (!currentResult.hasNext()) {
                      NAryMergeJoinWithoutSorting.this.realCardinality = this.number;
                      close();
                    }
                    return currentResult.hasNext();
                  }

                  @Override
                  public Bindings next() {
                    final Bindings b = currentResult.next();
                    if (b != null) this.number++;
                    if (!currentResult.hasNext()) {
                      NAryMergeJoinWithoutSorting.this.realCardinality = this.number;
                      close();
                    }
                    return b;
                  }

                  public Bindings getNext(final Bindings k) {
                    @SuppressWarnings("unchecked")
                    final Bindings b =
                        ((SIPParallelIterator<Bindings, Bindings>) currentResult).next(k);
                    if (b != null) this.number++;
                    if (!currentResult.hasNext()) {
                      NAryMergeJoinWithoutSorting.this.realCardinality = this.number;
                      close();
                    }
                    return b;
                  }

                  @Override
                  public void remove() {
                    currentResult.remove();
                  }

                  @Override
                  public void finalize() {
                    close();
                  }

                  @Override
                  public Bindings next(final Bindings k) {
                    if (currentResult instanceof SIPParallelIterator) return getNext(k);
                    else return next();
                  }
                });

        return result;
      } else {
        for (int i = 0; i < this.operandResults.length; i++) {
          if (this.operandResults[i] != null) {
            this.operandResults[i].release();
            this.operandResults[i] = null;
          }
        }
        return null;
      }
    } else {
      return null;
    }
  }
  @SuppressWarnings("unchecked")
  @Override
  public QueryResult process(final QueryResult bindings, final int operandID) {
    bindings.materialize();
    this.comp.setVariables(this.intersectionVariables);
    final QueryResult oldLeft = this.left;
    final QueryResult oldRight = this.right;
    if (operandID == 0) {
      if (this.left == null) this.left = bindings;
      else
        this.left =
            QueryResult.createInstance(
                new MergeIterator<Bindings>(this.comp, this.left.iterator(), bindings.iterator()));
    } else if (operandID == 1) {
      if (this.right == null) this.right = bindings;
      else
        this.right =
            QueryResult.createInstance(
                new MergeIterator<Bindings>(this.comp, this.right.iterator(), bindings.iterator()));
    } else
      System.err.println(
          "MergeJoin is a binary operator, but received the operand number " + operandID);
    if (this.left != null && this.right != null) {
      this.left.materialize();
      this.right.materialize();

      final Iterator<Bindings> leftIterator =
          (operandID == 0 && oldLeft != null)
              ? new MinusIterator(bindings.iterator(), oldLeft.iterator())
              : this.left.iterator();
      final QueryResult rightLocal =
          (operandID == 1 && oldRight != null)
              ? QueryResult.createInstance(
                  new MinusIterator(bindings.iterator(), oldRight.iterator()))
              : this.right;

      final ParallelIterator<Bindings> currentResult =
          (this.intersectionVariables.size() == 0)
              ? MergeJoin.cartesianProductIterator(leftIterator, rightLocal)
              : MergeJoin.mergeJoinIterator(
                  leftIterator, rightLocal.iterator(), this.comp, this.intersectionVariables);
      if (currentResult != null && currentResult.hasNext()) {
        final QueryResult result =
            QueryResult.createInstance(
                new ParallelIterator<Bindings>() {

                  int number = 0;

                  @Override
                  public void close() {
                    currentResult.close();
                  }

                  @Override
                  public boolean hasNext() {
                    if (!currentResult.hasNext()) {
                      MergeJoinWithoutSortingSeveralIterations.this.realCardinality = this.number;
                      close();
                    }
                    return currentResult.hasNext();
                  }

                  @Override
                  public Bindings next() {
                    final Bindings b = currentResult.next();
                    if (!currentResult.hasNext()) {
                      MergeJoinWithoutSortingSeveralIterations.this.realCardinality = this.number;
                      close();
                    }
                    if (b != null) this.number++;
                    return b;
                  }

                  @Override
                  public void remove() {
                    currentResult.remove();
                  }

                  @Override
                  public void finalize() {
                    close();
                  }
                });
        return result;
      } else {
        return null;
      }
    } else {
      return null;
    }
  }