public static TableScanOperator genRootTableScan(
      Operator<? extends OperatorDesc> op, List<String> keyNames) {

    Operator<? extends OperatorDesc> currOp = op;
    List<String> currColNames = keyNames;
    List<Operator<? extends OperatorDesc>> parentOps = null;

    // Track as you walk up the tree if there is an operator
    // along the way that changes the rows from the table through
    // joins or aggregations. Only allowed operators are selects
    // and filters.
    while (true) {
      parentOps = currOp.getParentOperators();
      if ((parentOps == null) || (parentOps.isEmpty())) {
        return (TableScanOperator) currOp;
      }

      if (parentOps.size() > 1 ||
          !(currOp.columnNamesRowResolvedCanBeObtained())) {
        return null;
      } else {
        // Generate the map of the input->output column name for the keys
        // we are about
        if (!TableAccessAnalyzer.genColNameMap(currOp, currColNames)) {
          return null;
        }
        currOp = parentOps.get(0);
      }
    }
  }
This method traces up from the given operator to the root
of the operator graph until a TableScanOperator is reached.
Along the way, if any operators are present that do not
provide a direct mapping from columns of the base table to
the keys on the input operator, the trace-back is stopped at that
point. If the trace back can be done successfully, the method
returns the root TableScanOperator as well as the list of column
names on that table that map to the keys used for the input
operator (which is currently only a join or group by).
ql/src/java/org/apache/hadoop/hive/ql/parse/TableAccessAnalyzer.java