private void updateNumNulls(ColStatistics colStats, long leftUnmatchedRows, long rightUnmatchedRows,
        long newNumRows, long pos, CommonJoinOperator<? extends JoinDesc> jop) {

      if (!(jop.getConf().getConds().length == 1)) {
        // TODO: handle multi joins
        return;
      }

      long oldNumNulls = colStats.getNumNulls();
      long newNumNulls = Math.min(newNumRows, oldNumNulls);

      JoinCondDesc joinCond = jop.getConf().getConds()[0];
      switch (joinCond.getType()) {
      case JoinDesc.LEFT_OUTER_JOIN:
        if (pos == joinCond.getRight()) {
          if (isJoinKey(colStats.getColumnName(), jop.getConf().getJoinKeys())) {
            newNumNulls = Math.min(newNumRows, leftUnmatchedRows);
          } else {
            newNumNulls = Math.min(newNumRows, oldNumNulls + leftUnmatchedRows);
          }
        }
        break;
      case JoinDesc.RIGHT_OUTER_JOIN:
        if (pos == joinCond.getLeft()) {
          if (isJoinKey(colStats.getColumnName(), jop.getConf().getJoinKeys())) {
            newNumNulls = Math.min(newNumRows, rightUnmatchedRows);
          } else {
            newNumNulls = Math.min(newNumRows, oldNumNulls + rightUnmatchedRows);
          }
        }
        break;
      case JoinDesc.FULL_OUTER_JOIN:
        if (isJoinKey(colStats.getColumnName(), jop.getConf().getJoinKeys())) {
          newNumNulls = Math.min(newNumRows, leftUnmatchedRows + rightUnmatchedRows);
        } else {
          newNumNulls = Math.min(newNumRows, oldNumNulls + leftUnmatchedRows + rightUnmatchedRows);
        }
        break;

      case JoinDesc.INNER_JOIN:
      case JoinDesc.UNIQUE_JOIN:
      case JoinDesc.LEFT_SEMI_JOIN:
      case JoinDesc.ANTI_JOIN:
        break;
      }
      colStats.setNumNulls(newNumNulls);
    }
Returns the index of parents whose join key columns are infer as primary keys
@param ops - operators
@return - list of primary key containing parent ids
ql/src/java/org/apache/hadoop/hive/ql/optimizer/stats/annotation/StatsRulesProcFactory.java