Program: 15948
Project: 15948
Buggy source:
/** 
 * Get the index that matches the ORDER BY list, if one exists. This is to avoid running a separate ORDER BY if an index can be used. This is specially important for large result sets, if only the first few rows are important (LIMIT is used)
 * @return the index if one is found
 */
private Index getSortIndex(){
  if (sort == null) {
    return null;
  }
  ArrayList<Column> sortColumns=New.arrayList();
  for (  int idx : sort.getIndexes()) {
    if (idx < 0 || idx >= expressions.size()) {
      throw DbException.getInvalidValueException("String_Node_Str",idx + 1);
    }
    Expression expr=expressions.get(idx);
    expr=expr.getNonAliasExpression();
    if (expr.isConstant()) {
      continue;
    }
    if (!(expr instanceof ExpressionColumn)) {
      return null;
    }
    ExpressionColumn exprCol=(ExpressionColumn)expr;
    if (exprCol.getTableFilter() != topTableFilter) {
      return null;
    }
    sortColumns.add(exprCol.getColumn());
  }
  Column[] sortCols=sortColumns.toArray(new Column[sortColumns.size()]);
  int[] sortTypes=sort.getSortTypes();
  if (sortCols.length == 0) {
    return topTableFilter.getTable().getScanIndex(session);
  }
  ArrayList<Index> list=topTableFilter.getTable().getIndexes();
  if (list != null) {
    for (int i=0, size=list.size(); i < size; i++) {
      Index index=list.get(i);
      if (index.getCreateSQL() == null) {
        continue;
      }
      if (index.getIndexType().isHash()) {
        continue;
      }
      IndexColumn[] indexCols=index.getIndexColumns();
      if (indexCols.length < sortCols.length) {
        continue;
      }
      boolean ok=true;
      for (int j=0; j < sortCols.length; j++) {
        IndexColumn idxCol=indexCols[j];
        Column sortCol=sortCols[j];
        if (idxCol.column != sortCol) {
          ok=false;
          break;
        }
        if (idxCol.sortType != sortTypes[j]) {
          ok=false;
          break;
        }
      }
      if (ok) {
        return index;
      }
    }
  }
  if (sortCols.length == 1 && sortCols[0].getColumnId() == -1) {
    Index index=topTableFilter.getTable().getScanIndex(session);
    if (index.isRowIdIndex()) {
      return index;
    }
  }
  return null;
}

Fixed version (ground truth):
/** 
 * Get the index that matches the ORDER BY list, if one exists. This is to avoid running a separate ORDER BY if an index can be used. This is specially important for large result sets, if only the first few rows are important (LIMIT is used)
 * @return the index if one is found
 */
private Index getSortIndex(){
  if (sort == null) {
    return null;
  }
  ArrayList<Column> sortColumns=New.arrayList();
  for (  int idx : sort.getQueryColumnIndexes()) {
    if (idx < 0 || idx >= expressions.size()) {
      throw DbException.getInvalidValueException("String_Node_Str",idx + 1);
    }
    Expression expr=expressions.get(idx);
    expr=expr.getNonAliasExpression();
    if (expr.isConstant()) {
      continue;
    }
    if (!(expr instanceof ExpressionColumn)) {
      return null;
    }
    ExpressionColumn exprCol=(ExpressionColumn)expr;
    if (exprCol.getTableFilter() != topTableFilter) {
      return null;
    }
    sortColumns.add(exprCol.getColumn());
  }
  Column[] sortCols=sortColumns.toArray(new Column[sortColumns.size()]);
  int[] sortTypes=sort.getSortTypes();
  if (sortCols.length == 0) {
    return topTableFilter.getTable().getScanIndex(session);
  }
  ArrayList<Index> list=topTableFilter.getTable().getIndexes();
  if (list != null) {
    for (int i=0, size=list.size(); i < size; i++) {
      Index index=list.get(i);
      if (index.getCreateSQL() == null) {
        continue;
      }
      if (index.getIndexType().isHash()) {
        continue;
      }
      IndexColumn[] indexCols=index.getIndexColumns();
      if (indexCols.length < sortCols.length) {
        continue;
      }
      boolean ok=true;
      for (int j=0; j < sortCols.length; j++) {
        IndexColumn idxCol=indexCols[j];
        Column sortCol=sortCols[j];
        if (idxCol.column != sortCol) {
          ok=false;
          break;
        }
        if (idxCol.sortType != sortTypes[j]) {
          ok=false;
          break;
        }
      }
      if (ok) {
        return index;
      }
    }
  }
  if (sortCols.length == 1 && sortCols[0].getColumnId() == -1) {
    Index index=topTableFilter.getTable().getScanIndex(session);
    if (index.isRowIdIndex()) {
      return index;
    }
  }
  return null;
}