@Override
  public Statistics visitFunctionHolderExpression(FunctionHolderExpression holderExpr, Void value)
      throws RuntimeException {
    FuncHolder funcHolder = holderExpr.getHolder();

    if (!(funcHolder instanceof DrillSimpleFuncHolder)) {
      // Only Drill function is allowed.
      return null;
    }

    final String funcName = ((DrillSimpleFuncHolder) funcHolder).getRegisteredNames()[0];

    if (CastFunctions.isCastFunction(funcName)) {
      Statistics stat = holderExpr.args.get(0).accept(this, null);
      if (stat != null && !stat.isEmpty()) {
        return evalCastFunc(holderExpr, stat);
      }
    }
    return null;
  }
  private Statistics evalCastFunc(FunctionHolderExpression holderExpr, Statistics input) {
    try {
      DrillSimpleFuncHolder funcHolder = (DrillSimpleFuncHolder) holderExpr.getHolder();

      DrillSimpleFunc interpreter = funcHolder.createInterpreter();

      final ValueHolder minHolder, maxHolder;

      TypeProtos.MinorType srcType = holderExpr.args.get(0).getMajorType().getMinorType();
      TypeProtos.MinorType destType = holderExpr.getMajorType().getMinorType();

      if (srcType.equals(destType)) {
        // same type cast ==> NoOp.
        return input;
      } else if (!CAST_FUNC.containsKey(srcType) || !CAST_FUNC.get(srcType).contains(destType)) {
        return null; // cast func between srcType and destType is NOT allowed.
      }

      switch (srcType) {
        case INT:
          minHolder = ValueHolderHelper.getIntHolder(((IntStatistics) input).getMin());
          maxHolder = ValueHolderHelper.getIntHolder(((IntStatistics) input).getMax());
          break;
        case BIGINT:
          minHolder = ValueHolderHelper.getBigIntHolder(((LongStatistics) input).getMin());
          maxHolder = ValueHolderHelper.getBigIntHolder(((LongStatistics) input).getMax());
          break;
        case FLOAT4:
          minHolder = ValueHolderHelper.getFloat4Holder(((FloatStatistics) input).getMin());
          maxHolder = ValueHolderHelper.getFloat4Holder(((FloatStatistics) input).getMax());
          break;
        case FLOAT8:
          minHolder = ValueHolderHelper.getFloat8Holder(((DoubleStatistics) input).getMin());
          maxHolder = ValueHolderHelper.getFloat8Holder(((DoubleStatistics) input).getMax());
          break;
        default:
          return null;
      }

      final ValueHolder[] args1 = {minHolder};
      final ValueHolder[] args2 = {maxHolder};

      final ValueHolder minFuncHolder =
          InterpreterEvaluator.evaluateFunction(interpreter, args1, holderExpr.getName());
      final ValueHolder maxFuncHolder =
          InterpreterEvaluator.evaluateFunction(interpreter, args2, holderExpr.getName());

      switch (destType) {
          // TODO : need handle # of nulls.
        case INT:
          return getStatistics(
              ((IntHolder) minFuncHolder).value, ((IntHolder) maxFuncHolder).value);
        case BIGINT:
          return getStatistics(
              ((BigIntHolder) minFuncHolder).value, ((BigIntHolder) maxFuncHolder).value);
        case FLOAT4:
          return getStatistics(
              ((Float4Holder) minFuncHolder).value, ((Float4Holder) maxFuncHolder).value);
        case FLOAT8:
          return getStatistics(
              ((Float8Holder) minFuncHolder).value, ((Float8Holder) maxFuncHolder).value);
        default:
          return null;
      }
    } catch (Exception e) {
      throw new DrillRuntimeException("Error in evaluating function of " + holderExpr.getName());
    }
  }