Program: 111844
Project: 111844
Buggy source:
/** 
 * Recursively matches operands above a given solve order.
 * @param solve Solver order of operand
 * @pre solve &gt; 0
 * @pre solve &lt;= rule.operands.length
 */
private void matchRecurse(int solve){
  if (solve == getRule().operands.size()) {
    if (getRule().matches(this)) {
      onMatch();
    }
  }
 else {
    int operandOrdinal=getOperand0().solveOrder[solve];
    int previousOperandOrdinal=getOperand0().solveOrder[solve - 1];
    boolean ascending=operandOrdinal < previousOperandOrdinal;
    RelOptRuleOperand previousOperand=getRule().operands.get(previousOperandOrdinal);
    RelOptRuleOperand operand=getRule().operands.get(operandOrdinal);
    List<RelNode> successors;
    if (ascending) {
      assert(previousOperand.getParent() == operand);
      final RelNode childRel=rels[previousOperandOrdinal];
      RelSubset subset=volcanoPlanner.getSubset(childRel);
      successors=subset.getParentRels();
    }
 else {
      int parentOrdinal=operand.getParent().ordinalInRule;
      RelNode parentRel=rels[parentOrdinal];
      List<RelNode> inputs=parentRel.getInputs();
      if (operand.ordinalInParent < inputs.size()) {
        RelSubset subset=(RelSubset)inputs.get(operand.ordinalInParent);
        successors=subset.getRelList();
      }
 else {
        successors=Collections.emptyList();
      }
    }
    for (    RelNode rel : successors) {
      if (!operand.matches(rel)) {
        continue;
      }
      if (ascending) {
        final RelSubset input=(RelSubset)rel.getInput(previousOperand.ordinalInParent);
        List<RelNode> inputRels=input.set.getRelsFromAllSubsets();
        if (!inputRels.contains(rels[previousOperandOrdinal])) {
          continue;
        }
      }
      rels[operandOrdinal]=rel;
      matchRecurse(solve + 1);
    }
  }
}

Fixed version (ground truth):
/** 
 * Recursively matches operands above a given solve order.
 * @param solve Solver order of operand
 * @pre solve &gt; 0
 * @pre solve &lt;= rule.operands.length
 */
private void matchRecurse(int solve){
  if (solve == getRule().operands.size()) {
    if (getRule().matches(this)) {
      onMatch();
    }
  }
 else {
    int operandOrdinal=getOperand0().solveOrder[solve];
    int previousOperandOrdinal=getOperand0().solveOrder[solve - 1];
    boolean ascending=operandOrdinal < previousOperandOrdinal;
    RelOptRuleOperand previousOperand=getRule().operands.get(previousOperandOrdinal);
    RelOptRuleOperand operand=getRule().operands.get(operandOrdinal);
    Collection<RelNode> successors;
    if (ascending) {
      assert(previousOperand.getParent() == operand);
      final RelNode childRel=rels[previousOperandOrdinal];
      RelSubset subset=volcanoPlanner.getSubset(childRel);
      successors=subset.getParentRels();
    }
 else {
      int parentOrdinal=operand.getParent().ordinalInRule;
      RelNode parentRel=rels[parentOrdinal];
      List<RelNode> inputs=parentRel.getInputs();
      if (operand.ordinalInParent < inputs.size()) {
        RelSubset subset=(RelSubset)inputs.get(operand.ordinalInParent);
        successors=subset.getRelList();
      }
 else {
        successors=Collections.emptyList();
      }
    }
    for (    RelNode rel : successors) {
      if (!operand.matches(rel)) {
        continue;
      }
      if (ascending) {
        final RelSubset input=(RelSubset)rel.getInput(previousOperand.ordinalInParent);
        List<RelNode> inputRels=input.set.getRelsFromAllSubsets();
        if (!inputRels.contains(rels[previousOperandOrdinal])) {
          continue;
        }
      }
      rels[operandOrdinal]=rel;
      matchRecurse(solve + 1);
    }
  }
}