@Override
  public ExprNodeDesc visitCall(RexCall call) {
    ExprNodeDesc gfDesc = null;

    if (!deep) {
      return null;
    }

    List<ExprNodeDesc> args = new LinkedList<ExprNodeDesc>();
    if (call.getKind() == SqlKind.EXTRACT) {
      // Extract on date: special handling since function in Hive does
      // include <time_unit>. Observe that <time_unit> information
      // is implicit in the function name, thus translation will
      // proceed correctly if we just ignore the <time_unit>
      args.add(call.operands.get(1).accept(this));
    } else if (call.getKind() == SqlKind.FLOOR &&
            call.operands.size() == 2) {
      // Floor on date: special handling since function in Hive does
      // include <time_unit>. Observe that <time_unit> information
      // is implicit in the function name, thus translation will
      // proceed correctly if we just ignore the <time_unit>
      args.add(call.operands.get(0).accept(this));
    } else if (call.getKind() == SqlKind.IS_DISTINCT_FROM) {
      call = (RexCall) RexUtil.not(rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_DISTINCT_FROM, call.operands));
      for (RexNode operand : call.operands) {
        args.add(operand.accept(this));
      }
    } else if (call.getKind() == SqlKind.SEARCH) {
      return new SearchTransformer<>(rexBuilder, call).transform().accept(this);
    } else {
      for (RexNode operand : call.operands) {
        args.add(operand.accept(this));
      }
    }

    // If Call is a redundant cast then bail out. Ex: cast(true)BOOLEAN
    if (call.isA(SqlKind.CAST)
        && (call.operands.size() == 1)
        && SqlTypeUtil.equalSansNullability(dTFactory, call.getType(),
            call.operands.get(0).getType())) {
      return args.get(0);
    } else {
      GenericUDF hiveUdf = SqlFunctionConverter.getHiveUDF(call.getOperator(), call.getType(),
          args.size());
      if (hiveUdf == null) {
        throw new RuntimeException("Cannot find UDF for " + call.getType() + " "
            + call.getOperator() + "[" + call.getOperator().getKind() + "]/" + args.size());
      }
      try {
        gfDesc = ExprNodeGenericFuncDesc.newInstance(hiveUdf, args);
      } catch (UDFArgumentException e) {
        LOG.error("Failed to instantiate udf: ", e);
        throw new RuntimeException(e);
      }
    }

    // Try to fold if it is a constant expression
    if (foldExpr && RexUtil.isConstant(call)) {
      ExprNodeDesc constantExpr = ConstantPropagateProcFactory.foldExpr((ExprNodeGenericFuncDesc)gfDesc);
      if (constantExpr != null) {
        gfDesc = constantExpr;
      }
    }

    return gfDesc;
  }
TODO: Handle 1) cast 2), Windowing Agg Call
ql/src/java/org/apache/hadoop/hive/ql/optimizer/calcite/translator/ExprNodeConverter.java