public static AggregateFunction rectifyAggregationFunction(AggregateFunction fn, Type argType, Type returnType) {
        if (argType.isDecimalV2() || argType.isDecimalV3()) {
            if (fn.functionName().equals(FunctionSet.COUNT) || fn.functionName().equals(FunctionSet.COUNT_IF)) {
                // count & count_if function return type always bigint
                returnType = fn.getReturnType();
            } else if (fn.functionName().equals(FunctionSet.AVG)) {
                // avg on decimal complies with Snowflake-style
                // avg actual processed like sum()/count(), it also has a risk of overflow if the scale is too large,
                // so we limit the maximum scale for this case
                if (((ScalarType) argType).getScalarScale() > 18) {
                    argType = ScalarType.createDecimalV3Type(PrimitiveType.DECIMAL128, 38, 18);
                }
                final ArithmeticExpr.TypeTriple triple =
                        ArithmeticExpr.getReturnTypeOfDecimal(ArithmeticExpr.Operator.DIVIDE, (ScalarType) argType,
                                DECIMAL128P38S0);
                returnType = triple.returnType;
            } else if (fn.functionName().equals(FunctionSet.APPROX_TOP_K)) {
                returnType = FunctionSet.APPROX_TOP_N_RET_TYPE_BUILDER.apply(argType);
            } else if (DECIMAL_AGG_VARIANCE_STDDEV_TYPE.contains(fn.functionName())) {
                returnType = argType;
            } else if (argType.isDecimalV3() && DECIMAL_SUM_FUNCTION_TYPE.contains(fn.functionName())) {
                // For decimal aggregation sum, there is a risk of overflow if the scale is too large,
                // so we limit the maximum scale for this case
                if (((ScalarType) argType).getScalarScale() > 18) {
                    argType = ScalarType.createDecimalV3Type(PrimitiveType.DECIMAL128, 38, 18);
                    returnType = argType;
                }
            }
        }

        Type[] decimalTypes = new Type[fn.getNumArgs()];
        Arrays.fill(decimalTypes, argType);
        Type[] args = replaceArgDecimalType(fn.getArgs(), decimalTypes);

        AggregateFunction newFn = (AggregateFunction) fn.copy();
        newFn.setArgsType(args);
        newFn.setRetType(returnType);
        return newFn;
    }
@Test
    public void testDecimalStd() {
        List<Expr> params = Lists.newArrayList();
        params.add(new DecimalLiteral(new BigDecimal(new BigInteger("1845076"), 2)));

        List<Type> paramTypes = Lists.newArrayList();
        paramTypes.add(ScalarType.DECIMAL128);

        List<String> stdFunctions =
                Arrays.asList(FunctionSet.STD, FunctionSet.STDDEV, FunctionSet.VARIANCE, FunctionSet.VARIANCE_POP,
                        FunctionSet.VAR_POP, FunctionSet.VARIANCE_SAMP, FunctionSet.VAR_SAMP, FunctionSet.STDDEV_POP,
                        FunctionSet.STDDEV_SAMP);
        for (String funcName : stdFunctions) {
            AggregateFunction function =
                    (AggregateFunction) Expr.getBuiltinFunction(funcName, paramTypes.toArray(new Type[0]),
                            Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
            Assert.assertNotNull(function);
            Type argType = ScalarType.createWildcardDecimalV3Type(PrimitiveType.DECIMAL128);
            Type retType = Type.DOUBLE;
            AggregateFunction aggFunc =
                    DecimalV3FunctionAnalyzer.rectifyAggregationFunction(function, argType, retType);
            Type returnType = aggFunc.getReturnType();
            Assert.assertTrue(returnType.isDecimalV3());
        }
    }