private void setupStats(TableScanDesc tsDesc, QBParseInfo qbp, Table tab, String alias,
                          RowResolver rwsch)
      throws SemanticException {

    // if it is not analyze command and not column stats, then do not gatherstats
    if (!qbp.isAnalyzeCommand() && qbp.getAnalyzeRewrite() == null) {
      tsDesc.setGatherStats(false);
      return;
    }

    if (HiveConf.getVar(conf, HIVE_STATS_DBCLASS).equalsIgnoreCase(StatDB.fs.name())) {
      String statsTmpLoc = ctx.getTempDirForInterimJobPath(tab.getPath()).toString();
      LOG.debug("Set stats collection dir : " + statsTmpLoc);
      tsDesc.setTmpStatsDir(statsTmpLoc);
    }
    tsDesc.setGatherStats(true);
    tsDesc.setStatsReliable(conf.getBoolVar(HiveConf.ConfVars.HIVE_STATS_RELIABLE));

    // append additional virtual columns for storing statistics
    Iterator<VirtualColumn> vcs = VirtualColumn.getStatsRegistry(conf).iterator();
    List<VirtualColumn> vcList = new ArrayList<VirtualColumn>();
    while (vcs.hasNext()) {
      VirtualColumn vc = vcs.next();
      rwsch.put(alias, vc.getName(), new ColumnInfo(vc.getName(),
          vc.getTypeInfo(), alias, true, vc.getIsHidden()));
      vcList.add(vc);
    }
    tsDesc.addVirtualCols(vcList);

    String tblName = tab.getTableName();
    // Theoretically the key prefix could be any unique string shared
    // between TableScanOperator (when publishing) and StatsTask (when aggregating).
    // Here we use
    // db_name.table_name + partitionSec
    // as the prefix for easy of read during explain and debugging.
    // Currently, partition spec can only be static partition.
    String k = FileUtils.escapePathName(tblName).toLowerCase() + Path.SEPARATOR;
    tsDesc.setStatsAggPrefix(FileUtils.escapePathName(tab.getDbName()).toLowerCase() + "." + k);

    // set up WriteEntity for replication and txn stats
    WriteEntity we = new WriteEntity(tab, WriteEntity.WriteType.DDL_SHARED);
    we.setTxnAnalyze(true);
    outputs.add(we);
    if (AcidUtils.isTransactionalTable(tab)) {
      if (acidAnalyzeTable != null) {
        throw new IllegalStateException("Multiple ACID tables in analyze: "
            + we + ", " + acidAnalyzeTable);
      }
      acidAnalyzeTable = we;
    }

    // add WriteEntity for each matching partition
    if (tab.isPartitioned() && !tab.hasNonNativePartitionSupport()) {
      List<String> cols = new ArrayList<String>();
      if (qbp.getAnalyzeRewrite() != null) {
        List<FieldSchema> partitionCols = tab.getPartCols();
        for (FieldSchema fs : partitionCols) {
          cols.add(fs.getName());
        }
        tsDesc.setPartColumns(cols);
        return;
      }
      TableSpec tblSpec = qbp.getTableSpec(alias);
      Map<String, String> partSpec = tblSpec.getPartSpec();
      if (partSpec != null) {
        cols.addAll(partSpec.keySet());
        tsDesc.setPartColumns(cols);
      } else {
        throw new SemanticException(ErrorMsg.NEED_PARTITION_SPECIFICATION.getMsg());
      }
      List<Partition> partitions = qbp.getTableSpec().partitions;
      if (partitions != null) {
        for (Partition partn : partitions) {
          WriteEntity pwe = new WriteEntity(partn, WriteEntity.WriteType.DDL_NO_LOCK);
          pwe.setTxnAnalyze(true);
          outputs.add(pwe);
        }
      }
    }
  }
if the column is a skewed column, use ColumnInfo accordingly
ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java